[置顶] 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


 

 

posted @ 2013-07-08 14:57  爱生活,爱编程  阅读(289)  评论(0编辑  收藏  举报