(六)cmockery中的assert_macro分析

    所分析的assert_macro.c和assert_macro_test.c文件位于 工程中的 cmockery/src/example/ 目录下,是关于assert方法的一个应用,可以进行判断指定类型数据的逻辑关系的断言,提供了一组函数如下:
  1. 断言整数相等或者不相等
  2. assert_int_equal(a, b)
  3. assert_int_not_equal(a, b)
  4. 断言字符串相等或者不相等
  5. assert_string_equal(a, b)
  6. assert_string_not_equal(a, b)
  7. 断言内存相等或者不相等
  8. assert_memory_equal(a, b, size)
  9. assert_memory_not_equal(a, b, size)
  10. 断言数据是不是在最大最小值之间
  11. assert_in_range(value, minimum, maximum)
  12. assert_not_in_range(value, minimum, maximum)
  13. 断言数据是不是在集合中
  14. assert_in_set(value, values, number_of_values)
  15. assert_not_in_set(value, values, number_of_values)
assert_macro.c
  1. #include <string.h>
  2. static const char* status_code_strings[] = {
  3. "Address not found",
  4. "Connection dropped",
  5. "Connection timed out",
  6. };
  7. const char* get_status_code_string(const unsigned int status_code) {
  8. return status_code_strings[status_code];
  9. };
  10. unsigned int string_to_status_code(const char* const status_code_string) {
  11. unsigned int i;
  12. for (i = 0; i < sizeof(status_code_strings) /
  13. sizeof(status_code_strings[0]); i++) {
  14. if (strcmp(status_code_strings[i], status_code_string) == 0) {
  15. return i;
  16. }
  17. }
  18. return ~0U;
  19. }
这个文件中有两个函数,get_status_code_string和string_to_status_code;
其中
    get_status_code_string函数就是简单的根据传入整数值作为索引,然后找到数组中的字符串并返回。
    string_to_status_code函数是根据传入的字符串和字符串数组中的状态值进行比较,如果找到则返回索引值,如果没有找到则返回0xffffffff

assert_macro_test.c
  1. #include <stdarg.h>
  2. #include <stddef.h>
  3. #include <setjmp.h>
  4. #include "cmockery.h"
  5. extern const char* get_status_code_string(const unsigned int status_code);
  6. extern unsigned int string_to_status_code(
  7. const char* const status_code_string);
  8. /* This test will fail since the string returned by get_status_code_string(0)
  9. * doesn't match "Connection timed out". */
  10. void get_status_code_string_test(void **state) {
  11. assert_string_equal(get_status_code_string(0), "Address not found");
  12. assert_string_equal(get_status_code_string(1), "Connection timed out");
  13. }
  14. // This test will fail since the status code of "Connection timed out" isn't 1
  15. void string_to_status_code_test(void **state) {
  16. assert_int_equal(string_to_status_code("Address not found"), 0);
  17. assert_int_equal(string_to_status_code("Connection timed out"), 1);
  18. }
  19. int main(int argc, char *argv[]) {
  20. const UnitTest tests[] = {
  21. unit_test(get_status_code_string_test),
  22. unit_test(string_to_status_code_test),
  23. };
  24. return run_tests(tests);
  25. }

有两个单元测试函数get_status_code_string_test和string_to_status_code_test;

对于assert_string_equal,是一个宏定义如下:
  1. #define assert_string_equal(a, b)
  2. _assert_string_equal((const char*)(a), (const char*)(b), __FILE__,
  3. __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__)
  1. void _assert_string_equal(const char * const a, const char * const b,
  2. const char * const file, const int line) {
  3. if (!string_equal_display_error(a, b)) {
  4. _fail(file, line);
  5. }
  6. }
最终这个函数的调用形式为:_assert_string_equal((const char*)("Address not found"), (const char*)("Address not found"), __FILE__, __LINE__)
  1. static int string_equal_display_error(
  2. const char * const left, const char * const right) {
  3. if (strcmp(left, right) == 0) {
  4. return 1;
  5. }
  6. print_error(""%s" != "%s" ", left, right);
  7. return 0;
  8. }
将参数带入只有 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这个宏来说,定义如下:
  1. #define LargestIntegralType unsigned long long
  2. #define cast_to_largest_integral_type(value)
  3. ((LargestIntegralType)((unsigned)(value)))
  4. #define assert_int_equal(a, b)
  5. _assert_int_equal(cast_to_largest_integral_type(a),
  6. cast_to_largest_integral_type(b),
  7. __FILE__, __LINE__)

将程序中的函数还原到宏体中如下:
_assert_int_equal((unsigned long long)(unsigned)(0),(unsigned long long)(unsigned)(0), __FILE__, __LINE__);
  1. void _assert_int_equal(
  2. const LargestIntegralType a, const LargestIntegralType b,
  3. const char * const file, const int line) {
  4. if (!values_equal_display_error(a, b)) {
  5. _fail(file, line);
  6. }
  7. }


  1. static int values_equal_display_error(const LargestIntegralType left,
  2. const LargestIntegralType right) {
  3. const int equal = left == right;
  4. if (!equal) {
  5. print_error(LargestIntegralTypePrintfFormat " != "
  6. LargestIntegralTypePrintfFormat " ", left, right);
  7. }
  8. return equal;
  9. }
很显然这个函数执行到这里的时候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位置进行下一个测试。

最后这样例程序的运行结果如下:


















原文地址:https://www.cnblogs.com/cfzhang/p/d75576559e58c3d0708d2d99dfe46947.html