cdemo/tests/test_errors.cpp

81 lines
3.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 <csignal>
#include <csetjmp>
// 用于捕获信号如SIGSEGV的全局跳转点
static jmp_buf jump_buffer;
// 信号处理函数
void signal_handler(int sig) {
(void)sig; // 抑制未使用参数的警告
longjmp(jump_buffer, 1);
}
// 测试空指针解引用
// 注意:此函数设计为会崩溃,因此测试需要捕获信号或异常。
// 由于直接测试崩溃行为在单元测试中不典型,我们通常期望这类错误在代码审查或静态分析中被发现。
// 这里我们演示一种通过信号处理来“捕获”崩溃的方法,但这更多是演示性质,并非标准单元测试实践。
TEST(ErrorsTest, TestNullPointerTriggersCrash) {
// 安装信号处理器
std::signal(SIGSEGV, signal_handler);
// 设置跳转点。如果setjmp返回0表示首次设置。如果返回非0表示从longjmp跳回。
if (setjmp(jump_buffer) == 0) {
// 尝试执行会崩溃的函数
test_null_pointer();
// 如果执行到这里,说明没有触发崩溃(理论上不应该发生)
FAIL() << "Expected test_null_pointer to cause a segmentation fault, but it did not.";
} else {
// 成功捕获到信号SIGSEGV测试通过
SUCCEED();
}
// 恢复默认信号处理
std::signal(SIGSEGV, SIG_DFL);
}
// 测试数组越界访问
// 与空指针类似数组越界访问也可能导致SIGSEGV或读取到垃圾数据。
// 测试方法同上,使用信号捕获。
TEST(ErrorsTest, TestArrayOutOfBoundsTriggersCrashOrUndefinedBehavior) {
std::signal(SIGSEGV, signal_handler);
if (setjmp(jump_buffer) == 0) {
test_array_out_of_bounds();
// 注意数组越界不一定总是立即导致SIGSEGV可能只是读取到未定义的值。
// 因此,如果执行到这里,我们无法断言测试失败,因为行为是“未定义”的。
// 我们可以输出一个警告,但测试本身不能证明函数正确。
std::cout << "Warning: test_array_out_of_bounds did not cause a segmentation fault.\n";
std::cout << "This does not mean the function is correct; it exhibits undefined behavior.\n";
// 对于未定义行为,我们无法有确定的断言。这里我们选择让测试通过,但附上警告。
// 在实际项目中这类错误应通过代码审查、静态分析或内存检查工具如AddressSanitizer来发现。
SUCCEED();
} else {
// 成功捕获到信号
SUCCEED();
}
std::signal(SIGSEGV, SIG_DFL);
}
// 测试未初始化变量
// 使用未初始化的变量是未定义行为,可能产生任意值,但通常不会直接导致程序崩溃。
// 因此,我们无法编写一个有确定断言的测试来验证其“错误性”。
// 这个测试主要是为了演示和文档化:该函数的行为是未定义的。
// 我们只能运行它,并观察输出(或没有输出)。
TEST(ErrorsTest, TestUninitializedVarExhibitsUndefinedBehavior) {
// 由于行为未定义,我们无法预测输出。
// 我们仅仅调用函数,确保它不会意外崩溃(尽管崩溃也是未定义行为的一种可能)。
// 这里没有断言,因为对于未定义行为,没有“正确”的预期。
// 在实际测试中我们可能希望用工具如Valgrind或MSVC的运行时检查来检测未初始化读取。
EXPECT_NO_FATAL_FAILURE(test_uninitialized_var()); // 至少确保没有gtest致命错误
// 注意EXPECT_NO_FATAL_FAILURE 只检查gtest断言失败不检查程序崩溃。
// 我们可以添加一个简单的输出说明
std::cout << "Note: test_uninitialized_var uses an uninitialized variable. Its behavior is undefined.\n";
}
// 主函数
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}