1178848Scokane/* Miniature re-implementation of the "check" library. 2178848Scokane 3355604Sdelphij This is intended to support just enough of check to run the Expat 4355604Sdelphij tests. This interface is based entirely on the portion of the 5355604Sdelphij check library being used. 6355604Sdelphij __ __ _ 7355604Sdelphij ___\ \/ /_ __ __ _| |_ 8355604Sdelphij / _ \\ /| '_ \ / _` | __| 9355604Sdelphij | __// \| |_) | (_| | |_ 10355604Sdelphij \___/_/\_\ .__/ \__,_|\__| 11355604Sdelphij |_| XML parser 12355604Sdelphij 13355604Sdelphij Copyright (c) 1997-2000 Thai Open Source Software Center Ltd 14355604Sdelphij Copyright (c) 2000-2017 Expat development team 15355604Sdelphij Licensed under the MIT license: 16355604Sdelphij 17355604Sdelphij Permission is hereby granted, free of charge, to any person obtaining 18355604Sdelphij a copy of this software and associated documentation files (the 19355604Sdelphij "Software"), to deal in the Software without restriction, including 20355604Sdelphij without limitation the rights to use, copy, modify, merge, publish, 21355604Sdelphij distribute, sublicense, and/or sell copies of the Software, and to permit 22355604Sdelphij persons to whom the Software is furnished to do so, subject to the 23355604Sdelphij following conditions: 24355604Sdelphij 25355604Sdelphij The above copyright notice and this permission notice shall be included 26355604Sdelphij in all copies or substantial portions of the Software. 27355604Sdelphij 28355604Sdelphij THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 29355604Sdelphij EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 30355604Sdelphij MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 31355604Sdelphij NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 32355604Sdelphij DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 33355604Sdelphij OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 34355604Sdelphij USE OR OTHER DEALINGS IN THE SOFTWARE. 35355604Sdelphij*/ 36355604Sdelphij 37178848Scokane#include <stdio.h> 38178848Scokane#include <stdlib.h> 39178848Scokane#include <setjmp.h> 40178848Scokane#include <assert.h> 41355604Sdelphij#include <string.h> 42178848Scokane 43355604Sdelphij#include "internal.h" /* for UNUSED_P only */ 44178848Scokane#include "minicheck.h" 45178848Scokane 46178848ScokaneSuite * 47355604Sdelphijsuite_create(const char *name) { 48355604Sdelphij Suite *suite = (Suite *)calloc(1, sizeof(Suite)); 49355604Sdelphij if (suite != NULL) { 50355604Sdelphij suite->name = name; 51355604Sdelphij } 52355604Sdelphij return suite; 53178848Scokane} 54178848Scokane 55178848ScokaneTCase * 56355604Sdelphijtcase_create(const char *name) { 57355604Sdelphij TCase *tc = (TCase *)calloc(1, sizeof(TCase)); 58355604Sdelphij if (tc != NULL) { 59355604Sdelphij tc->name = name; 60355604Sdelphij } 61355604Sdelphij return tc; 62178848Scokane} 63178848Scokane 64178848Scokanevoid 65355604Sdelphijsuite_add_tcase(Suite *suite, TCase *tc) { 66355604Sdelphij assert(suite != NULL); 67355604Sdelphij assert(tc != NULL); 68355604Sdelphij assert(tc->next_tcase == NULL); 69178848Scokane 70355604Sdelphij tc->next_tcase = suite->tests; 71355604Sdelphij suite->tests = tc; 72178848Scokane} 73178848Scokane 74178848Scokanevoid 75355604Sdelphijtcase_add_checked_fixture(TCase *tc, tcase_setup_function setup, 76355604Sdelphij tcase_teardown_function teardown) { 77355604Sdelphij assert(tc != NULL); 78355604Sdelphij tc->setup = setup; 79355604Sdelphij tc->teardown = teardown; 80178848Scokane} 81178848Scokane 82178848Scokanevoid 83355604Sdelphijtcase_add_test(TCase *tc, tcase_test_function test) { 84355604Sdelphij assert(tc != NULL); 85355604Sdelphij if (tc->allocated == tc->ntests) { 86355604Sdelphij int nalloc = tc->allocated + 100; 87355604Sdelphij size_t new_size = sizeof(tcase_test_function) * nalloc; 88355604Sdelphij tcase_test_function *new_tests = realloc(tc->tests, new_size); 89355604Sdelphij assert(new_tests != NULL); 90355604Sdelphij tc->tests = new_tests; 91355604Sdelphij tc->allocated = nalloc; 92355604Sdelphij } 93355604Sdelphij tc->tests[tc->ntests] = test; 94355604Sdelphij tc->ntests++; 95178848Scokane} 96178848Scokane 97355604Sdelphijstatic void 98355604Sdelphijtcase_free(TCase *tc) { 99355604Sdelphij if (! tc) { 100355604Sdelphij return; 101355604Sdelphij } 102355604Sdelphij 103355604Sdelphij free(tc->tests); 104355604Sdelphij free(tc); 105355604Sdelphij} 106355604Sdelphij 107355604Sdelphijstatic void 108355604Sdelphijsuite_free(Suite *suite) { 109355604Sdelphij if (! suite) { 110355604Sdelphij return; 111355604Sdelphij } 112355604Sdelphij 113355604Sdelphij while (suite->tests != NULL) { 114355604Sdelphij TCase *next = suite->tests->next_tcase; 115355604Sdelphij tcase_free(suite->tests); 116355604Sdelphij suite->tests = next; 117355604Sdelphij } 118355604Sdelphij free(suite); 119355604Sdelphij} 120355604Sdelphij 121178848ScokaneSRunner * 122355604Sdelphijsrunner_create(Suite *suite) { 123355604Sdelphij SRunner *runner = calloc(1, sizeof(SRunner)); 124355604Sdelphij if (runner != NULL) { 125355604Sdelphij runner->suite = suite; 126355604Sdelphij } 127355604Sdelphij return runner; 128178848Scokane} 129178848Scokane 130178848Scokanestatic jmp_buf env; 131178848Scokane 132178848Scokanestatic char const *_check_current_function = NULL; 133178848Scokanestatic int _check_current_lineno = -1; 134178848Scokanestatic char const *_check_current_filename = NULL; 135178848Scokane 136178848Scokanevoid 137355604Sdelphij_check_set_test_info(char const *function, char const *filename, int lineno) { 138355604Sdelphij _check_current_function = function; 139355604Sdelphij _check_current_lineno = lineno; 140355604Sdelphij _check_current_filename = filename; 141178848Scokane} 142178848Scokane 143178848Scokanestatic void 144355604Sdelphijadd_failure(SRunner *runner, int verbosity) { 145355604Sdelphij runner->nfailures++; 146355604Sdelphij if (verbosity >= CK_VERBOSE) { 147355604Sdelphij printf("%s:%d: %s\n", _check_current_filename, _check_current_lineno, 148355604Sdelphij _check_current_function); 149355604Sdelphij } 150178848Scokane} 151178848Scokane 152178848Scokanevoid 153355604Sdelphijsrunner_run_all(SRunner *runner, int verbosity) { 154355604Sdelphij Suite *suite; 155355604Sdelphij TCase *volatile tc; 156355604Sdelphij assert(runner != NULL); 157355604Sdelphij suite = runner->suite; 158355604Sdelphij tc = suite->tests; 159355604Sdelphij while (tc != NULL) { 160355604Sdelphij volatile int i; 161355604Sdelphij for (i = 0; i < tc->ntests; ++i) { 162355604Sdelphij runner->nchecks++; 163178848Scokane 164355604Sdelphij if (tc->setup != NULL) { 165355604Sdelphij /* setup */ 166355604Sdelphij if (setjmp(env)) { 167355604Sdelphij add_failure(runner, verbosity); 168355604Sdelphij continue; 169355604Sdelphij } 170355604Sdelphij tc->setup(); 171355604Sdelphij } 172355604Sdelphij /* test */ 173355604Sdelphij if (setjmp(env)) { 174355604Sdelphij add_failure(runner, verbosity); 175355604Sdelphij continue; 176355604Sdelphij } 177355604Sdelphij (tc->tests[i])(); 178178848Scokane 179355604Sdelphij /* teardown */ 180355604Sdelphij if (tc->teardown != NULL) { 181355604Sdelphij if (setjmp(env)) { 182355604Sdelphij add_failure(runner, verbosity); 183355604Sdelphij continue; 184178848Scokane } 185355604Sdelphij tc->teardown(); 186355604Sdelphij } 187178848Scokane } 188355604Sdelphij tc = tc->next_tcase; 189355604Sdelphij } 190355604Sdelphij if (verbosity) { 191355604Sdelphij int passed = runner->nchecks - runner->nfailures; 192355604Sdelphij double percentage = ((double)passed) / runner->nchecks; 193355604Sdelphij int display = (int)(percentage * 100); 194355604Sdelphij printf("%d%%: Checks: %d, Failed: %d\n", display, runner->nchecks, 195355604Sdelphij runner->nfailures); 196355604Sdelphij } 197178848Scokane} 198178848Scokane 199178848Scokanevoid 200355604Sdelphij_fail_unless(int condition, const char *file, int line, const char *msg) { 201355604Sdelphij /* Always print the error message so it isn't lost. In this case, 202355604Sdelphij we have a failure, so there's no reason to be quiet about what 203355604Sdelphij it is. 204355604Sdelphij */ 205355604Sdelphij UNUSED_P(condition); 206355604Sdelphij UNUSED_P(file); 207355604Sdelphij UNUSED_P(line); 208355604Sdelphij if (msg != NULL) { 209355604Sdelphij const int has_newline = (msg[strlen(msg) - 1] == '\n'); 210355604Sdelphij fprintf(stderr, "ERROR: %s%s", msg, has_newline ? "" : "\n"); 211355604Sdelphij } 212355604Sdelphij longjmp(env, 1); 213178848Scokane} 214178848Scokane 215178848Scokaneint 216355604Sdelphijsrunner_ntests_failed(SRunner *runner) { 217355604Sdelphij assert(runner != NULL); 218355604Sdelphij return runner->nfailures; 219178848Scokane} 220178848Scokane 221178848Scokanevoid 222355604Sdelphijsrunner_free(SRunner *runner) { 223355604Sdelphij if (! runner) { 224355604Sdelphij return; 225355604Sdelphij } 226355604Sdelphij 227355604Sdelphij suite_free(runner->suite); 228355604Sdelphij free(runner); 229178848Scokane} 230