cdemo/tests/test_errors.cpp

142 lines
4.5 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 <csignal>
#include <csetjmp>
// 信号处理跳转缓冲区,用于捕获崩溃
static jmp_buf jump_buffer;
// 信号处理函数
void signal_handler(int sig) {
(void)sig; // 抑制未使用参数警告
longjmp(jump_buffer, 1);
}
// 测试空指针解引用
TEST(ErrorsTest, TestNullPointerTriggersCrash) {
// 设置信号处理器来捕获段错误(SIGSEGV)
struct sigaction sa_old;
struct sigaction sa_new;
sa_new.sa_handler = signal_handler;
sigemptyset(&sa_new.sa_mask);
sa_new.sa_flags = 0;
// 保存旧的信号处理器并安装新的
sigaction(SIGSEGV, &sa_new, &sa_old);
// 使用 setjmp/longjmp 来捕获崩溃
if (setjmp(jump_buffer) == 0) {
// 尝试调用会崩溃的函数
test_null_pointer();
// 如果执行到这里,说明没有崩溃,测试失败
FAIL() << "Expected test_null_pointer() to cause a segmentation fault";
} else {
// 成功捕获到崩溃,测试通过
SUCCEED();
}
// 恢复旧的信号处理器
sigaction(SIGSEGV, &sa_old, nullptr);
}
// 测试数组越界访问
TEST(ErrorsTest, TestArrayOutOfBoundsTriggersCrash) {
// 设置信号处理器来捕获段错误(SIGSEGV)
struct sigaction sa_old;
struct sigaction sa_new;
sa_new.sa_handler = signal_handler;
sigemptyset(&sa_new.sa_mask);
sa_new.sa_flags = 0;
// 保存旧的信号处理器并安装新的
sigaction(SIGSEGV, &sa_new, &sa_old);
// 使用 setjmp/longjmp 来捕获崩溃
if (setjmp(jump_buffer) == 0) {
// 尝试调用会崩溃的函数
test_array_out_of_bounds();
// 如果执行到这里,说明没有崩溃,测试失败
FAIL() << "Expected test_array_out_of_bounds() to cause a segmentation fault";
} else {
// 成功捕获到崩溃,测试通过
SUCCEED();
}
// 恢复旧的信号处理器
sigaction(SIGSEGV, &sa_old, nullptr);
}
// 测试未初始化变量使用
// 注意:使用未初始化变量的行为是未定义的,可能不会立即崩溃
// 我们主要验证函数可以执行而不抛出异常(尽管行为未定义)
TEST(ErrorsTest, TestUninitializedVarExecutesWithoutCrash) {
// 设置信号处理器来捕获可能的崩溃
struct sigaction sa_old;
struct sigaction sa_new;
sa_new.sa_handler = signal_handler;
sigemptyset(&sa_new.sa_mask);
sa_new.sa_flags = 0;
// 保存旧的信号处理器并安装新的
sigaction(SIGSEGV, &sa_new, &sa_old);
// 使用 setjmp/longjmp 来捕获可能的崩溃
if (setjmp(jump_buffer) == 0) {
// 尝试调用函数
test_uninitialized_var();
// 如果执行到这里,说明没有崩溃
// 对于未初始化变量的使用,行为是未定义的,但通常不会立即崩溃
SUCCEED();
} else {
// 如果捕获到崩溃,也记录但不算失败(因为行为未定义)
ADD_FAILURE() << "test_uninitialized_var() caused a crash (undefined behavior)";
}
// 恢复旧的信号处理器
sigaction(SIGSEGV, &sa_old, nullptr);
}
// 边界条件测试:验证这些错误函数确实存在缺陷
// 这个测试验证正常代码不会崩溃
TEST(ErrorsTest, NormalCodeDoesNotCrash) {
// 正常的指针使用
int value = 42;
int* p = &value;
EXPECT_EQ(*p, 42);
// 正常的数组访问
int arr[3] = {1, 2, 3};
EXPECT_EQ(arr[0], 1);
EXPECT_EQ(arr[1], 2);
EXPECT_EQ(arr[2], 3);
// 正常的变量初始化
int val = 5;
if (val > 10) {
FAIL() << "This should not execute";
} else {
SUCCEED();
}
}
// 特殊场景:验证这些是真正的错误模式
TEST(ErrorsTest, ErrorPatternsAreDetected) {
// 这些测试验证了错误模式的存在
// 在实际项目中,应该修复这些错误而不是测试它们
// 测试1空指针解引用是严重错误
EXPECT_DEATH(test_null_pointer(), ".*") << "Null pointer dereference should cause program termination";
// 测试2数组越界是严重错误
EXPECT_DEATH(test_array_out_of_bounds(), ".*") << "Array out of bounds should cause program termination";
// 注意test_uninitialized_var 可能不会导致立即崩溃,
// 所以不使用 EXPECT_DEATH 测试它
}
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}