#include "gtest/gtest.h" #include "src/errors.h" #include #include #include // 全局跳转点,用于处理信号 static std::jmp_buf jump_buffer; // 信号处理函数 static void signal_handler(int sig) { std::longjmp(jump_buffer, sig); } // 测试夹具类 class ErrorsTest : public ::testing::Test { protected: // 保存旧的信号处理器 struct sigaction old_action_segv; struct sigaction old_action_abrt; void SetUp() override { // 为 SIGSEGV 和 SIGABRT 设置新的信号处理器 struct sigaction new_action; new_action.sa_handler = signal_handler; sigemptyset(&new_action.sa_mask); new_action.sa_flags = 0; sigaction(SIGSEGV, &new_action, &old_action_segv); sigaction(SIGABRT, &new_action, &old_action_abrt); } void TearDown() override { // 恢复旧的信号处理器 sigaction(SIGSEGV, &old_action_segv, nullptr); sigaction(SIGABRT, &old_action_abrt, nullptr); } }; // 测试 test_null_pointer 函数会触发段错误 TEST_F(ErrorsTest, test_null_pointerTriggersSegFault) { // 设置跳转点,如果发生信号则跳转回这里 int sig = setjmp(jump_buffer); if (sig == 0) { // 尝试调用会触发错误的函数 test_null_pointer(); // 如果执行到这里,说明没有触发信号,测试失败 FAIL() << "Expected test_null_pointer to cause a segmentation fault."; } else { // 检查捕获到的信号是否是预期的 SIGSEGV EXPECT_EQ(sig, SIGSEGV) << "Expected SIGSEGV, but got signal: " << sig; } } // 测试 test_array_out_of_bounds 函数会触发段错误 TEST_F(ErrorsTest, test_array_out_of_boundsTriggersSegFault) { int sig = setjmp(jump_buffer); if (sig == 0) { test_array_out_of_bounds(); FAIL() << "Expected test_array_out_of_bounds to cause a segmentation fault."; } else { // 数组越界通常也会导致 SIGSEGV EXPECT_EQ(sig, SIGSEGV) << "Expected SIGSEGV, but got signal: " << sig; } } // 测试 test_uninitialized_var 函数的行为是未定义的 // 我们无法可靠地测试未定义行为,但可以验证函数调用本身不会导致程序崩溃(如段错误) // 注意:这个测试可能通过,也可能失败,因为行为是未定义的。 // 更安全的做法是验证函数可以被调用,而不对输出做任何断言。 TEST_F(ErrorsTest, test_uninitialized_varDoesNotCrash) { // 设置跳转点捕获致命信号 int sig = setjmp(jump_buffer); if (sig == 0) { // 调用函数。由于使用未初始化变量是未定义行为, // 它可能做任何事情,包括不崩溃。 // 我们只测试它不会触发我们捕获的信号(SIGSEGV, SIGABRT)。 test_uninitialized_var(); // 如果执行到这里,说明没有触发 SIGSEGV 或 SIGABRT。 // 对于未定义行为,我们无法做出更多有意义的断言。 SUCCEED(); } else { // 如果捕获到信号,记录它,但这不是必然的预期。 // 我们将此视为测试通过的一种可能路径,因为行为未定义。 // 更严谨的做法是标记测试为不可靠或跳过。 // 这里我们选择不使测试失败,仅记录。 std::cout << "Note: test_uninitialized_var triggered signal " << sig << " (behavior is undefined)." << std::endl; } } // 主函数(通常由 gtest_main 提供,这里显式写出以确保可编译) int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }