[置顶] C语言单元测试框架
unitest.h
/******************************************************************************
* *
* This program is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
* or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed *
* under the GNU Lesser General Public License Version 3, 29 June 2007. *
* The complete license can be accessed from the following location: *
* http://opensource.org/licenses/lgpl-3.0.html *
* *
* Author: Yun Li (yunli.open@gmail.com) *
* Date: 03/06/2010 *
* Author: Gavin Ding (gavin_ding@sina.cn / fanfan.ding.ict@gmail.com) *
* Date: 07/07/2013 *
******************************************************************************/
/******************************************************************************
REVISION HISTORY
================
Date Version Name Description
---------- ------------ ---------------- --------------------------------
03/17/2013 V001.000.000 Gavin Ding rewrite this file
---------- ------------ ---------------- --------------------------------
Date Version Name Description
---------- ------------ ---------------- --------------------------------
07/07/2013 V001.001.000 Gavin Ding make it more useful
---------- ------------ ---------------- --------------------------------
******************************************************************************/
#ifndef __UNITEST_H
#define __UNITEST_H
#include <stdio.h>
#include <string.h>
static int g_case_total = 0;
static int g_case_succeeded = 0;
static int g_case_failed = 0;
#ifndef NULL
#define NULL ((void*)0)
#endif
#define INTERNAL_USE_ONLY_SUCCEEDED(_a, _b, _oper) \
printf(" Expected: \""#_a"\" "#_oper" \""#_b"\"\n Result: Succeeded\n")
#define INTERNAL_USE_ONLY_FAILED(_a, _b, _oper) \
printf(" Expected: \""#_a"\" "#_oper" \""#_b"\"\n (X) Result: Failed\n")
#define INTERNAL_USE_ONLY_CASE_SHOW() \
printf("Case %d =====>\n", g_case_total); \
printf(" Location: %s:%d\n", __FILE__, __LINE__); \
#define UNITEST_ERROR(_string) do { \
printf("Error: "#_string"\n"); \
return -1;\
} while (0)
#define UNITEST_EQUALS(_a, _b) do { \
g_case_total++; \
INTERNAL_USE_ONLY_CASE_SHOW(); \
if ((_a) == (_b)) { \
INTERNAL_USE_ONLY_SUCCEEDED(_a, _b, ==); \
g_case_succeeded++; \
} \
else { \
INTERNAL_USE_ONLY_FAILED(_a, _b, ==); \
g_case_failed++; \
} \
printf("\n"); \
} while (0)
#define UNITEST_DIFFERS(_a, _b) do { \
g_case_total++; \
INTERNAL_USE_ONLY_CASE_SHOW(); \
if ((_a) == (_b)) { \
INTERNAL_USE_ONLY_FAILED(_a, _b, !=); \
g_case_failed++; \
} \
else { \
INTERNAL_USE_ONLY_SUCCEEDED(_a, _b, !=); \
g_case_succeeded++; \
} \
printf("\n"); \
} while (0)
#define UNITEST_LESS_THAN(_a, _b) do { \
g_case_total++; \
INTERNAL_USE_ONLY_CASE_SHOW(); \
if ((_a) < (_b)) { \
INTERNAL_USE_ONLY_SUCCEEDED(_a, _b, <); \
g_case_succeeded ++; \
} \
else { \
INTERNAL_USE_ONLY_FAILED(_a, _b, <); \
g_case_failed++; \
} \
printf("\n"); \
} while (0)
#define UNITEST_LESS_THAN_EQUALS(_a, _b) do { \
g_case_total++; \
INTERNAL_USE_ONLY_CASE_SHOW(); \
if ((_a) <= (_b)) { \
INTERNAL_USE_ONLY_SUCCEEDED(_a, _b, <=); \
g_case_succeeded++; \
} \
else { \
INTERNAL_USE_ONLY_FAILED(_a, _b, <=); \
g_case_failed++; \
} \
printf("\n"); \
} while (0)
#define UNITEST_GREATER_THAN(_a, _b) do { \
g_case_total++; \
INTERNAL_USE_ONLY_CASE_SHOW(); \
if ((_a) > (_b)) { \
INTERNAL_USE_ONLY_SUCCEEDED(_a, _b, >); \
g_case_succeeded++; \
} \
else { \
INTERNAL_USE_ONLY_FAILED(_a, _b, >); \
g_case_failed++; \
} \
printf("\n"); \
} while (0)
#define UNITEST_GREATER_THAN_EQUALS(_a, _b) do { \
g_case_total++; \
INTERNAL_USE_ONLY_CASE_SHOW(); \
if ((_a) >= (_b)) { \
INTERNAL_USE_ONLY_SUCCEEDED(_a, _b, >=); \
g_case_succeeded++; \
} \
else { \
INTERNAL_USE_ONLY_FAILED(_a, _b, >=); \
g_case_failed++; \
} \
printf("\n"); \
} while (0)
#define UNITEST_STR_EQUALS(_a, _b) do { \
g_case_total++; \
INTERNAL_USE_ONLY_CASE_SHOW(); \
if ( NULL == (_a) || NULL == (_b) ) { \
UNITEST_ERROR(ptr should not be NULL); \
} \
if ( !strcmp((_a), (_b)) ) { \
INTERNAL_USE_ONLY_SUCCEEDED(_a, _b, ==); \
g_case_succeeded++; \
} \
else { \
INTERNAL_USE_ONLY_FAILED(_a, _b, ==); \
g_case_failed++; \
} \
printf("\n"); \
} while (0)
#define UNITEST_STR_DIFFERS(_a, _b) do { \
g_case_total++; \
INTERNAL_USE_ONLY_CASE_SHOW(); \
if ( NULL == (_a) || NULL == (_b) ) { \
UNITEST_ERROR(ptr should not be NULL); \
} \
if ( !strcmp((_a), (_b)) ) { \
INTERNAL_USE_ONLY_FAILED(_a, _b, !=); \
g_case_failed++; \
} \
else { \
INTERNAL_USE_ONLY_SUCCEEDED(_a, _b, !=); \
g_case_succeeded++; \
} \
printf("\n"); \
} while (0)
#define UNITEST_MEM_EQUALS(_a, _b, _len) do { \
g_case_total++; \
INTERNAL_USE_ONLY_CASE_SHOW(); \
if ( NULL == (_a) || NULL == (_b) ) { \
UNITEST_ERROR(ptr should not be NULL); \
} \
if ( (_len) <= 0 ) { \
UNITEST_ERROR(mem len should be positive); \
} \
if ( !memcmp((void*)(_a),(void*)(_b), (int)(_len)) ) { \
INTERNAL_USE_ONLY_SUCCEEDED(_a, _b, ==); \
g_case_succeeded++; \
} \
else { \
INTERNAL_USE_ONLY_FAILED(_a, _b, ==); \
g_case_failed++; \
} \
printf("\n"); \
} while (0)
#define UNITEST_MEM_DIFFERS(_a, _b, _len) do { \
g_case_total++; \
INTERNAL_USE_ONLY_CASE_SHOW(); \
if ( NULL == (_a) || NULL == (_b) ) { \
UNITEST_ERROR(ptr should not be NULL); \
} \
if ( (_len) <= 0 ) { \
UNITEST_ERROR(mem len should be positive); \
} \
if ( !memcmp((void*)(_a), (void*)(_b), (int)(_len)) ) { \
INTERNAL_USE_ONLY_FAILED(_a, _b, !=); \
g_case_failed++; \
} \
else { \
INTERNAL_USE_ONLY_SUCCEEDED(_a, _b, !=); \
g_case_succeeded++; \
} \
printf("\n"); \
} while (0)
static void unitest_bar()
{
printf("********************************************************\n");
printf("* Unit Test *\n");
printf("********************************************************\n");
printf("\n");
}
static int unitest_report()
{
printf("\n");
printf("********************************************************\n");
printf("* Test Report *\n");
printf("********************************************************\n");
if (0 == g_case_total) {
printf("No test case is run\n");
goto pass;
}
printf(" Total: %d\n", g_case_total);
printf("Succeeded: %d (%d%%)\n", g_case_succeeded, g_case_succeeded * 100 / g_case_total);
printf("********************************************************\n");
printf("\n");
if (g_case_total != g_case_succeeded) {
printf("\n");
printf(":-( Failed\n");
printf("\n");
return -1;
}
pass:
printf("\n");
printf(":-) Passed\n");
printf("\n");
return 0;
}
#ifndef HAVE_MAIN
extern int unitest_main(int _argc, char *_argv[]);
int main(int _argc, char *_argv[])
{
unitest_bar();
unitest_main(_argc, _argv);
return unitest_report();
}
#endif /* end of HAVE_MAIN */
#endif /* end of __UNITEST_H */
unitest_demo.c
/******************************************************************************
* *
* This program is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
* or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed *
* under the GNU Lesser General Public License Version 3, 29 June 2007. *
* The complete license can be accessed from the following location: *
* http://opensource.org/licenses/lgpl-3.0.html *
* *
* Author: Gavin Ding (gavin_ding@sina.cn / fanfan.ding.ict@gmail.com) *
* Date: 07/07/2013 *
* *
******************************************************************************/
/******************************************************************************
REVISION HISTORY
================
Date Version Name Description
-------- ------- ------------ --------------------------------------------
-------- ------- ------------ --------------------------------------------
******************************************************************************/
#include "unitest.h"
#include <stdlib.h>
#define UNUSED(param) ((param) = (param))
int unitest_main (int argc, char *argv[])
{
char *str1 = "YT";
char *str2 = "HW";
char *str3 = "HW";
void *p1 = NULL;
void *p2 = NULL;
UNUSED(argc);
UNUSED(argv);
UNITEST_EQUALS(87, 87);
UNITEST_DIFFERS(10, 13);
UNITEST_LESS_THAN(41, 70);
UNITEST_LESS_THAN_EQUALS(8, 8);
UNITEST_LESS_THAN_EQUALS(7, 8);
UNITEST_GREATER_THAN(70, 41);
UNITEST_GREATER_THAN_EQUALS(8, 8);
UNITEST_GREATER_THAN_EQUALS(8, 7);
UNITEST_STR_EQUALS(str2, str3);
UNITEST_STR_DIFFERS(str1, str2);
p1 = malloc(10);
memset(p1, 2, 10);
p2 = malloc(10);
memset(p2, 2, 10);
UNITEST_MEM_EQUALS(p1, p2, 10);
memset(p2, 5, 10);
UNITEST_MEM_DIFFERS(p1, p2, 10);
free(p1);
p1 = NULL;
free(p2);
p2 = NULL;
return 0;
}
unitest_demo.result
./unitest/unitest_demo.exe
********************************************************
* Unit Test *
********************************************************
Case 1 =====>
Location: unitest_demo.c:41
Expected: "87" == "87"
Result: Succeeded
Case 2 =====>
Location: unitest_demo.c:43
Expected: "10" != "13"
Result: Succeeded
Case 3 =====>
Location: unitest_demo.c:45
Expected: "41" < "70"
Result: Succeeded
Case 4 =====>
Location: unitest_demo.c:47
Expected: "8" <= "8"
Result: Succeeded
Case 5 =====>
Location: unitest_demo.c:48
Expected: "7" <= "8"
Result: Succeeded
Case 6 =====>
Location: unitest_demo.c:50
Expected: "70" > "41"
Result: Succeeded
Case 7 =====>
Location: unitest_demo.c:52
Expected: "8" >= "8"
Result: Succeeded
Case 8 =====>
Location: unitest_demo.c:53
Expected: "8" >= "7"
Result: Succeeded
Case 9 =====>
Location: unitest_demo.c:55
Expected: "str2" == "str3"
Result: Succeeded
Case 10 =====>
Location: unitest_demo.c:57
Expected: "str1" != "str2"
Result: Succeeded
Case 11 =====>
Location: unitest_demo.c:65
Expected: "p1" == "p2"
Result: Succeeded
Case 12 =====>
Location: unitest_demo.c:68
Expected: "p1" != "p2"
Result: Succeeded
********************************************************
* Test Report *
********************************************************
Total: 12
Succeeded: 12 (100%)
********************************************************
:-) Passed


浙公网安备 33010602011771号