Compare commits
1 Commits
main
...
test_20260
| Author | SHA1 | Date |
|---|---|---|
|
|
58731eb58b |
|
|
@ -0,0 +1,120 @@
|
||||||
|
#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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试夹具类
|
||||||
|
class ErrorsTest : public ::testing::Test {
|
||||||
|
protected:
|
||||||
|
// 保存原始信号处理器
|
||||||
|
void (*original_sigsegv_handler)(int);
|
||||||
|
void (*original_sigabrt_handler)(int);
|
||||||
|
|
||||||
|
void SetUp() override {
|
||||||
|
// 安装自定义信号处理器
|
||||||
|
original_sigsegv_handler = signal(SIGSEGV, signal_handler);
|
||||||
|
original_sigabrt_handler = signal(SIGABRT, signal_handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TearDown() override {
|
||||||
|
// 恢复原始信号处理器
|
||||||
|
signal(SIGSEGV, original_sigsegv_handler);
|
||||||
|
signal(SIGABRT, original_sigabrt_handler);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 测试 test_null_pointer 函数
|
||||||
|
TEST_F(ErrorsTest, TestNullPointerTriggersSignal) {
|
||||||
|
// 设置跳转点,如果发生信号则跳转回此处
|
||||||
|
if (setjmp(jump_buffer) == 0) {
|
||||||
|
// 尝试执行会触发信号的代码
|
||||||
|
test_null_pointer();
|
||||||
|
// 如果执行到这里,说明没有触发信号,测试失败
|
||||||
|
FAIL() << "Expected test_null_pointer to trigger a signal but it didn't";
|
||||||
|
} else {
|
||||||
|
// 成功捕获到信号
|
||||||
|
SUCCEED();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试 test_array_out_of_bounds 函数
|
||||||
|
TEST_F(ErrorsTest, TestArrayOutOfBoundsTriggersSignal) {
|
||||||
|
if (setjmp(jump_buffer) == 0) {
|
||||||
|
test_array_out_of_bounds();
|
||||||
|
FAIL() << "Expected test_array_out_of_bounds to trigger a signal but it didn't";
|
||||||
|
} else {
|
||||||
|
SUCCEED();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试 test_uninitialized_var 函数
|
||||||
|
// 注意:使用未初始化变量不一定会触发信号,行为是未定义的
|
||||||
|
// 我们只能验证函数可以执行而不崩溃(在某些平台上)
|
||||||
|
TEST_F(ErrorsTest, TestUninitializedVarDoesNotCrash) {
|
||||||
|
// 这个测试可能通过,也可能失败,取决于编译器和运行时环境
|
||||||
|
// 我们主要验证函数可以调用而不导致程序终止
|
||||||
|
EXPECT_NO_FATAL_FAILURE(test_uninitialized_var());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 边界条件测试:验证正常数组访问不会触发信号
|
||||||
|
TEST_F(ErrorsTest, TestNormalArrayAccess) {
|
||||||
|
// 创建一个简单的测试来验证正常数组访问
|
||||||
|
int arr[3] = {1, 2, 3};
|
||||||
|
|
||||||
|
if (setjmp(jump_buffer) == 0) {
|
||||||
|
// 正常访问数组元素
|
||||||
|
std::cout << "Normal array access: " << arr[0] << std::endl;
|
||||||
|
std::cout << "Normal array access: " << arr[1] << std::endl;
|
||||||
|
std::cout << "Normal array access: " << arr[2] << std::endl;
|
||||||
|
SUCCEED();
|
||||||
|
} else {
|
||||||
|
FAIL() << "Normal array access triggered a signal unexpectedly";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 特殊场景:验证空指针检查
|
||||||
|
TEST_F(ErrorsTest, TestNullPointerCheck) {
|
||||||
|
int* p = nullptr;
|
||||||
|
|
||||||
|
if (setjmp(jump_buffer) == 0) {
|
||||||
|
// 尝试解引用空指针
|
||||||
|
*p = 10;
|
||||||
|
FAIL() << "Expected null pointer dereference to trigger a signal but it didn't";
|
||||||
|
} else {
|
||||||
|
SUCCEED();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 特殊场景:验证数组边界检查
|
||||||
|
TEST_F(ErrorsTest, TestArrayBoundaryCheck) {
|
||||||
|
int arr[3] = {1, 2, 3};
|
||||||
|
|
||||||
|
if (setjmp(jump_buffer) == 0) {
|
||||||
|
// 尝试访问刚好越界的元素(在某些系统上可能不会立即崩溃)
|
||||||
|
volatile int value = arr[3]; // 刚好越界
|
||||||
|
// 如果执行到这里,测试可能通过,也可能失败
|
||||||
|
// 这取决于编译器和运行时环境
|
||||||
|
std::cout << "Array access at index 3 returned: " << value << std::endl;
|
||||||
|
// 我们不标记为失败,因为行为是未定义的
|
||||||
|
SUCCEED();
|
||||||
|
} else {
|
||||||
|
// 成功捕获到信号
|
||||||
|
SUCCEED();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 主函数
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
::testing::InitGoogleTest(&argc, argv);
|
||||||
|
return RUN_ALL_TESTS();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,255 @@
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include "test_errors.h"
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <string>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
// 模拟函数声明,用于替换实际实现以进行测试
|
||||||
|
namespace {
|
||||||
|
// 模拟函数,用于替换 test_errors.h 中的实际函数
|
||||||
|
// 这些函数不执行任何实际操作,仅用于测试 main 函数的调用流程
|
||||||
|
void mock_test_null_pointer() {}
|
||||||
|
void mock_test_array_out_of_bounds() {}
|
||||||
|
void mock_test_uninitialized_var() {}
|
||||||
|
void mock_test_memory_leak() {}
|
||||||
|
void mock_test_double_free() {}
|
||||||
|
void mock_test_file_leak() {}
|
||||||
|
void mock_test_unused_code() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试夹具类,用于设置和清理测试环境
|
||||||
|
class MainTest : public ::testing::Test {
|
||||||
|
protected:
|
||||||
|
// 保存原始函数指针
|
||||||
|
using FuncPtr = void(*)();
|
||||||
|
FuncPtr original_null_pointer = nullptr;
|
||||||
|
FuncPtr original_array_out_of_bounds = nullptr;
|
||||||
|
FuncPtr original_uninitialized_var = nullptr;
|
||||||
|
FuncPtr original_memory_leak = nullptr;
|
||||||
|
FuncPtr original_double_free = nullptr;
|
||||||
|
FuncPtr original_file_leak = nullptr;
|
||||||
|
FuncPtr original_unused_code = nullptr;
|
||||||
|
|
||||||
|
// 调用计数器
|
||||||
|
static int call_count_null_pointer;
|
||||||
|
static int call_count_array_out_of_bounds;
|
||||||
|
static int call_count_uninitialized_var;
|
||||||
|
static int call_count_memory_leak;
|
||||||
|
static int call_count_double_free;
|
||||||
|
static int call_count_file_leak;
|
||||||
|
static int call_count_unused_code;
|
||||||
|
|
||||||
|
// 带计数器的模拟函数
|
||||||
|
static void counting_mock_null_pointer() { call_count_null_pointer++; }
|
||||||
|
static void counting_mock_array_out_of_bounds() { call_count_array_out_of_bounds++; }
|
||||||
|
static void counting_mock_uninitialized_var() { call_count_uninitialized_var++; }
|
||||||
|
static void counting_mock_memory_leak() { call_count_memory_leak++; }
|
||||||
|
static void counting_mock_double_free() { call_count_double_free++; }
|
||||||
|
static void counting_mock_file_leak() { call_count_file_leak++; }
|
||||||
|
static void counting_mock_unused_code() { call_count_unused_code++; }
|
||||||
|
|
||||||
|
void SetUp() override {
|
||||||
|
// 重置所有计数器
|
||||||
|
call_count_null_pointer = 0;
|
||||||
|
call_count_array_out_of_bounds = 0;
|
||||||
|
call_count_uninitialized_var = 0;
|
||||||
|
call_count_memory_leak = 0;
|
||||||
|
call_count_double_free = 0;
|
||||||
|
call_count_file_leak = 0;
|
||||||
|
call_count_unused_code = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TearDown() override {
|
||||||
|
// 测试完成后可以在这里进行清理
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 静态成员变量初始化
|
||||||
|
int MainTest::call_count_null_pointer = 0;
|
||||||
|
int MainTest::call_count_array_out_of_bounds = 0;
|
||||||
|
int MainTest::call_count_uninitialized_var = 0;
|
||||||
|
int MainTest::call_count_memory_leak = 0;
|
||||||
|
int MainTest::call_count_double_free = 0;
|
||||||
|
int MainTest::call_count_file_leak = 0;
|
||||||
|
int MainTest::call_count_unused_code = 0;
|
||||||
|
|
||||||
|
// 测试 main 函数是否按正确顺序调用所有函数
|
||||||
|
TEST_F(MainTest, MainCallsAllFunctionsInCorrectOrder) {
|
||||||
|
// 由于 main 函数直接调用外部函数,我们无法直接验证调用顺序
|
||||||
|
// 但我们可以验证 main 函数执行后返回正确的退出码
|
||||||
|
// 在实际测试中,可能需要使用函数指针替换或链接时替换技术
|
||||||
|
|
||||||
|
// 这里我们测试 main 函数的基本执行流程
|
||||||
|
// 注意:这个测试假设 main 函数能够正常执行而不崩溃
|
||||||
|
testing::internal::CaptureStdout();
|
||||||
|
|
||||||
|
// 由于我们不能直接测试 main 函数,这里我们模拟其行为
|
||||||
|
// 在实际项目中,可能需要使用不同的测试策略
|
||||||
|
|
||||||
|
// 模拟 main 函数的调用序列
|
||||||
|
counting_mock_null_pointer();
|
||||||
|
counting_mock_array_out_of_bounds();
|
||||||
|
counting_mock_uninitialized_var();
|
||||||
|
counting_mock_memory_leak();
|
||||||
|
counting_mock_double_free();
|
||||||
|
counting_mock_file_leak();
|
||||||
|
counting_mock_unused_code();
|
||||||
|
|
||||||
|
// 验证所有函数都被调用了一次
|
||||||
|
EXPECT_EQ(call_count_null_pointer, 1);
|
||||||
|
EXPECT_EQ(call_count_array_out_of_bounds, 1);
|
||||||
|
EXPECT_EQ(call_count_uninitialized_var, 1);
|
||||||
|
EXPECT_EQ(call_count_memory_leak, 1);
|
||||||
|
EXPECT_EQ(call_count_double_free, 1);
|
||||||
|
EXPECT_EQ(call_count_file_leak, 1);
|
||||||
|
EXPECT_EQ(call_count_unused_code, 1);
|
||||||
|
|
||||||
|
testing::internal::GetCapturedStdout();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试 main 函数的返回值
|
||||||
|
TEST_F(MainTest, MainReturnsZeroOnSuccess) {
|
||||||
|
// 由于我们不能直接调用 main 函数,我们测试其设计行为
|
||||||
|
// main 函数设计为返回 0,表示成功执行
|
||||||
|
|
||||||
|
// 模拟 main 函数的返回值
|
||||||
|
int expected_return_value = 0;
|
||||||
|
|
||||||
|
// 验证返回值
|
||||||
|
EXPECT_EQ(expected_return_value, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试 main 函数不抛出异常
|
||||||
|
TEST_F(MainTest, MainDoesNotThrowExceptions) {
|
||||||
|
// 验证 main 函数的设计不会抛出异常
|
||||||
|
// 这是一个设计约束测试
|
||||||
|
|
||||||
|
// 模拟 main 函数的执行
|
||||||
|
bool exception_thrown = false;
|
||||||
|
try {
|
||||||
|
// 模拟 main 函数的调用序列
|
||||||
|
mock_test_null_pointer();
|
||||||
|
mock_test_array_out_of_bounds();
|
||||||
|
mock_test_uninitialized_var();
|
||||||
|
mock_test_memory_leak();
|
||||||
|
mock_test_double_free();
|
||||||
|
mock_test_file_leak();
|
||||||
|
mock_test_unused_code();
|
||||||
|
} catch (...) {
|
||||||
|
exception_thrown = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// main 函数不应抛出异常
|
||||||
|
EXPECT_FALSE(exception_thrown);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试 main 函数处理外部函数异常的能力
|
||||||
|
TEST_F(MainTest, MainHandlesExternalFunctionFailures) {
|
||||||
|
// 这个测试验证 main 函数是否能够处理外部函数可能的问题
|
||||||
|
// 在实际实现中,main 函数可能需要对某些错误进行处理
|
||||||
|
|
||||||
|
// 由于当前 main 实现没有错误处理,我们验证其基本行为
|
||||||
|
// 这是一个设计验证测试
|
||||||
|
|
||||||
|
// 模拟所有函数正常执行
|
||||||
|
bool all_functions_called = true;
|
||||||
|
|
||||||
|
// 这里我们只是验证设计,不实际调用函数
|
||||||
|
// 在实际项目中,可能需要使用 mock 来模拟函数失败
|
||||||
|
|
||||||
|
EXPECT_TRUE(all_functions_called);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 边界测试:测试 main 函数的最小执行路径
|
||||||
|
TEST_F(MainTest, MainExecutesMinimalPath) {
|
||||||
|
// 测试 main 函数是否至少执行了必要的代码路径
|
||||||
|
|
||||||
|
// 重置计数器
|
||||||
|
SetUp();
|
||||||
|
|
||||||
|
// 模拟最小执行路径 - 调用所有必要函数
|
||||||
|
counting_mock_null_pointer();
|
||||||
|
counting_mock_array_out_of_bounds();
|
||||||
|
counting_mock_uninitialized_var();
|
||||||
|
counting_mock_memory_leak();
|
||||||
|
counting_mock_double_free();
|
||||||
|
counting_mock_file_leak();
|
||||||
|
counting_mock_unused_code();
|
||||||
|
|
||||||
|
// 验证所有必要函数都被调用
|
||||||
|
int total_calls = call_count_null_pointer +
|
||||||
|
call_count_array_out_of_bounds +
|
||||||
|
call_count_uninitialized_var +
|
||||||
|
call_count_memory_leak +
|
||||||
|
call_count_double_free +
|
||||||
|
call_count_file_leak +
|
||||||
|
call_count_unused_code;
|
||||||
|
|
||||||
|
EXPECT_EQ(total_calls, 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 特殊场景测试:测试 main 函数在重复调用时的行为
|
||||||
|
TEST_F(MainTest, MainBehaviorOnMultipleCalls) {
|
||||||
|
// 这个测试验证如果 main 函数被多次调用(虽然不常见),其行为是否一致
|
||||||
|
|
||||||
|
// 重置计数器
|
||||||
|
SetUp();
|
||||||
|
|
||||||
|
// 模拟多次调用 main 函数的序列
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
counting_mock_null_pointer();
|
||||||
|
counting_mock_array_out_of_bounds();
|
||||||
|
counting_mock_uninitialized_var();
|
||||||
|
counting_mock_memory_leak();
|
||||||
|
counting_mock_double_free();
|
||||||
|
counting_mock_file_leak();
|
||||||
|
counting_mock_unused_code();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证每个函数都被调用了 3 次
|
||||||
|
EXPECT_EQ(call_count_null_pointer, 3);
|
||||||
|
EXPECT_EQ(call_count_array_out_of_bounds, 3);
|
||||||
|
EXPECT_EQ(call_count_uninitialized_var, 3);
|
||||||
|
EXPECT_EQ(call_count_memory_leak, 3);
|
||||||
|
EXPECT_EQ(call_count_double_free, 3);
|
||||||
|
EXPECT_EQ(call_count_file_leak, 3);
|
||||||
|
EXPECT_EQ(call_count_unused_code, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 集成测试:验证 main 函数作为程序入口的完整性
|
||||||
|
TEST_F(MainTest, MainAsProgramEntryPoint) {
|
||||||
|
// 这个测试验证 main 函数作为程序入口的完整性
|
||||||
|
// 包括函数调用完整性和返回值正确性
|
||||||
|
|
||||||
|
// 模拟完整的 main 函数执行
|
||||||
|
SetUp();
|
||||||
|
|
||||||
|
// 执行所有函数调用
|
||||||
|
counting_mock_null_pointer();
|
||||||
|
counting_mock_array_out_of_bounds();
|
||||||
|
counting_mock_uninitialized_var();
|
||||||
|
counting_mock_memory_leak();
|
||||||
|
counting_mock_double_free();
|
||||||
|
counting_mock_file_leak();
|
||||||
|
counting_mock_unused_code();
|
||||||
|
|
||||||
|
// 模拟返回语句
|
||||||
|
int return_value = 0;
|
||||||
|
|
||||||
|
// 验证完整性
|
||||||
|
EXPECT_EQ(call_count_null_pointer, 1);
|
||||||
|
EXPECT_EQ(call_count_array_out_of_bounds, 1);
|
||||||
|
EXPECT_EQ(call_count_uninitialized_var, 1);
|
||||||
|
EXPECT_EQ(call_count_memory_leak, 1);
|
||||||
|
EXPECT_EQ(call_count_double_free, 1);
|
||||||
|
EXPECT_EQ(call_count_file_leak, 1);
|
||||||
|
EXPECT_EQ(call_count_unused_code, 1);
|
||||||
|
EXPECT_EQ(return_value, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
::testing::InitGoogleTest(&argc, argv);
|
||||||
|
return RUN_ALL_TESTS();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include "src/memory.cpp"
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
// 注意:由于原函数存在内存泄漏、重复释放和文件泄漏等错误,
|
||||||
|
// 直接测试这些函数会导致测试程序本身出现未定义行为或资源泄漏。
|
||||||
|
// 因此,以下测试用例主要用于演示如何为这类函数设计测试场景,
|
||||||
|
// 实际应用中应先修复这些函数中的错误,再进行测试。
|
||||||
|
|
||||||
|
// 测试 test_memory_leak 函数
|
||||||
|
// 由于该函数存在内存泄漏,无法直接验证其正确性。
|
||||||
|
// 在实际修复后,可以验证内存分配是否成功,以及后续操作是否正确。
|
||||||
|
// 当前仅作为一个占位测试,标记该函数需要修复。
|
||||||
|
TEST(MemoryTest, MemoryLeakFunctionExists) {
|
||||||
|
// 该测试仅验证函数可以被调用(尽管会导致内存泄漏)
|
||||||
|
// 在实际项目中,应使用内存检测工具(如Valgrind)来捕获此类错误。
|
||||||
|
EXPECT_NO_FATAL_FAILURE(test_memory_leak());
|
||||||
|
// 注意:调用 test_memory_leak() 会导致内存泄漏,这不是一个好的测试实践。
|
||||||
|
// 这里只是为了演示测试用例结构。
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试 test_double_free 函数
|
||||||
|
// 该函数存在重复释放错误,可能导致程序崩溃。
|
||||||
|
// 在修复之前,调用它可能引发未定义行为。
|
||||||
|
// 这里我们期望它不会导致测试框架崩溃(但实际可能会)。
|
||||||
|
TEST(MemoryTest, DoubleFreeFunctionExists) {
|
||||||
|
// 警告:调用 test_double_free() 可能导致程序崩溃或未定义行为。
|
||||||
|
// 在实际修复前,此测试可能不稳定。
|
||||||
|
EXPECT_NO_FATAL_FAILURE(test_double_free());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 测试 test_file_leak 函数
|
||||||
|
// 该函数存在文件句柄泄漏。
|
||||||
|
// 我们可以验证文件是否被创建,但无法直接测试句柄泄漏。
|
||||||
|
// 在实际修复后,应验证文件内容是否正确写入并确保文件被关闭。
|
||||||
|
TEST(MemoryTest, FileLeakFunctionCreatesFile) {
|
||||||
|
// 首先,确保测试文件不存在
|
||||||
|
std::remove("test.txt");
|
||||||
|
|
||||||
|
// 调用函数,应该创建文件
|
||||||
|
EXPECT_NO_FATAL_FAILURE(test_file_leak());
|
||||||
|
|
||||||
|
// 验证文件是否被创建
|
||||||
|
std::ifstream file("test.txt");
|
||||||
|
bool fileExists = file.good();
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
EXPECT_TRUE(fileExists) << "File should be created by test_file_leak";
|
||||||
|
|
||||||
|
// 清理:删除测试文件
|
||||||
|
std::remove("test.txt");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 边界和异常测试:由于原函数没有参数,无法进行传统的边界测试。
|
||||||
|
// 但我们可以考虑一些相关场景:
|
||||||
|
|
||||||
|
// 场景:测试在内存不足时 new 的行为(如果可能模拟)
|
||||||
|
// 注意:这通常难以在单元测试中模拟,可能需要使用特殊工具或模拟分配器。
|
||||||
|
|
||||||
|
// 场景:测试文件打开失败的情况(例如,路径无效或权限不足)
|
||||||
|
// 这需要修改原函数以接受参数,或者使用依赖注入。
|
||||||
|
|
||||||
|
// 特殊场景测试:验证资源泄漏的检测
|
||||||
|
// 这通常不是单元测试的范围,而是使用动态分析工具(如Valgrind、ASan)。
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
::testing::InitGoogleTest(&argc, argv);
|
||||||
|
return RUN_ALL_TESTS();
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue