рдЙрджреНрджреЗрд╢реНрдп: CUnit рдврд╛рдВрдЪреЗ рдХреЗ рдКрдкрд░ рдПрдХ "рдореИрддреНрд░реАрдкреВрд░реНрдг" рд╡рд╛рддрд╛рд╡рд░рдг рдмрдирд╛рдирд╛, рдбреЗрд╡рд▓рдкрд░реНрд╕ / рдкрд░реАрдХреНрд╖рдХреЛрдВ рдХреЛ рдЕрддрд┐рд░рд┐рдХреНрдд рдЗрд╢рд╛рд░реЛрдВ рдХреЗ рдмрд┐рдирд╛ рдирдП рдкрд░реАрдХреНрд╖рдг рдЬреЛрдбрд╝рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрдирд╛ред рдХреНрдпреВрдирд┐рдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рд░реВрдкрд░реЗрдЦрд╛ рдХреЗ рд░реВрдк рдореЗрдВ рдХреНрдпреЛрдВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ? рдпрд╣ рд╕рд░рд▓ рд╣реИ: рд╕рд┐рддрд╛рд░реЗ рдмрд╣реБрдд рдЕрднрд┐рд╕рд░рдг рд╣реИрдВред
рдпрд╣рд╛рдВ рдореИрдВ рдпрд╣ рд╡рд░реНрдгрди рдирд╣реАрдВ рдХрд░реВрдВрдЧрд╛ рдХрд┐ рдХреНрдпреВрдирд┐рдЯ рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рдпрд╛ рдЗрд╕ рдлреНрд░реЗрдорд╡рд░реНрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЯреЗрд╕реНрдЯ рдХреЗрд╕ рдФрд░ рдЯреЗрд╕реНрдЯ рд╕реВрдЯ рдХреИрд╕реЗ рд▓рд┐рдЦрдирд╛ рд╣реИред рдпрд╣ рд╕рдм рдЖрдзрд┐рдХрд╛рд░рд┐рдХ рджрд╕реНрддрд╛рд╡реЗрдЬ рдореЗрдВ рд╣реИ, рдЬреЛ
http://cunit.sourceforge.net/doc/index.html рдкрд░ рд╕реНрдерд┐рдд рд╣реИред
рдЗрд╕рд▓рд┐рдП, рдкрд╣рд▓реЗ рд╣рдо рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛рдУрдВ рдФрд░ рдлрд╝рд╛рдЗрд▓реЛрдВ рдХреА рд╕рдВрд░рдЪрдирд╛ рдкрд░ рдирд┐рд░реНрдгрдп рд▓реЗрддреЗ рд╣реИрдВ:
.tests |-- suites | |-- CMakeLists.txt | |-- suite1.c | |-- suite2.c | |-- suite3.c |-- main.c |-- utils.c |-- utils.h |-- CMakeLists.txt
рдкреНрд░рддреНрдпреЗрдХ рдкрд░реАрдХреНрд╖рдг рд╕реВрдЯ рд╕реБрдЗрдЯ рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛ рдореЗрдВ рдПрдХ рдЕрд▓рдЧ рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рд╕реНрдерд┐рдд рд╣реЛрдЧрд╛ред рдбреЗрд╡рд▓рдкрд░ рдпрд╛ рдЯреЗрд╕реНрдЯрд░ рдХрд╛ рдХрд╛рдо рдХреЗрд╡рд▓ рдПрдХ рдЯреЗрд╕реНрдЯ рд╕реВрдЯ рд▓рд┐рдЦрдирд╛ рдФрд░ рдЙрд╕реЗ
рд╕реВрдЯреНрд╕ рдлреЛрд▓реНрдбрд░ рдореЗрдВ рдбрд╛рд▓рдирд╛ рд╣реИред рдбреЗрд╡рд▓рдкрд░ / рдкрд░реАрдХреНрд╖рдХ рд╕реЗ рдХрд┐рд╕реА рдЕрдиреНрдп рдЗрд╢рд╛рд░реЛрдВ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИ, рдкрд░реАрдХреНрд╖рдг рд╕реВрдЯ рдХреЛ рд╕рдВрдХрд▓рди рдХреЗ рд▓рд┐рдП рдирд┐рд░реНрдорд╛рдг рдкреНрд░рдгрд╛рд▓реА рджреНрд╡рд╛рд░рд╛ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдЙрдард╛рдпрд╛ рдЬрд╛рдПрдЧрд╛, рдФрд░ рдлрд┐рд░ рдкрд░реАрдХреНрд╖рдг рдЪрд▓рдиреЗ рдкрд░ рд╕реНрд╡рдпрдВ рдХрд╛рд░реНрдпрдХреНрд░рдоред
рдЗрд╕реЗ
рдЕрд╕реЗрдВрдмрд▓ рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж, рд╣рдореЗрдВ
рд░рдирдЯреИрд╕реНрдЯ рдорд┐рд▓рдиреА рдЪрд╛рд╣рд┐рдП - рдирд┐рд╖реНрдкрд╛рджрди рдпреЛрдЧреНрдп рдХрд╛рд░реНрдпрдХреНрд░рдо рдФрд░ рдкрд░реАрдХреНрд╖рдг рд╕реВрдЯ рдХреЗ рд╕рд╛рде рдореЙрдбреНрдпреВрд▓ред
рдирд╛рдордХрд░рдг рд╕рдореНрдореЗрд▓рди
рд╣рдо рд╕рд╣рдордд рд╣реИрдВ рдХрд┐ рдкрд░реАрдХреНрд╖рдг рдорд╛рдорд▓реЛрдВ рдореЗрдВ рдЙрдкрд╕рд░реНрдЧ
test_ рд╣реЛрдЧрд╛ ред рдпрд╣реА рд╣реИ, рдЕрдЧрд░ рд╣рдо рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдлрдВрдХреНрд╢рди
рдлреВ () рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рдкрд░реАрдХреНрд╖рдг рдорд╛рдорд▓реЗ рдХреЛ
test_foo () рдХрд╣рд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред
рдкрд░реАрдХреНрд╖рдг рд╕реВрдЯ рдХреЗ рдкреНрд░рддреНрдпреЗрдХ рдЧрддрд┐рд╢реАрд▓ рдореЙрдбреНрдпреВрд▓ рдореЗрдВ,
рд░рдирд╕реБрдЗрдЯ () рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдирд┐рд░реНрдпрд╛рдд рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП, рдЬрд┐рд╕реЗ рдирд┐рд╖реНрдкрд╛рджрди рдпреЛрдЧреНрдп рдХрд╛рд░реНрдпрдХреНрд░рдо рдореЗрдВ рдмреБрд▓рд╛рдпрд╛ рдЬрд╛рдПрдЧрд╛ред рдЗрд╕ рдлрд╝рдВрдХреНрд╢рди рдореЗрдВ, рдХреНрдпреВрдирд┐рдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдкрд░реАрдХреНрд╖рдг рд╕реВрдЯ рдмрдирд╛рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП, рдЬрд┐рд╕рдХреЗ рд╕рд╛рде рдкрд░реАрдХреНрд╖рдг рдорд╛рдорд▓реЗ рдЬреБрдбрд╝реЗ рд╣реБрдП рд╣реИрдВред рд╕рдорд╛рд░реЛрд╣ рдкреНрд░реЛрдЯреЛрдЯрд╛рдЗрдк:
рд╢реВрдиреНрдп рд░рдирд╕реБрдЗрдЯ (рд╡реЛрдж);рдбрд╛рдпрдирд╛рдорд┐рдХ рдореЙрдбреНрдпреВрд▓ рдЯреЗрдореНрдкрд▓реЗрдЯ - рдЯреЗрд╕реНрдЯ рд╕реВрдЯ
suite1.c: static void test_foo(void) { } static void test_foo2(void) { } void runSuite(void) { }
рдпрд╣ рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП
рдЬрдм
рд░рдирдЯреЗрд╕реНрдЯ рдирд┐рд╖реНрдкрд╛рджрди рдпреЛрдЧреНрдп рдкреНрд░реЛрдЧреНрд░рд╛рдо
рд▓реЙрдиреНрдЪ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рдпрд╣ рд╕рднреА рдбрд╛рдпрдиреЗрдорд┐рдХ рдореЙрдбреНрдпреВрд▓ рдХреЛ рд▓реЛрдб рдХрд░рддрд╛ рд╣реИ -
рд╕реБрдЗрдЯреНрд╕ рдбрд╛рдпрд░реЗрдХреНрдЯрд░реА рд╕реЗ рдЯреЗрд╕реНрдЯ рдХрд░рддрд╛ рд╣реИ, рдЕрдЧрд░ рдкрд░реНрдпрд╛рд╡рд░рдг рдЪрд░
TEST_MODULES_DIR рд╕реЗрдЯ рдирд╣реАрдВ рд╣реИ, рдФрд░ рдкреНрд░рддреНрдпреЗрдХ рдореЙрдбреНрдпреВрд▓ рдХреЗ
рд░рдирд╕реБрдЗрдЯ () рдлрд╝рдВрдХреНрд╢рди рдХрд░рддрд╛ рд╣реИред рдпрджрд┐ рдкрд░реНрдпрд╛рд╡рд░рдг рдЪрд░
TEST_MODULES_DIR рдирд┐рд░реНрджрд┐рд╖реНрдЯ рд╣реИ , рддреЛ рдЗрд╕ рдЪрд░ рджреНрд╡рд╛рд░рд╛ рдЗрдВрдЧрд┐рдд рдирд┐рд░реНрджреЗрд╢рд┐рдХрд╛ рд╕реЗ рд▓реЛрдб рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛
рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди
рдкрд╣рд▓реА рдЪреАрдЬ рдЬрд┐рд╕реЗ рд╣рдо рд▓рд╛рдЧреВ рдХрд░рддреЗ рд╣реИрдВ, рд╡рд╣ рд╣реИ рдореБрдЦреНрдп рдХрд╛рд░реНрдпрдХреНрд░рдо рдФрд░ рдЧрддрд┐рд╢реАрд▓ рдореЙрдбреНрдпреВрд▓ рдХреА рдЦреЛрдЬ рдХрд╛ рд╕рд╣рд╛рдпрдХ рдХрд╛рд░реНрдпред рдХрд╛рд░реНрдпреЛрдВ рдХреЛ
main.c рдлрд╛рдЗрд▓ рдореЗрдВ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛:
#include <stdio.h> #include <stdlib.h> #include <errno.h> #include <unistd.h> #include <dlfcn.h> #include <sys/types.h> #include <sys/stat.h> #include <dirent.h> #include <CUnit/Basic.h> #include "utils.h" int modules_alphasort(const char **a, const char **b) { return strcoll(*a, *b); } void (*runSuite)( void); /* */ size_t searchModulesInDir( char ***m_list, char *dir ) { DIR *modules_dir = NULL; struct dirent *ent = NULL; size_t count = 0; char **modules_list = NULL; char *error = NULL; void *mem_module = NULL; void *module_handle = NULL; unsigned int allocated_mem = 0; errno = 0; if( !dir ) { return -1; } modules_dir = opendir( dir ); if( !modules_dir ) { fprintf( stderr, "%s: %s\n", dir, strerror(errno)); return -1; } while( ( ent = readdir( modules_dir ) ) ) { if( strncmp( ent->d_name, ".", 1 ) == 0 || strstr( ent->d_name, ".so" ) == NULL ) { continue; } size_t mem_len = ( strlen( ent->d_name ) + strlen( dir ) ) * sizeof( char ) + 2; char *module_path = malloc( mem_len ); memset(module_path, 0, mem_len); if( !module_path ) { fprintf( stderr, "%s\n", strerror(errno) ); return -1; } strncat( module_path, dir, strlen( dir ) * sizeof( char ) ); strncat( module_path, "/", 1 ); strncat( module_path, ent->d_name, strlen( ent->d_name ) * sizeof( char ) ); module_handle = dlopen ( module_path, RTLD_LAZY ); if( !module_handle ) { fprintf( stderr, "Could not load module: '%s'\n", dlerror()); free( module_path ); continue; } dlerror(); runSuite= dlsym( module_handle, "runSuite" ); error = dlerror(); if( error ) { fprintf( stderr, "Could not load module: %s\n", error); dlclose( module_handle ); free( module_path ); continue; } mem_module = realloc( modules_list, allocated_mem + strlen(module_path)); allocated_mem += strlen(module_path); if( !mem_module ) { fprintf( stderr, "%s\n", strerror(errno)); free( module_path ); dlclose( module_handle ); return -1; } modules_list = mem_module; modules_list[ count ] = module_path; count++; dlclose( module_handle ); } closedir( modules_dir ); qsort(modules_list, count, sizeof(char *), (int (*)(const void *, const void *))modules_alphasort); *m_list = modules_list; return count; } int main() { char *modules_dir = NULL; char *env_modules_dir = NULL; struct stat dir_info; size_t modules_total = 0; char **modules = NULL; size_t i = 0; void *module_handle = NULL; env_modules_dir = getenv( "TEST_SUITES_DIR" ); modules_dir = ( env_modules_dir ) ? env_modules_dir : "./suites"; if( stat( modules_dir, &dir_info ) < 0 ) { fprintf( stderr, "%s: %s\n", modules_dir, strerror(errno)); return 1; } if( !S_ISDIR( dir_info.st_mode ) ) { fprintf( stderr, "'%s' is not a directory\n", modules_dir); return 1; } if( access( modules_dir, R_OK | X_OK ) != 0 ) { fprintf( stderr, "Directory '%s' is not accessible\n", modules_dir ); return 1; } modules_total = searchModulesInDir( &modules, modules_dir); if(modules_total <= 0) { fprintf( stderr, "No test suites\n"); return 0; } CUnitInitialize(); for( i = 0; i < modules_total; i++ ) { module_handle = dlopen ( modules[i], RTLD_LAZY ); if( !module_handle ) { fprintf( stderr, "Module '%s'\n", dlerror()); continue; } runSuite = dlsym( module_handle, "runSuite" ); runSuite(); } CU_basic_set_mode(CU_BRM_VERBOSE); CU_basic_run_tests(); CUnitUInitialize(); return CU_get_error(); }
рд╣реЗрд▓реНрдкрд░ рдлрд╝рдВрдХреНрд╢рдВрд╕ рдФрд░ рдкрд░реНрдпрд╛рд╡рд░рдг рдореИрдХреНрд░реЛрдЬрд╝
рдкрд░реАрдХреНрд╖рдг рдорд╛рдорд▓реЛрдВ рдХреЗ рд▓рд┐рдП рдЙрдкрд╕рд░реНрдЧ рдХреЛ рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ рд▓рд┐рдЦрдиреЗ рдпрд╛ рди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдпрджрд┐ рдмрджрддрд░ рд╣реИ, рдпрджрд┐ рдЙрдкрд╕рд░реНрдЧ рдмрд╛рдж рдореЗрдВ рдмрджрд▓ рдЧрдпрд╛ рд╣реИ, рддреЛ рд╕рднреА рдкрд░реАрдХреНрд╖рдг рдорд╛рдорд▓реЛрдВ рдХрд╛ рдирд╛рдо рдирд╣реАрдВ рдмрджрд▓реЗрдВ, рд╣рдо рдПрдХ рд╕рд╣рд╛рдпрдХ рдореИрдХреНрд░реЛ
TEST_FUNCT рд▓рд┐рдЦрддреЗ рд╣реИрдВ :
#define TEST_FUNCT(name) \ static void test_##name()
рдЕрдм рд▓рд┐рдЦрдиреЗ рдХреЗ рдмрдЬрд╛рдп:
static void test_foo() { }
рд▓рд┐рдЦреЗрдВ:
TEST_FUNCT(foo) { }
рдкрд░реАрдХреНрд╖рдг рд╕реВрдЯ рдореЗрдВ рдкрд░реАрдХреНрд╖рдг рдХреЗ рдорд╛рдорд▓реЛрдВ рдХреЛ рдЬреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдФрд░ рдореИрдХреНрд░реЛ
ADD_SUITE_TEST рдЬреЛрдбрд╝реЗрдВ:
#define ADD_SUITE_TEST(suite, name) \ if ((NULL == CU_add_test(suite, #name, (CU_TestFunc)test_##name))) \
рдареАрдХ рд╣реИ, рдЖрдЦрд┐рд░реА рдЪреАрдЬ рдЬреЛ рд╣рдореЗрдВ рдЪрд╛рд╣рд┐рдП рд╡рд╣ рд╣реИ рдЯреЗрд╕реНрдЯ
рд╕реВрдЯ рдХреНрдпреВрдирд╛рдЗрдЯ рдХреНрд░рд┐рдПрдЯрд╕реБрдЗрдЯ () рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд╣реЗрд▓реНрдкрд░ рдлрдВрдХреНрд╢рдиред
рд╕рд╣рд╛рдпрдХ рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рдореИрдХреНрд░реЛрдЬрд╝ рдФрд░ рдкреНрд░реЛрдЯреЛрдЯрд╛рдЗрдк utils.h рдлрд╝рд╛рдЗрд▓ рдореЗрдВ рд╕реНрдерд┐рдд рд╣реИрдВ:
#ifndef __UTILS_H__ #define __UTILS_H__ #include <stdio.h> #include <stdlib.h> #include <CUnit/Basic.h> #define TEST_FUNCT(name) \ static void test_##name() #define ADD_SUITE_TEST(suite, name) \ if ((NULL == CU_add_test(suite, #name, (CU_TestFunc)test_##name))) {\ CU_cleanup_registry();\ return;\ }\ CU_pSuite CUnitCreateSuite(const char* title); void CUnitInitialize(void); void CUnitUInitialize(void); #endif
Utils.c рдлрд╝рд╛рдЗрд▓ рдореЗрдВ, рд╣рдо рд╕рд╣рд╛рдпрдХ рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рддреЗ рд╣реИрдВ:
#include <string.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <CUnit/Basic.h> #include "utils.h" void CUnitUInitialize(void) { CU_cleanup_registry(); } void CUnitInitialize(void) { if (CU_initialize_registry() != CUE_SUCCESS) { fprintf(stderr, "Failed to initialize the CUnit registry: %d\n", CU_get_error()); exit(1); } } static int initSuite(void) { return 0; } static int cleanSuite(void) { return 0; } CU_pSuite CUnitCreateSuite(const char* title) { CU_pSuite suite = NULL; suite = CU_add_suite(title, initSuite, cleanSuite); if (suite == NULL) { CU_cleanup_registry(); return NULL; } return suite; }
рдЕрдм рдПрдХ рдкрд░реАрдХреНрд╖рдг рд╕реВрдЯ рд▓рд┐рдЦрддреЗ рд╣реИрдВ:
#include <stdio.h> #include <stdlib.h> #include <CUnit/Basic.h> #include "utils.h" TEST_FUNCT(foo) { /* */ CU_ASSERT_EQUAL(0, 1); } TEST_FUNCT(foo2) { /* */ CU_ASSERT_EQUAL(1, 1); } void runSuite(void) { CU_pSuite suite = CUnitCreateSuite("Suite1"); if (suite) { ADD_SUITE_TEST(suite, foo) ADD_SUITE_TEST(suite, foo2) } }
рд╕рднрд╛
рдлрд╝рд╛рдЗрд▓ рдореБрдХрджрдорд╛ / CMakeLists.txt:
MACRO(ADD_MODULE file) ADD_LIBRARY( ${file} MODULE ${file}.c ../utils.c ) TARGET_LINK_LIBRARIES( ${file} cunit ) SET_TARGET_PROPERTIES( ${file} PROPERTIES PREFIX "" LIBRARY_OUTPUT_DIRECTORY "." ) ENDMACRO(ADD_MODULE file) FILE(GLOB C_FILES RELATIVE "${CMAKE_SOURCE_DIR}/suites" "${CMAKE_SOURCE_DIR}/suites/*.c") INCLUDE_DIRECTORIES ( "${CMAKE_SOURCE_DIR}" ) FOREACH ( module ${C_FILES} ) STRING( REGEX REPLACE ".c$" "" module "${module}" ) MESSAGE(STATUS "Found test suite: ${module}") ADD_MODULE(${module}) ENDFOREACH ( module ${MODULES} )
CMakeLists.txt рдлрд╝рд╛рдЗрд▓:
CMAKE_MINIMUM_REQUIRED (VERSION 2.6) SET(CMAKE_VERBOSE_MAKEFILE ON) PROJECT("runtest") SET(CMAKE_C_FLAGS " -std=c99 -O3 -Wall -Wextra -Wimplicit") INCLUDE_DIRECTORIES ( "/usr/include" ) ADD_EXECUTABLE(runtests main.c utils.c) TARGET_LINK_LIBRARIES(runtests cunit dl) ADD_CUSTOM_TARGET(test "./runtests" WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" VERBATIM) ADD_SUBDIRECTORY(suites)
antonio: рдкрд░реАрдХреНрд╖рдг antonio $ cmakeред
рдПрдВрдЯреЛрдирд┐рдпреЛ: рдкрд░реАрдХреНрд╖рдг рдПрдВрдЯреЛрдирд┐рдпреЛ $ рдореЗрдХ
рдПрдВрдЯреЛрдирд┐рдпреЛ: рдПрдВрдЯреЛрдирд┐рдпреЛ $ ./runtests рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд░рддрд╛ рд╣реИ