testrunner.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. /*
  2. * testrunner.c
  3. *
  4. * Created on: Jun 18, 2013
  5. * Author: petera
  6. */
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include <sys/types.h>
  11. #include <sys/stat.h>
  12. #include <fcntl.h>
  13. #include <dirent.h>
  14. #include <unistd.h>
  15. #include "testrunner.h"
  16. static struct {
  17. test *tests;
  18. test *_last_test;
  19. int test_count;
  20. void (*on_stop)(test *t);
  21. test_res *failed;
  22. test_res *failed_last;
  23. test_res *stopped;
  24. test_res *stopped_last;
  25. FILE *spec;
  26. } test_main;
  27. void test_init(void (*on_stop)(test *t)) {
  28. test_main.on_stop = on_stop;
  29. }
  30. static char check_spec(char *name) {
  31. if (test_main.spec) {
  32. fseek(test_main.spec, 0, SEEK_SET);
  33. char *line = NULL;
  34. size_t sz;
  35. ssize_t read;
  36. while ((read = getline(&line, &sz, test_main.spec)) != -1) {
  37. if (strncmp(line, name, strlen(name)) == 0) {
  38. free(line);
  39. return 1;
  40. }
  41. }
  42. free(line);
  43. return 0;
  44. } else {
  45. return 1;
  46. }
  47. }
  48. void add_test(test_f f, char *name, void (*setup)(test *t), void (*teardown)(test *t)) {
  49. if (f == 0) return;
  50. if (!check_spec(name)) return;
  51. DBGT("adding test %s\n", name);
  52. test *t = malloc(sizeof(test));
  53. memset(t, 0, sizeof(test));
  54. t->f = f;
  55. strcpy(t->name, name);
  56. t->setup = setup;
  57. t->teardown = teardown;
  58. if (test_main.tests == 0) {
  59. test_main.tests = t;
  60. } else {
  61. test_main._last_test->_next = t;
  62. }
  63. test_main._last_test = t;
  64. test_main.test_count++;
  65. }
  66. static void add_res(test *t, test_res **head, test_res **last) {
  67. test_res *tr = malloc(sizeof(test_res));
  68. memset(tr,0,sizeof(test_res));
  69. strcpy(tr->name, t->name);
  70. if (*head == 0) {
  71. *head = tr;
  72. } else {
  73. (*last)->_next = tr;
  74. }
  75. *last = tr;
  76. }
  77. static void dump_res(test_res **head) {
  78. test_res *tr = (*head);
  79. while (tr) {
  80. test_res *next_tr = tr->_next;
  81. printf(" %s\n", tr->name);
  82. free(tr);
  83. tr = next_tr;
  84. }
  85. }
  86. void run_tests(int argc, char **args) {
  87. memset(&test_main, 0, sizeof(test_main));
  88. if (argc > 1) {
  89. printf("running tests from %s\n", args[1]);
  90. FILE *fd = fopen(args[1], "r");
  91. if (fd == NULL) {
  92. printf("%s not found\n", args[1]);
  93. exit(EXIT_FAILURE);
  94. }
  95. test_main.spec = fd;
  96. }
  97. DBGT("adding suites...\n");
  98. add_suites();
  99. DBGT("%i tests added\n", test_main.test_count);
  100. if (test_main.spec) {
  101. fclose(test_main.spec);
  102. }
  103. if (test_main.test_count == 0) {
  104. printf("No tests to run\n");
  105. return;
  106. }
  107. int fd_success = open("_tests_ok", O_APPEND | O_TRUNC | O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
  108. int fd_bad = open("_tests_fail", O_APPEND | O_TRUNC | O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
  109. DBGT("running tests...\n");
  110. int ok = 0;
  111. int failed = 0;
  112. int stopped = 0;
  113. test *cur_t = test_main.tests;
  114. int i = 1;
  115. while (cur_t) {
  116. cur_t->setup(cur_t);
  117. test *next_test = cur_t->_next;
  118. DBGT("TEST %i/%i : running test %s\n", i, test_main.test_count, cur_t->name);
  119. i++;
  120. int res = cur_t->f(cur_t);
  121. cur_t->teardown(cur_t);
  122. int fd = res == TEST_RES_OK ? fd_success : fd_bad;
  123. write(fd, cur_t->name, strlen(cur_t->name));
  124. write(fd, "\n", 1);
  125. switch (res) {
  126. case TEST_RES_OK:
  127. ok++;
  128. printf(" .. ok\n");
  129. break;
  130. case TEST_RES_FAIL:
  131. failed++;
  132. printf(" .. FAILED\n");
  133. if (test_main.on_stop) test_main.on_stop(cur_t);
  134. add_res(cur_t, &test_main.failed, &test_main.failed_last);
  135. break;
  136. case TEST_RES_ASSERT:
  137. stopped++;
  138. printf(" .. ABORTED\n");
  139. if (test_main.on_stop) test_main.on_stop(cur_t);
  140. add_res(cur_t, &test_main.stopped, &test_main.stopped_last);
  141. break;
  142. }
  143. free(cur_t);
  144. cur_t = next_test;
  145. }
  146. close(fd_success);
  147. close(fd_bad);
  148. DBGT("ran %i tests\n", test_main.test_count);
  149. printf("Test report, %i tests\n", test_main.test_count);
  150. printf("%i succeeded\n", ok);
  151. printf("%i failed\n", failed);
  152. dump_res(&test_main.failed);
  153. printf("%i stopped\n", stopped);
  154. dump_res(&test_main.stopped);
  155. if (ok < test_main.test_count) {
  156. printf("\nFAILED\n");
  157. } else {
  158. printf("\nALL TESTS OK\n");
  159. }
  160. }