diff --git a/tests/test_errors.cpp b/tests/test_errors.cpp new file mode 100644 index 0000000..3ac3a7b --- /dev/null +++ b/tests/test_errors.cpp @@ -0,0 +1,80 @@ +#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(); +}