tb_test.cpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. // ================================================================================
  2. // == This file is a part of Turbo Badger. (C) 2011-2014, Emil Segerås ==
  3. // == See tb_core.h for more information. ==
  4. // ================================================================================
  5. #include "tb_test.h"
  6. #include "tb_system.h"
  7. #ifdef TB_UNIT_TESTING
  8. // Reference at least one group in each test file, to force
  9. // linking the object file. This is needed if TB is compiled
  10. // as an library.
  11. TB_FORCE_LINK_TEST_GROUP(tb_color);
  12. TB_FORCE_LINK_TEST_GROUP(tb_dimension_converter);
  13. TB_FORCE_LINK_TEST_GROUP(tb_geometry);
  14. TB_FORCE_LINK_TEST_GROUP(tb_linklist);
  15. TB_FORCE_LINK_TEST_GROUP(tb_node_ref_tree);
  16. TB_FORCE_LINK_TEST_GROUP(tb_object);
  17. TB_FORCE_LINK_TEST_GROUP(tb_parser);
  18. TB_FORCE_LINK_TEST_GROUP(tb_space_allocator);
  19. TB_FORCE_LINK_TEST_GROUP(tb_editfield);
  20. TB_FORCE_LINK_TEST_GROUP(tb_tempbuffer);
  21. TB_FORCE_LINK_TEST_GROUP(tb_test);
  22. TB_FORCE_LINK_TEST_GROUP(tb_value);
  23. TB_FORCE_LINK_TEST_GROUP(tb_widget_value_text);
  24. #endif
  25. namespace tb {
  26. #ifdef TB_UNIT_TESTING
  27. uint32 test_settings;
  28. int fail_line_nr;
  29. const char *fail_file;
  30. const char *fail_text;
  31. // We can't use a linked list object since we don't know if its constructor
  32. // would run before of after any test group constructor that add itself
  33. // to it. Using a manual one way link list is very simple.
  34. TBTestGroup *g_test_groups = nullptr;
  35. // == Misc functions ==========================================================
  36. TBStr tb_get_test_file_name(const char *testpath, const char *filename)
  37. {
  38. TBStr str;
  39. int test_path_len = strlen(testpath);
  40. for (int i = test_path_len - 1; i > 0 && testpath[i] != '/' && testpath[i] != '\\'; i--)
  41. test_path_len = i;
  42. str.Set(testpath, test_path_len);
  43. str.Append(filename);
  44. return str;
  45. }
  46. // == TBRegisterCall ==========================================================
  47. TBRegisterCall::TBRegisterCall(TBTestGroup *test, TBCall *call)
  48. : call(call)
  49. {
  50. if (strcmp(call->name(), "Setup") == 0)
  51. test->setup = call;
  52. else if (strcmp(call->name(), "Cleanup") == 0)
  53. test->cleanup = call;
  54. else if (strcmp(call->name(), "Init") == 0)
  55. test->init = call;
  56. else if (strcmp(call->name(), "Shutdown") == 0)
  57. test->shutdown = call;
  58. else
  59. test->calls.AddLast(call);
  60. }
  61. TBRegisterCall::~TBRegisterCall()
  62. {
  63. if (call->linklist)
  64. call->linklist->Remove(call);
  65. }
  66. // == TBTestGroup =============================================================
  67. TBTestGroup::TBTestGroup(const char *name)
  68. : name(name), setup(nullptr), cleanup(nullptr), init(nullptr), shutdown(nullptr), next_test_group(g_test_groups)
  69. {
  70. g_test_groups = this;
  71. }
  72. const char *CallAndOutput(TBTestGroup *test, TBCall *call)
  73. {
  74. fail_text = nullptr;
  75. call->exec();
  76. if (!fail_text)
  77. return fail_text;
  78. TBStr msg;
  79. msg.SetFormatted("FAIL: \"%s/%s\":\n"
  80. " %s(%d): \"%s\"\n",
  81. test->name, call->name(),
  82. fail_file, fail_line_nr, fail_text);
  83. TBDebugOut(msg);
  84. return fail_text;
  85. }
  86. void OutputPass(TBTestGroup *test, const char *call_name)
  87. {
  88. if (!(test_settings & TB_TEST_VERBOSE))
  89. return;
  90. TBStr msg;
  91. msg.SetFormatted("PASS: \"%s/%s\"\n",
  92. test->name, call_name);
  93. TBDebugOut(msg);
  94. }
  95. int TBRunTests(uint32 settings)
  96. {
  97. test_settings = settings;
  98. int num_failed = 0;
  99. int num_passed = 0;
  100. TBDebugOut("Running tests...\n");
  101. for (TBTestGroup *group = g_test_groups; group; group = group->next_test_group)
  102. {
  103. if (group->init && CallAndOutput(group, group->init))
  104. {
  105. // The whole group failed because init failed.
  106. int num_tests_in_group = 0;
  107. for (TBCall *call = group->calls.GetFirst(); call; call = call->GetNext())
  108. if (!group->IsSpecialTest(call))
  109. num_tests_in_group++;
  110. TBStr msg;
  111. msg.SetFormatted(" %d tests skipped.\n", num_tests_in_group);
  112. TBDebugOut(msg);
  113. num_failed += num_tests_in_group;
  114. continue;
  115. }
  116. for (TBCall *call = group->calls.GetFirst(); call; call = call->GetNext())
  117. {
  118. // Execute test (and call setup and cleanup if available).
  119. int fail = 0;
  120. if (group->setup)
  121. fail = !!CallAndOutput(group, group->setup);
  122. if (!fail) // Only run if setup succeeded
  123. {
  124. fail |= !!CallAndOutput(group, call);
  125. if (group->cleanup)
  126. fail |= !!CallAndOutput(group, group->cleanup);
  127. }
  128. // Handle result
  129. if (fail)
  130. num_failed++;
  131. else
  132. {
  133. num_passed++;
  134. OutputPass(group, call->name());
  135. }
  136. }
  137. if (group->shutdown && CallAndOutput(group, group->shutdown))
  138. CallAndOutput(group, group->shutdown);
  139. }
  140. TBStr msg;
  141. msg.SetFormatted("Test results: %d passed, %d failed.\n", num_passed, num_failed);
  142. TBDebugOut(msg);
  143. return num_failed;
  144. }
  145. #endif // TB_UNIT_TESTING
  146. }; // namespace tb