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 / _ \\ /| '_ \ / _` | __| 9 | __// \| |_) | (_| | |_ 10 \___/_/\_\ .__/ \__,_|\__| 11 |_| XML parser 12 13 Copyright (c) 1997-2000 Thai Open Source Software Center Ltd 14 Copyright (c) 2000-2017 Expat development team 15 Licensed under the MIT license: 16 17 Permission is hereby granted, free of charge, to any person obtaining 18 a copy of this software and associated documentation files (the 19 "Software"), to deal in the Software without restriction, including 20 without limitation the rights to use, copy, modify, merge, publish, 21 distribute, sublicense, and/or sell copies of the Software, and to permit 22 persons to whom the Software is furnished to do so, subject to the 23 following conditions: 24 25 The above copyright notice and this permission notice shall be included 26 in all copies or substantial portions of the Software. 27 28 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 29 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 30 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 31 NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 32 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 33 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 34 USE OR OTHER DEALINGS IN THE SOFTWARE. 35 */ 36 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <setjmp.h> 40 #include <assert.h> 41 #include <string.h> 42 43 #include "internal.h" /* for UNUSED_P only */ 44 #include "minicheck.h" 45 46 Suite * 47 suite_create(const char *name) 48 { 49 Suite *suite = (Suite *) calloc(1, sizeof(Suite)); 50 if (suite != NULL) { 51 suite->name = name; 52 } 53 return suite; 54 } 55 56 TCase * 57 tcase_create(const char *name) 58 { 59 TCase *tc = (TCase *) calloc(1, sizeof(TCase)); 60 if (tc != NULL) { 61 tc->name = name; 62 } 63 return tc; 64 } 65 66 void 67 suite_add_tcase(Suite *suite, TCase *tc) 68 { 69 assert(suite != NULL); 70 assert(tc != NULL); 71 assert(tc->next_tcase == NULL); 72 73 tc->next_tcase = suite->tests; 74 suite->tests = tc; 75 } 76 77 void 78 tcase_add_checked_fixture(TCase *tc, 79 tcase_setup_function setup, 80 tcase_teardown_function teardown) 81 { 82 assert(tc != NULL); 83 tc->setup = setup; 84 tc->teardown = teardown; 85 } 86 87 void 88 tcase_add_test(TCase *tc, tcase_test_function test) 89 { 90 assert(tc != NULL); 91 if (tc->allocated == tc->ntests) { 92 int nalloc = tc->allocated + 100; 93 size_t new_size = sizeof(tcase_test_function) * nalloc; 94 tcase_test_function *new_tests = realloc(tc->tests, new_size); 95 assert(new_tests != NULL); 96 tc->tests = new_tests; 97 tc->allocated = nalloc; 98 } 99 tc->tests[tc->ntests] = test; 100 tc->ntests++; 101 } 102 103 static void 104 tcase_free(TCase *tc) 105 { 106 if (! tc) { 107 return; 108 } 109 110 free(tc->tests); 111 free(tc); 112 } 113 114 static void 115 suite_free(Suite *suite) 116 { 117 if (! suite) { 118 return; 119 } 120 121 while (suite->tests != NULL) { 122 TCase *next = suite->tests->next_tcase; 123 tcase_free(suite->tests); 124 suite->tests = next; 125 } 126 free(suite); 127 } 128 129 SRunner * 130 srunner_create(Suite *suite) 131 { 132 SRunner *runner = calloc(1, sizeof(SRunner)); 133 if (runner != NULL) { 134 runner->suite = suite; 135 } 136 return runner; 137 } 138 139 static jmp_buf env; 140 141 static char const *_check_current_function = NULL; 142 static int _check_current_lineno = -1; 143 static char const *_check_current_filename = NULL; 144 145 void 146 _check_set_test_info(char const *function, char const *filename, int lineno) 147 { 148 _check_current_function = function; 149 _check_current_lineno = lineno; 150 _check_current_filename = filename; 151 } 152 153 154 static void 155 add_failure(SRunner *runner, int verbosity) 156 { 157 runner->nfailures++; 158 if (verbosity >= CK_VERBOSE) { 159 printf("%s:%d: %s\n", _check_current_filename, 160 _check_current_lineno, _check_current_function); 161 } 162 } 163 164 void 165 srunner_run_all(SRunner *runner, int verbosity) 166 { 167 Suite *suite; 168 TCase *tc; 169 assert(runner != NULL); 170 suite = runner->suite; 171 tc = suite->tests; 172 while (tc != NULL) { 173 int i; 174 for (i = 0; i < tc->ntests; ++i) { 175 runner->nchecks++; 176 177 if (tc->setup != NULL) { 178 /* setup */ 179 if (setjmp(env)) { 180 add_failure(runner, verbosity); 181 continue; 182 } 183 tc->setup(); 184 } 185 /* test */ 186 if (setjmp(env)) { 187 add_failure(runner, verbosity); 188 continue; 189 } 190 (tc->tests[i])(); 191 192 /* teardown */ 193 if (tc->teardown != NULL) { 194 if (setjmp(env)) { 195 add_failure(runner, verbosity); 196 continue; 197 } 198 tc->teardown(); 199 } 200 } 201 tc = tc->next_tcase; 202 } 203 if (verbosity) { 204 int passed = runner->nchecks - runner->nfailures; 205 double percentage = ((double) passed) / runner->nchecks; 206 int display = (int) (percentage * 100); 207 printf("%d%%: Checks: %d, Failed: %d\n", 208 display, runner->nchecks, runner->nfailures); 209 } 210 } 211 212 void 213 _fail_unless(int UNUSED_P(condition), const char *UNUSED_P(file), int UNUSED_P(line), const char *msg) 214 { 215 /* Always print the error message so it isn't lost. In this case, 216 we have a failure, so there's no reason to be quiet about what 217 it is. 218 */ 219 if (msg != NULL) { 220 const int has_newline = (msg[strlen(msg) - 1] == '\n'); 221 fprintf(stderr, "ERROR: %s%s", msg, has_newline ? "" : "\n"); 222 } 223 longjmp(env, 1); 224 } 225 226 int 227 srunner_ntests_failed(SRunner *runner) 228 { 229 assert(runner != NULL); 230 return runner->nfailures; 231 } 232 233 void 234 srunner_free(SRunner *runner) 235 { 236 if (! runner) { 237 return; 238 } 239 240 suite_free(runner->suite); 241 free(runner); 242 } 243