cdemo/tests/test_errors.cpp

140 lines
4.9 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 <csetjmp>
#include <csignal>
// 全局变量用于信号处理
static std::jmp_buf jump_buffer;
static volatile sig_atomic_t gSignalStatus = 0;
// 信号处理函数
void signal_handler(int signal) {
gSignalStatus = signal;
std::longjmp(jump_buffer, 1);
}
// 测试夹具类
class ErrorsTest : public ::testing::Test {
protected:
void SetUp() override {
// 保存旧的信号处理器
old_sigsegv_handler = std::signal(SIGSEGV, signal_handler);
old_sigabrt_handler = std::signal(SIGABRT, signal_handler);
gSignalStatus = 0;
}
void TearDown() override {
// 恢复旧的信号处理器
std::signal(SIGSEGV, old_sigsegv_handler);
std::signal(SIGABRT, old_sigabrt_handler);
}
// 检查是否捕获到预期的信号
bool expectSignal(int expected_signal) {
if (setjmp(jump_buffer) == 0) {
// 第一次进入,执行可能崩溃的代码
return false;
} else {
// 从信号处理器跳转回来
return gSignalStatus == expected_signal;
}
}
private:
using SignalHandler = void (*)(int);
SignalHandler old_sigsegv_handler;
SignalHandler old_sigabrt_handler;
};
// 测试 test_null_pointer 函数
TEST_F(ErrorsTest, TestNullPointerTriggersSegmentationFault) {
// 这个测试期望函数触发段错误(SIGSEGV)
// 由于我们设置了信号处理器,测试不会崩溃
bool caught_signal = expectSignal(SIGSEGV);
if (!caught_signal) {
// 如果没有通过信号捕获,直接调用函数(这会导致测试进程崩溃)
// 但在我们的测试夹具中,这应该被信号处理器捕获
test_null_pointer();
}
// 验证我们捕获到了段错误信号
EXPECT_TRUE(caught_signal) << "Expected SIGSEGV signal from null pointer dereference";
}
TEST_F(ErrorsTest, TestNullPointerUndefinedBehavior) {
// 这个测试验证空指针解引用是未定义行为
// 在某些平台上,可能不会立即崩溃,但行为是未定义的
// 我们主要验证函数可以编译和链接
SUCCEED() << "test_null_pointer function exists and can be called";
}
// 测试 test_array_out_of_bounds 函数
TEST_F(ErrorsTest, TestArrayOutOfBoundsTriggersMemoryError) {
// 数组越界访问可能触发段错误(SIGSEGV)或其他内存错误
bool caught_signal = expectSignal(SIGSEGV);
if (!caught_signal) {
test_array_out_of_bounds();
}
// 数组越界是未定义行为,可能不会立即崩溃
// 但我们期望在大多数实现中会触发内存错误
if (caught_signal) {
EXPECT_TRUE(caught_signal) << "Expected memory error from array out of bounds access";
} else {
// 如果没有崩溃,记录警告
ADD_FAILURE() << "Array out of bounds access did not trigger immediate crash (undefined behavior)";
}
}
TEST_F(ErrorsTest, TestArrayOutOfBoundsUndefinedBehavior) {
// 验证数组越界访问是未定义行为
// 测试函数的存在性和可调用性
SUCCEED() << "test_array_out_of_bounds function exists and can be called";
}
// 测试 test_uninitialized_var 函数
TEST_F(ErrorsTest, TestUninitializedVarUndefinedBehavior) {
// 使用未初始化变量是未定义行为
// 这个测试主要验证函数可以编译和运行
// 由于行为未定义,我们无法预测具体输出
// 重定向std::cout以捕获输出
testing::internal::CaptureStdout();
// 调用函数 - 行为未定义,可能输出任何内容或不输出
test_uninitialized_var();
std::string output = testing::internal::GetCapturedStdout();
// 由于val未初始化其值不确定因此输出也不确定
// 我们只验证函数执行没有崩溃
SUCCEED() << "test_uninitialized_var executed without crash (output: '" << output << "')";
}
TEST_F(ErrorsTest, TestUninitializedVarRandomBehavior) {
// 多次调用函数,观察未初始化变量的随机行为
// 注意:这仍然是未定义行为,不仅仅是随机
std::set<std::string> outputs;
const int num_runs = 10;
for (int i = 0; i < num_runs; ++i) {
testing::internal::CaptureStdout();
test_uninitialized_var();
std::string output = testing::internal::GetCapturedStdout();
outputs.insert(output);
}
// 未初始化变量可能导致不同输出或相同输出
// 我们只记录观察到的行为
std::cout << "Observed " << outputs.size() << " different outputs from "
<< num_runs << " runs of test_uninitialized_var" << std::endl;
SUCCEED() << "test_uninitialized_var shows undefined behavior across multiple runs";
}
// 主函数
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}