Compare commits
1 Commits
main
...
test_20260
| Author | SHA1 | Date |
|---|---|---|
|
|
bc0c807bfd |
|
|
@ -0,0 +1,80 @@
|
||||||
|
#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();
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue