ASPiK SDK
unittests.h
1 // This file is part of VSTGUI. It is subject to the license terms
2 // in the LICENSE file found in the top-level directory of this
3 // distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
4 
5 #ifndef vstgui_unittests_h
6 #define vstgui_unittests_h
7 
8 #if ENABLE_UNIT_TESTS
9 
10 #include "../../lib/vstguifwd.h"
11 #include <string>
12 #include <list>
13 #include <functional>
14 #include <cstdio>
15 #include <cstdlib>
16 
17 /*
18  How-to write tests:
19 
20  1) include this file
21  2) optional: put the test code into namespaces: namespace VSTGUI { namespace UnitTest {
22  3) open testcase : TESTCASE (MySuite,
23  4) optional : declare SETUP and TEARDOWN functions
24  5) declare tests : TEST (MyTest, testing code);
25  6) inside of "testing code" use EXPECT or FAIL macros
26  7) close testcase: );
27  8) optional: close namespaces: }}
28 
29  Complete Example:
30 
31  #include "unittests.h"
32 
33  TESTCASE(Example,
34 
35  int result;
36 
37  SETUP(
38  result = 0;
39  );
40 
41  TEST(OnePlusOneIsTwo,
42  result = 1+1;
43  EXPECT (result == 2)
44  );
45 
46  TEST(ThreeMinusOneIsTwo,
47  result = 3-1;
48  if (result != 2)
49  {
50  FAIL ("result is not two")
51  }
52  );
53  );
54 
55 */
56 
57 namespace VSTGUI {
58 namespace UnitTest {
59 
60 //----------------------------------------------------------------------------------------------------
61 class error : public std::logic_error
62 {
63 public:
64  error (const char* str) : std::logic_error (str) {}
65 };
66 
67 #define VSTGUI_UNITTEST_MAKE_STRING_PRIVATE_DONT_USE(x) # x
68 #define VSTGUI_UNITTEST_MAKE_STRING(x) VSTGUI_UNITTEST_MAKE_STRING_PRIVATE_DONT_USE(x)
69 
70 //----------------------------------------------------------------------------------------------------
71 #define TESTCASE(name,function) static VSTGUI::UnitTest::TestCaseRegistrar name##TestCaseRegistrar (VSTGUI_UNITTEST_MAKE_STRING(name), [](VSTGUI::UnitTest::TestCase* testCase) { function })
72 #define TEST(name,function) testCase->registerTest (VSTGUI_UNITTEST_MAKE_STRING(name), [](VSTGUI::UnitTest::Context* context) { { function } return true; });
73 #define EXPECT(condition) if (!(condition)) { throw VSTGUI::UnitTest::error (__FILE__ ":" VSTGUI_UNITTEST_MAKE_STRING(__LINE__) ": Expected: " VSTGUI_UNITTEST_MAKE_STRING(condition)); }
74 #define FAIL(reason) { context->print (__FILE__ ":" VSTGUI_UNITTEST_MAKE_STRING(__LINE__) ": Failure: " reason); return false; }
75 
76 #define EXPECT_EXCEPTION(call, name) \
77 { \
78  bool b = false; \
79  try { \
80  call; \
81  } catch (const std::exception& error) {\
82  EXPECT(error.what() == std::string(name));\
83  b = true;\
84  } \
85  EXPECT(b);\
86 }
87 
88 #define SETUP(function) testCase->setSetupFunction ([](VSTGUI::UnitTest::Context* context) { function } )
89 #define TEARDOWN(function) testCase->setTeardownFunction ([](VSTGUI::UnitTest::Context* context) { function } )
90 //----------------------------------------------------------------------------------------------------
91 class Context;
92 class TestCase;
93 
94 //----------------------------------------------------------------------------------------------------
95 using TestFunction = std::function<bool(Context*)>;
96 using SetupFunction = std::function<void(Context*)>;
97 using TeardownFunction = std::function<void(Context*)>;
98 using TestCaseFunction = std::function<void(TestCase*)>;
99 
100 //----------------------------------------------------------------------------------------------------
101 class UnitTestRegistry
102 {
103  using TestCases = std::list<TestCase>;
104  using Iterator = TestCases::const_iterator;
105 public:
106  static UnitTestRegistry& instance ();
107 
108  void registerTestCase (TestCase&& testCase);
109 
110  Iterator begin () const { return testCases.begin (); }
111  Iterator end () const { return testCases.end (); }
112 private:
113  TestCases testCases;
114 };
115 
116 //----------------------------------------------------------------------------------------------------
117 class TestCase
118 {
119  using TestPair = std::pair<std::string, TestFunction>;
120  using Tests = std::list<TestPair>;
121  using Iterator = Tests::const_iterator;
122 public:
123  TestCase (std::string&& name, TestCaseFunction&& testCase);
124  TestCase (TestCase&& tc) noexcept;
125 
126  void setSetupFunction (SetupFunction&& setupFunction);
127  void setTeardownFunction (TeardownFunction&& teardownFunction);
128  void registerTest (std::string&& name, TestFunction&& function);
129 
130  const std::string& getName () const { return name; }
131 
132  Iterator begin () const { return tests.begin (); }
133  Iterator end () const { return tests.end (); }
134 
135  const SetupFunction& setup () const { return setupFunction; }
136  const TeardownFunction& teardown () const { return teardownFunction; }
137 
138  TestCase& operator= (TestCase&& tc) noexcept;
139 private:
140  Tests tests;
141  std::string name;
142  TestCaseFunction tcf;
143  SetupFunction setupFunction;
144  TeardownFunction teardownFunction;
145 };
146 
147 //----------------------------------------------------------------------------------------------------
148 class TestCaseRegistrar
149 {
150 public:
151  TestCaseRegistrar (std::string&& name, TestCaseFunction&& testCase)
152  {
153  UnitTestRegistry::instance().registerTestCase (TestCase (std::move (name), std::move (testCase)));
154  }
155 };
156 
157 //----------------------------------------------------------------------------------------------------
158 class Context
159 {
160 public:
161  void print (const char* fmt, ...);
162  virtual void printRaw (const char* str) = 0;
163 };
164 
165 }} // namespaces
166 
167 #else
168 
169 #define TESTCASE(x,y)
170 
171 #endif
172 
173 #endif
Context
Definition: iasync.h:22
Definition: customcontrols.cpp:8