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