cdemo/tests/test_errors.cpp

91 lines
3.4 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "gtest/gtest.h"
#include "src/errors.cpp"
#include <iostream>
#include <csetjmp>
#include <csignal>
// 全局跳转点,用于处理信号
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();
}