diff --git a/tests/test_errors.cpp b/tests/test_errors.cpp new file mode 100644 index 0000000..84326f2 --- /dev/null +++ b/tests/test_errors.cpp @@ -0,0 +1,88 @@ +#include +#include +#include +#include +#include + +// 由于被测函数包含未定义行为(空指针解引用、数组越界、未初始化变量), +// 这些函数在正常执行时会导致程序崩溃或不可预测的结果。 +// 因此,测试用例的设计侧重于验证这些函数在特定条件下的行为, +// 例如通过信号处理或模拟环境来捕获崩溃,或者验证函数不会在非崩溃路径上产生意外输出。 +// 注意:直接调用这些函数会导致测试程序崩溃,因此测试用例使用子进程或信号处理来隔离。 + +// 辅助函数:捕获信号并验证 +void signal_handler(int sig) { + // 空实现,仅用于捕获信号 +} + +// 测试 test_null_pointer 函数 +// 由于该函数会解引用空指针,预期会导致 SIGSEGV 信号 +TEST(ErrorTest, NullPointerCausesSegfault) { + // 设置信号处理函数 + signal(SIGSEGV, signal_handler); + + // 使用 EXPECT_EXIT 宏来验证程序因 SIGSEGV 而退出 + // 注意:由于函数直接崩溃,无法正常返回,因此使用 EXPECT_EXIT + EXPECT_EXIT({ + test_null_pointer(); + }, ::testing::KilledBySignal(SIGSEGV), ""); +} + +// 测试 test_array_out_of_bounds 函数 +// 数组越界访问是未定义行为,可能不会立即崩溃,但通常会导致访问非法内存 +// 这里我们使用 EXPECT_EXIT 来捕获可能的 SIGSEGV,但并非所有实现都会崩溃 +// 因此,我们也可以验证函数不会产生意外输出(如果未崩溃) +TEST(ErrorTest, ArrayOutOfBoundsUndefinedBehavior) { + // 由于未定义行为,测试可能不稳定。这里我们尝试捕获 SIGSEGV + // 如果程序崩溃,测试通过;如果不崩溃,我们至少验证没有异常输出 + // 但更合理的做法是使用 EXPECT_EXIT 并允许 SIGSEGV + EXPECT_EXIT({ + test_array_out_of_bounds(); + }, ::testing::KilledBySignal(SIGSEGV), ""); +} + +// 测试 test_uninitialized_var 函数 +// 未初始化变量的使用也是未定义行为,可能不会立即崩溃 +// 我们使用 EXPECT_EXIT 来捕获可能的 SIGSEGV,但通常不会崩溃 +// 因此,我们也可以验证函数不会产生意外输出 +TEST(ErrorTest, UninitializedVarUndefinedBehavior) { + // 未初始化变量通常不会导致崩溃,但行为不可预测 + // 这里我们尝试捕获 SIGSEGV,但预期不会发生 + // 更合理的测试是验证函数不会产生异常输出 + testing::internal::CaptureStdout(); + test_uninitialized_var(); + std::string output = testing::internal::GetCapturedStdout(); + // 由于 val 未初始化,条件可能为真或假,输出可能为空或包含 "val > 10" + // 我们只验证没有异常发生(即函数正常返回) + EXPECT_TRUE(true); // 函数正常返回即视为通过 +} + +// 额外的测试:验证函数在非崩溃路径下的行为 +// 由于这些函数设计为演示错误,我们也可以测试它们是否按预期产生输出 +// 但注意:直接调用会导致崩溃,因此需要特殊处理 + +// 使用子进程测试 test_null_pointer +TEST(ErrorTest, NullPointerSubprocess) { + // 使用 EXPECT_EXIT 验证子进程因 SIGSEGV 退出 + EXPECT_EXIT({ + test_null_pointer(); + }, ::testing::KilledBySignal(SIGSEGV), ""); +} + +// 使用子进程测试 test_array_out_of_bounds +TEST(ErrorTest, ArrayOutOfBoundsSubprocess) { + // 使用 EXPECT_EXIT 验证子进程可能因 SIGSEGV 退出 + EXPECT_EXIT({ + test_array_out_of_bounds(); + }, ::testing::KilledBySignal(SIGSEGV), ""); +} + +// 使用子进程测试 test_uninitialized_var +TEST(ErrorTest, UninitializedVarSubprocess) { + // 未初始化变量通常不会导致崩溃,但行为不可预测 + // 我们只验证子进程正常退出(返回0) + EXPECT_EXIT({ + test_uninitialized_var(); + exit(0); + }, ::testing::ExitedWithCode(0), ""); +}