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 Suite *suite = (Suite *)calloc(1, sizeof(Suite)); 49 if (suite != NULL) { 50 suite->name = name; 51 } 52 return suite; 53 } 54 55 TCase * 56 tcase_create(const char *name) { 57 TCase *tc = (TCase *)calloc(1, sizeof(TCase)); 58 if (tc != NULL) { 59 tc->name = name; 60 } 61 return tc; 62 } 63 64 void 65 suite_add_tcase(Suite *suite, TCase *tc) { 66 assert(suite != NULL); 67 assert(tc != NULL); 68 assert(tc->next_tcase == NULL); 69 70 tc->next_tcase = suite->tests; 71 suite->tests = tc; 72 } 73 74 void 75 tcase_add_checked_fixture(TCase *tc, tcase_setup_function setup, 76 tcase_teardown_function teardown) { 77 assert(tc != NULL); 78 tc->setup = setup; 79 tc->teardown = teardown; 80 } 81 82 void 83 tcase_add_test(TCase *tc, tcase_test_function test) { 84 assert(tc != NULL); 85 if (tc->allocated == tc->ntests) { 86 int nalloc = tc->allocated + 100; 87 size_t new_size = sizeof(tcase_test_function) * nalloc; 88 tcase_test_function *new_tests = realloc(tc->tests, new_size); 89 assert(new_tests != NULL); 90 tc->tests = new_tests; 91 tc->allocated = nalloc; 92 } 93 tc->tests[tc->ntests] = test; 94 tc->ntests++; 95 } 96 97 static void 98 tcase_free(TCase *tc) { 99 if (! tc) { 100 return; 101 } 102 103 free(tc->tests); 104 free(tc); 105 } 106 107 static void 108 suite_free(Suite *suite) { 109 if (! suite) { 110 return; 111 } 112 113 while (suite->tests != NULL) { 114 TCase *next = suite->tests->next_tcase; 115 tcase_free(suite->tests); 116 suite->tests = next; 117 } 118 free(suite); 119 } 120 121 SRunner * 122 srunner_create(Suite *suite) { 123 SRunner *runner = calloc(1, sizeof(SRunner)); 124 if (runner != NULL) { 125 runner->suite = suite; 126 } 127 return runner; 128 } 129 130 static jmp_buf env; 131 132 static char const *_check_current_function = NULL; 133 static int _check_current_lineno = -1; 134 static char const *_check_current_filename = NULL; 135 136 void 137 _check_set_test_info(char const *function, char const *filename, int lineno) { 138 _check_current_function = function; 139 _check_current_lineno = lineno; 140 _check_current_filename = filename; 141 } 142 143 static void 144 handle_success(int verbosity) { 145 if (verbosity >= CK_VERBOSE) { 146 printf("PASS: %s\n", _check_current_function); 147 } 148 } 149 150 static void 151 handle_failure(SRunner *runner, int verbosity, const char *phase_info) { 152 runner->nfailures++; 153 if (verbosity != CK_SILENT) { 154 printf("FAIL: %s (%s at %s:%d)\n", _check_current_function, phase_info, 155 _check_current_filename, _check_current_lineno); 156 } 157 } 158 159 void 160 srunner_run_all(SRunner *runner, int verbosity) { 161 Suite *suite; 162 TCase *volatile tc; 163 assert(runner != NULL); 164 suite = runner->suite; 165 tc = suite->tests; 166 while (tc != NULL) { 167 volatile int i; 168 for (i = 0; i < tc->ntests; ++i) { 169 runner->nchecks++; 170 171 if (tc->setup != NULL) { 172 /* setup */ 173 if (setjmp(env)) { 174 handle_failure(runner, verbosity, "during setup"); 175 continue; 176 } 177 tc->setup(); 178 } 179 /* test */ 180 if (setjmp(env)) { 181 handle_failure(runner, verbosity, "during actual test"); 182 continue; 183 } 184 (tc->tests[i])(); 185 186 /* teardown */ 187 if (tc->teardown != NULL) { 188 if (setjmp(env)) { 189 handle_failure(runner, verbosity, "during teardown"); 190 continue; 191 } 192 tc->teardown(); 193 } 194 195 handle_success(verbosity); 196 } 197 tc = tc->next_tcase; 198 } 199 if (verbosity != CK_SILENT) { 200 int passed = runner->nchecks - runner->nfailures; 201 double percentage = ((double)passed) / runner->nchecks; 202 int display = (int)(percentage * 100); 203 printf("%d%%: Checks: %d, Failed: %d\n", display, runner->nchecks, 204 runner->nfailures); 205 } 206 } 207 208 void 209 _fail_unless(int condition, const char *file, int line, const char *msg) { 210 /* Always print the error message so it isn't lost. In this case, 211 we have a failure, so there's no reason to be quiet about what 212 it is. 213 */ 214 UNUSED_P(condition); 215 _check_current_filename = file; 216 _check_current_lineno = line; 217 if (msg != NULL) { 218 const int has_newline = (msg[strlen(msg) - 1] == '\n'); 219 fprintf(stderr, "ERROR: %s%s", msg, has_newline ? "" : "\n"); 220 } 221 longjmp(env, 1); 222 } 223 224 int 225 srunner_ntests_failed(SRunner *runner) { 226 assert(runner != NULL); 227 return runner->nfailures; 228 } 229 230 void 231 srunner_free(SRunner *runner) { 232 if (! runner) { 233 return; 234 } 235 236 suite_free(runner->suite); 237 free(runner); 238 } 239