1251212Spfg/* Miniature re-implementation of the "check" library. 2251212Spfg * 3251212Spfg * This is intended to support just enough of check to run the Expat 4251212Spfg * tests. This interface is based entirely on the portion of the 5251212Spfg * check library being used. 6251212Spfg */ 7251212Spfg 8251212Spfg#include <stdio.h> 9251212Spfg#include <stdlib.h> 10251212Spfg#include <setjmp.h> 11251212Spfg#include <assert.h> 12251212Spfg 13251212Spfg#include "minicheck.h" 14251212Spfg 15251212SpfgSuite * 16251212Spfgsuite_create(char *name) 17251212Spfg{ 18251212Spfg Suite *suite = (Suite *) calloc(1, sizeof(Suite)); 19251212Spfg if (suite != NULL) { 20251212Spfg suite->name = name; 21251212Spfg } 22251212Spfg return suite; 23251212Spfg} 24251212Spfg 25251212SpfgTCase * 26251212Spfgtcase_create(char *name) 27251212Spfg{ 28251212Spfg TCase *tc = (TCase *) calloc(1, sizeof(TCase)); 29251212Spfg if (tc != NULL) { 30251212Spfg tc->name = name; 31251212Spfg } 32251212Spfg return tc; 33251212Spfg} 34251212Spfg 35251212Spfgvoid 36251212Spfgsuite_add_tcase(Suite *suite, TCase *tc) 37251212Spfg{ 38251212Spfg assert(suite != NULL); 39251212Spfg assert(tc != NULL); 40251212Spfg assert(tc->next_tcase == NULL); 41251212Spfg 42251212Spfg tc->next_tcase = suite->tests; 43251212Spfg suite->tests = tc; 44251212Spfg} 45251212Spfg 46251212Spfgvoid 47251212Spfgtcase_add_checked_fixture(TCase *tc, 48251212Spfg tcase_setup_function setup, 49251212Spfg tcase_teardown_function teardown) 50251212Spfg{ 51251212Spfg assert(tc != NULL); 52251212Spfg tc->setup = setup; 53251212Spfg tc->teardown = teardown; 54251212Spfg} 55251212Spfg 56251212Spfgvoid 57251212Spfgtcase_add_test(TCase *tc, tcase_test_function test) 58251212Spfg{ 59251212Spfg assert(tc != NULL); 60251212Spfg if (tc->allocated == tc->ntests) { 61251212Spfg int nalloc = tc->allocated + 100; 62251212Spfg size_t new_size = sizeof(tcase_test_function) * nalloc; 63251212Spfg tcase_test_function *new_tests = realloc(tc->tests, new_size); 64251212Spfg assert(new_tests != NULL); 65251212Spfg if (new_tests != tc->tests) { 66251212Spfg free(tc->tests); 67251212Spfg tc->tests = new_tests; 68251212Spfg } 69251212Spfg tc->allocated = nalloc; 70251212Spfg } 71251212Spfg tc->tests[tc->ntests] = test; 72251212Spfg tc->ntests++; 73251212Spfg} 74 75SRunner * 76srunner_create(Suite *suite) 77{ 78 SRunner *runner = calloc(1, sizeof(SRunner)); 79 if (runner != NULL) { 80 runner->suite = suite; 81 } 82 return runner; 83} 84 85static jmp_buf env; 86 87static char const *_check_current_function = NULL; 88static int _check_current_lineno = -1; 89static char const *_check_current_filename = NULL; 90 91void 92_check_set_test_info(char const *function, char const *filename, int lineno) 93{ 94 _check_current_function = function; 95 _check_current_lineno = lineno; 96 _check_current_filename = filename; 97} 98 99 100static void 101add_failure(SRunner *runner, int verbosity) 102{ 103 runner->nfailures++; 104 if (verbosity >= CK_VERBOSE) { 105 printf("%s:%d: %s\n", _check_current_filename, 106 _check_current_lineno, _check_current_function); 107 } 108} 109 110void 111srunner_run_all(SRunner *runner, int verbosity) 112{ 113 Suite *suite; 114 TCase *tc; 115 assert(runner != NULL); 116 suite = runner->suite; 117 tc = suite->tests; 118 while (tc != NULL) { 119 int i; 120 for (i = 0; i < tc->ntests; ++i) { 121 runner->nchecks++; 122 123 if (tc->setup != NULL) { 124 /* setup */ 125 if (setjmp(env)) { 126 add_failure(runner, verbosity); 127 continue; 128 } 129 tc->setup(); 130 } 131 /* test */ 132 if (setjmp(env)) { 133 add_failure(runner, verbosity); 134 continue; 135 } 136 (tc->tests[i])(); 137 138 /* teardown */ 139 if (tc->teardown != NULL) { 140 if (setjmp(env)) { 141 add_failure(runner, verbosity); 142 continue; 143 } 144 tc->teardown(); 145 } 146 } 147 tc = tc->next_tcase; 148 } 149 if (verbosity) { 150 int passed = runner->nchecks - runner->nfailures; 151 double percentage = ((double) passed) / runner->nchecks; 152 int display = (int) (percentage * 100); 153 printf("%d%%: Checks: %d, Failed: %d\n", 154 display, runner->nchecks, runner->nfailures); 155 } 156} 157 158void 159_fail_unless(int condition, const char *file, int line, char *msg) 160{ 161 /* Always print the error message so it isn't lost. In this case, 162 we have a failure, so there's no reason to be quiet about what 163 it is. 164 */ 165 if (msg != NULL) 166 printf("%s", msg); 167 longjmp(env, 1); 168} 169 170int 171srunner_ntests_failed(SRunner *runner) 172{ 173 assert(runner != NULL); 174 return runner->nfailures; 175} 176 177void 178srunner_free(SRunner *runner) 179{ 180 free(runner->suite); 181 free(runner); 182} 183