Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
self_test.h
Go to the documentation of this file.
1 /* Copyright (c) 2010 Wildfire Games
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining
4  * a copy of this software and associated documentation files (the
5  * "Software"), to deal in the Software without restriction, including
6  * without limitation the rights to use, copy, modify, merge, publish,
7  * distribute, sublicense, and/or sell copies of the Software, and to
8  * permit persons to whom the Software is furnished to do so, subject to
9  * the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22 
23 /*
24  * helpers for built-in self tests
25  */
26 
27 /*
28 
29 [KEEP IN SYNC WITH WIKI!]
30 
31 Introduction
32 ------------
33 
34 Self-tests as advocated by eXtreme Programming have proven to be useful.
35 By embedding test code into modules, we can be confident that boundary
36 cases are handled correctly and everything still works after edits.
37 We give guidelines for their use and explain several helper mechanisms below.
38 
39 
40 Guidelines
41 ----------
42 
43 What makes a good self-test?
44 - They belong in the module being tested to ensure they are kept in
45  sync with it.
46 - It is easiest to attach them to low-level functions, e.g. ceil_log2,
47  rather than verifying the module's final result (e.g. checking renderer
48  output by comparing pictures).
49 - You should cover all cases: expected failures ("does it fail as expected?"),
50  bad inputs ("does it reject those?"), and successes ("did it have the
51  expected result?").
52 - Tests should be non-intrusive (only bother user if something fails) and
53  very quick. This is because they are executed every program run - which
54  is a good thing because it solves the common problem of forgetting to
55  run them after a change.
56 
57  If the test is unavoidably slow or annoying (example: wdbg_sym's
58  stack trace), then best to disable it by default; see below for how.
59  It can then be enabled manually after changes, and that is better than
60  no test at all.
61 
62 
63 Example Usage
64 -------------
65 
66 The following is a working example of a built-in self test using
67 our facilities. Further notes below are referenced with (1) etc.
68 
69 >>>
70 
71 #if SELF_TEST_ENABLED // (1)
72 namespace test { // (2)
73 
74 static void test_log2()
75 {
76  TEST(ilog2(0) == -1); // (3)
77  // further test cases..
78 }
79 
80 static void self_test()
81 {
82  test_log2();
83  // further test groups..
84 }
85 
86 SELF_TEST_RUN; // (4)
87 
88 } // namespace test
89 #endif // #if SELF_TEST_ENABLED
90 
91 <<<
92 
93 (1) when not enabled, self-tests are completely removed so as
94  not to bloat the executable. for details on how to enable/disable them
95  globally or override in single files, see below.
96 
97 (2) wrapping in a namespace is optional and must be removed for C programs.
98  it avoids possible name collisions with the module being tested.
99 
100 (3) TEST *must* be used instead of ENSURE et al.! this is
101  explained below.
102 
103 (4) automatically calls your self_test function at non-local static object
104  init time (i.e. before main is entered).
105 
106 For further details, see below.
107 
108 */
109 
110 #ifndef INCLUDED_SELF_TEST
111 #define INCLUDED_SELF_TEST
112 
113 /*
114 
115 // a self test is enabled if at the point of its definition
116 // SELF_TEST_ENABLED evaluates to 1 (non-zero).
117 // the value #defined below is the global default. you can override it
118 // in individual files by defining to 0 or 1 before including this header.
119 #ifndef SELF_TEST_ENABLED
120 #define SELF_TEST_ENABLED 1
121 #endif
122 
123 // each test case should use this (instead of assert et al.) to verify
124 // conditions.
125 // rationale: some code checks boundary conditions via assert. these are
126 // often triggered deliberately in self-tests to verify error behavior.
127 // we therefore squelch asserts while tests are active (see mechanism below),
128 // and this is the only error reporter guaranteed to work.
129 //
130 // note: could also stringize condition and display that, but it'd require
131 // macro magic (stringize+prepend L) and we already display file+line.
132 #define TEST(condition) STMT(\
133  if(!(condition))\
134  debug_DisplayError(L"Self-test failed");\
135 )
136 
137 
138 // your source file should contain a function: void self_test() that
139 // performs all tests or calls out to individual test functions.
140 // this macro calls it at static init time and takes care of setting
141 // self_test_active (see above).
142 //
143 // rationale: since compiler optimizations may mess with the dummy variable,
144 // best to put this in a macro so we won't have to change each occurrence.
145 #define SELF_TEST_RUN\
146  static int dummy = self_test_run(self_test)
147 
148 // calling at static init time may not always be desirable - some
149 // self-tests may require initialization beforehand. this mechanism allows
150 // registering self tests automatically, which are then all run when you
151 // call self_test_run_all.
152 #define SELF_TEST_REGISTER\
153  static SelfTestRecord self_test_record = { self_test, 0 };\
154  static int dummy = self_test_register(&self_test_record)
155 
156 struct SelfTestRecord
157 {
158  void(*func)();
159  const SelfTestRecord* next;
160 };
161 
162 // call all self-tests registered thus far. rationale: see above.
163 // also displays a banner+elapsed time via debug_printf.
164 extern void self_test_run_all();
165 
166 
167 //
168 // internal use only:
169 //
170 
171 // trampoline that sets self_test_active and returns a dummy value;
172 // used by SELF_TEST_RUN.
173 extern int self_test_run(void(*func)());
174 
175 extern int self_test_register(SelfTestRecord* r);
176 
177 // checked by debug_OnAssertionFailure; disables asserts if true (see above).
178 // set/cleared by run_self_test.
179 extern bool self_test_active;
180 
181 */
182 
183 
184 // for convenience, to avoid having to include all of these manually
185 #include "lib/status.h"
186 #include "lib/os_path.h"
187 #include "lib/posix/posix.h"
188 
189 #define CXXTEST_HAVE_EH
190 #define CXXTEST_HAVE_STD
191 
192 // If HAVE_STD wasn't defined at the point the ValueTraits header was included
193 // this header won't have been included and the default traits will be used for
194 // all variables... So fix that now ;-)
195 #include <cxxtest/StdValueTraits.h>
196 #include <cxxtest/TestSuite.h>
197 
198 // Perform nice printing of CStr, based on std::string
199 #include "ps/CStr.h"
200 namespace CxxTest
201 {
202  CXXTEST_TEMPLATE_INSTANTIATION
203  class ValueTraits<const CStr8> : public ValueTraits<const CXXTEST_STD(string)>
204  {
205  public:
206  ValueTraits( const CStr8 &s ) : ValueTraits<const CXXTEST_STD(string)>( s.c_str() ) {}
207  };
208 
209  CXXTEST_COPY_CONST_TRAITS( CStr8 );
210 
211  CXXTEST_TEMPLATE_INSTANTIATION
212  class ValueTraits<const CStrW> : public ValueTraits<const CXXTEST_STD(wstring)>
213  {
214  public:
215  ValueTraits( const CStrW &s ) : ValueTraits<const CXXTEST_STD(wstring)>( s.c_str() ) {}
216  };
217 
218  CXXTEST_COPY_CONST_TRAITS( CStrW );
219 }
220 
221 // Perform nice printing of vectors
222 #include "maths/FixedVector3D.h"
223 #include "maths/Vector3D.h"
224 namespace CxxTest
225 {
226  template<>
227  class ValueTraits<CFixedVector3D>
228  {
230  std::string str;
231  public:
232  ValueTraits(const CFixedVector3D& v) : v(v)
233  {
234  std::stringstream s;
235  s << "[" << v.X.ToDouble() << ", " << v.Y.ToDouble() << ", " << v.Z.ToDouble() << "]";
236  str = s.str();
237  }
238  const char* asString() const
239  {
240  return str.c_str();
241  }
242  };
243 
244  template<>
245  class ValueTraits<CVector3D>
246  {
248  std::string str;
249  public:
250  ValueTraits(const CVector3D& v) : v(v)
251  {
252  std::stringstream s;
253  s << "[" << v.X << ", " << v.Y << ", " << v.Z << "]";
254  str = s.str();
255  }
256  const char* asString() const
257  {
258  return str.c_str();
259  }
260  };
261 }
262 
263 #define TS_ASSERT_OK(expr) TS_ASSERT_EQUALS((expr), INFO::OK)
264 #define TSM_ASSERT_OK(m, expr) TSM_ASSERT_EQUALS(m, (expr), INFO::OK)
265 #define TS_ASSERT_STR_EQUALS(str1, str2) TS_ASSERT_EQUALS(std::string(str1), std::string(str2))
266 #define TSM_ASSERT_STR_EQUALS(m, str1, str2) TSM_ASSERT_EQUALS(m, std::string(str1), std::string(str2))
267 #define TS_ASSERT_WSTR_EQUALS(str1, str2) TS_ASSERT_EQUALS(std::wstring(str1), std::wstring(str2))
268 #define TSM_ASSERT_WSTR_EQUALS(m, str1, str2) TSM_ASSERT_EQUALS(m, std::wstring(str1), std::wstring(str2))
269 #define TS_ASSERT_PATH_EQUALS(path1, path2) TS_ASSERT_EQUALS((path1).string(), (path2).string())
270 #define TSM_ASSERT_PATH_EQUALS(m, path1, path2) TSM_ASSERT_EQUALS(m, (path1).string(), (path2).string())
271 
272 bool ts_str_contains(const std::wstring& str1, const std::wstring& str2); // defined in test_setup.cpp
273 #define TS_ASSERT_WSTR_CONTAINS(str1, str2) TSM_ASSERT(str1, ts_str_contains(str1, str2))
274 #define TS_ASSERT_WSTR_NOT_CONTAINS(str1, str2) TSM_ASSERT(str1, !ts_str_contains(str1, str2))
275 
276 template <typename T>
277 std::vector<T> ts_make_vector(T* start, size_t size_bytes)
278 {
279  return std::vector<T>(start, start+(size_bytes/sizeof(T)));
280 }
281 #define TS_ASSERT_VECTOR_EQUALS_ARRAY(vec1, array) TS_ASSERT_EQUALS(vec1, ts_make_vector((array), sizeof(array)))
282 #define TS_ASSERT_VECTOR_CONTAINS(vec1, element) TS_ASSERT(std::find((vec1).begin(), (vec1).end(), element) != (vec1).end());
283 
284 class ScriptInterface;
285 // Script-based testing setup (defined in test_setup.cpp). Defines TS_* functions.
287 
288 // Default game data directory
289 // (TODO: game-specific functions like this probably shouldn't be inside lib/, but it's useful
290 // here since lots of tests use it)
291 OsPath DataDir(); // defined in test_setup.cpp
292 
293 #endif // #ifndef INCLUDED_SELF_TEST
OsPath DataDir()
Definition: test_setup.cpp:110
void ScriptTestSetup(ScriptInterface &)
Definition: test_setup.cpp:125
const char * asString() const
Definition: self_test.h:238
float X
Definition: Vector3D.h:31
CXXTEST_COPY_CONST_TRAITS(CStr8)
Definition: path.h:75
float Y
Definition: Vector3D.h:31
ValueTraits(const CFixedVector3D &v)
Definition: self_test.h:232
#define T(string_literal)
Definition: secure_crt.cpp:70
double ToDouble() const
Convert to double. Won&#39;t be lossy - double can precisely represent all values.
Definition: Fixed.h:167
bool ts_str_contains(const std::wstring &str1, const std::wstring &str2)
Definition: test_setup.cpp:101
std::vector< T > ts_make_vector(T *start, size_t size_bytes)
Definition: self_test.h:277
ValueTraits(const CVector3D &v)
Definition: self_test.h:250
float Z
Definition: Vector3D.h:31
Abstraction around a SpiderMonkey JSContext.
const char * asString() const
Definition: self_test.h:256