cdemo/tests/test_errors.cpp

106 lines
4.1 KiB
C++
Raw Permalink 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 <csignal>
#include <csetjmp>
// 用于捕获信号和异常的全局变量
static std::jmp_buf jump_buffer;
static volatile std::sig_atomic_t gSignalStatus;
// 信号处理函数
void signal_handler(int signal) {
gSignalStatus = signal;
std::longjmp(jump_buffer, 1);
}
namespace {
// 测试类,用于设置和恢复信号处理器
class SignalGuard {
public:
SignalGuard(int sig, void (*handler)(int)) : m_sig(sig), m_old_handler(std::signal(sig, handler)) {}
~SignalGuard() { std::signal(m_sig, m_old_handler); }
private:
int m_sig;
void (*m_old_handler)(int);
};
// 测试 test_null_pointer 函数
TEST(ErrorsTest, TestNullPointerTriggersSignal) {
// 安装 SIGSEGV 信号处理器
SignalGuard guard(SIGSEGV, signal_handler);
gSignalStatus = 0;
// 使用 setjmp/longjmp 来捕获信号后的跳转
if (setjmp(jump_buffer) == 0) {
// 尝试执行会触发段错误的函数
test_null_pointer();
// 如果执行到这里,说明没有触发信号,测试失败
FAIL() << "Expected test_null_pointer to cause a segmentation fault";
} else {
// 成功捕获到信号
EXPECT_EQ(gSignalStatus, SIGSEGV);
}
}
// 测试 test_array_out_of_bounds 函数
TEST(ErrorsTest, TestArrayOutOfBoundsTriggersSignal) {
// 安装 SIGSEGV 信号处理器
SignalGuard guard(SIGSEGV, signal_handler);
gSignalStatus = 0;
if (setjmp(jump_buffer) == 0) {
test_array_out_of_bounds();
FAIL() << "Expected test_array_out_of_bounds to cause a segmentation fault";
} else {
EXPECT_EQ(gSignalStatus, SIGSEGV);
}
}
// 测试 test_uninitialized_var 函数
// 注意:未初始化变量的行为是未定义的,可能不会崩溃,但结果不可预测。
// 我们无法可靠地测试其具体行为,但可以验证函数调用本身不会导致程序终止(如信号)。
// 然而,为了演示,我们仍然运行它,但不对其输出做任何断言,因为它是未定义的。
TEST(ErrorsTest, TestUninitializedVarRunsWithoutCrash) {
// 这个测试主要是为了确保函数可以被调用,而不导致程序崩溃(尽管行为未定义)。
// 由于未初始化变量的值是未定义的,我们无法断言其具体行为。
// 在某些配置下如调试模式变量可能被初始化为0但这不是保证的。
// 因此,我们只调用函数,不进行断言。
// 注意:这实际上不是一个好的单元测试,因为它没有验证任何确定的行为。
// 它只是为了演示如何“测试”一个具有未定义行为的函数。
// 在实际项目中,这样的函数应该被修复,而不是被测试。
test_uninitialized_var();
// 如果程序执行到这里,说明没有崩溃,测试通过。
// 我们无法对输出做任何有意义的断言。
SUCCEED();
}
// 额外的测试:验证正常数组访问不会崩溃(作为对比)
TEST(ErrorsTest, TestNormalArrayAccessDoesNotCrash) {
int arr[3] = {1, 2, 3};
EXPECT_EQ(arr[0], 1);
EXPECT_EQ(arr[1], 2);
EXPECT_EQ(arr[2], 3);
// 访问有效索引,不应崩溃
SUCCEED();
}
// 额外的测试:验证已初始化的指针解引用不会崩溃(作为对比)
TEST(ErrorsTest, TestValidPointerDereferenceDoesNotCrash) {
int value = 42;
int* p = &value;
EXPECT_EQ(*p, 42);
SUCCEED();
}
// 额外的测试:验证已初始化的变量行为可预测
TEST(ErrorsTest, TestInitializedVarBehaviorIsPredictable) {
int val = 15; // 明确初始化
if (val > 10) {
SUCCEED(); // 条件为真,符合预期
} else {
FAIL() << "Initialized variable should behave predictably";
}
}
}