#include "gtest/gtest.h" #include "src/errors.cpp" #include #include #include // 全局跳转点,用于处理信号 static std::jmp_buf jump_buffer; // 信号处理函数 static void signal_handler(int sig) { std::longjmp(jump_buffer, 1); } // 测试夹具类 class ErrorsTest : public ::testing::Test { protected: // 保存旧的信号处理器 struct sigaction old_action{}; struct sigaction new_action{}; void SetUp() override { // 设置 SIGSEGV 和 SIGABRT 的信号处理器 new_action.sa_handler = signal_handler; sigemptyset(&new_action.sa_mask); new_action.sa_flags = 0; sigaction(SIGSEGV, &new_action, &old_action); sigaction(SIGABRT, &new_action, nullptr); } void TearDown() override { // 恢复旧的信号处理器 sigaction(SIGSEGV, &old_action, nullptr); } }; // 测试 test_null_pointer 函数 // 该函数会解引用空指针,预期会触发段错误 (SIGSEGV) 或程序终止 TEST_F(ErrorsTest, test_null_pointer_TriggersCrash) { // 设置跳转点,如果发生信号则跳转回来 if (setjmp(jump_buffer) == 0) { // 尝试调用会崩溃的函数 test_null_pointer(); // 如果执行到这里,说明没有崩溃,测试失败 FAIL() << "Expected test_null_pointer to cause a crash (SIGSEGV), but it didn't."; } else { // 成功捕获到信号,测试通过 SUCCEED(); } } // 测试 test_array_out_of_bounds 函数 // 该函数会访问数组越界,预期会触发段错误 (SIGSEGV) 或程序终止 TEST_F(ErrorsTest, test_array_out_of_bounds_TriggersCrash) { if (setjmp(jump_buffer) == 0) { test_array_out_of_bounds(); FAIL() << "Expected test_array_out_of_bounds to cause a crash (SIGSEGV), but it didn't."; } else { SUCCEED(); } } // 测试 test_uninitialized_var 函数 // 该函数使用未初始化的变量,行为是未定义的。 // 我们无法可靠地测试其输出,但可以验证函数能运行而不崩溃(尽管结果不可预测)。 // 注意:这是一个“正常”路径测试,因为函数定义本身没有语法错误,可以执行。 TEST_F(ErrorsTest, test_uninitialized_var_RunsWithoutCrash) { // 由于使用未初始化变量是未定义行为,它可能崩溃也可能不崩溃。 // 我们只测试函数可以被调用而不导致必然的、可捕获的崩溃(如SIGSEGV)。 // 我们使用一个 try-catch 块,但C++标准异常通常捕获不了内存错误。 // 因此,我们设置一个信号处理器,如果它因未初始化变量而意外崩溃,我们也能捕获。 if (setjmp(jump_buffer) == 0) { test_uninitialized_var(); // 如果执行到这里,说明没有触发我们设置的信号处理器(SIGSEGV/SIGABRT)。 // 这被认为是测试通过,因为函数执行完成了。 // 我们无法断言它的输出,因为 val 是未定义的。 SUCCEED(); } else { // 如果它意外地因为未初始化变量而崩溃了,我们也记录下来。 // 这在某些平台/编译器上是有可能的。 ADD_FAILURE() << "test_uninitialized_var caused a signal. This is possible UB."; } } // 主函数 int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }