Code - LoneWolfL/LeetCode GitHub Wiki
链表结构的相关函数声明
// 链表节点的结构体
typedef struct ListNode {
const void *value; // 节点值
int refcount;
struct ListNode *next; // 指向下一节点的链表指针
struct ListNode *prev; // 指向上一节点的链表指针
} ListNode;
// 链表的初始化函数
static ListNode* list_initialize(ListNode * const node);
// 将一个链表节点添加到指定的链表中
static ListNode* list_add(ListNode * const head, ListNode *new_node);
// 分配一个链表节点结构并将它添加到指定的链表中
static ListNode* list_add_value(ListNode * const head, const void *value, const int count);
// 从链表中移除指定的节点
static ListNode* list_remove(ListNode * const node, const CleanupListValue cleanup_value, void * const cleanup_value_data);
// 从链表中移除指定的节点并释放该节点
static void list_remove_free(ListNode * const node, const CleanupListValue cleanup_value, void * const cleanup_value_data);
// 判断链表是否为空
static int list_empty(const ListNode * const head);
// 使用传入的函数equal_func()在链表中查找指定值
static int list_find(ListNode * const head, const void *value, const EqualityFunction equal_func, ListNode **output);
// 返回链表中的第一个值
static int list_first(ListNode * const head, ListNode **output);
// 释放链表中除了head节点外所有节点
static ListNode* list_free(ListNode * const head, const CleanupListValue cleanup_value, void * const cleanup_value_data);
Map结构的相关函数声明
// 为指定符号添加对应值
static void add_symbol_value(ListNode * const symbol_map_head, const char * const symbol_names[], const size_t number_of_symbol_names, const void* value, const int count);
// 获取指定符号对应的值
static int get_symbol_value(ListNode * const symbol_map_head, const char * const symbol_names[], const size_t number_of_symbol_names, void **output);
static void free_value(const void *value, void *cleanup_value_data);
// 移除一个值
static void free_symbol_map_value(const void *value, void *cleanup_value_data);
// 移除持续返回的值
static void remove_always_return_values(ListNode * const map_head, const size_t number_of_symbol_names);
测试环境创建函数setup_test()的代码实现
void setup_test(const char *test_name) {
// 初始化存储预期Mock值链表
list_initialize(&global_function_result_map_head);
initialize_source_location(&global_last_mock_value_location);
// 初始化存储预期参数值链表
list_initialize(&global_function_parameter_map_head);
initialize_source_location(&global_last_parameter_location);
}
测试环境清除函数teardown_test()的代码实现
void teardown_test(const char *test_name) {
// 释放存储预期Mock值链表内所有节点
list_free(&global_function_result_map_head, free_symbol_map_value,(void*)0);
initialize_source_location(&global_last_mock_value_location);
// 释放存储预期参数值链表内所有节点
list_free(&global_function_parameter_map_head, free_symbol_map_value,(void*)1);
initialize_source_location(&global_last_parameter_location);
}
Mock值和参数值使用检查函数
void fail_if_leftover_values(const char *test_name) {
int error_occurred = 0;
// 移除持续返回的Mock值
remove_always_return_values(&global_function_result_map_head, 1);
// 检查是否有剩余Mock函数值
if (check_for_leftover_values(&global_function_result_map_head, "%s() has remaining non-returned values.\n", 1)) {
error_occurred = 1;
}
// 移除持续检查参数事件
remove_always_return_values(&global_function_parameter_map_head, 2);
// 检查是否有未使用参数检查事件
if (check_for_leftover_values(&global_function_parameter_map_head, "%s parameter still has values that haven't been checked.\n", 2)) {
error_occurred = 1;
}
if (error_occurred) {
exit_test(1);
}
}
内存泄漏检查函数
static void fail_if_blocks_allocated(const ListNode * const check_point, const char * const test_name) {
const int allocated_blocks = display_allocated_blocks(check_point); // 检查存储内存块链表内节点数量
if (allocated_blocks) {
free_allocated_blocks(check_point);
print_error("ERROR: %s leaked %d block(s)\n", test_name, allocated_blocks);
exit_test(1);
}
}
单元测试执行函数run_test()的关键代码
int run_test(
const char * const function_name, // 测试用例名
const UnitTestFunction Function, // 测试用例函数
void ** const state,
const UnitTestFunctionType function_type,
const void* const heap_check_point
) {
const ListNode * const check_point = heap_check_point ? heap_check_point : check_point_allocated_blocks();
void *current_state = NULL;
int rc = 1; // 测试结果标记
...
setup_test(function_name); // 创建测试环境
global_running_test = 1; // 测试开始
if (setjmp(global_run_test_env) == 0) { // 设置跳转点
Function(state ? state : ¤t_state); // 运行测试用例,进行测试
fail_if_leftover_values(function_name); // Mock值和参数值使用检查
fail_if_blocks_allocated(check_point, function_name); // 内存泄漏检查
global_running_test = 0; // 测试结束
print_message("%s: Test completed successfully.\n", function_name);
rc = 0; // 测试成功
}
else {
global_running_test = 0; // 测试结束
print_message("%s: Test failed.\n", function_name);
}
teardown_test(function_name); // 清除测试环境
...
return rc;
}
异常断言宏定义
#if UNIT_TESTING
extern void mock_assert(const int result, const char* const expression, const char * const file, const int line);
#undef assert
#define assert(expression) mock_assert((int)(expression), #expression, __FILE__, __LINE__);
#endif // UNIT_TESTING
mock_assert()函数的代码实现
void mock_assert(const int result, const char* const expression, const char* const file, const int line) {
if (!result) {
// 判断是否预期触发
if (global_expecting_assert) {
longjmp(global_expect_assert_env, (int)expression);
} else {
print_error("ASSERT: %s\n", expression);
_fail(file, line);
}
}
}
异常断言函数集的函数声明
// 逻辑true断言
void assert_true(const int result, const char* const expression, const char * const file, const int line);
// int值相等断言
void assert_int_equal(const int a, const int b, const char * const file, const int line);
// int值不等断言
void assert_int_not_equal(const int a, const int b, const char * const file, const int line);
// string值相等断言
void assert_string_equal(const char * const a, const char * const b, const char * const file, const int line);
// string值不等断言
void assert_string_not_equal(const char * const a, const char * const b, const char *file, const int line);
// 内存块值相等断言
void assert_memory_equal(const void * const a, const void * const b, const size_t size, const char* const file, const int line);
// 内存块值不等断言
void assert_memory_not_equal(const void * const a, const void * const b, const size_t size, const char* const file, const int line);
// int值在值区间内
void assert_in_range(const int value, const int minimum, const int maximum, const char* const file, const int line);
// int值不在值区间内
void assert_not_in_range(const int value, const int minimum, const int maximum, const char* const file, const int line);
// int值在值集合内
void assert_in_set(const void * const value, const void *values[], const size_t number_of_values, const char* const file, const int line);
// int值不在值集合内
void assert_not_in_set(const void * const value, const void *values[], const size_t number_of_values, const char* const file, const int line);
内存操作监测宏定义
#if UNIT_TESTING
extern void* _test_malloc(const size_t size, const char* file, const int line);
extern void* _test_calloc(const size_t number_of_elements, const size_t size, const char* file, const int line);
extern void _test_free(void* const ptr, const char* file, const int line);
#define malloc(size) _test_malloc(size, __FILE__, __LINE__)
#define calloc(num, size) _test_calloc(num, size, __FILE__, __LINE__)
#define free(ptr) _test_free(ptr, __FILE__, __LINE__)
#endif // UNIT_TESTING
test_malloc()函数的代码实现
#undef malloc
void* test_malloc(const size_t size, const char* file, const int line) {
char* ptr;
MallocBlockInfo *block_info;
ListNode * const block_list = get_allocated_blocks_list();
const size_t allocate_size = size + (MALLOC_GUARD_SIZE * 2) + sizeof(*block_info) + MALLOC_ALIGNMENT;
char* const block = (char*)malloc(allocate_size);
assert_true(block);
// 计算真正需要的内存块的起始位置
ptr = (char*)(((size_t)block + MALLOC_GUARD_SIZE + sizeof(*block_info) + MALLOC_ALIGNMENT) & ~(MALLOC_ALIGNMENT - 1));
// 在内存块前后填充标志字符,初始化此内存块。
memset(ptr - MALLOC_GUARD_SIZE, MALLOC_GUARD_PATTERN, MALLOC_GUARD_SIZE);
memset(ptr + size, MALLOC_GUARD_PATTERN, MALLOC_GUARD_SIZE);
memset(ptr, MALLOC_ALLOC_PATTERN, size);
// 初始化MallocBlockInfo结构
block_info = (MallocBlockInfo*)(ptr - (MALLOC_GUARD_SIZE + sizeof(*block_info)));
set_source_location(&block_info->location, file, line);
block_info->allocated_size = allocate_size;
block_info->size = size;
block_info->block = block;
block_info->node.value = block_info;
// 将内存块插入存储内存块的链表
list_add(block_list, &block_info->node);
return ptr;
}
#define malloc test_malloc
test_free()函数的代码实现
#undef free
void _test_free(void* const ptr, const char* file, const int line) {
unsigned int i;
char *block = (char*)ptr;
MallocBlockInfo *block_info;
_assert_true((int)ptr, "ptr", file, line);
block_info = (MallocBlockInfo*)(block - (MALLOC_GUARD_SIZE + sizeof(*block_info)));
// 内存越界检查
{
char *guards[2] = {block - MALLOC_GUARD_SIZE, block + block_info->size};
for (i = 0; i < ARRAY_LENGTH(guards); i++) {
unsigned int j;
char * const guard = guards[i];
for (j = 0; j < MALLOC_GUARD_SIZE; j++) {
const char diff = guard[j] - MALLOC_GUARD_PATTERN;
if (diff) {
print_error(
"Guard block of 0x%08x size=%d allocated by " SOURCE_LOCATION_FORMAT " at 0x%08x is corrupt\n",
(size_t)ptr, block_info->size,
block_info->location.file, block_info->location.line,
(size_t)&guard[j]);
_fail(file, line);
}
}
}
}
// 从存储内存块的链表中移除
list_remove(&block_info->node, NULL, NULL);
block = block_info->block;
memset(block, MALLOC_FREE_PATTERN, block_info->allocated_size);
// 释放该内存块的空间
free(block);
}
#define free test_free
will_return()函数的代码实现
void will_return(const char * const function_name, const char * const file, const int line, const void* const value, const int count) {
SymbolValue * const return_value = malloc(sizeof(*return_value));
assert_true(count > 0);
return_value->value = value;
set_source_location(&return_value->location, file, line);
add_symbol_value(&global_function_result_map_head, &function_name, 1, return_value, count);
}
mock()函数的代码实现
void* mock(const char * const function, const char* const file, const int line) {
void *result;
// 调用get_symbol_value()获取对应的mock值
const int rc = get_symbol_value(&global_function_result_map_head, &function, 1, &result);
if (rc) {
// 成功获取mock值
SymbolValue * const symbol = result;
void * const value = (void*)symbol->value;
global_last_mock_value_location = symbol->location;
if (rc == 1) {
free(symbol);
}
return value;
} else {
// 链表中没有对应的mock值
print_error("ERROR: " SOURCE_LOCATION_FORMAT " - Could not get value to mock function %s\n", file, line, function);
if (source_location_is_set(&global_last_mock_value_location)) {
print_error("Previously returned mock value was declared at " SOURCE_LOCATION_FORMAT "\n",
global_last_mock_value_location.file,
global_last_mock_value_location.line);
} else {
print_error("There were no previously returned mock values for this test.\n");
}
exit_test(1);
}
return NULL;
}
Mock Object的简单示例
int func() {
return (int)mock();
}
void test(void **state) {
will_return(func, 0);
}
expect_*()函数集内函数的声明
void expect_in_set(const char* const function, const char* const parameter, const char* const file, const int line, const void *values[], const size_t number_of_values, const int count);
void expect_not_in_set(const char* const function, const char* const parameter, const char* const file, const int line, const void *values[], const size_t number_of_values, const int count);
void expect_in_range(const char* const function, const char* const parameter, const char* const file, const int line, const int minimum, const int maximum, const int count);
void expect_not_in_range(const char* const function, const char* const parameter, const char* const file, const int line, const int minimum, const int maximum, const int count);
void expect_value(const char* const function, const char* const parameter, const char* const file, const int line, const void* const value, const int count);
void expect_not_value(const char* const function, const char* const parameter, const char* const file, const int line, const void* const value, const int count);
void expect_string(const char* const function, const char* const parameter, const char* const file, const int line, const char* string, const int count);
void expect_not_string(const char* const function, const char* const parameter, const char* const file, const int line, const char* string, const int count);
void expect_memory(const char* const function, const char* const parameter, const char* const file, const int line, const void* const memory, const size_t size, const int count);
void expect_not_memory(const char* const function, const char* const parameter, const char* const file, const int line, const void* const memory, const size_t size, const int count);
void expect_any(const char* const function, const char* const parameter, const char* const file, const int line, const int count);
check_expected()函数的代码实现
void check_expected(const char * const function_name, const char * const parameter_name, const char* file, const int line, const void* value) {
void *result;// 存储参数检查事件
const char* symbols[] = {function_name, parameter_name};
// 获取设置的参数值,及参数检查事件
const int rc = get_symbol_value(&global_function_parameter_map_head, symbols, 2, &result);
if (!rc)
{
// 获取设置的参数值失败
print_error("ERROR: " SOURCE_LOCATION_FORMAT " - Could not get value to check parameter %s of function %s\n", file, line,
parameter_name, function_name);
if (source_location_is_set(&global_last_parameter_location)) {
print_error("Previously declared parameter value was declared at " SOURCE_LOCATION_FORMAT "\n",
global_last_parameter_location.file,
global_last_parameter_location.line);
} else {
print_error("There were no previously declared parameter values for this test.\n");
}
exit_test(1);
}
// 获得设置的参数值成功
CheckParameterEvent * const check = (CheckParameterEvent*)result;
int check_succeeded;
global_last_parameter_location = check->location;
check_succeeded = check->check_value(value, check->check_value_data);
if (rc == 1) {
free(check);
}
if (!check_succeeded) {
print_error("ERROR: Check of parameter %s, function %s failed\n"
"Expected parameter declared at "SOURCE_LOCATION_FORMAT "\n",
parameter_name, function_name,
global_last_parameter_location.file,
global_last_parameter_location.line);
_fail(file, line);
}
}
参数检查的简单示例
void func(type T) {
check_expected(T)
return ;
}
void test(void **state) {
expect_value(func, T, 0);
}
数据计算函数集的代码实现
#include <assert.h>
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if UNIT_TESTING
extern void mock_assert(const int result, const char* const expression, const char * const file, const int line);
#undef assert
#define assert(expression) mock_assert((int)(expression), #expression, __FILE__, __LINE__);
extern void* _test_malloc(const size_t size, const char* file, const int line);
extern void* _test_calloc(const size_t number_of_elements, const size_t size, const char* file, const int line);
extern void _test_free(void* const ptr, const char* file, const int line);
#define malloc(size) _test_malloc(size, __FILE__, __LINE__)
#define calloc(num, size) _test_calloc(num, size, __FILE__, __LINE__)
#define free(ptr) _test_free(ptr, __FILE__, __LINE__)
#endif
int add(int a, int b);
int subtract(int a, int b);
extern int multiply(int a, int b);
int divide(int a, int b);
int pow2(int a);
int add(int a, int b) {
return a + b;
}
int subtract(int a, int b) {
int * ret = malloc(sizeof(int));
*ret = a - b;
return *ret;
}
int divide(int a, int b) {
assert(b);
return a / b;
}
int pow2(int a) {
return multiply(a, a);
}
数据计算函数集的测试代码
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include "cmockery.h"
#include <stdio.h>
extern int add(int a, int b);
extern int subtract(int a, int b);
int multiply(int a, int b);
extern int divide(int a, int b);
extern int pow2(int a);
int multiply(int a, int b) {
check_expected(a);
check_expected(b);
return (int)mock();
}
void test_add(void **state) {
assert_int_equal(add(5, 5), 10);
assert_int_equal(add(5, -5), 0);
}
void test_subtract(void **state) {
assert_int_equal(subtract(3, 3), 0);
}
void test_divide(void **state) {
assert_int_equal(divide(10, 2), 5);
assert_int_equal(divide(2, 10), 0);
}
void test_divide_by_zero(void **state) {
expect_assert_failure(divide(10, 0));
}
void test_pow2(void **state) {
will_return(multiply, 9);
expect_value(multiply, a, 3);
expect_value(multiply, b, 3);
assert_int_equal(pow2(3), 9);
}
int main(int argc, char* argv[]) {
UnitTest tests[] = {
test_case(test_add),
test_case(test_subtract),
test_case(test_divide),
test_case(test_divide_by_zero),
test_case(test_pow2),
};
return test_runner(tests);
}