unity_runner.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. // Copyright 2016-2018 Espressif Systems (Shanghai) PTE LTD
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <stdbool.h>
  17. #include <ctype.h>
  18. #include <stdio.h>
  19. #include "unity.h"
  20. #include "esp_system.h"
  21. /* similar to UNITY_PRINT_EOL */
  22. #define UNITY_PRINT_TAB() UNITY_OUTPUT_CHAR('\t')
  23. // Pointers to the head and tail of linked list of test description structs:
  24. static test_desc_t *s_unity_tests_first = NULL;
  25. static test_desc_t *s_unity_tests_last = NULL;
  26. void unity_testcase_register(test_desc_t *desc)
  27. {
  28. if (!s_unity_tests_first) {
  29. s_unity_tests_first = desc;
  30. s_unity_tests_last = desc;
  31. } else {
  32. test_desc_t *temp = s_unity_tests_first;
  33. s_unity_tests_first = desc;
  34. s_unity_tests_first->next = temp;
  35. }
  36. }
  37. /* print the multiple function case name and its sub-menu
  38. * e.g:
  39. * (1) spi master/slave case
  40. * (1)master case
  41. * (2)slave case
  42. * */
  43. static void print_multiple_function_test_menu(const test_desc_t *test_ms)
  44. {
  45. UnityPrint(test_ms->name);
  46. UNITY_PRINT_EOL();
  47. for (int i = 0; i < test_ms->test_fn_count; i++) {
  48. UNITY_PRINT_TAB();
  49. UnityPrint("(");
  50. UnityPrintNumberUnsigned(i + 1);
  51. UnityPrint(")");
  52. UNITY_PRINT_TAB();
  53. UnityPrint("\"");
  54. UnityPrint(test_ms->test_fn_name[i]);
  55. UnityPrint("\"");
  56. UNITY_PRINT_EOL();
  57. }
  58. }
  59. /*
  60. * This function looks like UnityDefaultTestRun function only without UNITY_CLR_DETAILS.
  61. * void UnityDefaultTestRun(UnityTestFunction Func, const char* FuncName, const int FuncLineNum)
  62. * was moved from `components/unity/unity/src/unity.c` to here.
  63. */
  64. static void unity_default_test_run(UnityTestFunction Func, const char* FuncName, const int FuncLineNum)
  65. {
  66. Unity.CurrentTestName = FuncName;
  67. Unity.CurrentTestLineNumber = (UNITY_LINE_TYPE)FuncLineNum;
  68. Unity.NumberOfTests++;
  69. if (TEST_PROTECT())
  70. {
  71. setUp();
  72. Func();
  73. }
  74. if (TEST_PROTECT())
  75. {
  76. tearDown();
  77. }
  78. UnityConcludeTest();
  79. }
  80. static int multiple_function_option(const test_desc_t *test_ms)
  81. {
  82. int selection;
  83. char cmdline[256] = {0};
  84. print_multiple_function_test_menu(test_ms);
  85. while (strlen(cmdline) == 0) {
  86. unity_gets(cmdline, sizeof(cmdline));
  87. if (strlen(cmdline) == 0) {
  88. /* if input was newline, print a new menu */
  89. print_multiple_function_test_menu(test_ms);
  90. }
  91. }
  92. selection = atoi((const char *) cmdline) - 1;
  93. if (selection >= 0 && selection < test_ms->test_fn_count) {
  94. unity_default_test_run(test_ms->fn[selection], test_ms->name, test_ms->line);
  95. } else {
  96. UnityPrint("Invalid selection, your should input number 1-");
  97. UnityPrintNumber(test_ms->test_fn_count);
  98. UNITY_PRINT_EOL();
  99. }
  100. return selection;
  101. }
  102. static void unity_run_single_test(const test_desc_t *test)
  103. {
  104. UnityPrint("Running ");
  105. UnityPrint(test->name);
  106. UnityPrint("...");
  107. UNITY_PRINT_EOL();
  108. // Unit test runner expects to see test name before the test starts
  109. UNITY_OUTPUT_FLUSH();
  110. Unity.TestFile = test->file;
  111. Unity.CurrentDetail1 = test->desc;
  112. bool reset_after_test = strstr(Unity.CurrentDetail1, "[leaks") != NULL;
  113. bool multi_device = strstr(Unity.CurrentDetail1, "[multi_device]") != NULL;
  114. if (test->test_fn_count == 1) {
  115. unity_default_test_run(test->fn[0], test->name, test->line);
  116. } else {
  117. int selection = multiple_function_option(test);
  118. if (reset_after_test && multi_device == false) {
  119. if (selection != (test->test_fn_count - 1)) {
  120. // to do a reset for all stages except the last stage.
  121. esp_restart();
  122. }
  123. }
  124. }
  125. if (reset_after_test) {
  126. // print a result of test before to do reset for the last stage.
  127. UNITY_END();
  128. UnityPrint("Enter next test, or 'enter' to see menu");
  129. UNITY_PRINT_EOL();
  130. UNITY_OUTPUT_FLUSH();
  131. esp_restart();
  132. }
  133. }
  134. static void unity_run_single_test_by_index(int index)
  135. {
  136. const test_desc_t *test;
  137. for (test = s_unity_tests_first; test != NULL && index != 0; test = test->next, --index) {
  138. ;
  139. }
  140. if (test != NULL) {
  141. unity_run_single_test(test);
  142. }
  143. }
  144. static void unity_run_single_test_by_index_parse(const char *filter, int index_max)
  145. {
  146. int test_index = strtol(filter, NULL, 10);
  147. if (test_index >= 1 && test_index <= index_max) {
  148. UNITY_EXEC_TIME_START();
  149. unity_run_single_test_by_index(test_index - 1);
  150. UNITY_EXEC_TIME_STOP();
  151. UnityPrint("Test ran in ");
  152. UnityPrintNumberUnsigned(UNITY_EXEC_TIME_MS());
  153. UnityPrint("ms");
  154. UNITY_PRINT_EOL();
  155. UNITY_OUTPUT_FLUSH();
  156. }
  157. }
  158. void unity_run_test_by_name(const char *name)
  159. {
  160. for (const test_desc_t *test = s_unity_tests_first; test != NULL; test = test->next) {
  161. if (strcmp(test->name, name) == 0) {
  162. unity_run_single_test(test);
  163. }
  164. }
  165. }
  166. void unity_run_all_tests()
  167. {
  168. for (const test_desc_t *test = s_unity_tests_first; test != NULL; test = test->next) {
  169. unity_run_single_test(test);
  170. }
  171. }
  172. void unity_run_tests_by_tag(const char *tag, bool invert)
  173. {
  174. UnityPrint("Running tests ");
  175. if (invert) {
  176. UnityPrint("NOT ");
  177. }
  178. UnityPrint("matching '");
  179. UnityPrint(tag);
  180. UnityPrint("'...");
  181. UNITY_PRINT_EOL();
  182. for (const test_desc_t *test = s_unity_tests_first; test != NULL; test = test->next) {
  183. if ((strstr(test->desc, tag) != NULL) == !invert) {
  184. unity_run_single_test(test);
  185. }
  186. }
  187. }
  188. static void trim_trailing_space(char *str)
  189. {
  190. char *end = str + strlen(str) - 1;
  191. while (end >= str && isspace((int) *end)) {
  192. *end = 0;
  193. --end;
  194. }
  195. }
  196. static int print_test_menu(void)
  197. {
  198. int test_counter = 0;
  199. UNITY_PRINT_EOL();
  200. UNITY_PRINT_EOL();
  201. UnityPrint("Here's the test menu, pick your combo:");
  202. UNITY_PRINT_EOL();
  203. for (const test_desc_t *test = s_unity_tests_first;
  204. test != NULL;
  205. test = test->next, ++test_counter) {
  206. UnityPrint("(");
  207. UnityPrintNumber(test_counter + 1);
  208. UnityPrint(")");
  209. UNITY_PRINT_TAB();
  210. UnityPrint("\"");
  211. UnityPrint(test->name);
  212. UnityPrint("\" ");
  213. UnityPrint(test->desc);
  214. UNITY_PRINT_EOL();
  215. if (test->test_fn_count > 1) {
  216. for (int i = 0; i < test->test_fn_count; i++) {
  217. UNITY_PRINT_TAB();
  218. UnityPrint("(");
  219. UnityPrintNumber(i + 1);
  220. UnityPrint(")");
  221. UNITY_PRINT_TAB();
  222. UnityPrint("\"");
  223. UnityPrint(test->test_fn_name[i]);
  224. UnityPrint("\"");
  225. UNITY_PRINT_EOL();
  226. }
  227. }
  228. }
  229. UNITY_PRINT_EOL();
  230. UnityPrint("Enter test for running."); /* unit_test.py needs it for finding the end of test menu */
  231. UNITY_PRINT_EOL();
  232. UNITY_OUTPUT_FLUSH();
  233. return test_counter;
  234. }
  235. static int get_test_count(void)
  236. {
  237. int test_counter = 0;
  238. for (const test_desc_t *test = s_unity_tests_first;
  239. test != NULL;
  240. test = test->next) {
  241. ++test_counter;
  242. }
  243. return test_counter;
  244. }
  245. void unity_run_menu()
  246. {
  247. UNITY_PRINT_EOL();
  248. UNITY_PRINT_EOL();
  249. UnityPrint("Press ENTER to see the list of tests.");
  250. UNITY_PRINT_EOL();
  251. int test_count = get_test_count();
  252. while (true) {
  253. char cmdline[256] = { 0 };
  254. while (strlen(cmdline) == 0) {
  255. unity_gets(cmdline, sizeof(cmdline));
  256. trim_trailing_space(cmdline);
  257. if (strlen(cmdline) == 0) {
  258. /* if input was newline, print a new menu */
  259. print_test_menu();
  260. }
  261. }
  262. /*use '-' to show test history. Need to do it before UNITY_BEGIN cleanup history */
  263. if (cmdline[0] == '-') {
  264. UNITY_END();
  265. continue;
  266. }
  267. UNITY_BEGIN();
  268. size_t idx = 0;
  269. bool invert = false;
  270. if (cmdline[idx] == '!') {
  271. invert = true;
  272. ++idx;
  273. }
  274. if (cmdline[idx] == '*') {
  275. unity_run_all_tests();
  276. } else if (cmdline[idx] == '[') {
  277. unity_run_tests_by_tag(cmdline + idx, invert);
  278. } else if (cmdline[idx] == '"') {
  279. char* end = strrchr(cmdline, '"');
  280. if (end > &cmdline[idx]) {
  281. *end = 0;
  282. unity_run_test_by_name(cmdline + idx + 1);
  283. }
  284. } else if (isdigit((unsigned char)cmdline[idx])) {
  285. unity_run_single_test_by_index_parse(cmdline + idx, test_count);
  286. }
  287. UNITY_END();
  288. UnityPrint("Enter next test, or 'enter' to see menu");
  289. UNITY_PRINT_EOL();
  290. UNITY_OUTPUT_FLUSH();
  291. }
  292. }