minicheck.c 4.5 KB

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