libcsptr源码中的check目录下是其单元测试的源码,主要是使用了check的单元测试框架。

Check 最主要的优点是对于每一个测试用例的运行都 fork 一个子进程,这么做的原因是因为 C 语言的独特性:
(1) 其它语言如 Java,Python,Ruby等,单元测试出错最多不过是抛出异常;
(2) C 语言如果指针操作错误,乱指一气,可是会 coredump的。测试框架因此直接退出,用户是看不到任何返回的,只有郁闷的 coredump;
(3) Check 的单元测试运行在 fork 的子进程中,可以避免测试框架由于 coredump 而崩溃。

首先查看check/test/test.c,代码比较简单

通过master_suite构造出一个Suite结构体,结构体中存放所有测试用例
往Suite结构体中添加用例的方法是

suite_add_tcase(s, make_test_case("misc", misc_tests));

其中s是Suite结构体,misc_tests测试函数指针数组即测试用例,如下图所示

然后在main函数中能过srunner_create中构造SRunner
通过srunner_run_all(Srunner *, CK_NORMAL)即可运行所有测试用例
srunner_ntests_failed可检查测试用例失败个数

有点费解的是这里

其实是licsptr实现的智能指针是可以指定alloc和dealloc函数的,这个测试用例是为了测试如果改变alloc函数从
malloc到一个自定义函数,是否返回一个空的smart ptr

第14行的lambda宏是一个帮助自定义函数的宏

lambda(void *, (UNUSED size_t s) { return NULL; }),

#define lambda(RType, Body) ({ RType __fn__ Body; __fn__; })
#define UNUSED __attribute__ ((unused))

//展开后

{void * __fn__ (__attribute__ ((unused)) size_t s) { return NULL; }; __fn__;}

这种写法利用了GCC对C语言的扩展(被一对花括号包起来的代码块能够返回一个值),展开后的写法能够返回一个函数指针,
函数指针类型为返回值为void *,参数为size_t size_t,函数结构体为return NULL

smalloc_allocator = (s_allocator) {
    lambda(void *, (UNUSED size_t s) { return NULL; }),
    lambda(void, (UNUSED void *ptr) {})
};

//等同于

smalloc_allocator = (s_allocator) {
    void *(*__fn__)(size_t);
    void (*__fn__)(void *);
};

这样就把libcsptr中的alloc和dealloc函数从malloc和free更改了,然后测试完毕后在第19行又改回正常值