Compare commits
1 Commits
main
...
test_20260
| Author | SHA1 | Date |
|---|---|---|
|
|
33df0ce250 |
|
|
@ -0,0 +1,113 @@
|
|||
#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, TestNullPointer) {
|
||||
// 设置信号处理程序以捕获段错误
|
||||
struct sigaction sa;
|
||||
struct sigaction old_sa;
|
||||
|
||||
sa.sa_handler = signal_handler;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = 0;
|
||||
|
||||
// 保存旧的信号处理程序
|
||||
sigaction(SIGSEGV, &sa, &old_sa);
|
||||
|
||||
// 设置跳转点
|
||||
if (setjmp(jump_buffer) == 0) {
|
||||
// 尝试调用会触发段错误的函数
|
||||
test_null_pointer();
|
||||
// 如果执行到这里,说明没有触发段错误
|
||||
FAIL() << "Expected segmentation fault but none occurred";
|
||||
} else {
|
||||
// 成功捕获到段错误
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
// 恢复旧的信号处理程序
|
||||
sigaction(SIGSEGV, &old_sa, nullptr);
|
||||
}
|
||||
|
||||
// 测试数组越界访问
|
||||
TEST(ErrorsTest, TestArrayOutOfBounds) {
|
||||
// 设置信号处理程序以捕获段错误
|
||||
struct sigaction sa;
|
||||
struct sigaction old_sa;
|
||||
|
||||
sa.sa_handler = signal_handler;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = 0;
|
||||
|
||||
// 保存旧的信号处理程序
|
||||
sigaction(SIGSEGV, &sa, &old_sa);
|
||||
|
||||
// 设置跳转点
|
||||
if (setjmp(jump_buffer) == 0) {
|
||||
// 尝试调用会触发段错误的函数
|
||||
test_array_out_of_bounds();
|
||||
// 如果执行到这里,说明没有触发段错误
|
||||
FAIL() << "Expected segmentation fault but none occurred";
|
||||
} else {
|
||||
// 成功捕获到段错误
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
// 恢复旧的信号处理程序
|
||||
sigaction(SIGSEGV, &old_sa, nullptr);
|
||||
}
|
||||
|
||||
// 测试未初始化变量使用
|
||||
TEST(ErrorsTest, TestUninitializedVar) {
|
||||
// 未初始化变量的行为是未定义的,可能不会立即崩溃
|
||||
// 我们只能验证函数可以执行而不崩溃
|
||||
// 多次运行以增加检测到问题的机会
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
// 设置信号处理程序以捕获可能的段错误
|
||||
struct sigaction sa;
|
||||
struct sigaction old_sa;
|
||||
|
||||
sa.sa_handler = signal_handler;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = 0;
|
||||
|
||||
// 保存旧的信号处理程序
|
||||
sigaction(SIGSEGV, &sa, &old_sa);
|
||||
|
||||
// 设置跳转点
|
||||
if (setjmp(jump_buffer) == 0) {
|
||||
// 尝试调用函数
|
||||
test_uninitialized_var();
|
||||
// 如果执行到这里,说明没有触发段错误
|
||||
// 这是可接受的,因为未初始化变量的行为是未定义的
|
||||
} else {
|
||||
// 如果捕获到段错误,记录但继续测试
|
||||
ADD_FAILURE() << "Segmentation fault occurred at iteration " << i;
|
||||
}
|
||||
|
||||
// 恢复旧的信号处理程序
|
||||
sigaction(SIGSEGV, &old_sa, nullptr);
|
||||
}
|
||||
|
||||
// 由于未初始化变量的行为是未定义的,我们无法做出确定的断言
|
||||
// 测试通过意味着函数可以执行而不一定意味着行为正确
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
// 主函数
|
||||
int main(int argc, char **argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
|
|
@ -0,0 +1,153 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include "test_errors.h"
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <cstdio>
|
||||
|
||||
// 模拟函数声明,用于测试 main 函数调用顺序
|
||||
namespace {
|
||||
int call_order[7] = {0};
|
||||
int call_index = 0;
|
||||
|
||||
void mock_test_null_pointer() { call_order[call_index++] = 1; }
|
||||
void mock_test_array_out_of_bounds() { call_order[call_index++] = 2; }
|
||||
void mock_test_uninitialized_var() { call_order[call_index++] = 3; }
|
||||
void mock_test_memory_leak() { call_order[call_index++] = 4; }
|
||||
void mock_test_double_free() { call_order[call_index++] = 5; }
|
||||
void mock_test_file_leak() { call_order[call_index++] = 6; }
|
||||
void mock_test_unused_code() { call_order[call_index++] = 7; }
|
||||
}
|
||||
|
||||
// 测试 main 函数的基本功能
|
||||
TEST(MainTest, MainFunctionCallsAllTestFunctions) {
|
||||
// 保存原始函数指针
|
||||
auto original_null_pointer = test_null_pointer;
|
||||
auto original_array_out_of_bounds = test_array_out_of_bounds;
|
||||
auto original_uninitialized_var = test_uninitialized_var;
|
||||
auto original_memory_leak = test_memory_leak;
|
||||
auto original_double_free = test_double_free;
|
||||
auto original_file_leak = test_file_leak;
|
||||
auto original_unused_code = test_unused_code;
|
||||
|
||||
// 替换为模拟函数
|
||||
test_null_pointer = mock_test_null_pointer;
|
||||
test_array_out_of_bounds = mock_test_array_out_of_bounds;
|
||||
test_uninitialized_var = mock_test_uninitialized_var;
|
||||
test_memory_leak = mock_test_memory_leak;
|
||||
test_double_free = mock_test_double_free;
|
||||
test_file_leak = mock_test_file_leak;
|
||||
test_unused_code = mock_test_unused_code;
|
||||
|
||||
// 重置调用记录
|
||||
call_index = 0;
|
||||
for (int i = 0; i < 7; i++) {
|
||||
call_order[i] = 0;
|
||||
}
|
||||
|
||||
// 调用 main 函数
|
||||
int result = main();
|
||||
|
||||
// 验证返回值
|
||||
EXPECT_EQ(result, 0);
|
||||
|
||||
// 验证所有函数都被调用
|
||||
EXPECT_EQ(call_index, 7);
|
||||
|
||||
// 验证调用顺序(按 main 函数中的顺序)
|
||||
EXPECT_EQ(call_order[0], 1); // test_null_pointer
|
||||
EXPECT_EQ(call_order[1], 2); // test_array_out_of_bounds
|
||||
EXPECT_EQ(call_order[2], 3); // test_uninitialized_var
|
||||
EXPECT_EQ(call_order[3], 4); // test_memory_leak
|
||||
EXPECT_EQ(call_order[4], 5); // test_double_free
|
||||
EXPECT_EQ(call_order[5], 6); // test_file_leak
|
||||
EXPECT_EQ(call_order[6], 7); // test_unused_code
|
||||
|
||||
// 恢复原始函数
|
||||
test_null_pointer = original_null_pointer;
|
||||
test_array_out_of_bounds = original_array_out_of_bounds;
|
||||
test_uninitialized_var = original_uninitialized_var;
|
||||
test_memory_leak = original_memory_leak;
|
||||
test_double_free = original_double_free;
|
||||
test_file_leak = original_file_leak;
|
||||
test_unused_code = original_unused_code;
|
||||
}
|
||||
|
||||
// 测试 main 函数在异常情况下的行为
|
||||
TEST(MainTest, MainFunctionReturnsZeroOnNormalExecution) {
|
||||
// 直接测试 main 函数返回值
|
||||
int result = main();
|
||||
|
||||
// main 函数应该返回 0
|
||||
EXPECT_EQ(result, 0);
|
||||
}
|
||||
|
||||
// 测试 main 函数不会抛出异常
|
||||
TEST(MainTest, MainFunctionDoesNotThrow) {
|
||||
// 确保 main 函数不会抛出异常
|
||||
EXPECT_NO_THROW({
|
||||
main();
|
||||
});
|
||||
}
|
||||
|
||||
// 测试 main 函数多次调用的稳定性
|
||||
TEST(MainTest, MainFunctionCanBeCalledMultipleTimes) {
|
||||
// 多次调用 main 函数,确保不会崩溃
|
||||
for (int i = 0; i < 3; i++) {
|
||||
EXPECT_NO_THROW({
|
||||
int result = main();
|
||||
EXPECT_EQ(result, 0);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 测试 main 函数在内存受限环境下的行为
|
||||
TEST(MainTest, MainFunctionHandlesMemoryConstraints) {
|
||||
// 这个测试验证 main 函数在正常内存条件下能正常工作
|
||||
// 注意:我们无法直接模拟内存不足,但可以验证函数不会过度分配内存
|
||||
|
||||
// 记录初始内存状态(简化版本)
|
||||
std::ifstream status_file("/proc/self/status");
|
||||
long initial_vm_size = 0;
|
||||
|
||||
if (status_file.is_open()) {
|
||||
std::string line;
|
||||
while (std::getline(status_file, line)) {
|
||||
if (line.find("VmSize:") == 0) {
|
||||
sscanf(line.c_str(), "VmSize: %ld", &initial_vm_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 调用 main 函数
|
||||
int result = main();
|
||||
EXPECT_EQ(result, 0);
|
||||
|
||||
// 检查内存使用情况(简化检查)
|
||||
// 注意:由于测试函数可能分配内存,我们只做基本验证
|
||||
if (initial_vm_size > 0) {
|
||||
std::ifstream status_file2("/proc/self/status");
|
||||
long final_vm_size = 0;
|
||||
|
||||
if (status_file2.is_open()) {
|
||||
std::string line;
|
||||
while (std::getline(status_file2, line)) {
|
||||
if (line.find("VmSize:") == 0) {
|
||||
sscanf(line.c_str(), "VmSize: %ld", &final_vm_size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 验证内存使用在合理范围内(允许一定增长)
|
||||
EXPECT_LE(final_vm_size, initial_vm_size * 2);
|
||||
}
|
||||
}
|
||||
|
||||
// 主函数,运行所有测试
|
||||
int main(int argc, char **argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
#include "gtest/gtest.h"
|
||||
#include "src/memory.cpp"
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
// 测试 test_memory_leak 函数
|
||||
// 注意:内存泄漏本身无法通过常规断言直接验证,但可以通过工具检测。
|
||||
// 此测试主要验证函数能正常执行而不崩溃。
|
||||
TEST(MemoryTest, MemoryLeakFunctionRuns) {
|
||||
// 调用函数,验证其能正常执行完毕(不崩溃)。
|
||||
// 内存泄漏的检测通常依赖外部工具(如Valgrind, AddressSanitizer)。
|
||||
EXPECT_NO_FATAL_FAILURE(test_memory_leak());
|
||||
}
|
||||
|
||||
// 测试 test_double_free 函数
|
||||
// 重复释放会导致未定义行为,通常是程序崩溃。
|
||||
// 在启用特定工具(如AddressSanitizer)时,可以捕获此错误。
|
||||
// 此测试在常规环境下可能不稳定,标记为可能崩溃。
|
||||
TEST(MemoryTest, DoubleFreeFunctionBehavior) {
|
||||
// 由于重复释放是未定义行为,我们主要测试函数是否能被调用。
|
||||
// 实际测试中,应结合 AddressSanitizer 等工具运行。
|
||||
// 这里仅作为演示,调用函数。
|
||||
// 注意:此测试在没有保护措施的环境下可能崩溃。
|
||||
EXPECT_NO_FATAL_FAILURE(test_double_free());
|
||||
}
|
||||
|
||||
// 测试 test_file_leak 函数
|
||||
// 验证文件被创建,并且函数执行后文件句柄泄漏(无法直接断言)。
|
||||
// 可以通过检查文件是否存在来间接验证部分行为。
|
||||
TEST(MemoryTest, FileLeakFunctionCreatesFile) {
|
||||
const std::string filename = "test.txt";
|
||||
// 确保测试前文件不存在,避免干扰。
|
||||
if (fs::exists(filename)) {
|
||||
fs::remove(filename);
|
||||
}
|
||||
|
||||
// 调用函数,应该创建文件。
|
||||
EXPECT_NO_FATAL_FAILURE(test_file_leak());
|
||||
|
||||
// 验证文件确实被创建了。
|
||||
EXPECT_TRUE(fs::exists(filename)) << "File should be created by test_file_leak.";
|
||||
|
||||
// 清理:删除测试文件,避免累积。
|
||||
// 注意:由于函数没有关闭文件,在某些系统上直接删除可能失败或有问题。
|
||||
// 这里尝试删除,但主要目的是验证文件创建。
|
||||
try {
|
||||
fs::remove(filename);
|
||||
} catch (...) {
|
||||
// 忽略删除错误
|
||||
}
|
||||
}
|
||||
|
||||
// 边界/异常测试:这些函数没有参数,因此边界测试不直接适用。
|
||||
// 但可以测试在多次调用下的行为(虽然不推荐,因为会累积泄漏)。
|
||||
TEST(MemoryTest, MultipleCallsDoNotCrash) {
|
||||
// 多次调用,验证不会因为累积的未定义行为立即崩溃。
|
||||
// 这是一个压力测试,但结果不可预测。
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
EXPECT_NO_FATAL_FAILURE(test_memory_leak());
|
||||
EXPECT_NO_FATAL_FAILURE(test_double_free());
|
||||
EXPECT_NO_FATAL_FAILURE(test_file_leak());
|
||||
// 清理文件,避免重复创建失败。
|
||||
try { fs::remove("test.txt"); } catch (...) {}
|
||||
}
|
||||
}
|
||||
|
||||
// 特殊场景:与内存/文件泄漏检测工具结合使用的说明性测试。
|
||||
// 此测试实际上不运行有问题的函数,而是说明正确的模式。
|
||||
TEST(MemoryTest, CorrectPatternForComparison) {
|
||||
// 正确分配和释放内存
|
||||
{
|
||||
int* data = new int[100];
|
||||
delete[] data; // 正确释放
|
||||
data = nullptr;
|
||||
}
|
||||
|
||||
// 正确打开和关闭文件
|
||||
{
|
||||
FILE* fp = fopen("correct_test.txt", "w");
|
||||
ASSERT_NE(fp, nullptr) << "Failed to open file correctly.";
|
||||
fclose(fp); // 正确关闭
|
||||
}
|
||||
|
||||
// 清理正确测试创建的文件
|
||||
fs::remove("correct_test.txt");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
Loading…
Reference in New Issue