1 /* Miniature re-implementation of the "check" library. 2 * 3 * This is intended to support just enough of check to run the Expat 4 * tests. This interface is based entirely on the portion of the 5 * check library being used. 6 */ 7 8 #include <stdio.h> 9 #include <stdlib.h> 10 #include <setjmp.h> 11 #include <assert.h> 12 13 #include "internal.h" /* for UNUSED_P only */ 14 #include "minicheck.h" 15 16 Suite * 17 suite_create(const char *name) 18 { 19 Suite *suite = (Suite *) calloc(1, sizeof(Suite)); 20 if (suite != NULL) { 21 suite->name = name; 22 } 23 return suite; 24 } 25 26 TCase * 27 tcase_create(const char *name) 28 { 29 TCase *tc = (TCase *) calloc(1, sizeof(TCase)); 30 if (tc != NULL) { 31 tc->name = name; 32 } 33 return tc; 34 } 35 36 void 37 suite_add_tcase(Suite *suite, TCase *tc) 38 { 39 assert(suite != NULL); 40 assert(tc != NULL); 41 assert(tc->next_tcase == NULL); 42 43 tc->next_tcase = suite->tests; 44 suite->tests = tc; 45 } 46 47 void 48 tcase_add_checked_fixture(TCase *tc, 49 tcase_setup_function setup, 50 tcase_teardown_function teardown) 51 { 52 assert(tc != NULL); 53 tc->setup = setup; 54 tc->teardown = teardown; 55 } 56 57 void 58 tcase_add_test(TCase *tc, tcase_test_function test) 59 { 60 assert(tc != NULL); 61 if (tc->allocated == tc->ntests) { 62 int nalloc = tc->allocated + 100; 63 size_t new_size = sizeof(tcase_test_function) * nalloc; 64 tcase_test_function *new_tests = realloc(tc->tests, new_size); 65 assert(new_tests != NULL); 66 if (new_tests != tc->tests) { 67 free(tc->tests); 68 tc->tests = new_tests; 69 } 70 tc->allocated = nalloc; 71 } 72 tc->tests[tc->ntests] = test; 73 tc->ntests++; 74 } 75 76 SRunner * 77 srunner_create(Suite *suite) 78 { 79 SRunner *runner = calloc(1, sizeof(SRunner)); 80 if (runner != NULL) { 81 runner->suite = suite; 82 } 83 return runner; 84 } 85 86 static jmp_buf env; 87 88 static char const *_check_current_function = NULL; 89 static int _check_current_lineno = -1; 90 static char const *_check_current_filename = NULL; 91 92 void 93 _check_set_test_info(char const *function, char const *filename, int lineno) 94 { 95 _check_current_function = function; 96 _check_current_lineno = lineno; 97 _check_current_filename = filename; 98 } 99 100 101 static void 102 add_failure(SRunner *runner, int verbosity) 103 { 104 runner->nfailures++; 105 if (verbosity >= CK_VERBOSE) { 106 printf("%s:%d: %s\n", _check_current_filename, 107 _check_current_lineno, _check_current_function); 108 } 109 } 110 111 void 112 srunner_run_all(SRunner *runner, int verbosity) 113 { 114 Suite *suite; 115 TCase *tc; 116 assert(runner != NULL); 117 suite = runner->suite; 118 tc = suite->tests; 119 while (tc != NULL) { 120 int i; 121 for (i = 0; i < tc->ntests; ++i) { 122 runner->nchecks++; 123 124 if (tc->setup != NULL) { 125 /* setup */ 126 if (setjmp(env)) { 127 add_failure(runner, verbosity); 128 continue; 129 } 130 tc->setup(); 131 } 132 /* test */ 133 if (setjmp(env)) { 134 add_failure(runner, verbosity); 135 continue; 136 } 137 (tc->tests[i])(); 138 139 /* teardown */ 140 if (tc->teardown != NULL) { 141 if (setjmp(env)) { 142 add_failure(runner, verbosity); 143 continue; 144 } 145 tc->teardown(); 146 } 147 } 148 tc = tc->next_tcase; 149 } 150 if (verbosity) { 151 int passed = runner->nchecks - runner->nfailures; 152 double percentage = ((double) passed) / runner->nchecks; 153 int display = (int) (percentage * 100); 154 printf("%d%%: Checks: %d, Failed: %d\n", 155 display, runner->nchecks, runner->nfailures); 156 } 157 } 158 159 void 160 _fail_unless(int UNUSED_P(condition), const char *UNUSED_P(file), int UNUSED_P(line), const char *msg) 161 { 162 /* Always print the error message so it isn't lost. In this case, 163 we have a failure, so there's no reason to be quiet about what 164 it is. 165 */ 166 if (msg != NULL) 167 printf("%s", msg); 168 longjmp(env, 1); 169 } 170 171 int 172 srunner_ntests_failed(SRunner *runner) 173 { 174 assert(runner != NULL); 175 return runner->nfailures; 176 } 177 178 void 179 srunner_free(SRunner *runner) 180 { 181 free(runner->suite); 182 free(runner); 183 } 184