diff --git a/tests/test_errors.cpp b/tests/test_errors.cpp new file mode 100644 index 0000000..cd3a6c0 --- /dev/null +++ b/tests/test_errors.cpp @@ -0,0 +1,105 @@ +#include "gtest/gtest.h" +#include "src/errors.cpp" +#include +#include +#include + +// 用于捕获信号和异常的全局变量 +static std::jmp_buf jump_buffer; +static volatile std::sig_atomic_t gSignalStatus; + +// 信号处理函数 +void signal_handler(int signal) { + gSignalStatus = signal; + std::longjmp(jump_buffer, 1); +} + +namespace { + // 测试类,用于设置和恢复信号处理器 + class SignalGuard { + public: + SignalGuard(int sig, void (*handler)(int)) : m_sig(sig), m_old_handler(std::signal(sig, handler)) {} + ~SignalGuard() { std::signal(m_sig, m_old_handler); } + private: + int m_sig; + void (*m_old_handler)(int); + }; + + // 测试 test_null_pointer 函数 + TEST(ErrorsTest, TestNullPointerTriggersSignal) { + // 安装 SIGSEGV 信号处理器 + SignalGuard guard(SIGSEGV, signal_handler); + gSignalStatus = 0; + + // 使用 setjmp/longjmp 来捕获信号后的跳转 + if (setjmp(jump_buffer) == 0) { + // 尝试执行会触发段错误的函数 + test_null_pointer(); + // 如果执行到这里,说明没有触发信号,测试失败 + FAIL() << "Expected test_null_pointer to cause a segmentation fault"; + } else { + // 成功捕获到信号 + EXPECT_EQ(gSignalStatus, SIGSEGV); + } + } + + // 测试 test_array_out_of_bounds 函数 + TEST(ErrorsTest, TestArrayOutOfBoundsTriggersSignal) { + // 安装 SIGSEGV 信号处理器 + SignalGuard guard(SIGSEGV, signal_handler); + gSignalStatus = 0; + + if (setjmp(jump_buffer) == 0) { + test_array_out_of_bounds(); + FAIL() << "Expected test_array_out_of_bounds to cause a segmentation fault"; + } else { + EXPECT_EQ(gSignalStatus, SIGSEGV); + } + } + + // 测试 test_uninitialized_var 函数 + // 注意:未初始化变量的行为是未定义的,可能不会崩溃,但结果不可预测。 + // 我们无法可靠地测试其具体行为,但可以验证函数调用本身不会导致程序终止(如信号)。 + // 然而,为了演示,我们仍然运行它,但不对其输出做任何断言,因为它是未定义的。 + TEST(ErrorsTest, TestUninitializedVarRunsWithoutCrash) { + // 这个测试主要是为了确保函数可以被调用,而不导致程序崩溃(尽管行为未定义)。 + // 由于未初始化变量的值是未定义的,我们无法断言其具体行为。 + // 在某些配置下(如调试模式),变量可能被初始化为0,但这不是保证的。 + // 因此,我们只调用函数,不进行断言。 + // 注意:这实际上不是一个好的单元测试,因为它没有验证任何确定的行为。 + // 它只是为了演示如何“测试”一个具有未定义行为的函数。 + // 在实际项目中,这样的函数应该被修复,而不是被测试。 + test_uninitialized_var(); + // 如果程序执行到这里,说明没有崩溃,测试通过。 + // 我们无法对输出做任何有意义的断言。 + SUCCEED(); + } + + // 额外的测试:验证正常数组访问不会崩溃(作为对比) + TEST(ErrorsTest, TestNormalArrayAccessDoesNotCrash) { + int arr[3] = {1, 2, 3}; + EXPECT_EQ(arr[0], 1); + EXPECT_EQ(arr[1], 2); + EXPECT_EQ(arr[2], 3); + // 访问有效索引,不应崩溃 + SUCCEED(); + } + + // 额外的测试:验证已初始化的指针解引用不会崩溃(作为对比) + TEST(ErrorsTest, TestValidPointerDereferenceDoesNotCrash) { + int value = 42; + int* p = &value; + EXPECT_EQ(*p, 42); + SUCCEED(); + } + + // 额外的测试:验证已初始化的变量行为可预测 + TEST(ErrorsTest, TestInitializedVarBehaviorIsPredictable) { + int val = 15; // 明确初始化 + if (val > 10) { + SUCCEED(); // 条件为真,符合预期 + } else { + FAIL() << "Initialized variable should behave predictably"; + } + } +}