tb_test.h 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  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. #ifndef TB_TEST_H
  6. #define TB_TEST_H
  7. /**
  8. This file contains a very simple unit testing framework.
  9. There are more capable unit testing frameworks available (that
  10. might be more suitable if you need extensive testing of your target
  11. application.
  12. I've chosen to not use any other framework for internal testing of
  13. Turbo Badger to minimize dependences.
  14. Test groups and tests:
  15. ---------------------
  16. Tests are specified in named groups, that can contain multiple named tests
  17. that are run in the order specified, except for special tests.
  18. Special tests are test with the names Init, Shutdown, Setup, Cleanup.
  19. They can be left out if they are not needed.
  20. Init and Shutdown - Called once per group. If Init fail, the tests in the
  21. group and Shutdown will be skipped.
  22. Setup and Cleanup - Called once per test. If Setup fail, the current test
  23. and Cleanup will be skipped.
  24. How to define a single test:
  25. ---------------------------
  26. TB_TEST_GROUP(groupname)
  27. {
  28. TB_TEST(testname)
  29. {
  30. // Here goes test code and calls
  31. // to TB_VERIFY, TB_PASS, TB_FAIL etc.
  32. TB_VERIFY(1);
  33. }
  34. }
  35. How to define multiple tests, with data, setup and cleanup:
  36. ----------------------------------------------------------
  37. TB_TEST_GROUP(groupname)
  38. {
  39. // Here goes the data for this group
  40. TBStr str;
  41. // Here goes methods with access to data
  42. bool is_str_empty() { return str.IsEmpty(); }
  43. // A test with name Setup will be called before each test.
  44. // If it fail, no other tests will be called (not even Cleanup).
  45. TB_TEST(Setup)
  46. {
  47. // Setup
  48. }
  49. // The actual test code. Will be called if Setup passed.
  50. TB_TEST(test_something_1)
  51. {
  52. // Test 1
  53. }
  54. // Another test code. Will be called if Setup passed.
  55. TB_TEST(test_something_2)
  56. {
  57. // Test 2
  58. }
  59. // A test with name Cleanup will be called after each test.
  60. // Will be called even if the test failed.
  61. TB_TEST(Cleanup)
  62. {
  63. // Cleanup
  64. }
  65. }
  66. */
  67. #include "tb_types.h"
  68. #include "tb_linklist.h"
  69. #include "tb_str.h"
  70. #include <math.h>
  71. namespace tb {
  72. /** Setting for TBRunTests to print out more information. */
  73. #define TB_TEST_VERBOSE 1
  74. #ifdef TB_UNIT_TESTING
  75. /** Run the tests. Return the number of fails. */
  76. int TBRunTests(uint32 settings = TB_TEST_VERBOSE);
  77. /** Verify that the expression is true and fail if it isn't. */
  78. #define TB_VERIFY(expr) { fail_line_nr = __LINE__; fail_file = __FILE__; if (!(expr)) { fail_text = (#expr); return; } }
  79. /** Verify that the values are approximately the same. */
  80. #define TB_VERIFY_FLOAT(val, ref_val) { TB_VERIFY(fabs(ref_val - val) < 1.0E-5); }
  81. /** Verify that the strings are equal. */
  82. #define TB_VERIFY_STR(str1, str2) { TB_VERIFY(strcmp(str1, str2) == 0); }
  83. /** End the test with a pass. */
  84. #define TB_PASS() return;
  85. /** End the test with a description why it failed. */
  86. #define TB_FAIL(error) { fail_line_nr = __LINE__; fail_file = __FILE__; fail_text = error; return; }
  87. /** Return a absolute path for the given filename relative to the test source file. */
  88. #define TB_TEST_FILE(filename) tb_get_test_file_name(__FILE__, filename)
  89. /** TBCall is used to execute callbacks for tests in TBTestGroup. */
  90. class TBCall : public TBLinkOf<TBCall>
  91. {
  92. public:
  93. /** return the name of the call */
  94. virtual const char *name() = 0;
  95. /** execute the test code */
  96. virtual void exec() = 0;
  97. };
  98. /** TBTestGroup has a collection of callbacks for tests, and optional Setup and Cleanup calls. */
  99. class TBTestGroup
  100. {
  101. public:
  102. TBTestGroup(const char *name);
  103. bool IsSpecialTest(TBCall *call) const { return !call->linklist; }
  104. public:
  105. const char *name; ///< Test group name.
  106. TBCall *setup; ///< Setup call, or nullptr.
  107. TBCall *cleanup; ///< Cleanup call, or nullptr.
  108. TBCall *init; ///< Init call, or nullptr.
  109. TBCall *shutdown; ///< Shutdown call, or nullptr.
  110. TBLinkListOf<TBCall> calls;///< All test calls to call.
  111. TBTestGroup *next_test_group;
  112. };
  113. /** TBRegisterCall is used for registering calls on TBTestGroup .*/
  114. class TBRegisterCall
  115. {
  116. public:
  117. TBRegisterCall(TBTestGroup *test, TBCall *call);
  118. ~TBRegisterCall();
  119. private:
  120. TBCall *call;
  121. };
  122. #define TB_TEST_GROUP(name) \
  123. namespace testgroup_##name \
  124. { \
  125. class TheGroup : public TBTestGroup \
  126. { \
  127. public: \
  128. TheGroup() : TBTestGroup(#name) {} \
  129. }; \
  130. TheGroup the_group_obj; \
  131. int force_link = 0; \
  132. } \
  133. namespace testgroup_##name \
  134. #define TB_TEST(callname) \
  135. class CallObj##callname : public TBCall \
  136. { \
  137. public: \
  138. virtual const char *name(); \
  139. virtual void exec(); \
  140. }; \
  141. CallObj##callname callname; \
  142. TBRegisterCall callname##reg(&the_group_obj, &callname); \
  143. const char *CallObj##callname::name() { return #callname; } \
  144. void CallObj##callname::exec()
  145. /** Hack to force linking the given test group.
  146. This might be needed for test groups in source files that contain
  147. nothing else that's referenced by the application, and which are
  148. linked in an library. */
  149. #define TB_FORCE_LINK_TEST_GROUP(name) \
  150. namespace testgroup_##name { void force_link_call() { extern int force_link; force_link = 1; }}
  151. TBStr tb_get_test_file_name(const char *testpath, const char *filename);
  152. // Internal globals
  153. extern uint32 test_settings; ///< Settings, as sent to TBRunTests
  154. extern int fail_line_nr; ///< Fail line number
  155. extern const char *fail_file; ///< Fail file name
  156. extern const char *fail_text; ///< Fail text description
  157. #else
  158. inline int TBRunTests(uint32 settings = TB_TEST_VERBOSE) { return 0; }
  159. #endif
  160. }; // namespace tb
  161. #endif // TB_TEST_H