(六)cmockery中的assert_macro分析
所分析的assert_macro.c和assert_macro_test.c文件位于 工程中的 cmockery/src/example/ 目录下,是关于assert方法的一个应用,可以进行判断指定类型数据的逻辑关系的断言,提供了一组函数如下:
断言整数相等或者不相等
assert_int_equal(a, b)
assert_int_not_equal(a, b)
断言字符串相等或者不相等
assert_string_equal(a, b)
assert_string_not_equal(a, b)
断言内存相等或者不相等
assert_memory_equal(a, b, size)
assert_memory_not_equal(a, b, size)
断言数据是不是在最大最小值之间
assert_in_range(value, minimum, maximum)
assert_not_in_range(value, minimum, maximum)
断言数据是不是在集合中
assert_in_set(value, values, number_of_values)
assert_not_in_set(value, values, number_of_values)
assert_macro.c
#include <string.h>
static const char* status_code_strings[] = {
"Address not found",
"Connection dropped",
"Connection timed out",
};
const char* get_status_code_string(const unsigned int status_code) {
return status_code_strings[status_code];
};
unsigned int string_to_status_code(const char* const status_code_string) {
unsigned int i;
for (i = 0; i < sizeof(status_code_strings) /
sizeof(status_code_strings[0]); i++) {
if (strcmp(status_code_strings[i], status_code_string) == 0) {
return i;
}
}
return ~0U;
}
这个文件中有两个函数,get_status_code_string和string_to_status_code;
其中
get_status_code_string函数就是简单的根据传入整数值作为索引,然后找到数组中的字符串并返回。
string_to_status_code函数是根据传入的字符串和字符串数组中的状态值进行比较,如果找到则返回索引值,如果没有找到则返回0xffffffff
assert_macro_test.c
#include <stdarg.h>
#include <stddef.h>
#include <setjmp.h>
#include "cmockery.h"
extern const char* get_status_code_string(const unsigned int status_code);
extern unsigned int string_to_status_code(
const char* const status_code_string);
/* This test will fail since the string returned by get_status_code_string(0)
* doesn't match "Connection timed out". */
void get_status_code_string_test(void **state) {
assert_string_equal(get_status_code_string(0), "Address not found");
assert_string_equal(get_status_code_string(1), "Connection timed out");
}
// This test will fail since the status code of "Connection timed out" isn't 1
void string_to_status_code_test(void **state) {
assert_int_equal(string_to_status_code("Address not found"), 0);
assert_int_equal(string_to_status_code("Connection timed out"), 1);
}
int main(int argc, char *argv[]) {
const UnitTest tests[] = {
unit_test(get_status_code_string_test),
unit_test(string_to_status_code_test),
};
return run_tests(tests);
}
有两个单元测试函数get_status_code_string_test和string_to_status_code_test;
对于assert_string_equal,是一个宏定义如下:
#define assert_string_equal(a, b) \
_assert_string_equal((const char*)(a), (const char*)(b), __FILE__, \
__LINE__)
将函数assert_string_equal(get_status_code_string(0), "Address not found");带入之后为
_assert_string_equal((const char*)(get_status_code_string(0)), (const char*)("Address not found"), __FILE__, __LINE__)
void _assert_string_equal(const char * const a, const char * const b,
const char * const file, const int line) {
if (!string_equal_display_error(a, b)) {
_fail(file, line);
}
}
最终这个函数的调用形式为:_assert_string_equal((const char*)("Address not found"), (const char*)("Address not found"), __FILE__, __LINE__)
static int string_equal_display_error(
const char * const left, const char * const right) {
if (strcmp(left, right) == 0) {
return 1;
}
print_error("\"%s\" != \"%s\"\n", left, right);
return 0;
}
将参数带入只有 left=right所以会返回1;不会有任何的报错信息。
而以同样的方式带入assert_string_equal("Connection dropped", "Connection timed out");则会在string_equal_display_error函数中打印error信息并且返回0,然后再
_assert_string_equal函数中调用_fail函数,打印日志信息,并且longjmp跳转到setjmp位置,进行下一个测试的执行。
对于assert_int_equal这个宏来说,定义如下:
#define LargestIntegralType unsigned long long
#define cast_to_largest_integral_type(value) \
((LargestIntegralType)((unsigned)(value)))
#define assert_int_equal(a, b) \
_assert_int_equal(cast_to_largest_integral_type(a), \
cast_to_largest_integral_type(b), \
__FILE__, __LINE__)
将程序中的函数还原到宏体中如下:
_assert_int_equal((unsigned long long)(unsigned)(0),(unsigned long long)(unsigned)(0), __FILE__, __LINE__);
void _assert_int_equal(
const LargestIntegralType a, const LargestIntegralType b,
const char * const file, const int line) {
if (!values_equal_display_error(a, b)) {
_fail(file, line);
}
}
static int values_equal_display_error(const LargestIntegralType left,
const LargestIntegralType right) {
const int equal = left == right;
if (!equal) {
print_error(LargestIntegralTypePrintfFormat " != "
LargestIntegralTypePrintfFormat "\n", left, right);
}
return equal;
}
很显然这个函数执行到这里的时候left==right==0;会赋值给equal为1,即返回值为1.正常结束。
而在执行_assert_int_equal((unsigned long long)(unsigned)(2),(unsigned long long)(unsigned)(1), __FILE__, __LINE__);的时候会返回0,导致在_assert_int_equal函数中调用_fail函数,跳转到setjmp位置进行下一个测试。
最后这样例程序的运行结果如下: