#include "gtest/gtest.h" #include "src/errors.cpp" #include #include #include // 用于捕获信号(如SIGSEGV)的全局跳转点 static jmp_buf jump_buffer; // 信号处理函数 void signal_handler(int sig) { (void)sig; // 抑制未使用参数的警告 longjmp(jump_buffer, 1); } // 测试空指针解引用 // 注意:此函数设计为会崩溃,因此测试需要捕获信号或异常。 // 由于直接测试崩溃行为在单元测试中不典型,我们通常期望这类错误在代码审查或静态分析中被发现。 // 这里我们演示一种通过信号处理来“捕获”崩溃的方法,但这更多是演示性质,并非标准单元测试实践。 TEST(ErrorsTest, TestNullPointerTriggersCrash) { // 安装信号处理器 std::signal(SIGSEGV, signal_handler); // 设置跳转点。如果setjmp返回0,表示首次设置。如果返回非0,表示从longjmp跳回。 if (setjmp(jump_buffer) == 0) { // 尝试执行会崩溃的函数 test_null_pointer(); // 如果执行到这里,说明没有触发崩溃(理论上不应该发生) FAIL() << "Expected test_null_pointer to cause a segmentation fault, but it did not."; } else { // 成功捕获到信号(SIGSEGV),测试通过 SUCCEED(); } // 恢复默认信号处理 std::signal(SIGSEGV, SIG_DFL); } // 测试数组越界访问 // 与空指针类似,数组越界访问也可能导致SIGSEGV或读取到垃圾数据。 // 测试方法同上,使用信号捕获。 TEST(ErrorsTest, TestArrayOutOfBoundsTriggersCrashOrUndefinedBehavior) { std::signal(SIGSEGV, signal_handler); if (setjmp(jump_buffer) == 0) { test_array_out_of_bounds(); // 注意:数组越界不一定总是立即导致SIGSEGV,可能只是读取到未定义的值。 // 因此,如果执行到这里,我们无法断言测试失败,因为行为是“未定义”的。 // 我们可以输出一个警告,但测试本身不能证明函数正确。 std::cout << "Warning: test_array_out_of_bounds did not cause a segmentation fault.\n"; std::cout << "This does not mean the function is correct; it exhibits undefined behavior.\n"; // 对于未定义行为,我们无法有确定的断言。这里我们选择让测试通过,但附上警告。 // 在实际项目中,这类错误应通过代码审查、静态分析或内存检查工具(如AddressSanitizer)来发现。 SUCCEED(); } else { // 成功捕获到信号 SUCCEED(); } std::signal(SIGSEGV, SIG_DFL); } // 测试未初始化变量 // 使用未初始化的变量是未定义行为,可能产生任意值,但通常不会直接导致程序崩溃。 // 因此,我们无法编写一个有确定断言的测试来验证其“错误性”。 // 这个测试主要是为了演示和文档化:该函数的行为是未定义的。 // 我们只能运行它,并观察输出(或没有输出)。 TEST(ErrorsTest, TestUninitializedVarExhibitsUndefinedBehavior) { // 由于行为未定义,我们无法预测输出。 // 我们仅仅调用函数,确保它不会意外崩溃(尽管崩溃也是未定义行为的一种可能)。 // 这里没有断言,因为对于未定义行为,没有“正确”的预期。 // 在实际测试中,我们可能希望用工具如Valgrind或MSVC的运行时检查来检测未初始化读取。 EXPECT_NO_FATAL_FAILURE(test_uninitialized_var()); // 至少确保没有gtest致命错误 // 注意:EXPECT_NO_FATAL_FAILURE 只检查gtest断言失败,不检查程序崩溃。 // 我们可以添加一个简单的输出说明 std::cout << "Note: test_uninitialized_var uses an uninitialized variable. Its behavior is undefined.\n"; } // 主函数 int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }