]>
Commit | Line | Data |
---|---|---|
f67539c2 TL |
1 | /* |
2 | * Catch v1.9.4 | |
3 | * Generated: 2017-05-16 13:51:55.506519 | |
4 | * ---------------------------------------------------------- | |
5 | * This file has been merged from multiple headers. Please don't edit it directly | |
6 | * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. | |
7 | * | |
8 | * Distributed under the Boost Software License, Version 1.0. (See accompanying | |
9 | * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
10 | */ | |
11 | #ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED | |
12 | #define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED | |
13 | ||
14 | #define TWOBLUECUBES_CATCH_HPP_INCLUDED | |
15 | ||
16 | #ifdef __clang__ | |
17 | # pragma clang system_header | |
18 | #elif defined __GNUC__ | |
19 | # pragma GCC system_header | |
20 | #endif | |
21 | ||
22 | // #included from: internal/catch_suppress_warnings.h | |
23 | ||
24 | #ifdef __clang__ | |
25 | # ifdef __ICC // icpc defines the __clang__ macro | |
26 | # pragma warning(push) | |
27 | # pragma warning(disable: 161 1682) | |
28 | # else // __ICC | |
29 | # pragma clang diagnostic ignored "-Wglobal-constructors" | |
30 | # pragma clang diagnostic ignored "-Wvariadic-macros" | |
31 | # pragma clang diagnostic ignored "-Wc99-extensions" | |
32 | # pragma clang diagnostic ignored "-Wunused-variable" | |
33 | # pragma clang diagnostic push | |
34 | # pragma clang diagnostic ignored "-Wpadded" | |
35 | # pragma clang diagnostic ignored "-Wc++98-compat" | |
36 | # pragma clang diagnostic ignored "-Wc++98-compat-pedantic" | |
37 | # pragma clang diagnostic ignored "-Wswitch-enum" | |
38 | # pragma clang diagnostic ignored "-Wcovered-switch-default" | |
39 | # endif | |
40 | #elif defined __GNUC__ | |
41 | # pragma GCC diagnostic ignored "-Wvariadic-macros" | |
42 | # pragma GCC diagnostic ignored "-Wunused-variable" | |
43 | # pragma GCC diagnostic ignored "-Wparentheses" | |
44 | ||
45 | # pragma GCC diagnostic push | |
46 | # pragma GCC diagnostic ignored "-Wpadded" | |
47 | #endif | |
48 | #if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) | |
49 | # define CATCH_IMPL | |
50 | #endif | |
51 | ||
52 | #ifdef CATCH_IMPL | |
53 | # ifndef CLARA_CONFIG_MAIN | |
54 | # define CLARA_CONFIG_MAIN_NOT_DEFINED | |
55 | # define CLARA_CONFIG_MAIN | |
56 | # endif | |
57 | #endif | |
58 | ||
59 | // #included from: internal/catch_notimplemented_exception.h | |
60 | #define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED | |
61 | ||
62 | // #included from: catch_common.h | |
63 | #define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED | |
64 | ||
65 | // #included from: catch_compiler_capabilities.h | |
66 | #define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED | |
67 | ||
68 | // Detect a number of compiler features - mostly C++11/14 conformance - by compiler | |
69 | // The following features are defined: | |
70 | // | |
71 | // CATCH_CONFIG_CPP11_NULLPTR : is nullptr supported? | |
72 | // CATCH_CONFIG_CPP11_NOEXCEPT : is noexcept supported? | |
73 | // CATCH_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods | |
74 | // CATCH_CONFIG_CPP11_IS_ENUM : std::is_enum is supported? | |
75 | // CATCH_CONFIG_CPP11_TUPLE : std::tuple is supported | |
76 | // CATCH_CONFIG_CPP11_LONG_LONG : is long long supported? | |
77 | // CATCH_CONFIG_CPP11_OVERRIDE : is override supported? | |
78 | // CATCH_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr) | |
79 | // CATCH_CONFIG_CPP11_SHUFFLE : is std::shuffle supported? | |
80 | // CATCH_CONFIG_CPP11_TYPE_TRAITS : are type_traits and enable_if supported? | |
81 | ||
82 | // CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported? | |
83 | ||
84 | // CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported? | |
85 | // CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported? | |
86 | // CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? | |
87 | // CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? | |
88 | // **************** | |
89 | // Note to maintainers: if new toggles are added please document them | |
90 | // in configuration.md, too | |
91 | // **************** | |
92 | ||
93 | // In general each macro has a _NO_<feature name> form | |
94 | // (e.g. CATCH_CONFIG_CPP11_NO_NULLPTR) which disables the feature. | |
95 | // Many features, at point of detection, define an _INTERNAL_ macro, so they | |
96 | // can be combined, en-mass, with the _NO_ forms later. | |
97 | ||
98 | // All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11 | |
99 | ||
100 | #ifdef __cplusplus | |
101 | ||
102 | # if __cplusplus >= 201103L | |
103 | # define CATCH_CPP11_OR_GREATER | |
104 | # endif | |
105 | ||
106 | # if __cplusplus >= 201402L | |
107 | # define CATCH_CPP14_OR_GREATER | |
108 | # endif | |
109 | ||
110 | #endif | |
111 | ||
112 | #ifdef __clang__ | |
113 | ||
114 | # if __has_feature(cxx_nullptr) | |
115 | # define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR | |
116 | # endif | |
117 | ||
118 | # if __has_feature(cxx_noexcept) | |
119 | # define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT | |
120 | # endif | |
121 | ||
122 | # if defined(CATCH_CPP11_OR_GREATER) | |
123 | # define CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ | |
124 | _Pragma( "clang diagnostic push" ) \ | |
125 | _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) | |
126 | # define CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ | |
127 | _Pragma( "clang diagnostic pop" ) | |
128 | ||
129 | # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ | |
130 | _Pragma( "clang diagnostic push" ) \ | |
131 | _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) | |
132 | # define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ | |
133 | _Pragma( "clang diagnostic pop" ) | |
134 | # endif | |
135 | ||
136 | #endif // __clang__ | |
137 | ||
138 | //////////////////////////////////////////////////////////////////////////////// | |
139 | // We know some environments not to support full POSIX signals | |
140 | #if defined(__CYGWIN__) || defined(__QNX__) | |
141 | ||
142 | # if !defined(CATCH_CONFIG_POSIX_SIGNALS) | |
143 | # define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS | |
144 | # endif | |
145 | ||
146 | #endif | |
147 | ||
148 | //////////////////////////////////////////////////////////////////////////////// | |
149 | // Cygwin | |
150 | #ifdef __CYGWIN__ | |
151 | ||
152 | // Required for some versions of Cygwin to declare gettimeofday | |
153 | // see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin | |
154 | # define _BSD_SOURCE | |
155 | ||
156 | #endif // __CYGWIN__ | |
157 | ||
158 | //////////////////////////////////////////////////////////////////////////////// | |
159 | // Borland | |
160 | #ifdef __BORLANDC__ | |
161 | ||
162 | #endif // __BORLANDC__ | |
163 | ||
164 | //////////////////////////////////////////////////////////////////////////////// | |
165 | // EDG | |
166 | #ifdef __EDG_VERSION__ | |
167 | ||
168 | #endif // __EDG_VERSION__ | |
169 | ||
170 | //////////////////////////////////////////////////////////////////////////////// | |
171 | // Digital Mars | |
172 | #ifdef __DMC__ | |
173 | ||
174 | #endif // __DMC__ | |
175 | ||
176 | //////////////////////////////////////////////////////////////////////////////// | |
177 | // GCC | |
178 | #ifdef __GNUC__ | |
179 | ||
180 | # if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) | |
181 | # define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR | |
182 | # endif | |
183 | ||
184 | // - otherwise more recent versions define __cplusplus >= 201103L | |
185 | // and will get picked up below | |
186 | ||
187 | #endif // __GNUC__ | |
188 | ||
189 | //////////////////////////////////////////////////////////////////////////////// | |
190 | // Visual C++ | |
191 | #ifdef _MSC_VER | |
192 | ||
193 | #define CATCH_INTERNAL_CONFIG_WINDOWS_SEH | |
194 | ||
195 | #if (_MSC_VER >= 1600) | |
196 | # define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR | |
197 | # define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR | |
198 | #endif | |
199 | ||
200 | #if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) | |
201 | #define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT | |
202 | #define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS | |
203 | #define CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE | |
204 | #define CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS | |
205 | #endif | |
206 | ||
207 | #endif // _MSC_VER | |
208 | ||
209 | //////////////////////////////////////////////////////////////////////////////// | |
210 | ||
211 | // Use variadic macros if the compiler supports them | |
212 | #if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \ | |
213 | ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \ | |
214 | ( defined __GNUC__ && __GNUC__ >= 3 ) || \ | |
215 | ( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L ) | |
216 | ||
217 | #define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS | |
218 | ||
219 | #endif | |
220 | ||
221 | // Use __COUNTER__ if the compiler supports it | |
222 | #if ( defined _MSC_VER && _MSC_VER >= 1300 ) || \ | |
223 | ( defined __GNUC__ && __GNUC__ >= 4 && __GNUC_MINOR__ >= 3 ) || \ | |
224 | ( defined __clang__ && __clang_major__ >= 3 ) | |
225 | ||
226 | #define CATCH_INTERNAL_CONFIG_COUNTER | |
227 | ||
228 | #endif | |
229 | ||
230 | //////////////////////////////////////////////////////////////////////////////// | |
231 | // C++ language feature support | |
232 | ||
233 | // catch all support for C++11 | |
234 | #if defined(CATCH_CPP11_OR_GREATER) | |
235 | ||
236 | # if !defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) | |
237 | # define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR | |
238 | # endif | |
239 | ||
240 | # ifndef CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT | |
241 | # define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT | |
242 | # endif | |
243 | ||
244 | # ifndef CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS | |
245 | # define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS | |
246 | # endif | |
247 | ||
248 | # ifndef CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM | |
249 | # define CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM | |
250 | # endif | |
251 | ||
252 | # ifndef CATCH_INTERNAL_CONFIG_CPP11_TUPLE | |
253 | # define CATCH_INTERNAL_CONFIG_CPP11_TUPLE | |
254 | # endif | |
255 | ||
256 | # ifndef CATCH_INTERNAL_CONFIG_VARIADIC_MACROS | |
257 | # define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS | |
258 | # endif | |
259 | ||
260 | # if !defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) | |
261 | # define CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG | |
262 | # endif | |
263 | ||
264 | # if !defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) | |
265 | # define CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE | |
266 | # endif | |
267 | # if !defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) | |
268 | # define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR | |
269 | # endif | |
270 | # if !defined(CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE) | |
271 | # define CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE | |
272 | # endif | |
273 | # if !defined(CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS) | |
274 | # define CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS | |
275 | # endif | |
276 | ||
277 | #endif // __cplusplus >= 201103L | |
278 | ||
279 | // Now set the actual defines based on the above + anything the user has configured | |
280 | #if defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NO_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_NO_CPP11) | |
281 | # define CATCH_CONFIG_CPP11_NULLPTR | |
282 | #endif | |
283 | #if defined(CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_NO_CPP11) | |
284 | # define CATCH_CONFIG_CPP11_NOEXCEPT | |
285 | #endif | |
286 | #if defined(CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_NO_CPP11) | |
287 | # define CATCH_CONFIG_CPP11_GENERATED_METHODS | |
288 | #endif | |
289 | #if defined(CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_NO_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_NO_CPP11) | |
290 | # define CATCH_CONFIG_CPP11_IS_ENUM | |
291 | #endif | |
292 | #if defined(CATCH_INTERNAL_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_CPP11_NO_TUPLE) && !defined(CATCH_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_NO_CPP11) | |
293 | # define CATCH_CONFIG_CPP11_TUPLE | |
294 | #endif | |
295 | #if defined(CATCH_INTERNAL_CONFIG_VARIADIC_MACROS) && !defined(CATCH_CONFIG_NO_VARIADIC_MACROS) && !defined(CATCH_CONFIG_VARIADIC_MACROS) | |
296 | # define CATCH_CONFIG_VARIADIC_MACROS | |
297 | #endif | |
298 | #if defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_NO_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_CPP11) | |
299 | # define CATCH_CONFIG_CPP11_LONG_LONG | |
300 | #endif | |
301 | #if defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_NO_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_CPP11) | |
302 | # define CATCH_CONFIG_CPP11_OVERRIDE | |
303 | #endif | |
304 | #if defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_NO_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_CPP11) | |
305 | # define CATCH_CONFIG_CPP11_UNIQUE_PTR | |
306 | #endif | |
307 | // Use of __COUNTER__ is suppressed if __JETBRAINS_IDE__ is #defined (meaning we're being parsed by a JetBrains IDE for | |
308 | // analytics) because, at time of writing, __COUNTER__ is not properly handled by it. | |
309 | // This does not affect compilation | |
310 | #if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) && !defined(__JETBRAINS_IDE__) | |
311 | # define CATCH_CONFIG_COUNTER | |
312 | #endif | |
313 | #if defined(CATCH_INTERNAL_CONFIG_CPP11_SHUFFLE) && !defined(CATCH_CONFIG_CPP11_NO_SHUFFLE) && !defined(CATCH_CONFIG_CPP11_SHUFFLE) && !defined(CATCH_CONFIG_NO_CPP11) | |
314 | # define CATCH_CONFIG_CPP11_SHUFFLE | |
315 | #endif | |
316 | # if defined(CATCH_INTERNAL_CONFIG_CPP11_TYPE_TRAITS) && !defined(CATCH_CONFIG_CPP11_NO_TYPE_TRAITS) && !defined(CATCH_CONFIG_CPP11_TYPE_TRAITS) && !defined(CATCH_CONFIG_NO_CPP11) | |
317 | # define CATCH_CONFIG_CPP11_TYPE_TRAITS | |
318 | # endif | |
319 | #if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) | |
320 | # define CATCH_CONFIG_WINDOWS_SEH | |
321 | #endif | |
322 | // This is set by default, because we assume that unix compilers are posix-signal-compatible by default. | |
323 | #if !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) | |
324 | # define CATCH_CONFIG_POSIX_SIGNALS | |
325 | #endif | |
326 | ||
327 | #if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) | |
328 | # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS | |
329 | # define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS | |
330 | #endif | |
331 | #if !defined(CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS) | |
332 | # define CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS | |
333 | # define CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS | |
334 | #endif | |
335 | ||
336 | // noexcept support: | |
337 | #if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT) | |
338 | # define CATCH_NOEXCEPT noexcept | |
339 | # define CATCH_NOEXCEPT_IS(x) noexcept(x) | |
340 | #else | |
341 | # define CATCH_NOEXCEPT throw() | |
342 | # define CATCH_NOEXCEPT_IS(x) | |
343 | #endif | |
344 | ||
345 | // nullptr support | |
346 | #ifdef CATCH_CONFIG_CPP11_NULLPTR | |
347 | # define CATCH_NULL nullptr | |
348 | #else | |
349 | # define CATCH_NULL NULL | |
350 | #endif | |
351 | ||
352 | // override support | |
353 | #ifdef CATCH_CONFIG_CPP11_OVERRIDE | |
354 | # define CATCH_OVERRIDE override | |
355 | #else | |
356 | # define CATCH_OVERRIDE | |
357 | #endif | |
358 | ||
359 | // unique_ptr support | |
360 | #ifdef CATCH_CONFIG_CPP11_UNIQUE_PTR | |
361 | # define CATCH_AUTO_PTR( T ) std::unique_ptr<T> | |
362 | #else | |
363 | # define CATCH_AUTO_PTR( T ) std::auto_ptr<T> | |
364 | #endif | |
365 | ||
366 | #define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line | |
367 | #define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) | |
368 | #ifdef CATCH_CONFIG_COUNTER | |
369 | # define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) | |
370 | #else | |
371 | # define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) | |
372 | #endif | |
373 | ||
374 | #define INTERNAL_CATCH_STRINGIFY2( expr ) #expr | |
375 | #define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr ) | |
376 | ||
377 | #include <sstream> | |
378 | #include <algorithm> | |
379 | ||
380 | namespace Catch { | |
381 | ||
382 | struct IConfig; | |
383 | ||
384 | struct CaseSensitive { enum Choice { | |
385 | Yes, | |
386 | No | |
387 | }; }; | |
388 | ||
389 | class NonCopyable { | |
390 | #ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS | |
391 | NonCopyable( NonCopyable const& ) = delete; | |
392 | NonCopyable( NonCopyable && ) = delete; | |
393 | NonCopyable& operator = ( NonCopyable const& ) = delete; | |
394 | NonCopyable& operator = ( NonCopyable && ) = delete; | |
395 | #else | |
396 | NonCopyable( NonCopyable const& info ); | |
397 | NonCopyable& operator = ( NonCopyable const& ); | |
398 | #endif | |
399 | ||
400 | protected: | |
401 | NonCopyable() {} | |
402 | virtual ~NonCopyable(); | |
403 | }; | |
404 | ||
405 | class SafeBool { | |
406 | public: | |
407 | typedef void (SafeBool::*type)() const; | |
408 | ||
409 | static type makeSafe( bool value ) { | |
410 | return value ? &SafeBool::trueValue : 0; | |
411 | } | |
412 | private: | |
413 | void trueValue() const {} | |
414 | }; | |
415 | ||
416 | template<typename ContainerT> | |
417 | inline void deleteAll( ContainerT& container ) { | |
418 | typename ContainerT::const_iterator it = container.begin(); | |
419 | typename ContainerT::const_iterator itEnd = container.end(); | |
420 | for(; it != itEnd; ++it ) | |
421 | delete *it; | |
422 | } | |
423 | template<typename AssociativeContainerT> | |
424 | inline void deleteAllValues( AssociativeContainerT& container ) { | |
425 | typename AssociativeContainerT::const_iterator it = container.begin(); | |
426 | typename AssociativeContainerT::const_iterator itEnd = container.end(); | |
427 | for(; it != itEnd; ++it ) | |
428 | delete it->second; | |
429 | } | |
430 | ||
431 | bool startsWith( std::string const& s, std::string const& prefix ); | |
432 | bool startsWith( std::string const& s, char prefix ); | |
433 | bool endsWith( std::string const& s, std::string const& suffix ); | |
434 | bool endsWith( std::string const& s, char suffix ); | |
435 | bool contains( std::string const& s, std::string const& infix ); | |
436 | void toLowerInPlace( std::string& s ); | |
437 | std::string toLower( std::string const& s ); | |
438 | std::string trim( std::string const& str ); | |
439 | bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); | |
440 | ||
441 | struct pluralise { | |
442 | pluralise( std::size_t count, std::string const& label ); | |
443 | ||
444 | friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ); | |
445 | ||
446 | std::size_t m_count; | |
447 | std::string m_label; | |
448 | }; | |
449 | ||
450 | struct SourceLineInfo { | |
451 | ||
452 | SourceLineInfo(); | |
453 | SourceLineInfo( char const* _file, std::size_t _line ); | |
454 | # ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS | |
455 | SourceLineInfo(SourceLineInfo const& other) = default; | |
456 | SourceLineInfo( SourceLineInfo && ) = default; | |
457 | SourceLineInfo& operator = ( SourceLineInfo const& ) = default; | |
458 | SourceLineInfo& operator = ( SourceLineInfo && ) = default; | |
459 | # endif | |
460 | bool empty() const; | |
461 | bool operator == ( SourceLineInfo const& other ) const; | |
462 | bool operator < ( SourceLineInfo const& other ) const; | |
463 | ||
464 | char const* file; | |
465 | std::size_t line; | |
466 | }; | |
467 | ||
468 | std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); | |
469 | ||
470 | // This is just here to avoid compiler warnings with macro constants and boolean literals | |
471 | inline bool isTrue( bool value ){ return value; } | |
472 | inline bool alwaysTrue() { return true; } | |
473 | inline bool alwaysFalse() { return false; } | |
474 | ||
475 | void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ); | |
476 | ||
477 | void seedRng( IConfig const& config ); | |
478 | unsigned int rngSeed(); | |
479 | ||
480 | // Use this in variadic streaming macros to allow | |
481 | // >> +StreamEndStop | |
482 | // as well as | |
483 | // >> stuff +StreamEndStop | |
484 | struct StreamEndStop { | |
485 | std::string operator+() { | |
486 | return std::string(); | |
487 | } | |
488 | }; | |
489 | template<typename T> | |
490 | T const& operator + ( T const& value, StreamEndStop ) { | |
491 | return value; | |
492 | } | |
493 | } | |
494 | ||
495 | #define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast<std::size_t>( __LINE__ ) ) | |
496 | #define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO ); | |
497 | ||
498 | namespace Catch { | |
499 | ||
500 | class NotImplementedException : public std::exception | |
501 | { | |
502 | public: | |
503 | NotImplementedException( SourceLineInfo const& lineInfo ); | |
504 | NotImplementedException( NotImplementedException const& ) {} | |
505 | ||
506 | virtual ~NotImplementedException() CATCH_NOEXCEPT {} | |
507 | ||
508 | virtual const char* what() const CATCH_NOEXCEPT; | |
509 | ||
510 | private: | |
511 | std::string m_what; | |
512 | SourceLineInfo m_lineInfo; | |
513 | }; | |
514 | ||
515 | } // end namespace Catch | |
516 | ||
517 | /////////////////////////////////////////////////////////////////////////////// | |
518 | #define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException( CATCH_INTERNAL_LINEINFO ) | |
519 | ||
520 | // #included from: internal/catch_context.h | |
521 | #define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED | |
522 | ||
523 | // #included from: catch_interfaces_generators.h | |
524 | #define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED | |
525 | ||
526 | #include <string> | |
527 | ||
528 | namespace Catch { | |
529 | ||
530 | struct IGeneratorInfo { | |
531 | virtual ~IGeneratorInfo(); | |
532 | virtual bool moveNext() = 0; | |
533 | virtual std::size_t getCurrentIndex() const = 0; | |
534 | }; | |
535 | ||
536 | struct IGeneratorsForTest { | |
537 | virtual ~IGeneratorsForTest(); | |
538 | ||
539 | virtual IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) = 0; | |
540 | virtual bool moveNext() = 0; | |
541 | }; | |
542 | ||
543 | IGeneratorsForTest* createGeneratorsForTest(); | |
544 | ||
545 | } // end namespace Catch | |
546 | ||
547 | // #included from: catch_ptr.hpp | |
548 | #define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED | |
549 | ||
550 | #ifdef __clang__ | |
551 | #pragma clang diagnostic push | |
552 | #pragma clang diagnostic ignored "-Wpadded" | |
553 | #endif | |
554 | ||
555 | namespace Catch { | |
556 | ||
557 | // An intrusive reference counting smart pointer. | |
558 | // T must implement addRef() and release() methods | |
559 | // typically implementing the IShared interface | |
560 | template<typename T> | |
561 | class Ptr { | |
562 | public: | |
563 | Ptr() : m_p( CATCH_NULL ){} | |
564 | Ptr( T* p ) : m_p( p ){ | |
565 | if( m_p ) | |
566 | m_p->addRef(); | |
567 | } | |
568 | Ptr( Ptr const& other ) : m_p( other.m_p ){ | |
569 | if( m_p ) | |
570 | m_p->addRef(); | |
571 | } | |
572 | ~Ptr(){ | |
573 | if( m_p ) | |
574 | m_p->release(); | |
575 | } | |
576 | void reset() { | |
577 | if( m_p ) | |
578 | m_p->release(); | |
579 | m_p = CATCH_NULL; | |
580 | } | |
581 | Ptr& operator = ( T* p ){ | |
582 | Ptr temp( p ); | |
583 | swap( temp ); | |
584 | return *this; | |
585 | } | |
586 | Ptr& operator = ( Ptr const& other ){ | |
587 | Ptr temp( other ); | |
588 | swap( temp ); | |
589 | return *this; | |
590 | } | |
591 | void swap( Ptr& other ) { std::swap( m_p, other.m_p ); } | |
592 | T* get() const{ return m_p; } | |
593 | T& operator*() const { return *m_p; } | |
594 | T* operator->() const { return m_p; } | |
595 | bool operator !() const { return m_p == CATCH_NULL; } | |
596 | operator SafeBool::type() const { return SafeBool::makeSafe( m_p != CATCH_NULL ); } | |
597 | ||
598 | private: | |
599 | T* m_p; | |
600 | }; | |
601 | ||
602 | struct IShared : NonCopyable { | |
603 | virtual ~IShared(); | |
604 | virtual void addRef() const = 0; | |
605 | virtual void release() const = 0; | |
606 | }; | |
607 | ||
608 | template<typename T = IShared> | |
609 | struct SharedImpl : T { | |
610 | ||
611 | SharedImpl() : m_rc( 0 ){} | |
612 | ||
613 | virtual void addRef() const { | |
614 | ++m_rc; | |
615 | } | |
616 | virtual void release() const { | |
617 | if( --m_rc == 0 ) | |
618 | delete this; | |
619 | } | |
620 | ||
621 | mutable unsigned int m_rc; | |
622 | }; | |
623 | ||
624 | } // end namespace Catch | |
625 | ||
626 | #ifdef __clang__ | |
627 | #pragma clang diagnostic pop | |
628 | #endif | |
629 | ||
630 | namespace Catch { | |
631 | ||
632 | class TestCase; | |
633 | class Stream; | |
634 | struct IResultCapture; | |
635 | struct IRunner; | |
636 | struct IGeneratorsForTest; | |
637 | struct IConfig; | |
638 | ||
639 | struct IContext | |
640 | { | |
641 | virtual ~IContext(); | |
642 | ||
643 | virtual IResultCapture* getResultCapture() = 0; | |
644 | virtual IRunner* getRunner() = 0; | |
645 | virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) = 0; | |
646 | virtual bool advanceGeneratorsForCurrentTest() = 0; | |
647 | virtual Ptr<IConfig const> getConfig() const = 0; | |
648 | }; | |
649 | ||
650 | struct IMutableContext : IContext | |
651 | { | |
652 | virtual ~IMutableContext(); | |
653 | virtual void setResultCapture( IResultCapture* resultCapture ) = 0; | |
654 | virtual void setRunner( IRunner* runner ) = 0; | |
655 | virtual void setConfig( Ptr<IConfig const> const& config ) = 0; | |
656 | }; | |
657 | ||
658 | IContext& getCurrentContext(); | |
659 | IMutableContext& getCurrentMutableContext(); | |
660 | void cleanUpContext(); | |
661 | Stream createStream( std::string const& streamName ); | |
662 | ||
663 | } | |
664 | ||
665 | // #included from: internal/catch_test_registry.hpp | |
666 | #define TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED | |
667 | ||
668 | // #included from: catch_interfaces_testcase.h | |
669 | #define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED | |
670 | ||
671 | #include <vector> | |
672 | ||
673 | namespace Catch { | |
674 | ||
675 | class TestSpec; | |
676 | ||
677 | struct ITestCase : IShared { | |
678 | virtual void invoke () const = 0; | |
679 | protected: | |
680 | virtual ~ITestCase(); | |
681 | }; | |
682 | ||
683 | class TestCase; | |
684 | struct IConfig; | |
685 | ||
686 | struct ITestCaseRegistry { | |
687 | virtual ~ITestCaseRegistry(); | |
688 | virtual std::vector<TestCase> const& getAllTests() const = 0; | |
689 | virtual std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const = 0; | |
690 | }; | |
691 | ||
692 | bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); | |
693 | std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ); | |
694 | std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ); | |
695 | ||
696 | } | |
697 | ||
698 | namespace Catch { | |
699 | ||
700 | template<typename C> | |
701 | class MethodTestCase : public SharedImpl<ITestCase> { | |
702 | ||
703 | public: | |
704 | MethodTestCase( void (C::*method)() ) : m_method( method ) {} | |
705 | ||
706 | virtual void invoke() const { | |
707 | C obj; | |
708 | (obj.*m_method)(); | |
709 | } | |
710 | ||
711 | private: | |
712 | virtual ~MethodTestCase() {} | |
713 | ||
714 | void (C::*m_method)(); | |
715 | }; | |
716 | ||
717 | typedef void(*TestFunction)(); | |
718 | ||
719 | struct NameAndDesc { | |
720 | NameAndDesc( const char* _name = "", const char* _description= "" ) | |
721 | : name( _name ), description( _description ) | |
722 | {} | |
723 | ||
724 | const char* name; | |
725 | const char* description; | |
726 | }; | |
727 | ||
728 | void registerTestCase | |
729 | ( ITestCase* testCase, | |
730 | char const* className, | |
731 | NameAndDesc const& nameAndDesc, | |
732 | SourceLineInfo const& lineInfo ); | |
733 | ||
734 | struct AutoReg { | |
735 | ||
736 | AutoReg | |
737 | ( TestFunction function, | |
738 | SourceLineInfo const& lineInfo, | |
739 | NameAndDesc const& nameAndDesc ); | |
740 | ||
741 | template<typename C> | |
742 | AutoReg | |
743 | ( void (C::*method)(), | |
744 | char const* className, | |
745 | NameAndDesc const& nameAndDesc, | |
746 | SourceLineInfo const& lineInfo ) { | |
747 | ||
748 | registerTestCase | |
749 | ( new MethodTestCase<C>( method ), | |
750 | className, | |
751 | nameAndDesc, | |
752 | lineInfo ); | |
753 | } | |
754 | ||
755 | ~AutoReg(); | |
756 | ||
757 | private: | |
758 | AutoReg( AutoReg const& ); | |
759 | void operator= ( AutoReg const& ); | |
760 | }; | |
761 | ||
762 | void registerTestCaseFunction | |
763 | ( TestFunction function, | |
764 | SourceLineInfo const& lineInfo, | |
765 | NameAndDesc const& nameAndDesc ); | |
766 | ||
767 | } // end namespace Catch | |
768 | ||
769 | #ifdef CATCH_CONFIG_VARIADIC_MACROS | |
770 | /////////////////////////////////////////////////////////////////////////////// | |
771 | #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \ | |
772 | static void TestName(); \ | |
773 | CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ | |
774 | namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); } \ | |
775 | CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ | |
776 | static void TestName() | |
777 | #define INTERNAL_CATCH_TESTCASE( ... ) \ | |
778 | INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ ) | |
779 | ||
780 | /////////////////////////////////////////////////////////////////////////////// | |
781 | #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ | |
782 | CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ | |
783 | namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); } \ | |
784 | CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS | |
785 | ||
786 | /////////////////////////////////////////////////////////////////////////////// | |
787 | #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\ | |
788 | CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ | |
789 | namespace{ \ | |
790 | struct TestName : ClassName{ \ | |
791 | void test(); \ | |
792 | }; \ | |
793 | Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestName::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \ | |
794 | } \ | |
795 | CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ | |
796 | void TestName::test() | |
797 | #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \ | |
798 | INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ ) | |
799 | ||
800 | /////////////////////////////////////////////////////////////////////////////// | |
801 | #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ | |
802 | CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ | |
803 | Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); \ | |
804 | CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS | |
805 | ||
806 | #else | |
807 | /////////////////////////////////////////////////////////////////////////////// | |
808 | #define INTERNAL_CATCH_TESTCASE2( TestName, Name, Desc ) \ | |
809 | static void TestName(); \ | |
810 | CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ | |
811 | namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &TestName, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\ | |
812 | CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ | |
813 | static void TestName() | |
814 | #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \ | |
815 | INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), Name, Desc ) | |
816 | ||
817 | /////////////////////////////////////////////////////////////////////////////// | |
818 | #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \ | |
819 | CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ | |
820 | namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); } \ | |
821 | CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS | |
822 | ||
823 | /////////////////////////////////////////////////////////////////////////////// | |
824 | #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestCaseName, ClassName, TestName, Desc )\ | |
825 | CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ | |
826 | namespace{ \ | |
827 | struct TestCaseName : ClassName{ \ | |
828 | void test(); \ | |
829 | }; \ | |
830 | Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &TestCaseName::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \ | |
831 | } \ | |
832 | CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS \ | |
833 | void TestCaseName::test() | |
834 | #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\ | |
835 | INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, TestName, Desc ) | |
836 | ||
837 | /////////////////////////////////////////////////////////////////////////////// | |
838 | #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, Name, Desc ) \ | |
839 | CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS \ | |
840 | Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); \ | |
841 | CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS | |
842 | ||
843 | #endif | |
844 | ||
845 | // #included from: internal/catch_capture.hpp | |
846 | #define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED | |
847 | ||
848 | // #included from: catch_result_builder.h | |
849 | #define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED | |
850 | ||
851 | // #included from: catch_result_type.h | |
852 | #define TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED | |
853 | ||
854 | namespace Catch { | |
855 | ||
856 | // ResultWas::OfType enum | |
857 | struct ResultWas { enum OfType { | |
858 | Unknown = -1, | |
859 | Ok = 0, | |
860 | Info = 1, | |
861 | Warning = 2, | |
862 | ||
863 | FailureBit = 0x10, | |
864 | ||
865 | ExpressionFailed = FailureBit | 1, | |
866 | ExplicitFailure = FailureBit | 2, | |
867 | ||
868 | Exception = 0x100 | FailureBit, | |
869 | ||
870 | ThrewException = Exception | 1, | |
871 | DidntThrowException = Exception | 2, | |
872 | ||
873 | FatalErrorCondition = 0x200 | FailureBit | |
874 | ||
875 | }; }; | |
876 | ||
877 | inline bool isOk( ResultWas::OfType resultType ) { | |
878 | return ( resultType & ResultWas::FailureBit ) == 0; | |
879 | } | |
880 | inline bool isJustInfo( int flags ) { | |
881 | return flags == ResultWas::Info; | |
882 | } | |
883 | ||
884 | // ResultDisposition::Flags enum | |
885 | struct ResultDisposition { enum Flags { | |
886 | Normal = 0x01, | |
887 | ||
888 | ContinueOnFailure = 0x02, // Failures fail test, but execution continues | |
889 | FalseTest = 0x04, // Prefix expression with ! | |
890 | SuppressFail = 0x08 // Failures are reported but do not fail the test | |
891 | }; }; | |
892 | ||
893 | inline ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { | |
894 | return static_cast<ResultDisposition::Flags>( static_cast<int>( lhs ) | static_cast<int>( rhs ) ); | |
895 | } | |
896 | ||
897 | inline bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } | |
898 | inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } | |
899 | inline bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } | |
900 | ||
901 | } // end namespace Catch | |
902 | ||
903 | // #included from: catch_assertionresult.h | |
904 | #define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED | |
905 | ||
906 | #include <string> | |
907 | ||
908 | namespace Catch { | |
909 | ||
910 | struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison; | |
911 | ||
912 | struct DecomposedExpression | |
913 | { | |
914 | virtual ~DecomposedExpression() {} | |
915 | virtual bool isBinaryExpression() const { | |
916 | return false; | |
917 | } | |
918 | virtual void reconstructExpression( std::string& dest ) const = 0; | |
919 | ||
920 | // Only simple binary comparisons can be decomposed. | |
921 | // If more complex check is required then wrap sub-expressions in parentheses. | |
922 | template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( T const& ); | |
923 | template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( T const& ); | |
924 | template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( T const& ); | |
925 | template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( T const& ); | |
926 | template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator % ( T const& ); | |
927 | template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( T const& ); | |
928 | template<typename T> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( T const& ); | |
929 | ||
930 | private: | |
931 | DecomposedExpression& operator = (DecomposedExpression const&); | |
932 | }; | |
933 | ||
934 | struct AssertionInfo | |
935 | { | |
936 | AssertionInfo() {} | |
937 | AssertionInfo( std::string const& _macroName, | |
938 | SourceLineInfo const& _lineInfo, | |
939 | std::string const& _capturedExpression, | |
940 | ResultDisposition::Flags _resultDisposition ); | |
941 | ||
942 | std::string macroName; | |
943 | SourceLineInfo lineInfo; | |
944 | std::string capturedExpression; | |
945 | ResultDisposition::Flags resultDisposition; | |
946 | }; | |
947 | ||
948 | struct AssertionResultData | |
949 | { | |
950 | AssertionResultData() : decomposedExpression( CATCH_NULL ) | |
951 | , resultType( ResultWas::Unknown ) | |
952 | , negated( false ) | |
953 | , parenthesized( false ) {} | |
954 | ||
955 | void negate( bool parenthesize ) { | |
956 | negated = !negated; | |
957 | parenthesized = parenthesize; | |
958 | if( resultType == ResultWas::Ok ) | |
959 | resultType = ResultWas::ExpressionFailed; | |
960 | else if( resultType == ResultWas::ExpressionFailed ) | |
961 | resultType = ResultWas::Ok; | |
962 | } | |
963 | ||
964 | std::string const& reconstructExpression() const { | |
965 | if( decomposedExpression != CATCH_NULL ) { | |
966 | decomposedExpression->reconstructExpression( reconstructedExpression ); | |
967 | if( parenthesized ) { | |
968 | reconstructedExpression.insert( 0, 1, '(' ); | |
969 | reconstructedExpression.append( 1, ')' ); | |
970 | } | |
971 | if( negated ) { | |
972 | reconstructedExpression.insert( 0, 1, '!' ); | |
973 | } | |
974 | decomposedExpression = CATCH_NULL; | |
975 | } | |
976 | return reconstructedExpression; | |
977 | } | |
978 | ||
979 | mutable DecomposedExpression const* decomposedExpression; | |
980 | mutable std::string reconstructedExpression; | |
981 | std::string message; | |
982 | ResultWas::OfType resultType; | |
983 | bool negated; | |
984 | bool parenthesized; | |
985 | }; | |
986 | ||
987 | class AssertionResult { | |
988 | public: | |
989 | AssertionResult(); | |
990 | AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); | |
991 | ~AssertionResult(); | |
992 | # ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS | |
993 | AssertionResult( AssertionResult const& ) = default; | |
994 | AssertionResult( AssertionResult && ) = default; | |
995 | AssertionResult& operator = ( AssertionResult const& ) = default; | |
996 | AssertionResult& operator = ( AssertionResult && ) = default; | |
997 | # endif | |
998 | ||
999 | bool isOk() const; | |
1000 | bool succeeded() const; | |
1001 | ResultWas::OfType getResultType() const; | |
1002 | bool hasExpression() const; | |
1003 | bool hasMessage() const; | |
1004 | std::string getExpression() const; | |
1005 | std::string getExpressionInMacro() const; | |
1006 | bool hasExpandedExpression() const; | |
1007 | std::string getExpandedExpression() const; | |
1008 | std::string getMessage() const; | |
1009 | SourceLineInfo getSourceInfo() const; | |
1010 | std::string getTestMacroName() const; | |
1011 | void discardDecomposedExpression() const; | |
1012 | void expandDecomposedExpression() const; | |
1013 | ||
1014 | protected: | |
1015 | AssertionInfo m_info; | |
1016 | AssertionResultData m_resultData; | |
1017 | }; | |
1018 | ||
1019 | } // end namespace Catch | |
1020 | ||
1021 | // #included from: catch_matchers.hpp | |
1022 | #define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED | |
1023 | ||
1024 | namespace Catch { | |
1025 | namespace Matchers { | |
1026 | namespace Impl { | |
1027 | ||
1028 | template<typename ArgT> struct MatchAllOf; | |
1029 | template<typename ArgT> struct MatchAnyOf; | |
1030 | template<typename ArgT> struct MatchNotOf; | |
1031 | ||
1032 | class MatcherUntypedBase { | |
1033 | public: | |
1034 | std::string toString() const { | |
1035 | if( m_cachedToString.empty() ) | |
1036 | m_cachedToString = describe(); | |
1037 | return m_cachedToString; | |
1038 | } | |
1039 | ||
1040 | protected: | |
1041 | virtual ~MatcherUntypedBase(); | |
1042 | virtual std::string describe() const = 0; | |
1043 | mutable std::string m_cachedToString; | |
1044 | private: | |
1045 | MatcherUntypedBase& operator = ( MatcherUntypedBase const& ); | |
1046 | }; | |
1047 | ||
1048 | template<typename ObjectT> | |
1049 | struct MatcherMethod { | |
1050 | virtual bool match( ObjectT const& arg ) const = 0; | |
1051 | }; | |
1052 | template<typename PtrT> | |
1053 | struct MatcherMethod<PtrT*> { | |
1054 | virtual bool match( PtrT* arg ) const = 0; | |
1055 | }; | |
1056 | ||
1057 | template<typename ObjectT, typename ComparatorT = ObjectT> | |
1058 | struct MatcherBase : MatcherUntypedBase, MatcherMethod<ObjectT> { | |
1059 | ||
1060 | MatchAllOf<ComparatorT> operator && ( MatcherBase const& other ) const; | |
1061 | MatchAnyOf<ComparatorT> operator || ( MatcherBase const& other ) const; | |
1062 | MatchNotOf<ComparatorT> operator ! () const; | |
1063 | }; | |
1064 | ||
1065 | template<typename ArgT> | |
1066 | struct MatchAllOf : MatcherBase<ArgT> { | |
1067 | virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE { | |
1068 | for( std::size_t i = 0; i < m_matchers.size(); ++i ) { | |
1069 | if (!m_matchers[i]->match(arg)) | |
1070 | return false; | |
1071 | } | |
1072 | return true; | |
1073 | } | |
1074 | virtual std::string describe() const CATCH_OVERRIDE { | |
1075 | std::string description; | |
1076 | description.reserve( 4 + m_matchers.size()*32 ); | |
1077 | description += "( "; | |
1078 | for( std::size_t i = 0; i < m_matchers.size(); ++i ) { | |
1079 | if( i != 0 ) | |
1080 | description += " and "; | |
1081 | description += m_matchers[i]->toString(); | |
1082 | } | |
1083 | description += " )"; | |
1084 | return description; | |
1085 | } | |
1086 | ||
1087 | MatchAllOf<ArgT>& operator && ( MatcherBase<ArgT> const& other ) { | |
1088 | m_matchers.push_back( &other ); | |
1089 | return *this; | |
1090 | } | |
1091 | ||
1092 | std::vector<MatcherBase<ArgT> const*> m_matchers; | |
1093 | }; | |
1094 | template<typename ArgT> | |
1095 | struct MatchAnyOf : MatcherBase<ArgT> { | |
1096 | ||
1097 | virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE { | |
1098 | for( std::size_t i = 0; i < m_matchers.size(); ++i ) { | |
1099 | if (m_matchers[i]->match(arg)) | |
1100 | return true; | |
1101 | } | |
1102 | return false; | |
1103 | } | |
1104 | virtual std::string describe() const CATCH_OVERRIDE { | |
1105 | std::string description; | |
1106 | description.reserve( 4 + m_matchers.size()*32 ); | |
1107 | description += "( "; | |
1108 | for( std::size_t i = 0; i < m_matchers.size(); ++i ) { | |
1109 | if( i != 0 ) | |
1110 | description += " or "; | |
1111 | description += m_matchers[i]->toString(); | |
1112 | } | |
1113 | description += " )"; | |
1114 | return description; | |
1115 | } | |
1116 | ||
1117 | MatchAnyOf<ArgT>& operator || ( MatcherBase<ArgT> const& other ) { | |
1118 | m_matchers.push_back( &other ); | |
1119 | return *this; | |
1120 | } | |
1121 | ||
1122 | std::vector<MatcherBase<ArgT> const*> m_matchers; | |
1123 | }; | |
1124 | ||
1125 | template<typename ArgT> | |
1126 | struct MatchNotOf : MatcherBase<ArgT> { | |
1127 | ||
1128 | MatchNotOf( MatcherBase<ArgT> const& underlyingMatcher ) : m_underlyingMatcher( underlyingMatcher ) {} | |
1129 | ||
1130 | virtual bool match( ArgT const& arg ) const CATCH_OVERRIDE { | |
1131 | return !m_underlyingMatcher.match( arg ); | |
1132 | } | |
1133 | ||
1134 | virtual std::string describe() const CATCH_OVERRIDE { | |
1135 | return "not " + m_underlyingMatcher.toString(); | |
1136 | } | |
1137 | MatcherBase<ArgT> const& m_underlyingMatcher; | |
1138 | }; | |
1139 | ||
1140 | template<typename ObjectT, typename ComparatorT> | |
1141 | MatchAllOf<ComparatorT> MatcherBase<ObjectT, ComparatorT>::operator && ( MatcherBase const& other ) const { | |
1142 | return MatchAllOf<ComparatorT>() && *this && other; | |
1143 | } | |
1144 | template<typename ObjectT, typename ComparatorT> | |
1145 | MatchAnyOf<ComparatorT> MatcherBase<ObjectT, ComparatorT>::operator || ( MatcherBase const& other ) const { | |
1146 | return MatchAnyOf<ComparatorT>() || *this || other; | |
1147 | } | |
1148 | template<typename ObjectT, typename ComparatorT> | |
1149 | MatchNotOf<ComparatorT> MatcherBase<ObjectT, ComparatorT>::operator ! () const { | |
1150 | return MatchNotOf<ComparatorT>( *this ); | |
1151 | } | |
1152 | ||
1153 | } // namespace Impl | |
1154 | ||
1155 | // The following functions create the actual matcher objects. | |
1156 | // This allows the types to be inferred | |
1157 | // - deprecated: prefer ||, && and ! | |
1158 | template<typename T> | |
1159 | inline Impl::MatchNotOf<T> Not( Impl::MatcherBase<T> const& underlyingMatcher ) { | |
1160 | return Impl::MatchNotOf<T>( underlyingMatcher ); | |
1161 | } | |
1162 | template<typename T> | |
1163 | inline Impl::MatchAllOf<T> AllOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2 ) { | |
1164 | return Impl::MatchAllOf<T>() && m1 && m2; | |
1165 | } | |
1166 | template<typename T> | |
1167 | inline Impl::MatchAllOf<T> AllOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2, Impl::MatcherBase<T> const& m3 ) { | |
1168 | return Impl::MatchAllOf<T>() && m1 && m2 && m3; | |
1169 | } | |
1170 | template<typename T> | |
1171 | inline Impl::MatchAnyOf<T> AnyOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2 ) { | |
1172 | return Impl::MatchAnyOf<T>() || m1 || m2; | |
1173 | } | |
1174 | template<typename T> | |
1175 | inline Impl::MatchAnyOf<T> AnyOf( Impl::MatcherBase<T> const& m1, Impl::MatcherBase<T> const& m2, Impl::MatcherBase<T> const& m3 ) { | |
1176 | return Impl::MatchAnyOf<T>() || m1 || m2 || m3; | |
1177 | } | |
1178 | ||
1179 | } // namespace Matchers | |
1180 | ||
1181 | using namespace Matchers; | |
1182 | using Matchers::Impl::MatcherBase; | |
1183 | ||
1184 | } // namespace Catch | |
1185 | ||
1186 | namespace Catch { | |
1187 | ||
1188 | struct TestFailureException{}; | |
1189 | ||
1190 | template<typename T> class ExpressionLhs; | |
1191 | ||
1192 | struct CopyableStream { | |
1193 | CopyableStream() {} | |
1194 | CopyableStream( CopyableStream const& other ) { | |
1195 | oss << other.oss.str(); | |
1196 | } | |
1197 | CopyableStream& operator=( CopyableStream const& other ) { | |
1198 | oss.str(std::string()); | |
1199 | oss << other.oss.str(); | |
1200 | return *this; | |
1201 | } | |
1202 | std::ostringstream oss; | |
1203 | }; | |
1204 | ||
1205 | class ResultBuilder : public DecomposedExpression { | |
1206 | public: | |
1207 | ResultBuilder( char const* macroName, | |
1208 | SourceLineInfo const& lineInfo, | |
1209 | char const* capturedExpression, | |
1210 | ResultDisposition::Flags resultDisposition, | |
1211 | char const* secondArg = "" ); | |
1212 | ~ResultBuilder(); | |
1213 | ||
1214 | template<typename T> | |
1215 | ExpressionLhs<T const&> operator <= ( T const& operand ); | |
1216 | ExpressionLhs<bool> operator <= ( bool value ); | |
1217 | ||
1218 | template<typename T> | |
1219 | ResultBuilder& operator << ( T const& value ) { | |
1220 | m_stream.oss << value; | |
1221 | return *this; | |
1222 | } | |
1223 | ||
1224 | ResultBuilder& setResultType( ResultWas::OfType result ); | |
1225 | ResultBuilder& setResultType( bool result ); | |
1226 | ||
1227 | void endExpression( DecomposedExpression const& expr ); | |
1228 | ||
1229 | virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE; | |
1230 | ||
1231 | AssertionResult build() const; | |
1232 | AssertionResult build( DecomposedExpression const& expr ) const; | |
1233 | ||
1234 | void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal ); | |
1235 | void captureResult( ResultWas::OfType resultType ); | |
1236 | void captureExpression(); | |
1237 | void captureExpectedException( std::string const& expectedMessage ); | |
1238 | void captureExpectedException( Matchers::Impl::MatcherBase<std::string> const& matcher ); | |
1239 | void handleResult( AssertionResult const& result ); | |
1240 | void react(); | |
1241 | bool shouldDebugBreak() const; | |
1242 | bool allowThrows() const; | |
1243 | ||
1244 | template<typename ArgT, typename MatcherT> | |
1245 | void captureMatch( ArgT const& arg, MatcherT const& matcher, char const* matcherString ); | |
1246 | ||
1247 | void setExceptionGuard(); | |
1248 | void unsetExceptionGuard(); | |
1249 | ||
1250 | private: | |
1251 | AssertionInfo m_assertionInfo; | |
1252 | AssertionResultData m_data; | |
1253 | CopyableStream m_stream; | |
1254 | ||
1255 | bool m_shouldDebugBreak; | |
1256 | bool m_shouldThrow; | |
1257 | bool m_guardException; | |
1258 | }; | |
1259 | ||
1260 | } // namespace Catch | |
1261 | ||
1262 | // Include after due to circular dependency: | |
1263 | // #included from: catch_expression_lhs.hpp | |
1264 | #define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED | |
1265 | ||
1266 | // #included from: catch_evaluate.hpp | |
1267 | #define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED | |
1268 | ||
1269 | #ifdef _MSC_VER | |
1270 | #pragma warning(push) | |
1271 | #pragma warning(disable:4389) // '==' : signed/unsigned mismatch | |
1272 | #pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform) | |
1273 | #endif | |
1274 | ||
1275 | #include <cstddef> | |
1276 | ||
1277 | namespace Catch { | |
1278 | namespace Internal { | |
1279 | ||
1280 | enum Operator { | |
1281 | IsEqualTo, | |
1282 | IsNotEqualTo, | |
1283 | IsLessThan, | |
1284 | IsGreaterThan, | |
1285 | IsLessThanOrEqualTo, | |
1286 | IsGreaterThanOrEqualTo | |
1287 | }; | |
1288 | ||
1289 | template<Operator Op> struct OperatorTraits { static const char* getName(){ return "*error*"; } }; | |
1290 | template<> struct OperatorTraits<IsEqualTo> { static const char* getName(){ return "=="; } }; | |
1291 | template<> struct OperatorTraits<IsNotEqualTo> { static const char* getName(){ return "!="; } }; | |
1292 | template<> struct OperatorTraits<IsLessThan> { static const char* getName(){ return "<"; } }; | |
1293 | template<> struct OperatorTraits<IsGreaterThan> { static const char* getName(){ return ">"; } }; | |
1294 | template<> struct OperatorTraits<IsLessThanOrEqualTo> { static const char* getName(){ return "<="; } }; | |
1295 | template<> struct OperatorTraits<IsGreaterThanOrEqualTo>{ static const char* getName(){ return ">="; } }; | |
1296 | ||
1297 | template<typename T> | |
1298 | inline T& opCast(T const& t) { return const_cast<T&>(t); } | |
1299 | ||
1300 | // nullptr_t support based on pull request #154 from Konstantin Baumann | |
1301 | #ifdef CATCH_CONFIG_CPP11_NULLPTR | |
1302 | inline std::nullptr_t opCast(std::nullptr_t) { return nullptr; } | |
1303 | #endif // CATCH_CONFIG_CPP11_NULLPTR | |
1304 | ||
1305 | // So the compare overloads can be operator agnostic we convey the operator as a template | |
1306 | // enum, which is used to specialise an Evaluator for doing the comparison. | |
1307 | template<typename T1, typename T2, Operator Op> | |
1308 | class Evaluator{}; | |
1309 | ||
1310 | template<typename T1, typename T2> | |
1311 | struct Evaluator<T1, T2, IsEqualTo> { | |
1312 | static bool evaluate( T1 const& lhs, T2 const& rhs) { | |
1313 | return bool( opCast( lhs ) == opCast( rhs ) ); | |
1314 | } | |
1315 | }; | |
1316 | template<typename T1, typename T2> | |
1317 | struct Evaluator<T1, T2, IsNotEqualTo> { | |
1318 | static bool evaluate( T1 const& lhs, T2 const& rhs ) { | |
1319 | return bool( opCast( lhs ) != opCast( rhs ) ); | |
1320 | } | |
1321 | }; | |
1322 | template<typename T1, typename T2> | |
1323 | struct Evaluator<T1, T2, IsLessThan> { | |
1324 | static bool evaluate( T1 const& lhs, T2 const& rhs ) { | |
1325 | return bool( opCast( lhs ) < opCast( rhs ) ); | |
1326 | } | |
1327 | }; | |
1328 | template<typename T1, typename T2> | |
1329 | struct Evaluator<T1, T2, IsGreaterThan> { | |
1330 | static bool evaluate( T1 const& lhs, T2 const& rhs ) { | |
1331 | return bool( opCast( lhs ) > opCast( rhs ) ); | |
1332 | } | |
1333 | }; | |
1334 | template<typename T1, typename T2> | |
1335 | struct Evaluator<T1, T2, IsGreaterThanOrEqualTo> { | |
1336 | static bool evaluate( T1 const& lhs, T2 const& rhs ) { | |
1337 | return bool( opCast( lhs ) >= opCast( rhs ) ); | |
1338 | } | |
1339 | }; | |
1340 | template<typename T1, typename T2> | |
1341 | struct Evaluator<T1, T2, IsLessThanOrEqualTo> { | |
1342 | static bool evaluate( T1 const& lhs, T2 const& rhs ) { | |
1343 | return bool( opCast( lhs ) <= opCast( rhs ) ); | |
1344 | } | |
1345 | }; | |
1346 | ||
1347 | template<Operator Op, typename T1, typename T2> | |
1348 | bool applyEvaluator( T1 const& lhs, T2 const& rhs ) { | |
1349 | return Evaluator<T1, T2, Op>::evaluate( lhs, rhs ); | |
1350 | } | |
1351 | ||
1352 | // This level of indirection allows us to specialise for integer types | |
1353 | // to avoid signed/ unsigned warnings | |
1354 | ||
1355 | // "base" overload | |
1356 | template<Operator Op, typename T1, typename T2> | |
1357 | bool compare( T1 const& lhs, T2 const& rhs ) { | |
1358 | return Evaluator<T1, T2, Op>::evaluate( lhs, rhs ); | |
1359 | } | |
1360 | ||
1361 | // unsigned X to int | |
1362 | template<Operator Op> bool compare( unsigned int lhs, int rhs ) { | |
1363 | return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) ); | |
1364 | } | |
1365 | template<Operator Op> bool compare( unsigned long lhs, int rhs ) { | |
1366 | return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) ); | |
1367 | } | |
1368 | template<Operator Op> bool compare( unsigned char lhs, int rhs ) { | |
1369 | return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) ); | |
1370 | } | |
1371 | ||
1372 | // unsigned X to long | |
1373 | template<Operator Op> bool compare( unsigned int lhs, long rhs ) { | |
1374 | return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) ); | |
1375 | } | |
1376 | template<Operator Op> bool compare( unsigned long lhs, long rhs ) { | |
1377 | return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) ); | |
1378 | } | |
1379 | template<Operator Op> bool compare( unsigned char lhs, long rhs ) { | |
1380 | return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) ); | |
1381 | } | |
1382 | ||
1383 | // int to unsigned X | |
1384 | template<Operator Op> bool compare( int lhs, unsigned int rhs ) { | |
1385 | return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs ); | |
1386 | } | |
1387 | template<Operator Op> bool compare( int lhs, unsigned long rhs ) { | |
1388 | return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs ); | |
1389 | } | |
1390 | template<Operator Op> bool compare( int lhs, unsigned char rhs ) { | |
1391 | return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs ); | |
1392 | } | |
1393 | ||
1394 | // long to unsigned X | |
1395 | template<Operator Op> bool compare( long lhs, unsigned int rhs ) { | |
1396 | return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs ); | |
1397 | } | |
1398 | template<Operator Op> bool compare( long lhs, unsigned long rhs ) { | |
1399 | return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs ); | |
1400 | } | |
1401 | template<Operator Op> bool compare( long lhs, unsigned char rhs ) { | |
1402 | return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs ); | |
1403 | } | |
1404 | ||
1405 | // pointer to long (when comparing against NULL) | |
1406 | template<Operator Op, typename T> bool compare( long lhs, T* rhs ) { | |
1407 | return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs ); | |
1408 | } | |
1409 | template<Operator Op, typename T> bool compare( T* lhs, long rhs ) { | |
1410 | return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) ); | |
1411 | } | |
1412 | ||
1413 | // pointer to int (when comparing against NULL) | |
1414 | template<Operator Op, typename T> bool compare( int lhs, T* rhs ) { | |
1415 | return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs ); | |
1416 | } | |
1417 | template<Operator Op, typename T> bool compare( T* lhs, int rhs ) { | |
1418 | return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) ); | |
1419 | } | |
1420 | ||
1421 | #ifdef CATCH_CONFIG_CPP11_LONG_LONG | |
1422 | // long long to unsigned X | |
1423 | template<Operator Op> bool compare( long long lhs, unsigned int rhs ) { | |
1424 | return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs ); | |
1425 | } | |
1426 | template<Operator Op> bool compare( long long lhs, unsigned long rhs ) { | |
1427 | return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs ); | |
1428 | } | |
1429 | template<Operator Op> bool compare( long long lhs, unsigned long long rhs ) { | |
1430 | return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs ); | |
1431 | } | |
1432 | template<Operator Op> bool compare( long long lhs, unsigned char rhs ) { | |
1433 | return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs ); | |
1434 | } | |
1435 | ||
1436 | // unsigned long long to X | |
1437 | template<Operator Op> bool compare( unsigned long long lhs, int rhs ) { | |
1438 | return applyEvaluator<Op>( static_cast<long>( lhs ), rhs ); | |
1439 | } | |
1440 | template<Operator Op> bool compare( unsigned long long lhs, long rhs ) { | |
1441 | return applyEvaluator<Op>( static_cast<long>( lhs ), rhs ); | |
1442 | } | |
1443 | template<Operator Op> bool compare( unsigned long long lhs, long long rhs ) { | |
1444 | return applyEvaluator<Op>( static_cast<long>( lhs ), rhs ); | |
1445 | } | |
1446 | template<Operator Op> bool compare( unsigned long long lhs, char rhs ) { | |
1447 | return applyEvaluator<Op>( static_cast<long>( lhs ), rhs ); | |
1448 | } | |
1449 | ||
1450 | // pointer to long long (when comparing against NULL) | |
1451 | template<Operator Op, typename T> bool compare( long long lhs, T* rhs ) { | |
1452 | return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs ); | |
1453 | } | |
1454 | template<Operator Op, typename T> bool compare( T* lhs, long long rhs ) { | |
1455 | return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) ); | |
1456 | } | |
1457 | #endif // CATCH_CONFIG_CPP11_LONG_LONG | |
1458 | ||
1459 | #ifdef CATCH_CONFIG_CPP11_NULLPTR | |
1460 | // pointer to nullptr_t (when comparing against nullptr) | |
1461 | template<Operator Op, typename T> bool compare( std::nullptr_t, T* rhs ) { | |
1462 | return Evaluator<T*, T*, Op>::evaluate( nullptr, rhs ); | |
1463 | } | |
1464 | template<Operator Op, typename T> bool compare( T* lhs, std::nullptr_t ) { | |
1465 | return Evaluator<T*, T*, Op>::evaluate( lhs, nullptr ); | |
1466 | } | |
1467 | #endif // CATCH_CONFIG_CPP11_NULLPTR | |
1468 | ||
1469 | } // end of namespace Internal | |
1470 | } // end of namespace Catch | |
1471 | ||
1472 | #ifdef _MSC_VER | |
1473 | #pragma warning(pop) | |
1474 | #endif | |
1475 | ||
1476 | // #included from: catch_tostring.h | |
1477 | #define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED | |
1478 | ||
1479 | #include <sstream> | |
1480 | #include <iomanip> | |
1481 | #include <limits> | |
1482 | #include <vector> | |
1483 | #include <cstddef> | |
1484 | ||
1485 | #ifdef __OBJC__ | |
1486 | // #included from: catch_objc_arc.hpp | |
1487 | #define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED | |
1488 | ||
1489 | #import <Foundation/Foundation.h> | |
1490 | ||
1491 | #ifdef __has_feature | |
1492 | #define CATCH_ARC_ENABLED __has_feature(objc_arc) | |
1493 | #else | |
1494 | #define CATCH_ARC_ENABLED 0 | |
1495 | #endif | |
1496 | ||
1497 | void arcSafeRelease( NSObject* obj ); | |
1498 | id performOptionalSelector( id obj, SEL sel ); | |
1499 | ||
1500 | #if !CATCH_ARC_ENABLED | |
1501 | inline void arcSafeRelease( NSObject* obj ) { | |
1502 | [obj release]; | |
1503 | } | |
1504 | inline id performOptionalSelector( id obj, SEL sel ) { | |
1505 | if( [obj respondsToSelector: sel] ) | |
1506 | return [obj performSelector: sel]; | |
1507 | return nil; | |
1508 | } | |
1509 | #define CATCH_UNSAFE_UNRETAINED | |
1510 | #define CATCH_ARC_STRONG | |
1511 | #else | |
1512 | inline void arcSafeRelease( NSObject* ){} | |
1513 | inline id performOptionalSelector( id obj, SEL sel ) { | |
1514 | #ifdef __clang__ | |
1515 | #pragma clang diagnostic push | |
1516 | #pragma clang diagnostic ignored "-Warc-performSelector-leaks" | |
1517 | #endif | |
1518 | if( [obj respondsToSelector: sel] ) | |
1519 | return [obj performSelector: sel]; | |
1520 | #ifdef __clang__ | |
1521 | #pragma clang diagnostic pop | |
1522 | #endif | |
1523 | return nil; | |
1524 | } | |
1525 | #define CATCH_UNSAFE_UNRETAINED __unsafe_unretained | |
1526 | #define CATCH_ARC_STRONG __strong | |
1527 | #endif | |
1528 | ||
1529 | #endif | |
1530 | ||
1531 | #ifdef CATCH_CONFIG_CPP11_TUPLE | |
1532 | #include <tuple> | |
1533 | #endif | |
1534 | ||
1535 | #ifdef CATCH_CONFIG_CPP11_IS_ENUM | |
1536 | #include <type_traits> | |
1537 | #endif | |
1538 | ||
1539 | namespace Catch { | |
1540 | ||
1541 | // Why we're here. | |
1542 | template<typename T> | |
1543 | std::string toString( T const& value ); | |
1544 | ||
1545 | // Built in overloads | |
1546 | ||
1547 | std::string toString( std::string const& value ); | |
1548 | std::string toString( std::wstring const& value ); | |
1549 | std::string toString( const char* const value ); | |
1550 | std::string toString( char* const value ); | |
1551 | std::string toString( const wchar_t* const value ); | |
1552 | std::string toString( wchar_t* const value ); | |
1553 | std::string toString( int value ); | |
1554 | std::string toString( unsigned long value ); | |
1555 | std::string toString( unsigned int value ); | |
1556 | std::string toString( const double value ); | |
1557 | std::string toString( const float value ); | |
1558 | std::string toString( bool value ); | |
1559 | std::string toString( char value ); | |
1560 | std::string toString( signed char value ); | |
1561 | std::string toString( unsigned char value ); | |
1562 | ||
1563 | #ifdef CATCH_CONFIG_CPP11_LONG_LONG | |
1564 | std::string toString( long long value ); | |
1565 | std::string toString( unsigned long long value ); | |
1566 | #endif | |
1567 | ||
1568 | #ifdef CATCH_CONFIG_CPP11_NULLPTR | |
1569 | std::string toString( std::nullptr_t ); | |
1570 | #endif | |
1571 | ||
1572 | #ifdef __OBJC__ | |
1573 | std::string toString( NSString const * const& nsstring ); | |
1574 | std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ); | |
1575 | std::string toString( NSObject* const& nsObject ); | |
1576 | #endif | |
1577 | ||
1578 | namespace Detail { | |
1579 | ||
1580 | extern const std::string unprintableString; | |
1581 | ||
1582 | #if !defined(CATCH_CONFIG_CPP11_STREAM_INSERTABLE_CHECK) | |
1583 | struct BorgType { | |
1584 | template<typename T> BorgType( T const& ); | |
1585 | }; | |
1586 | ||
1587 | struct TrueType { char sizer[1]; }; | |
1588 | struct FalseType { char sizer[2]; }; | |
1589 | ||
1590 | TrueType& testStreamable( std::ostream& ); | |
1591 | FalseType testStreamable( FalseType ); | |
1592 | ||
1593 | FalseType operator<<( std::ostream const&, BorgType const& ); | |
1594 | ||
1595 | template<typename T> | |
1596 | struct IsStreamInsertable { | |
1597 | static std::ostream &s; | |
1598 | static T const&t; | |
1599 | enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) }; | |
1600 | }; | |
1601 | #else | |
1602 | template<typename T> | |
1603 | class IsStreamInsertable { | |
1604 | template<typename SS, typename TT> | |
1605 | static auto test(int) | |
1606 | -> decltype( std::declval<SS&>() << std::declval<TT>(), std::true_type() ); | |
1607 | ||
1608 | template<typename, typename> | |
1609 | static auto test(...) -> std::false_type; | |
1610 | ||
1611 | public: | |
1612 | static const bool value = decltype(test<std::ostream,const T&>(0))::value; | |
1613 | }; | |
1614 | #endif | |
1615 | ||
1616 | #if defined(CATCH_CONFIG_CPP11_IS_ENUM) | |
1617 | template<typename T, | |
1618 | bool IsEnum = std::is_enum<T>::value | |
1619 | > | |
1620 | struct EnumStringMaker | |
1621 | { | |
1622 | static std::string convert( T const& ) { return unprintableString; } | |
1623 | }; | |
1624 | ||
1625 | template<typename T> | |
1626 | struct EnumStringMaker<T,true> | |
1627 | { | |
1628 | static std::string convert( T const& v ) | |
1629 | { | |
1630 | return ::Catch::toString( | |
1631 | static_cast<typename std::underlying_type<T>::type>(v) | |
1632 | ); | |
1633 | } | |
1634 | }; | |
1635 | #endif | |
1636 | template<bool C> | |
1637 | struct StringMakerBase { | |
1638 | #if defined(CATCH_CONFIG_CPP11_IS_ENUM) | |
1639 | template<typename T> | |
1640 | static std::string convert( T const& v ) | |
1641 | { | |
1642 | return EnumStringMaker<T>::convert( v ); | |
1643 | } | |
1644 | #else | |
1645 | template<typename T> | |
1646 | static std::string convert( T const& ) { return unprintableString; } | |
1647 | #endif | |
1648 | }; | |
1649 | ||
1650 | template<> | |
1651 | struct StringMakerBase<true> { | |
1652 | template<typename T> | |
1653 | static std::string convert( T const& _value ) { | |
1654 | std::ostringstream oss; | |
1655 | oss << _value; | |
1656 | return oss.str(); | |
1657 | } | |
1658 | }; | |
1659 | ||
1660 | std::string rawMemoryToString( const void *object, std::size_t size ); | |
1661 | ||
1662 | template<typename T> | |
1663 | inline std::string rawMemoryToString( const T& object ) { | |
1664 | return rawMemoryToString( &object, sizeof(object) ); | |
1665 | } | |
1666 | ||
1667 | } // end namespace Detail | |
1668 | ||
1669 | template<typename T> | |
1670 | struct StringMaker : | |
1671 | Detail::StringMakerBase<Detail::IsStreamInsertable<T>::value> {}; | |
1672 | ||
1673 | template<typename T> | |
1674 | struct StringMaker<T*> { | |
1675 | template<typename U> | |
1676 | static std::string convert( U* p ) { | |
1677 | if( !p ) | |
1678 | return "NULL"; | |
1679 | else | |
1680 | return Detail::rawMemoryToString( p ); | |
1681 | } | |
1682 | }; | |
1683 | ||
1684 | template<typename R, typename C> | |
1685 | struct StringMaker<R C::*> { | |
1686 | static std::string convert( R C::* p ) { | |
1687 | if( !p ) | |
1688 | return "NULL"; | |
1689 | else | |
1690 | return Detail::rawMemoryToString( p ); | |
1691 | } | |
1692 | }; | |
1693 | ||
1694 | namespace Detail { | |
1695 | template<typename InputIterator> | |
1696 | std::string rangeToString( InputIterator first, InputIterator last ); | |
1697 | } | |
1698 | ||
1699 | //template<typename T, typename Allocator> | |
1700 | //struct StringMaker<std::vector<T, Allocator> > { | |
1701 | // static std::string convert( std::vector<T,Allocator> const& v ) { | |
1702 | // return Detail::rangeToString( v.begin(), v.end() ); | |
1703 | // } | |
1704 | //}; | |
1705 | ||
1706 | template<typename T, typename Allocator> | |
1707 | std::string toString( std::vector<T,Allocator> const& v ) { | |
1708 | return Detail::rangeToString( v.begin(), v.end() ); | |
1709 | } | |
1710 | ||
1711 | #ifdef CATCH_CONFIG_CPP11_TUPLE | |
1712 | ||
1713 | // toString for tuples | |
1714 | namespace TupleDetail { | |
1715 | template< | |
1716 | typename Tuple, | |
1717 | std::size_t N = 0, | |
1718 | bool = (N < std::tuple_size<Tuple>::value) | |
1719 | > | |
1720 | struct ElementPrinter { | |
1721 | static void print( const Tuple& tuple, std::ostream& os ) | |
1722 | { | |
1723 | os << ( N ? ", " : " " ) | |
1724 | << Catch::toString(std::get<N>(tuple)); | |
1725 | ElementPrinter<Tuple,N+1>::print(tuple,os); | |
1726 | } | |
1727 | }; | |
1728 | ||
1729 | template< | |
1730 | typename Tuple, | |
1731 | std::size_t N | |
1732 | > | |
1733 | struct ElementPrinter<Tuple,N,false> { | |
1734 | static void print( const Tuple&, std::ostream& ) {} | |
1735 | }; | |
1736 | ||
1737 | } | |
1738 | ||
1739 | template<typename ...Types> | |
1740 | struct StringMaker<std::tuple<Types...>> { | |
1741 | ||
1742 | static std::string convert( const std::tuple<Types...>& tuple ) | |
1743 | { | |
1744 | std::ostringstream os; | |
1745 | os << '{'; | |
1746 | TupleDetail::ElementPrinter<std::tuple<Types...>>::print( tuple, os ); | |
1747 | os << " }"; | |
1748 | return os.str(); | |
1749 | } | |
1750 | }; | |
1751 | #endif // CATCH_CONFIG_CPP11_TUPLE | |
1752 | ||
1753 | namespace Detail { | |
1754 | template<typename T> | |
1755 | std::string makeString( T const& value ) { | |
1756 | return StringMaker<T>::convert( value ); | |
1757 | } | |
1758 | } // end namespace Detail | |
1759 | ||
1760 | /// \brief converts any type to a string | |
1761 | /// | |
1762 | /// The default template forwards on to ostringstream - except when an | |
1763 | /// ostringstream overload does not exist - in which case it attempts to detect | |
1764 | /// that and writes {?}. | |
1765 | /// Overload (not specialise) this template for custom typs that you don't want | |
1766 | /// to provide an ostream overload for. | |
1767 | template<typename T> | |
1768 | std::string toString( T const& value ) { | |
1769 | return StringMaker<T>::convert( value ); | |
1770 | } | |
1771 | ||
1772 | namespace Detail { | |
1773 | template<typename InputIterator> | |
1774 | std::string rangeToString( InputIterator first, InputIterator last ) { | |
1775 | std::ostringstream oss; | |
1776 | oss << "{ "; | |
1777 | if( first != last ) { | |
1778 | oss << Catch::toString( *first ); | |
1779 | for( ++first ; first != last ; ++first ) | |
1780 | oss << ", " << Catch::toString( *first ); | |
1781 | } | |
1782 | oss << " }"; | |
1783 | return oss.str(); | |
1784 | } | |
1785 | } | |
1786 | ||
1787 | } // end namespace Catch | |
1788 | ||
1789 | namespace Catch { | |
1790 | ||
1791 | template<typename LhsT, Internal::Operator Op, typename RhsT> | |
1792 | class BinaryExpression; | |
1793 | ||
1794 | template<typename ArgT, typename MatcherT> | |
1795 | class MatchExpression; | |
1796 | ||
1797 | // Wraps the LHS of an expression and overloads comparison operators | |
1798 | // for also capturing those and RHS (if any) | |
1799 | template<typename T> | |
1800 | class ExpressionLhs : public DecomposedExpression { | |
1801 | public: | |
1802 | ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ), m_truthy(false) {} | |
1803 | ||
1804 | ExpressionLhs& operator = ( const ExpressionLhs& ); | |
1805 | ||
1806 | template<typename RhsT> | |
1807 | BinaryExpression<T, Internal::IsEqualTo, RhsT const&> | |
1808 | operator == ( RhsT const& rhs ) { | |
1809 | return captureExpression<Internal::IsEqualTo>( rhs ); | |
1810 | } | |
1811 | ||
1812 | template<typename RhsT> | |
1813 | BinaryExpression<T, Internal::IsNotEqualTo, RhsT const&> | |
1814 | operator != ( RhsT const& rhs ) { | |
1815 | return captureExpression<Internal::IsNotEqualTo>( rhs ); | |
1816 | } | |
1817 | ||
1818 | template<typename RhsT> | |
1819 | BinaryExpression<T, Internal::IsLessThan, RhsT const&> | |
1820 | operator < ( RhsT const& rhs ) { | |
1821 | return captureExpression<Internal::IsLessThan>( rhs ); | |
1822 | } | |
1823 | ||
1824 | template<typename RhsT> | |
1825 | BinaryExpression<T, Internal::IsGreaterThan, RhsT const&> | |
1826 | operator > ( RhsT const& rhs ) { | |
1827 | return captureExpression<Internal::IsGreaterThan>( rhs ); | |
1828 | } | |
1829 | ||
1830 | template<typename RhsT> | |
1831 | BinaryExpression<T, Internal::IsLessThanOrEqualTo, RhsT const&> | |
1832 | operator <= ( RhsT const& rhs ) { | |
1833 | return captureExpression<Internal::IsLessThanOrEqualTo>( rhs ); | |
1834 | } | |
1835 | ||
1836 | template<typename RhsT> | |
1837 | BinaryExpression<T, Internal::IsGreaterThanOrEqualTo, RhsT const&> | |
1838 | operator >= ( RhsT const& rhs ) { | |
1839 | return captureExpression<Internal::IsGreaterThanOrEqualTo>( rhs ); | |
1840 | } | |
1841 | ||
1842 | BinaryExpression<T, Internal::IsEqualTo, bool> operator == ( bool rhs ) { | |
1843 | return captureExpression<Internal::IsEqualTo>( rhs ); | |
1844 | } | |
1845 | ||
1846 | BinaryExpression<T, Internal::IsNotEqualTo, bool> operator != ( bool rhs ) { | |
1847 | return captureExpression<Internal::IsNotEqualTo>( rhs ); | |
1848 | } | |
1849 | ||
1850 | void endExpression() { | |
1851 | m_truthy = m_lhs ? true : false; | |
1852 | m_rb | |
1853 | .setResultType( m_truthy ) | |
1854 | .endExpression( *this ); | |
1855 | } | |
1856 | ||
1857 | virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE { | |
1858 | dest = Catch::toString( m_truthy ); | |
1859 | } | |
1860 | ||
1861 | private: | |
1862 | template<Internal::Operator Op, typename RhsT> | |
1863 | BinaryExpression<T, Op, RhsT&> captureExpression( RhsT& rhs ) const { | |
1864 | return BinaryExpression<T, Op, RhsT&>( m_rb, m_lhs, rhs ); | |
1865 | } | |
1866 | ||
1867 | template<Internal::Operator Op> | |
1868 | BinaryExpression<T, Op, bool> captureExpression( bool rhs ) const { | |
1869 | return BinaryExpression<T, Op, bool>( m_rb, m_lhs, rhs ); | |
1870 | } | |
1871 | ||
1872 | private: | |
1873 | ResultBuilder& m_rb; | |
1874 | T m_lhs; | |
1875 | bool m_truthy; | |
1876 | }; | |
1877 | ||
1878 | template<typename LhsT, Internal::Operator Op, typename RhsT> | |
1879 | class BinaryExpression : public DecomposedExpression { | |
1880 | public: | |
1881 | BinaryExpression( ResultBuilder& rb, LhsT lhs, RhsT rhs ) | |
1882 | : m_rb( rb ), m_lhs( lhs ), m_rhs( rhs ) {} | |
1883 | ||
1884 | BinaryExpression& operator = ( BinaryExpression& ); | |
1885 | ||
1886 | void endExpression() const { | |
1887 | m_rb | |
1888 | .setResultType( Internal::compare<Op>( m_lhs, m_rhs ) ) | |
1889 | .endExpression( *this ); | |
1890 | } | |
1891 | ||
1892 | virtual bool isBinaryExpression() const CATCH_OVERRIDE { | |
1893 | return true; | |
1894 | } | |
1895 | ||
1896 | virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE { | |
1897 | std::string lhs = Catch::toString( m_lhs ); | |
1898 | std::string rhs = Catch::toString( m_rhs ); | |
1899 | char delim = lhs.size() + rhs.size() < 40 && | |
1900 | lhs.find('\n') == std::string::npos && | |
1901 | rhs.find('\n') == std::string::npos ? ' ' : '\n'; | |
1902 | dest.reserve( 7 + lhs.size() + rhs.size() ); | |
1903 | // 2 for spaces around operator | |
1904 | // 2 for operator | |
1905 | // 2 for parentheses (conditionally added later) | |
1906 | // 1 for negation (conditionally added later) | |
1907 | dest = lhs; | |
1908 | dest += delim; | |
1909 | dest += Internal::OperatorTraits<Op>::getName(); | |
1910 | dest += delim; | |
1911 | dest += rhs; | |
1912 | } | |
1913 | ||
1914 | private: | |
1915 | ResultBuilder& m_rb; | |
1916 | LhsT m_lhs; | |
1917 | RhsT m_rhs; | |
1918 | }; | |
1919 | ||
1920 | template<typename ArgT, typename MatcherT> | |
1921 | class MatchExpression : public DecomposedExpression { | |
1922 | public: | |
1923 | MatchExpression( ArgT arg, MatcherT matcher, char const* matcherString ) | |
1924 | : m_arg( arg ), m_matcher( matcher ), m_matcherString( matcherString ) {} | |
1925 | ||
1926 | virtual bool isBinaryExpression() const CATCH_OVERRIDE { | |
1927 | return true; | |
1928 | } | |
1929 | ||
1930 | virtual void reconstructExpression( std::string& dest ) const CATCH_OVERRIDE { | |
1931 | std::string matcherAsString = m_matcher.toString(); | |
1932 | dest = Catch::toString( m_arg ); | |
1933 | dest += ' '; | |
1934 | if( matcherAsString == Detail::unprintableString ) | |
1935 | dest += m_matcherString; | |
1936 | else | |
1937 | dest += matcherAsString; | |
1938 | } | |
1939 | ||
1940 | private: | |
1941 | ArgT m_arg; | |
1942 | MatcherT m_matcher; | |
1943 | char const* m_matcherString; | |
1944 | }; | |
1945 | ||
1946 | } // end namespace Catch | |
1947 | ||
1948 | ||
1949 | namespace Catch { | |
1950 | ||
1951 | template<typename T> | |
1952 | inline ExpressionLhs<T const&> ResultBuilder::operator <= ( T const& operand ) { | |
1953 | return ExpressionLhs<T const&>( *this, operand ); | |
1954 | } | |
1955 | ||
1956 | inline ExpressionLhs<bool> ResultBuilder::operator <= ( bool value ) { | |
1957 | return ExpressionLhs<bool>( *this, value ); | |
1958 | } | |
1959 | ||
1960 | template<typename ArgT, typename MatcherT> | |
1961 | inline void ResultBuilder::captureMatch( ArgT const& arg, MatcherT const& matcher, | |
1962 | char const* matcherString ) { | |
1963 | MatchExpression<ArgT const&, MatcherT const&> expr( arg, matcher, matcherString ); | |
1964 | setResultType( matcher.match( arg ) ); | |
1965 | endExpression( expr ); | |
1966 | } | |
1967 | ||
1968 | } // namespace Catch | |
1969 | ||
1970 | // #included from: catch_message.h | |
1971 | #define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED | |
1972 | ||
1973 | #include <string> | |
1974 | ||
1975 | namespace Catch { | |
1976 | ||
1977 | struct MessageInfo { | |
1978 | MessageInfo( std::string const& _macroName, | |
1979 | SourceLineInfo const& _lineInfo, | |
1980 | ResultWas::OfType _type ); | |
1981 | ||
1982 | std::string macroName; | |
1983 | SourceLineInfo lineInfo; | |
1984 | ResultWas::OfType type; | |
1985 | std::string message; | |
1986 | unsigned int sequence; | |
1987 | ||
1988 | bool operator == ( MessageInfo const& other ) const { | |
1989 | return sequence == other.sequence; | |
1990 | } | |
1991 | bool operator < ( MessageInfo const& other ) const { | |
1992 | return sequence < other.sequence; | |
1993 | } | |
1994 | private: | |
1995 | static unsigned int globalCount; | |
1996 | }; | |
1997 | ||
1998 | struct MessageBuilder { | |
1999 | MessageBuilder( std::string const& macroName, | |
2000 | SourceLineInfo const& lineInfo, | |
2001 | ResultWas::OfType type ) | |
2002 | : m_info( macroName, lineInfo, type ) | |
2003 | {} | |
2004 | ||
2005 | template<typename T> | |
2006 | MessageBuilder& operator << ( T const& value ) { | |
2007 | m_stream << value; | |
2008 | return *this; | |
2009 | } | |
2010 | ||
2011 | MessageInfo m_info; | |
2012 | std::ostringstream m_stream; | |
2013 | }; | |
2014 | ||
2015 | class ScopedMessage { | |
2016 | public: | |
2017 | ScopedMessage( MessageBuilder const& builder ); | |
2018 | ScopedMessage( ScopedMessage const& other ); | |
2019 | ~ScopedMessage(); | |
2020 | ||
2021 | MessageInfo m_info; | |
2022 | }; | |
2023 | ||
2024 | } // end namespace Catch | |
2025 | ||
2026 | // #included from: catch_interfaces_capture.h | |
2027 | #define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED | |
2028 | ||
2029 | #include <string> | |
2030 | ||
2031 | namespace Catch { | |
2032 | ||
2033 | class TestCase; | |
2034 | class AssertionResult; | |
2035 | struct AssertionInfo; | |
2036 | struct SectionInfo; | |
2037 | struct SectionEndInfo; | |
2038 | struct MessageInfo; | |
2039 | class ScopedMessageBuilder; | |
2040 | struct Counts; | |
2041 | ||
2042 | struct IResultCapture { | |
2043 | ||
2044 | virtual ~IResultCapture(); | |
2045 | ||
2046 | virtual void assertionEnded( AssertionResult const& result ) = 0; | |
2047 | virtual bool sectionStarted( SectionInfo const& sectionInfo, | |
2048 | Counts& assertions ) = 0; | |
2049 | virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; | |
2050 | virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; | |
2051 | virtual void pushScopedMessage( MessageInfo const& message ) = 0; | |
2052 | virtual void popScopedMessage( MessageInfo const& message ) = 0; | |
2053 | ||
2054 | virtual std::string getCurrentTestName() const = 0; | |
2055 | virtual const AssertionResult* getLastResult() const = 0; | |
2056 | ||
2057 | virtual void exceptionEarlyReported() = 0; | |
2058 | ||
2059 | virtual void handleFatalErrorCondition( std::string const& message ) = 0; | |
2060 | }; | |
2061 | ||
2062 | IResultCapture& getResultCapture(); | |
2063 | } | |
2064 | ||
2065 | // #included from: catch_debugger.h | |
2066 | #define TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED | |
2067 | ||
2068 | // #included from: catch_platform.h | |
2069 | #define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED | |
2070 | ||
2071 | #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) | |
2072 | # define CATCH_PLATFORM_MAC | |
2073 | #elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) | |
2074 | # define CATCH_PLATFORM_IPHONE | |
2075 | #elif defined(linux) || defined(__linux) || defined(__linux__) | |
2076 | # define CATCH_PLATFORM_LINUX | |
2077 | #elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) | |
2078 | # define CATCH_PLATFORM_WINDOWS | |
2079 | # if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX) | |
2080 | # define CATCH_DEFINES_NOMINMAX | |
2081 | # endif | |
2082 | # if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN) | |
2083 | # define CATCH_DEFINES_WIN32_LEAN_AND_MEAN | |
2084 | # endif | |
2085 | #endif | |
2086 | ||
2087 | #include <string> | |
2088 | ||
2089 | namespace Catch{ | |
2090 | ||
2091 | bool isDebuggerActive(); | |
2092 | void writeToDebugConsole( std::string const& text ); | |
2093 | } | |
2094 | ||
2095 | #ifdef CATCH_PLATFORM_MAC | |
2096 | ||
2097 | // The following code snippet based on: | |
2098 | // http://cocoawithlove.com/2008/03/break-into-debugger.html | |
2099 | #if defined(__ppc64__) || defined(__ppc__) | |
2100 | #define CATCH_TRAP() \ | |
2101 | __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \ | |
2102 | : : : "memory","r0","r3","r4" ) | |
2103 | #else | |
2104 | #define CATCH_TRAP() __asm__("int $3\n" : : ) | |
2105 | #endif | |
2106 | ||
2107 | #elif defined(CATCH_PLATFORM_LINUX) | |
2108 | // If we can use inline assembler, do it because this allows us to break | |
2109 | // directly at the location of the failing check instead of breaking inside | |
2110 | // raise() called from it, i.e. one stack frame below. | |
2111 | #if defined(__GNUC__) && (defined(__i386) || defined(__x86_64)) | |
2112 | #define CATCH_TRAP() asm volatile ("int $3") | |
2113 | #else // Fall back to the generic way. | |
2114 | #include <signal.h> | |
2115 | ||
2116 | #define CATCH_TRAP() raise(SIGTRAP) | |
2117 | #endif | |
2118 | #elif defined(_MSC_VER) | |
2119 | #define CATCH_TRAP() __debugbreak() | |
2120 | #elif defined(__MINGW32__) | |
2121 | extern "C" __declspec(dllimport) void __stdcall DebugBreak(); | |
2122 | #define CATCH_TRAP() DebugBreak() | |
2123 | #endif | |
2124 | ||
2125 | #ifdef CATCH_TRAP | |
2126 | #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } | |
2127 | #else | |
2128 | #define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue(); | |
2129 | #endif | |
2130 | ||
2131 | // #included from: catch_interfaces_runner.h | |
2132 | #define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED | |
2133 | ||
2134 | namespace Catch { | |
2135 | class TestCase; | |
2136 | ||
2137 | struct IRunner { | |
2138 | virtual ~IRunner(); | |
2139 | virtual bool aborting() const = 0; | |
2140 | }; | |
2141 | } | |
2142 | ||
2143 | #if defined(CATCH_CONFIG_FAST_COMPILE) | |
2144 | /////////////////////////////////////////////////////////////////////////////// | |
2145 | // We can speedup compilation significantly by breaking into debugger lower in | |
2146 | // the callstack, because then we don't have to expand CATCH_BREAK_INTO_DEBUGGER | |
2147 | // macro in each assertion | |
2148 | #define INTERNAL_CATCH_REACT( resultBuilder ) \ | |
2149 | resultBuilder.react(); | |
2150 | ||
2151 | /////////////////////////////////////////////////////////////////////////////// | |
2152 | // Another way to speed-up compilation is to omit local try-catch for REQUIRE* | |
2153 | // macros. | |
2154 | // This can potentially cause false negative, if the test code catches | |
2155 | // the exception before it propagates back up to the runner. | |
2156 | #define INTERNAL_CATCH_TEST_NO_TRY( macroName, resultDisposition, expr ) \ | |
2157 | do { \ | |
2158 | Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ | |
2159 | __catchResult.setExceptionGuard(); \ | |
2160 | CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ | |
2161 | ( __catchResult <= expr ).endExpression(); \ | |
2162 | CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ | |
2163 | __catchResult.unsetExceptionGuard(); \ | |
2164 | INTERNAL_CATCH_REACT( __catchResult ) \ | |
2165 | } while( Catch::isTrue( false && static_cast<bool>( !!(expr) ) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look | |
2166 | // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&. | |
2167 | ||
2168 | #define INTERNAL_CHECK_THAT_NO_TRY( macroName, matcher, resultDisposition, arg ) \ | |
2169 | do { \ | |
2170 | Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \ | |
2171 | __catchResult.setExceptionGuard(); \ | |
2172 | __catchResult.captureMatch( arg, matcher, #matcher ); \ | |
2173 | __catchResult.unsetExceptionGuard(); \ | |
2174 | INTERNAL_CATCH_REACT( __catchResult ) \ | |
2175 | } while( Catch::alwaysFalse() ) | |
2176 | ||
2177 | #else | |
2178 | /////////////////////////////////////////////////////////////////////////////// | |
2179 | // In the event of a failure works out if the debugger needs to be invoked | |
2180 | // and/or an exception thrown and takes appropriate action. | |
2181 | // This needs to be done as a macro so the debugger will stop in the user | |
2182 | // source code rather than in Catch library code | |
2183 | #define INTERNAL_CATCH_REACT( resultBuilder ) \ | |
2184 | if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \ | |
2185 | resultBuilder.react(); | |
2186 | #endif | |
2187 | ||
2188 | /////////////////////////////////////////////////////////////////////////////// | |
2189 | #define INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ) \ | |
2190 | do { \ | |
2191 | Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ | |
2192 | try { \ | |
2193 | CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ | |
2194 | ( __catchResult <= expr ).endExpression(); \ | |
2195 | CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ | |
2196 | } \ | |
2197 | catch( ... ) { \ | |
2198 | __catchResult.useActiveException( resultDisposition ); \ | |
2199 | } \ | |
2200 | INTERNAL_CATCH_REACT( __catchResult ) \ | |
2201 | } while( Catch::isTrue( false && static_cast<bool>( !!(expr) ) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look | |
2202 | // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&. | |
2203 | ||
2204 | /////////////////////////////////////////////////////////////////////////////// | |
2205 | #define INTERNAL_CATCH_IF( macroName, resultDisposition, expr ) \ | |
2206 | INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ); \ | |
2207 | if( Catch::getResultCapture().getLastResult()->succeeded() ) | |
2208 | ||
2209 | /////////////////////////////////////////////////////////////////////////////// | |
2210 | #define INTERNAL_CATCH_ELSE( macroName, resultDisposition, expr ) \ | |
2211 | INTERNAL_CATCH_TEST( macroName, resultDisposition, expr ); \ | |
2212 | if( !Catch::getResultCapture().getLastResult()->succeeded() ) | |
2213 | ||
2214 | /////////////////////////////////////////////////////////////////////////////// | |
2215 | #define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, expr ) \ | |
2216 | do { \ | |
2217 | Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ | |
2218 | try { \ | |
2219 | static_cast<void>(expr); \ | |
2220 | __catchResult.captureResult( Catch::ResultWas::Ok ); \ | |
2221 | } \ | |
2222 | catch( ... ) { \ | |
2223 | __catchResult.useActiveException( resultDisposition ); \ | |
2224 | } \ | |
2225 | INTERNAL_CATCH_REACT( __catchResult ) \ | |
2226 | } while( Catch::alwaysFalse() ) | |
2227 | ||
2228 | /////////////////////////////////////////////////////////////////////////////// | |
2229 | #define INTERNAL_CATCH_THROWS( macroName, resultDisposition, matcher, expr ) \ | |
2230 | do { \ | |
2231 | Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition, #matcher ); \ | |
2232 | if( __catchResult.allowThrows() ) \ | |
2233 | try { \ | |
2234 | static_cast<void>(expr); \ | |
2235 | __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ | |
2236 | } \ | |
2237 | catch( ... ) { \ | |
2238 | __catchResult.captureExpectedException( matcher ); \ | |
2239 | } \ | |
2240 | else \ | |
2241 | __catchResult.captureResult( Catch::ResultWas::Ok ); \ | |
2242 | INTERNAL_CATCH_REACT( __catchResult ) \ | |
2243 | } while( Catch::alwaysFalse() ) | |
2244 | ||
2245 | /////////////////////////////////////////////////////////////////////////////// | |
2246 | #define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \ | |
2247 | do { \ | |
2248 | Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr ", " #exceptionType, resultDisposition ); \ | |
2249 | if( __catchResult.allowThrows() ) \ | |
2250 | try { \ | |
2251 | static_cast<void>(expr); \ | |
2252 | __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ | |
2253 | } \ | |
2254 | catch( exceptionType ) { \ | |
2255 | __catchResult.captureResult( Catch::ResultWas::Ok ); \ | |
2256 | } \ | |
2257 | catch( ... ) { \ | |
2258 | __catchResult.useActiveException( resultDisposition ); \ | |
2259 | } \ | |
2260 | else \ | |
2261 | __catchResult.captureResult( Catch::ResultWas::Ok ); \ | |
2262 | INTERNAL_CATCH_REACT( __catchResult ) \ | |
2263 | } while( Catch::alwaysFalse() ) | |
2264 | ||
2265 | /////////////////////////////////////////////////////////////////////////////// | |
2266 | #ifdef CATCH_CONFIG_VARIADIC_MACROS | |
2267 | #define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \ | |
2268 | do { \ | |
2269 | Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ | |
2270 | __catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \ | |
2271 | __catchResult.captureResult( messageType ); \ | |
2272 | INTERNAL_CATCH_REACT( __catchResult ) \ | |
2273 | } while( Catch::alwaysFalse() ) | |
2274 | #else | |
2275 | #define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, log ) \ | |
2276 | do { \ | |
2277 | Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ | |
2278 | __catchResult << log + ::Catch::StreamEndStop(); \ | |
2279 | __catchResult.captureResult( messageType ); \ | |
2280 | INTERNAL_CATCH_REACT( __catchResult ) \ | |
2281 | } while( Catch::alwaysFalse() ) | |
2282 | #endif | |
2283 | ||
2284 | /////////////////////////////////////////////////////////////////////////////// | |
2285 | #define INTERNAL_CATCH_INFO( macroName, log ) \ | |
2286 | Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log; | |
2287 | ||
2288 | /////////////////////////////////////////////////////////////////////////////// | |
2289 | #define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \ | |
2290 | do { \ | |
2291 | Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \ | |
2292 | try { \ | |
2293 | __catchResult.captureMatch( arg, matcher, #matcher ); \ | |
2294 | } catch( ... ) { \ | |
2295 | __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \ | |
2296 | } \ | |
2297 | INTERNAL_CATCH_REACT( __catchResult ) \ | |
2298 | } while( Catch::alwaysFalse() ) | |
2299 | ||
2300 | // #included from: internal/catch_section.h | |
2301 | #define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED | |
2302 | ||
2303 | // #included from: catch_section_info.h | |
2304 | #define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED | |
2305 | ||
2306 | // #included from: catch_totals.hpp | |
2307 | #define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED | |
2308 | ||
2309 | #include <cstddef> | |
2310 | ||
2311 | namespace Catch { | |
2312 | ||
2313 | struct Counts { | |
2314 | Counts() : passed( 0 ), failed( 0 ), failedButOk( 0 ) {} | |
2315 | ||
2316 | Counts operator - ( Counts const& other ) const { | |
2317 | Counts diff; | |
2318 | diff.passed = passed - other.passed; | |
2319 | diff.failed = failed - other.failed; | |
2320 | diff.failedButOk = failedButOk - other.failedButOk; | |
2321 | return diff; | |
2322 | } | |
2323 | Counts& operator += ( Counts const& other ) { | |
2324 | passed += other.passed; | |
2325 | failed += other.failed; | |
2326 | failedButOk += other.failedButOk; | |
2327 | return *this; | |
2328 | } | |
2329 | ||
2330 | std::size_t total() const { | |
2331 | return passed + failed + failedButOk; | |
2332 | } | |
2333 | bool allPassed() const { | |
2334 | return failed == 0 && failedButOk == 0; | |
2335 | } | |
2336 | bool allOk() const { | |
2337 | return failed == 0; | |
2338 | } | |
2339 | ||
2340 | std::size_t passed; | |
2341 | std::size_t failed; | |
2342 | std::size_t failedButOk; | |
2343 | }; | |
2344 | ||
2345 | struct Totals { | |
2346 | ||
2347 | Totals operator - ( Totals const& other ) const { | |
2348 | Totals diff; | |
2349 | diff.assertions = assertions - other.assertions; | |
2350 | diff.testCases = testCases - other.testCases; | |
2351 | return diff; | |
2352 | } | |
2353 | ||
2354 | Totals delta( Totals const& prevTotals ) const { | |
2355 | Totals diff = *this - prevTotals; | |
2356 | if( diff.assertions.failed > 0 ) | |
2357 | ++diff.testCases.failed; | |
2358 | else if( diff.assertions.failedButOk > 0 ) | |
2359 | ++diff.testCases.failedButOk; | |
2360 | else | |
2361 | ++diff.testCases.passed; | |
2362 | return diff; | |
2363 | } | |
2364 | ||
2365 | Totals& operator += ( Totals const& other ) { | |
2366 | assertions += other.assertions; | |
2367 | testCases += other.testCases; | |
2368 | return *this; | |
2369 | } | |
2370 | ||
2371 | Counts assertions; | |
2372 | Counts testCases; | |
2373 | }; | |
2374 | } | |
2375 | ||
2376 | #include <string> | |
2377 | ||
2378 | namespace Catch { | |
2379 | ||
2380 | struct SectionInfo { | |
2381 | SectionInfo | |
2382 | ( SourceLineInfo const& _lineInfo, | |
2383 | std::string const& _name, | |
2384 | std::string const& _description = std::string() ); | |
2385 | ||
2386 | std::string name; | |
2387 | std::string description; | |
2388 | SourceLineInfo lineInfo; | |
2389 | }; | |
2390 | ||
2391 | struct SectionEndInfo { | |
2392 | SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds ) | |
2393 | : sectionInfo( _sectionInfo ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) | |
2394 | {} | |
2395 | ||
2396 | SectionInfo sectionInfo; | |
2397 | Counts prevAssertions; | |
2398 | double durationInSeconds; | |
2399 | }; | |
2400 | ||
2401 | } // end namespace Catch | |
2402 | ||
2403 | // #included from: catch_timer.h | |
2404 | #define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED | |
2405 | ||
2406 | #ifdef _MSC_VER | |
2407 | ||
2408 | namespace Catch { | |
2409 | typedef unsigned long long UInt64; | |
2410 | } | |
2411 | #else | |
2412 | #include <stdint.h> | |
2413 | namespace Catch { | |
2414 | typedef uint64_t UInt64; | |
2415 | } | |
2416 | #endif | |
2417 | ||
2418 | namespace Catch { | |
2419 | class Timer { | |
2420 | public: | |
2421 | Timer() : m_ticks( 0 ) {} | |
2422 | void start(); | |
2423 | unsigned int getElapsedMicroseconds() const; | |
2424 | unsigned int getElapsedMilliseconds() const; | |
2425 | double getElapsedSeconds() const; | |
2426 | ||
2427 | private: | |
2428 | UInt64 m_ticks; | |
2429 | }; | |
2430 | ||
2431 | } // namespace Catch | |
2432 | ||
2433 | #include <string> | |
2434 | ||
2435 | namespace Catch { | |
2436 | ||
2437 | class Section : NonCopyable { | |
2438 | public: | |
2439 | Section( SectionInfo const& info ); | |
2440 | ~Section(); | |
2441 | ||
2442 | // This indicates whether the section should be executed or not | |
2443 | operator bool() const; | |
2444 | ||
2445 | private: | |
2446 | SectionInfo m_info; | |
2447 | ||
2448 | std::string m_name; | |
2449 | Counts m_assertions; | |
2450 | bool m_sectionIncluded; | |
2451 | Timer m_timer; | |
2452 | }; | |
2453 | ||
2454 | } // end namespace Catch | |
2455 | ||
2456 | #ifdef CATCH_CONFIG_VARIADIC_MACROS | |
2457 | #define INTERNAL_CATCH_SECTION( ... ) \ | |
2458 | if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) | |
2459 | #else | |
2460 | #define INTERNAL_CATCH_SECTION( name, desc ) \ | |
2461 | if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, name, desc ) ) | |
2462 | #endif | |
2463 | ||
2464 | // #included from: internal/catch_generators.hpp | |
2465 | #define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED | |
2466 | ||
2467 | #include <vector> | |
2468 | #include <string> | |
2469 | #include <stdlib.h> | |
2470 | ||
2471 | namespace Catch { | |
2472 | ||
2473 | template<typename T> | |
2474 | struct IGenerator { | |
2475 | virtual ~IGenerator() {} | |
2476 | virtual T getValue( std::size_t index ) const = 0; | |
2477 | virtual std::size_t size () const = 0; | |
2478 | }; | |
2479 | ||
2480 | template<typename T> | |
2481 | class BetweenGenerator : public IGenerator<T> { | |
2482 | public: | |
2483 | BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){} | |
2484 | ||
2485 | virtual T getValue( std::size_t index ) const { | |
2486 | return m_from+static_cast<int>( index ); | |
2487 | } | |
2488 | ||
2489 | virtual std::size_t size() const { | |
2490 | return static_cast<std::size_t>( 1+m_to-m_from ); | |
2491 | } | |
2492 | ||
2493 | private: | |
2494 | ||
2495 | T m_from; | |
2496 | T m_to; | |
2497 | }; | |
2498 | ||
2499 | template<typename T> | |
2500 | class ValuesGenerator : public IGenerator<T> { | |
2501 | public: | |
2502 | ValuesGenerator(){} | |
2503 | ||
2504 | void add( T value ) { | |
2505 | m_values.push_back( value ); | |
2506 | } | |
2507 | ||
2508 | virtual T getValue( std::size_t index ) const { | |
2509 | return m_values[index]; | |
2510 | } | |
2511 | ||
2512 | virtual std::size_t size() const { | |
2513 | return m_values.size(); | |
2514 | } | |
2515 | ||
2516 | private: | |
2517 | std::vector<T> m_values; | |
2518 | }; | |
2519 | ||
2520 | template<typename T> | |
2521 | class CompositeGenerator { | |
2522 | public: | |
2523 | CompositeGenerator() : m_totalSize( 0 ) {} | |
2524 | ||
2525 | // *** Move semantics, similar to auto_ptr *** | |
2526 | CompositeGenerator( CompositeGenerator& other ) | |
2527 | : m_fileInfo( other.m_fileInfo ), | |
2528 | m_totalSize( 0 ) | |
2529 | { | |
2530 | move( other ); | |
2531 | } | |
2532 | ||
2533 | CompositeGenerator& setFileInfo( const char* fileInfo ) { | |
2534 | m_fileInfo = fileInfo; | |
2535 | return *this; | |
2536 | } | |
2537 | ||
2538 | ~CompositeGenerator() { | |
2539 | deleteAll( m_composed ); | |
2540 | } | |
2541 | ||
2542 | operator T () const { | |
2543 | size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize ); | |
2544 | ||
2545 | typename std::vector<const IGenerator<T>*>::const_iterator it = m_composed.begin(); | |
2546 | typename std::vector<const IGenerator<T>*>::const_iterator itEnd = m_composed.end(); | |
2547 | for( size_t index = 0; it != itEnd; ++it ) | |
2548 | { | |
2549 | const IGenerator<T>* generator = *it; | |
2550 | if( overallIndex >= index && overallIndex < index + generator->size() ) | |
2551 | { | |
2552 | return generator->getValue( overallIndex-index ); | |
2553 | } | |
2554 | index += generator->size(); | |
2555 | } | |
2556 | CATCH_INTERNAL_ERROR( "Indexed past end of generated range" ); | |
2557 | return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so | |
2558 | } | |
2559 | ||
2560 | void add( const IGenerator<T>* generator ) { | |
2561 | m_totalSize += generator->size(); | |
2562 | m_composed.push_back( generator ); | |
2563 | } | |
2564 | ||
2565 | CompositeGenerator& then( CompositeGenerator& other ) { | |
2566 | move( other ); | |
2567 | return *this; | |
2568 | } | |
2569 | ||
2570 | CompositeGenerator& then( T value ) { | |
2571 | ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>(); | |
2572 | valuesGen->add( value ); | |
2573 | add( valuesGen ); | |
2574 | return *this; | |
2575 | } | |
2576 | ||
2577 | private: | |
2578 | ||
2579 | void move( CompositeGenerator& other ) { | |
2580 | m_composed.insert( m_composed.end(), other.m_composed.begin(), other.m_composed.end() ); | |
2581 | m_totalSize += other.m_totalSize; | |
2582 | other.m_composed.clear(); | |
2583 | } | |
2584 | ||
2585 | std::vector<const IGenerator<T>*> m_composed; | |
2586 | std::string m_fileInfo; | |
2587 | size_t m_totalSize; | |
2588 | }; | |
2589 | ||
2590 | namespace Generators | |
2591 | { | |
2592 | template<typename T> | |
2593 | CompositeGenerator<T> between( T from, T to ) { | |
2594 | CompositeGenerator<T> generators; | |
2595 | generators.add( new BetweenGenerator<T>( from, to ) ); | |
2596 | return generators; | |
2597 | } | |
2598 | ||
2599 | template<typename T> | |
2600 | CompositeGenerator<T> values( T val1, T val2 ) { | |
2601 | CompositeGenerator<T> generators; | |
2602 | ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>(); | |
2603 | valuesGen->add( val1 ); | |
2604 | valuesGen->add( val2 ); | |
2605 | generators.add( valuesGen ); | |
2606 | return generators; | |
2607 | } | |
2608 | ||
2609 | template<typename T> | |
2610 | CompositeGenerator<T> values( T val1, T val2, T val3 ){ | |
2611 | CompositeGenerator<T> generators; | |
2612 | ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>(); | |
2613 | valuesGen->add( val1 ); | |
2614 | valuesGen->add( val2 ); | |
2615 | valuesGen->add( val3 ); | |
2616 | generators.add( valuesGen ); | |
2617 | return generators; | |
2618 | } | |
2619 | ||
2620 | template<typename T> | |
2621 | CompositeGenerator<T> values( T val1, T val2, T val3, T val4 ) { | |
2622 | CompositeGenerator<T> generators; | |
2623 | ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>(); | |
2624 | valuesGen->add( val1 ); | |
2625 | valuesGen->add( val2 ); | |
2626 | valuesGen->add( val3 ); | |
2627 | valuesGen->add( val4 ); | |
2628 | generators.add( valuesGen ); | |
2629 | return generators; | |
2630 | } | |
2631 | ||
2632 | } // end namespace Generators | |
2633 | ||
2634 | using namespace Generators; | |
2635 | ||
2636 | } // end namespace Catch | |
2637 | ||
2638 | #define INTERNAL_CATCH_LINESTR2( line ) #line | |
2639 | #define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line ) | |
2640 | ||
2641 | #define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" ) | |
2642 | ||
2643 | // #included from: internal/catch_interfaces_exception.h | |
2644 | #define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED | |
2645 | ||
2646 | #include <string> | |
2647 | #include <vector> | |
2648 | ||
2649 | // #included from: catch_interfaces_registry_hub.h | |
2650 | #define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED | |
2651 | ||
2652 | #include <string> | |
2653 | ||
2654 | namespace Catch { | |
2655 | ||
2656 | class TestCase; | |
2657 | struct ITestCaseRegistry; | |
2658 | struct IExceptionTranslatorRegistry; | |
2659 | struct IExceptionTranslator; | |
2660 | struct IReporterRegistry; | |
2661 | struct IReporterFactory; | |
2662 | struct ITagAliasRegistry; | |
2663 | ||
2664 | struct IRegistryHub { | |
2665 | virtual ~IRegistryHub(); | |
2666 | ||
2667 | virtual IReporterRegistry const& getReporterRegistry() const = 0; | |
2668 | virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; | |
2669 | virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0; | |
2670 | ||
2671 | virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0; | |
2672 | }; | |
2673 | ||
2674 | struct IMutableRegistryHub { | |
2675 | virtual ~IMutableRegistryHub(); | |
2676 | virtual void registerReporter( std::string const& name, Ptr<IReporterFactory> const& factory ) = 0; | |
2677 | virtual void registerListener( Ptr<IReporterFactory> const& factory ) = 0; | |
2678 | virtual void registerTest( TestCase const& testInfo ) = 0; | |
2679 | virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; | |
2680 | virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0; | |
2681 | }; | |
2682 | ||
2683 | IRegistryHub& getRegistryHub(); | |
2684 | IMutableRegistryHub& getMutableRegistryHub(); | |
2685 | void cleanUp(); | |
2686 | std::string translateActiveException(); | |
2687 | ||
2688 | } | |
2689 | ||
2690 | namespace Catch { | |
2691 | ||
2692 | typedef std::string(*exceptionTranslateFunction)(); | |
2693 | ||
2694 | struct IExceptionTranslator; | |
2695 | typedef std::vector<const IExceptionTranslator*> ExceptionTranslators; | |
2696 | ||
2697 | struct IExceptionTranslator { | |
2698 | virtual ~IExceptionTranslator(); | |
2699 | virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0; | |
2700 | }; | |
2701 | ||
2702 | struct IExceptionTranslatorRegistry { | |
2703 | virtual ~IExceptionTranslatorRegistry(); | |
2704 | ||
2705 | virtual std::string translateActiveException() const = 0; | |
2706 | }; | |
2707 | ||
2708 | class ExceptionTranslatorRegistrar { | |
2709 | template<typename T> | |
2710 | class ExceptionTranslator : public IExceptionTranslator { | |
2711 | public: | |
2712 | ||
2713 | ExceptionTranslator( std::string(*translateFunction)( T& ) ) | |
2714 | : m_translateFunction( translateFunction ) | |
2715 | {} | |
2716 | ||
2717 | virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const CATCH_OVERRIDE { | |
2718 | try { | |
2719 | if( it == itEnd ) | |
2720 | throw; | |
2721 | else | |
2722 | return (*it)->translate( it+1, itEnd ); | |
2723 | } | |
2724 | catch( T& ex ) { | |
2725 | return m_translateFunction( ex ); | |
2726 | } | |
2727 | } | |
2728 | ||
2729 | protected: | |
2730 | std::string(*m_translateFunction)( T& ); | |
2731 | }; | |
2732 | ||
2733 | public: | |
2734 | template<typename T> | |
2735 | ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) { | |
2736 | getMutableRegistryHub().registerTranslator | |
2737 | ( new ExceptionTranslator<T>( translateFunction ) ); | |
2738 | } | |
2739 | }; | |
2740 | } | |
2741 | ||
2742 | /////////////////////////////////////////////////////////////////////////////// | |
2743 | #define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \ | |
2744 | static std::string translatorName( signature ); \ | |
2745 | namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); }\ | |
2746 | static std::string translatorName( signature ) | |
2747 | ||
2748 | #define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) | |
2749 | ||
2750 | // #included from: internal/catch_approx.hpp | |
2751 | #define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED | |
2752 | ||
2753 | #include <cmath> | |
2754 | #include <limits> | |
2755 | ||
2756 | #if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS) | |
2757 | #include <type_traits> | |
2758 | #endif | |
2759 | ||
2760 | namespace Catch { | |
2761 | namespace Detail { | |
2762 | ||
2763 | class Approx { | |
2764 | public: | |
2765 | explicit Approx ( double value ) | |
2766 | : m_epsilon( std::numeric_limits<float>::epsilon()*100 ), | |
2767 | m_margin( 0.0 ), | |
2768 | m_scale( 1.0 ), | |
2769 | m_value( value ) | |
2770 | {} | |
2771 | ||
2772 | Approx( Approx const& other ) | |
2773 | : m_epsilon( other.m_epsilon ), | |
2774 | m_margin( other.m_margin ), | |
2775 | m_scale( other.m_scale ), | |
2776 | m_value( other.m_value ) | |
2777 | {} | |
2778 | ||
2779 | static Approx custom() { | |
2780 | return Approx( 0 ); | |
2781 | } | |
2782 | ||
2783 | #if defined(CATCH_CONFIG_CPP11_TYPE_TRAITS) | |
2784 | ||
2785 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> | |
2786 | Approx operator()( T value ) { | |
2787 | Approx approx( static_cast<double>(value) ); | |
2788 | approx.epsilon( m_epsilon ); | |
2789 | approx.margin( m_margin ); | |
2790 | approx.scale( m_scale ); | |
2791 | return approx; | |
2792 | } | |
2793 | ||
2794 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> | |
2795 | explicit Approx( T value ): Approx(static_cast<double>(value)) | |
2796 | {} | |
2797 | ||
2798 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> | |
2799 | friend bool operator == ( const T& lhs, Approx const& rhs ) { | |
2800 | // Thanks to Richard Harris for his help refining this formula | |
2801 | auto lhs_v = double(lhs); | |
2802 | bool relativeOK = std::fabs(lhs_v - rhs.m_value) < rhs.m_epsilon * (rhs.m_scale + (std::max)(std::fabs(lhs_v), std::fabs(rhs.m_value))); | |
2803 | if (relativeOK) { | |
2804 | return true; | |
2805 | } | |
2806 | return std::fabs(lhs_v - rhs.m_value) < rhs.m_margin; | |
2807 | } | |
2808 | ||
2809 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> | |
2810 | friend bool operator == ( Approx const& lhs, const T& rhs ) { | |
2811 | return operator==( rhs, lhs ); | |
2812 | } | |
2813 | ||
2814 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> | |
2815 | friend bool operator != ( T lhs, Approx const& rhs ) { | |
2816 | return !operator==( lhs, rhs ); | |
2817 | } | |
2818 | ||
2819 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> | |
2820 | friend bool operator != ( Approx const& lhs, T rhs ) { | |
2821 | return !operator==( rhs, lhs ); | |
2822 | } | |
2823 | ||
2824 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> | |
2825 | friend bool operator <= ( T lhs, Approx const& rhs ) { | |
2826 | return double(lhs) < rhs.m_value || lhs == rhs; | |
2827 | } | |
2828 | ||
2829 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> | |
2830 | friend bool operator <= ( Approx const& lhs, T rhs ) { | |
2831 | return lhs.m_value < double(rhs) || lhs == rhs; | |
2832 | } | |
2833 | ||
2834 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> | |
2835 | friend bool operator >= ( T lhs, Approx const& rhs ) { | |
2836 | return double(lhs) > rhs.m_value || lhs == rhs; | |
2837 | } | |
2838 | ||
2839 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> | |
2840 | friend bool operator >= ( Approx const& lhs, T rhs ) { | |
2841 | return lhs.m_value > double(rhs) || lhs == rhs; | |
2842 | } | |
2843 | ||
2844 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> | |
2845 | Approx& epsilon( T newEpsilon ) { | |
2846 | m_epsilon = double(newEpsilon); | |
2847 | return *this; | |
2848 | } | |
2849 | ||
2850 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> | |
2851 | Approx& margin( T newMargin ) { | |
2852 | m_margin = double(newMargin); | |
2853 | return *this; | |
2854 | } | |
2855 | ||
2856 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> | |
2857 | Approx& scale( T newScale ) { | |
2858 | m_scale = double(newScale); | |
2859 | return *this; | |
2860 | } | |
2861 | ||
2862 | #else | |
2863 | ||
2864 | Approx operator()( double value ) { | |
2865 | Approx approx( value ); | |
2866 | approx.epsilon( m_epsilon ); | |
2867 | approx.margin( m_margin ); | |
2868 | approx.scale( m_scale ); | |
2869 | return approx; | |
2870 | } | |
2871 | ||
2872 | friend bool operator == ( double lhs, Approx const& rhs ) { | |
2873 | // Thanks to Richard Harris for his help refining this formula | |
2874 | bool relativeOK = std::fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( std::fabs(lhs), std::fabs(rhs.m_value) ) ); | |
2875 | if (relativeOK) { | |
2876 | return true; | |
2877 | } | |
2878 | return std::fabs(lhs - rhs.m_value) < rhs.m_margin; | |
2879 | } | |
2880 | ||
2881 | friend bool operator == ( Approx const& lhs, double rhs ) { | |
2882 | return operator==( rhs, lhs ); | |
2883 | } | |
2884 | ||
2885 | friend bool operator != ( double lhs, Approx const& rhs ) { | |
2886 | return !operator==( lhs, rhs ); | |
2887 | } | |
2888 | ||
2889 | friend bool operator != ( Approx const& lhs, double rhs ) { | |
2890 | return !operator==( rhs, lhs ); | |
2891 | } | |
2892 | ||
2893 | friend bool operator <= ( double lhs, Approx const& rhs ) { | |
2894 | return lhs < rhs.m_value || lhs == rhs; | |
2895 | } | |
2896 | ||
2897 | friend bool operator <= ( Approx const& lhs, double rhs ) { | |
2898 | return lhs.m_value < rhs || lhs == rhs; | |
2899 | } | |
2900 | ||
2901 | friend bool operator >= ( double lhs, Approx const& rhs ) { | |
2902 | return lhs > rhs.m_value || lhs == rhs; | |
2903 | } | |
2904 | ||
2905 | friend bool operator >= ( Approx const& lhs, double rhs ) { | |
2906 | return lhs.m_value > rhs || lhs == rhs; | |
2907 | } | |
2908 | ||
2909 | Approx& epsilon( double newEpsilon ) { | |
2910 | m_epsilon = newEpsilon; | |
2911 | return *this; | |
2912 | } | |
2913 | ||
2914 | Approx& margin( double newMargin ) { | |
2915 | m_margin = newMargin; | |
2916 | return *this; | |
2917 | } | |
2918 | ||
2919 | Approx& scale( double newScale ) { | |
2920 | m_scale = newScale; | |
2921 | return *this; | |
2922 | } | |
2923 | #endif | |
2924 | ||
2925 | std::string toString() const { | |
2926 | std::ostringstream oss; | |
2927 | oss << "Approx( " << Catch::toString( m_value ) << " )"; | |
2928 | return oss.str(); | |
2929 | } | |
2930 | ||
2931 | private: | |
2932 | double m_epsilon; | |
2933 | double m_margin; | |
2934 | double m_scale; | |
2935 | double m_value; | |
2936 | }; | |
2937 | } | |
2938 | ||
2939 | template<> | |
2940 | inline std::string toString<Detail::Approx>( Detail::Approx const& value ) { | |
2941 | return value.toString(); | |
2942 | } | |
2943 | ||
2944 | } // end namespace Catch | |
2945 | ||
2946 | // #included from: internal/catch_matchers_string.h | |
2947 | #define TWOBLUECUBES_CATCH_MATCHERS_STRING_H_INCLUDED | |
2948 | ||
2949 | namespace Catch { | |
2950 | namespace Matchers { | |
2951 | ||
2952 | namespace StdString { | |
2953 | ||
2954 | struct CasedString | |
2955 | { | |
2956 | CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ); | |
2957 | std::string adjustString( std::string const& str ) const; | |
2958 | std::string caseSensitivitySuffix() const; | |
2959 | ||
2960 | CaseSensitive::Choice m_caseSensitivity; | |
2961 | std::string m_str; | |
2962 | }; | |
2963 | ||
2964 | struct StringMatcherBase : MatcherBase<std::string> { | |
2965 | StringMatcherBase( std::string const& operation, CasedString const& comparator ); | |
2966 | virtual std::string describe() const CATCH_OVERRIDE; | |
2967 | ||
2968 | CasedString m_comparator; | |
2969 | std::string m_operation; | |
2970 | }; | |
2971 | ||
2972 | struct EqualsMatcher : StringMatcherBase { | |
2973 | EqualsMatcher( CasedString const& comparator ); | |
2974 | virtual bool match( std::string const& source ) const CATCH_OVERRIDE; | |
2975 | }; | |
2976 | struct ContainsMatcher : StringMatcherBase { | |
2977 | ContainsMatcher( CasedString const& comparator ); | |
2978 | virtual bool match( std::string const& source ) const CATCH_OVERRIDE; | |
2979 | }; | |
2980 | struct StartsWithMatcher : StringMatcherBase { | |
2981 | StartsWithMatcher( CasedString const& comparator ); | |
2982 | virtual bool match( std::string const& source ) const CATCH_OVERRIDE; | |
2983 | }; | |
2984 | struct EndsWithMatcher : StringMatcherBase { | |
2985 | EndsWithMatcher( CasedString const& comparator ); | |
2986 | virtual bool match( std::string const& source ) const CATCH_OVERRIDE; | |
2987 | }; | |
2988 | ||
2989 | } // namespace StdString | |
2990 | ||
2991 | // The following functions create the actual matcher objects. | |
2992 | // This allows the types to be inferred | |
2993 | ||
2994 | StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); | |
2995 | StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); | |
2996 | StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); | |
2997 | StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); | |
2998 | ||
2999 | } // namespace Matchers | |
3000 | } // namespace Catch | |
3001 | ||
3002 | // #included from: internal/catch_matchers_vector.h | |
3003 | #define TWOBLUECUBES_CATCH_MATCHERS_VECTOR_H_INCLUDED | |
3004 | ||
3005 | namespace Catch { | |
3006 | namespace Matchers { | |
3007 | ||
3008 | namespace Vector { | |
3009 | ||
3010 | template<typename T> | |
3011 | struct ContainsElementMatcher : MatcherBase<std::vector<T>, T> { | |
3012 | ||
3013 | ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {} | |
3014 | ||
3015 | bool match(std::vector<T> const &v) const CATCH_OVERRIDE { | |
3016 | return std::find(v.begin(), v.end(), m_comparator) != v.end(); | |
3017 | } | |
3018 | ||
3019 | virtual std::string describe() const CATCH_OVERRIDE { | |
3020 | return "Contains: " + Catch::toString( m_comparator ); | |
3021 | } | |
3022 | ||
3023 | T const& m_comparator; | |
3024 | }; | |
3025 | ||
3026 | template<typename T> | |
3027 | struct ContainsMatcher : MatcherBase<std::vector<T>, std::vector<T> > { | |
3028 | ||
3029 | ContainsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {} | |
3030 | ||
3031 | bool match(std::vector<T> const &v) const CATCH_OVERRIDE { | |
3032 | // !TBD: see note in EqualsMatcher | |
3033 | if (m_comparator.size() > v.size()) | |
3034 | return false; | |
3035 | for (size_t i = 0; i < m_comparator.size(); ++i) | |
3036 | if (std::find(v.begin(), v.end(), m_comparator[i]) == v.end()) | |
3037 | return false; | |
3038 | return true; | |
3039 | } | |
3040 | virtual std::string describe() const CATCH_OVERRIDE { | |
3041 | return "Contains: " + Catch::toString( m_comparator ); | |
3042 | } | |
3043 | ||
3044 | std::vector<T> const& m_comparator; | |
3045 | }; | |
3046 | ||
3047 | template<typename T> | |
3048 | struct EqualsMatcher : MatcherBase<std::vector<T>, std::vector<T> > { | |
3049 | ||
3050 | EqualsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {} | |
3051 | ||
3052 | bool match(std::vector<T> const &v) const CATCH_OVERRIDE { | |
3053 | // !TBD: This currently works if all elements can be compared using != | |
3054 | // - a more general approach would be via a compare template that defaults | |
3055 | // to using !=. but could be specialised for, e.g. std::vector<T> etc | |
3056 | // - then just call that directly | |
3057 | if (m_comparator.size() != v.size()) | |
3058 | return false; | |
3059 | for (size_t i = 0; i < v.size(); ++i) | |
3060 | if (m_comparator[i] != v[i]) | |
3061 | return false; | |
3062 | return true; | |
3063 | } | |
3064 | virtual std::string describe() const CATCH_OVERRIDE { | |
3065 | return "Equals: " + Catch::toString( m_comparator ); | |
3066 | } | |
3067 | std::vector<T> const& m_comparator; | |
3068 | }; | |
3069 | ||
3070 | } // namespace Vector | |
3071 | ||
3072 | // The following functions create the actual matcher objects. | |
3073 | // This allows the types to be inferred | |
3074 | ||
3075 | template<typename T> | |
3076 | Vector::ContainsMatcher<T> Contains( std::vector<T> const& comparator ) { | |
3077 | return Vector::ContainsMatcher<T>( comparator ); | |
3078 | } | |
3079 | ||
3080 | template<typename T> | |
3081 | Vector::ContainsElementMatcher<T> VectorContains( T const& comparator ) { | |
3082 | return Vector::ContainsElementMatcher<T>( comparator ); | |
3083 | } | |
3084 | ||
3085 | template<typename T> | |
3086 | Vector::EqualsMatcher<T> Equals( std::vector<T> const& comparator ) { | |
3087 | return Vector::EqualsMatcher<T>( comparator ); | |
3088 | } | |
3089 | ||
3090 | } // namespace Matchers | |
3091 | } // namespace Catch | |
3092 | ||
3093 | // #included from: internal/catch_interfaces_tag_alias_registry.h | |
3094 | #define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED | |
3095 | ||
3096 | // #included from: catch_tag_alias.h | |
3097 | #define TWOBLUECUBES_CATCH_TAG_ALIAS_H_INCLUDED | |
3098 | ||
3099 | #include <string> | |
3100 | ||
3101 | namespace Catch { | |
3102 | ||
3103 | struct TagAlias { | |
3104 | TagAlias( std::string const& _tag, SourceLineInfo _lineInfo ) : tag( _tag ), lineInfo( _lineInfo ) {} | |
3105 | ||
3106 | std::string tag; | |
3107 | SourceLineInfo lineInfo; | |
3108 | }; | |
3109 | ||
3110 | struct RegistrarForTagAliases { | |
3111 | RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); | |
3112 | }; | |
3113 | ||
3114 | } // end namespace Catch | |
3115 | ||
3116 | #define CATCH_REGISTER_TAG_ALIAS( alias, spec ) namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } | |
3117 | // #included from: catch_option.hpp | |
3118 | #define TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED | |
3119 | ||
3120 | namespace Catch { | |
3121 | ||
3122 | // An optional type | |
3123 | template<typename T> | |
3124 | class Option { | |
3125 | public: | |
3126 | Option() : nullableValue( CATCH_NULL ) {} | |
3127 | Option( T const& _value ) | |
3128 | : nullableValue( new( storage ) T( _value ) ) | |
3129 | {} | |
3130 | Option( Option const& _other ) | |
3131 | : nullableValue( _other ? new( storage ) T( *_other ) : CATCH_NULL ) | |
3132 | {} | |
3133 | ||
3134 | ~Option() { | |
3135 | reset(); | |
3136 | } | |
3137 | ||
3138 | Option& operator= ( Option const& _other ) { | |
3139 | if( &_other != this ) { | |
3140 | reset(); | |
3141 | if( _other ) | |
3142 | nullableValue = new( storage ) T( *_other ); | |
3143 | } | |
3144 | return *this; | |
3145 | } | |
3146 | Option& operator = ( T const& _value ) { | |
3147 | reset(); | |
3148 | nullableValue = new( storage ) T( _value ); | |
3149 | return *this; | |
3150 | } | |
3151 | ||
3152 | void reset() { | |
3153 | if( nullableValue ) | |
3154 | nullableValue->~T(); | |
3155 | nullableValue = CATCH_NULL; | |
3156 | } | |
3157 | ||
3158 | T& operator*() { return *nullableValue; } | |
3159 | T const& operator*() const { return *nullableValue; } | |
3160 | T* operator->() { return nullableValue; } | |
3161 | const T* operator->() const { return nullableValue; } | |
3162 | ||
3163 | T valueOr( T const& defaultValue ) const { | |
3164 | return nullableValue ? *nullableValue : defaultValue; | |
3165 | } | |
3166 | ||
3167 | bool some() const { return nullableValue != CATCH_NULL; } | |
3168 | bool none() const { return nullableValue == CATCH_NULL; } | |
3169 | ||
3170 | bool operator !() const { return nullableValue == CATCH_NULL; } | |
3171 | operator SafeBool::type() const { | |
3172 | return SafeBool::makeSafe( some() ); | |
3173 | } | |
3174 | ||
3175 | private: | |
3176 | T *nullableValue; | |
3177 | union { | |
3178 | char storage[sizeof(T)]; | |
3179 | ||
3180 | // These are here to force alignment for the storage | |
3181 | long double dummy1; | |
3182 | void (*dummy2)(); | |
3183 | long double dummy3; | |
3184 | #ifdef CATCH_CONFIG_CPP11_LONG_LONG | |
3185 | long long dummy4; | |
3186 | #endif | |
3187 | }; | |
3188 | }; | |
3189 | ||
3190 | } // end namespace Catch | |
3191 | ||
3192 | namespace Catch { | |
3193 | ||
3194 | struct ITagAliasRegistry { | |
3195 | virtual ~ITagAliasRegistry(); | |
3196 | virtual Option<TagAlias> find( std::string const& alias ) const = 0; | |
3197 | virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0; | |
3198 | ||
3199 | static ITagAliasRegistry const& get(); | |
3200 | }; | |
3201 | ||
3202 | } // end namespace Catch | |
3203 | ||
3204 | // These files are included here so the single_include script doesn't put them | |
3205 | // in the conditionally compiled sections | |
3206 | // #included from: internal/catch_test_case_info.h | |
3207 | #define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED | |
3208 | ||
3209 | #include <string> | |
3210 | #include <set> | |
3211 | ||
3212 | #ifdef __clang__ | |
3213 | #pragma clang diagnostic push | |
3214 | #pragma clang diagnostic ignored "-Wpadded" | |
3215 | #endif | |
3216 | ||
3217 | namespace Catch { | |
3218 | ||
3219 | struct ITestCase; | |
3220 | ||
3221 | struct TestCaseInfo { | |
3222 | enum SpecialProperties{ | |
3223 | None = 0, | |
3224 | IsHidden = 1 << 1, | |
3225 | ShouldFail = 1 << 2, | |
3226 | MayFail = 1 << 3, | |
3227 | Throws = 1 << 4, | |
3228 | NonPortable = 1 << 5 | |
3229 | }; | |
3230 | ||
3231 | TestCaseInfo( std::string const& _name, | |
3232 | std::string const& _className, | |
3233 | std::string const& _description, | |
3234 | std::set<std::string> const& _tags, | |
3235 | SourceLineInfo const& _lineInfo ); | |
3236 | ||
3237 | TestCaseInfo( TestCaseInfo const& other ); | |
3238 | ||
3239 | friend void setTags( TestCaseInfo& testCaseInfo, std::set<std::string> const& tags ); | |
3240 | ||
3241 | bool isHidden() const; | |
3242 | bool throws() const; | |
3243 | bool okToFail() const; | |
3244 | bool expectedToFail() const; | |
3245 | ||
3246 | std::string name; | |
3247 | std::string className; | |
3248 | std::string description; | |
3249 | std::set<std::string> tags; | |
3250 | std::set<std::string> lcaseTags; | |
3251 | std::string tagsAsString; | |
3252 | SourceLineInfo lineInfo; | |
3253 | SpecialProperties properties; | |
3254 | }; | |
3255 | ||
3256 | class TestCase : public TestCaseInfo { | |
3257 | public: | |
3258 | ||
3259 | TestCase( ITestCase* testCase, TestCaseInfo const& info ); | |
3260 | TestCase( TestCase const& other ); | |
3261 | ||
3262 | TestCase withName( std::string const& _newName ) const; | |
3263 | ||
3264 | void invoke() const; | |
3265 | ||
3266 | TestCaseInfo const& getTestCaseInfo() const; | |
3267 | ||
3268 | void swap( TestCase& other ); | |
3269 | bool operator == ( TestCase const& other ) const; | |
3270 | bool operator < ( TestCase const& other ) const; | |
3271 | TestCase& operator = ( TestCase const& other ); | |
3272 | ||
3273 | private: | |
3274 | Ptr<ITestCase> test; | |
3275 | }; | |
3276 | ||
3277 | TestCase makeTestCase( ITestCase* testCase, | |
3278 | std::string const& className, | |
3279 | std::string const& name, | |
3280 | std::string const& description, | |
3281 | SourceLineInfo const& lineInfo ); | |
3282 | } | |
3283 | ||
3284 | #ifdef __clang__ | |
3285 | #pragma clang diagnostic pop | |
3286 | #endif | |
3287 | ||
3288 | ||
3289 | #ifdef __OBJC__ | |
3290 | // #included from: internal/catch_objc.hpp | |
3291 | #define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED | |
3292 | ||
3293 | #import <objc/runtime.h> | |
3294 | ||
3295 | #include <string> | |
3296 | ||
3297 | // NB. Any general catch headers included here must be included | |
3298 | // in catch.hpp first to make sure they are included by the single | |
3299 | // header for non obj-usage | |
3300 | ||
3301 | /////////////////////////////////////////////////////////////////////////////// | |
3302 | // This protocol is really only here for (self) documenting purposes, since | |
3303 | // all its methods are optional. | |
3304 | @protocol OcFixture | |
3305 | ||
3306 | @optional | |
3307 | ||
3308 | -(void) setUp; | |
3309 | -(void) tearDown; | |
3310 | ||
3311 | @end | |
3312 | ||
3313 | namespace Catch { | |
3314 | ||
3315 | class OcMethod : public SharedImpl<ITestCase> { | |
3316 | ||
3317 | public: | |
3318 | OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {} | |
3319 | ||
3320 | virtual void invoke() const { | |
3321 | id obj = [[m_cls alloc] init]; | |
3322 | ||
3323 | performOptionalSelector( obj, @selector(setUp) ); | |
3324 | performOptionalSelector( obj, m_sel ); | |
3325 | performOptionalSelector( obj, @selector(tearDown) ); | |
3326 | ||
3327 | arcSafeRelease( obj ); | |
3328 | } | |
3329 | private: | |
3330 | virtual ~OcMethod() {} | |
3331 | ||
3332 | Class m_cls; | |
3333 | SEL m_sel; | |
3334 | }; | |
3335 | ||
3336 | namespace Detail{ | |
3337 | ||
3338 | inline std::string getAnnotation( Class cls, | |
3339 | std::string const& annotationName, | |
3340 | std::string const& testCaseName ) { | |
3341 | NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()]; | |
3342 | SEL sel = NSSelectorFromString( selStr ); | |
3343 | arcSafeRelease( selStr ); | |
3344 | id value = performOptionalSelector( cls, sel ); | |
3345 | if( value ) | |
3346 | return [(NSString*)value UTF8String]; | |
3347 | return ""; | |
3348 | } | |
3349 | } | |
3350 | ||
3351 | inline size_t registerTestMethods() { | |
3352 | size_t noTestMethods = 0; | |
3353 | int noClasses = objc_getClassList( CATCH_NULL, 0 ); | |
3354 | ||
3355 | Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); | |
3356 | objc_getClassList( classes, noClasses ); | |
3357 | ||
3358 | for( int c = 0; c < noClasses; c++ ) { | |
3359 | Class cls = classes[c]; | |
3360 | { | |
3361 | u_int count; | |
3362 | Method* methods = class_copyMethodList( cls, &count ); | |
3363 | for( u_int m = 0; m < count ; m++ ) { | |
3364 | SEL selector = method_getName(methods[m]); | |
3365 | std::string methodName = sel_getName(selector); | |
3366 | if( startsWith( methodName, "Catch_TestCase_" ) ) { | |
3367 | std::string testCaseName = methodName.substr( 15 ); | |
3368 | std::string name = Detail::getAnnotation( cls, "Name", testCaseName ); | |
3369 | std::string desc = Detail::getAnnotation( cls, "Description", testCaseName ); | |
3370 | const char* className = class_getName( cls ); | |
3371 | ||
3372 | getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo() ) ); | |
3373 | noTestMethods++; | |
3374 | } | |
3375 | } | |
3376 | free(methods); | |
3377 | } | |
3378 | } | |
3379 | return noTestMethods; | |
3380 | } | |
3381 | ||
3382 | namespace Matchers { | |
3383 | namespace Impl { | |
3384 | namespace NSStringMatchers { | |
3385 | ||
3386 | struct StringHolder : MatcherBase<NSString*>{ | |
3387 | StringHolder( NSString* substr ) : m_substr( [substr copy] ){} | |
3388 | StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){} | |
3389 | StringHolder() { | |
3390 | arcSafeRelease( m_substr ); | |
3391 | } | |
3392 | ||
3393 | virtual bool match( NSString* arg ) const CATCH_OVERRIDE { | |
3394 | return false; | |
3395 | } | |
3396 | ||
3397 | NSString* m_substr; | |
3398 | }; | |
3399 | ||
3400 | struct Equals : StringHolder { | |
3401 | Equals( NSString* substr ) : StringHolder( substr ){} | |
3402 | ||
3403 | virtual bool match( NSString* str ) const CATCH_OVERRIDE { | |
3404 | return (str != nil || m_substr == nil ) && | |
3405 | [str isEqualToString:m_substr]; | |
3406 | } | |
3407 | ||
3408 | virtual std::string describe() const CATCH_OVERRIDE { | |
3409 | return "equals string: " + Catch::toString( m_substr ); | |
3410 | } | |
3411 | }; | |
3412 | ||
3413 | struct Contains : StringHolder { | |
3414 | Contains( NSString* substr ) : StringHolder( substr ){} | |
3415 | ||
3416 | virtual bool match( NSString* str ) const { | |
3417 | return (str != nil || m_substr == nil ) && | |
3418 | [str rangeOfString:m_substr].location != NSNotFound; | |
3419 | } | |
3420 | ||
3421 | virtual std::string describe() const CATCH_OVERRIDE { | |
3422 | return "contains string: " + Catch::toString( m_substr ); | |
3423 | } | |
3424 | }; | |
3425 | ||
3426 | struct StartsWith : StringHolder { | |
3427 | StartsWith( NSString* substr ) : StringHolder( substr ){} | |
3428 | ||
3429 | virtual bool match( NSString* str ) const { | |
3430 | return (str != nil || m_substr == nil ) && | |
3431 | [str rangeOfString:m_substr].location == 0; | |
3432 | } | |
3433 | ||
3434 | virtual std::string describe() const CATCH_OVERRIDE { | |
3435 | return "starts with: " + Catch::toString( m_substr ); | |
3436 | } | |
3437 | }; | |
3438 | struct EndsWith : StringHolder { | |
3439 | EndsWith( NSString* substr ) : StringHolder( substr ){} | |
3440 | ||
3441 | virtual bool match( NSString* str ) const { | |
3442 | return (str != nil || m_substr == nil ) && | |
3443 | [str rangeOfString:m_substr].location == [str length] - [m_substr length]; | |
3444 | } | |
3445 | ||
3446 | virtual std::string describe() const CATCH_OVERRIDE { | |
3447 | return "ends with: " + Catch::toString( m_substr ); | |
3448 | } | |
3449 | }; | |
3450 | ||
3451 | } // namespace NSStringMatchers | |
3452 | } // namespace Impl | |
3453 | ||
3454 | inline Impl::NSStringMatchers::Equals | |
3455 | Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); } | |
3456 | ||
3457 | inline Impl::NSStringMatchers::Contains | |
3458 | Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); } | |
3459 | ||
3460 | inline Impl::NSStringMatchers::StartsWith | |
3461 | StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); } | |
3462 | ||
3463 | inline Impl::NSStringMatchers::EndsWith | |
3464 | EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); } | |
3465 | ||
3466 | } // namespace Matchers | |
3467 | ||
3468 | using namespace Matchers; | |
3469 | ||
3470 | } // namespace Catch | |
3471 | ||
3472 | /////////////////////////////////////////////////////////////////////////////// | |
3473 | #define OC_TEST_CASE( name, desc )\ | |
3474 | +(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \ | |
3475 | {\ | |
3476 | return @ name; \ | |
3477 | }\ | |
3478 | +(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \ | |
3479 | { \ | |
3480 | return @ desc; \ | |
3481 | } \ | |
3482 | -(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test ) | |
3483 | ||
3484 | #endif | |
3485 | ||
3486 | #ifdef CATCH_IMPL | |
3487 | ||
3488 | // !TBD: Move the leak detector code into a separate header | |
3489 | #ifdef CATCH_CONFIG_WINDOWS_CRTDBG | |
3490 | #include <crtdbg.h> | |
3491 | class LeakDetector { | |
3492 | public: | |
3493 | LeakDetector() { | |
3494 | int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); | |
3495 | flag |= _CRTDBG_LEAK_CHECK_DF; | |
3496 | flag |= _CRTDBG_ALLOC_MEM_DF; | |
3497 | _CrtSetDbgFlag(flag); | |
3498 | _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); | |
3499 | _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); | |
3500 | // Change this to leaking allocation's number to break there | |
3501 | _CrtSetBreakAlloc(-1); | |
3502 | } | |
3503 | }; | |
3504 | #else | |
3505 | class LeakDetector {}; | |
3506 | #endif | |
3507 | ||
3508 | LeakDetector leakDetector; | |
3509 | ||
3510 | // #included from: internal/catch_impl.hpp | |
3511 | #define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED | |
3512 | ||
3513 | // Collect all the implementation files together here | |
3514 | // These are the equivalent of what would usually be cpp files | |
3515 | ||
3516 | #ifdef __clang__ | |
3517 | #pragma clang diagnostic push | |
3518 | #pragma clang diagnostic ignored "-Wweak-vtables" | |
3519 | #endif | |
3520 | ||
3521 | // #included from: ../catch_session.hpp | |
3522 | #define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED | |
3523 | ||
3524 | // #included from: internal/catch_commandline.hpp | |
3525 | #define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED | |
3526 | ||
3527 | // #included from: catch_config.hpp | |
3528 | #define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED | |
3529 | ||
3530 | // #included from: catch_test_spec_parser.hpp | |
3531 | #define TWOBLUECUBES_CATCH_TEST_SPEC_PARSER_HPP_INCLUDED | |
3532 | ||
3533 | #ifdef __clang__ | |
3534 | #pragma clang diagnostic push | |
3535 | #pragma clang diagnostic ignored "-Wpadded" | |
3536 | #endif | |
3537 | ||
3538 | // #included from: catch_test_spec.hpp | |
3539 | #define TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED | |
3540 | ||
3541 | #ifdef __clang__ | |
3542 | #pragma clang diagnostic push | |
3543 | #pragma clang diagnostic ignored "-Wpadded" | |
3544 | #endif | |
3545 | ||
3546 | // #included from: catch_wildcard_pattern.hpp | |
3547 | #define TWOBLUECUBES_CATCH_WILDCARD_PATTERN_HPP_INCLUDED | |
3548 | ||
3549 | #include <stdexcept> | |
3550 | ||
3551 | namespace Catch | |
3552 | { | |
3553 | class WildcardPattern { | |
3554 | enum WildcardPosition { | |
3555 | NoWildcard = 0, | |
3556 | WildcardAtStart = 1, | |
3557 | WildcardAtEnd = 2, | |
3558 | WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd | |
3559 | }; | |
3560 | ||
3561 | public: | |
3562 | ||
3563 | WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity ) | |
3564 | : m_caseSensitivity( caseSensitivity ), | |
3565 | m_wildcard( NoWildcard ), | |
3566 | m_pattern( adjustCase( pattern ) ) | |
3567 | { | |
3568 | if( startsWith( m_pattern, '*' ) ) { | |
3569 | m_pattern = m_pattern.substr( 1 ); | |
3570 | m_wildcard = WildcardAtStart; | |
3571 | } | |
3572 | if( endsWith( m_pattern, '*' ) ) { | |
3573 | m_pattern = m_pattern.substr( 0, m_pattern.size()-1 ); | |
3574 | m_wildcard = static_cast<WildcardPosition>( m_wildcard | WildcardAtEnd ); | |
3575 | } | |
3576 | } | |
3577 | virtual ~WildcardPattern(); | |
3578 | virtual bool matches( std::string const& str ) const { | |
3579 | switch( m_wildcard ) { | |
3580 | case NoWildcard: | |
3581 | return m_pattern == adjustCase( str ); | |
3582 | case WildcardAtStart: | |
3583 | return endsWith( adjustCase( str ), m_pattern ); | |
3584 | case WildcardAtEnd: | |
3585 | return startsWith( adjustCase( str ), m_pattern ); | |
3586 | case WildcardAtBothEnds: | |
3587 | return contains( adjustCase( str ), m_pattern ); | |
3588 | } | |
3589 | ||
3590 | #ifdef __clang__ | |
3591 | #pragma clang diagnostic push | |
3592 | #pragma clang diagnostic ignored "-Wunreachable-code" | |
3593 | #endif | |
3594 | throw std::logic_error( "Unknown enum" ); | |
3595 | #ifdef __clang__ | |
3596 | #pragma clang diagnostic pop | |
3597 | #endif | |
3598 | } | |
3599 | private: | |
3600 | std::string adjustCase( std::string const& str ) const { | |
3601 | return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str; | |
3602 | } | |
3603 | CaseSensitive::Choice m_caseSensitivity; | |
3604 | WildcardPosition m_wildcard; | |
3605 | std::string m_pattern; | |
3606 | }; | |
3607 | } | |
3608 | ||
3609 | #include <string> | |
3610 | #include <vector> | |
3611 | ||
3612 | namespace Catch { | |
3613 | ||
3614 | class TestSpec { | |
3615 | struct Pattern : SharedImpl<> { | |
3616 | virtual ~Pattern(); | |
3617 | virtual bool matches( TestCaseInfo const& testCase ) const = 0; | |
3618 | }; | |
3619 | class NamePattern : public Pattern { | |
3620 | public: | |
3621 | NamePattern( std::string const& name ) | |
3622 | : m_wildcardPattern( toLower( name ), CaseSensitive::No ) | |
3623 | {} | |
3624 | virtual ~NamePattern(); | |
3625 | virtual bool matches( TestCaseInfo const& testCase ) const { | |
3626 | return m_wildcardPattern.matches( toLower( testCase.name ) ); | |
3627 | } | |
3628 | private: | |
3629 | WildcardPattern m_wildcardPattern; | |
3630 | }; | |
3631 | ||
3632 | class TagPattern : public Pattern { | |
3633 | public: | |
3634 | TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} | |
3635 | virtual ~TagPattern(); | |
3636 | virtual bool matches( TestCaseInfo const& testCase ) const { | |
3637 | return testCase.lcaseTags.find( m_tag ) != testCase.lcaseTags.end(); | |
3638 | } | |
3639 | private: | |
3640 | std::string m_tag; | |
3641 | }; | |
3642 | ||
3643 | class ExcludedPattern : public Pattern { | |
3644 | public: | |
3645 | ExcludedPattern( Ptr<Pattern> const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} | |
3646 | virtual ~ExcludedPattern(); | |
3647 | virtual bool matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); } | |
3648 | private: | |
3649 | Ptr<Pattern> m_underlyingPattern; | |
3650 | }; | |
3651 | ||
3652 | struct Filter { | |
3653 | std::vector<Ptr<Pattern> > m_patterns; | |
3654 | ||
3655 | bool matches( TestCaseInfo const& testCase ) const { | |
3656 | // All patterns in a filter must match for the filter to be a match | |
3657 | for( std::vector<Ptr<Pattern> >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) { | |
3658 | if( !(*it)->matches( testCase ) ) | |
3659 | return false; | |
3660 | } | |
3661 | return true; | |
3662 | } | |
3663 | }; | |
3664 | ||
3665 | public: | |
3666 | bool hasFilters() const { | |
3667 | return !m_filters.empty(); | |
3668 | } | |
3669 | bool matches( TestCaseInfo const& testCase ) const { | |
3670 | // A TestSpec matches if any filter matches | |
3671 | for( std::vector<Filter>::const_iterator it = m_filters.begin(), itEnd = m_filters.end(); it != itEnd; ++it ) | |
3672 | if( it->matches( testCase ) ) | |
3673 | return true; | |
3674 | return false; | |
3675 | } | |
3676 | ||
3677 | private: | |
3678 | std::vector<Filter> m_filters; | |
3679 | ||
3680 | friend class TestSpecParser; | |
3681 | }; | |
3682 | } | |
3683 | ||
3684 | #ifdef __clang__ | |
3685 | #pragma clang diagnostic pop | |
3686 | #endif | |
3687 | ||
3688 | namespace Catch { | |
3689 | ||
3690 | class TestSpecParser { | |
3691 | enum Mode{ None, Name, QuotedName, Tag, EscapedName }; | |
3692 | Mode m_mode; | |
3693 | bool m_exclusion; | |
3694 | std::size_t m_start, m_pos; | |
3695 | std::string m_arg; | |
3696 | std::vector<std::size_t> m_escapeChars; | |
3697 | TestSpec::Filter m_currentFilter; | |
3698 | TestSpec m_testSpec; | |
3699 | ITagAliasRegistry const* m_tagAliases; | |
3700 | ||
3701 | public: | |
3702 | TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {} | |
3703 | ||
3704 | TestSpecParser& parse( std::string const& arg ) { | |
3705 | m_mode = None; | |
3706 | m_exclusion = false; | |
3707 | m_start = std::string::npos; | |
3708 | m_arg = m_tagAliases->expandAliases( arg ); | |
3709 | m_escapeChars.clear(); | |
3710 | for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) | |
3711 | visitChar( m_arg[m_pos] ); | |
3712 | if( m_mode == Name ) | |
3713 | addPattern<TestSpec::NamePattern>(); | |
3714 | return *this; | |
3715 | } | |
3716 | TestSpec testSpec() { | |
3717 | addFilter(); | |
3718 | return m_testSpec; | |
3719 | } | |
3720 | private: | |
3721 | void visitChar( char c ) { | |
3722 | if( m_mode == None ) { | |
3723 | switch( c ) { | |
3724 | case ' ': return; | |
3725 | case '~': m_exclusion = true; return; | |
3726 | case '[': return startNewMode( Tag, ++m_pos ); | |
3727 | case '"': return startNewMode( QuotedName, ++m_pos ); | |
3728 | case '\\': return escape(); | |
3729 | default: startNewMode( Name, m_pos ); break; | |
3730 | } | |
3731 | } | |
3732 | if( m_mode == Name ) { | |
3733 | if( c == ',' ) { | |
3734 | addPattern<TestSpec::NamePattern>(); | |
3735 | addFilter(); | |
3736 | } | |
3737 | else if( c == '[' ) { | |
3738 | if( subString() == "exclude:" ) | |
3739 | m_exclusion = true; | |
3740 | else | |
3741 | addPattern<TestSpec::NamePattern>(); | |
3742 | startNewMode( Tag, ++m_pos ); | |
3743 | } | |
3744 | else if( c == '\\' ) | |
3745 | escape(); | |
3746 | } | |
3747 | else if( m_mode == EscapedName ) | |
3748 | m_mode = Name; | |
3749 | else if( m_mode == QuotedName && c == '"' ) | |
3750 | addPattern<TestSpec::NamePattern>(); | |
3751 | else if( m_mode == Tag && c == ']' ) | |
3752 | addPattern<TestSpec::TagPattern>(); | |
3753 | } | |
3754 | void startNewMode( Mode mode, std::size_t start ) { | |
3755 | m_mode = mode; | |
3756 | m_start = start; | |
3757 | } | |
3758 | void escape() { | |
3759 | if( m_mode == None ) | |
3760 | m_start = m_pos; | |
3761 | m_mode = EscapedName; | |
3762 | m_escapeChars.push_back( m_pos ); | |
3763 | } | |
3764 | std::string subString() const { return m_arg.substr( m_start, m_pos - m_start ); } | |
3765 | template<typename T> | |
3766 | void addPattern() { | |
3767 | std::string token = subString(); | |
3768 | for( size_t i = 0; i < m_escapeChars.size(); ++i ) | |
3769 | token = token.substr( 0, m_escapeChars[i]-m_start-i ) + token.substr( m_escapeChars[i]-m_start-i+1 ); | |
3770 | m_escapeChars.clear(); | |
3771 | if( startsWith( token, "exclude:" ) ) { | |
3772 | m_exclusion = true; | |
3773 | token = token.substr( 8 ); | |
3774 | } | |
3775 | if( !token.empty() ) { | |
3776 | Ptr<TestSpec::Pattern> pattern = new T( token ); | |
3777 | if( m_exclusion ) | |
3778 | pattern = new TestSpec::ExcludedPattern( pattern ); | |
3779 | m_currentFilter.m_patterns.push_back( pattern ); | |
3780 | } | |
3781 | m_exclusion = false; | |
3782 | m_mode = None; | |
3783 | } | |
3784 | void addFilter() { | |
3785 | if( !m_currentFilter.m_patterns.empty() ) { | |
3786 | m_testSpec.m_filters.push_back( m_currentFilter ); | |
3787 | m_currentFilter = TestSpec::Filter(); | |
3788 | } | |
3789 | } | |
3790 | }; | |
3791 | inline TestSpec parseTestSpec( std::string const& arg ) { | |
3792 | return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); | |
3793 | } | |
3794 | ||
3795 | } // namespace Catch | |
3796 | ||
3797 | #ifdef __clang__ | |
3798 | #pragma clang diagnostic pop | |
3799 | #endif | |
3800 | ||
3801 | // #included from: catch_interfaces_config.h | |
3802 | #define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED | |
3803 | ||
3804 | #include <iosfwd> | |
3805 | #include <string> | |
3806 | #include <vector> | |
3807 | ||
3808 | namespace Catch { | |
3809 | ||
3810 | struct Verbosity { enum Level { | |
3811 | NoOutput = 0, | |
3812 | Quiet, | |
3813 | Normal | |
3814 | }; }; | |
3815 | ||
3816 | struct WarnAbout { enum What { | |
3817 | Nothing = 0x00, | |
3818 | NoAssertions = 0x01 | |
3819 | }; }; | |
3820 | ||
3821 | struct ShowDurations { enum OrNot { | |
3822 | DefaultForReporter, | |
3823 | Always, | |
3824 | Never | |
3825 | }; }; | |
3826 | struct RunTests { enum InWhatOrder { | |
3827 | InDeclarationOrder, | |
3828 | InLexicographicalOrder, | |
3829 | InRandomOrder | |
3830 | }; }; | |
3831 | struct UseColour { enum YesOrNo { | |
3832 | Auto, | |
3833 | Yes, | |
3834 | No | |
3835 | }; }; | |
3836 | ||
3837 | class TestSpec; | |
3838 | ||
3839 | struct IConfig : IShared { | |
3840 | ||
3841 | virtual ~IConfig(); | |
3842 | ||
3843 | virtual bool allowThrows() const = 0; | |
3844 | virtual std::ostream& stream() const = 0; | |
3845 | virtual std::string name() const = 0; | |
3846 | virtual bool includeSuccessfulResults() const = 0; | |
3847 | virtual bool shouldDebugBreak() const = 0; | |
3848 | virtual bool warnAboutMissingAssertions() const = 0; | |
3849 | virtual int abortAfter() const = 0; | |
3850 | virtual bool showInvisibles() const = 0; | |
3851 | virtual ShowDurations::OrNot showDurations() const = 0; | |
3852 | virtual TestSpec const& testSpec() const = 0; | |
3853 | virtual RunTests::InWhatOrder runOrder() const = 0; | |
3854 | virtual unsigned int rngSeed() const = 0; | |
3855 | virtual UseColour::YesOrNo useColour() const = 0; | |
3856 | virtual std::vector<std::string> const& getSectionsToRun() const = 0; | |
3857 | ||
3858 | }; | |
3859 | } | |
3860 | ||
3861 | // #included from: catch_stream.h | |
3862 | #define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED | |
3863 | ||
3864 | // #included from: catch_streambuf.h | |
3865 | #define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED | |
3866 | ||
3867 | #include <streambuf> | |
3868 | ||
3869 | namespace Catch { | |
3870 | ||
3871 | class StreamBufBase : public std::streambuf { | |
3872 | public: | |
3873 | virtual ~StreamBufBase() CATCH_NOEXCEPT; | |
3874 | }; | |
3875 | } | |
3876 | ||
3877 | #include <streambuf> | |
3878 | #include <ostream> | |
3879 | #include <fstream> | |
3880 | #include <memory> | |
3881 | ||
3882 | namespace Catch { | |
3883 | ||
3884 | std::ostream& cout(); | |
3885 | std::ostream& cerr(); | |
3886 | ||
3887 | struct IStream { | |
3888 | virtual ~IStream() CATCH_NOEXCEPT; | |
3889 | virtual std::ostream& stream() const = 0; | |
3890 | }; | |
3891 | ||
3892 | class FileStream : public IStream { | |
3893 | mutable std::ofstream m_ofs; | |
3894 | public: | |
3895 | FileStream( std::string const& filename ); | |
3896 | virtual ~FileStream() CATCH_NOEXCEPT; | |
3897 | public: // IStream | |
3898 | virtual std::ostream& stream() const CATCH_OVERRIDE; | |
3899 | }; | |
3900 | ||
3901 | class CoutStream : public IStream { | |
3902 | mutable std::ostream m_os; | |
3903 | public: | |
3904 | CoutStream(); | |
3905 | virtual ~CoutStream() CATCH_NOEXCEPT; | |
3906 | ||
3907 | public: // IStream | |
3908 | virtual std::ostream& stream() const CATCH_OVERRIDE; | |
3909 | }; | |
3910 | ||
3911 | class DebugOutStream : public IStream { | |
3912 | CATCH_AUTO_PTR( StreamBufBase ) m_streamBuf; | |
3913 | mutable std::ostream m_os; | |
3914 | public: | |
3915 | DebugOutStream(); | |
3916 | virtual ~DebugOutStream() CATCH_NOEXCEPT; | |
3917 | ||
3918 | public: // IStream | |
3919 | virtual std::ostream& stream() const CATCH_OVERRIDE; | |
3920 | }; | |
3921 | } | |
3922 | ||
3923 | #include <memory> | |
3924 | #include <vector> | |
3925 | #include <string> | |
3926 | #include <stdexcept> | |
3927 | ||
3928 | #ifndef CATCH_CONFIG_CONSOLE_WIDTH | |
3929 | #define CATCH_CONFIG_CONSOLE_WIDTH 80 | |
3930 | #endif | |
3931 | ||
3932 | namespace Catch { | |
3933 | ||
3934 | struct ConfigData { | |
3935 | ||
3936 | ConfigData() | |
3937 | : listTests( false ), | |
3938 | listTags( false ), | |
3939 | listReporters( false ), | |
3940 | listTestNamesOnly( false ), | |
3941 | showSuccessfulTests( false ), | |
3942 | shouldDebugBreak( false ), | |
3943 | noThrow( false ), | |
3944 | showHelp( false ), | |
3945 | showInvisibles( false ), | |
3946 | filenamesAsTags( false ), | |
3947 | abortAfter( -1 ), | |
3948 | rngSeed( 0 ), | |
3949 | verbosity( Verbosity::Normal ), | |
3950 | warnings( WarnAbout::Nothing ), | |
3951 | showDurations( ShowDurations::DefaultForReporter ), | |
3952 | runOrder( RunTests::InDeclarationOrder ), | |
3953 | useColour( UseColour::Auto ) | |
3954 | {} | |
3955 | ||
3956 | bool listTests; | |
3957 | bool listTags; | |
3958 | bool listReporters; | |
3959 | bool listTestNamesOnly; | |
3960 | ||
3961 | bool showSuccessfulTests; | |
3962 | bool shouldDebugBreak; | |
3963 | bool noThrow; | |
3964 | bool showHelp; | |
3965 | bool showInvisibles; | |
3966 | bool filenamesAsTags; | |
3967 | ||
3968 | int abortAfter; | |
3969 | unsigned int rngSeed; | |
3970 | ||
3971 | Verbosity::Level verbosity; | |
3972 | WarnAbout::What warnings; | |
3973 | ShowDurations::OrNot showDurations; | |
3974 | RunTests::InWhatOrder runOrder; | |
3975 | UseColour::YesOrNo useColour; | |
3976 | ||
3977 | std::string outputFilename; | |
3978 | std::string name; | |
3979 | std::string processName; | |
3980 | ||
3981 | std::vector<std::string> reporterNames; | |
3982 | std::vector<std::string> testsOrTags; | |
3983 | std::vector<std::string> sectionsToRun; | |
3984 | }; | |
3985 | ||
3986 | class Config : public SharedImpl<IConfig> { | |
3987 | private: | |
3988 | Config( Config const& other ); | |
3989 | Config& operator = ( Config const& other ); | |
3990 | virtual void dummy(); | |
3991 | public: | |
3992 | ||
3993 | Config() | |
3994 | {} | |
3995 | ||
3996 | Config( ConfigData const& data ) | |
3997 | : m_data( data ), | |
3998 | m_stream( openStream() ) | |
3999 | { | |
4000 | if( !data.testsOrTags.empty() ) { | |
4001 | TestSpecParser parser( ITagAliasRegistry::get() ); | |
4002 | for( std::size_t i = 0; i < data.testsOrTags.size(); ++i ) | |
4003 | parser.parse( data.testsOrTags[i] ); | |
4004 | m_testSpec = parser.testSpec(); | |
4005 | } | |
4006 | } | |
4007 | ||
4008 | virtual ~Config() {} | |
4009 | ||
4010 | std::string const& getFilename() const { | |
4011 | return m_data.outputFilename ; | |
4012 | } | |
4013 | ||
4014 | bool listTests() const { return m_data.listTests; } | |
4015 | bool listTestNamesOnly() const { return m_data.listTestNamesOnly; } | |
4016 | bool listTags() const { return m_data.listTags; } | |
4017 | bool listReporters() const { return m_data.listReporters; } | |
4018 | ||
4019 | std::string getProcessName() const { return m_data.processName; } | |
4020 | ||
4021 | std::vector<std::string> const& getReporterNames() const { return m_data.reporterNames; } | |
4022 | std::vector<std::string> const& getSectionsToRun() const CATCH_OVERRIDE { return m_data.sectionsToRun; } | |
4023 | ||
4024 | virtual TestSpec const& testSpec() const CATCH_OVERRIDE { return m_testSpec; } | |
4025 | ||
4026 | bool showHelp() const { return m_data.showHelp; } | |
4027 | ||
4028 | // IConfig interface | |
4029 | virtual bool allowThrows() const CATCH_OVERRIDE { return !m_data.noThrow; } | |
4030 | virtual std::ostream& stream() const CATCH_OVERRIDE { return m_stream->stream(); } | |
4031 | virtual std::string name() const CATCH_OVERRIDE { return m_data.name.empty() ? m_data.processName : m_data.name; } | |
4032 | virtual bool includeSuccessfulResults() const CATCH_OVERRIDE { return m_data.showSuccessfulTests; } | |
4033 | virtual bool warnAboutMissingAssertions() const CATCH_OVERRIDE { return m_data.warnings & WarnAbout::NoAssertions; } | |
4034 | virtual ShowDurations::OrNot showDurations() const CATCH_OVERRIDE { return m_data.showDurations; } | |
4035 | virtual RunTests::InWhatOrder runOrder() const CATCH_OVERRIDE { return m_data.runOrder; } | |
4036 | virtual unsigned int rngSeed() const CATCH_OVERRIDE { return m_data.rngSeed; } | |
4037 | virtual UseColour::YesOrNo useColour() const CATCH_OVERRIDE { return m_data.useColour; } | |
4038 | virtual bool shouldDebugBreak() const CATCH_OVERRIDE { return m_data.shouldDebugBreak; } | |
4039 | virtual int abortAfter() const CATCH_OVERRIDE { return m_data.abortAfter; } | |
4040 | virtual bool showInvisibles() const CATCH_OVERRIDE { return m_data.showInvisibles; } | |
4041 | ||
4042 | private: | |
4043 | ||
4044 | IStream const* openStream() { | |
4045 | if( m_data.outputFilename.empty() ) | |
4046 | return new CoutStream(); | |
4047 | else if( m_data.outputFilename[0] == '%' ) { | |
4048 | if( m_data.outputFilename == "%debug" ) | |
4049 | return new DebugOutStream(); | |
4050 | else | |
4051 | throw std::domain_error( "Unrecognised stream: " + m_data.outputFilename ); | |
4052 | } | |
4053 | else | |
4054 | return new FileStream( m_data.outputFilename ); | |
4055 | } | |
4056 | ConfigData m_data; | |
4057 | ||
4058 | CATCH_AUTO_PTR( IStream const ) m_stream; | |
4059 | TestSpec m_testSpec; | |
4060 | }; | |
4061 | ||
4062 | } // end namespace Catch | |
4063 | ||
4064 | // #included from: catch_clara.h | |
4065 | #define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED | |
4066 | ||
4067 | // Use Catch's value for console width (store Clara's off to the side, if present) | |
4068 | #ifdef CLARA_CONFIG_CONSOLE_WIDTH | |
4069 | #define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH | |
4070 | #undef CLARA_CONFIG_CONSOLE_WIDTH | |
4071 | #endif | |
4072 | #define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH | |
4073 | ||
4074 | // Declare Clara inside the Catch namespace | |
4075 | #define STITCH_CLARA_OPEN_NAMESPACE namespace Catch { | |
4076 | // #included from: ../external/clara.h | |
4077 | ||
4078 | // Version 0.0.2.4 | |
4079 | ||
4080 | // Only use header guard if we are not using an outer namespace | |
4081 | #if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE) | |
4082 | ||
4083 | #ifndef STITCH_CLARA_OPEN_NAMESPACE | |
4084 | #define TWOBLUECUBES_CLARA_H_INCLUDED | |
4085 | #define STITCH_CLARA_OPEN_NAMESPACE | |
4086 | #define STITCH_CLARA_CLOSE_NAMESPACE | |
4087 | #else | |
4088 | #define STITCH_CLARA_CLOSE_NAMESPACE } | |
4089 | #endif | |
4090 | ||
4091 | #define STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE | |
4092 | ||
4093 | // ----------- #included from tbc_text_format.h ----------- | |
4094 | ||
4095 | // Only use header guard if we are not using an outer namespace | |
4096 | #if !defined(TBC_TEXT_FORMAT_H_INCLUDED) || defined(STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE) | |
4097 | #ifndef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE | |
4098 | #define TBC_TEXT_FORMAT_H_INCLUDED | |
4099 | #endif | |
4100 | ||
4101 | #include <string> | |
4102 | #include <vector> | |
4103 | #include <sstream> | |
4104 | #include <algorithm> | |
4105 | #include <cctype> | |
4106 | ||
4107 | // Use optional outer namespace | |
4108 | #ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE | |
4109 | namespace STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE { | |
4110 | #endif | |
4111 | ||
4112 | namespace Tbc { | |
4113 | ||
4114 | #ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH | |
4115 | const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; | |
4116 | #else | |
4117 | const unsigned int consoleWidth = 80; | |
4118 | #endif | |
4119 | ||
4120 | struct TextAttributes { | |
4121 | TextAttributes() | |
4122 | : initialIndent( std::string::npos ), | |
4123 | indent( 0 ), | |
4124 | width( consoleWidth-1 ), | |
4125 | tabChar( '\t' ) | |
4126 | {} | |
4127 | ||
4128 | TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } | |
4129 | TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } | |
4130 | TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } | |
4131 | TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } | |
4132 | ||
4133 | std::size_t initialIndent; // indent of first line, or npos | |
4134 | std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos | |
4135 | std::size_t width; // maximum width of text, including indent. Longer text will wrap | |
4136 | char tabChar; // If this char is seen the indent is changed to current pos | |
4137 | }; | |
4138 | ||
4139 | class Text { | |
4140 | public: | |
4141 | Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) | |
4142 | : attr( _attr ) | |
4143 | { | |
4144 | std::string wrappableChars = " [({.,/|\\-"; | |
4145 | std::size_t indent = _attr.initialIndent != std::string::npos | |
4146 | ? _attr.initialIndent | |
4147 | : _attr.indent; | |
4148 | std::string remainder = _str; | |
4149 | ||
4150 | while( !remainder.empty() ) { | |
4151 | if( lines.size() >= 1000 ) { | |
4152 | lines.push_back( "... message truncated due to excessive size" ); | |
4153 | return; | |
4154 | } | |
4155 | std::size_t tabPos = std::string::npos; | |
4156 | std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); | |
4157 | std::size_t pos = remainder.find_first_of( '\n' ); | |
4158 | if( pos <= width ) { | |
4159 | width = pos; | |
4160 | } | |
4161 | pos = remainder.find_last_of( _attr.tabChar, width ); | |
4162 | if( pos != std::string::npos ) { | |
4163 | tabPos = pos; | |
4164 | if( remainder[width] == '\n' ) | |
4165 | width--; | |
4166 | remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); | |
4167 | } | |
4168 | ||
4169 | if( width == remainder.size() ) { | |
4170 | spliceLine( indent, remainder, width ); | |
4171 | } | |
4172 | else if( remainder[width] == '\n' ) { | |
4173 | spliceLine( indent, remainder, width ); | |
4174 | if( width <= 1 || remainder.size() != 1 ) | |
4175 | remainder = remainder.substr( 1 ); | |
4176 | indent = _attr.indent; | |
4177 | } | |
4178 | else { | |
4179 | pos = remainder.find_last_of( wrappableChars, width ); | |
4180 | if( pos != std::string::npos && pos > 0 ) { | |
4181 | spliceLine( indent, remainder, pos ); | |
4182 | if( remainder[0] == ' ' ) | |
4183 | remainder = remainder.substr( 1 ); | |
4184 | } | |
4185 | else { | |
4186 | spliceLine( indent, remainder, width-1 ); | |
4187 | lines.back() += "-"; | |
4188 | } | |
4189 | if( lines.size() == 1 ) | |
4190 | indent = _attr.indent; | |
4191 | if( tabPos != std::string::npos ) | |
4192 | indent += tabPos; | |
4193 | } | |
4194 | } | |
4195 | } | |
4196 | ||
4197 | void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { | |
4198 | lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); | |
4199 | _remainder = _remainder.substr( _pos ); | |
4200 | } | |
4201 | ||
4202 | typedef std::vector<std::string>::const_iterator const_iterator; | |
4203 | ||
4204 | const_iterator begin() const { return lines.begin(); } | |
4205 | const_iterator end() const { return lines.end(); } | |
4206 | std::string const& last() const { return lines.back(); } | |
4207 | std::size_t size() const { return lines.size(); } | |
4208 | std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } | |
4209 | std::string toString() const { | |
4210 | std::ostringstream oss; | |
4211 | oss << *this; | |
4212 | return oss.str(); | |
4213 | } | |
4214 | ||
4215 | inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { | |
4216 | for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); | |
4217 | it != itEnd; ++it ) { | |
4218 | if( it != _text.begin() ) | |
4219 | _stream << "\n"; | |
4220 | _stream << *it; | |
4221 | } | |
4222 | return _stream; | |
4223 | } | |
4224 | ||
4225 | private: | |
4226 | std::string str; | |
4227 | TextAttributes attr; | |
4228 | std::vector<std::string> lines; | |
4229 | }; | |
4230 | ||
4231 | } // end namespace Tbc | |
4232 | ||
4233 | #ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE | |
4234 | } // end outer namespace | |
4235 | #endif | |
4236 | ||
4237 | #endif // TBC_TEXT_FORMAT_H_INCLUDED | |
4238 | ||
4239 | // ----------- end of #include from tbc_text_format.h ----------- | |
4240 | // ........... back in clara.h | |
4241 | ||
4242 | #undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE | |
4243 | ||
4244 | // ----------- #included from clara_compilers.h ----------- | |
4245 | ||
4246 | #ifndef TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED | |
4247 | #define TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED | |
4248 | ||
4249 | // Detect a number of compiler features - mostly C++11/14 conformance - by compiler | |
4250 | // The following features are defined: | |
4251 | // | |
4252 | // CLARA_CONFIG_CPP11_NULLPTR : is nullptr supported? | |
4253 | // CLARA_CONFIG_CPP11_NOEXCEPT : is noexcept supported? | |
4254 | // CLARA_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods | |
4255 | // CLARA_CONFIG_CPP11_OVERRIDE : is override supported? | |
4256 | // CLARA_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr) | |
4257 | ||
4258 | // CLARA_CONFIG_CPP11_OR_GREATER : Is C++11 supported? | |
4259 | ||
4260 | // CLARA_CONFIG_VARIADIC_MACROS : are variadic macros supported? | |
4261 | ||
4262 | // In general each macro has a _NO_<feature name> form | |
4263 | // (e.g. CLARA_CONFIG_CPP11_NO_NULLPTR) which disables the feature. | |
4264 | // Many features, at point of detection, define an _INTERNAL_ macro, so they | |
4265 | // can be combined, en-mass, with the _NO_ forms later. | |
4266 | ||
4267 | // All the C++11 features can be disabled with CLARA_CONFIG_NO_CPP11 | |
4268 | ||
4269 | #ifdef __clang__ | |
4270 | ||
4271 | #if __has_feature(cxx_nullptr) | |
4272 | #define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR | |
4273 | #endif | |
4274 | ||
4275 | #if __has_feature(cxx_noexcept) | |
4276 | #define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT | |
4277 | #endif | |
4278 | ||
4279 | #endif // __clang__ | |
4280 | ||
4281 | //////////////////////////////////////////////////////////////////////////////// | |
4282 | // GCC | |
4283 | #ifdef __GNUC__ | |
4284 | ||
4285 | #if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) | |
4286 | #define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR | |
4287 | #endif | |
4288 | ||
4289 | // - otherwise more recent versions define __cplusplus >= 201103L | |
4290 | // and will get picked up below | |
4291 | ||
4292 | #endif // __GNUC__ | |
4293 | ||
4294 | //////////////////////////////////////////////////////////////////////////////// | |
4295 | // Visual C++ | |
4296 | #ifdef _MSC_VER | |
4297 | ||
4298 | #if (_MSC_VER >= 1600) | |
4299 | #define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR | |
4300 | #define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR | |
4301 | #endif | |
4302 | ||
4303 | #if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) | |
4304 | #define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT | |
4305 | #define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS | |
4306 | #endif | |
4307 | ||
4308 | #endif // _MSC_VER | |
4309 | ||
4310 | //////////////////////////////////////////////////////////////////////////////// | |
4311 | // C++ language feature support | |
4312 | ||
4313 | // catch all support for C++11 | |
4314 | #if defined(__cplusplus) && __cplusplus >= 201103L | |
4315 | ||
4316 | #define CLARA_CPP11_OR_GREATER | |
4317 | ||
4318 | #if !defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR) | |
4319 | #define CLARA_INTERNAL_CONFIG_CPP11_NULLPTR | |
4320 | #endif | |
4321 | ||
4322 | #ifndef CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT | |
4323 | #define CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT | |
4324 | #endif | |
4325 | ||
4326 | #ifndef CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS | |
4327 | #define CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS | |
4328 | #endif | |
4329 | ||
4330 | #if !defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE) | |
4331 | #define CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE | |
4332 | #endif | |
4333 | #if !defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) | |
4334 | #define CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR | |
4335 | #endif | |
4336 | ||
4337 | #endif // __cplusplus >= 201103L | |
4338 | ||
4339 | // Now set the actual defines based on the above + anything the user has configured | |
4340 | #if defined(CLARA_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NO_NULLPTR) && !defined(CLARA_CONFIG_CPP11_NULLPTR) && !defined(CLARA_CONFIG_NO_CPP11) | |
4341 | #define CLARA_CONFIG_CPP11_NULLPTR | |
4342 | #endif | |
4343 | #if defined(CLARA_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_CONFIG_NO_CPP11) | |
4344 | #define CLARA_CONFIG_CPP11_NOEXCEPT | |
4345 | #endif | |
4346 | #if defined(CLARA_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CLARA_CONFIG_CPP11_GENERATED_METHODS) && !defined(CLARA_CONFIG_NO_CPP11) | |
4347 | #define CLARA_CONFIG_CPP11_GENERATED_METHODS | |
4348 | #endif | |
4349 | #if defined(CLARA_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_OVERRIDE) && !defined(CLARA_CONFIG_CPP11_OVERRIDE) && !defined(CLARA_CONFIG_NO_CPP11) | |
4350 | #define CLARA_CONFIG_CPP11_OVERRIDE | |
4351 | #endif | |
4352 | #if defined(CLARA_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_UNIQUE_PTR) && !defined(CLARA_CONFIG_CPP11_UNIQUE_PTR) && !defined(CLARA_CONFIG_NO_CPP11) | |
4353 | #define CLARA_CONFIG_CPP11_UNIQUE_PTR | |
4354 | #endif | |
4355 | ||
4356 | // noexcept support: | |
4357 | #if defined(CLARA_CONFIG_CPP11_NOEXCEPT) && !defined(CLARA_NOEXCEPT) | |
4358 | #define CLARA_NOEXCEPT noexcept | |
4359 | # define CLARA_NOEXCEPT_IS(x) noexcept(x) | |
4360 | #else | |
4361 | #define CLARA_NOEXCEPT throw() | |
4362 | # define CLARA_NOEXCEPT_IS(x) | |
4363 | #endif | |
4364 | ||
4365 | // nullptr support | |
4366 | #ifdef CLARA_CONFIG_CPP11_NULLPTR | |
4367 | #define CLARA_NULL nullptr | |
4368 | #else | |
4369 | #define CLARA_NULL NULL | |
4370 | #endif | |
4371 | ||
4372 | // override support | |
4373 | #ifdef CLARA_CONFIG_CPP11_OVERRIDE | |
4374 | #define CLARA_OVERRIDE override | |
4375 | #else | |
4376 | #define CLARA_OVERRIDE | |
4377 | #endif | |
4378 | ||
4379 | // unique_ptr support | |
4380 | #ifdef CLARA_CONFIG_CPP11_UNIQUE_PTR | |
4381 | # define CLARA_AUTO_PTR( T ) std::unique_ptr<T> | |
4382 | #else | |
4383 | # define CLARA_AUTO_PTR( T ) std::auto_ptr<T> | |
4384 | #endif | |
4385 | ||
4386 | #endif // TWOBLUECUBES_CLARA_COMPILERS_H_INCLUDED | |
4387 | ||
4388 | // ----------- end of #include from clara_compilers.h ----------- | |
4389 | // ........... back in clara.h | |
4390 | ||
4391 | #include <map> | |
4392 | #include <stdexcept> | |
4393 | #include <memory> | |
4394 | ||
4395 | #if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) | |
4396 | #define CLARA_PLATFORM_WINDOWS | |
4397 | #endif | |
4398 | ||
4399 | // Use optional outer namespace | |
4400 | #ifdef STITCH_CLARA_OPEN_NAMESPACE | |
4401 | STITCH_CLARA_OPEN_NAMESPACE | |
4402 | #endif | |
4403 | ||
4404 | namespace Clara { | |
4405 | ||
4406 | struct UnpositionalTag {}; | |
4407 | ||
4408 | extern UnpositionalTag _; | |
4409 | ||
4410 | #ifdef CLARA_CONFIG_MAIN | |
4411 | UnpositionalTag _; | |
4412 | #endif | |
4413 | ||
4414 | namespace Detail { | |
4415 | ||
4416 | #ifdef CLARA_CONSOLE_WIDTH | |
4417 | const unsigned int consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH; | |
4418 | #else | |
4419 | const unsigned int consoleWidth = 80; | |
4420 | #endif | |
4421 | ||
4422 | using namespace Tbc; | |
4423 | ||
4424 | inline bool startsWith( std::string const& str, std::string const& prefix ) { | |
4425 | return str.size() >= prefix.size() && str.substr( 0, prefix.size() ) == prefix; | |
4426 | } | |
4427 | ||
4428 | template<typename T> struct RemoveConstRef{ typedef T type; }; | |
4429 | template<typename T> struct RemoveConstRef<T&>{ typedef T type; }; | |
4430 | template<typename T> struct RemoveConstRef<T const&>{ typedef T type; }; | |
4431 | template<typename T> struct RemoveConstRef<T const>{ typedef T type; }; | |
4432 | ||
4433 | template<typename T> struct IsBool { static const bool value = false; }; | |
4434 | template<> struct IsBool<bool> { static const bool value = true; }; | |
4435 | ||
4436 | template<typename T> | |
4437 | void convertInto( std::string const& _source, T& _dest ) { | |
4438 | std::stringstream ss; | |
4439 | ss << _source; | |
4440 | ss >> _dest; | |
4441 | if( ss.fail() ) | |
4442 | throw std::runtime_error( "Unable to convert " + _source + " to destination type" ); | |
4443 | } | |
4444 | inline void convertInto( std::string const& _source, std::string& _dest ) { | |
4445 | _dest = _source; | |
4446 | } | |
4447 | char toLowerCh(char c) { | |
4448 | return static_cast<char>( std::tolower( c ) ); | |
4449 | } | |
4450 | inline void convertInto( std::string const& _source, bool& _dest ) { | |
4451 | std::string sourceLC = _source; | |
4452 | std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), toLowerCh ); | |
4453 | if( sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on" ) | |
4454 | _dest = true; | |
4455 | else if( sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off" ) | |
4456 | _dest = false; | |
4457 | else | |
4458 | throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" ); | |
4459 | } | |
4460 | ||
4461 | template<typename ConfigT> | |
4462 | struct IArgFunction { | |
4463 | virtual ~IArgFunction() {} | |
4464 | #ifdef CLARA_CONFIG_CPP11_GENERATED_METHODS | |
4465 | IArgFunction() = default; | |
4466 | IArgFunction( IArgFunction const& ) = default; | |
4467 | #endif | |
4468 | virtual void set( ConfigT& config, std::string const& value ) const = 0; | |
4469 | virtual bool takesArg() const = 0; | |
4470 | virtual IArgFunction* clone() const = 0; | |
4471 | }; | |
4472 | ||
4473 | template<typename ConfigT> | |
4474 | class BoundArgFunction { | |
4475 | public: | |
4476 | BoundArgFunction() : functionObj( CLARA_NULL ) {} | |
4477 | BoundArgFunction( IArgFunction<ConfigT>* _functionObj ) : functionObj( _functionObj ) {} | |
4478 | BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : CLARA_NULL ) {} | |
4479 | BoundArgFunction& operator = ( BoundArgFunction const& other ) { | |
4480 | IArgFunction<ConfigT>* newFunctionObj = other.functionObj ? other.functionObj->clone() : CLARA_NULL; | |
4481 | delete functionObj; | |
4482 | functionObj = newFunctionObj; | |
4483 | return *this; | |
4484 | } | |
4485 | ~BoundArgFunction() { delete functionObj; } | |
4486 | ||
4487 | void set( ConfigT& config, std::string const& value ) const { | |
4488 | functionObj->set( config, value ); | |
4489 | } | |
4490 | bool takesArg() const { return functionObj->takesArg(); } | |
4491 | ||
4492 | bool isSet() const { | |
4493 | return functionObj != CLARA_NULL; | |
4494 | } | |
4495 | private: | |
4496 | IArgFunction<ConfigT>* functionObj; | |
4497 | }; | |
4498 | ||
4499 | template<typename C> | |
4500 | struct NullBinder : IArgFunction<C>{ | |
4501 | virtual void set( C&, std::string const& ) const {} | |
4502 | virtual bool takesArg() const { return true; } | |
4503 | virtual IArgFunction<C>* clone() const { return new NullBinder( *this ); } | |
4504 | }; | |
4505 | ||
4506 | template<typename C, typename M> | |
4507 | struct BoundDataMember : IArgFunction<C>{ | |
4508 | BoundDataMember( M C::* _member ) : member( _member ) {} | |
4509 | virtual void set( C& p, std::string const& stringValue ) const { | |
4510 | convertInto( stringValue, p.*member ); | |
4511 | } | |
4512 | virtual bool takesArg() const { return !IsBool<M>::value; } | |
4513 | virtual IArgFunction<C>* clone() const { return new BoundDataMember( *this ); } | |
4514 | M C::* member; | |
4515 | }; | |
4516 | template<typename C, typename M> | |
4517 | struct BoundUnaryMethod : IArgFunction<C>{ | |
4518 | BoundUnaryMethod( void (C::*_member)( M ) ) : member( _member ) {} | |
4519 | virtual void set( C& p, std::string const& stringValue ) const { | |
4520 | typename RemoveConstRef<M>::type value; | |
4521 | convertInto( stringValue, value ); | |
4522 | (p.*member)( value ); | |
4523 | } | |
4524 | virtual bool takesArg() const { return !IsBool<M>::value; } | |
4525 | virtual IArgFunction<C>* clone() const { return new BoundUnaryMethod( *this ); } | |
4526 | void (C::*member)( M ); | |
4527 | }; | |
4528 | template<typename C> | |
4529 | struct BoundNullaryMethod : IArgFunction<C>{ | |
4530 | BoundNullaryMethod( void (C::*_member)() ) : member( _member ) {} | |
4531 | virtual void set( C& p, std::string const& stringValue ) const { | |
4532 | bool value; | |
4533 | convertInto( stringValue, value ); | |
4534 | if( value ) | |
4535 | (p.*member)(); | |
4536 | } | |
4537 | virtual bool takesArg() const { return false; } | |
4538 | virtual IArgFunction<C>* clone() const { return new BoundNullaryMethod( *this ); } | |
4539 | void (C::*member)(); | |
4540 | }; | |
4541 | ||
4542 | template<typename C> | |
4543 | struct BoundUnaryFunction : IArgFunction<C>{ | |
4544 | BoundUnaryFunction( void (*_function)( C& ) ) : function( _function ) {} | |
4545 | virtual void set( C& obj, std::string const& stringValue ) const { | |
4546 | bool value; | |
4547 | convertInto( stringValue, value ); | |
4548 | if( value ) | |
4549 | function( obj ); | |
4550 | } | |
4551 | virtual bool takesArg() const { return false; } | |
4552 | virtual IArgFunction<C>* clone() const { return new BoundUnaryFunction( *this ); } | |
4553 | void (*function)( C& ); | |
4554 | }; | |
4555 | ||
4556 | template<typename C, typename T> | |
4557 | struct BoundBinaryFunction : IArgFunction<C>{ | |
4558 | BoundBinaryFunction( void (*_function)( C&, T ) ) : function( _function ) {} | |
4559 | virtual void set( C& obj, std::string const& stringValue ) const { | |
4560 | typename RemoveConstRef<T>::type value; | |
4561 | convertInto( stringValue, value ); | |
4562 | function( obj, value ); | |
4563 | } | |
4564 | virtual bool takesArg() const { return !IsBool<T>::value; } | |
4565 | virtual IArgFunction<C>* clone() const { return new BoundBinaryFunction( *this ); } | |
4566 | void (*function)( C&, T ); | |
4567 | }; | |
4568 | ||
4569 | } // namespace Detail | |
4570 | ||
4571 | inline std::vector<std::string> argsToVector( int argc, char const* const* const argv ) { | |
4572 | std::vector<std::string> args( static_cast<std::size_t>( argc ) ); | |
4573 | for( std::size_t i = 0; i < static_cast<std::size_t>( argc ); ++i ) | |
4574 | args[i] = argv[i]; | |
4575 | ||
4576 | return args; | |
4577 | } | |
4578 | ||
4579 | class Parser { | |
4580 | enum Mode { None, MaybeShortOpt, SlashOpt, ShortOpt, LongOpt, Positional }; | |
4581 | Mode mode; | |
4582 | std::size_t from; | |
4583 | bool inQuotes; | |
4584 | public: | |
4585 | ||
4586 | struct Token { | |
4587 | enum Type { Positional, ShortOpt, LongOpt }; | |
4588 | Token( Type _type, std::string const& _data ) : type( _type ), data( _data ) {} | |
4589 | Type type; | |
4590 | std::string data; | |
4591 | }; | |
4592 | ||
4593 | Parser() : mode( None ), from( 0 ), inQuotes( false ){} | |
4594 | ||
4595 | void parseIntoTokens( std::vector<std::string> const& args, std::vector<Token>& tokens ) { | |
4596 | const std::string doubleDash = "--"; | |
4597 | for( std::size_t i = 1; i < args.size() && args[i] != doubleDash; ++i ) | |
4598 | parseIntoTokens( args[i], tokens); | |
4599 | } | |
4600 | ||
4601 | void parseIntoTokens( std::string const& arg, std::vector<Token>& tokens ) { | |
4602 | for( std::size_t i = 0; i < arg.size(); ++i ) { | |
4603 | char c = arg[i]; | |
4604 | if( c == '"' ) | |
4605 | inQuotes = !inQuotes; | |
4606 | mode = handleMode( i, c, arg, tokens ); | |
4607 | } | |
4608 | mode = handleMode( arg.size(), '\0', arg, tokens ); | |
4609 | } | |
4610 | Mode handleMode( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) { | |
4611 | switch( mode ) { | |
4612 | case None: return handleNone( i, c ); | |
4613 | case MaybeShortOpt: return handleMaybeShortOpt( i, c ); | |
4614 | case ShortOpt: | |
4615 | case LongOpt: | |
4616 | case SlashOpt: return handleOpt( i, c, arg, tokens ); | |
4617 | case Positional: return handlePositional( i, c, arg, tokens ); | |
4618 | default: throw std::logic_error( "Unknown mode" ); | |
4619 | } | |
4620 | } | |
4621 | ||
4622 | Mode handleNone( std::size_t i, char c ) { | |
4623 | if( inQuotes ) { | |
4624 | from = i; | |
4625 | return Positional; | |
4626 | } | |
4627 | switch( c ) { | |
4628 | case '-': return MaybeShortOpt; | |
4629 | #ifdef CLARA_PLATFORM_WINDOWS | |
4630 | case '/': from = i+1; return SlashOpt; | |
4631 | #endif | |
4632 | default: from = i; return Positional; | |
4633 | } | |
4634 | } | |
4635 | Mode handleMaybeShortOpt( std::size_t i, char c ) { | |
4636 | switch( c ) { | |
4637 | case '-': from = i+1; return LongOpt; | |
4638 | default: from = i; return ShortOpt; | |
4639 | } | |
4640 | } | |
4641 | ||
4642 | Mode handleOpt( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) { | |
4643 | if( std::string( ":=\0", 3 ).find( c ) == std::string::npos ) | |
4644 | return mode; | |
4645 | ||
4646 | std::string optName = arg.substr( from, i-from ); | |
4647 | if( mode == ShortOpt ) | |
4648 | for( std::size_t j = 0; j < optName.size(); ++j ) | |
4649 | tokens.push_back( Token( Token::ShortOpt, optName.substr( j, 1 ) ) ); | |
4650 | else if( mode == SlashOpt && optName.size() == 1 ) | |
4651 | tokens.push_back( Token( Token::ShortOpt, optName ) ); | |
4652 | else | |
4653 | tokens.push_back( Token( Token::LongOpt, optName ) ); | |
4654 | return None; | |
4655 | } | |
4656 | Mode handlePositional( std::size_t i, char c, std::string const& arg, std::vector<Token>& tokens ) { | |
4657 | if( inQuotes || std::string( "\0", 1 ).find( c ) == std::string::npos ) | |
4658 | return mode; | |
4659 | ||
4660 | std::string data = arg.substr( from, i-from ); | |
4661 | tokens.push_back( Token( Token::Positional, data ) ); | |
4662 | return None; | |
4663 | } | |
4664 | }; | |
4665 | ||
4666 | template<typename ConfigT> | |
4667 | struct CommonArgProperties { | |
4668 | CommonArgProperties() {} | |
4669 | CommonArgProperties( Detail::BoundArgFunction<ConfigT> const& _boundField ) : boundField( _boundField ) {} | |
4670 | ||
4671 | Detail::BoundArgFunction<ConfigT> boundField; | |
4672 | std::string description; | |
4673 | std::string detail; | |
4674 | std::string placeholder; // Only value if boundField takes an arg | |
4675 | ||
4676 | bool takesArg() const { | |
4677 | return !placeholder.empty(); | |
4678 | } | |
4679 | void validate() const { | |
4680 | if( !boundField.isSet() ) | |
4681 | throw std::logic_error( "option not bound" ); | |
4682 | } | |
4683 | }; | |
4684 | struct OptionArgProperties { | |
4685 | std::vector<std::string> shortNames; | |
4686 | std::string longName; | |
4687 | ||
4688 | bool hasShortName( std::string const& shortName ) const { | |
4689 | return std::find( shortNames.begin(), shortNames.end(), shortName ) != shortNames.end(); | |
4690 | } | |
4691 | bool hasLongName( std::string const& _longName ) const { | |
4692 | return _longName == longName; | |
4693 | } | |
4694 | }; | |
4695 | struct PositionalArgProperties { | |
4696 | PositionalArgProperties() : position( -1 ) {} | |
4697 | int position; // -1 means non-positional (floating) | |
4698 | ||
4699 | bool isFixedPositional() const { | |
4700 | return position != -1; | |
4701 | } | |
4702 | }; | |
4703 | ||
4704 | template<typename ConfigT> | |
4705 | class CommandLine { | |
4706 | ||
4707 | struct Arg : CommonArgProperties<ConfigT>, OptionArgProperties, PositionalArgProperties { | |
4708 | Arg() {} | |
4709 | Arg( Detail::BoundArgFunction<ConfigT> const& _boundField ) : CommonArgProperties<ConfigT>( _boundField ) {} | |
4710 | ||
4711 | using CommonArgProperties<ConfigT>::placeholder; // !TBD | |
4712 | ||
4713 | std::string dbgName() const { | |
4714 | if( !longName.empty() ) | |
4715 | return "--" + longName; | |
4716 | if( !shortNames.empty() ) | |
4717 | return "-" + shortNames[0]; | |
4718 | return "positional args"; | |
4719 | } | |
4720 | std::string commands() const { | |
4721 | std::ostringstream oss; | |
4722 | bool first = true; | |
4723 | std::vector<std::string>::const_iterator it = shortNames.begin(), itEnd = shortNames.end(); | |
4724 | for(; it != itEnd; ++it ) { | |
4725 | if( first ) | |
4726 | first = false; | |
4727 | else | |
4728 | oss << ", "; | |
4729 | oss << "-" << *it; | |
4730 | } | |
4731 | if( !longName.empty() ) { | |
4732 | if( !first ) | |
4733 | oss << ", "; | |
4734 | oss << "--" << longName; | |
4735 | } | |
4736 | if( !placeholder.empty() ) | |
4737 | oss << " <" << placeholder << ">"; | |
4738 | return oss.str(); | |
4739 | } | |
4740 | }; | |
4741 | ||
4742 | typedef CLARA_AUTO_PTR( Arg ) ArgAutoPtr; | |
4743 | ||
4744 | friend void addOptName( Arg& arg, std::string const& optName ) | |
4745 | { | |
4746 | if( optName.empty() ) | |
4747 | return; | |
4748 | if( Detail::startsWith( optName, "--" ) ) { | |
4749 | if( !arg.longName.empty() ) | |
4750 | throw std::logic_error( "Only one long opt may be specified. '" | |
4751 | + arg.longName | |
4752 | + "' already specified, now attempting to add '" | |
4753 | + optName + "'" ); | |
4754 | arg.longName = optName.substr( 2 ); | |
4755 | } | |
4756 | else if( Detail::startsWith( optName, "-" ) ) | |
4757 | arg.shortNames.push_back( optName.substr( 1 ) ); | |
4758 | else | |
4759 | throw std::logic_error( "option must begin with - or --. Option was: '" + optName + "'" ); | |
4760 | } | |
4761 | friend void setPositionalArg( Arg& arg, int position ) | |
4762 | { | |
4763 | arg.position = position; | |
4764 | } | |
4765 | ||
4766 | class ArgBuilder { | |
4767 | public: | |
4768 | ArgBuilder( Arg* arg ) : m_arg( arg ) {} | |
4769 | ||
4770 | // Bind a non-boolean data member (requires placeholder string) | |
4771 | template<typename C, typename M> | |
4772 | void bind( M C::* field, std::string const& placeholder ) { | |
4773 | m_arg->boundField = new Detail::BoundDataMember<C,M>( field ); | |
4774 | m_arg->placeholder = placeholder; | |
4775 | } | |
4776 | // Bind a boolean data member (no placeholder required) | |
4777 | template<typename C> | |
4778 | void bind( bool C::* field ) { | |
4779 | m_arg->boundField = new Detail::BoundDataMember<C,bool>( field ); | |
4780 | } | |
4781 | ||
4782 | // Bind a method taking a single, non-boolean argument (requires a placeholder string) | |
4783 | template<typename C, typename M> | |
4784 | void bind( void (C::* unaryMethod)( M ), std::string const& placeholder ) { | |
4785 | m_arg->boundField = new Detail::BoundUnaryMethod<C,M>( unaryMethod ); | |
4786 | m_arg->placeholder = placeholder; | |
4787 | } | |
4788 | ||
4789 | // Bind a method taking a single, boolean argument (no placeholder string required) | |
4790 | template<typename C> | |
4791 | void bind( void (C::* unaryMethod)( bool ) ) { | |
4792 | m_arg->boundField = new Detail::BoundUnaryMethod<C,bool>( unaryMethod ); | |
4793 | } | |
4794 | ||
4795 | // Bind a method that takes no arguments (will be called if opt is present) | |
4796 | template<typename C> | |
4797 | void bind( void (C::* nullaryMethod)() ) { | |
4798 | m_arg->boundField = new Detail::BoundNullaryMethod<C>( nullaryMethod ); | |
4799 | } | |
4800 | ||
4801 | // Bind a free function taking a single argument - the object to operate on (no placeholder string required) | |
4802 | template<typename C> | |
4803 | void bind( void (* unaryFunction)( C& ) ) { | |
4804 | m_arg->boundField = new Detail::BoundUnaryFunction<C>( unaryFunction ); | |
4805 | } | |
4806 | ||
4807 | // Bind a free function taking a single argument - the object to operate on (requires a placeholder string) | |
4808 | template<typename C, typename T> | |
4809 | void bind( void (* binaryFunction)( C&, T ), std::string const& placeholder ) { | |
4810 | m_arg->boundField = new Detail::BoundBinaryFunction<C, T>( binaryFunction ); | |
4811 | m_arg->placeholder = placeholder; | |
4812 | } | |
4813 | ||
4814 | ArgBuilder& describe( std::string const& description ) { | |
4815 | m_arg->description = description; | |
4816 | return *this; | |
4817 | } | |
4818 | ArgBuilder& detail( std::string const& detail ) { | |
4819 | m_arg->detail = detail; | |
4820 | return *this; | |
4821 | } | |
4822 | ||
4823 | protected: | |
4824 | Arg* m_arg; | |
4825 | }; | |
4826 | ||
4827 | class OptBuilder : public ArgBuilder { | |
4828 | public: | |
4829 | OptBuilder( Arg* arg ) : ArgBuilder( arg ) {} | |
4830 | OptBuilder( OptBuilder& other ) : ArgBuilder( other ) {} | |
4831 | ||
4832 | OptBuilder& operator[]( std::string const& optName ) { | |
4833 | addOptName( *ArgBuilder::m_arg, optName ); | |
4834 | return *this; | |
4835 | } | |
4836 | }; | |
4837 | ||
4838 | public: | |
4839 | ||
4840 | CommandLine() | |
4841 | : m_boundProcessName( new Detail::NullBinder<ConfigT>() ), | |
4842 | m_highestSpecifiedArgPosition( 0 ), | |
4843 | m_throwOnUnrecognisedTokens( false ) | |
4844 | {} | |
4845 | CommandLine( CommandLine const& other ) | |
4846 | : m_boundProcessName( other.m_boundProcessName ), | |
4847 | m_options ( other.m_options ), | |
4848 | m_positionalArgs( other.m_positionalArgs ), | |
4849 | m_highestSpecifiedArgPosition( other.m_highestSpecifiedArgPosition ), | |
4850 | m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens ) | |
4851 | { | |
4852 | if( other.m_floatingArg.get() ) | |
4853 | m_floatingArg.reset( new Arg( *other.m_floatingArg ) ); | |
4854 | } | |
4855 | ||
4856 | CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) { | |
4857 | m_throwOnUnrecognisedTokens = shouldThrow; | |
4858 | return *this; | |
4859 | } | |
4860 | ||
4861 | OptBuilder operator[]( std::string const& optName ) { | |
4862 | m_options.push_back( Arg() ); | |
4863 | addOptName( m_options.back(), optName ); | |
4864 | OptBuilder builder( &m_options.back() ); | |
4865 | return builder; | |
4866 | } | |
4867 | ||
4868 | ArgBuilder operator[]( int position ) { | |
4869 | m_positionalArgs.insert( std::make_pair( position, Arg() ) ); | |
4870 | if( position > m_highestSpecifiedArgPosition ) | |
4871 | m_highestSpecifiedArgPosition = position; | |
4872 | setPositionalArg( m_positionalArgs[position], position ); | |
4873 | ArgBuilder builder( &m_positionalArgs[position] ); | |
4874 | return builder; | |
4875 | } | |
4876 | ||
4877 | // Invoke this with the _ instance | |
4878 | ArgBuilder operator[]( UnpositionalTag ) { | |
4879 | if( m_floatingArg.get() ) | |
4880 | throw std::logic_error( "Only one unpositional argument can be added" ); | |
4881 | m_floatingArg.reset( new Arg() ); | |
4882 | ArgBuilder builder( m_floatingArg.get() ); | |
4883 | return builder; | |
4884 | } | |
4885 | ||
4886 | template<typename C, typename M> | |
4887 | void bindProcessName( M C::* field ) { | |
4888 | m_boundProcessName = new Detail::BoundDataMember<C,M>( field ); | |
4889 | } | |
4890 | template<typename C, typename M> | |
4891 | void bindProcessName( void (C::*_unaryMethod)( M ) ) { | |
4892 | m_boundProcessName = new Detail::BoundUnaryMethod<C,M>( _unaryMethod ); | |
4893 | } | |
4894 | ||
4895 | void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = Detail::consoleWidth ) const { | |
4896 | typename std::vector<Arg>::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it; | |
4897 | std::size_t maxWidth = 0; | |
4898 | for( it = itBegin; it != itEnd; ++it ) | |
4899 | maxWidth = (std::max)( maxWidth, it->commands().size() ); | |
4900 | ||
4901 | for( it = itBegin; it != itEnd; ++it ) { | |
4902 | Detail::Text usage( it->commands(), Detail::TextAttributes() | |
4903 | .setWidth( maxWidth+indent ) | |
4904 | .setIndent( indent ) ); | |
4905 | Detail::Text desc( it->description, Detail::TextAttributes() | |
4906 | .setWidth( width - maxWidth - 3 ) ); | |
4907 | ||
4908 | for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) { | |
4909 | std::string usageCol = i < usage.size() ? usage[i] : ""; | |
4910 | os << usageCol; | |
4911 | ||
4912 | if( i < desc.size() && !desc[i].empty() ) | |
4913 | os << std::string( indent + 2 + maxWidth - usageCol.size(), ' ' ) | |
4914 | << desc[i]; | |
4915 | os << "\n"; | |
4916 | } | |
4917 | } | |
4918 | } | |
4919 | std::string optUsage() const { | |
4920 | std::ostringstream oss; | |
4921 | optUsage( oss ); | |
4922 | return oss.str(); | |
4923 | } | |
4924 | ||
4925 | void argSynopsis( std::ostream& os ) const { | |
4926 | for( int i = 1; i <= m_highestSpecifiedArgPosition; ++i ) { | |
4927 | if( i > 1 ) | |
4928 | os << " "; | |
4929 | typename std::map<int, Arg>::const_iterator it = m_positionalArgs.find( i ); | |
4930 | if( it != m_positionalArgs.end() ) | |
4931 | os << "<" << it->second.placeholder << ">"; | |
4932 | else if( m_floatingArg.get() ) | |
4933 | os << "<" << m_floatingArg->placeholder << ">"; | |
4934 | else | |
4935 | throw std::logic_error( "non consecutive positional arguments with no floating args" ); | |
4936 | } | |
4937 | // !TBD No indication of mandatory args | |
4938 | if( m_floatingArg.get() ) { | |
4939 | if( m_highestSpecifiedArgPosition > 1 ) | |
4940 | os << " "; | |
4941 | os << "[<" << m_floatingArg->placeholder << "> ...]"; | |
4942 | } | |
4943 | } | |
4944 | std::string argSynopsis() const { | |
4945 | std::ostringstream oss; | |
4946 | argSynopsis( oss ); | |
4947 | return oss.str(); | |
4948 | } | |
4949 | ||
4950 | void usage( std::ostream& os, std::string const& procName ) const { | |
4951 | validate(); | |
4952 | os << "usage:\n " << procName << " "; | |
4953 | argSynopsis( os ); | |
4954 | if( !m_options.empty() ) { | |
4955 | os << " [options]\n\nwhere options are: \n"; | |
4956 | optUsage( os, 2 ); | |
4957 | } | |
4958 | os << "\n"; | |
4959 | } | |
4960 | std::string usage( std::string const& procName ) const { | |
4961 | std::ostringstream oss; | |
4962 | usage( oss, procName ); | |
4963 | return oss.str(); | |
4964 | } | |
4965 | ||
4966 | ConfigT parse( std::vector<std::string> const& args ) const { | |
4967 | ConfigT config; | |
4968 | parseInto( args, config ); | |
4969 | return config; | |
4970 | } | |
4971 | ||
4972 | std::vector<Parser::Token> parseInto( std::vector<std::string> const& args, ConfigT& config ) const { | |
4973 | std::string processName = args.empty() ? std::string() : args[0]; | |
4974 | std::size_t lastSlash = processName.find_last_of( "/\\" ); | |
4975 | if( lastSlash != std::string::npos ) | |
4976 | processName = processName.substr( lastSlash+1 ); | |
4977 | m_boundProcessName.set( config, processName ); | |
4978 | std::vector<Parser::Token> tokens; | |
4979 | Parser parser; | |
4980 | parser.parseIntoTokens( args, tokens ); | |
4981 | return populate( tokens, config ); | |
4982 | } | |
4983 | ||
4984 | std::vector<Parser::Token> populate( std::vector<Parser::Token> const& tokens, ConfigT& config ) const { | |
4985 | validate(); | |
4986 | std::vector<Parser::Token> unusedTokens = populateOptions( tokens, config ); | |
4987 | unusedTokens = populateFixedArgs( unusedTokens, config ); | |
4988 | unusedTokens = populateFloatingArgs( unusedTokens, config ); | |
4989 | return unusedTokens; | |
4990 | } | |
4991 | ||
4992 | std::vector<Parser::Token> populateOptions( std::vector<Parser::Token> const& tokens, ConfigT& config ) const { | |
4993 | std::vector<Parser::Token> unusedTokens; | |
4994 | std::vector<std::string> errors; | |
4995 | for( std::size_t i = 0; i < tokens.size(); ++i ) { | |
4996 | Parser::Token const& token = tokens[i]; | |
4997 | typename std::vector<Arg>::const_iterator it = m_options.begin(), itEnd = m_options.end(); | |
4998 | for(; it != itEnd; ++it ) { | |
4999 | Arg const& arg = *it; | |
5000 | ||
5001 | try { | |
5002 | if( ( token.type == Parser::Token::ShortOpt && arg.hasShortName( token.data ) ) || | |
5003 | ( token.type == Parser::Token::LongOpt && arg.hasLongName( token.data ) ) ) { | |
5004 | if( arg.takesArg() ) { | |
5005 | if( i == tokens.size()-1 || tokens[i+1].type != Parser::Token::Positional ) | |
5006 | errors.push_back( "Expected argument to option: " + token.data ); | |
5007 | else | |
5008 | arg.boundField.set( config, tokens[++i].data ); | |
5009 | } | |
5010 | else { | |
5011 | arg.boundField.set( config, "true" ); | |
5012 | } | |
5013 | break; | |
5014 | } | |
5015 | } | |
5016 | catch( std::exception& ex ) { | |
5017 | errors.push_back( std::string( ex.what() ) + "\n- while parsing: (" + arg.commands() + ")" ); | |
5018 | } | |
5019 | } | |
5020 | if( it == itEnd ) { | |
5021 | if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens ) | |
5022 | unusedTokens.push_back( token ); | |
5023 | else if( errors.empty() && m_throwOnUnrecognisedTokens ) | |
5024 | errors.push_back( "unrecognised option: " + token.data ); | |
5025 | } | |
5026 | } | |
5027 | if( !errors.empty() ) { | |
5028 | std::ostringstream oss; | |
5029 | for( std::vector<std::string>::const_iterator it = errors.begin(), itEnd = errors.end(); | |
5030 | it != itEnd; | |
5031 | ++it ) { | |
5032 | if( it != errors.begin() ) | |
5033 | oss << "\n"; | |
5034 | oss << *it; | |
5035 | } | |
5036 | throw std::runtime_error( oss.str() ); | |
5037 | } | |
5038 | return unusedTokens; | |
5039 | } | |
5040 | std::vector<Parser::Token> populateFixedArgs( std::vector<Parser::Token> const& tokens, ConfigT& config ) const { | |
5041 | std::vector<Parser::Token> unusedTokens; | |
5042 | int position = 1; | |
5043 | for( std::size_t i = 0; i < tokens.size(); ++i ) { | |
5044 | Parser::Token const& token = tokens[i]; | |
5045 | typename std::map<int, Arg>::const_iterator it = m_positionalArgs.find( position ); | |
5046 | if( it != m_positionalArgs.end() ) | |
5047 | it->second.boundField.set( config, token.data ); | |
5048 | else | |
5049 | unusedTokens.push_back( token ); | |
5050 | if( token.type == Parser::Token::Positional ) | |
5051 | position++; | |
5052 | } | |
5053 | return unusedTokens; | |
5054 | } | |
5055 | std::vector<Parser::Token> populateFloatingArgs( std::vector<Parser::Token> const& tokens, ConfigT& config ) const { | |
5056 | if( !m_floatingArg.get() ) | |
5057 | return tokens; | |
5058 | std::vector<Parser::Token> unusedTokens; | |
5059 | for( std::size_t i = 0; i < tokens.size(); ++i ) { | |
5060 | Parser::Token const& token = tokens[i]; | |
5061 | if( token.type == Parser::Token::Positional ) | |
5062 | m_floatingArg->boundField.set( config, token.data ); | |
5063 | else | |
5064 | unusedTokens.push_back( token ); | |
5065 | } | |
5066 | return unusedTokens; | |
5067 | } | |
5068 | ||
5069 | void validate() const | |
5070 | { | |
5071 | if( m_options.empty() && m_positionalArgs.empty() && !m_floatingArg.get() ) | |
5072 | throw std::logic_error( "No options or arguments specified" ); | |
5073 | ||
5074 | for( typename std::vector<Arg>::const_iterator it = m_options.begin(), | |
5075 | itEnd = m_options.end(); | |
5076 | it != itEnd; ++it ) | |
5077 | it->validate(); | |
5078 | } | |
5079 | ||
5080 | private: | |
5081 | Detail::BoundArgFunction<ConfigT> m_boundProcessName; | |
5082 | std::vector<Arg> m_options; | |
5083 | std::map<int, Arg> m_positionalArgs; | |
5084 | ArgAutoPtr m_floatingArg; | |
5085 | int m_highestSpecifiedArgPosition; | |
5086 | bool m_throwOnUnrecognisedTokens; | |
5087 | }; | |
5088 | ||
5089 | } // end namespace Clara | |
5090 | ||
5091 | STITCH_CLARA_CLOSE_NAMESPACE | |
5092 | #undef STITCH_CLARA_OPEN_NAMESPACE | |
5093 | #undef STITCH_CLARA_CLOSE_NAMESPACE | |
5094 | ||
5095 | #endif // TWOBLUECUBES_CLARA_H_INCLUDED | |
5096 | #undef STITCH_CLARA_OPEN_NAMESPACE | |
5097 | ||
5098 | // Restore Clara's value for console width, if present | |
5099 | #ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH | |
5100 | #define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH | |
5101 | #undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH | |
5102 | #endif | |
5103 | ||
5104 | #include <fstream> | |
5105 | #include <ctime> | |
5106 | ||
5107 | namespace Catch { | |
5108 | ||
5109 | inline void abortAfterFirst( ConfigData& config ) { config.abortAfter = 1; } | |
5110 | inline void abortAfterX( ConfigData& config, int x ) { | |
5111 | if( x < 1 ) | |
5112 | throw std::runtime_error( "Value after -x or --abortAfter must be greater than zero" ); | |
5113 | config.abortAfter = x; | |
5114 | } | |
5115 | inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); } | |
5116 | inline void addSectionToRun( ConfigData& config, std::string const& sectionName ) { config.sectionsToRun.push_back( sectionName ); } | |
5117 | inline void addReporterName( ConfigData& config, std::string const& _reporterName ) { config.reporterNames.push_back( _reporterName ); } | |
5118 | ||
5119 | inline void addWarning( ConfigData& config, std::string const& _warning ) { | |
5120 | if( _warning == "NoAssertions" ) | |
5121 | config.warnings = static_cast<WarnAbout::What>( config.warnings | WarnAbout::NoAssertions ); | |
5122 | else | |
5123 | throw std::runtime_error( "Unrecognised warning: '" + _warning + '\'' ); | |
5124 | } | |
5125 | inline void setOrder( ConfigData& config, std::string const& order ) { | |
5126 | if( startsWith( "declared", order ) ) | |
5127 | config.runOrder = RunTests::InDeclarationOrder; | |
5128 | else if( startsWith( "lexical", order ) ) | |
5129 | config.runOrder = RunTests::InLexicographicalOrder; | |
5130 | else if( startsWith( "random", order ) ) | |
5131 | config.runOrder = RunTests::InRandomOrder; | |
5132 | else | |
5133 | throw std::runtime_error( "Unrecognised ordering: '" + order + '\'' ); | |
5134 | } | |
5135 | inline void setRngSeed( ConfigData& config, std::string const& seed ) { | |
5136 | if( seed == "time" ) { | |
5137 | config.rngSeed = static_cast<unsigned int>( std::time(0) ); | |
5138 | } | |
5139 | else { | |
5140 | std::stringstream ss; | |
5141 | ss << seed; | |
5142 | ss >> config.rngSeed; | |
5143 | if( ss.fail() ) | |
5144 | throw std::runtime_error( "Argument to --rng-seed should be the word 'time' or a number" ); | |
5145 | } | |
5146 | } | |
5147 | inline void setVerbosity( ConfigData& config, int level ) { | |
5148 | // !TBD: accept strings? | |
5149 | config.verbosity = static_cast<Verbosity::Level>( level ); | |
5150 | } | |
5151 | inline void setShowDurations( ConfigData& config, bool _showDurations ) { | |
5152 | config.showDurations = _showDurations | |
5153 | ? ShowDurations::Always | |
5154 | : ShowDurations::Never; | |
5155 | } | |
5156 | inline void setUseColour( ConfigData& config, std::string const& value ) { | |
5157 | std::string mode = toLower( value ); | |
5158 | ||
5159 | if( mode == "yes" ) | |
5160 | config.useColour = UseColour::Yes; | |
5161 | else if( mode == "no" ) | |
5162 | config.useColour = UseColour::No; | |
5163 | else if( mode == "auto" ) | |
5164 | config.useColour = UseColour::Auto; | |
5165 | else | |
5166 | throw std::runtime_error( "colour mode must be one of: auto, yes or no" ); | |
5167 | } | |
5168 | inline void forceColour( ConfigData& config ) { | |
5169 | config.useColour = UseColour::Yes; | |
5170 | } | |
5171 | inline void loadTestNamesFromFile( ConfigData& config, std::string const& _filename ) { | |
5172 | std::ifstream f( _filename.c_str() ); | |
5173 | if( !f.is_open() ) | |
5174 | throw std::domain_error( "Unable to load input file: " + _filename ); | |
5175 | ||
5176 | std::string line; | |
5177 | while( std::getline( f, line ) ) { | |
5178 | line = trim(line); | |
5179 | if( !line.empty() && !startsWith( line, '#' ) ) { | |
5180 | if( !startsWith( line, '"' ) ) | |
5181 | line = '"' + line + '"'; | |
5182 | addTestOrTags( config, line + ',' ); | |
5183 | } | |
5184 | } | |
5185 | } | |
5186 | ||
5187 | inline Clara::CommandLine<ConfigData> makeCommandLineParser() { | |
5188 | ||
5189 | using namespace Clara; | |
5190 | CommandLine<ConfigData> cli; | |
5191 | ||
5192 | cli.bindProcessName( &ConfigData::processName ); | |
5193 | ||
5194 | cli["-?"]["-h"]["--help"] | |
5195 | .describe( "display usage information" ) | |
5196 | .bind( &ConfigData::showHelp ); | |
5197 | ||
5198 | cli["-l"]["--list-tests"] | |
5199 | .describe( "list all/matching test cases" ) | |
5200 | .bind( &ConfigData::listTests ); | |
5201 | ||
5202 | cli["-t"]["--list-tags"] | |
5203 | .describe( "list all/matching tags" ) | |
5204 | .bind( &ConfigData::listTags ); | |
5205 | ||
5206 | cli["-s"]["--success"] | |
5207 | .describe( "include successful tests in output" ) | |
5208 | .bind( &ConfigData::showSuccessfulTests ); | |
5209 | ||
5210 | cli["-b"]["--break"] | |
5211 | .describe( "break into debugger on failure" ) | |
5212 | .bind( &ConfigData::shouldDebugBreak ); | |
5213 | ||
5214 | cli["-e"]["--nothrow"] | |
5215 | .describe( "skip exception tests" ) | |
5216 | .bind( &ConfigData::noThrow ); | |
5217 | ||
5218 | cli["-i"]["--invisibles"] | |
5219 | .describe( "show invisibles (tabs, newlines)" ) | |
5220 | .bind( &ConfigData::showInvisibles ); | |
5221 | ||
5222 | cli["-o"]["--out"] | |
5223 | .describe( "output filename" ) | |
5224 | .bind( &ConfigData::outputFilename, "filename" ); | |
5225 | ||
5226 | cli["-r"]["--reporter"] | |
5227 | // .placeholder( "name[:filename]" ) | |
5228 | .describe( "reporter to use (defaults to console)" ) | |
5229 | .bind( &addReporterName, "name" ); | |
5230 | ||
5231 | cli["-n"]["--name"] | |
5232 | .describe( "suite name" ) | |
5233 | .bind( &ConfigData::name, "name" ); | |
5234 | ||
5235 | cli["-a"]["--abort"] | |
5236 | .describe( "abort at first failure" ) | |
5237 | .bind( &abortAfterFirst ); | |
5238 | ||
5239 | cli["-x"]["--abortx"] | |
5240 | .describe( "abort after x failures" ) | |
5241 | .bind( &abortAfterX, "no. failures" ); | |
5242 | ||
5243 | cli["-w"]["--warn"] | |
5244 | .describe( "enable warnings" ) | |
5245 | .bind( &addWarning, "warning name" ); | |
5246 | ||
5247 | // - needs updating if reinstated | |
5248 | // cli.into( &setVerbosity ) | |
5249 | // .describe( "level of verbosity (0=no output)" ) | |
5250 | // .shortOpt( "v") | |
5251 | // .longOpt( "verbosity" ) | |
5252 | // .placeholder( "level" ); | |
5253 | ||
5254 | cli[_] | |
5255 | .describe( "which test or tests to use" ) | |
5256 | .bind( &addTestOrTags, "test name, pattern or tags" ); | |
5257 | ||
5258 | cli["-d"]["--durations"] | |
5259 | .describe( "show test durations" ) | |
5260 | .bind( &setShowDurations, "yes|no" ); | |
5261 | ||
5262 | cli["-f"]["--input-file"] | |
5263 | .describe( "load test names to run from a file" ) | |
5264 | .bind( &loadTestNamesFromFile, "filename" ); | |
5265 | ||
5266 | cli["-#"]["--filenames-as-tags"] | |
5267 | .describe( "adds a tag for the filename" ) | |
5268 | .bind( &ConfigData::filenamesAsTags ); | |
5269 | ||
5270 | cli["-c"]["--section"] | |
5271 | .describe( "specify section to run" ) | |
5272 | .bind( &addSectionToRun, "section name" ); | |
5273 | ||
5274 | // Less common commands which don't have a short form | |
5275 | cli["--list-test-names-only"] | |
5276 | .describe( "list all/matching test cases names only" ) | |
5277 | .bind( &ConfigData::listTestNamesOnly ); | |
5278 | ||
5279 | cli["--list-reporters"] | |
5280 | .describe( "list all reporters" ) | |
5281 | .bind( &ConfigData::listReporters ); | |
5282 | ||
5283 | cli["--order"] | |
5284 | .describe( "test case order (defaults to decl)" ) | |
5285 | .bind( &setOrder, "decl|lex|rand" ); | |
5286 | ||
5287 | cli["--rng-seed"] | |
5288 | .describe( "set a specific seed for random numbers" ) | |
5289 | .bind( &setRngSeed, "'time'|number" ); | |
5290 | ||
5291 | cli["--force-colour"] | |
5292 | .describe( "force colourised output (deprecated)" ) | |
5293 | .bind( &forceColour ); | |
5294 | ||
5295 | cli["--use-colour"] | |
5296 | .describe( "should output be colourised" ) | |
5297 | .bind( &setUseColour, "yes|no" ); | |
5298 | ||
5299 | return cli; | |
5300 | } | |
5301 | ||
5302 | } // end namespace Catch | |
5303 | ||
5304 | // #included from: internal/catch_list.hpp | |
5305 | #define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED | |
5306 | ||
5307 | // #included from: catch_text.h | |
5308 | #define TWOBLUECUBES_CATCH_TEXT_H_INCLUDED | |
5309 | ||
5310 | #define TBC_TEXT_FORMAT_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH | |
5311 | ||
5312 | #define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Catch | |
5313 | // #included from: ../external/tbc_text_format.h | |
5314 | // Only use header guard if we are not using an outer namespace | |
5315 | #ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE | |
5316 | # ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED | |
5317 | # ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED | |
5318 | # define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED | |
5319 | # endif | |
5320 | # else | |
5321 | # define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED | |
5322 | # endif | |
5323 | #endif | |
5324 | #ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED | |
5325 | #include <string> | |
5326 | #include <vector> | |
5327 | #include <sstream> | |
5328 | ||
5329 | // Use optional outer namespace | |
5330 | #ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE | |
5331 | namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE { | |
5332 | #endif | |
5333 | ||
5334 | namespace Tbc { | |
5335 | ||
5336 | #ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH | |
5337 | const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; | |
5338 | #else | |
5339 | const unsigned int consoleWidth = 80; | |
5340 | #endif | |
5341 | ||
5342 | struct TextAttributes { | |
5343 | TextAttributes() | |
5344 | : initialIndent( std::string::npos ), | |
5345 | indent( 0 ), | |
5346 | width( consoleWidth-1 ) | |
5347 | {} | |
5348 | ||
5349 | TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } | |
5350 | TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } | |
5351 | TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } | |
5352 | ||
5353 | std::size_t initialIndent; // indent of first line, or npos | |
5354 | std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos | |
5355 | std::size_t width; // maximum width of text, including indent. Longer text will wrap | |
5356 | }; | |
5357 | ||
5358 | class Text { | |
5359 | public: | |
5360 | Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) | |
5361 | : attr( _attr ) | |
5362 | { | |
5363 | const std::string wrappableBeforeChars = "[({<\t"; | |
5364 | const std::string wrappableAfterChars = "])}>-,./|\\"; | |
5365 | const std::string wrappableInsteadOfChars = " \n\r"; | |
5366 | std::string indent = _attr.initialIndent != std::string::npos | |
5367 | ? std::string( _attr.initialIndent, ' ' ) | |
5368 | : std::string( _attr.indent, ' ' ); | |
5369 | ||
5370 | typedef std::string::const_iterator iterator; | |
5371 | iterator it = _str.begin(); | |
5372 | const iterator strEnd = _str.end(); | |
5373 | ||
5374 | while( it != strEnd ) { | |
5375 | ||
5376 | if( lines.size() >= 1000 ) { | |
5377 | lines.push_back( "... message truncated due to excessive size" ); | |
5378 | return; | |
5379 | } | |
5380 | ||
5381 | std::string suffix; | |
5382 | std::size_t width = (std::min)( static_cast<size_t>( strEnd-it ), _attr.width-static_cast<size_t>( indent.size() ) ); | |
5383 | iterator itEnd = it+width; | |
5384 | iterator itNext = _str.end(); | |
5385 | ||
5386 | iterator itNewLine = std::find( it, itEnd, '\n' ); | |
5387 | if( itNewLine != itEnd ) | |
5388 | itEnd = itNewLine; | |
5389 | ||
5390 | if( itEnd != strEnd ) { | |
5391 | bool foundWrapPoint = false; | |
5392 | iterator findIt = itEnd; | |
5393 | do { | |
5394 | if( wrappableAfterChars.find( *findIt ) != std::string::npos && findIt != itEnd ) { | |
5395 | itEnd = findIt+1; | |
5396 | itNext = findIt+1; | |
5397 | foundWrapPoint = true; | |
5398 | } | |
5399 | else if( findIt > it && wrappableBeforeChars.find( *findIt ) != std::string::npos ) { | |
5400 | itEnd = findIt; | |
5401 | itNext = findIt; | |
5402 | foundWrapPoint = true; | |
5403 | } | |
5404 | else if( wrappableInsteadOfChars.find( *findIt ) != std::string::npos ) { | |
5405 | itNext = findIt+1; | |
5406 | itEnd = findIt; | |
5407 | foundWrapPoint = true; | |
5408 | } | |
5409 | if( findIt == it ) | |
5410 | break; | |
5411 | else | |
5412 | --findIt; | |
5413 | } | |
5414 | while( !foundWrapPoint ); | |
5415 | ||
5416 | if( !foundWrapPoint ) { | |
5417 | // No good wrap char, so we'll break mid word and add a hyphen | |
5418 | --itEnd; | |
5419 | itNext = itEnd; | |
5420 | suffix = "-"; | |
5421 | } | |
5422 | else { | |
5423 | while( itEnd > it && wrappableInsteadOfChars.find( *(itEnd-1) ) != std::string::npos ) | |
5424 | --itEnd; | |
5425 | } | |
5426 | } | |
5427 | lines.push_back( indent + std::string( it, itEnd ) + suffix ); | |
5428 | ||
5429 | if( indent.size() != _attr.indent ) | |
5430 | indent = std::string( _attr.indent, ' ' ); | |
5431 | it = itNext; | |
5432 | } | |
5433 | } | |
5434 | ||
5435 | typedef std::vector<std::string>::const_iterator const_iterator; | |
5436 | ||
5437 | const_iterator begin() const { return lines.begin(); } | |
5438 | const_iterator end() const { return lines.end(); } | |
5439 | std::string const& last() const { return lines.back(); } | |
5440 | std::size_t size() const { return lines.size(); } | |
5441 | std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } | |
5442 | std::string toString() const { | |
5443 | std::ostringstream oss; | |
5444 | oss << *this; | |
5445 | return oss.str(); | |
5446 | } | |
5447 | ||
5448 | inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { | |
5449 | for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); | |
5450 | it != itEnd; ++it ) { | |
5451 | if( it != _text.begin() ) | |
5452 | _stream << "\n"; | |
5453 | _stream << *it; | |
5454 | } | |
5455 | return _stream; | |
5456 | } | |
5457 | ||
5458 | private: | |
5459 | std::string str; | |
5460 | TextAttributes attr; | |
5461 | std::vector<std::string> lines; | |
5462 | }; | |
5463 | ||
5464 | } // end namespace Tbc | |
5465 | ||
5466 | #ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE | |
5467 | } // end outer namespace | |
5468 | #endif | |
5469 | ||
5470 | #endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED | |
5471 | #undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE | |
5472 | ||
5473 | namespace Catch { | |
5474 | using Tbc::Text; | |
5475 | using Tbc::TextAttributes; | |
5476 | } | |
5477 | ||
5478 | // #included from: catch_console_colour.hpp | |
5479 | #define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_HPP_INCLUDED | |
5480 | ||
5481 | namespace Catch { | |
5482 | ||
5483 | struct Colour { | |
5484 | enum Code { | |
5485 | None = 0, | |
5486 | ||
5487 | White, | |
5488 | Red, | |
5489 | Green, | |
5490 | Blue, | |
5491 | Cyan, | |
5492 | Yellow, | |
5493 | Grey, | |
5494 | ||
5495 | Bright = 0x10, | |
5496 | ||
5497 | BrightRed = Bright | Red, | |
5498 | BrightGreen = Bright | Green, | |
5499 | LightGrey = Bright | Grey, | |
5500 | BrightWhite = Bright | White, | |
5501 | ||
5502 | // By intention | |
5503 | FileName = LightGrey, | |
5504 | Warning = Yellow, | |
5505 | ResultError = BrightRed, | |
5506 | ResultSuccess = BrightGreen, | |
5507 | ResultExpectedFailure = Warning, | |
5508 | ||
5509 | Error = BrightRed, | |
5510 | Success = Green, | |
5511 | ||
5512 | OriginalExpression = Cyan, | |
5513 | ReconstructedExpression = Yellow, | |
5514 | ||
5515 | SecondaryText = LightGrey, | |
5516 | Headers = White | |
5517 | }; | |
5518 | ||
5519 | // Use constructed object for RAII guard | |
5520 | Colour( Code _colourCode ); | |
5521 | Colour( Colour const& other ); | |
5522 | ~Colour(); | |
5523 | ||
5524 | // Use static method for one-shot changes | |
5525 | static void use( Code _colourCode ); | |
5526 | ||
5527 | private: | |
5528 | bool m_moved; | |
5529 | }; | |
5530 | ||
5531 | inline std::ostream& operator << ( std::ostream& os, Colour const& ) { return os; } | |
5532 | ||
5533 | } // end namespace Catch | |
5534 | ||
5535 | // #included from: catch_interfaces_reporter.h | |
5536 | #define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED | |
5537 | ||
5538 | #include <string> | |
5539 | #include <ostream> | |
5540 | #include <map> | |
5541 | ||
5542 | namespace Catch | |
5543 | { | |
5544 | struct ReporterConfig { | |
5545 | explicit ReporterConfig( Ptr<IConfig const> const& _fullConfig ) | |
5546 | : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} | |
5547 | ||
5548 | ReporterConfig( Ptr<IConfig const> const& _fullConfig, std::ostream& _stream ) | |
5549 | : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} | |
5550 | ||
5551 | std::ostream& stream() const { return *m_stream; } | |
5552 | Ptr<IConfig const> fullConfig() const { return m_fullConfig; } | |
5553 | ||
5554 | private: | |
5555 | std::ostream* m_stream; | |
5556 | Ptr<IConfig const> m_fullConfig; | |
5557 | }; | |
5558 | ||
5559 | struct ReporterPreferences { | |
5560 | ReporterPreferences() | |
5561 | : shouldRedirectStdOut( false ) | |
5562 | {} | |
5563 | ||
5564 | bool shouldRedirectStdOut; | |
5565 | }; | |
5566 | ||
5567 | template<typename T> | |
5568 | struct LazyStat : Option<T> { | |
5569 | LazyStat() : used( false ) {} | |
5570 | LazyStat& operator=( T const& _value ) { | |
5571 | Option<T>::operator=( _value ); | |
5572 | used = false; | |
5573 | return *this; | |
5574 | } | |
5575 | void reset() { | |
5576 | Option<T>::reset(); | |
5577 | used = false; | |
5578 | } | |
5579 | bool used; | |
5580 | }; | |
5581 | ||
5582 | struct TestRunInfo { | |
5583 | TestRunInfo( std::string const& _name ) : name( _name ) {} | |
5584 | std::string name; | |
5585 | }; | |
5586 | struct GroupInfo { | |
5587 | GroupInfo( std::string const& _name, | |
5588 | std::size_t _groupIndex, | |
5589 | std::size_t _groupsCount ) | |
5590 | : name( _name ), | |
5591 | groupIndex( _groupIndex ), | |
5592 | groupsCounts( _groupsCount ) | |
5593 | {} | |
5594 | ||
5595 | std::string name; | |
5596 | std::size_t groupIndex; | |
5597 | std::size_t groupsCounts; | |
5598 | }; | |
5599 | ||
5600 | struct AssertionStats { | |
5601 | AssertionStats( AssertionResult const& _assertionResult, | |
5602 | std::vector<MessageInfo> const& _infoMessages, | |
5603 | Totals const& _totals ) | |
5604 | : assertionResult( _assertionResult ), | |
5605 | infoMessages( _infoMessages ), | |
5606 | totals( _totals ) | |
5607 | { | |
5608 | if( assertionResult.hasMessage() ) { | |
5609 | // Copy message into messages list. | |
5610 | // !TBD This should have been done earlier, somewhere | |
5611 | MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); | |
5612 | builder << assertionResult.getMessage(); | |
5613 | builder.m_info.message = builder.m_stream.str(); | |
5614 | ||
5615 | infoMessages.push_back( builder.m_info ); | |
5616 | } | |
5617 | } | |
5618 | virtual ~AssertionStats(); | |
5619 | ||
5620 | # ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS | |
5621 | AssertionStats( AssertionStats const& ) = default; | |
5622 | AssertionStats( AssertionStats && ) = default; | |
5623 | AssertionStats& operator = ( AssertionStats const& ) = default; | |
5624 | AssertionStats& operator = ( AssertionStats && ) = default; | |
5625 | # endif | |
5626 | ||
5627 | AssertionResult assertionResult; | |
5628 | std::vector<MessageInfo> infoMessages; | |
5629 | Totals totals; | |
5630 | }; | |
5631 | ||
5632 | struct SectionStats { | |
5633 | SectionStats( SectionInfo const& _sectionInfo, | |
5634 | Counts const& _assertions, | |
5635 | double _durationInSeconds, | |
5636 | bool _missingAssertions ) | |
5637 | : sectionInfo( _sectionInfo ), | |
5638 | assertions( _assertions ), | |
5639 | durationInSeconds( _durationInSeconds ), | |
5640 | missingAssertions( _missingAssertions ) | |
5641 | {} | |
5642 | virtual ~SectionStats(); | |
5643 | # ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS | |
5644 | SectionStats( SectionStats const& ) = default; | |
5645 | SectionStats( SectionStats && ) = default; | |
5646 | SectionStats& operator = ( SectionStats const& ) = default; | |
5647 | SectionStats& operator = ( SectionStats && ) = default; | |
5648 | # endif | |
5649 | ||
5650 | SectionInfo sectionInfo; | |
5651 | Counts assertions; | |
5652 | double durationInSeconds; | |
5653 | bool missingAssertions; | |
5654 | }; | |
5655 | ||
5656 | struct TestCaseStats { | |
5657 | TestCaseStats( TestCaseInfo const& _testInfo, | |
5658 | Totals const& _totals, | |
5659 | std::string const& _stdOut, | |
5660 | std::string const& _stdErr, | |
5661 | bool _aborting ) | |
5662 | : testInfo( _testInfo ), | |
5663 | totals( _totals ), | |
5664 | stdOut( _stdOut ), | |
5665 | stdErr( _stdErr ), | |
5666 | aborting( _aborting ) | |
5667 | {} | |
5668 | virtual ~TestCaseStats(); | |
5669 | ||
5670 | # ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS | |
5671 | TestCaseStats( TestCaseStats const& ) = default; | |
5672 | TestCaseStats( TestCaseStats && ) = default; | |
5673 | TestCaseStats& operator = ( TestCaseStats const& ) = default; | |
5674 | TestCaseStats& operator = ( TestCaseStats && ) = default; | |
5675 | # endif | |
5676 | ||
5677 | TestCaseInfo testInfo; | |
5678 | Totals totals; | |
5679 | std::string stdOut; | |
5680 | std::string stdErr; | |
5681 | bool aborting; | |
5682 | }; | |
5683 | ||
5684 | struct TestGroupStats { | |
5685 | TestGroupStats( GroupInfo const& _groupInfo, | |
5686 | Totals const& _totals, | |
5687 | bool _aborting ) | |
5688 | : groupInfo( _groupInfo ), | |
5689 | totals( _totals ), | |
5690 | aborting( _aborting ) | |
5691 | {} | |
5692 | TestGroupStats( GroupInfo const& _groupInfo ) | |
5693 | : groupInfo( _groupInfo ), | |
5694 | aborting( false ) | |
5695 | {} | |
5696 | virtual ~TestGroupStats(); | |
5697 | ||
5698 | # ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS | |
5699 | TestGroupStats( TestGroupStats const& ) = default; | |
5700 | TestGroupStats( TestGroupStats && ) = default; | |
5701 | TestGroupStats& operator = ( TestGroupStats const& ) = default; | |
5702 | TestGroupStats& operator = ( TestGroupStats && ) = default; | |
5703 | # endif | |
5704 | ||
5705 | GroupInfo groupInfo; | |
5706 | Totals totals; | |
5707 | bool aborting; | |
5708 | }; | |
5709 | ||
5710 | struct TestRunStats { | |
5711 | TestRunStats( TestRunInfo const& _runInfo, | |
5712 | Totals const& _totals, | |
5713 | bool _aborting ) | |
5714 | : runInfo( _runInfo ), | |
5715 | totals( _totals ), | |
5716 | aborting( _aborting ) | |
5717 | {} | |
5718 | virtual ~TestRunStats(); | |
5719 | ||
5720 | # ifndef CATCH_CONFIG_CPP11_GENERATED_METHODS | |
5721 | TestRunStats( TestRunStats const& _other ) | |
5722 | : runInfo( _other.runInfo ), | |
5723 | totals( _other.totals ), | |
5724 | aborting( _other.aborting ) | |
5725 | {} | |
5726 | # else | |
5727 | TestRunStats( TestRunStats const& ) = default; | |
5728 | TestRunStats( TestRunStats && ) = default; | |
5729 | TestRunStats& operator = ( TestRunStats const& ) = default; | |
5730 | TestRunStats& operator = ( TestRunStats && ) = default; | |
5731 | # endif | |
5732 | ||
5733 | TestRunInfo runInfo; | |
5734 | Totals totals; | |
5735 | bool aborting; | |
5736 | }; | |
5737 | ||
5738 | class MultipleReporters; | |
5739 | ||
5740 | struct IStreamingReporter : IShared { | |
5741 | virtual ~IStreamingReporter(); | |
5742 | ||
5743 | // Implementing class must also provide the following static method: | |
5744 | // static std::string getDescription(); | |
5745 | ||
5746 | virtual ReporterPreferences getPreferences() const = 0; | |
5747 | ||
5748 | virtual void noMatchingTestCases( std::string const& spec ) = 0; | |
5749 | ||
5750 | virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; | |
5751 | virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0; | |
5752 | ||
5753 | virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; | |
5754 | virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; | |
5755 | ||
5756 | virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; | |
5757 | ||
5758 | // The return value indicates if the messages buffer should be cleared: | |
5759 | virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; | |
5760 | ||
5761 | virtual void sectionEnded( SectionStats const& sectionStats ) = 0; | |
5762 | virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; | |
5763 | virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; | |
5764 | virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; | |
5765 | ||
5766 | virtual void skipTest( TestCaseInfo const& testInfo ) = 0; | |
5767 | ||
5768 | virtual MultipleReporters* tryAsMulti() { return CATCH_NULL; } | |
5769 | }; | |
5770 | ||
5771 | struct IReporterFactory : IShared { | |
5772 | virtual ~IReporterFactory(); | |
5773 | virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0; | |
5774 | virtual std::string getDescription() const = 0; | |
5775 | }; | |
5776 | ||
5777 | struct IReporterRegistry { | |
5778 | typedef std::map<std::string, Ptr<IReporterFactory> > FactoryMap; | |
5779 | typedef std::vector<Ptr<IReporterFactory> > Listeners; | |
5780 | ||
5781 | virtual ~IReporterRegistry(); | |
5782 | virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig const> const& config ) const = 0; | |
5783 | virtual FactoryMap const& getFactories() const = 0; | |
5784 | virtual Listeners const& getListeners() const = 0; | |
5785 | }; | |
5786 | ||
5787 | Ptr<IStreamingReporter> addReporter( Ptr<IStreamingReporter> const& existingReporter, Ptr<IStreamingReporter> const& additionalReporter ); | |
5788 | ||
5789 | } | |
5790 | ||
5791 | #include <limits> | |
5792 | #include <algorithm> | |
5793 | ||
5794 | namespace Catch { | |
5795 | ||
5796 | inline std::size_t listTests( Config const& config ) { | |
5797 | ||
5798 | TestSpec testSpec = config.testSpec(); | |
5799 | if( config.testSpec().hasFilters() ) | |
5800 | Catch::cout() << "Matching test cases:\n"; | |
5801 | else { | |
5802 | Catch::cout() << "All available test cases:\n"; | |
5803 | testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); | |
5804 | } | |
5805 | ||
5806 | std::size_t matchedTests = 0; | |
5807 | TextAttributes nameAttr, tagsAttr; | |
5808 | nameAttr.setInitialIndent( 2 ).setIndent( 4 ); | |
5809 | tagsAttr.setIndent( 6 ); | |
5810 | ||
5811 | std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); | |
5812 | for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); | |
5813 | it != itEnd; | |
5814 | ++it ) { | |
5815 | matchedTests++; | |
5816 | TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); | |
5817 | Colour::Code colour = testCaseInfo.isHidden() | |
5818 | ? Colour::SecondaryText | |
5819 | : Colour::None; | |
5820 | Colour colourGuard( colour ); | |
5821 | ||
5822 | Catch::cout() << Text( testCaseInfo.name, nameAttr ) << std::endl; | |
5823 | if( !testCaseInfo.tags.empty() ) | |
5824 | Catch::cout() << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl; | |
5825 | } | |
5826 | ||
5827 | if( !config.testSpec().hasFilters() ) | |
5828 | Catch::cout() << pluralise( matchedTests, "test case" ) << '\n' << std::endl; | |
5829 | else | |
5830 | Catch::cout() << pluralise( matchedTests, "matching test case" ) << '\n' << std::endl; | |
5831 | return matchedTests; | |
5832 | } | |
5833 | ||
5834 | inline std::size_t listTestsNamesOnly( Config const& config ) { | |
5835 | TestSpec testSpec = config.testSpec(); | |
5836 | if( !config.testSpec().hasFilters() ) | |
5837 | testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); | |
5838 | std::size_t matchedTests = 0; | |
5839 | std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); | |
5840 | for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); | |
5841 | it != itEnd; | |
5842 | ++it ) { | |
5843 | matchedTests++; | |
5844 | TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); | |
5845 | if( startsWith( testCaseInfo.name, '#' ) ) | |
5846 | Catch::cout() << '"' << testCaseInfo.name << '"' << std::endl; | |
5847 | else | |
5848 | Catch::cout() << testCaseInfo.name << std::endl; | |
5849 | } | |
5850 | return matchedTests; | |
5851 | } | |
5852 | ||
5853 | struct TagInfo { | |
5854 | TagInfo() : count ( 0 ) {} | |
5855 | void add( std::string const& spelling ) { | |
5856 | ++count; | |
5857 | spellings.insert( spelling ); | |
5858 | } | |
5859 | std::string all() const { | |
5860 | std::string out; | |
5861 | for( std::set<std::string>::const_iterator it = spellings.begin(), itEnd = spellings.end(); | |
5862 | it != itEnd; | |
5863 | ++it ) | |
5864 | out += "[" + *it + "]"; | |
5865 | return out; | |
5866 | } | |
5867 | std::set<std::string> spellings; | |
5868 | std::size_t count; | |
5869 | }; | |
5870 | ||
5871 | inline std::size_t listTags( Config const& config ) { | |
5872 | TestSpec testSpec = config.testSpec(); | |
5873 | if( config.testSpec().hasFilters() ) | |
5874 | Catch::cout() << "Tags for matching test cases:\n"; | |
5875 | else { | |
5876 | Catch::cout() << "All available tags:\n"; | |
5877 | testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); | |
5878 | } | |
5879 | ||
5880 | std::map<std::string, TagInfo> tagCounts; | |
5881 | ||
5882 | std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); | |
5883 | for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); | |
5884 | it != itEnd; | |
5885 | ++it ) { | |
5886 | for( std::set<std::string>::const_iterator tagIt = it->getTestCaseInfo().tags.begin(), | |
5887 | tagItEnd = it->getTestCaseInfo().tags.end(); | |
5888 | tagIt != tagItEnd; | |
5889 | ++tagIt ) { | |
5890 | std::string tagName = *tagIt; | |
5891 | std::string lcaseTagName = toLower( tagName ); | |
5892 | std::map<std::string, TagInfo>::iterator countIt = tagCounts.find( lcaseTagName ); | |
5893 | if( countIt == tagCounts.end() ) | |
5894 | countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; | |
5895 | countIt->second.add( tagName ); | |
5896 | } | |
5897 | } | |
5898 | ||
5899 | for( std::map<std::string, TagInfo>::const_iterator countIt = tagCounts.begin(), | |
5900 | countItEnd = tagCounts.end(); | |
5901 | countIt != countItEnd; | |
5902 | ++countIt ) { | |
5903 | std::ostringstream oss; | |
5904 | oss << " " << std::setw(2) << countIt->second.count << " "; | |
5905 | Text wrapper( countIt->second.all(), TextAttributes() | |
5906 | .setInitialIndent( 0 ) | |
5907 | .setIndent( oss.str().size() ) | |
5908 | .setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) ); | |
5909 | Catch::cout() << oss.str() << wrapper << '\n'; | |
5910 | } | |
5911 | Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl; | |
5912 | return tagCounts.size(); | |
5913 | } | |
5914 | ||
5915 | inline std::size_t listReporters( Config const& /*config*/ ) { | |
5916 | Catch::cout() << "Available reporters:\n"; | |
5917 | IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); | |
5918 | IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it; | |
5919 | std::size_t maxNameLen = 0; | |
5920 | for(it = itBegin; it != itEnd; ++it ) | |
5921 | maxNameLen = (std::max)( maxNameLen, it->first.size() ); | |
5922 | ||
5923 | for(it = itBegin; it != itEnd; ++it ) { | |
5924 | Text wrapper( it->second->getDescription(), TextAttributes() | |
5925 | .setInitialIndent( 0 ) | |
5926 | .setIndent( 7+maxNameLen ) | |
5927 | .setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) ); | |
5928 | Catch::cout() << " " | |
5929 | << it->first | |
5930 | << ':' | |
5931 | << std::string( maxNameLen - it->first.size() + 2, ' ' ) | |
5932 | << wrapper << '\n'; | |
5933 | } | |
5934 | Catch::cout() << std::endl; | |
5935 | return factories.size(); | |
5936 | } | |
5937 | ||
5938 | inline Option<std::size_t> list( Config const& config ) { | |
5939 | Option<std::size_t> listedCount; | |
5940 | if( config.listTests() ) | |
5941 | listedCount = listedCount.valueOr(0) + listTests( config ); | |
5942 | if( config.listTestNamesOnly() ) | |
5943 | listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config ); | |
5944 | if( config.listTags() ) | |
5945 | listedCount = listedCount.valueOr(0) + listTags( config ); | |
5946 | if( config.listReporters() ) | |
5947 | listedCount = listedCount.valueOr(0) + listReporters( config ); | |
5948 | return listedCount; | |
5949 | } | |
5950 | ||
5951 | } // end namespace Catch | |
5952 | ||
5953 | // #included from: internal/catch_run_context.hpp | |
5954 | #define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED | |
5955 | ||
5956 | // #included from: catch_test_case_tracker.hpp | |
5957 | #define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED | |
5958 | ||
5959 | #include <algorithm> | |
5960 | #include <string> | |
5961 | #include <assert.h> | |
5962 | #include <vector> | |
5963 | #include <stdexcept> | |
5964 | ||
5965 | CATCH_INTERNAL_SUPPRESS_ETD_WARNINGS | |
5966 | ||
5967 | namespace Catch { | |
5968 | namespace TestCaseTracking { | |
5969 | ||
5970 | struct NameAndLocation { | |
5971 | std::string name; | |
5972 | SourceLineInfo location; | |
5973 | ||
5974 | NameAndLocation( std::string const& _name, SourceLineInfo const& _location ) | |
5975 | : name( _name ), | |
5976 | location( _location ) | |
5977 | {} | |
5978 | }; | |
5979 | ||
5980 | struct ITracker : SharedImpl<> { | |
5981 | virtual ~ITracker(); | |
5982 | ||
5983 | // static queries | |
5984 | virtual NameAndLocation const& nameAndLocation() const = 0; | |
5985 | ||
5986 | // dynamic queries | |
5987 | virtual bool isComplete() const = 0; // Successfully completed or failed | |
5988 | virtual bool isSuccessfullyCompleted() const = 0; | |
5989 | virtual bool isOpen() const = 0; // Started but not complete | |
5990 | virtual bool hasChildren() const = 0; | |
5991 | ||
5992 | virtual ITracker& parent() = 0; | |
5993 | ||
5994 | // actions | |
5995 | virtual void close() = 0; // Successfully complete | |
5996 | virtual void fail() = 0; | |
5997 | virtual void markAsNeedingAnotherRun() = 0; | |
5998 | ||
5999 | virtual void addChild( Ptr<ITracker> const& child ) = 0; | |
6000 | virtual ITracker* findChild( NameAndLocation const& nameAndLocation ) = 0; | |
6001 | virtual void openChild() = 0; | |
6002 | ||
6003 | // Debug/ checking | |
6004 | virtual bool isSectionTracker() const = 0; | |
6005 | virtual bool isIndexTracker() const = 0; | |
6006 | }; | |
6007 | ||
6008 | class TrackerContext { | |
6009 | ||
6010 | enum RunState { | |
6011 | NotStarted, | |
6012 | Executing, | |
6013 | CompletedCycle | |
6014 | }; | |
6015 | ||
6016 | Ptr<ITracker> m_rootTracker; | |
6017 | ITracker* m_currentTracker; | |
6018 | RunState m_runState; | |
6019 | ||
6020 | public: | |
6021 | ||
6022 | static TrackerContext& instance() { | |
6023 | static TrackerContext s_instance; | |
6024 | return s_instance; | |
6025 | } | |
6026 | ||
6027 | TrackerContext() | |
6028 | : m_currentTracker( CATCH_NULL ), | |
6029 | m_runState( NotStarted ) | |
6030 | {} | |
6031 | ||
6032 | ITracker& startRun(); | |
6033 | ||
6034 | void endRun() { | |
6035 | m_rootTracker.reset(); | |
6036 | m_currentTracker = CATCH_NULL; | |
6037 | m_runState = NotStarted; | |
6038 | } | |
6039 | ||
6040 | void startCycle() { | |
6041 | m_currentTracker = m_rootTracker.get(); | |
6042 | m_runState = Executing; | |
6043 | } | |
6044 | void completeCycle() { | |
6045 | m_runState = CompletedCycle; | |
6046 | } | |
6047 | ||
6048 | bool completedCycle() const { | |
6049 | return m_runState == CompletedCycle; | |
6050 | } | |
6051 | ITracker& currentTracker() { | |
6052 | return *m_currentTracker; | |
6053 | } | |
6054 | void setCurrentTracker( ITracker* tracker ) { | |
6055 | m_currentTracker = tracker; | |
6056 | } | |
6057 | }; | |
6058 | ||
6059 | class TrackerBase : public ITracker { | |
6060 | protected: | |
6061 | enum CycleState { | |
6062 | NotStarted, | |
6063 | Executing, | |
6064 | ExecutingChildren, | |
6065 | NeedsAnotherRun, | |
6066 | CompletedSuccessfully, | |
6067 | Failed | |
6068 | }; | |
6069 | class TrackerHasName { | |
6070 | NameAndLocation m_nameAndLocation; | |
6071 | public: | |
6072 | TrackerHasName( NameAndLocation const& nameAndLocation ) : m_nameAndLocation( nameAndLocation ) {} | |
6073 | bool operator ()( Ptr<ITracker> const& tracker ) { | |
6074 | return | |
6075 | tracker->nameAndLocation().name == m_nameAndLocation.name && | |
6076 | tracker->nameAndLocation().location == m_nameAndLocation.location; | |
6077 | } | |
6078 | }; | |
6079 | typedef std::vector<Ptr<ITracker> > Children; | |
6080 | NameAndLocation m_nameAndLocation; | |
6081 | TrackerContext& m_ctx; | |
6082 | ITracker* m_parent; | |
6083 | Children m_children; | |
6084 | CycleState m_runState; | |
6085 | public: | |
6086 | TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) | |
6087 | : m_nameAndLocation( nameAndLocation ), | |
6088 | m_ctx( ctx ), | |
6089 | m_parent( parent ), | |
6090 | m_runState( NotStarted ) | |
6091 | {} | |
6092 | virtual ~TrackerBase(); | |
6093 | ||
6094 | virtual NameAndLocation const& nameAndLocation() const CATCH_OVERRIDE { | |
6095 | return m_nameAndLocation; | |
6096 | } | |
6097 | virtual bool isComplete() const CATCH_OVERRIDE { | |
6098 | return m_runState == CompletedSuccessfully || m_runState == Failed; | |
6099 | } | |
6100 | virtual bool isSuccessfullyCompleted() const CATCH_OVERRIDE { | |
6101 | return m_runState == CompletedSuccessfully; | |
6102 | } | |
6103 | virtual bool isOpen() const CATCH_OVERRIDE { | |
6104 | return m_runState != NotStarted && !isComplete(); | |
6105 | } | |
6106 | virtual bool hasChildren() const CATCH_OVERRIDE { | |
6107 | return !m_children.empty(); | |
6108 | } | |
6109 | ||
6110 | virtual void addChild( Ptr<ITracker> const& child ) CATCH_OVERRIDE { | |
6111 | m_children.push_back( child ); | |
6112 | } | |
6113 | ||
6114 | virtual ITracker* findChild( NameAndLocation const& nameAndLocation ) CATCH_OVERRIDE { | |
6115 | Children::const_iterator it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( nameAndLocation ) ); | |
6116 | return( it != m_children.end() ) | |
6117 | ? it->get() | |
6118 | : CATCH_NULL; | |
6119 | } | |
6120 | virtual ITracker& parent() CATCH_OVERRIDE { | |
6121 | assert( m_parent ); // Should always be non-null except for root | |
6122 | return *m_parent; | |
6123 | } | |
6124 | ||
6125 | virtual void openChild() CATCH_OVERRIDE { | |
6126 | if( m_runState != ExecutingChildren ) { | |
6127 | m_runState = ExecutingChildren; | |
6128 | if( m_parent ) | |
6129 | m_parent->openChild(); | |
6130 | } | |
6131 | } | |
6132 | ||
6133 | virtual bool isSectionTracker() const CATCH_OVERRIDE { return false; } | |
6134 | virtual bool isIndexTracker() const CATCH_OVERRIDE { return false; } | |
6135 | ||
6136 | void open() { | |
6137 | m_runState = Executing; | |
6138 | moveToThis(); | |
6139 | if( m_parent ) | |
6140 | m_parent->openChild(); | |
6141 | } | |
6142 | ||
6143 | virtual void close() CATCH_OVERRIDE { | |
6144 | ||
6145 | // Close any still open children (e.g. generators) | |
6146 | while( &m_ctx.currentTracker() != this ) | |
6147 | m_ctx.currentTracker().close(); | |
6148 | ||
6149 | switch( m_runState ) { | |
6150 | case NotStarted: | |
6151 | case CompletedSuccessfully: | |
6152 | case Failed: | |
6153 | throw std::logic_error( "Illogical state" ); | |
6154 | ||
6155 | case NeedsAnotherRun: | |
6156 | break;; | |
6157 | ||
6158 | case Executing: | |
6159 | m_runState = CompletedSuccessfully; | |
6160 | break; | |
6161 | case ExecutingChildren: | |
6162 | if( m_children.empty() || m_children.back()->isComplete() ) | |
6163 | m_runState = CompletedSuccessfully; | |
6164 | break; | |
6165 | ||
6166 | default: | |
6167 | throw std::logic_error( "Unexpected state" ); | |
6168 | } | |
6169 | moveToParent(); | |
6170 | m_ctx.completeCycle(); | |
6171 | } | |
6172 | virtual void fail() CATCH_OVERRIDE { | |
6173 | m_runState = Failed; | |
6174 | if( m_parent ) | |
6175 | m_parent->markAsNeedingAnotherRun(); | |
6176 | moveToParent(); | |
6177 | m_ctx.completeCycle(); | |
6178 | } | |
6179 | virtual void markAsNeedingAnotherRun() CATCH_OVERRIDE { | |
6180 | m_runState = NeedsAnotherRun; | |
6181 | } | |
6182 | private: | |
6183 | void moveToParent() { | |
6184 | assert( m_parent ); | |
6185 | m_ctx.setCurrentTracker( m_parent ); | |
6186 | } | |
6187 | void moveToThis() { | |
6188 | m_ctx.setCurrentTracker( this ); | |
6189 | } | |
6190 | }; | |
6191 | ||
6192 | class SectionTracker : public TrackerBase { | |
6193 | std::vector<std::string> m_filters; | |
6194 | public: | |
6195 | SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) | |
6196 | : TrackerBase( nameAndLocation, ctx, parent ) | |
6197 | { | |
6198 | if( parent ) { | |
6199 | while( !parent->isSectionTracker() ) | |
6200 | parent = &parent->parent(); | |
6201 | ||
6202 | SectionTracker& parentSection = static_cast<SectionTracker&>( *parent ); | |
6203 | addNextFilters( parentSection.m_filters ); | |
6204 | } | |
6205 | } | |
6206 | virtual ~SectionTracker(); | |
6207 | ||
6208 | virtual bool isSectionTracker() const CATCH_OVERRIDE { return true; } | |
6209 | ||
6210 | static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) { | |
6211 | SectionTracker* section = CATCH_NULL; | |
6212 | ||
6213 | ITracker& currentTracker = ctx.currentTracker(); | |
6214 | if( ITracker* childTracker = currentTracker.findChild( nameAndLocation ) ) { | |
6215 | assert( childTracker ); | |
6216 | assert( childTracker->isSectionTracker() ); | |
6217 | section = static_cast<SectionTracker*>( childTracker ); | |
6218 | } | |
6219 | else { | |
6220 | section = new SectionTracker( nameAndLocation, ctx, ¤tTracker ); | |
6221 | currentTracker.addChild( section ); | |
6222 | } | |
6223 | if( !ctx.completedCycle() ) | |
6224 | section->tryOpen(); | |
6225 | return *section; | |
6226 | } | |
6227 | ||
6228 | void tryOpen() { | |
6229 | if( !isComplete() && (m_filters.empty() || m_filters[0].empty() || m_filters[0] == m_nameAndLocation.name ) ) | |
6230 | open(); | |
6231 | } | |
6232 | ||
6233 | void addInitialFilters( std::vector<std::string> const& filters ) { | |
6234 | if( !filters.empty() ) { | |
6235 | m_filters.push_back(""); // Root - should never be consulted | |
6236 | m_filters.push_back(""); // Test Case - not a section filter | |
6237 | m_filters.insert( m_filters.end(), filters.begin(), filters.end() ); | |
6238 | } | |
6239 | } | |
6240 | void addNextFilters( std::vector<std::string> const& filters ) { | |
6241 | if( filters.size() > 1 ) | |
6242 | m_filters.insert( m_filters.end(), ++filters.begin(), filters.end() ); | |
6243 | } | |
6244 | }; | |
6245 | ||
6246 | class IndexTracker : public TrackerBase { | |
6247 | int m_size; | |
6248 | int m_index; | |
6249 | public: | |
6250 | IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size ) | |
6251 | : TrackerBase( nameAndLocation, ctx, parent ), | |
6252 | m_size( size ), | |
6253 | m_index( -1 ) | |
6254 | {} | |
6255 | virtual ~IndexTracker(); | |
6256 | ||
6257 | virtual bool isIndexTracker() const CATCH_OVERRIDE { return true; } | |
6258 | ||
6259 | static IndexTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ) { | |
6260 | IndexTracker* tracker = CATCH_NULL; | |
6261 | ||
6262 | ITracker& currentTracker = ctx.currentTracker(); | |
6263 | if( ITracker* childTracker = currentTracker.findChild( nameAndLocation ) ) { | |
6264 | assert( childTracker ); | |
6265 | assert( childTracker->isIndexTracker() ); | |
6266 | tracker = static_cast<IndexTracker*>( childTracker ); | |
6267 | } | |
6268 | else { | |
6269 | tracker = new IndexTracker( nameAndLocation, ctx, ¤tTracker, size ); | |
6270 | currentTracker.addChild( tracker ); | |
6271 | } | |
6272 | ||
6273 | if( !ctx.completedCycle() && !tracker->isComplete() ) { | |
6274 | if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun ) | |
6275 | tracker->moveNext(); | |
6276 | tracker->open(); | |
6277 | } | |
6278 | ||
6279 | return *tracker; | |
6280 | } | |
6281 | ||
6282 | int index() const { return m_index; } | |
6283 | ||
6284 | void moveNext() { | |
6285 | m_index++; | |
6286 | m_children.clear(); | |
6287 | } | |
6288 | ||
6289 | virtual void close() CATCH_OVERRIDE { | |
6290 | TrackerBase::close(); | |
6291 | if( m_runState == CompletedSuccessfully && m_index < m_size-1 ) | |
6292 | m_runState = Executing; | |
6293 | } | |
6294 | }; | |
6295 | ||
6296 | inline ITracker& TrackerContext::startRun() { | |
6297 | m_rootTracker = new SectionTracker( NameAndLocation( "{root}", CATCH_INTERNAL_LINEINFO ), *this, CATCH_NULL ); | |
6298 | m_currentTracker = CATCH_NULL; | |
6299 | m_runState = Executing; | |
6300 | return *m_rootTracker; | |
6301 | } | |
6302 | ||
6303 | } // namespace TestCaseTracking | |
6304 | ||
6305 | using TestCaseTracking::ITracker; | |
6306 | using TestCaseTracking::TrackerContext; | |
6307 | using TestCaseTracking::SectionTracker; | |
6308 | using TestCaseTracking::IndexTracker; | |
6309 | ||
6310 | } // namespace Catch | |
6311 | ||
6312 | CATCH_INTERNAL_UNSUPPRESS_ETD_WARNINGS | |
6313 | ||
6314 | // #included from: catch_fatal_condition.hpp | |
6315 | #define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED | |
6316 | ||
6317 | namespace Catch { | |
6318 | ||
6319 | // Report the error condition | |
6320 | inline void reportFatal( std::string const& message ) { | |
6321 | IContext& context = Catch::getCurrentContext(); | |
6322 | IResultCapture* resultCapture = context.getResultCapture(); | |
6323 | resultCapture->handleFatalErrorCondition( message ); | |
6324 | } | |
6325 | ||
6326 | } // namespace Catch | |
6327 | ||
6328 | #if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// | |
6329 | // #included from: catch_windows_h_proxy.h | |
6330 | ||
6331 | #define TWOBLUECUBES_CATCH_WINDOWS_H_PROXY_H_INCLUDED | |
6332 | ||
6333 | #ifdef CATCH_DEFINES_NOMINMAX | |
6334 | # define NOMINMAX | |
6335 | #endif | |
6336 | #ifdef CATCH_DEFINES_WIN32_LEAN_AND_MEAN | |
6337 | # define WIN32_LEAN_AND_MEAN | |
6338 | #endif | |
6339 | ||
6340 | #ifdef __AFXDLL | |
6341 | #include <AfxWin.h> | |
6342 | #else | |
6343 | #include <windows.h> | |
6344 | #endif | |
6345 | ||
6346 | #ifdef CATCH_DEFINES_NOMINMAX | |
6347 | # undef NOMINMAX | |
6348 | #endif | |
6349 | #ifdef CATCH_DEFINES_WIN32_LEAN_AND_MEAN | |
6350 | # undef WIN32_LEAN_AND_MEAN | |
6351 | #endif | |
6352 | ||
6353 | ||
6354 | # if !defined ( CATCH_CONFIG_WINDOWS_SEH ) | |
6355 | ||
6356 | namespace Catch { | |
6357 | struct FatalConditionHandler { | |
6358 | void reset() {} | |
6359 | }; | |
6360 | } | |
6361 | ||
6362 | # else // CATCH_CONFIG_WINDOWS_SEH is defined | |
6363 | ||
6364 | namespace Catch { | |
6365 | ||
6366 | struct SignalDefs { DWORD id; const char* name; }; | |
6367 | extern SignalDefs signalDefs[]; | |
6368 | // There is no 1-1 mapping between signals and windows exceptions. | |
6369 | // Windows can easily distinguish between SO and SigSegV, | |
6370 | // but SigInt, SigTerm, etc are handled differently. | |
6371 | SignalDefs signalDefs[] = { | |
6372 | { EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal" }, | |
6373 | { EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" }, | |
6374 | { EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" }, | |
6375 | { EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" }, | |
6376 | }; | |
6377 | ||
6378 | struct FatalConditionHandler { | |
6379 | ||
6380 | static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) { | |
6381 | for (int i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) { | |
6382 | if (ExceptionInfo->ExceptionRecord->ExceptionCode == signalDefs[i].id) { | |
6383 | reportFatal(signalDefs[i].name); | |
6384 | } | |
6385 | } | |
6386 | // If its not an exception we care about, pass it along. | |
6387 | // This stops us from eating debugger breaks etc. | |
6388 | return EXCEPTION_CONTINUE_SEARCH; | |
6389 | } | |
6390 | ||
6391 | FatalConditionHandler() { | |
6392 | isSet = true; | |
6393 | // 32k seems enough for Catch to handle stack overflow, | |
6394 | // but the value was found experimentally, so there is no strong guarantee | |
6395 | guaranteeSize = 32 * 1024; | |
6396 | exceptionHandlerHandle = CATCH_NULL; | |
6397 | // Register as first handler in current chain | |
6398 | exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException); | |
6399 | // Pass in guarantee size to be filled | |
6400 | SetThreadStackGuarantee(&guaranteeSize); | |
6401 | } | |
6402 | ||
6403 | static void reset() { | |
6404 | if (isSet) { | |
6405 | // Unregister handler and restore the old guarantee | |
6406 | RemoveVectoredExceptionHandler(exceptionHandlerHandle); | |
6407 | SetThreadStackGuarantee(&guaranteeSize); | |
6408 | exceptionHandlerHandle = CATCH_NULL; | |
6409 | isSet = false; | |
6410 | } | |
6411 | } | |
6412 | ||
6413 | ~FatalConditionHandler() { | |
6414 | reset(); | |
6415 | } | |
6416 | private: | |
6417 | static bool isSet; | |
6418 | static ULONG guaranteeSize; | |
6419 | static PVOID exceptionHandlerHandle; | |
6420 | }; | |
6421 | ||
6422 | bool FatalConditionHandler::isSet = false; | |
6423 | ULONG FatalConditionHandler::guaranteeSize = 0; | |
6424 | PVOID FatalConditionHandler::exceptionHandlerHandle = CATCH_NULL; | |
6425 | ||
6426 | } // namespace Catch | |
6427 | ||
6428 | # endif // CATCH_CONFIG_WINDOWS_SEH | |
6429 | ||
6430 | #else // Not Windows - assumed to be POSIX compatible ////////////////////////// | |
6431 | ||
6432 | # if !defined(CATCH_CONFIG_POSIX_SIGNALS) | |
6433 | ||
6434 | namespace Catch { | |
6435 | struct FatalConditionHandler { | |
6436 | void reset() {} | |
6437 | }; | |
6438 | } | |
6439 | ||
6440 | # else // CATCH_CONFIG_POSIX_SIGNALS is defined | |
6441 | ||
6442 | #include <signal.h> | |
6443 | ||
6444 | namespace Catch { | |
6445 | ||
6446 | struct SignalDefs { | |
6447 | int id; | |
6448 | const char* name; | |
6449 | }; | |
6450 | extern SignalDefs signalDefs[]; | |
6451 | SignalDefs signalDefs[] = { | |
6452 | { SIGINT, "SIGINT - Terminal interrupt signal" }, | |
6453 | { SIGILL, "SIGILL - Illegal instruction signal" }, | |
6454 | { SIGFPE, "SIGFPE - Floating point error signal" }, | |
6455 | { SIGSEGV, "SIGSEGV - Segmentation violation signal" }, | |
6456 | { SIGTERM, "SIGTERM - Termination request signal" }, | |
6457 | { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } | |
6458 | }; | |
6459 | ||
6460 | struct FatalConditionHandler { | |
6461 | ||
6462 | static bool isSet; | |
6463 | static struct sigaction oldSigActions [sizeof(signalDefs)/sizeof(SignalDefs)]; | |
6464 | static stack_t oldSigStack; | |
6465 | static char altStackMem[SIGSTKSZ]; | |
6466 | ||
6467 | static void handleSignal( int sig ) { | |
6468 | std::string name = "<unknown signal>"; | |
6469 | for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) { | |
6470 | SignalDefs &def = signalDefs[i]; | |
6471 | if (sig == def.id) { | |
6472 | name = def.name; | |
6473 | break; | |
6474 | } | |
6475 | } | |
6476 | reset(); | |
6477 | reportFatal(name); | |
6478 | raise( sig ); | |
6479 | } | |
6480 | ||
6481 | FatalConditionHandler() { | |
6482 | isSet = true; | |
6483 | stack_t sigStack; | |
6484 | sigStack.ss_sp = altStackMem; | |
6485 | sigStack.ss_size = SIGSTKSZ; | |
6486 | sigStack.ss_flags = 0; | |
6487 | sigaltstack(&sigStack, &oldSigStack); | |
6488 | struct sigaction sa = { 0 }; | |
6489 | ||
6490 | sa.sa_handler = handleSignal; | |
6491 | sa.sa_flags = SA_ONSTACK; | |
6492 | for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) { | |
6493 | sigaction(signalDefs[i].id, &sa, &oldSigActions[i]); | |
6494 | } | |
6495 | } | |
6496 | ||
6497 | ~FatalConditionHandler() { | |
6498 | reset(); | |
6499 | } | |
6500 | static void reset() { | |
6501 | if( isSet ) { | |
6502 | // Set signals back to previous values -- hopefully nobody overwrote them in the meantime | |
6503 | for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) { | |
6504 | sigaction(signalDefs[i].id, &oldSigActions[i], CATCH_NULL); | |
6505 | } | |
6506 | // Return the old stack | |
6507 | sigaltstack(&oldSigStack, CATCH_NULL); | |
6508 | isSet = false; | |
6509 | } | |
6510 | } | |
6511 | }; | |
6512 | ||
6513 | bool FatalConditionHandler::isSet = false; | |
6514 | struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {}; | |
6515 | stack_t FatalConditionHandler::oldSigStack = {}; | |
6516 | char FatalConditionHandler::altStackMem[SIGSTKSZ] = {}; | |
6517 | ||
6518 | } // namespace Catch | |
6519 | ||
6520 | # endif // CATCH_CONFIG_POSIX_SIGNALS | |
6521 | ||
6522 | #endif // not Windows | |
6523 | ||
6524 | #include <set> | |
6525 | #include <string> | |
6526 | ||
6527 | namespace Catch { | |
6528 | ||
6529 | class StreamRedirect { | |
6530 | ||
6531 | public: | |
6532 | StreamRedirect( std::ostream& stream, std::string& targetString ) | |
6533 | : m_stream( stream ), | |
6534 | m_prevBuf( stream.rdbuf() ), | |
6535 | m_targetString( targetString ) | |
6536 | { | |
6537 | stream.rdbuf( m_oss.rdbuf() ); | |
6538 | } | |
6539 | ||
6540 | ~StreamRedirect() { | |
6541 | m_targetString += m_oss.str(); | |
6542 | m_stream.rdbuf( m_prevBuf ); | |
6543 | } | |
6544 | ||
6545 | private: | |
6546 | std::ostream& m_stream; | |
6547 | std::streambuf* m_prevBuf; | |
6548 | std::ostringstream m_oss; | |
6549 | std::string& m_targetString; | |
6550 | }; | |
6551 | ||
6552 | /////////////////////////////////////////////////////////////////////////// | |
6553 | ||
6554 | class RunContext : public IResultCapture, public IRunner { | |
6555 | ||
6556 | RunContext( RunContext const& ); | |
6557 | void operator =( RunContext const& ); | |
6558 | ||
6559 | public: | |
6560 | ||
6561 | explicit RunContext( Ptr<IConfig const> const& _config, Ptr<IStreamingReporter> const& reporter ) | |
6562 | : m_runInfo( _config->name() ), | |
6563 | m_context( getCurrentMutableContext() ), | |
6564 | m_activeTestCase( CATCH_NULL ), | |
6565 | m_config( _config ), | |
6566 | m_reporter( reporter ), | |
6567 | m_shouldReportUnexpected ( true ) | |
6568 | { | |
6569 | m_context.setRunner( this ); | |
6570 | m_context.setConfig( m_config ); | |
6571 | m_context.setResultCapture( this ); | |
6572 | m_reporter->testRunStarting( m_runInfo ); | |
6573 | } | |
6574 | ||
6575 | virtual ~RunContext() { | |
6576 | m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) ); | |
6577 | } | |
6578 | ||
6579 | void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) { | |
6580 | m_reporter->testGroupStarting( GroupInfo( testSpec, groupIndex, groupsCount ) ); | |
6581 | } | |
6582 | void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ) { | |
6583 | m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec, groupIndex, groupsCount ), totals, aborting() ) ); | |
6584 | } | |
6585 | ||
6586 | Totals runTest( TestCase const& testCase ) { | |
6587 | Totals prevTotals = m_totals; | |
6588 | ||
6589 | std::string redirectedCout; | |
6590 | std::string redirectedCerr; | |
6591 | ||
6592 | TestCaseInfo testInfo = testCase.getTestCaseInfo(); | |
6593 | ||
6594 | m_reporter->testCaseStarting( testInfo ); | |
6595 | ||
6596 | m_activeTestCase = &testCase; | |
6597 | ||
6598 | do { | |
6599 | ITracker& rootTracker = m_trackerContext.startRun(); | |
6600 | assert( rootTracker.isSectionTracker() ); | |
6601 | static_cast<SectionTracker&>( rootTracker ).addInitialFilters( m_config->getSectionsToRun() ); | |
6602 | do { | |
6603 | m_trackerContext.startCycle(); | |
6604 | m_testCaseTracker = &SectionTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( testInfo.name, testInfo.lineInfo ) ); | |
6605 | runCurrentTest( redirectedCout, redirectedCerr ); | |
6606 | } | |
6607 | while( !m_testCaseTracker->isSuccessfullyCompleted() && !aborting() ); | |
6608 | } | |
6609 | // !TBD: deprecated - this will be replaced by indexed trackers | |
6610 | while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() ); | |
6611 | ||
6612 | Totals deltaTotals = m_totals.delta( prevTotals ); | |
6613 | if( testInfo.expectedToFail() && deltaTotals.testCases.passed > 0 ) { | |
6614 | deltaTotals.assertions.failed++; | |
6615 | deltaTotals.testCases.passed--; | |
6616 | deltaTotals.testCases.failed++; | |
6617 | } | |
6618 | m_totals.testCases += deltaTotals.testCases; | |
6619 | m_reporter->testCaseEnded( TestCaseStats( testInfo, | |
6620 | deltaTotals, | |
6621 | redirectedCout, | |
6622 | redirectedCerr, | |
6623 | aborting() ) ); | |
6624 | ||
6625 | m_activeTestCase = CATCH_NULL; | |
6626 | m_testCaseTracker = CATCH_NULL; | |
6627 | ||
6628 | return deltaTotals; | |
6629 | } | |
6630 | ||
6631 | Ptr<IConfig const> config() const { | |
6632 | return m_config; | |
6633 | } | |
6634 | ||
6635 | private: // IResultCapture | |
6636 | ||
6637 | virtual void assertionEnded( AssertionResult const& result ) { | |
6638 | if( result.getResultType() == ResultWas::Ok ) { | |
6639 | m_totals.assertions.passed++; | |
6640 | } | |
6641 | else if( !result.isOk() ) { | |
6642 | m_totals.assertions.failed++; | |
6643 | } | |
6644 | ||
6645 | // We have no use for the return value (whether messages should be cleared), because messages were made scoped | |
6646 | // and should be let to clear themselves out. | |
6647 | static_cast<void>(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals))); | |
6648 | ||
6649 | // Reset working state | |
6650 | m_lastAssertionInfo = AssertionInfo( std::string(), m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition ); | |
6651 | m_lastResult = result; | |
6652 | } | |
6653 | ||
6654 | virtual bool sectionStarted ( | |
6655 | SectionInfo const& sectionInfo, | |
6656 | Counts& assertions | |
6657 | ) | |
6658 | { | |
6659 | ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( sectionInfo.name, sectionInfo.lineInfo ) ); | |
6660 | if( !sectionTracker.isOpen() ) | |
6661 | return false; | |
6662 | m_activeSections.push_back( §ionTracker ); | |
6663 | ||
6664 | m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; | |
6665 | ||
6666 | m_reporter->sectionStarting( sectionInfo ); | |
6667 | ||
6668 | assertions = m_totals.assertions; | |
6669 | ||
6670 | return true; | |
6671 | } | |
6672 | bool testForMissingAssertions( Counts& assertions ) { | |
6673 | if( assertions.total() != 0 ) | |
6674 | return false; | |
6675 | if( !m_config->warnAboutMissingAssertions() ) | |
6676 | return false; | |
6677 | if( m_trackerContext.currentTracker().hasChildren() ) | |
6678 | return false; | |
6679 | m_totals.assertions.failed++; | |
6680 | assertions.failed++; | |
6681 | return true; | |
6682 | } | |
6683 | ||
6684 | virtual void sectionEnded( SectionEndInfo const& endInfo ) { | |
6685 | Counts assertions = m_totals.assertions - endInfo.prevAssertions; | |
6686 | bool missingAssertions = testForMissingAssertions( assertions ); | |
6687 | ||
6688 | if( !m_activeSections.empty() ) { | |
6689 | m_activeSections.back()->close(); | |
6690 | m_activeSections.pop_back(); | |
6691 | } | |
6692 | ||
6693 | m_reporter->sectionEnded( SectionStats( endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions ) ); | |
6694 | m_messages.clear(); | |
6695 | } | |
6696 | ||
6697 | virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) { | |
6698 | if( m_unfinishedSections.empty() ) | |
6699 | m_activeSections.back()->fail(); | |
6700 | else | |
6701 | m_activeSections.back()->close(); | |
6702 | m_activeSections.pop_back(); | |
6703 | ||
6704 | m_unfinishedSections.push_back( endInfo ); | |
6705 | } | |
6706 | ||
6707 | virtual void pushScopedMessage( MessageInfo const& message ) { | |
6708 | m_messages.push_back( message ); | |
6709 | } | |
6710 | ||
6711 | virtual void popScopedMessage( MessageInfo const& message ) { | |
6712 | m_messages.erase( std::remove( m_messages.begin(), m_messages.end(), message ), m_messages.end() ); | |
6713 | } | |
6714 | ||
6715 | virtual std::string getCurrentTestName() const { | |
6716 | return m_activeTestCase | |
6717 | ? m_activeTestCase->getTestCaseInfo().name | |
6718 | : std::string(); | |
6719 | } | |
6720 | ||
6721 | virtual const AssertionResult* getLastResult() const { | |
6722 | return &m_lastResult; | |
6723 | } | |
6724 | ||
6725 | virtual void exceptionEarlyReported() { | |
6726 | m_shouldReportUnexpected = false; | |
6727 | } | |
6728 | ||
6729 | virtual void handleFatalErrorCondition( std::string const& message ) { | |
6730 | // Don't rebuild the result -- the stringification itself can cause more fatal errors | |
6731 | // Instead, fake a result data. | |
6732 | AssertionResultData tempResult; | |
6733 | tempResult.resultType = ResultWas::FatalErrorCondition; | |
6734 | tempResult.message = message; | |
6735 | AssertionResult result(m_lastAssertionInfo, tempResult); | |
6736 | ||
6737 | getResultCapture().assertionEnded(result); | |
6738 | ||
6739 | handleUnfinishedSections(); | |
6740 | ||
6741 | // Recreate section for test case (as we will lose the one that was in scope) | |
6742 | TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); | |
6743 | SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); | |
6744 | ||
6745 | Counts assertions; | |
6746 | assertions.failed = 1; | |
6747 | SectionStats testCaseSectionStats( testCaseSection, assertions, 0, false ); | |
6748 | m_reporter->sectionEnded( testCaseSectionStats ); | |
6749 | ||
6750 | TestCaseInfo testInfo = m_activeTestCase->getTestCaseInfo(); | |
6751 | ||
6752 | Totals deltaTotals; | |
6753 | deltaTotals.testCases.failed = 1; | |
6754 | m_reporter->testCaseEnded( TestCaseStats( testInfo, | |
6755 | deltaTotals, | |
6756 | std::string(), | |
6757 | std::string(), | |
6758 | false ) ); | |
6759 | m_totals.testCases.failed++; | |
6760 | testGroupEnded( std::string(), m_totals, 1, 1 ); | |
6761 | m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, false ) ); | |
6762 | } | |
6763 | ||
6764 | public: | |
6765 | // !TBD We need to do this another way! | |
6766 | bool aborting() const { | |
6767 | return m_totals.assertions.failed == static_cast<std::size_t>( m_config->abortAfter() ); | |
6768 | } | |
6769 | ||
6770 | private: | |
6771 | ||
6772 | void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) { | |
6773 | TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); | |
6774 | SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); | |
6775 | m_reporter->sectionStarting( testCaseSection ); | |
6776 | Counts prevAssertions = m_totals.assertions; | |
6777 | double duration = 0; | |
6778 | m_shouldReportUnexpected = true; | |
6779 | try { | |
6780 | m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, std::string(), ResultDisposition::Normal ); | |
6781 | ||
6782 | seedRng( *m_config ); | |
6783 | ||
6784 | Timer timer; | |
6785 | timer.start(); | |
6786 | if( m_reporter->getPreferences().shouldRedirectStdOut ) { | |
6787 | StreamRedirect coutRedir( Catch::cout(), redirectedCout ); | |
6788 | StreamRedirect cerrRedir( Catch::cerr(), redirectedCerr ); | |
6789 | invokeActiveTestCase(); | |
6790 | } | |
6791 | else { | |
6792 | invokeActiveTestCase(); | |
6793 | } | |
6794 | duration = timer.getElapsedSeconds(); | |
6795 | } | |
6796 | catch( TestFailureException& ) { | |
6797 | // This just means the test was aborted due to failure | |
6798 | } | |
6799 | catch(...) { | |
6800 | // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions | |
6801 | // are reported without translation at the point of origin. | |
6802 | if (m_shouldReportUnexpected) { | |
6803 | makeUnexpectedResultBuilder().useActiveException(); | |
6804 | } | |
6805 | } | |
6806 | m_testCaseTracker->close(); | |
6807 | handleUnfinishedSections(); | |
6808 | m_messages.clear(); | |
6809 | ||
6810 | Counts assertions = m_totals.assertions - prevAssertions; | |
6811 | bool missingAssertions = testForMissingAssertions( assertions ); | |
6812 | ||
6813 | if( testCaseInfo.okToFail() ) { | |
6814 | std::swap( assertions.failedButOk, assertions.failed ); | |
6815 | m_totals.assertions.failed -= assertions.failedButOk; | |
6816 | m_totals.assertions.failedButOk += assertions.failedButOk; | |
6817 | } | |
6818 | ||
6819 | SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions ); | |
6820 | m_reporter->sectionEnded( testCaseSectionStats ); | |
6821 | } | |
6822 | ||
6823 | void invokeActiveTestCase() { | |
6824 | FatalConditionHandler fatalConditionHandler; // Handle signals | |
6825 | m_activeTestCase->invoke(); | |
6826 | fatalConditionHandler.reset(); | |
6827 | } | |
6828 | ||
6829 | private: | |
6830 | ||
6831 | ResultBuilder makeUnexpectedResultBuilder() const { | |
6832 | return ResultBuilder( m_lastAssertionInfo.macroName.c_str(), | |
6833 | m_lastAssertionInfo.lineInfo, | |
6834 | m_lastAssertionInfo.capturedExpression.c_str(), | |
6835 | m_lastAssertionInfo.resultDisposition ); | |
6836 | } | |
6837 | ||
6838 | void handleUnfinishedSections() { | |
6839 | // If sections ended prematurely due to an exception we stored their | |
6840 | // infos here so we can tear them down outside the unwind process. | |
6841 | for( std::vector<SectionEndInfo>::const_reverse_iterator it = m_unfinishedSections.rbegin(), | |
6842 | itEnd = m_unfinishedSections.rend(); | |
6843 | it != itEnd; | |
6844 | ++it ) | |
6845 | sectionEnded( *it ); | |
6846 | m_unfinishedSections.clear(); | |
6847 | } | |
6848 | ||
6849 | TestRunInfo m_runInfo; | |
6850 | IMutableContext& m_context; | |
6851 | TestCase const* m_activeTestCase; | |
6852 | ITracker* m_testCaseTracker; | |
6853 | ITracker* m_currentSectionTracker; | |
6854 | AssertionResult m_lastResult; | |
6855 | ||
6856 | Ptr<IConfig const> m_config; | |
6857 | Totals m_totals; | |
6858 | Ptr<IStreamingReporter> m_reporter; | |
6859 | std::vector<MessageInfo> m_messages; | |
6860 | AssertionInfo m_lastAssertionInfo; | |
6861 | std::vector<SectionEndInfo> m_unfinishedSections; | |
6862 | std::vector<ITracker*> m_activeSections; | |
6863 | TrackerContext m_trackerContext; | |
6864 | bool m_shouldReportUnexpected; | |
6865 | }; | |
6866 | ||
6867 | IResultCapture& getResultCapture() { | |
6868 | if( IResultCapture* capture = getCurrentContext().getResultCapture() ) | |
6869 | return *capture; | |
6870 | else | |
6871 | throw std::logic_error( "No result capture instance" ); | |
6872 | } | |
6873 | ||
6874 | } // end namespace Catch | |
6875 | ||
6876 | // #included from: internal/catch_version.h | |
6877 | #define TWOBLUECUBES_CATCH_VERSION_H_INCLUDED | |
6878 | ||
6879 | namespace Catch { | |
6880 | ||
6881 | // Versioning information | |
6882 | struct Version { | |
6883 | Version( unsigned int _majorVersion, | |
6884 | unsigned int _minorVersion, | |
6885 | unsigned int _patchNumber, | |
6886 | char const * const _branchName, | |
6887 | unsigned int _buildNumber ); | |
6888 | ||
6889 | unsigned int const majorVersion; | |
6890 | unsigned int const minorVersion; | |
6891 | unsigned int const patchNumber; | |
6892 | ||
6893 | // buildNumber is only used if branchName is not null | |
6894 | char const * const branchName; | |
6895 | unsigned int const buildNumber; | |
6896 | ||
6897 | friend std::ostream& operator << ( std::ostream& os, Version const& version ); | |
6898 | ||
6899 | private: | |
6900 | void operator=( Version const& ); | |
6901 | }; | |
6902 | ||
6903 | inline Version libraryVersion(); | |
6904 | } | |
6905 | ||
6906 | #include <fstream> | |
6907 | #include <stdlib.h> | |
6908 | #include <limits> | |
6909 | ||
6910 | namespace Catch { | |
6911 | ||
6912 | Ptr<IStreamingReporter> createReporter( std::string const& reporterName, Ptr<Config> const& config ) { | |
6913 | Ptr<IStreamingReporter> reporter = getRegistryHub().getReporterRegistry().create( reporterName, config.get() ); | |
6914 | if( !reporter ) { | |
6915 | std::ostringstream oss; | |
6916 | oss << "No reporter registered with name: '" << reporterName << "'"; | |
6917 | throw std::domain_error( oss.str() ); | |
6918 | } | |
6919 | return reporter; | |
6920 | } | |
6921 | ||
6922 | Ptr<IStreamingReporter> makeReporter( Ptr<Config> const& config ) { | |
6923 | std::vector<std::string> reporters = config->getReporterNames(); | |
6924 | if( reporters.empty() ) | |
6925 | reporters.push_back( "console" ); | |
6926 | ||
6927 | Ptr<IStreamingReporter> reporter; | |
6928 | for( std::vector<std::string>::const_iterator it = reporters.begin(), itEnd = reporters.end(); | |
6929 | it != itEnd; | |
6930 | ++it ) | |
6931 | reporter = addReporter( reporter, createReporter( *it, config ) ); | |
6932 | return reporter; | |
6933 | } | |
6934 | Ptr<IStreamingReporter> addListeners( Ptr<IConfig const> const& config, Ptr<IStreamingReporter> reporters ) { | |
6935 | IReporterRegistry::Listeners listeners = getRegistryHub().getReporterRegistry().getListeners(); | |
6936 | for( IReporterRegistry::Listeners::const_iterator it = listeners.begin(), itEnd = listeners.end(); | |
6937 | it != itEnd; | |
6938 | ++it ) | |
6939 | reporters = addReporter(reporters, (*it)->create( ReporterConfig( config ) ) ); | |
6940 | return reporters; | |
6941 | } | |
6942 | ||
6943 | Totals runTests( Ptr<Config> const& config ) { | |
6944 | ||
6945 | Ptr<IConfig const> iconfig = config.get(); | |
6946 | ||
6947 | Ptr<IStreamingReporter> reporter = makeReporter( config ); | |
6948 | reporter = addListeners( iconfig, reporter ); | |
6949 | ||
6950 | RunContext context( iconfig, reporter ); | |
6951 | ||
6952 | Totals totals; | |
6953 | ||
6954 | context.testGroupStarting( config->name(), 1, 1 ); | |
6955 | ||
6956 | TestSpec testSpec = config->testSpec(); | |
6957 | if( !testSpec.hasFilters() ) | |
6958 | testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests | |
6959 | ||
6960 | std::vector<TestCase> const& allTestCases = getAllTestCasesSorted( *iconfig ); | |
6961 | for( std::vector<TestCase>::const_iterator it = allTestCases.begin(), itEnd = allTestCases.end(); | |
6962 | it != itEnd; | |
6963 | ++it ) { | |
6964 | if( !context.aborting() && matchTest( *it, testSpec, *iconfig ) ) | |
6965 | totals += context.runTest( *it ); | |
6966 | else | |
6967 | reporter->skipTest( *it ); | |
6968 | } | |
6969 | ||
6970 | context.testGroupEnded( iconfig->name(), totals, 1, 1 ); | |
6971 | return totals; | |
6972 | } | |
6973 | ||
6974 | void applyFilenamesAsTags( IConfig const& config ) { | |
6975 | std::vector<TestCase> const& tests = getAllTestCasesSorted( config ); | |
6976 | for(std::size_t i = 0; i < tests.size(); ++i ) { | |
6977 | TestCase& test = const_cast<TestCase&>( tests[i] ); | |
6978 | std::set<std::string> tags = test.tags; | |
6979 | ||
6980 | std::string filename = test.lineInfo.file; | |
6981 | std::string::size_type lastSlash = filename.find_last_of( "\\/" ); | |
6982 | if( lastSlash != std::string::npos ) | |
6983 | filename = filename.substr( lastSlash+1 ); | |
6984 | ||
6985 | std::string::size_type lastDot = filename.find_last_of( "." ); | |
6986 | if( lastDot != std::string::npos ) | |
6987 | filename = filename.substr( 0, lastDot ); | |
6988 | ||
6989 | tags.insert( "#" + filename ); | |
6990 | setTags( test, tags ); | |
6991 | } | |
6992 | } | |
6993 | ||
6994 | class Session : NonCopyable { | |
6995 | static bool alreadyInstantiated; | |
6996 | ||
6997 | public: | |
6998 | ||
6999 | struct OnUnusedOptions { enum DoWhat { Ignore, Fail }; }; | |
7000 | ||
7001 | Session() | |
7002 | : m_cli( makeCommandLineParser() ) { | |
7003 | if( alreadyInstantiated ) { | |
7004 | std::string msg = "Only one instance of Catch::Session can ever be used"; | |
7005 | Catch::cerr() << msg << std::endl; | |
7006 | throw std::logic_error( msg ); | |
7007 | } | |
7008 | alreadyInstantiated = true; | |
7009 | } | |
7010 | ~Session() { | |
7011 | Catch::cleanUp(); | |
7012 | } | |
7013 | ||
7014 | void showHelp( std::string const& processName ) { | |
7015 | Catch::cout() << "\nCatch v" << libraryVersion() << "\n"; | |
7016 | ||
7017 | m_cli.usage( Catch::cout(), processName ); | |
7018 | Catch::cout() << "For more detail usage please see the project docs\n" << std::endl; | |
7019 | } | |
7020 | ||
7021 | int applyCommandLine( int argc, char const* const* const argv, OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { | |
7022 | try { | |
7023 | m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail ); | |
7024 | m_unusedTokens = m_cli.parseInto( Clara::argsToVector( argc, argv ), m_configData ); | |
7025 | if( m_configData.showHelp ) | |
7026 | showHelp( m_configData.processName ); | |
7027 | m_config.reset(); | |
7028 | } | |
7029 | catch( std::exception& ex ) { | |
7030 | { | |
7031 | Colour colourGuard( Colour::Red ); | |
7032 | Catch::cerr() | |
7033 | << "\nError(s) in input:\n" | |
7034 | << Text( ex.what(), TextAttributes().setIndent(2) ) | |
7035 | << "\n\n"; | |
7036 | } | |
7037 | m_cli.usage( Catch::cout(), m_configData.processName ); | |
7038 | return (std::numeric_limits<int>::max)(); | |
7039 | } | |
7040 | return 0; | |
7041 | } | |
7042 | ||
7043 | void useConfigData( ConfigData const& _configData ) { | |
7044 | m_configData = _configData; | |
7045 | m_config.reset(); | |
7046 | } | |
7047 | ||
7048 | int run( int argc, char const* const* const argv ) { | |
7049 | ||
7050 | int returnCode = applyCommandLine( argc, argv ); | |
7051 | if( returnCode == 0 ) | |
7052 | returnCode = run(); | |
7053 | return returnCode; | |
7054 | } | |
7055 | ||
7056 | #if defined(WIN32) && defined(UNICODE) | |
7057 | int run( int argc, wchar_t const* const* const argv ) { | |
7058 | ||
7059 | char **utf8Argv = new char *[ argc ]; | |
7060 | ||
7061 | for ( int i = 0; i < argc; ++i ) { | |
7062 | int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL ); | |
7063 | ||
7064 | utf8Argv[ i ] = new char[ bufSize ]; | |
7065 | ||
7066 | WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL ); | |
7067 | } | |
7068 | ||
7069 | int returnCode = applyCommandLine( argc, utf8Argv ); | |
7070 | if( returnCode == 0 ) | |
7071 | returnCode = run(); | |
7072 | ||
7073 | for ( int i = 0; i < argc; ++i ) | |
7074 | delete [] utf8Argv[ i ]; | |
7075 | ||
7076 | delete [] utf8Argv; | |
7077 | ||
7078 | return returnCode; | |
7079 | } | |
7080 | #endif | |
7081 | ||
7082 | int run() { | |
7083 | if( m_configData.showHelp ) | |
7084 | return 0; | |
7085 | ||
7086 | try | |
7087 | { | |
7088 | config(); // Force config to be constructed | |
7089 | ||
7090 | seedRng( *m_config ); | |
7091 | ||
7092 | if( m_configData.filenamesAsTags ) | |
7093 | applyFilenamesAsTags( *m_config ); | |
7094 | ||
7095 | // Handle list request | |
7096 | if( Option<std::size_t> listed = list( config() ) ) | |
7097 | return static_cast<int>( *listed ); | |
7098 | ||
7099 | return static_cast<int>( runTests( m_config ).assertions.failed ); | |
7100 | } | |
7101 | catch( std::exception& ex ) { | |
7102 | Catch::cerr() << ex.what() << std::endl; | |
7103 | return (std::numeric_limits<int>::max)(); | |
7104 | } | |
7105 | } | |
7106 | ||
7107 | Clara::CommandLine<ConfigData> const& cli() const { | |
7108 | return m_cli; | |
7109 | } | |
7110 | std::vector<Clara::Parser::Token> const& unusedTokens() const { | |
7111 | return m_unusedTokens; | |
7112 | } | |
7113 | ConfigData& configData() { | |
7114 | return m_configData; | |
7115 | } | |
7116 | Config& config() { | |
7117 | if( !m_config ) | |
7118 | m_config = new Config( m_configData ); | |
7119 | return *m_config; | |
7120 | } | |
7121 | private: | |
7122 | Clara::CommandLine<ConfigData> m_cli; | |
7123 | std::vector<Clara::Parser::Token> m_unusedTokens; | |
7124 | ConfigData m_configData; | |
7125 | Ptr<Config> m_config; | |
7126 | }; | |
7127 | ||
7128 | bool Session::alreadyInstantiated = false; | |
7129 | ||
7130 | } // end namespace Catch | |
7131 | ||
7132 | // #included from: catch_registry_hub.hpp | |
7133 | #define TWOBLUECUBES_CATCH_REGISTRY_HUB_HPP_INCLUDED | |
7134 | ||
7135 | // #included from: catch_test_case_registry_impl.hpp | |
7136 | #define TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED | |
7137 | ||
7138 | #include <vector> | |
7139 | #include <set> | |
7140 | #include <sstream> | |
7141 | #include <algorithm> | |
7142 | ||
7143 | namespace Catch { | |
7144 | ||
7145 | struct RandomNumberGenerator { | |
7146 | typedef std::ptrdiff_t result_type; | |
7147 | ||
7148 | result_type operator()( result_type n ) const { return std::rand() % n; } | |
7149 | ||
7150 | #ifdef CATCH_CONFIG_CPP11_SHUFFLE | |
7151 | static constexpr result_type min() { return 0; } | |
7152 | static constexpr result_type max() { return 1000000; } | |
7153 | result_type operator()() const { return std::rand() % max(); } | |
7154 | #endif | |
7155 | template<typename V> | |
7156 | static void shuffle( V& vector ) { | |
7157 | RandomNumberGenerator rng; | |
7158 | #ifdef CATCH_CONFIG_CPP11_SHUFFLE | |
7159 | std::shuffle( vector.begin(), vector.end(), rng ); | |
7160 | #else | |
7161 | std::random_shuffle( vector.begin(), vector.end(), rng ); | |
7162 | #endif | |
7163 | } | |
7164 | }; | |
7165 | ||
7166 | inline std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) { | |
7167 | ||
7168 | std::vector<TestCase> sorted = unsortedTestCases; | |
7169 | ||
7170 | switch( config.runOrder() ) { | |
7171 | case RunTests::InLexicographicalOrder: | |
7172 | std::sort( sorted.begin(), sorted.end() ); | |
7173 | break; | |
7174 | case RunTests::InRandomOrder: | |
7175 | { | |
7176 | seedRng( config ); | |
7177 | RandomNumberGenerator::shuffle( sorted ); | |
7178 | } | |
7179 | break; | |
7180 | case RunTests::InDeclarationOrder: | |
7181 | // already in declaration order | |
7182 | break; | |
7183 | } | |
7184 | return sorted; | |
7185 | } | |
7186 | bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) { | |
7187 | return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() ); | |
7188 | } | |
7189 | ||
7190 | void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions ) { | |
7191 | std::set<TestCase> seenFunctions; | |
7192 | for( std::vector<TestCase>::const_iterator it = functions.begin(), itEnd = functions.end(); | |
7193 | it != itEnd; | |
7194 | ++it ) { | |
7195 | std::pair<std::set<TestCase>::const_iterator, bool> prev = seenFunctions.insert( *it ); | |
7196 | if( !prev.second ) { | |
7197 | std::ostringstream ss; | |
7198 | ||
7199 | ss << Colour( Colour::Red ) | |
7200 | << "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n" | |
7201 | << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << '\n' | |
7202 | << "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl; | |
7203 | ||
7204 | throw std::runtime_error(ss.str()); | |
7205 | } | |
7206 | } | |
7207 | } | |
7208 | ||
7209 | std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ) { | |
7210 | std::vector<TestCase> filtered; | |
7211 | filtered.reserve( testCases.size() ); | |
7212 | for( std::vector<TestCase>::const_iterator it = testCases.begin(), itEnd = testCases.end(); | |
7213 | it != itEnd; | |
7214 | ++it ) | |
7215 | if( matchTest( *it, testSpec, config ) ) | |
7216 | filtered.push_back( *it ); | |
7217 | return filtered; | |
7218 | } | |
7219 | std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ) { | |
7220 | return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config ); | |
7221 | } | |
7222 | ||
7223 | class TestRegistry : public ITestCaseRegistry { | |
7224 | public: | |
7225 | TestRegistry() | |
7226 | : m_currentSortOrder( RunTests::InDeclarationOrder ), | |
7227 | m_unnamedCount( 0 ) | |
7228 | {} | |
7229 | virtual ~TestRegistry(); | |
7230 | ||
7231 | virtual void registerTest( TestCase const& testCase ) { | |
7232 | std::string name = testCase.getTestCaseInfo().name; | |
7233 | if( name.empty() ) { | |
7234 | std::ostringstream oss; | |
7235 | oss << "Anonymous test case " << ++m_unnamedCount; | |
7236 | return registerTest( testCase.withName( oss.str() ) ); | |
7237 | } | |
7238 | m_functions.push_back( testCase ); | |
7239 | } | |
7240 | ||
7241 | virtual std::vector<TestCase> const& getAllTests() const { | |
7242 | return m_functions; | |
7243 | } | |
7244 | virtual std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const { | |
7245 | if( m_sortedFunctions.empty() ) | |
7246 | enforceNoDuplicateTestCases( m_functions ); | |
7247 | ||
7248 | if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) { | |
7249 | m_sortedFunctions = sortTests( config, m_functions ); | |
7250 | m_currentSortOrder = config.runOrder(); | |
7251 | } | |
7252 | return m_sortedFunctions; | |
7253 | } | |
7254 | ||
7255 | private: | |
7256 | std::vector<TestCase> m_functions; | |
7257 | mutable RunTests::InWhatOrder m_currentSortOrder; | |
7258 | mutable std::vector<TestCase> m_sortedFunctions; | |
7259 | size_t m_unnamedCount; | |
7260 | std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised | |
7261 | }; | |
7262 | ||
7263 | /////////////////////////////////////////////////////////////////////////// | |
7264 | ||
7265 | class FreeFunctionTestCase : public SharedImpl<ITestCase> { | |
7266 | public: | |
7267 | ||
7268 | FreeFunctionTestCase( TestFunction fun ) : m_fun( fun ) {} | |
7269 | ||
7270 | virtual void invoke() const { | |
7271 | m_fun(); | |
7272 | } | |
7273 | ||
7274 | private: | |
7275 | virtual ~FreeFunctionTestCase(); | |
7276 | ||
7277 | TestFunction m_fun; | |
7278 | }; | |
7279 | ||
7280 | inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) { | |
7281 | std::string className = classOrQualifiedMethodName; | |
7282 | if( startsWith( className, '&' ) ) | |
7283 | { | |
7284 | std::size_t lastColons = className.rfind( "::" ); | |
7285 | std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); | |
7286 | if( penultimateColons == std::string::npos ) | |
7287 | penultimateColons = 1; | |
7288 | className = className.substr( penultimateColons, lastColons-penultimateColons ); | |
7289 | } | |
7290 | return className; | |
7291 | } | |
7292 | ||
7293 | void registerTestCase | |
7294 | ( ITestCase* testCase, | |
7295 | char const* classOrQualifiedMethodName, | |
7296 | NameAndDesc const& nameAndDesc, | |
7297 | SourceLineInfo const& lineInfo ) { | |
7298 | ||
7299 | getMutableRegistryHub().registerTest | |
7300 | ( makeTestCase | |
7301 | ( testCase, | |
7302 | extractClassName( classOrQualifiedMethodName ), | |
7303 | nameAndDesc.name, | |
7304 | nameAndDesc.description, | |
7305 | lineInfo ) ); | |
7306 | } | |
7307 | void registerTestCaseFunction | |
7308 | ( TestFunction function, | |
7309 | SourceLineInfo const& lineInfo, | |
7310 | NameAndDesc const& nameAndDesc ) { | |
7311 | registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo ); | |
7312 | } | |
7313 | ||
7314 | /////////////////////////////////////////////////////////////////////////// | |
7315 | ||
7316 | AutoReg::AutoReg | |
7317 | ( TestFunction function, | |
7318 | SourceLineInfo const& lineInfo, | |
7319 | NameAndDesc const& nameAndDesc ) { | |
7320 | registerTestCaseFunction( function, lineInfo, nameAndDesc ); | |
7321 | } | |
7322 | ||
7323 | AutoReg::~AutoReg() {} | |
7324 | ||
7325 | } // end namespace Catch | |
7326 | ||
7327 | // #included from: catch_reporter_registry.hpp | |
7328 | #define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED | |
7329 | ||
7330 | #include <map> | |
7331 | ||
7332 | namespace Catch { | |
7333 | ||
7334 | class ReporterRegistry : public IReporterRegistry { | |
7335 | ||
7336 | public: | |
7337 | ||
7338 | virtual ~ReporterRegistry() CATCH_OVERRIDE {} | |
7339 | ||
7340 | virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig const> const& config ) const CATCH_OVERRIDE { | |
7341 | FactoryMap::const_iterator it = m_factories.find( name ); | |
7342 | if( it == m_factories.end() ) | |
7343 | return CATCH_NULL; | |
7344 | return it->second->create( ReporterConfig( config ) ); | |
7345 | } | |
7346 | ||
7347 | void registerReporter( std::string const& name, Ptr<IReporterFactory> const& factory ) { | |
7348 | m_factories.insert( std::make_pair( name, factory ) ); | |
7349 | } | |
7350 | void registerListener( Ptr<IReporterFactory> const& factory ) { | |
7351 | m_listeners.push_back( factory ); | |
7352 | } | |
7353 | ||
7354 | virtual FactoryMap const& getFactories() const CATCH_OVERRIDE { | |
7355 | return m_factories; | |
7356 | } | |
7357 | virtual Listeners const& getListeners() const CATCH_OVERRIDE { | |
7358 | return m_listeners; | |
7359 | } | |
7360 | ||
7361 | private: | |
7362 | FactoryMap m_factories; | |
7363 | Listeners m_listeners; | |
7364 | }; | |
7365 | } | |
7366 | ||
7367 | // #included from: catch_exception_translator_registry.hpp | |
7368 | #define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED | |
7369 | ||
7370 | #ifdef __OBJC__ | |
7371 | #import "Foundation/Foundation.h" | |
7372 | #endif | |
7373 | ||
7374 | namespace Catch { | |
7375 | ||
7376 | class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { | |
7377 | public: | |
7378 | ~ExceptionTranslatorRegistry() { | |
7379 | deleteAll( m_translators ); | |
7380 | } | |
7381 | ||
7382 | virtual void registerTranslator( const IExceptionTranslator* translator ) { | |
7383 | m_translators.push_back( translator ); | |
7384 | } | |
7385 | ||
7386 | virtual std::string translateActiveException() const { | |
7387 | try { | |
7388 | #ifdef __OBJC__ | |
7389 | // In Objective-C try objective-c exceptions first | |
7390 | @try { | |
7391 | return tryTranslators(); | |
7392 | } | |
7393 | @catch (NSException *exception) { | |
7394 | return Catch::toString( [exception description] ); | |
7395 | } | |
7396 | #else | |
7397 | return tryTranslators(); | |
7398 | #endif | |
7399 | } | |
7400 | catch( TestFailureException& ) { | |
7401 | throw; | |
7402 | } | |
7403 | catch( std::exception& ex ) { | |
7404 | return ex.what(); | |
7405 | } | |
7406 | catch( std::string& msg ) { | |
7407 | return msg; | |
7408 | } | |
7409 | catch( const char* msg ) { | |
7410 | return msg; | |
7411 | } | |
7412 | catch(...) { | |
7413 | return "Unknown exception"; | |
7414 | } | |
7415 | } | |
7416 | ||
7417 | std::string tryTranslators() const { | |
7418 | if( m_translators.empty() ) | |
7419 | throw; | |
7420 | else | |
7421 | return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() ); | |
7422 | } | |
7423 | ||
7424 | private: | |
7425 | std::vector<const IExceptionTranslator*> m_translators; | |
7426 | }; | |
7427 | } | |
7428 | ||
7429 | // #included from: catch_tag_alias_registry.h | |
7430 | #define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_H_INCLUDED | |
7431 | ||
7432 | #include <map> | |
7433 | ||
7434 | namespace Catch { | |
7435 | ||
7436 | class TagAliasRegistry : public ITagAliasRegistry { | |
7437 | public: | |
7438 | virtual ~TagAliasRegistry(); | |
7439 | virtual Option<TagAlias> find( std::string const& alias ) const; | |
7440 | virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const; | |
7441 | void add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ); | |
7442 | ||
7443 | private: | |
7444 | std::map<std::string, TagAlias> m_registry; | |
7445 | }; | |
7446 | ||
7447 | } // end namespace Catch | |
7448 | ||
7449 | namespace Catch { | |
7450 | ||
7451 | namespace { | |
7452 | ||
7453 | class RegistryHub : public IRegistryHub, public IMutableRegistryHub { | |
7454 | ||
7455 | RegistryHub( RegistryHub const& ); | |
7456 | void operator=( RegistryHub const& ); | |
7457 | ||
7458 | public: // IRegistryHub | |
7459 | RegistryHub() { | |
7460 | } | |
7461 | virtual IReporterRegistry const& getReporterRegistry() const CATCH_OVERRIDE { | |
7462 | return m_reporterRegistry; | |
7463 | } | |
7464 | virtual ITestCaseRegistry const& getTestCaseRegistry() const CATCH_OVERRIDE { | |
7465 | return m_testCaseRegistry; | |
7466 | } | |
7467 | virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() CATCH_OVERRIDE { | |
7468 | return m_exceptionTranslatorRegistry; | |
7469 | } | |
7470 | virtual ITagAliasRegistry const& getTagAliasRegistry() const CATCH_OVERRIDE { | |
7471 | return m_tagAliasRegistry; | |
7472 | } | |
7473 | ||
7474 | public: // IMutableRegistryHub | |
7475 | virtual void registerReporter( std::string const& name, Ptr<IReporterFactory> const& factory ) CATCH_OVERRIDE { | |
7476 | m_reporterRegistry.registerReporter( name, factory ); | |
7477 | } | |
7478 | virtual void registerListener( Ptr<IReporterFactory> const& factory ) CATCH_OVERRIDE { | |
7479 | m_reporterRegistry.registerListener( factory ); | |
7480 | } | |
7481 | virtual void registerTest( TestCase const& testInfo ) CATCH_OVERRIDE { | |
7482 | m_testCaseRegistry.registerTest( testInfo ); | |
7483 | } | |
7484 | virtual void registerTranslator( const IExceptionTranslator* translator ) CATCH_OVERRIDE { | |
7485 | m_exceptionTranslatorRegistry.registerTranslator( translator ); | |
7486 | } | |
7487 | virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) CATCH_OVERRIDE { | |
7488 | m_tagAliasRegistry.add( alias, tag, lineInfo ); | |
7489 | } | |
7490 | ||
7491 | private: | |
7492 | TestRegistry m_testCaseRegistry; | |
7493 | ReporterRegistry m_reporterRegistry; | |
7494 | ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; | |
7495 | TagAliasRegistry m_tagAliasRegistry; | |
7496 | }; | |
7497 | ||
7498 | // Single, global, instance | |
7499 | inline RegistryHub*& getTheRegistryHub() { | |
7500 | static RegistryHub* theRegistryHub = CATCH_NULL; | |
7501 | if( !theRegistryHub ) | |
7502 | theRegistryHub = new RegistryHub(); | |
7503 | return theRegistryHub; | |
7504 | } | |
7505 | } | |
7506 | ||
7507 | IRegistryHub& getRegistryHub() { | |
7508 | return *getTheRegistryHub(); | |
7509 | } | |
7510 | IMutableRegistryHub& getMutableRegistryHub() { | |
7511 | return *getTheRegistryHub(); | |
7512 | } | |
7513 | void cleanUp() { | |
7514 | delete getTheRegistryHub(); | |
7515 | getTheRegistryHub() = CATCH_NULL; | |
7516 | cleanUpContext(); | |
7517 | } | |
7518 | std::string translateActiveException() { | |
7519 | return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); | |
7520 | } | |
7521 | ||
7522 | } // end namespace Catch | |
7523 | ||
7524 | // #included from: catch_notimplemented_exception.hpp | |
7525 | #define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED | |
7526 | ||
7527 | #include <sstream> | |
7528 | ||
7529 | namespace Catch { | |
7530 | ||
7531 | NotImplementedException::NotImplementedException( SourceLineInfo const& lineInfo ) | |
7532 | : m_lineInfo( lineInfo ) { | |
7533 | std::ostringstream oss; | |
7534 | oss << lineInfo << ": function "; | |
7535 | oss << "not implemented"; | |
7536 | m_what = oss.str(); | |
7537 | } | |
7538 | ||
7539 | const char* NotImplementedException::what() const CATCH_NOEXCEPT { | |
7540 | return m_what.c_str(); | |
7541 | } | |
7542 | ||
7543 | } // end namespace Catch | |
7544 | ||
7545 | // #included from: catch_context_impl.hpp | |
7546 | #define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED | |
7547 | ||
7548 | // #included from: catch_stream.hpp | |
7549 | #define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED | |
7550 | ||
7551 | #include <stdexcept> | |
7552 | #include <cstdio> | |
7553 | #include <iostream> | |
7554 | ||
7555 | namespace Catch { | |
7556 | ||
7557 | template<typename WriterF, size_t bufferSize=256> | |
7558 | class StreamBufImpl : public StreamBufBase { | |
7559 | char data[bufferSize]; | |
7560 | WriterF m_writer; | |
7561 | ||
7562 | public: | |
7563 | StreamBufImpl() { | |
7564 | setp( data, data + sizeof(data) ); | |
7565 | } | |
7566 | ||
7567 | ~StreamBufImpl() CATCH_NOEXCEPT { | |
7568 | sync(); | |
7569 | } | |
7570 | ||
7571 | private: | |
7572 | int overflow( int c ) { | |
7573 | sync(); | |
7574 | ||
7575 | if( c != EOF ) { | |
7576 | if( pbase() == epptr() ) | |
7577 | m_writer( std::string( 1, static_cast<char>( c ) ) ); | |
7578 | else | |
7579 | sputc( static_cast<char>( c ) ); | |
7580 | } | |
7581 | return 0; | |
7582 | } | |
7583 | ||
7584 | int sync() { | |
7585 | if( pbase() != pptr() ) { | |
7586 | m_writer( std::string( pbase(), static_cast<std::string::size_type>( pptr() - pbase() ) ) ); | |
7587 | setp( pbase(), epptr() ); | |
7588 | } | |
7589 | return 0; | |
7590 | } | |
7591 | }; | |
7592 | ||
7593 | /////////////////////////////////////////////////////////////////////////// | |
7594 | ||
7595 | FileStream::FileStream( std::string const& filename ) { | |
7596 | m_ofs.open( filename.c_str() ); | |
7597 | if( m_ofs.fail() ) { | |
7598 | std::ostringstream oss; | |
7599 | oss << "Unable to open file: '" << filename << '\''; | |
7600 | throw std::domain_error( oss.str() ); | |
7601 | } | |
7602 | } | |
7603 | ||
7604 | std::ostream& FileStream::stream() const { | |
7605 | return m_ofs; | |
7606 | } | |
7607 | ||
7608 | struct OutputDebugWriter { | |
7609 | ||
7610 | void operator()( std::string const&str ) { | |
7611 | writeToDebugConsole( str ); | |
7612 | } | |
7613 | }; | |
7614 | ||
7615 | DebugOutStream::DebugOutStream() | |
7616 | : m_streamBuf( new StreamBufImpl<OutputDebugWriter>() ), | |
7617 | m_os( m_streamBuf.get() ) | |
7618 | {} | |
7619 | ||
7620 | std::ostream& DebugOutStream::stream() const { | |
7621 | return m_os; | |
7622 | } | |
7623 | ||
7624 | // Store the streambuf from cout up-front because | |
7625 | // cout may get redirected when running tests | |
7626 | CoutStream::CoutStream() | |
7627 | : m_os( Catch::cout().rdbuf() ) | |
7628 | {} | |
7629 | ||
7630 | std::ostream& CoutStream::stream() const { | |
7631 | return m_os; | |
7632 | } | |
7633 | ||
7634 | #ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions | |
7635 | std::ostream& cout() { | |
7636 | return std::cout; | |
7637 | } | |
7638 | std::ostream& cerr() { | |
7639 | return std::cerr; | |
7640 | } | |
7641 | #endif | |
7642 | } | |
7643 | ||
7644 | namespace Catch { | |
7645 | ||
7646 | class Context : public IMutableContext { | |
7647 | ||
7648 | Context() : m_config( CATCH_NULL ), m_runner( CATCH_NULL ), m_resultCapture( CATCH_NULL ) {} | |
7649 | Context( Context const& ); | |
7650 | void operator=( Context const& ); | |
7651 | ||
7652 | public: | |
7653 | virtual ~Context() { | |
7654 | deleteAllValues( m_generatorsByTestName ); | |
7655 | } | |
7656 | ||
7657 | public: // IContext | |
7658 | virtual IResultCapture* getResultCapture() { | |
7659 | return m_resultCapture; | |
7660 | } | |
7661 | virtual IRunner* getRunner() { | |
7662 | return m_runner; | |
7663 | } | |
7664 | virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) { | |
7665 | return getGeneratorsForCurrentTest() | |
7666 | .getGeneratorInfo( fileInfo, totalSize ) | |
7667 | .getCurrentIndex(); | |
7668 | } | |
7669 | virtual bool advanceGeneratorsForCurrentTest() { | |
7670 | IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); | |
7671 | return generators && generators->moveNext(); | |
7672 | } | |
7673 | ||
7674 | virtual Ptr<IConfig const> getConfig() const { | |
7675 | return m_config; | |
7676 | } | |
7677 | ||
7678 | public: // IMutableContext | |
7679 | virtual void setResultCapture( IResultCapture* resultCapture ) { | |
7680 | m_resultCapture = resultCapture; | |
7681 | } | |
7682 | virtual void setRunner( IRunner* runner ) { | |
7683 | m_runner = runner; | |
7684 | } | |
7685 | virtual void setConfig( Ptr<IConfig const> const& config ) { | |
7686 | m_config = config; | |
7687 | } | |
7688 | ||
7689 | friend IMutableContext& getCurrentMutableContext(); | |
7690 | ||
7691 | private: | |
7692 | IGeneratorsForTest* findGeneratorsForCurrentTest() { | |
7693 | std::string testName = getResultCapture()->getCurrentTestName(); | |
7694 | ||
7695 | std::map<std::string, IGeneratorsForTest*>::const_iterator it = | |
7696 | m_generatorsByTestName.find( testName ); | |
7697 | return it != m_generatorsByTestName.end() | |
7698 | ? it->second | |
7699 | : CATCH_NULL; | |
7700 | } | |
7701 | ||
7702 | IGeneratorsForTest& getGeneratorsForCurrentTest() { | |
7703 | IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); | |
7704 | if( !generators ) { | |
7705 | std::string testName = getResultCapture()->getCurrentTestName(); | |
7706 | generators = createGeneratorsForTest(); | |
7707 | m_generatorsByTestName.insert( std::make_pair( testName, generators ) ); | |
7708 | } | |
7709 | return *generators; | |
7710 | } | |
7711 | ||
7712 | private: | |
7713 | Ptr<IConfig const> m_config; | |
7714 | IRunner* m_runner; | |
7715 | IResultCapture* m_resultCapture; | |
7716 | std::map<std::string, IGeneratorsForTest*> m_generatorsByTestName; | |
7717 | }; | |
7718 | ||
7719 | namespace { | |
7720 | Context* currentContext = CATCH_NULL; | |
7721 | } | |
7722 | IMutableContext& getCurrentMutableContext() { | |
7723 | if( !currentContext ) | |
7724 | currentContext = new Context(); | |
7725 | return *currentContext; | |
7726 | } | |
7727 | IContext& getCurrentContext() { | |
7728 | return getCurrentMutableContext(); | |
7729 | } | |
7730 | ||
7731 | void cleanUpContext() { | |
7732 | delete currentContext; | |
7733 | currentContext = CATCH_NULL; | |
7734 | } | |
7735 | } | |
7736 | ||
7737 | // #included from: catch_console_colour_impl.hpp | |
7738 | #define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED | |
7739 | ||
7740 | // #included from: catch_errno_guard.hpp | |
7741 | #define TWOBLUECUBES_CATCH_ERRNO_GUARD_HPP_INCLUDED | |
7742 | ||
7743 | #include <cerrno> | |
7744 | ||
7745 | namespace Catch { | |
7746 | ||
7747 | class ErrnoGuard { | |
7748 | public: | |
7749 | ErrnoGuard():m_oldErrno(errno){} | |
7750 | ~ErrnoGuard() { errno = m_oldErrno; } | |
7751 | private: | |
7752 | int m_oldErrno; | |
7753 | }; | |
7754 | ||
7755 | } | |
7756 | ||
7757 | namespace Catch { | |
7758 | namespace { | |
7759 | ||
7760 | struct IColourImpl { | |
7761 | virtual ~IColourImpl() {} | |
7762 | virtual void use( Colour::Code _colourCode ) = 0; | |
7763 | }; | |
7764 | ||
7765 | struct NoColourImpl : IColourImpl { | |
7766 | void use( Colour::Code ) {} | |
7767 | ||
7768 | static IColourImpl* instance() { | |
7769 | static NoColourImpl s_instance; | |
7770 | return &s_instance; | |
7771 | } | |
7772 | }; | |
7773 | ||
7774 | } // anon namespace | |
7775 | } // namespace Catch | |
7776 | ||
7777 | #if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI ) | |
7778 | # ifdef CATCH_PLATFORM_WINDOWS | |
7779 | # define CATCH_CONFIG_COLOUR_WINDOWS | |
7780 | # else | |
7781 | # define CATCH_CONFIG_COLOUR_ANSI | |
7782 | # endif | |
7783 | #endif | |
7784 | ||
7785 | #if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) ///////////////////////////////////////// | |
7786 | ||
7787 | namespace Catch { | |
7788 | namespace { | |
7789 | ||
7790 | class Win32ColourImpl : public IColourImpl { | |
7791 | public: | |
7792 | Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) | |
7793 | { | |
7794 | CONSOLE_SCREEN_BUFFER_INFO csbiInfo; | |
7795 | GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); | |
7796 | originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY ); | |
7797 | originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY ); | |
7798 | } | |
7799 | ||
7800 | virtual void use( Colour::Code _colourCode ) { | |
7801 | switch( _colourCode ) { | |
7802 | case Colour::None: return setTextAttribute( originalForegroundAttributes ); | |
7803 | case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); | |
7804 | case Colour::Red: return setTextAttribute( FOREGROUND_RED ); | |
7805 | case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); | |
7806 | case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE ); | |
7807 | case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN ); | |
7808 | case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN ); | |
7809 | case Colour::Grey: return setTextAttribute( 0 ); | |
7810 | ||
7811 | case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY ); | |
7812 | case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED ); | |
7813 | case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); | |
7814 | case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); | |
7815 | ||
7816 | case Colour::Bright: throw std::logic_error( "not a colour" ); | |
7817 | } | |
7818 | } | |
7819 | ||
7820 | private: | |
7821 | void setTextAttribute( WORD _textAttribute ) { | |
7822 | SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes ); | |
7823 | } | |
7824 | HANDLE stdoutHandle; | |
7825 | WORD originalForegroundAttributes; | |
7826 | WORD originalBackgroundAttributes; | |
7827 | }; | |
7828 | ||
7829 | IColourImpl* platformColourInstance() { | |
7830 | static Win32ColourImpl s_instance; | |
7831 | ||
7832 | Ptr<IConfig const> config = getCurrentContext().getConfig(); | |
7833 | UseColour::YesOrNo colourMode = config | |
7834 | ? config->useColour() | |
7835 | : UseColour::Auto; | |
7836 | if( colourMode == UseColour::Auto ) | |
7837 | colourMode = !isDebuggerActive() | |
7838 | ? UseColour::Yes | |
7839 | : UseColour::No; | |
7840 | return colourMode == UseColour::Yes | |
7841 | ? &s_instance | |
7842 | : NoColourImpl::instance(); | |
7843 | } | |
7844 | ||
7845 | } // end anon namespace | |
7846 | } // end namespace Catch | |
7847 | ||
7848 | #elif defined( CATCH_CONFIG_COLOUR_ANSI ) ////////////////////////////////////// | |
7849 | ||
7850 | #include <unistd.h> | |
7851 | ||
7852 | namespace Catch { | |
7853 | namespace { | |
7854 | ||
7855 | // use POSIX/ ANSI console terminal codes | |
7856 | // Thanks to Adam Strzelecki for original contribution | |
7857 | // (http://github.com/nanoant) | |
7858 | // https://github.com/philsquared/Catch/pull/131 | |
7859 | class PosixColourImpl : public IColourImpl { | |
7860 | public: | |
7861 | virtual void use( Colour::Code _colourCode ) { | |
7862 | switch( _colourCode ) { | |
7863 | case Colour::None: | |
7864 | case Colour::White: return setColour( "[0m" ); | |
7865 | case Colour::Red: return setColour( "[0;31m" ); | |
7866 | case Colour::Green: return setColour( "[0;32m" ); | |
7867 | case Colour::Blue: return setColour( "[0;34m" ); | |
7868 | case Colour::Cyan: return setColour( "[0;36m" ); | |
7869 | case Colour::Yellow: return setColour( "[0;33m" ); | |
7870 | case Colour::Grey: return setColour( "[1;30m" ); | |
7871 | ||
7872 | case Colour::LightGrey: return setColour( "[0;37m" ); | |
7873 | case Colour::BrightRed: return setColour( "[1;31m" ); | |
7874 | case Colour::BrightGreen: return setColour( "[1;32m" ); | |
7875 | case Colour::BrightWhite: return setColour( "[1;37m" ); | |
7876 | ||
7877 | case Colour::Bright: throw std::logic_error( "not a colour" ); | |
7878 | } | |
7879 | } | |
7880 | static IColourImpl* instance() { | |
7881 | static PosixColourImpl s_instance; | |
7882 | return &s_instance; | |
7883 | } | |
7884 | ||
7885 | private: | |
7886 | void setColour( const char* _escapeCode ) { | |
7887 | Catch::cout() << '\033' << _escapeCode; | |
7888 | } | |
7889 | }; | |
7890 | ||
7891 | IColourImpl* platformColourInstance() { | |
7892 | ErrnoGuard guard; | |
7893 | Ptr<IConfig const> config = getCurrentContext().getConfig(); | |
7894 | UseColour::YesOrNo colourMode = config | |
7895 | ? config->useColour() | |
7896 | : UseColour::Auto; | |
7897 | if( colourMode == UseColour::Auto ) | |
7898 | colourMode = (!isDebuggerActive() && isatty(STDOUT_FILENO) ) | |
7899 | ? UseColour::Yes | |
7900 | : UseColour::No; | |
7901 | return colourMode == UseColour::Yes | |
7902 | ? PosixColourImpl::instance() | |
7903 | : NoColourImpl::instance(); | |
7904 | } | |
7905 | ||
7906 | } // end anon namespace | |
7907 | } // end namespace Catch | |
7908 | ||
7909 | #else // not Windows or ANSI /////////////////////////////////////////////// | |
7910 | ||
7911 | namespace Catch { | |
7912 | ||
7913 | static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); } | |
7914 | ||
7915 | } // end namespace Catch | |
7916 | ||
7917 | #endif // Windows/ ANSI/ None | |
7918 | ||
7919 | namespace Catch { | |
7920 | ||
7921 | Colour::Colour( Code _colourCode ) : m_moved( false ) { use( _colourCode ); } | |
7922 | Colour::Colour( Colour const& _other ) : m_moved( false ) { const_cast<Colour&>( _other ).m_moved = true; } | |
7923 | Colour::~Colour(){ if( !m_moved ) use( None ); } | |
7924 | ||
7925 | void Colour::use( Code _colourCode ) { | |
7926 | static IColourImpl* impl = platformColourInstance(); | |
7927 | impl->use( _colourCode ); | |
7928 | } | |
7929 | ||
7930 | } // end namespace Catch | |
7931 | ||
7932 | // #included from: catch_generators_impl.hpp | |
7933 | #define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED | |
7934 | ||
7935 | #include <vector> | |
7936 | #include <string> | |
7937 | #include <map> | |
7938 | ||
7939 | namespace Catch { | |
7940 | ||
7941 | struct GeneratorInfo : IGeneratorInfo { | |
7942 | ||
7943 | GeneratorInfo( std::size_t size ) | |
7944 | : m_size( size ), | |
7945 | m_currentIndex( 0 ) | |
7946 | {} | |
7947 | ||
7948 | bool moveNext() { | |
7949 | if( ++m_currentIndex == m_size ) { | |
7950 | m_currentIndex = 0; | |
7951 | return false; | |
7952 | } | |
7953 | return true; | |
7954 | } | |
7955 | ||
7956 | std::size_t getCurrentIndex() const { | |
7957 | return m_currentIndex; | |
7958 | } | |
7959 | ||
7960 | std::size_t m_size; | |
7961 | std::size_t m_currentIndex; | |
7962 | }; | |
7963 | ||
7964 | /////////////////////////////////////////////////////////////////////////// | |
7965 | ||
7966 | class GeneratorsForTest : public IGeneratorsForTest { | |
7967 | ||
7968 | public: | |
7969 | ~GeneratorsForTest() { | |
7970 | deleteAll( m_generatorsInOrder ); | |
7971 | } | |
7972 | ||
7973 | IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) { | |
7974 | std::map<std::string, IGeneratorInfo*>::const_iterator it = m_generatorsByName.find( fileInfo ); | |
7975 | if( it == m_generatorsByName.end() ) { | |
7976 | IGeneratorInfo* info = new GeneratorInfo( size ); | |
7977 | m_generatorsByName.insert( std::make_pair( fileInfo, info ) ); | |
7978 | m_generatorsInOrder.push_back( info ); | |
7979 | return *info; | |
7980 | } | |
7981 | return *it->second; | |
7982 | } | |
7983 | ||
7984 | bool moveNext() { | |
7985 | std::vector<IGeneratorInfo*>::const_iterator it = m_generatorsInOrder.begin(); | |
7986 | std::vector<IGeneratorInfo*>::const_iterator itEnd = m_generatorsInOrder.end(); | |
7987 | for(; it != itEnd; ++it ) { | |
7988 | if( (*it)->moveNext() ) | |
7989 | return true; | |
7990 | } | |
7991 | return false; | |
7992 | } | |
7993 | ||
7994 | private: | |
7995 | std::map<std::string, IGeneratorInfo*> m_generatorsByName; | |
7996 | std::vector<IGeneratorInfo*> m_generatorsInOrder; | |
7997 | }; | |
7998 | ||
7999 | IGeneratorsForTest* createGeneratorsForTest() | |
8000 | { | |
8001 | return new GeneratorsForTest(); | |
8002 | } | |
8003 | ||
8004 | } // end namespace Catch | |
8005 | ||
8006 | // #included from: catch_assertionresult.hpp | |
8007 | #define TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED | |
8008 | ||
8009 | namespace Catch { | |
8010 | ||
8011 | AssertionInfo::AssertionInfo( std::string const& _macroName, | |
8012 | SourceLineInfo const& _lineInfo, | |
8013 | std::string const& _capturedExpression, | |
8014 | ResultDisposition::Flags _resultDisposition ) | |
8015 | : macroName( _macroName ), | |
8016 | lineInfo( _lineInfo ), | |
8017 | capturedExpression( _capturedExpression ), | |
8018 | resultDisposition( _resultDisposition ) | |
8019 | {} | |
8020 | ||
8021 | AssertionResult::AssertionResult() {} | |
8022 | ||
8023 | AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) | |
8024 | : m_info( info ), | |
8025 | m_resultData( data ) | |
8026 | {} | |
8027 | ||
8028 | AssertionResult::~AssertionResult() {} | |
8029 | ||
8030 | // Result was a success | |
8031 | bool AssertionResult::succeeded() const { | |
8032 | return Catch::isOk( m_resultData.resultType ); | |
8033 | } | |
8034 | ||
8035 | // Result was a success, or failure is suppressed | |
8036 | bool AssertionResult::isOk() const { | |
8037 | return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition ); | |
8038 | } | |
8039 | ||
8040 | ResultWas::OfType AssertionResult::getResultType() const { | |
8041 | return m_resultData.resultType; | |
8042 | } | |
8043 | ||
8044 | bool AssertionResult::hasExpression() const { | |
8045 | return !m_info.capturedExpression.empty(); | |
8046 | } | |
8047 | ||
8048 | bool AssertionResult::hasMessage() const { | |
8049 | return !m_resultData.message.empty(); | |
8050 | } | |
8051 | ||
8052 | std::string AssertionResult::getExpression() const { | |
8053 | if( isFalseTest( m_info.resultDisposition ) ) | |
8054 | return '!' + m_info.capturedExpression; | |
8055 | else | |
8056 | return m_info.capturedExpression; | |
8057 | } | |
8058 | std::string AssertionResult::getExpressionInMacro() const { | |
8059 | if( m_info.macroName.empty() ) | |
8060 | return m_info.capturedExpression; | |
8061 | else | |
8062 | return m_info.macroName + "( " + m_info.capturedExpression + " )"; | |
8063 | } | |
8064 | ||
8065 | bool AssertionResult::hasExpandedExpression() const { | |
8066 | return hasExpression() && getExpandedExpression() != getExpression(); | |
8067 | } | |
8068 | ||
8069 | std::string AssertionResult::getExpandedExpression() const { | |
8070 | return m_resultData.reconstructExpression(); | |
8071 | } | |
8072 | ||
8073 | std::string AssertionResult::getMessage() const { | |
8074 | return m_resultData.message; | |
8075 | } | |
8076 | SourceLineInfo AssertionResult::getSourceInfo() const { | |
8077 | return m_info.lineInfo; | |
8078 | } | |
8079 | ||
8080 | std::string AssertionResult::getTestMacroName() const { | |
8081 | return m_info.macroName; | |
8082 | } | |
8083 | ||
8084 | void AssertionResult::discardDecomposedExpression() const { | |
8085 | m_resultData.decomposedExpression = CATCH_NULL; | |
8086 | } | |
8087 | ||
8088 | void AssertionResult::expandDecomposedExpression() const { | |
8089 | m_resultData.reconstructExpression(); | |
8090 | } | |
8091 | ||
8092 | } // end namespace Catch | |
8093 | ||
8094 | // #included from: catch_test_case_info.hpp | |
8095 | #define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED | |
8096 | ||
8097 | #include <cctype> | |
8098 | ||
8099 | namespace Catch { | |
8100 | ||
8101 | inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { | |
8102 | if( startsWith( tag, '.' ) || | |
8103 | tag == "hide" || | |
8104 | tag == "!hide" ) | |
8105 | return TestCaseInfo::IsHidden; | |
8106 | else if( tag == "!throws" ) | |
8107 | return TestCaseInfo::Throws; | |
8108 | else if( tag == "!shouldfail" ) | |
8109 | return TestCaseInfo::ShouldFail; | |
8110 | else if( tag == "!mayfail" ) | |
8111 | return TestCaseInfo::MayFail; | |
8112 | else if( tag == "!nonportable" ) | |
8113 | return TestCaseInfo::NonPortable; | |
8114 | else | |
8115 | return TestCaseInfo::None; | |
8116 | } | |
8117 | inline bool isReservedTag( std::string const& tag ) { | |
8118 | return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( tag[0] ); | |
8119 | } | |
8120 | inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { | |
8121 | if( isReservedTag( tag ) ) { | |
8122 | std::ostringstream ss; | |
8123 | ss << Colour(Colour::Red) | |
8124 | << "Tag name [" << tag << "] not allowed.\n" | |
8125 | << "Tag names starting with non alpha-numeric characters are reserved\n" | |
8126 | << Colour(Colour::FileName) | |
8127 | << _lineInfo << '\n'; | |
8128 | throw std::runtime_error(ss.str()); | |
8129 | } | |
8130 | } | |
8131 | ||
8132 | TestCase makeTestCase( ITestCase* _testCase, | |
8133 | std::string const& _className, | |
8134 | std::string const& _name, | |
8135 | std::string const& _descOrTags, | |
8136 | SourceLineInfo const& _lineInfo ) | |
8137 | { | |
8138 | bool isHidden( startsWith( _name, "./" ) ); // Legacy support | |
8139 | ||
8140 | // Parse out tags | |
8141 | std::set<std::string> tags; | |
8142 | std::string desc, tag; | |
8143 | bool inTag = false; | |
8144 | for( std::size_t i = 0; i < _descOrTags.size(); ++i ) { | |
8145 | char c = _descOrTags[i]; | |
8146 | if( !inTag ) { | |
8147 | if( c == '[' ) | |
8148 | inTag = true; | |
8149 | else | |
8150 | desc += c; | |
8151 | } | |
8152 | else { | |
8153 | if( c == ']' ) { | |
8154 | TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag ); | |
8155 | if( prop == TestCaseInfo::IsHidden ) | |
8156 | isHidden = true; | |
8157 | else if( prop == TestCaseInfo::None ) | |
8158 | enforceNotReservedTag( tag, _lineInfo ); | |
8159 | ||
8160 | tags.insert( tag ); | |
8161 | tag.clear(); | |
8162 | inTag = false; | |
8163 | } | |
8164 | else | |
8165 | tag += c; | |
8166 | } | |
8167 | } | |
8168 | if( isHidden ) { | |
8169 | tags.insert( "hide" ); | |
8170 | tags.insert( "." ); | |
8171 | } | |
8172 | ||
8173 | TestCaseInfo info( _name, _className, desc, tags, _lineInfo ); | |
8174 | return TestCase( _testCase, info ); | |
8175 | } | |
8176 | ||
8177 | void setTags( TestCaseInfo& testCaseInfo, std::set<std::string> const& tags ) | |
8178 | { | |
8179 | testCaseInfo.tags = tags; | |
8180 | testCaseInfo.lcaseTags.clear(); | |
8181 | ||
8182 | std::ostringstream oss; | |
8183 | for( std::set<std::string>::const_iterator it = tags.begin(), itEnd = tags.end(); it != itEnd; ++it ) { | |
8184 | oss << '[' << *it << ']'; | |
8185 | std::string lcaseTag = toLower( *it ); | |
8186 | testCaseInfo.properties = static_cast<TestCaseInfo::SpecialProperties>( testCaseInfo.properties | parseSpecialTag( lcaseTag ) ); | |
8187 | testCaseInfo.lcaseTags.insert( lcaseTag ); | |
8188 | } | |
8189 | testCaseInfo.tagsAsString = oss.str(); | |
8190 | } | |
8191 | ||
8192 | TestCaseInfo::TestCaseInfo( std::string const& _name, | |
8193 | std::string const& _className, | |
8194 | std::string const& _description, | |
8195 | std::set<std::string> const& _tags, | |
8196 | SourceLineInfo const& _lineInfo ) | |
8197 | : name( _name ), | |
8198 | className( _className ), | |
8199 | description( _description ), | |
8200 | lineInfo( _lineInfo ), | |
8201 | properties( None ) | |
8202 | { | |
8203 | setTags( *this, _tags ); | |
8204 | } | |
8205 | ||
8206 | TestCaseInfo::TestCaseInfo( TestCaseInfo const& other ) | |
8207 | : name( other.name ), | |
8208 | className( other.className ), | |
8209 | description( other.description ), | |
8210 | tags( other.tags ), | |
8211 | lcaseTags( other.lcaseTags ), | |
8212 | tagsAsString( other.tagsAsString ), | |
8213 | lineInfo( other.lineInfo ), | |
8214 | properties( other.properties ) | |
8215 | {} | |
8216 | ||
8217 | bool TestCaseInfo::isHidden() const { | |
8218 | return ( properties & IsHidden ) != 0; | |
8219 | } | |
8220 | bool TestCaseInfo::throws() const { | |
8221 | return ( properties & Throws ) != 0; | |
8222 | } | |
8223 | bool TestCaseInfo::okToFail() const { | |
8224 | return ( properties & (ShouldFail | MayFail ) ) != 0; | |
8225 | } | |
8226 | bool TestCaseInfo::expectedToFail() const { | |
8227 | return ( properties & (ShouldFail ) ) != 0; | |
8228 | } | |
8229 | ||
8230 | TestCase::TestCase( ITestCase* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {} | |
8231 | ||
8232 | TestCase::TestCase( TestCase const& other ) | |
8233 | : TestCaseInfo( other ), | |
8234 | test( other.test ) | |
8235 | {} | |
8236 | ||
8237 | TestCase TestCase::withName( std::string const& _newName ) const { | |
8238 | TestCase other( *this ); | |
8239 | other.name = _newName; | |
8240 | return other; | |
8241 | } | |
8242 | ||
8243 | void TestCase::swap( TestCase& other ) { | |
8244 | test.swap( other.test ); | |
8245 | name.swap( other.name ); | |
8246 | className.swap( other.className ); | |
8247 | description.swap( other.description ); | |
8248 | tags.swap( other.tags ); | |
8249 | lcaseTags.swap( other.lcaseTags ); | |
8250 | tagsAsString.swap( other.tagsAsString ); | |
8251 | std::swap( TestCaseInfo::properties, static_cast<TestCaseInfo&>( other ).properties ); | |
8252 | std::swap( lineInfo, other.lineInfo ); | |
8253 | } | |
8254 | ||
8255 | void TestCase::invoke() const { | |
8256 | test->invoke(); | |
8257 | } | |
8258 | ||
8259 | bool TestCase::operator == ( TestCase const& other ) const { | |
8260 | return test.get() == other.test.get() && | |
8261 | name == other.name && | |
8262 | className == other.className; | |
8263 | } | |
8264 | ||
8265 | bool TestCase::operator < ( TestCase const& other ) const { | |
8266 | return name < other.name; | |
8267 | } | |
8268 | TestCase& TestCase::operator = ( TestCase const& other ) { | |
8269 | TestCase temp( other ); | |
8270 | swap( temp ); | |
8271 | return *this; | |
8272 | } | |
8273 | ||
8274 | TestCaseInfo const& TestCase::getTestCaseInfo() const | |
8275 | { | |
8276 | return *this; | |
8277 | } | |
8278 | ||
8279 | } // end namespace Catch | |
8280 | ||
8281 | // #included from: catch_version.hpp | |
8282 | #define TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED | |
8283 | ||
8284 | namespace Catch { | |
8285 | ||
8286 | Version::Version | |
8287 | ( unsigned int _majorVersion, | |
8288 | unsigned int _minorVersion, | |
8289 | unsigned int _patchNumber, | |
8290 | char const * const _branchName, | |
8291 | unsigned int _buildNumber ) | |
8292 | : majorVersion( _majorVersion ), | |
8293 | minorVersion( _minorVersion ), | |
8294 | patchNumber( _patchNumber ), | |
8295 | branchName( _branchName ), | |
8296 | buildNumber( _buildNumber ) | |
8297 | {} | |
8298 | ||
8299 | std::ostream& operator << ( std::ostream& os, Version const& version ) { | |
8300 | os << version.majorVersion << '.' | |
8301 | << version.minorVersion << '.' | |
8302 | << version.patchNumber; | |
8303 | // branchName is never null -> 0th char is \0 if it is empty | |
8304 | if (version.branchName[0]) { | |
8305 | os << '-' << version.branchName | |
8306 | << '.' << version.buildNumber; | |
8307 | } | |
8308 | return os; | |
8309 | } | |
8310 | ||
8311 | inline Version libraryVersion() { | |
8312 | static Version version( 1, 9, 4, "", 0 ); | |
8313 | return version; | |
8314 | } | |
8315 | ||
8316 | } | |
8317 | ||
8318 | // #included from: catch_message.hpp | |
8319 | #define TWOBLUECUBES_CATCH_MESSAGE_HPP_INCLUDED | |
8320 | ||
8321 | namespace Catch { | |
8322 | ||
8323 | MessageInfo::MessageInfo( std::string const& _macroName, | |
8324 | SourceLineInfo const& _lineInfo, | |
8325 | ResultWas::OfType _type ) | |
8326 | : macroName( _macroName ), | |
8327 | lineInfo( _lineInfo ), | |
8328 | type( _type ), | |
8329 | sequence( ++globalCount ) | |
8330 | {} | |
8331 | ||
8332 | // This may need protecting if threading support is added | |
8333 | unsigned int MessageInfo::globalCount = 0; | |
8334 | ||
8335 | //////////////////////////////////////////////////////////////////////////// | |
8336 | ||
8337 | ScopedMessage::ScopedMessage( MessageBuilder const& builder ) | |
8338 | : m_info( builder.m_info ) | |
8339 | { | |
8340 | m_info.message = builder.m_stream.str(); | |
8341 | getResultCapture().pushScopedMessage( m_info ); | |
8342 | } | |
8343 | ScopedMessage::ScopedMessage( ScopedMessage const& other ) | |
8344 | : m_info( other.m_info ) | |
8345 | {} | |
8346 | ||
8347 | ScopedMessage::~ScopedMessage() { | |
8348 | if ( !std::uncaught_exception() ){ | |
8349 | getResultCapture().popScopedMessage(m_info); | |
8350 | } | |
8351 | } | |
8352 | ||
8353 | } // end namespace Catch | |
8354 | ||
8355 | // #included from: catch_legacy_reporter_adapter.hpp | |
8356 | #define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED | |
8357 | ||
8358 | // #included from: catch_legacy_reporter_adapter.h | |
8359 | #define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED | |
8360 | ||
8361 | namespace Catch | |
8362 | { | |
8363 | // Deprecated | |
8364 | struct IReporter : IShared { | |
8365 | virtual ~IReporter(); | |
8366 | ||
8367 | virtual bool shouldRedirectStdout() const = 0; | |
8368 | ||
8369 | virtual void StartTesting() = 0; | |
8370 | virtual void EndTesting( Totals const& totals ) = 0; | |
8371 | virtual void StartGroup( std::string const& groupName ) = 0; | |
8372 | virtual void EndGroup( std::string const& groupName, Totals const& totals ) = 0; | |
8373 | virtual void StartTestCase( TestCaseInfo const& testInfo ) = 0; | |
8374 | virtual void EndTestCase( TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr ) = 0; | |
8375 | virtual void StartSection( std::string const& sectionName, std::string const& description ) = 0; | |
8376 | virtual void EndSection( std::string const& sectionName, Counts const& assertions ) = 0; | |
8377 | virtual void NoAssertionsInSection( std::string const& sectionName ) = 0; | |
8378 | virtual void NoAssertionsInTestCase( std::string const& testName ) = 0; | |
8379 | virtual void Aborted() = 0; | |
8380 | virtual void Result( AssertionResult const& result ) = 0; | |
8381 | }; | |
8382 | ||
8383 | class LegacyReporterAdapter : public SharedImpl<IStreamingReporter> | |
8384 | { | |
8385 | public: | |
8386 | LegacyReporterAdapter( Ptr<IReporter> const& legacyReporter ); | |
8387 | virtual ~LegacyReporterAdapter(); | |
8388 | ||
8389 | virtual ReporterPreferences getPreferences() const; | |
8390 | virtual void noMatchingTestCases( std::string const& ); | |
8391 | virtual void testRunStarting( TestRunInfo const& ); | |
8392 | virtual void testGroupStarting( GroupInfo const& groupInfo ); | |
8393 | virtual void testCaseStarting( TestCaseInfo const& testInfo ); | |
8394 | virtual void sectionStarting( SectionInfo const& sectionInfo ); | |
8395 | virtual void assertionStarting( AssertionInfo const& ); | |
8396 | virtual bool assertionEnded( AssertionStats const& assertionStats ); | |
8397 | virtual void sectionEnded( SectionStats const& sectionStats ); | |
8398 | virtual void testCaseEnded( TestCaseStats const& testCaseStats ); | |
8399 | virtual void testGroupEnded( TestGroupStats const& testGroupStats ); | |
8400 | virtual void testRunEnded( TestRunStats const& testRunStats ); | |
8401 | virtual void skipTest( TestCaseInfo const& ); | |
8402 | ||
8403 | private: | |
8404 | Ptr<IReporter> m_legacyReporter; | |
8405 | }; | |
8406 | } | |
8407 | ||
8408 | namespace Catch | |
8409 | { | |
8410 | LegacyReporterAdapter::LegacyReporterAdapter( Ptr<IReporter> const& legacyReporter ) | |
8411 | : m_legacyReporter( legacyReporter ) | |
8412 | {} | |
8413 | LegacyReporterAdapter::~LegacyReporterAdapter() {} | |
8414 | ||
8415 | ReporterPreferences LegacyReporterAdapter::getPreferences() const { | |
8416 | ReporterPreferences prefs; | |
8417 | prefs.shouldRedirectStdOut = m_legacyReporter->shouldRedirectStdout(); | |
8418 | return prefs; | |
8419 | } | |
8420 | ||
8421 | void LegacyReporterAdapter::noMatchingTestCases( std::string const& ) {} | |
8422 | void LegacyReporterAdapter::testRunStarting( TestRunInfo const& ) { | |
8423 | m_legacyReporter->StartTesting(); | |
8424 | } | |
8425 | void LegacyReporterAdapter::testGroupStarting( GroupInfo const& groupInfo ) { | |
8426 | m_legacyReporter->StartGroup( groupInfo.name ); | |
8427 | } | |
8428 | void LegacyReporterAdapter::testCaseStarting( TestCaseInfo const& testInfo ) { | |
8429 | m_legacyReporter->StartTestCase( testInfo ); | |
8430 | } | |
8431 | void LegacyReporterAdapter::sectionStarting( SectionInfo const& sectionInfo ) { | |
8432 | m_legacyReporter->StartSection( sectionInfo.name, sectionInfo.description ); | |
8433 | } | |
8434 | void LegacyReporterAdapter::assertionStarting( AssertionInfo const& ) { | |
8435 | // Not on legacy interface | |
8436 | } | |
8437 | ||
8438 | bool LegacyReporterAdapter::assertionEnded( AssertionStats const& assertionStats ) { | |
8439 | if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { | |
8440 | for( std::vector<MessageInfo>::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); | |
8441 | it != itEnd; | |
8442 | ++it ) { | |
8443 | if( it->type == ResultWas::Info ) { | |
8444 | ResultBuilder rb( it->macroName.c_str(), it->lineInfo, "", ResultDisposition::Normal ); | |
8445 | rb << it->message; | |
8446 | rb.setResultType( ResultWas::Info ); | |
8447 | AssertionResult result = rb.build(); | |
8448 | m_legacyReporter->Result( result ); | |
8449 | } | |
8450 | } | |
8451 | } | |
8452 | m_legacyReporter->Result( assertionStats.assertionResult ); | |
8453 | return true; | |
8454 | } | |
8455 | void LegacyReporterAdapter::sectionEnded( SectionStats const& sectionStats ) { | |
8456 | if( sectionStats.missingAssertions ) | |
8457 | m_legacyReporter->NoAssertionsInSection( sectionStats.sectionInfo.name ); | |
8458 | m_legacyReporter->EndSection( sectionStats.sectionInfo.name, sectionStats.assertions ); | |
8459 | } | |
8460 | void LegacyReporterAdapter::testCaseEnded( TestCaseStats const& testCaseStats ) { | |
8461 | m_legacyReporter->EndTestCase | |
8462 | ( testCaseStats.testInfo, | |
8463 | testCaseStats.totals, | |
8464 | testCaseStats.stdOut, | |
8465 | testCaseStats.stdErr ); | |
8466 | } | |
8467 | void LegacyReporterAdapter::testGroupEnded( TestGroupStats const& testGroupStats ) { | |
8468 | if( testGroupStats.aborting ) | |
8469 | m_legacyReporter->Aborted(); | |
8470 | m_legacyReporter->EndGroup( testGroupStats.groupInfo.name, testGroupStats.totals ); | |
8471 | } | |
8472 | void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) { | |
8473 | m_legacyReporter->EndTesting( testRunStats.totals ); | |
8474 | } | |
8475 | void LegacyReporterAdapter::skipTest( TestCaseInfo const& ) { | |
8476 | } | |
8477 | } | |
8478 | ||
8479 | // #included from: catch_timer.hpp | |
8480 | ||
8481 | #ifdef __clang__ | |
8482 | #pragma clang diagnostic push | |
8483 | #pragma clang diagnostic ignored "-Wc++11-long-long" | |
8484 | #endif | |
8485 | ||
8486 | #ifdef CATCH_PLATFORM_WINDOWS | |
8487 | ||
8488 | #else | |
8489 | ||
8490 | #include <sys/time.h> | |
8491 | ||
8492 | #endif | |
8493 | ||
8494 | namespace Catch { | |
8495 | ||
8496 | namespace { | |
8497 | #ifdef CATCH_PLATFORM_WINDOWS | |
8498 | UInt64 getCurrentTicks() { | |
8499 | static UInt64 hz=0, hzo=0; | |
8500 | if (!hz) { | |
8501 | QueryPerformanceFrequency( reinterpret_cast<LARGE_INTEGER*>( &hz ) ); | |
8502 | QueryPerformanceCounter( reinterpret_cast<LARGE_INTEGER*>( &hzo ) ); | |
8503 | } | |
8504 | UInt64 t; | |
8505 | QueryPerformanceCounter( reinterpret_cast<LARGE_INTEGER*>( &t ) ); | |
8506 | return ((t-hzo)*1000000)/hz; | |
8507 | } | |
8508 | #else | |
8509 | UInt64 getCurrentTicks() { | |
8510 | timeval t; | |
8511 | gettimeofday(&t,CATCH_NULL); | |
8512 | return static_cast<UInt64>( t.tv_sec ) * 1000000ull + static_cast<UInt64>( t.tv_usec ); | |
8513 | } | |
8514 | #endif | |
8515 | } | |
8516 | ||
8517 | void Timer::start() { | |
8518 | m_ticks = getCurrentTicks(); | |
8519 | } | |
8520 | unsigned int Timer::getElapsedMicroseconds() const { | |
8521 | return static_cast<unsigned int>(getCurrentTicks() - m_ticks); | |
8522 | } | |
8523 | unsigned int Timer::getElapsedMilliseconds() const { | |
8524 | return static_cast<unsigned int>(getElapsedMicroseconds()/1000); | |
8525 | } | |
8526 | double Timer::getElapsedSeconds() const { | |
8527 | return getElapsedMicroseconds()/1000000.0; | |
8528 | } | |
8529 | ||
8530 | } // namespace Catch | |
8531 | ||
8532 | #ifdef __clang__ | |
8533 | #pragma clang diagnostic pop | |
8534 | #endif | |
8535 | // #included from: catch_common.hpp | |
8536 | #define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED | |
8537 | ||
8538 | #include <cstring> | |
8539 | #include <cctype> | |
8540 | ||
8541 | namespace Catch { | |
8542 | ||
8543 | bool startsWith( std::string const& s, std::string const& prefix ) { | |
8544 | return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin()); | |
8545 | } | |
8546 | bool startsWith( std::string const& s, char prefix ) { | |
8547 | return !s.empty() && s[0] == prefix; | |
8548 | } | |
8549 | bool endsWith( std::string const& s, std::string const& suffix ) { | |
8550 | return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin()); | |
8551 | } | |
8552 | bool endsWith( std::string const& s, char suffix ) { | |
8553 | return !s.empty() && s[s.size()-1] == suffix; | |
8554 | } | |
8555 | bool contains( std::string const& s, std::string const& infix ) { | |
8556 | return s.find( infix ) != std::string::npos; | |
8557 | } | |
8558 | char toLowerCh(char c) { | |
8559 | return static_cast<char>( std::tolower( c ) ); | |
8560 | } | |
8561 | void toLowerInPlace( std::string& s ) { | |
8562 | std::transform( s.begin(), s.end(), s.begin(), toLowerCh ); | |
8563 | } | |
8564 | std::string toLower( std::string const& s ) { | |
8565 | std::string lc = s; | |
8566 | toLowerInPlace( lc ); | |
8567 | return lc; | |
8568 | } | |
8569 | std::string trim( std::string const& str ) { | |
8570 | static char const* whitespaceChars = "\n\r\t "; | |
8571 | std::string::size_type start = str.find_first_not_of( whitespaceChars ); | |
8572 | std::string::size_type end = str.find_last_not_of( whitespaceChars ); | |
8573 | ||
8574 | return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string(); | |
8575 | } | |
8576 | ||
8577 | bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { | |
8578 | bool replaced = false; | |
8579 | std::size_t i = str.find( replaceThis ); | |
8580 | while( i != std::string::npos ) { | |
8581 | replaced = true; | |
8582 | str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() ); | |
8583 | if( i < str.size()-withThis.size() ) | |
8584 | i = str.find( replaceThis, i+withThis.size() ); | |
8585 | else | |
8586 | i = std::string::npos; | |
8587 | } | |
8588 | return replaced; | |
8589 | } | |
8590 | ||
8591 | pluralise::pluralise( std::size_t count, std::string const& label ) | |
8592 | : m_count( count ), | |
8593 | m_label( label ) | |
8594 | {} | |
8595 | ||
8596 | std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { | |
8597 | os << pluraliser.m_count << ' ' << pluraliser.m_label; | |
8598 | if( pluraliser.m_count != 1 ) | |
8599 | os << 's'; | |
8600 | return os; | |
8601 | } | |
8602 | ||
8603 | SourceLineInfo::SourceLineInfo() : file(""), line( 0 ){} | |
8604 | SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line ) | |
8605 | : file( _file ), | |
8606 | line( _line ) | |
8607 | {} | |
8608 | bool SourceLineInfo::empty() const { | |
8609 | return file[0] == '\0'; | |
8610 | } | |
8611 | bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const { | |
8612 | return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0); | |
8613 | } | |
8614 | bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const { | |
8615 | return line < other.line || ( line == other.line && (std::strcmp(file, other.file) < 0)); | |
8616 | } | |
8617 | ||
8618 | void seedRng( IConfig const& config ) { | |
8619 | if( config.rngSeed() != 0 ) | |
8620 | std::srand( config.rngSeed() ); | |
8621 | } | |
8622 | unsigned int rngSeed() { | |
8623 | return getCurrentContext().getConfig()->rngSeed(); | |
8624 | } | |
8625 | ||
8626 | std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { | |
8627 | #ifndef __GNUG__ | |
8628 | os << info.file << '(' << info.line << ')'; | |
8629 | #else | |
8630 | os << info.file << ':' << info.line; | |
8631 | #endif | |
8632 | return os; | |
8633 | } | |
8634 | ||
8635 | void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) { | |
8636 | std::ostringstream oss; | |
8637 | oss << locationInfo << ": Internal Catch error: '" << message << '\''; | |
8638 | if( alwaysTrue() ) | |
8639 | throw std::logic_error( oss.str() ); | |
8640 | } | |
8641 | } | |
8642 | ||
8643 | // #included from: catch_section.hpp | |
8644 | #define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED | |
8645 | ||
8646 | namespace Catch { | |
8647 | ||
8648 | SectionInfo::SectionInfo | |
8649 | ( SourceLineInfo const& _lineInfo, | |
8650 | std::string const& _name, | |
8651 | std::string const& _description ) | |
8652 | : name( _name ), | |
8653 | description( _description ), | |
8654 | lineInfo( _lineInfo ) | |
8655 | {} | |
8656 | ||
8657 | Section::Section( SectionInfo const& info ) | |
8658 | : m_info( info ), | |
8659 | m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) ) | |
8660 | { | |
8661 | m_timer.start(); | |
8662 | } | |
8663 | ||
8664 | Section::~Section() { | |
8665 | if( m_sectionIncluded ) { | |
8666 | SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() ); | |
8667 | if( std::uncaught_exception() ) | |
8668 | getResultCapture().sectionEndedEarly( endInfo ); | |
8669 | else | |
8670 | getResultCapture().sectionEnded( endInfo ); | |
8671 | } | |
8672 | } | |
8673 | ||
8674 | // This indicates whether the section should be executed or not | |
8675 | Section::operator bool() const { | |
8676 | return m_sectionIncluded; | |
8677 | } | |
8678 | ||
8679 | } // end namespace Catch | |
8680 | ||
8681 | // #included from: catch_debugger.hpp | |
8682 | #define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED | |
8683 | ||
8684 | #ifdef CATCH_PLATFORM_MAC | |
8685 | ||
8686 | #include <assert.h> | |
8687 | #include <stdbool.h> | |
8688 | #include <sys/types.h> | |
8689 | #include <unistd.h> | |
8690 | #include <sys/sysctl.h> | |
8691 | ||
8692 | namespace Catch{ | |
8693 | ||
8694 | // The following function is taken directly from the following technical note: | |
8695 | // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html | |
8696 | ||
8697 | // Returns true if the current process is being debugged (either | |
8698 | // running under the debugger or has a debugger attached post facto). | |
8699 | bool isDebuggerActive(){ | |
8700 | ||
8701 | int mib[4]; | |
8702 | struct kinfo_proc info; | |
8703 | size_t size; | |
8704 | ||
8705 | // Initialize the flags so that, if sysctl fails for some bizarre | |
8706 | // reason, we get a predictable result. | |
8707 | ||
8708 | info.kp_proc.p_flag = 0; | |
8709 | ||
8710 | // Initialize mib, which tells sysctl the info we want, in this case | |
8711 | // we're looking for information about a specific process ID. | |
8712 | ||
8713 | mib[0] = CTL_KERN; | |
8714 | mib[1] = KERN_PROC; | |
8715 | mib[2] = KERN_PROC_PID; | |
8716 | mib[3] = getpid(); | |
8717 | ||
8718 | // Call sysctl. | |
8719 | ||
8720 | size = sizeof(info); | |
8721 | if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, CATCH_NULL, 0) != 0 ) { | |
8722 | Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; | |
8723 | return false; | |
8724 | } | |
8725 | ||
8726 | // We're being debugged if the P_TRACED flag is set. | |
8727 | ||
8728 | return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); | |
8729 | } | |
8730 | } // namespace Catch | |
8731 | ||
8732 | #elif defined(CATCH_PLATFORM_LINUX) | |
8733 | #include <fstream> | |
8734 | #include <string> | |
8735 | ||
8736 | namespace Catch{ | |
8737 | // The standard POSIX way of detecting a debugger is to attempt to | |
8738 | // ptrace() the process, but this needs to be done from a child and not | |
8739 | // this process itself to still allow attaching to this process later | |
8740 | // if wanted, so is rather heavy. Under Linux we have the PID of the | |
8741 | // "debugger" (which doesn't need to be gdb, of course, it could also | |
8742 | // be strace, for example) in /proc/$PID/status, so just get it from | |
8743 | // there instead. | |
8744 | bool isDebuggerActive(){ | |
8745 | // Libstdc++ has a bug, where std::ifstream sets errno to 0 | |
8746 | // This way our users can properly assert over errno values | |
8747 | ErrnoGuard guard; | |
8748 | std::ifstream in("/proc/self/status"); | |
8749 | for( std::string line; std::getline(in, line); ) { | |
8750 | static const int PREFIX_LEN = 11; | |
8751 | if( line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0 ) { | |
8752 | // We're traced if the PID is not 0 and no other PID starts | |
8753 | // with 0 digit, so it's enough to check for just a single | |
8754 | // character. | |
8755 | return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0'; | |
8756 | } | |
8757 | } | |
8758 | ||
8759 | return false; | |
8760 | } | |
8761 | } // namespace Catch | |
8762 | #elif defined(_MSC_VER) | |
8763 | extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); | |
8764 | namespace Catch { | |
8765 | bool isDebuggerActive() { | |
8766 | return IsDebuggerPresent() != 0; | |
8767 | } | |
8768 | } | |
8769 | #elif defined(__MINGW32__) | |
8770 | extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); | |
8771 | namespace Catch { | |
8772 | bool isDebuggerActive() { | |
8773 | return IsDebuggerPresent() != 0; | |
8774 | } | |
8775 | } | |
8776 | #else | |
8777 | namespace Catch { | |
8778 | inline bool isDebuggerActive() { return false; } | |
8779 | } | |
8780 | #endif // Platform | |
8781 | ||
8782 | #ifdef CATCH_PLATFORM_WINDOWS | |
8783 | ||
8784 | namespace Catch { | |
8785 | void writeToDebugConsole( std::string const& text ) { | |
8786 | ::OutputDebugStringA( text.c_str() ); | |
8787 | } | |
8788 | } | |
8789 | #else | |
8790 | namespace Catch { | |
8791 | void writeToDebugConsole( std::string const& text ) { | |
8792 | // !TBD: Need a version for Mac/ XCode and other IDEs | |
8793 | Catch::cout() << text; | |
8794 | } | |
8795 | } | |
8796 | #endif // Platform | |
8797 | ||
8798 | // #included from: catch_tostring.hpp | |
8799 | #define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED | |
8800 | ||
8801 | namespace Catch { | |
8802 | ||
8803 | namespace Detail { | |
8804 | ||
8805 | const std::string unprintableString = "{?}"; | |
8806 | ||
8807 | namespace { | |
8808 | const int hexThreshold = 255; | |
8809 | ||
8810 | struct Endianness { | |
8811 | enum Arch { Big, Little }; | |
8812 | ||
8813 | static Arch which() { | |
8814 | union _{ | |
8815 | int asInt; | |
8816 | char asChar[sizeof (int)]; | |
8817 | } u; | |
8818 | ||
8819 | u.asInt = 1; | |
8820 | return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little; | |
8821 | } | |
8822 | }; | |
8823 | } | |
8824 | ||
8825 | std::string rawMemoryToString( const void *object, std::size_t size ) | |
8826 | { | |
8827 | // Reverse order for little endian architectures | |
8828 | int i = 0, end = static_cast<int>( size ), inc = 1; | |
8829 | if( Endianness::which() == Endianness::Little ) { | |
8830 | i = end-1; | |
8831 | end = inc = -1; | |
8832 | } | |
8833 | ||
8834 | unsigned char const *bytes = static_cast<unsigned char const *>(object); | |
8835 | std::ostringstream os; | |
8836 | os << "0x" << std::setfill('0') << std::hex; | |
8837 | for( ; i != end; i += inc ) | |
8838 | os << std::setw(2) << static_cast<unsigned>(bytes[i]); | |
8839 | return os.str(); | |
8840 | } | |
8841 | } | |
8842 | ||
8843 | std::string toString( std::string const& value ) { | |
8844 | std::string s = value; | |
8845 | if( getCurrentContext().getConfig()->showInvisibles() ) { | |
8846 | for(size_t i = 0; i < s.size(); ++i ) { | |
8847 | std::string subs; | |
8848 | switch( s[i] ) { | |
8849 | case '\n': subs = "\\n"; break; | |
8850 | case '\t': subs = "\\t"; break; | |
8851 | default: break; | |
8852 | } | |
8853 | if( !subs.empty() ) { | |
8854 | s = s.substr( 0, i ) + subs + s.substr( i+1 ); | |
8855 | ++i; | |
8856 | } | |
8857 | } | |
8858 | } | |
8859 | return '"' + s + '"'; | |
8860 | } | |
8861 | std::string toString( std::wstring const& value ) { | |
8862 | ||
8863 | std::string s; | |
8864 | s.reserve( value.size() ); | |
8865 | for(size_t i = 0; i < value.size(); ++i ) | |
8866 | s += value[i] <= 0xff ? static_cast<char>( value[i] ) : '?'; | |
8867 | return Catch::toString( s ); | |
8868 | } | |
8869 | ||
8870 | std::string toString( const char* const value ) { | |
8871 | return value ? Catch::toString( std::string( value ) ) : std::string( "{null string}" ); | |
8872 | } | |
8873 | ||
8874 | std::string toString( char* const value ) { | |
8875 | return Catch::toString( static_cast<const char*>( value ) ); | |
8876 | } | |
8877 | ||
8878 | std::string toString( const wchar_t* const value ) | |
8879 | { | |
8880 | return value ? Catch::toString( std::wstring(value) ) : std::string( "{null string}" ); | |
8881 | } | |
8882 | ||
8883 | std::string toString( wchar_t* const value ) | |
8884 | { | |
8885 | return Catch::toString( static_cast<const wchar_t*>( value ) ); | |
8886 | } | |
8887 | ||
8888 | std::string toString( int value ) { | |
8889 | std::ostringstream oss; | |
8890 | oss << value; | |
8891 | if( value > Detail::hexThreshold ) | |
8892 | oss << " (0x" << std::hex << value << ')'; | |
8893 | return oss.str(); | |
8894 | } | |
8895 | ||
8896 | std::string toString( unsigned long value ) { | |
8897 | std::ostringstream oss; | |
8898 | oss << value; | |
8899 | if( value > Detail::hexThreshold ) | |
8900 | oss << " (0x" << std::hex << value << ')'; | |
8901 | return oss.str(); | |
8902 | } | |
8903 | ||
8904 | std::string toString( unsigned int value ) { | |
8905 | return Catch::toString( static_cast<unsigned long>( value ) ); | |
8906 | } | |
8907 | ||
8908 | template<typename T> | |
8909 | std::string fpToString( T value, int precision ) { | |
8910 | std::ostringstream oss; | |
8911 | oss << std::setprecision( precision ) | |
8912 | << std::fixed | |
8913 | << value; | |
8914 | std::string d = oss.str(); | |
8915 | std::size_t i = d.find_last_not_of( '0' ); | |
8916 | if( i != std::string::npos && i != d.size()-1 ) { | |
8917 | if( d[i] == '.' ) | |
8918 | i++; | |
8919 | d = d.substr( 0, i+1 ); | |
8920 | } | |
8921 | return d; | |
8922 | } | |
8923 | ||
8924 | std::string toString( const double value ) { | |
8925 | return fpToString( value, 10 ); | |
8926 | } | |
8927 | std::string toString( const float value ) { | |
8928 | return fpToString( value, 5 ) + 'f'; | |
8929 | } | |
8930 | ||
8931 | std::string toString( bool value ) { | |
8932 | return value ? "true" : "false"; | |
8933 | } | |
8934 | ||
8935 | std::string toString( char value ) { | |
8936 | if ( value == '\r' ) | |
8937 | return "'\\r'"; | |
8938 | if ( value == '\f' ) | |
8939 | return "'\\f'"; | |
8940 | if ( value == '\n' ) | |
8941 | return "'\\n'"; | |
8942 | if ( value == '\t' ) | |
8943 | return "'\\t'"; | |
8944 | if ( '\0' <= value && value < ' ' ) | |
8945 | return toString( static_cast<unsigned int>( value ) ); | |
8946 | char chstr[] = "' '"; | |
8947 | chstr[1] = value; | |
8948 | return chstr; | |
8949 | } | |
8950 | ||
8951 | std::string toString( signed char value ) { | |
8952 | return toString( static_cast<char>( value ) ); | |
8953 | } | |
8954 | ||
8955 | std::string toString( unsigned char value ) { | |
8956 | return toString( static_cast<char>( value ) ); | |
8957 | } | |
8958 | ||
8959 | #ifdef CATCH_CONFIG_CPP11_LONG_LONG | |
8960 | std::string toString( long long value ) { | |
8961 | std::ostringstream oss; | |
8962 | oss << value; | |
8963 | if( value > Detail::hexThreshold ) | |
8964 | oss << " (0x" << std::hex << value << ')'; | |
8965 | return oss.str(); | |
8966 | } | |
8967 | std::string toString( unsigned long long value ) { | |
8968 | std::ostringstream oss; | |
8969 | oss << value; | |
8970 | if( value > Detail::hexThreshold ) | |
8971 | oss << " (0x" << std::hex << value << ')'; | |
8972 | return oss.str(); | |
8973 | } | |
8974 | #endif | |
8975 | ||
8976 | #ifdef CATCH_CONFIG_CPP11_NULLPTR | |
8977 | std::string toString( std::nullptr_t ) { | |
8978 | return "nullptr"; | |
8979 | } | |
8980 | #endif | |
8981 | ||
8982 | #ifdef __OBJC__ | |
8983 | std::string toString( NSString const * const& nsstring ) { | |
8984 | if( !nsstring ) | |
8985 | return "nil"; | |
8986 | return "@" + toString([nsstring UTF8String]); | |
8987 | } | |
8988 | std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ) { | |
8989 | if( !nsstring ) | |
8990 | return "nil"; | |
8991 | return "@" + toString([nsstring UTF8String]); | |
8992 | } | |
8993 | std::string toString( NSObject* const& nsObject ) { | |
8994 | return toString( [nsObject description] ); | |
8995 | } | |
8996 | #endif | |
8997 | ||
8998 | } // end namespace Catch | |
8999 | ||
9000 | // #included from: catch_result_builder.hpp | |
9001 | #define TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED | |
9002 | ||
9003 | namespace Catch { | |
9004 | ||
9005 | std::string capturedExpressionWithSecondArgument( std::string const& capturedExpression, std::string const& secondArg ) { | |
9006 | return secondArg.empty() || secondArg == "\"\"" | |
9007 | ? capturedExpression | |
9008 | : capturedExpression + ", " + secondArg; | |
9009 | } | |
9010 | ResultBuilder::ResultBuilder( char const* macroName, | |
9011 | SourceLineInfo const& lineInfo, | |
9012 | char const* capturedExpression, | |
9013 | ResultDisposition::Flags resultDisposition, | |
9014 | char const* secondArg ) | |
9015 | : m_assertionInfo( macroName, lineInfo, capturedExpressionWithSecondArgument( capturedExpression, secondArg ), resultDisposition ), | |
9016 | m_shouldDebugBreak( false ), | |
9017 | m_shouldThrow( false ), | |
9018 | m_guardException( false ) | |
9019 | {} | |
9020 | ||
9021 | ResultBuilder::~ResultBuilder() { | |
9022 | #if defined(CATCH_CONFIG_FAST_COMPILE) | |
9023 | if ( m_guardException ) { | |
9024 | m_stream.oss << "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"; | |
9025 | captureResult( ResultWas::ThrewException ); | |
9026 | getCurrentContext().getResultCapture()->exceptionEarlyReported(); | |
9027 | } | |
9028 | #endif | |
9029 | } | |
9030 | ||
9031 | ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) { | |
9032 | m_data.resultType = result; | |
9033 | return *this; | |
9034 | } | |
9035 | ResultBuilder& ResultBuilder::setResultType( bool result ) { | |
9036 | m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed; | |
9037 | return *this; | |
9038 | } | |
9039 | ||
9040 | void ResultBuilder::endExpression( DecomposedExpression const& expr ) { | |
9041 | AssertionResult result = build( expr ); | |
9042 | handleResult( result ); | |
9043 | } | |
9044 | ||
9045 | void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) { | |
9046 | m_assertionInfo.resultDisposition = resultDisposition; | |
9047 | m_stream.oss << Catch::translateActiveException(); | |
9048 | captureResult( ResultWas::ThrewException ); | |
9049 | } | |
9050 | ||
9051 | void ResultBuilder::captureResult( ResultWas::OfType resultType ) { | |
9052 | setResultType( resultType ); | |
9053 | captureExpression(); | |
9054 | } | |
9055 | ||
9056 | void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) { | |
9057 | if( expectedMessage.empty() ) | |
9058 | captureExpectedException( Matchers::Impl::MatchAllOf<std::string>() ); | |
9059 | else | |
9060 | captureExpectedException( Matchers::Equals( expectedMessage ) ); | |
9061 | } | |
9062 | ||
9063 | void ResultBuilder::captureExpectedException( Matchers::Impl::MatcherBase<std::string> const& matcher ) { | |
9064 | ||
9065 | assert( !isFalseTest( m_assertionInfo.resultDisposition ) ); | |
9066 | AssertionResultData data = m_data; | |
9067 | data.resultType = ResultWas::Ok; | |
9068 | data.reconstructedExpression = m_assertionInfo.capturedExpression; | |
9069 | ||
9070 | std::string actualMessage = Catch::translateActiveException(); | |
9071 | if( !matcher.match( actualMessage ) ) { | |
9072 | data.resultType = ResultWas::ExpressionFailed; | |
9073 | data.reconstructedExpression = actualMessage; | |
9074 | } | |
9075 | AssertionResult result( m_assertionInfo, data ); | |
9076 | handleResult( result ); | |
9077 | } | |
9078 | ||
9079 | void ResultBuilder::captureExpression() { | |
9080 | AssertionResult result = build(); | |
9081 | handleResult( result ); | |
9082 | } | |
9083 | ||
9084 | void ResultBuilder::handleResult( AssertionResult const& result ) | |
9085 | { | |
9086 | getResultCapture().assertionEnded( result ); | |
9087 | ||
9088 | if( !result.isOk() ) { | |
9089 | if( getCurrentContext().getConfig()->shouldDebugBreak() ) | |
9090 | m_shouldDebugBreak = true; | |
9091 | if( getCurrentContext().getRunner()->aborting() || (m_assertionInfo.resultDisposition & ResultDisposition::Normal) ) | |
9092 | m_shouldThrow = true; | |
9093 | } | |
9094 | } | |
9095 | ||
9096 | void ResultBuilder::react() { | |
9097 | #if defined(CATCH_CONFIG_FAST_COMPILE) | |
9098 | if (m_shouldDebugBreak) { | |
9099 | /////////////////////////////////////////////////////////////////// | |
9100 | // To inspect the state during test, you need to go one level up the callstack | |
9101 | // To go back to the test and change execution, jump over the throw statement | |
9102 | /////////////////////////////////////////////////////////////////// | |
9103 | CATCH_BREAK_INTO_DEBUGGER(); | |
9104 | } | |
9105 | #endif | |
9106 | if( m_shouldThrow ) | |
9107 | throw Catch::TestFailureException(); | |
9108 | } | |
9109 | ||
9110 | bool ResultBuilder::shouldDebugBreak() const { return m_shouldDebugBreak; } | |
9111 | bool ResultBuilder::allowThrows() const { return getCurrentContext().getConfig()->allowThrows(); } | |
9112 | ||
9113 | AssertionResult ResultBuilder::build() const | |
9114 | { | |
9115 | return build( *this ); | |
9116 | } | |
9117 | ||
9118 | // CAVEAT: The returned AssertionResult stores a pointer to the argument expr, | |
9119 | // a temporary DecomposedExpression, which in turn holds references to | |
9120 | // operands, possibly temporary as well. | |
9121 | // It should immediately be passed to handleResult; if the expression | |
9122 | // needs to be reported, its string expansion must be composed before | |
9123 | // the temporaries are destroyed. | |
9124 | AssertionResult ResultBuilder::build( DecomposedExpression const& expr ) const | |
9125 | { | |
9126 | assert( m_data.resultType != ResultWas::Unknown ); | |
9127 | AssertionResultData data = m_data; | |
9128 | ||
9129 | // Flip bool results if FalseTest flag is set | |
9130 | if( isFalseTest( m_assertionInfo.resultDisposition ) ) { | |
9131 | data.negate( expr.isBinaryExpression() ); | |
9132 | } | |
9133 | ||
9134 | data.message = m_stream.oss.str(); | |
9135 | data.decomposedExpression = &expr; // for lazy reconstruction | |
9136 | return AssertionResult( m_assertionInfo, data ); | |
9137 | } | |
9138 | ||
9139 | void ResultBuilder::reconstructExpression( std::string& dest ) const { | |
9140 | dest = m_assertionInfo.capturedExpression; | |
9141 | } | |
9142 | ||
9143 | void ResultBuilder::setExceptionGuard() { | |
9144 | m_guardException = true; | |
9145 | } | |
9146 | void ResultBuilder::unsetExceptionGuard() { | |
9147 | m_guardException = false; | |
9148 | } | |
9149 | ||
9150 | } // end namespace Catch | |
9151 | ||
9152 | // #included from: catch_tag_alias_registry.hpp | |
9153 | #define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED | |
9154 | ||
9155 | namespace Catch { | |
9156 | ||
9157 | TagAliasRegistry::~TagAliasRegistry() {} | |
9158 | ||
9159 | Option<TagAlias> TagAliasRegistry::find( std::string const& alias ) const { | |
9160 | std::map<std::string, TagAlias>::const_iterator it = m_registry.find( alias ); | |
9161 | if( it != m_registry.end() ) | |
9162 | return it->second; | |
9163 | else | |
9164 | return Option<TagAlias>(); | |
9165 | } | |
9166 | ||
9167 | std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { | |
9168 | std::string expandedTestSpec = unexpandedTestSpec; | |
9169 | for( std::map<std::string, TagAlias>::const_iterator it = m_registry.begin(), itEnd = m_registry.end(); | |
9170 | it != itEnd; | |
9171 | ++it ) { | |
9172 | std::size_t pos = expandedTestSpec.find( it->first ); | |
9173 | if( pos != std::string::npos ) { | |
9174 | expandedTestSpec = expandedTestSpec.substr( 0, pos ) + | |
9175 | it->second.tag + | |
9176 | expandedTestSpec.substr( pos + it->first.size() ); | |
9177 | } | |
9178 | } | |
9179 | return expandedTestSpec; | |
9180 | } | |
9181 | ||
9182 | void TagAliasRegistry::add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) { | |
9183 | ||
9184 | if( !startsWith( alias, "[@" ) || !endsWith( alias, ']' ) ) { | |
9185 | std::ostringstream oss; | |
9186 | oss << Colour( Colour::Red ) | |
9187 | << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n" | |
9188 | << Colour( Colour::FileName ) | |
9189 | << lineInfo << '\n'; | |
9190 | throw std::domain_error( oss.str().c_str() ); | |
9191 | } | |
9192 | if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) { | |
9193 | std::ostringstream oss; | |
9194 | oss << Colour( Colour::Red ) | |
9195 | << "error: tag alias, \"" << alias << "\" already registered.\n" | |
9196 | << "\tFirst seen at " | |
9197 | << Colour( Colour::Red ) << find(alias)->lineInfo << '\n' | |
9198 | << Colour( Colour::Red ) << "\tRedefined at " | |
9199 | << Colour( Colour::FileName) << lineInfo << '\n'; | |
9200 | throw std::domain_error( oss.str().c_str() ); | |
9201 | } | |
9202 | } | |
9203 | ||
9204 | ITagAliasRegistry::~ITagAliasRegistry() {} | |
9205 | ||
9206 | ITagAliasRegistry const& ITagAliasRegistry::get() { | |
9207 | return getRegistryHub().getTagAliasRegistry(); | |
9208 | } | |
9209 | ||
9210 | RegistrarForTagAliases::RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { | |
9211 | getMutableRegistryHub().registerTagAlias( alias, tag, lineInfo ); | |
9212 | } | |
9213 | ||
9214 | } // end namespace Catch | |
9215 | ||
9216 | // #included from: catch_matchers_string.hpp | |
9217 | ||
9218 | namespace Catch { | |
9219 | namespace Matchers { | |
9220 | ||
9221 | namespace StdString { | |
9222 | ||
9223 | CasedString::CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ) | |
9224 | : m_caseSensitivity( caseSensitivity ), | |
9225 | m_str( adjustString( str ) ) | |
9226 | {} | |
9227 | std::string CasedString::adjustString( std::string const& str ) const { | |
9228 | return m_caseSensitivity == CaseSensitive::No | |
9229 | ? toLower( str ) | |
9230 | : str; | |
9231 | } | |
9232 | std::string CasedString::caseSensitivitySuffix() const { | |
9233 | return m_caseSensitivity == CaseSensitive::No | |
9234 | ? " (case insensitive)" | |
9235 | : std::string(); | |
9236 | } | |
9237 | ||
9238 | StringMatcherBase::StringMatcherBase( std::string const& operation, CasedString const& comparator ) | |
9239 | : m_comparator( comparator ), | |
9240 | m_operation( operation ) { | |
9241 | } | |
9242 | ||
9243 | std::string StringMatcherBase::describe() const { | |
9244 | std::string description; | |
9245 | description.reserve(5 + m_operation.size() + m_comparator.m_str.size() + | |
9246 | m_comparator.caseSensitivitySuffix().size()); | |
9247 | description += m_operation; | |
9248 | description += ": \""; | |
9249 | description += m_comparator.m_str; | |
9250 | description += "\""; | |
9251 | description += m_comparator.caseSensitivitySuffix(); | |
9252 | return description; | |
9253 | } | |
9254 | ||
9255 | EqualsMatcher::EqualsMatcher( CasedString const& comparator ) : StringMatcherBase( "equals", comparator ) {} | |
9256 | ||
9257 | bool EqualsMatcher::match( std::string const& source ) const { | |
9258 | return m_comparator.adjustString( source ) == m_comparator.m_str; | |
9259 | } | |
9260 | ||
9261 | ContainsMatcher::ContainsMatcher( CasedString const& comparator ) : StringMatcherBase( "contains", comparator ) {} | |
9262 | ||
9263 | bool ContainsMatcher::match( std::string const& source ) const { | |
9264 | return contains( m_comparator.adjustString( source ), m_comparator.m_str ); | |
9265 | } | |
9266 | ||
9267 | StartsWithMatcher::StartsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "starts with", comparator ) {} | |
9268 | ||
9269 | bool StartsWithMatcher::match( std::string const& source ) const { | |
9270 | return startsWith( m_comparator.adjustString( source ), m_comparator.m_str ); | |
9271 | } | |
9272 | ||
9273 | EndsWithMatcher::EndsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "ends with", comparator ) {} | |
9274 | ||
9275 | bool EndsWithMatcher::match( std::string const& source ) const { | |
9276 | return endsWith( m_comparator.adjustString( source ), m_comparator.m_str ); | |
9277 | } | |
9278 | ||
9279 | } // namespace StdString | |
9280 | ||
9281 | StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity ) { | |
9282 | return StdString::EqualsMatcher( StdString::CasedString( str, caseSensitivity) ); | |
9283 | } | |
9284 | StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity ) { | |
9285 | return StdString::ContainsMatcher( StdString::CasedString( str, caseSensitivity) ); | |
9286 | } | |
9287 | StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) { | |
9288 | return StdString::EndsWithMatcher( StdString::CasedString( str, caseSensitivity) ); | |
9289 | } | |
9290 | StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) { | |
9291 | return StdString::StartsWithMatcher( StdString::CasedString( str, caseSensitivity) ); | |
9292 | } | |
9293 | ||
9294 | } // namespace Matchers | |
9295 | } // namespace Catch | |
9296 | // #included from: ../reporters/catch_reporter_multi.hpp | |
9297 | #define TWOBLUECUBES_CATCH_REPORTER_MULTI_HPP_INCLUDED | |
9298 | ||
9299 | namespace Catch { | |
9300 | ||
9301 | class MultipleReporters : public SharedImpl<IStreamingReporter> { | |
9302 | typedef std::vector<Ptr<IStreamingReporter> > Reporters; | |
9303 | Reporters m_reporters; | |
9304 | ||
9305 | public: | |
9306 | void add( Ptr<IStreamingReporter> const& reporter ) { | |
9307 | m_reporters.push_back( reporter ); | |
9308 | } | |
9309 | ||
9310 | public: // IStreamingReporter | |
9311 | ||
9312 | virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { | |
9313 | return m_reporters[0]->getPreferences(); | |
9314 | } | |
9315 | ||
9316 | virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { | |
9317 | for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); | |
9318 | it != itEnd; | |
9319 | ++it ) | |
9320 | (*it)->noMatchingTestCases( spec ); | |
9321 | } | |
9322 | ||
9323 | virtual void testRunStarting( TestRunInfo const& testRunInfo ) CATCH_OVERRIDE { | |
9324 | for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); | |
9325 | it != itEnd; | |
9326 | ++it ) | |
9327 | (*it)->testRunStarting( testRunInfo ); | |
9328 | } | |
9329 | ||
9330 | virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { | |
9331 | for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); | |
9332 | it != itEnd; | |
9333 | ++it ) | |
9334 | (*it)->testGroupStarting( groupInfo ); | |
9335 | } | |
9336 | ||
9337 | virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { | |
9338 | for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); | |
9339 | it != itEnd; | |
9340 | ++it ) | |
9341 | (*it)->testCaseStarting( testInfo ); | |
9342 | } | |
9343 | ||
9344 | virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { | |
9345 | for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); | |
9346 | it != itEnd; | |
9347 | ++it ) | |
9348 | (*it)->sectionStarting( sectionInfo ); | |
9349 | } | |
9350 | ||
9351 | virtual void assertionStarting( AssertionInfo const& assertionInfo ) CATCH_OVERRIDE { | |
9352 | for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); | |
9353 | it != itEnd; | |
9354 | ++it ) | |
9355 | (*it)->assertionStarting( assertionInfo ); | |
9356 | } | |
9357 | ||
9358 | // The return value indicates if the messages buffer should be cleared: | |
9359 | virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { | |
9360 | bool clearBuffer = false; | |
9361 | for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); | |
9362 | it != itEnd; | |
9363 | ++it ) | |
9364 | clearBuffer |= (*it)->assertionEnded( assertionStats ); | |
9365 | return clearBuffer; | |
9366 | } | |
9367 | ||
9368 | virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { | |
9369 | for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); | |
9370 | it != itEnd; | |
9371 | ++it ) | |
9372 | (*it)->sectionEnded( sectionStats ); | |
9373 | } | |
9374 | ||
9375 | virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { | |
9376 | for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); | |
9377 | it != itEnd; | |
9378 | ++it ) | |
9379 | (*it)->testCaseEnded( testCaseStats ); | |
9380 | } | |
9381 | ||
9382 | virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { | |
9383 | for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); | |
9384 | it != itEnd; | |
9385 | ++it ) | |
9386 | (*it)->testGroupEnded( testGroupStats ); | |
9387 | } | |
9388 | ||
9389 | virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { | |
9390 | for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); | |
9391 | it != itEnd; | |
9392 | ++it ) | |
9393 | (*it)->testRunEnded( testRunStats ); | |
9394 | } | |
9395 | ||
9396 | virtual void skipTest( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { | |
9397 | for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); | |
9398 | it != itEnd; | |
9399 | ++it ) | |
9400 | (*it)->skipTest( testInfo ); | |
9401 | } | |
9402 | ||
9403 | virtual MultipleReporters* tryAsMulti() CATCH_OVERRIDE { | |
9404 | return this; | |
9405 | } | |
9406 | ||
9407 | }; | |
9408 | ||
9409 | Ptr<IStreamingReporter> addReporter( Ptr<IStreamingReporter> const& existingReporter, Ptr<IStreamingReporter> const& additionalReporter ) { | |
9410 | Ptr<IStreamingReporter> resultingReporter; | |
9411 | ||
9412 | if( existingReporter ) { | |
9413 | MultipleReporters* multi = existingReporter->tryAsMulti(); | |
9414 | if( !multi ) { | |
9415 | multi = new MultipleReporters; | |
9416 | resultingReporter = Ptr<IStreamingReporter>( multi ); | |
9417 | if( existingReporter ) | |
9418 | multi->add( existingReporter ); | |
9419 | } | |
9420 | else | |
9421 | resultingReporter = existingReporter; | |
9422 | multi->add( additionalReporter ); | |
9423 | } | |
9424 | else | |
9425 | resultingReporter = additionalReporter; | |
9426 | ||
9427 | return resultingReporter; | |
9428 | } | |
9429 | ||
9430 | } // end namespace Catch | |
9431 | ||
9432 | // #included from: ../reporters/catch_reporter_xml.hpp | |
9433 | #define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED | |
9434 | ||
9435 | // #included from: catch_reporter_bases.hpp | |
9436 | #define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED | |
9437 | ||
9438 | #include <cstring> | |
9439 | #include <cfloat> | |
9440 | #include <cstdio> | |
9441 | #include <assert.h> | |
9442 | ||
9443 | namespace Catch { | |
9444 | ||
9445 | namespace { | |
9446 | // Because formatting using c++ streams is stateful, drop down to C is required | |
9447 | // Alternatively we could use stringstream, but its performance is... not good. | |
9448 | std::string getFormattedDuration( double duration ) { | |
9449 | // Max exponent + 1 is required to represent the whole part | |
9450 | // + 1 for decimal point | |
9451 | // + 3 for the 3 decimal places | |
9452 | // + 1 for null terminator | |
9453 | const size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1; | |
9454 | char buffer[maxDoubleSize]; | |
9455 | ||
9456 | // Save previous errno, to prevent sprintf from overwriting it | |
9457 | ErrnoGuard guard; | |
9458 | #ifdef _MSC_VER | |
9459 | sprintf_s(buffer, "%.3f", duration); | |
9460 | #else | |
9461 | sprintf(buffer, "%.3f", duration); | |
9462 | #endif | |
9463 | return std::string(buffer); | |
9464 | } | |
9465 | } | |
9466 | ||
9467 | struct StreamingReporterBase : SharedImpl<IStreamingReporter> { | |
9468 | ||
9469 | StreamingReporterBase( ReporterConfig const& _config ) | |
9470 | : m_config( _config.fullConfig() ), | |
9471 | stream( _config.stream() ) | |
9472 | { | |
9473 | m_reporterPrefs.shouldRedirectStdOut = false; | |
9474 | } | |
9475 | ||
9476 | virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { | |
9477 | return m_reporterPrefs; | |
9478 | } | |
9479 | ||
9480 | virtual ~StreamingReporterBase() CATCH_OVERRIDE; | |
9481 | ||
9482 | virtual void noMatchingTestCases( std::string const& ) CATCH_OVERRIDE {} | |
9483 | ||
9484 | virtual void testRunStarting( TestRunInfo const& _testRunInfo ) CATCH_OVERRIDE { | |
9485 | currentTestRunInfo = _testRunInfo; | |
9486 | } | |
9487 | virtual void testGroupStarting( GroupInfo const& _groupInfo ) CATCH_OVERRIDE { | |
9488 | currentGroupInfo = _groupInfo; | |
9489 | } | |
9490 | ||
9491 | virtual void testCaseStarting( TestCaseInfo const& _testInfo ) CATCH_OVERRIDE { | |
9492 | currentTestCaseInfo = _testInfo; | |
9493 | } | |
9494 | virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE { | |
9495 | m_sectionStack.push_back( _sectionInfo ); | |
9496 | } | |
9497 | ||
9498 | virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) CATCH_OVERRIDE { | |
9499 | m_sectionStack.pop_back(); | |
9500 | } | |
9501 | virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) CATCH_OVERRIDE { | |
9502 | currentTestCaseInfo.reset(); | |
9503 | } | |
9504 | virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) CATCH_OVERRIDE { | |
9505 | currentGroupInfo.reset(); | |
9506 | } | |
9507 | virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) CATCH_OVERRIDE { | |
9508 | currentTestCaseInfo.reset(); | |
9509 | currentGroupInfo.reset(); | |
9510 | currentTestRunInfo.reset(); | |
9511 | } | |
9512 | ||
9513 | virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE { | |
9514 | // Don't do anything with this by default. | |
9515 | // It can optionally be overridden in the derived class. | |
9516 | } | |
9517 | ||
9518 | Ptr<IConfig const> m_config; | |
9519 | std::ostream& stream; | |
9520 | ||
9521 | LazyStat<TestRunInfo> currentTestRunInfo; | |
9522 | LazyStat<GroupInfo> currentGroupInfo; | |
9523 | LazyStat<TestCaseInfo> currentTestCaseInfo; | |
9524 | ||
9525 | std::vector<SectionInfo> m_sectionStack; | |
9526 | ReporterPreferences m_reporterPrefs; | |
9527 | }; | |
9528 | ||
9529 | struct CumulativeReporterBase : SharedImpl<IStreamingReporter> { | |
9530 | template<typename T, typename ChildNodeT> | |
9531 | struct Node : SharedImpl<> { | |
9532 | explicit Node( T const& _value ) : value( _value ) {} | |
9533 | virtual ~Node() {} | |
9534 | ||
9535 | typedef std::vector<Ptr<ChildNodeT> > ChildNodes; | |
9536 | T value; | |
9537 | ChildNodes children; | |
9538 | }; | |
9539 | struct SectionNode : SharedImpl<> { | |
9540 | explicit SectionNode( SectionStats const& _stats ) : stats( _stats ) {} | |
9541 | virtual ~SectionNode(); | |
9542 | ||
9543 | bool operator == ( SectionNode const& other ) const { | |
9544 | return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo; | |
9545 | } | |
9546 | bool operator == ( Ptr<SectionNode> const& other ) const { | |
9547 | return operator==( *other ); | |
9548 | } | |
9549 | ||
9550 | SectionStats stats; | |
9551 | typedef std::vector<Ptr<SectionNode> > ChildSections; | |
9552 | typedef std::vector<AssertionStats> Assertions; | |
9553 | ChildSections childSections; | |
9554 | Assertions assertions; | |
9555 | std::string stdOut; | |
9556 | std::string stdErr; | |
9557 | }; | |
9558 | ||
9559 | struct BySectionInfo { | |
9560 | BySectionInfo( SectionInfo const& other ) : m_other( other ) {} | |
9561 | BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} | |
9562 | bool operator() ( Ptr<SectionNode> const& node ) const { | |
9563 | return node->stats.sectionInfo.lineInfo == m_other.lineInfo; | |
9564 | } | |
9565 | private: | |
9566 | void operator=( BySectionInfo const& ); | |
9567 | SectionInfo const& m_other; | |
9568 | }; | |
9569 | ||
9570 | typedef Node<TestCaseStats, SectionNode> TestCaseNode; | |
9571 | typedef Node<TestGroupStats, TestCaseNode> TestGroupNode; | |
9572 | typedef Node<TestRunStats, TestGroupNode> TestRunNode; | |
9573 | ||
9574 | CumulativeReporterBase( ReporterConfig const& _config ) | |
9575 | : m_config( _config.fullConfig() ), | |
9576 | stream( _config.stream() ) | |
9577 | { | |
9578 | m_reporterPrefs.shouldRedirectStdOut = false; | |
9579 | } | |
9580 | ~CumulativeReporterBase(); | |
9581 | ||
9582 | virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { | |
9583 | return m_reporterPrefs; | |
9584 | } | |
9585 | ||
9586 | virtual void testRunStarting( TestRunInfo const& ) CATCH_OVERRIDE {} | |
9587 | virtual void testGroupStarting( GroupInfo const& ) CATCH_OVERRIDE {} | |
9588 | ||
9589 | virtual void testCaseStarting( TestCaseInfo const& ) CATCH_OVERRIDE {} | |
9590 | ||
9591 | virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { | |
9592 | SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); | |
9593 | Ptr<SectionNode> node; | |
9594 | if( m_sectionStack.empty() ) { | |
9595 | if( !m_rootSection ) | |
9596 | m_rootSection = new SectionNode( incompleteStats ); | |
9597 | node = m_rootSection; | |
9598 | } | |
9599 | else { | |
9600 | SectionNode& parentNode = *m_sectionStack.back(); | |
9601 | SectionNode::ChildSections::const_iterator it = | |
9602 | std::find_if( parentNode.childSections.begin(), | |
9603 | parentNode.childSections.end(), | |
9604 | BySectionInfo( sectionInfo ) ); | |
9605 | if( it == parentNode.childSections.end() ) { | |
9606 | node = new SectionNode( incompleteStats ); | |
9607 | parentNode.childSections.push_back( node ); | |
9608 | } | |
9609 | else | |
9610 | node = *it; | |
9611 | } | |
9612 | m_sectionStack.push_back( node ); | |
9613 | m_deepestSection = node; | |
9614 | } | |
9615 | ||
9616 | virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} | |
9617 | ||
9618 | virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { | |
9619 | assert( !m_sectionStack.empty() ); | |
9620 | SectionNode& sectionNode = *m_sectionStack.back(); | |
9621 | sectionNode.assertions.push_back( assertionStats ); | |
9622 | // AssertionResult holds a pointer to a temporary DecomposedExpression, | |
9623 | // which getExpandedExpression() calls to build the expression string. | |
9624 | // Our section stack copy of the assertionResult will likely outlive the | |
9625 | // temporary, so it must be expanded or discarded now to avoid calling | |
9626 | // a destroyed object later. | |
9627 | prepareExpandedExpression( sectionNode.assertions.back().assertionResult ); | |
9628 | return true; | |
9629 | } | |
9630 | virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { | |
9631 | assert( !m_sectionStack.empty() ); | |
9632 | SectionNode& node = *m_sectionStack.back(); | |
9633 | node.stats = sectionStats; | |
9634 | m_sectionStack.pop_back(); | |
9635 | } | |
9636 | virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { | |
9637 | Ptr<TestCaseNode> node = new TestCaseNode( testCaseStats ); | |
9638 | assert( m_sectionStack.size() == 0 ); | |
9639 | node->children.push_back( m_rootSection ); | |
9640 | m_testCases.push_back( node ); | |
9641 | m_rootSection.reset(); | |
9642 | ||
9643 | assert( m_deepestSection ); | |
9644 | m_deepestSection->stdOut = testCaseStats.stdOut; | |
9645 | m_deepestSection->stdErr = testCaseStats.stdErr; | |
9646 | } | |
9647 | virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { | |
9648 | Ptr<TestGroupNode> node = new TestGroupNode( testGroupStats ); | |
9649 | node->children.swap( m_testCases ); | |
9650 | m_testGroups.push_back( node ); | |
9651 | } | |
9652 | virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { | |
9653 | Ptr<TestRunNode> node = new TestRunNode( testRunStats ); | |
9654 | node->children.swap( m_testGroups ); | |
9655 | m_testRuns.push_back( node ); | |
9656 | testRunEndedCumulative(); | |
9657 | } | |
9658 | virtual void testRunEndedCumulative() = 0; | |
9659 | ||
9660 | virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE {} | |
9661 | ||
9662 | virtual void prepareExpandedExpression( AssertionResult& result ) const { | |
9663 | if( result.isOk() ) | |
9664 | result.discardDecomposedExpression(); | |
9665 | else | |
9666 | result.expandDecomposedExpression(); | |
9667 | } | |
9668 | ||
9669 | Ptr<IConfig const> m_config; | |
9670 | std::ostream& stream; | |
9671 | std::vector<AssertionStats> m_assertions; | |
9672 | std::vector<std::vector<Ptr<SectionNode> > > m_sections; | |
9673 | std::vector<Ptr<TestCaseNode> > m_testCases; | |
9674 | std::vector<Ptr<TestGroupNode> > m_testGroups; | |
9675 | ||
9676 | std::vector<Ptr<TestRunNode> > m_testRuns; | |
9677 | ||
9678 | Ptr<SectionNode> m_rootSection; | |
9679 | Ptr<SectionNode> m_deepestSection; | |
9680 | std::vector<Ptr<SectionNode> > m_sectionStack; | |
9681 | ReporterPreferences m_reporterPrefs; | |
9682 | ||
9683 | }; | |
9684 | ||
9685 | template<char C> | |
9686 | char const* getLineOfChars() { | |
9687 | static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; | |
9688 | if( !*line ) { | |
9689 | std::memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); | |
9690 | line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; | |
9691 | } | |
9692 | return line; | |
9693 | } | |
9694 | ||
9695 | struct TestEventListenerBase : StreamingReporterBase { | |
9696 | TestEventListenerBase( ReporterConfig const& _config ) | |
9697 | : StreamingReporterBase( _config ) | |
9698 | {} | |
9699 | ||
9700 | virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} | |
9701 | virtual bool assertionEnded( AssertionStats const& ) CATCH_OVERRIDE { | |
9702 | return false; | |
9703 | } | |
9704 | }; | |
9705 | ||
9706 | } // end namespace Catch | |
9707 | ||
9708 | // #included from: ../internal/catch_reporter_registrars.hpp | |
9709 | #define TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED | |
9710 | ||
9711 | namespace Catch { | |
9712 | ||
9713 | template<typename T> | |
9714 | class LegacyReporterRegistrar { | |
9715 | ||
9716 | class ReporterFactory : public IReporterFactory { | |
9717 | virtual IStreamingReporter* create( ReporterConfig const& config ) const { | |
9718 | return new LegacyReporterAdapter( new T( config ) ); | |
9719 | } | |
9720 | ||
9721 | virtual std::string getDescription() const { | |
9722 | return T::getDescription(); | |
9723 | } | |
9724 | }; | |
9725 | ||
9726 | public: | |
9727 | ||
9728 | LegacyReporterRegistrar( std::string const& name ) { | |
9729 | getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); | |
9730 | } | |
9731 | }; | |
9732 | ||
9733 | template<typename T> | |
9734 | class ReporterRegistrar { | |
9735 | ||
9736 | class ReporterFactory : public SharedImpl<IReporterFactory> { | |
9737 | ||
9738 | // *** Please Note ***: | |
9739 | // - If you end up here looking at a compiler error because it's trying to register | |
9740 | // your custom reporter class be aware that the native reporter interface has changed | |
9741 | // to IStreamingReporter. The "legacy" interface, IReporter, is still supported via | |
9742 | // an adapter. Just use REGISTER_LEGACY_REPORTER to take advantage of the adapter. | |
9743 | // However please consider updating to the new interface as the old one is now | |
9744 | // deprecated and will probably be removed quite soon! | |
9745 | // Please contact me via github if you have any questions at all about this. | |
9746 | // In fact, ideally, please contact me anyway to let me know you've hit this - as I have | |
9747 | // no idea who is actually using custom reporters at all (possibly no-one!). | |
9748 | // The new interface is designed to minimise exposure to interface changes in the future. | |
9749 | virtual IStreamingReporter* create( ReporterConfig const& config ) const { | |
9750 | return new T( config ); | |
9751 | } | |
9752 | ||
9753 | virtual std::string getDescription() const { | |
9754 | return T::getDescription(); | |
9755 | } | |
9756 | }; | |
9757 | ||
9758 | public: | |
9759 | ||
9760 | ReporterRegistrar( std::string const& name ) { | |
9761 | getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); | |
9762 | } | |
9763 | }; | |
9764 | ||
9765 | template<typename T> | |
9766 | class ListenerRegistrar { | |
9767 | ||
9768 | class ListenerFactory : public SharedImpl<IReporterFactory> { | |
9769 | ||
9770 | virtual IStreamingReporter* create( ReporterConfig const& config ) const { | |
9771 | return new T( config ); | |
9772 | } | |
9773 | virtual std::string getDescription() const { | |
9774 | return std::string(); | |
9775 | } | |
9776 | }; | |
9777 | ||
9778 | public: | |
9779 | ||
9780 | ListenerRegistrar() { | |
9781 | getMutableRegistryHub().registerListener( new ListenerFactory() ); | |
9782 | } | |
9783 | }; | |
9784 | } | |
9785 | ||
9786 | #define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \ | |
9787 | namespace{ Catch::LegacyReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); } | |
9788 | ||
9789 | #define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \ | |
9790 | namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); } | |
9791 | ||
9792 | // Deprecated - use the form without INTERNAL_ | |
9793 | #define INTERNAL_CATCH_REGISTER_LISTENER( listenerType ) \ | |
9794 | namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; } | |
9795 | ||
9796 | #define CATCH_REGISTER_LISTENER( listenerType ) \ | |
9797 | namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; } | |
9798 | ||
9799 | // #included from: ../internal/catch_xmlwriter.hpp | |
9800 | #define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED | |
9801 | ||
9802 | #include <sstream> | |
9803 | #include <string> | |
9804 | #include <vector> | |
9805 | #include <iomanip> | |
9806 | ||
9807 | namespace Catch { | |
9808 | ||
9809 | class XmlEncode { | |
9810 | public: | |
9811 | enum ForWhat { ForTextNodes, ForAttributes }; | |
9812 | ||
9813 | XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ) | |
9814 | : m_str( str ), | |
9815 | m_forWhat( forWhat ) | |
9816 | {} | |
9817 | ||
9818 | void encodeTo( std::ostream& os ) const { | |
9819 | ||
9820 | // Apostrophe escaping not necessary if we always use " to write attributes | |
9821 | // (see: http://www.w3.org/TR/xml/#syntax) | |
9822 | ||
9823 | for( std::size_t i = 0; i < m_str.size(); ++ i ) { | |
9824 | char c = m_str[i]; | |
9825 | switch( c ) { | |
9826 | case '<': os << "<"; break; | |
9827 | case '&': os << "&"; break; | |
9828 | ||
9829 | case '>': | |
9830 | // See: http://www.w3.org/TR/xml/#syntax | |
9831 | if( i > 2 && m_str[i-1] == ']' && m_str[i-2] == ']' ) | |
9832 | os << ">"; | |
9833 | else | |
9834 | os << c; | |
9835 | break; | |
9836 | ||
9837 | case '\"': | |
9838 | if( m_forWhat == ForAttributes ) | |
9839 | os << """; | |
9840 | else | |
9841 | os << c; | |
9842 | break; | |
9843 | ||
9844 | default: | |
9845 | // Escape control chars - based on contribution by @espenalb in PR #465 and | |
9846 | // by @mrpi PR #588 | |
9847 | if ( ( c >= 0 && c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' ) { | |
9848 | // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0 | |
9849 | os << "\\x" << std::uppercase << std::hex << std::setfill('0') << std::setw(2) | |
9850 | << static_cast<int>( c ); | |
9851 | } | |
9852 | else | |
9853 | os << c; | |
9854 | } | |
9855 | } | |
9856 | } | |
9857 | ||
9858 | friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { | |
9859 | xmlEncode.encodeTo( os ); | |
9860 | return os; | |
9861 | } | |
9862 | ||
9863 | private: | |
9864 | std::string m_str; | |
9865 | ForWhat m_forWhat; | |
9866 | }; | |
9867 | ||
9868 | class XmlWriter { | |
9869 | public: | |
9870 | ||
9871 | class ScopedElement { | |
9872 | public: | |
9873 | ScopedElement( XmlWriter* writer ) | |
9874 | : m_writer( writer ) | |
9875 | {} | |
9876 | ||
9877 | ScopedElement( ScopedElement const& other ) | |
9878 | : m_writer( other.m_writer ){ | |
9879 | other.m_writer = CATCH_NULL; | |
9880 | } | |
9881 | ||
9882 | ~ScopedElement() { | |
9883 | if( m_writer ) | |
9884 | m_writer->endElement(); | |
9885 | } | |
9886 | ||
9887 | ScopedElement& writeText( std::string const& text, bool indent = true ) { | |
9888 | m_writer->writeText( text, indent ); | |
9889 | return *this; | |
9890 | } | |
9891 | ||
9892 | template<typename T> | |
9893 | ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { | |
9894 | m_writer->writeAttribute( name, attribute ); | |
9895 | return *this; | |
9896 | } | |
9897 | ||
9898 | private: | |
9899 | mutable XmlWriter* m_writer; | |
9900 | }; | |
9901 | ||
9902 | XmlWriter() | |
9903 | : m_tagIsOpen( false ), | |
9904 | m_needsNewline( false ), | |
9905 | m_os( Catch::cout() ) | |
9906 | { | |
9907 | writeDeclaration(); | |
9908 | } | |
9909 | ||
9910 | XmlWriter( std::ostream& os ) | |
9911 | : m_tagIsOpen( false ), | |
9912 | m_needsNewline( false ), | |
9913 | m_os( os ) | |
9914 | { | |
9915 | writeDeclaration(); | |
9916 | } | |
9917 | ||
9918 | ~XmlWriter() { | |
9919 | while( !m_tags.empty() ) | |
9920 | endElement(); | |
9921 | } | |
9922 | ||
9923 | XmlWriter& startElement( std::string const& name ) { | |
9924 | ensureTagClosed(); | |
9925 | newlineIfNecessary(); | |
9926 | m_os << m_indent << '<' << name; | |
9927 | m_tags.push_back( name ); | |
9928 | m_indent += " "; | |
9929 | m_tagIsOpen = true; | |
9930 | return *this; | |
9931 | } | |
9932 | ||
9933 | ScopedElement scopedElement( std::string const& name ) { | |
9934 | ScopedElement scoped( this ); | |
9935 | startElement( name ); | |
9936 | return scoped; | |
9937 | } | |
9938 | ||
9939 | XmlWriter& endElement() { | |
9940 | newlineIfNecessary(); | |
9941 | m_indent = m_indent.substr( 0, m_indent.size()-2 ); | |
9942 | if( m_tagIsOpen ) { | |
9943 | m_os << "/>"; | |
9944 | m_tagIsOpen = false; | |
9945 | } | |
9946 | else { | |
9947 | m_os << m_indent << "</" << m_tags.back() << ">"; | |
9948 | } | |
9949 | m_os << std::endl; | |
9950 | m_tags.pop_back(); | |
9951 | return *this; | |
9952 | } | |
9953 | ||
9954 | XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) { | |
9955 | if( !name.empty() && !attribute.empty() ) | |
9956 | m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"'; | |
9957 | return *this; | |
9958 | } | |
9959 | ||
9960 | XmlWriter& writeAttribute( std::string const& name, bool attribute ) { | |
9961 | m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"'; | |
9962 | return *this; | |
9963 | } | |
9964 | ||
9965 | template<typename T> | |
9966 | XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { | |
9967 | std::ostringstream oss; | |
9968 | oss << attribute; | |
9969 | return writeAttribute( name, oss.str() ); | |
9970 | } | |
9971 | ||
9972 | XmlWriter& writeText( std::string const& text, bool indent = true ) { | |
9973 | if( !text.empty() ){ | |
9974 | bool tagWasOpen = m_tagIsOpen; | |
9975 | ensureTagClosed(); | |
9976 | if( tagWasOpen && indent ) | |
9977 | m_os << m_indent; | |
9978 | m_os << XmlEncode( text ); | |
9979 | m_needsNewline = true; | |
9980 | } | |
9981 | return *this; | |
9982 | } | |
9983 | ||
9984 | XmlWriter& writeComment( std::string const& text ) { | |
9985 | ensureTagClosed(); | |
9986 | m_os << m_indent << "<!--" << text << "-->"; | |
9987 | m_needsNewline = true; | |
9988 | return *this; | |
9989 | } | |
9990 | ||
9991 | void writeStylesheetRef( std::string const& url ) { | |
9992 | m_os << "<?xml-stylesheet type=\"text/xsl\" href=\"" << url << "\"?>\n"; | |
9993 | } | |
9994 | ||
9995 | XmlWriter& writeBlankLine() { | |
9996 | ensureTagClosed(); | |
9997 | m_os << '\n'; | |
9998 | return *this; | |
9999 | } | |
10000 | ||
10001 | void ensureTagClosed() { | |
10002 | if( m_tagIsOpen ) { | |
10003 | m_os << ">" << std::endl; | |
10004 | m_tagIsOpen = false; | |
10005 | } | |
10006 | } | |
10007 | ||
10008 | private: | |
10009 | XmlWriter( XmlWriter const& ); | |
10010 | void operator=( XmlWriter const& ); | |
10011 | ||
10012 | void writeDeclaration() { | |
10013 | m_os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; | |
10014 | } | |
10015 | ||
10016 | void newlineIfNecessary() { | |
10017 | if( m_needsNewline ) { | |
10018 | m_os << std::endl; | |
10019 | m_needsNewline = false; | |
10020 | } | |
10021 | } | |
10022 | ||
10023 | bool m_tagIsOpen; | |
10024 | bool m_needsNewline; | |
10025 | std::vector<std::string> m_tags; | |
10026 | std::string m_indent; | |
10027 | std::ostream& m_os; | |
10028 | }; | |
10029 | ||
10030 | } | |
10031 | // #included from: catch_reenable_warnings.h | |
10032 | ||
10033 | #define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED | |
10034 | ||
10035 | #ifdef __clang__ | |
10036 | # ifdef __ICC // icpc defines the __clang__ macro | |
10037 | # pragma warning(pop) | |
10038 | # else | |
10039 | # pragma clang diagnostic pop | |
10040 | # endif | |
10041 | #elif defined __GNUC__ | |
10042 | # pragma GCC diagnostic pop | |
10043 | #endif | |
10044 | ||
10045 | ||
10046 | namespace Catch { | |
10047 | class XmlReporter : public StreamingReporterBase { | |
10048 | public: | |
10049 | XmlReporter( ReporterConfig const& _config ) | |
10050 | : StreamingReporterBase( _config ), | |
10051 | m_xml(_config.stream()), | |
10052 | m_sectionDepth( 0 ) | |
10053 | { | |
10054 | m_reporterPrefs.shouldRedirectStdOut = true; | |
10055 | } | |
10056 | ||
10057 | virtual ~XmlReporter() CATCH_OVERRIDE; | |
10058 | ||
10059 | static std::string getDescription() { | |
10060 | return "Reports test results as an XML document"; | |
10061 | } | |
10062 | ||
10063 | virtual std::string getStylesheetRef() const { | |
10064 | return std::string(); | |
10065 | } | |
10066 | ||
10067 | void writeSourceInfo( SourceLineInfo const& sourceInfo ) { | |
10068 | m_xml | |
10069 | .writeAttribute( "filename", sourceInfo.file ) | |
10070 | .writeAttribute( "line", sourceInfo.line ); | |
10071 | } | |
10072 | ||
10073 | public: // StreamingReporterBase | |
10074 | ||
10075 | virtual void noMatchingTestCases( std::string const& s ) CATCH_OVERRIDE { | |
10076 | StreamingReporterBase::noMatchingTestCases( s ); | |
10077 | } | |
10078 | ||
10079 | virtual void testRunStarting( TestRunInfo const& testInfo ) CATCH_OVERRIDE { | |
10080 | StreamingReporterBase::testRunStarting( testInfo ); | |
10081 | std::string stylesheetRef = getStylesheetRef(); | |
10082 | if( !stylesheetRef.empty() ) | |
10083 | m_xml.writeStylesheetRef( stylesheetRef ); | |
10084 | m_xml.startElement( "Catch" ); | |
10085 | if( !m_config->name().empty() ) | |
10086 | m_xml.writeAttribute( "name", m_config->name() ); | |
10087 | } | |
10088 | ||
10089 | virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { | |
10090 | StreamingReporterBase::testGroupStarting( groupInfo ); | |
10091 | m_xml.startElement( "Group" ) | |
10092 | .writeAttribute( "name", groupInfo.name ); | |
10093 | } | |
10094 | ||
10095 | virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { | |
10096 | StreamingReporterBase::testCaseStarting(testInfo); | |
10097 | m_xml.startElement( "TestCase" ) | |
10098 | .writeAttribute( "name", trim( testInfo.name ) ) | |
10099 | .writeAttribute( "description", testInfo.description ) | |
10100 | .writeAttribute( "tags", testInfo.tagsAsString ); | |
10101 | ||
10102 | writeSourceInfo( testInfo.lineInfo ); | |
10103 | ||
10104 | if ( m_config->showDurations() == ShowDurations::Always ) | |
10105 | m_testCaseTimer.start(); | |
10106 | m_xml.ensureTagClosed(); | |
10107 | } | |
10108 | ||
10109 | virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { | |
10110 | StreamingReporterBase::sectionStarting( sectionInfo ); | |
10111 | if( m_sectionDepth++ > 0 ) { | |
10112 | m_xml.startElement( "Section" ) | |
10113 | .writeAttribute( "name", trim( sectionInfo.name ) ) | |
10114 | .writeAttribute( "description", sectionInfo.description ); | |
10115 | writeSourceInfo( sectionInfo.lineInfo ); | |
10116 | m_xml.ensureTagClosed(); | |
10117 | } | |
10118 | } | |
10119 | ||
10120 | virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { } | |
10121 | ||
10122 | virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { | |
10123 | ||
10124 | AssertionResult const& result = assertionStats.assertionResult; | |
10125 | ||
10126 | bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); | |
10127 | ||
10128 | if( includeResults ) { | |
10129 | // Print any info messages in <Info> tags. | |
10130 | for( std::vector<MessageInfo>::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); | |
10131 | it != itEnd; | |
10132 | ++it ) { | |
10133 | if( it->type == ResultWas::Info ) { | |
10134 | m_xml.scopedElement( "Info" ) | |
10135 | .writeText( it->message ); | |
10136 | } else if ( it->type == ResultWas::Warning ) { | |
10137 | m_xml.scopedElement( "Warning" ) | |
10138 | .writeText( it->message ); | |
10139 | } | |
10140 | } | |
10141 | } | |
10142 | ||
10143 | // Drop out if result was successful but we're not printing them. | |
10144 | if( !includeResults && result.getResultType() != ResultWas::Warning ) | |
10145 | return true; | |
10146 | ||
10147 | // Print the expression if there is one. | |
10148 | if( result.hasExpression() ) { | |
10149 | m_xml.startElement( "Expression" ) | |
10150 | .writeAttribute( "success", result.succeeded() ) | |
10151 | .writeAttribute( "type", result.getTestMacroName() ); | |
10152 | ||
10153 | writeSourceInfo( result.getSourceInfo() ); | |
10154 | ||
10155 | m_xml.scopedElement( "Original" ) | |
10156 | .writeText( result.getExpression() ); | |
10157 | m_xml.scopedElement( "Expanded" ) | |
10158 | .writeText( result.getExpandedExpression() ); | |
10159 | } | |
10160 | ||
10161 | // And... Print a result applicable to each result type. | |
10162 | switch( result.getResultType() ) { | |
10163 | case ResultWas::ThrewException: | |
10164 | m_xml.startElement( "Exception" ); | |
10165 | writeSourceInfo( result.getSourceInfo() ); | |
10166 | m_xml.writeText( result.getMessage() ); | |
10167 | m_xml.endElement(); | |
10168 | break; | |
10169 | case ResultWas::FatalErrorCondition: | |
10170 | m_xml.startElement( "FatalErrorCondition" ); | |
10171 | writeSourceInfo( result.getSourceInfo() ); | |
10172 | m_xml.writeText( result.getMessage() ); | |
10173 | m_xml.endElement(); | |
10174 | break; | |
10175 | case ResultWas::Info: | |
10176 | m_xml.scopedElement( "Info" ) | |
10177 | .writeText( result.getMessage() ); | |
10178 | break; | |
10179 | case ResultWas::Warning: | |
10180 | // Warning will already have been written | |
10181 | break; | |
10182 | case ResultWas::ExplicitFailure: | |
10183 | m_xml.startElement( "Failure" ); | |
10184 | writeSourceInfo( result.getSourceInfo() ); | |
10185 | m_xml.writeText( result.getMessage() ); | |
10186 | m_xml.endElement(); | |
10187 | break; | |
10188 | default: | |
10189 | break; | |
10190 | } | |
10191 | ||
10192 | if( result.hasExpression() ) | |
10193 | m_xml.endElement(); | |
10194 | ||
10195 | return true; | |
10196 | } | |
10197 | ||
10198 | virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { | |
10199 | StreamingReporterBase::sectionEnded( sectionStats ); | |
10200 | if( --m_sectionDepth > 0 ) { | |
10201 | XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); | |
10202 | e.writeAttribute( "successes", sectionStats.assertions.passed ); | |
10203 | e.writeAttribute( "failures", sectionStats.assertions.failed ); | |
10204 | e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); | |
10205 | ||
10206 | if ( m_config->showDurations() == ShowDurations::Always ) | |
10207 | e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); | |
10208 | ||
10209 | m_xml.endElement(); | |
10210 | } | |
10211 | } | |
10212 | ||
10213 | virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { | |
10214 | StreamingReporterBase::testCaseEnded( testCaseStats ); | |
10215 | XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); | |
10216 | e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); | |
10217 | ||
10218 | if ( m_config->showDurations() == ShowDurations::Always ) | |
10219 | e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); | |
10220 | ||
10221 | if( !testCaseStats.stdOut.empty() ) | |
10222 | m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), false ); | |
10223 | if( !testCaseStats.stdErr.empty() ) | |
10224 | m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), false ); | |
10225 | ||
10226 | m_xml.endElement(); | |
10227 | } | |
10228 | ||
10229 | virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { | |
10230 | StreamingReporterBase::testGroupEnded( testGroupStats ); | |
10231 | // TODO: Check testGroupStats.aborting and act accordingly. | |
10232 | m_xml.scopedElement( "OverallResults" ) | |
10233 | .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) | |
10234 | .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) | |
10235 | .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); | |
10236 | m_xml.endElement(); | |
10237 | } | |
10238 | ||
10239 | virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { | |
10240 | StreamingReporterBase::testRunEnded( testRunStats ); | |
10241 | m_xml.scopedElement( "OverallResults" ) | |
10242 | .writeAttribute( "successes", testRunStats.totals.assertions.passed ) | |
10243 | .writeAttribute( "failures", testRunStats.totals.assertions.failed ) | |
10244 | .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); | |
10245 | m_xml.endElement(); | |
10246 | } | |
10247 | ||
10248 | private: | |
10249 | Timer m_testCaseTimer; | |
10250 | XmlWriter m_xml; | |
10251 | int m_sectionDepth; | |
10252 | }; | |
10253 | ||
10254 | INTERNAL_CATCH_REGISTER_REPORTER( "xml", XmlReporter ) | |
10255 | ||
10256 | } // end namespace Catch | |
10257 | ||
10258 | // #included from: ../reporters/catch_reporter_junit.hpp | |
10259 | #define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED | |
10260 | ||
10261 | #include <assert.h> | |
10262 | ||
10263 | namespace Catch { | |
10264 | ||
10265 | namespace { | |
10266 | std::string getCurrentTimestamp() { | |
10267 | // Beware, this is not reentrant because of backward compatibility issues | |
10268 | // Also, UTC only, again because of backward compatibility (%z is C++11) | |
10269 | time_t rawtime; | |
10270 | std::time(&rawtime); | |
10271 | const size_t timeStampSize = sizeof("2017-01-16T17:06:45Z"); | |
10272 | ||
10273 | #ifdef _MSC_VER | |
10274 | std::tm timeInfo = {}; | |
10275 | gmtime_s(&timeInfo, &rawtime); | |
10276 | #else | |
10277 | std::tm* timeInfo; | |
10278 | timeInfo = std::gmtime(&rawtime); | |
10279 | #endif | |
10280 | ||
10281 | char timeStamp[timeStampSize]; | |
10282 | const char * const fmt = "%Y-%m-%dT%H:%M:%SZ"; | |
10283 | ||
10284 | #ifdef _MSC_VER | |
10285 | std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); | |
10286 | #else | |
10287 | std::strftime(timeStamp, timeStampSize, fmt, timeInfo); | |
10288 | #endif | |
10289 | return std::string(timeStamp); | |
10290 | } | |
10291 | ||
10292 | } | |
10293 | ||
10294 | class JunitReporter : public CumulativeReporterBase { | |
10295 | public: | |
10296 | JunitReporter( ReporterConfig const& _config ) | |
10297 | : CumulativeReporterBase( _config ), | |
10298 | xml( _config.stream() ), | |
10299 | m_okToFail( false ) | |
10300 | { | |
10301 | m_reporterPrefs.shouldRedirectStdOut = true; | |
10302 | } | |
10303 | ||
10304 | virtual ~JunitReporter() CATCH_OVERRIDE; | |
10305 | ||
10306 | static std::string getDescription() { | |
10307 | return "Reports test results in an XML format that looks like Ant's junitreport target"; | |
10308 | } | |
10309 | ||
10310 | virtual void noMatchingTestCases( std::string const& /*spec*/ ) CATCH_OVERRIDE {} | |
10311 | ||
10312 | virtual void testRunStarting( TestRunInfo const& runInfo ) CATCH_OVERRIDE { | |
10313 | CumulativeReporterBase::testRunStarting( runInfo ); | |
10314 | xml.startElement( "testsuites" ); | |
10315 | } | |
10316 | ||
10317 | virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { | |
10318 | suiteTimer.start(); | |
10319 | stdOutForSuite.str(""); | |
10320 | stdErrForSuite.str(""); | |
10321 | unexpectedExceptions = 0; | |
10322 | CumulativeReporterBase::testGroupStarting( groupInfo ); | |
10323 | } | |
10324 | ||
10325 | virtual void testCaseStarting( TestCaseInfo const& testCaseInfo ) CATCH_OVERRIDE { | |
10326 | m_okToFail = testCaseInfo.okToFail(); | |
10327 | } | |
10328 | virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { | |
10329 | if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail ) | |
10330 | unexpectedExceptions++; | |
10331 | return CumulativeReporterBase::assertionEnded( assertionStats ); | |
10332 | } | |
10333 | ||
10334 | virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { | |
10335 | stdOutForSuite << testCaseStats.stdOut; | |
10336 | stdErrForSuite << testCaseStats.stdErr; | |
10337 | CumulativeReporterBase::testCaseEnded( testCaseStats ); | |
10338 | } | |
10339 | ||
10340 | virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { | |
10341 | double suiteTime = suiteTimer.getElapsedSeconds(); | |
10342 | CumulativeReporterBase::testGroupEnded( testGroupStats ); | |
10343 | writeGroup( *m_testGroups.back(), suiteTime ); | |
10344 | } | |
10345 | ||
10346 | virtual void testRunEndedCumulative() CATCH_OVERRIDE { | |
10347 | xml.endElement(); | |
10348 | } | |
10349 | ||
10350 | void writeGroup( TestGroupNode const& groupNode, double suiteTime ) { | |
10351 | XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); | |
10352 | TestGroupStats const& stats = groupNode.value; | |
10353 | xml.writeAttribute( "name", stats.groupInfo.name ); | |
10354 | xml.writeAttribute( "errors", unexpectedExceptions ); | |
10355 | xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions ); | |
10356 | xml.writeAttribute( "tests", stats.totals.assertions.total() ); | |
10357 | xml.writeAttribute( "hostname", "tbd" ); // !TBD | |
10358 | if( m_config->showDurations() == ShowDurations::Never ) | |
10359 | xml.writeAttribute( "time", "" ); | |
10360 | else | |
10361 | xml.writeAttribute( "time", suiteTime ); | |
10362 | xml.writeAttribute( "timestamp", getCurrentTimestamp() ); | |
10363 | ||
10364 | // Write test cases | |
10365 | for( TestGroupNode::ChildNodes::const_iterator | |
10366 | it = groupNode.children.begin(), itEnd = groupNode.children.end(); | |
10367 | it != itEnd; | |
10368 | ++it ) | |
10369 | writeTestCase( **it ); | |
10370 | ||
10371 | xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite.str() ), false ); | |
10372 | xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite.str() ), false ); | |
10373 | } | |
10374 | ||
10375 | void writeTestCase( TestCaseNode const& testCaseNode ) { | |
10376 | TestCaseStats const& stats = testCaseNode.value; | |
10377 | ||
10378 | // All test cases have exactly one section - which represents the | |
10379 | // test case itself. That section may have 0-n nested sections | |
10380 | assert( testCaseNode.children.size() == 1 ); | |
10381 | SectionNode const& rootSection = *testCaseNode.children.front(); | |
10382 | ||
10383 | std::string className = stats.testInfo.className; | |
10384 | ||
10385 | if( className.empty() ) { | |
10386 | if( rootSection.childSections.empty() ) | |
10387 | className = "global"; | |
10388 | } | |
10389 | writeSection( className, "", rootSection ); | |
10390 | } | |
10391 | ||
10392 | void writeSection( std::string const& className, | |
10393 | std::string const& rootName, | |
10394 | SectionNode const& sectionNode ) { | |
10395 | std::string name = trim( sectionNode.stats.sectionInfo.name ); | |
10396 | if( !rootName.empty() ) | |
10397 | name = rootName + '/' + name; | |
10398 | ||
10399 | if( !sectionNode.assertions.empty() || | |
10400 | !sectionNode.stdOut.empty() || | |
10401 | !sectionNode.stdErr.empty() ) { | |
10402 | XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); | |
10403 | if( className.empty() ) { | |
10404 | xml.writeAttribute( "classname", name ); | |
10405 | xml.writeAttribute( "name", "root" ); | |
10406 | } | |
10407 | else { | |
10408 | xml.writeAttribute( "classname", className ); | |
10409 | xml.writeAttribute( "name", name ); | |
10410 | } | |
10411 | xml.writeAttribute( "time", Catch::toString( sectionNode.stats.durationInSeconds ) ); | |
10412 | ||
10413 | writeAssertions( sectionNode ); | |
10414 | ||
10415 | if( !sectionNode.stdOut.empty() ) | |
10416 | xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false ); | |
10417 | if( !sectionNode.stdErr.empty() ) | |
10418 | xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false ); | |
10419 | } | |
10420 | for( SectionNode::ChildSections::const_iterator | |
10421 | it = sectionNode.childSections.begin(), | |
10422 | itEnd = sectionNode.childSections.end(); | |
10423 | it != itEnd; | |
10424 | ++it ) | |
10425 | if( className.empty() ) | |
10426 | writeSection( name, "", **it ); | |
10427 | else | |
10428 | writeSection( className, name, **it ); | |
10429 | } | |
10430 | ||
10431 | void writeAssertions( SectionNode const& sectionNode ) { | |
10432 | for( SectionNode::Assertions::const_iterator | |
10433 | it = sectionNode.assertions.begin(), itEnd = sectionNode.assertions.end(); | |
10434 | it != itEnd; | |
10435 | ++it ) | |
10436 | writeAssertion( *it ); | |
10437 | } | |
10438 | void writeAssertion( AssertionStats const& stats ) { | |
10439 | AssertionResult const& result = stats.assertionResult; | |
10440 | if( !result.isOk() ) { | |
10441 | std::string elementName; | |
10442 | switch( result.getResultType() ) { | |
10443 | case ResultWas::ThrewException: | |
10444 | case ResultWas::FatalErrorCondition: | |
10445 | elementName = "error"; | |
10446 | break; | |
10447 | case ResultWas::ExplicitFailure: | |
10448 | elementName = "failure"; | |
10449 | break; | |
10450 | case ResultWas::ExpressionFailed: | |
10451 | elementName = "failure"; | |
10452 | break; | |
10453 | case ResultWas::DidntThrowException: | |
10454 | elementName = "failure"; | |
10455 | break; | |
10456 | ||
10457 | // We should never see these here: | |
10458 | case ResultWas::Info: | |
10459 | case ResultWas::Warning: | |
10460 | case ResultWas::Ok: | |
10461 | case ResultWas::Unknown: | |
10462 | case ResultWas::FailureBit: | |
10463 | case ResultWas::Exception: | |
10464 | elementName = "internalError"; | |
10465 | break; | |
10466 | } | |
10467 | ||
10468 | XmlWriter::ScopedElement e = xml.scopedElement( elementName ); | |
10469 | ||
10470 | xml.writeAttribute( "message", result.getExpandedExpression() ); | |
10471 | xml.writeAttribute( "type", result.getTestMacroName() ); | |
10472 | ||
10473 | std::ostringstream oss; | |
10474 | if( !result.getMessage().empty() ) | |
10475 | oss << result.getMessage() << '\n'; | |
10476 | for( std::vector<MessageInfo>::const_iterator | |
10477 | it = stats.infoMessages.begin(), | |
10478 | itEnd = stats.infoMessages.end(); | |
10479 | it != itEnd; | |
10480 | ++it ) | |
10481 | if( it->type == ResultWas::Info ) | |
10482 | oss << it->message << '\n'; | |
10483 | ||
10484 | oss << "at " << result.getSourceInfo(); | |
10485 | xml.writeText( oss.str(), false ); | |
10486 | } | |
10487 | } | |
10488 | ||
10489 | XmlWriter xml; | |
10490 | Timer suiteTimer; | |
10491 | std::ostringstream stdOutForSuite; | |
10492 | std::ostringstream stdErrForSuite; | |
10493 | unsigned int unexpectedExceptions; | |
10494 | bool m_okToFail; | |
10495 | }; | |
10496 | ||
10497 | INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter ) | |
10498 | ||
10499 | } // end namespace Catch | |
10500 | ||
10501 | // #included from: ../reporters/catch_reporter_console.hpp | |
10502 | #define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED | |
10503 | ||
10504 | #include <cfloat> | |
10505 | #include <cstdio> | |
10506 | ||
10507 | namespace Catch { | |
10508 | ||
10509 | struct ConsoleReporter : StreamingReporterBase { | |
10510 | ConsoleReporter( ReporterConfig const& _config ) | |
10511 | : StreamingReporterBase( _config ), | |
10512 | m_headerPrinted( false ) | |
10513 | {} | |
10514 | ||
10515 | virtual ~ConsoleReporter() CATCH_OVERRIDE; | |
10516 | static std::string getDescription() { | |
10517 | return "Reports test results as plain lines of text"; | |
10518 | } | |
10519 | ||
10520 | virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { | |
10521 | stream << "No test cases matched '" << spec << '\'' << std::endl; | |
10522 | } | |
10523 | ||
10524 | virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { | |
10525 | } | |
10526 | ||
10527 | virtual bool assertionEnded( AssertionStats const& _assertionStats ) CATCH_OVERRIDE { | |
10528 | AssertionResult const& result = _assertionStats.assertionResult; | |
10529 | ||
10530 | bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); | |
10531 | ||
10532 | // Drop out if result was successful but we're not printing them. | |
10533 | if( !includeResults && result.getResultType() != ResultWas::Warning ) | |
10534 | return false; | |
10535 | ||
10536 | lazyPrint(); | |
10537 | ||
10538 | AssertionPrinter printer( stream, _assertionStats, includeResults ); | |
10539 | printer.print(); | |
10540 | stream << std::endl; | |
10541 | return true; | |
10542 | } | |
10543 | ||
10544 | virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE { | |
10545 | m_headerPrinted = false; | |
10546 | StreamingReporterBase::sectionStarting( _sectionInfo ); | |
10547 | } | |
10548 | virtual void sectionEnded( SectionStats const& _sectionStats ) CATCH_OVERRIDE { | |
10549 | if( _sectionStats.missingAssertions ) { | |
10550 | lazyPrint(); | |
10551 | Colour colour( Colour::ResultError ); | |
10552 | if( m_sectionStack.size() > 1 ) | |
10553 | stream << "\nNo assertions in section"; | |
10554 | else | |
10555 | stream << "\nNo assertions in test case"; | |
10556 | stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; | |
10557 | } | |
10558 | if( m_config->showDurations() == ShowDurations::Always ) { | |
10559 | stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; | |
10560 | } | |
10561 | if( m_headerPrinted ) { | |
10562 | m_headerPrinted = false; | |
10563 | } | |
10564 | StreamingReporterBase::sectionEnded( _sectionStats ); | |
10565 | } | |
10566 | ||
10567 | virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) CATCH_OVERRIDE { | |
10568 | StreamingReporterBase::testCaseEnded( _testCaseStats ); | |
10569 | m_headerPrinted = false; | |
10570 | } | |
10571 | virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) CATCH_OVERRIDE { | |
10572 | if( currentGroupInfo.used ) { | |
10573 | printSummaryDivider(); | |
10574 | stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; | |
10575 | printTotals( _testGroupStats.totals ); | |
10576 | stream << '\n' << std::endl; | |
10577 | } | |
10578 | StreamingReporterBase::testGroupEnded( _testGroupStats ); | |
10579 | } | |
10580 | virtual void testRunEnded( TestRunStats const& _testRunStats ) CATCH_OVERRIDE { | |
10581 | printTotalsDivider( _testRunStats.totals ); | |
10582 | printTotals( _testRunStats.totals ); | |
10583 | stream << std::endl; | |
10584 | StreamingReporterBase::testRunEnded( _testRunStats ); | |
10585 | } | |
10586 | ||
10587 | private: | |
10588 | ||
10589 | class AssertionPrinter { | |
10590 | void operator= ( AssertionPrinter const& ); | |
10591 | public: | |
10592 | AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) | |
10593 | : stream( _stream ), | |
10594 | stats( _stats ), | |
10595 | result( _stats.assertionResult ), | |
10596 | colour( Colour::None ), | |
10597 | message( result.getMessage() ), | |
10598 | messages( _stats.infoMessages ), | |
10599 | printInfoMessages( _printInfoMessages ) | |
10600 | { | |
10601 | switch( result.getResultType() ) { | |
10602 | case ResultWas::Ok: | |
10603 | colour = Colour::Success; | |
10604 | passOrFail = "PASSED"; | |
10605 | //if( result.hasMessage() ) | |
10606 | if( _stats.infoMessages.size() == 1 ) | |
10607 | messageLabel = "with message"; | |
10608 | if( _stats.infoMessages.size() > 1 ) | |
10609 | messageLabel = "with messages"; | |
10610 | break; | |
10611 | case ResultWas::ExpressionFailed: | |
10612 | if( result.isOk() ) { | |
10613 | colour = Colour::Success; | |
10614 | passOrFail = "FAILED - but was ok"; | |
10615 | } | |
10616 | else { | |
10617 | colour = Colour::Error; | |
10618 | passOrFail = "FAILED"; | |
10619 | } | |
10620 | if( _stats.infoMessages.size() == 1 ) | |
10621 | messageLabel = "with message"; | |
10622 | if( _stats.infoMessages.size() > 1 ) | |
10623 | messageLabel = "with messages"; | |
10624 | break; | |
10625 | case ResultWas::ThrewException: | |
10626 | colour = Colour::Error; | |
10627 | passOrFail = "FAILED"; | |
10628 | messageLabel = "due to unexpected exception with "; | |
10629 | if (_stats.infoMessages.size() == 1) | |
10630 | messageLabel += "message"; | |
10631 | if (_stats.infoMessages.size() > 1) | |
10632 | messageLabel += "messages"; | |
10633 | break; | |
10634 | case ResultWas::FatalErrorCondition: | |
10635 | colour = Colour::Error; | |
10636 | passOrFail = "FAILED"; | |
10637 | messageLabel = "due to a fatal error condition"; | |
10638 | break; | |
10639 | case ResultWas::DidntThrowException: | |
10640 | colour = Colour::Error; | |
10641 | passOrFail = "FAILED"; | |
10642 | messageLabel = "because no exception was thrown where one was expected"; | |
10643 | break; | |
10644 | case ResultWas::Info: | |
10645 | messageLabel = "info"; | |
10646 | break; | |
10647 | case ResultWas::Warning: | |
10648 | messageLabel = "warning"; | |
10649 | break; | |
10650 | case ResultWas::ExplicitFailure: | |
10651 | passOrFail = "FAILED"; | |
10652 | colour = Colour::Error; | |
10653 | if( _stats.infoMessages.size() == 1 ) | |
10654 | messageLabel = "explicitly with message"; | |
10655 | if( _stats.infoMessages.size() > 1 ) | |
10656 | messageLabel = "explicitly with messages"; | |
10657 | break; | |
10658 | // These cases are here to prevent compiler warnings | |
10659 | case ResultWas::Unknown: | |
10660 | case ResultWas::FailureBit: | |
10661 | case ResultWas::Exception: | |
10662 | passOrFail = "** internal error **"; | |
10663 | colour = Colour::Error; | |
10664 | break; | |
10665 | } | |
10666 | } | |
10667 | ||
10668 | void print() const { | |
10669 | printSourceInfo(); | |
10670 | if( stats.totals.assertions.total() > 0 ) { | |
10671 | if( result.isOk() ) | |
10672 | stream << '\n'; | |
10673 | printResultType(); | |
10674 | printOriginalExpression(); | |
10675 | printReconstructedExpression(); | |
10676 | } | |
10677 | else { | |
10678 | stream << '\n'; | |
10679 | } | |
10680 | printMessage(); | |
10681 | } | |
10682 | ||
10683 | private: | |
10684 | void printResultType() const { | |
10685 | if( !passOrFail.empty() ) { | |
10686 | Colour colourGuard( colour ); | |
10687 | stream << passOrFail << ":\n"; | |
10688 | } | |
10689 | } | |
10690 | void printOriginalExpression() const { | |
10691 | if( result.hasExpression() ) { | |
10692 | Colour colourGuard( Colour::OriginalExpression ); | |
10693 | stream << " "; | |
10694 | stream << result.getExpressionInMacro(); | |
10695 | stream << '\n'; | |
10696 | } | |
10697 | } | |
10698 | void printReconstructedExpression() const { | |
10699 | if( result.hasExpandedExpression() ) { | |
10700 | stream << "with expansion:\n"; | |
10701 | Colour colourGuard( Colour::ReconstructedExpression ); | |
10702 | stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << '\n'; | |
10703 | } | |
10704 | } | |
10705 | void printMessage() const { | |
10706 | if( !messageLabel.empty() ) | |
10707 | stream << messageLabel << ':' << '\n'; | |
10708 | for( std::vector<MessageInfo>::const_iterator it = messages.begin(), itEnd = messages.end(); | |
10709 | it != itEnd; | |
10710 | ++it ) { | |
10711 | // If this assertion is a warning ignore any INFO messages | |
10712 | if( printInfoMessages || it->type != ResultWas::Info ) | |
10713 | stream << Text( it->message, TextAttributes().setIndent(2) ) << '\n'; | |
10714 | } | |
10715 | } | |
10716 | void printSourceInfo() const { | |
10717 | Colour colourGuard( Colour::FileName ); | |
10718 | stream << result.getSourceInfo() << ": "; | |
10719 | } | |
10720 | ||
10721 | std::ostream& stream; | |
10722 | AssertionStats const& stats; | |
10723 | AssertionResult const& result; | |
10724 | Colour::Code colour; | |
10725 | std::string passOrFail; | |
10726 | std::string messageLabel; | |
10727 | std::string message; | |
10728 | std::vector<MessageInfo> messages; | |
10729 | bool printInfoMessages; | |
10730 | }; | |
10731 | ||
10732 | void lazyPrint() { | |
10733 | ||
10734 | if( !currentTestRunInfo.used ) | |
10735 | lazyPrintRunInfo(); | |
10736 | if( !currentGroupInfo.used ) | |
10737 | lazyPrintGroupInfo(); | |
10738 | ||
10739 | if( !m_headerPrinted ) { | |
10740 | printTestCaseAndSectionHeader(); | |
10741 | m_headerPrinted = true; | |
10742 | } | |
10743 | } | |
10744 | void lazyPrintRunInfo() { | |
10745 | stream << '\n' << getLineOfChars<'~'>() << '\n'; | |
10746 | Colour colour( Colour::SecondaryText ); | |
10747 | stream << currentTestRunInfo->name | |
10748 | << " is a Catch v" << libraryVersion() << " host application.\n" | |
10749 | << "Run with -? for options\n\n"; | |
10750 | ||
10751 | if( m_config->rngSeed() != 0 ) | |
10752 | stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n"; | |
10753 | ||
10754 | currentTestRunInfo.used = true; | |
10755 | } | |
10756 | void lazyPrintGroupInfo() { | |
10757 | if( !currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1 ) { | |
10758 | printClosedHeader( "Group: " + currentGroupInfo->name ); | |
10759 | currentGroupInfo.used = true; | |
10760 | } | |
10761 | } | |
10762 | void printTestCaseAndSectionHeader() { | |
10763 | assert( !m_sectionStack.empty() ); | |
10764 | printOpenHeader( currentTestCaseInfo->name ); | |
10765 | ||
10766 | if( m_sectionStack.size() > 1 ) { | |
10767 | Colour colourGuard( Colour::Headers ); | |
10768 | ||
10769 | std::vector<SectionInfo>::const_iterator | |
10770 | it = m_sectionStack.begin()+1, // Skip first section (test case) | |
10771 | itEnd = m_sectionStack.end(); | |
10772 | for( ; it != itEnd; ++it ) | |
10773 | printHeaderString( it->name, 2 ); | |
10774 | } | |
10775 | ||
10776 | SourceLineInfo lineInfo = m_sectionStack.back().lineInfo; | |
10777 | ||
10778 | if( !lineInfo.empty() ){ | |
10779 | stream << getLineOfChars<'-'>() << '\n'; | |
10780 | Colour colourGuard( Colour::FileName ); | |
10781 | stream << lineInfo << '\n'; | |
10782 | } | |
10783 | stream << getLineOfChars<'.'>() << '\n' << std::endl; | |
10784 | } | |
10785 | ||
10786 | void printClosedHeader( std::string const& _name ) { | |
10787 | printOpenHeader( _name ); | |
10788 | stream << getLineOfChars<'.'>() << '\n'; | |
10789 | } | |
10790 | void printOpenHeader( std::string const& _name ) { | |
10791 | stream << getLineOfChars<'-'>() << '\n'; | |
10792 | { | |
10793 | Colour colourGuard( Colour::Headers ); | |
10794 | printHeaderString( _name ); | |
10795 | } | |
10796 | } | |
10797 | ||
10798 | // if string has a : in first line will set indent to follow it on | |
10799 | // subsequent lines | |
10800 | void printHeaderString( std::string const& _string, std::size_t indent = 0 ) { | |
10801 | std::size_t i = _string.find( ": " ); | |
10802 | if( i != std::string::npos ) | |
10803 | i+=2; | |
10804 | else | |
10805 | i = 0; | |
10806 | stream << Text( _string, TextAttributes() | |
10807 | .setIndent( indent+i) | |
10808 | .setInitialIndent( indent ) ) << '\n'; | |
10809 | } | |
10810 | ||
10811 | struct SummaryColumn { | |
10812 | ||
10813 | SummaryColumn( std::string const& _label, Colour::Code _colour ) | |
10814 | : label( _label ), | |
10815 | colour( _colour ) | |
10816 | {} | |
10817 | SummaryColumn addRow( std::size_t count ) { | |
10818 | std::ostringstream oss; | |
10819 | oss << count; | |
10820 | std::string row = oss.str(); | |
10821 | for( std::vector<std::string>::iterator it = rows.begin(); it != rows.end(); ++it ) { | |
10822 | while( it->size() < row.size() ) | |
10823 | *it = ' ' + *it; | |
10824 | while( it->size() > row.size() ) | |
10825 | row = ' ' + row; | |
10826 | } | |
10827 | rows.push_back( row ); | |
10828 | return *this; | |
10829 | } | |
10830 | ||
10831 | std::string label; | |
10832 | Colour::Code colour; | |
10833 | std::vector<std::string> rows; | |
10834 | ||
10835 | }; | |
10836 | ||
10837 | void printTotals( Totals const& totals ) { | |
10838 | if( totals.testCases.total() == 0 ) { | |
10839 | stream << Colour( Colour::Warning ) << "No tests ran\n"; | |
10840 | } | |
10841 | else if( totals.assertions.total() > 0 && totals.testCases.allPassed() ) { | |
10842 | stream << Colour( Colour::ResultSuccess ) << "All tests passed"; | |
10843 | stream << " (" | |
10844 | << pluralise( totals.assertions.passed, "assertion" ) << " in " | |
10845 | << pluralise( totals.testCases.passed, "test case" ) << ')' | |
10846 | << '\n'; | |
10847 | } | |
10848 | else { | |
10849 | ||
10850 | std::vector<SummaryColumn> columns; | |
10851 | columns.push_back( SummaryColumn( "", Colour::None ) | |
10852 | .addRow( totals.testCases.total() ) | |
10853 | .addRow( totals.assertions.total() ) ); | |
10854 | columns.push_back( SummaryColumn( "passed", Colour::Success ) | |
10855 | .addRow( totals.testCases.passed ) | |
10856 | .addRow( totals.assertions.passed ) ); | |
10857 | columns.push_back( SummaryColumn( "failed", Colour::ResultError ) | |
10858 | .addRow( totals.testCases.failed ) | |
10859 | .addRow( totals.assertions.failed ) ); | |
10860 | columns.push_back( SummaryColumn( "failed as expected", Colour::ResultExpectedFailure ) | |
10861 | .addRow( totals.testCases.failedButOk ) | |
10862 | .addRow( totals.assertions.failedButOk ) ); | |
10863 | ||
10864 | printSummaryRow( "test cases", columns, 0 ); | |
10865 | printSummaryRow( "assertions", columns, 1 ); | |
10866 | } | |
10867 | } | |
10868 | void printSummaryRow( std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row ) { | |
10869 | for( std::vector<SummaryColumn>::const_iterator it = cols.begin(); it != cols.end(); ++it ) { | |
10870 | std::string value = it->rows[row]; | |
10871 | if( it->label.empty() ) { | |
10872 | stream << label << ": "; | |
10873 | if( value != "0" ) | |
10874 | stream << value; | |
10875 | else | |
10876 | stream << Colour( Colour::Warning ) << "- none -"; | |
10877 | } | |
10878 | else if( value != "0" ) { | |
10879 | stream << Colour( Colour::LightGrey ) << " | "; | |
10880 | stream << Colour( it->colour ) | |
10881 | << value << ' ' << it->label; | |
10882 | } | |
10883 | } | |
10884 | stream << '\n'; | |
10885 | } | |
10886 | ||
10887 | static std::size_t makeRatio( std::size_t number, std::size_t total ) { | |
10888 | std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number/ total : 0; | |
10889 | return ( ratio == 0 && number > 0 ) ? 1 : ratio; | |
10890 | } | |
10891 | static std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) { | |
10892 | if( i > j && i > k ) | |
10893 | return i; | |
10894 | else if( j > k ) | |
10895 | return j; | |
10896 | else | |
10897 | return k; | |
10898 | } | |
10899 | ||
10900 | void printTotalsDivider( Totals const& totals ) { | |
10901 | if( totals.testCases.total() > 0 ) { | |
10902 | std::size_t failedRatio = makeRatio( totals.testCases.failed, totals.testCases.total() ); | |
10903 | std::size_t failedButOkRatio = makeRatio( totals.testCases.failedButOk, totals.testCases.total() ); | |
10904 | std::size_t passedRatio = makeRatio( totals.testCases.passed, totals.testCases.total() ); | |
10905 | while( failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH-1 ) | |
10906 | findMax( failedRatio, failedButOkRatio, passedRatio )++; | |
10907 | while( failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH-1 ) | |
10908 | findMax( failedRatio, failedButOkRatio, passedRatio )--; | |
10909 | ||
10910 | stream << Colour( Colour::Error ) << std::string( failedRatio, '=' ); | |
10911 | stream << Colour( Colour::ResultExpectedFailure ) << std::string( failedButOkRatio, '=' ); | |
10912 | if( totals.testCases.allPassed() ) | |
10913 | stream << Colour( Colour::ResultSuccess ) << std::string( passedRatio, '=' ); | |
10914 | else | |
10915 | stream << Colour( Colour::Success ) << std::string( passedRatio, '=' ); | |
10916 | } | |
10917 | else { | |
10918 | stream << Colour( Colour::Warning ) << std::string( CATCH_CONFIG_CONSOLE_WIDTH-1, '=' ); | |
10919 | } | |
10920 | stream << '\n'; | |
10921 | } | |
10922 | void printSummaryDivider() { | |
10923 | stream << getLineOfChars<'-'>() << '\n'; | |
10924 | } | |
10925 | ||
10926 | private: | |
10927 | bool m_headerPrinted; | |
10928 | }; | |
10929 | ||
10930 | INTERNAL_CATCH_REGISTER_REPORTER( "console", ConsoleReporter ) | |
10931 | ||
10932 | } // end namespace Catch | |
10933 | ||
10934 | // #included from: ../reporters/catch_reporter_compact.hpp | |
10935 | #define TWOBLUECUBES_CATCH_REPORTER_COMPACT_HPP_INCLUDED | |
10936 | ||
10937 | namespace Catch { | |
10938 | ||
10939 | struct CompactReporter : StreamingReporterBase { | |
10940 | ||
10941 | CompactReporter( ReporterConfig const& _config ) | |
10942 | : StreamingReporterBase( _config ) | |
10943 | {} | |
10944 | ||
10945 | virtual ~CompactReporter(); | |
10946 | ||
10947 | static std::string getDescription() { | |
10948 | return "Reports test results on a single line, suitable for IDEs"; | |
10949 | } | |
10950 | ||
10951 | virtual ReporterPreferences getPreferences() const { | |
10952 | ReporterPreferences prefs; | |
10953 | prefs.shouldRedirectStdOut = false; | |
10954 | return prefs; | |
10955 | } | |
10956 | ||
10957 | virtual void noMatchingTestCases( std::string const& spec ) { | |
10958 | stream << "No test cases matched '" << spec << '\'' << std::endl; | |
10959 | } | |
10960 | ||
10961 | virtual void assertionStarting( AssertionInfo const& ) {} | |
10962 | ||
10963 | virtual bool assertionEnded( AssertionStats const& _assertionStats ) { | |
10964 | AssertionResult const& result = _assertionStats.assertionResult; | |
10965 | ||
10966 | bool printInfoMessages = true; | |
10967 | ||
10968 | // Drop out if result was successful and we're not printing those | |
10969 | if( !m_config->includeSuccessfulResults() && result.isOk() ) { | |
10970 | if( result.getResultType() != ResultWas::Warning ) | |
10971 | return false; | |
10972 | printInfoMessages = false; | |
10973 | } | |
10974 | ||
10975 | AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); | |
10976 | printer.print(); | |
10977 | ||
10978 | stream << std::endl; | |
10979 | return true; | |
10980 | } | |
10981 | ||
10982 | virtual void sectionEnded(SectionStats const& _sectionStats) CATCH_OVERRIDE { | |
10983 | if (m_config->showDurations() == ShowDurations::Always) { | |
10984 | stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; | |
10985 | } | |
10986 | } | |
10987 | ||
10988 | virtual void testRunEnded( TestRunStats const& _testRunStats ) { | |
10989 | printTotals( _testRunStats.totals ); | |
10990 | stream << '\n' << std::endl; | |
10991 | StreamingReporterBase::testRunEnded( _testRunStats ); | |
10992 | } | |
10993 | ||
10994 | private: | |
10995 | class AssertionPrinter { | |
10996 | void operator= ( AssertionPrinter const& ); | |
10997 | public: | |
10998 | AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) | |
10999 | : stream( _stream ) | |
11000 | , stats( _stats ) | |
11001 | , result( _stats.assertionResult ) | |
11002 | , messages( _stats.infoMessages ) | |
11003 | , itMessage( _stats.infoMessages.begin() ) | |
11004 | , printInfoMessages( _printInfoMessages ) | |
11005 | {} | |
11006 | ||
11007 | void print() { | |
11008 | printSourceInfo(); | |
11009 | ||
11010 | itMessage = messages.begin(); | |
11011 | ||
11012 | switch( result.getResultType() ) { | |
11013 | case ResultWas::Ok: | |
11014 | printResultType( Colour::ResultSuccess, passedString() ); | |
11015 | printOriginalExpression(); | |
11016 | printReconstructedExpression(); | |
11017 | if ( ! result.hasExpression() ) | |
11018 | printRemainingMessages( Colour::None ); | |
11019 | else | |
11020 | printRemainingMessages(); | |
11021 | break; | |
11022 | case ResultWas::ExpressionFailed: | |
11023 | if( result.isOk() ) | |
11024 | printResultType( Colour::ResultSuccess, failedString() + std::string( " - but was ok" ) ); | |
11025 | else | |
11026 | printResultType( Colour::Error, failedString() ); | |
11027 | printOriginalExpression(); | |
11028 | printReconstructedExpression(); | |
11029 | printRemainingMessages(); | |
11030 | break; | |
11031 | case ResultWas::ThrewException: | |
11032 | printResultType( Colour::Error, failedString() ); | |
11033 | printIssue( "unexpected exception with message:" ); | |
11034 | printMessage(); | |
11035 | printExpressionWas(); | |
11036 | printRemainingMessages(); | |
11037 | break; | |
11038 | case ResultWas::FatalErrorCondition: | |
11039 | printResultType( Colour::Error, failedString() ); | |
11040 | printIssue( "fatal error condition with message:" ); | |
11041 | printMessage(); | |
11042 | printExpressionWas(); | |
11043 | printRemainingMessages(); | |
11044 | break; | |
11045 | case ResultWas::DidntThrowException: | |
11046 | printResultType( Colour::Error, failedString() ); | |
11047 | printIssue( "expected exception, got none" ); | |
11048 | printExpressionWas(); | |
11049 | printRemainingMessages(); | |
11050 | break; | |
11051 | case ResultWas::Info: | |
11052 | printResultType( Colour::None, "info" ); | |
11053 | printMessage(); | |
11054 | printRemainingMessages(); | |
11055 | break; | |
11056 | case ResultWas::Warning: | |
11057 | printResultType( Colour::None, "warning" ); | |
11058 | printMessage(); | |
11059 | printRemainingMessages(); | |
11060 | break; | |
11061 | case ResultWas::ExplicitFailure: | |
11062 | printResultType( Colour::Error, failedString() ); | |
11063 | printIssue( "explicitly" ); | |
11064 | printRemainingMessages( Colour::None ); | |
11065 | break; | |
11066 | // These cases are here to prevent compiler warnings | |
11067 | case ResultWas::Unknown: | |
11068 | case ResultWas::FailureBit: | |
11069 | case ResultWas::Exception: | |
11070 | printResultType( Colour::Error, "** internal error **" ); | |
11071 | break; | |
11072 | } | |
11073 | } | |
11074 | ||
11075 | private: | |
11076 | // Colour::LightGrey | |
11077 | ||
11078 | static Colour::Code dimColour() { return Colour::FileName; } | |
11079 | ||
11080 | #ifdef CATCH_PLATFORM_MAC | |
11081 | static const char* failedString() { return "FAILED"; } | |
11082 | static const char* passedString() { return "PASSED"; } | |
11083 | #else | |
11084 | static const char* failedString() { return "failed"; } | |
11085 | static const char* passedString() { return "passed"; } | |
11086 | #endif | |
11087 | ||
11088 | void printSourceInfo() const { | |
11089 | Colour colourGuard( Colour::FileName ); | |
11090 | stream << result.getSourceInfo() << ':'; | |
11091 | } | |
11092 | ||
11093 | void printResultType( Colour::Code colour, std::string const& passOrFail ) const { | |
11094 | if( !passOrFail.empty() ) { | |
11095 | { | |
11096 | Colour colourGuard( colour ); | |
11097 | stream << ' ' << passOrFail; | |
11098 | } | |
11099 | stream << ':'; | |
11100 | } | |
11101 | } | |
11102 | ||
11103 | void printIssue( std::string const& issue ) const { | |
11104 | stream << ' ' << issue; | |
11105 | } | |
11106 | ||
11107 | void printExpressionWas() { | |
11108 | if( result.hasExpression() ) { | |
11109 | stream << ';'; | |
11110 | { | |
11111 | Colour colour( dimColour() ); | |
11112 | stream << " expression was:"; | |
11113 | } | |
11114 | printOriginalExpression(); | |
11115 | } | |
11116 | } | |
11117 | ||
11118 | void printOriginalExpression() const { | |
11119 | if( result.hasExpression() ) { | |
11120 | stream << ' ' << result.getExpression(); | |
11121 | } | |
11122 | } | |
11123 | ||
11124 | void printReconstructedExpression() const { | |
11125 | if( result.hasExpandedExpression() ) { | |
11126 | { | |
11127 | Colour colour( dimColour() ); | |
11128 | stream << " for: "; | |
11129 | } | |
11130 | stream << result.getExpandedExpression(); | |
11131 | } | |
11132 | } | |
11133 | ||
11134 | void printMessage() { | |
11135 | if ( itMessage != messages.end() ) { | |
11136 | stream << " '" << itMessage->message << '\''; | |
11137 | ++itMessage; | |
11138 | } | |
11139 | } | |
11140 | ||
11141 | void printRemainingMessages( Colour::Code colour = dimColour() ) { | |
11142 | if ( itMessage == messages.end() ) | |
11143 | return; | |
11144 | ||
11145 | // using messages.end() directly yields compilation error: | |
11146 | std::vector<MessageInfo>::const_iterator itEnd = messages.end(); | |
11147 | const std::size_t N = static_cast<std::size_t>( std::distance( itMessage, itEnd ) ); | |
11148 | ||
11149 | { | |
11150 | Colour colourGuard( colour ); | |
11151 | stream << " with " << pluralise( N, "message" ) << ':'; | |
11152 | } | |
11153 | ||
11154 | for(; itMessage != itEnd; ) { | |
11155 | // If this assertion is a warning ignore any INFO messages | |
11156 | if( printInfoMessages || itMessage->type != ResultWas::Info ) { | |
11157 | stream << " '" << itMessage->message << '\''; | |
11158 | if ( ++itMessage != itEnd ) { | |
11159 | Colour colourGuard( dimColour() ); | |
11160 | stream << " and"; | |
11161 | } | |
11162 | } | |
11163 | } | |
11164 | } | |
11165 | ||
11166 | private: | |
11167 | std::ostream& stream; | |
11168 | AssertionStats const& stats; | |
11169 | AssertionResult const& result; | |
11170 | std::vector<MessageInfo> messages; | |
11171 | std::vector<MessageInfo>::const_iterator itMessage; | |
11172 | bool printInfoMessages; | |
11173 | }; | |
11174 | ||
11175 | // Colour, message variants: | |
11176 | // - white: No tests ran. | |
11177 | // - red: Failed [both/all] N test cases, failed [both/all] M assertions. | |
11178 | // - white: Passed [both/all] N test cases (no assertions). | |
11179 | // - red: Failed N tests cases, failed M assertions. | |
11180 | // - green: Passed [both/all] N tests cases with M assertions. | |
11181 | ||
11182 | std::string bothOrAll( std::size_t count ) const { | |
11183 | return count == 1 ? std::string() : count == 2 ? "both " : "all " ; | |
11184 | } | |
11185 | ||
11186 | void printTotals( const Totals& totals ) const { | |
11187 | if( totals.testCases.total() == 0 ) { | |
11188 | stream << "No tests ran."; | |
11189 | } | |
11190 | else if( totals.testCases.failed == totals.testCases.total() ) { | |
11191 | Colour colour( Colour::ResultError ); | |
11192 | const std::string qualify_assertions_failed = | |
11193 | totals.assertions.failed == totals.assertions.total() ? | |
11194 | bothOrAll( totals.assertions.failed ) : std::string(); | |
11195 | stream << | |
11196 | "Failed " << bothOrAll( totals.testCases.failed ) | |
11197 | << pluralise( totals.testCases.failed, "test case" ) << ", " | |
11198 | "failed " << qualify_assertions_failed << | |
11199 | pluralise( totals.assertions.failed, "assertion" ) << '.'; | |
11200 | } | |
11201 | else if( totals.assertions.total() == 0 ) { | |
11202 | stream << | |
11203 | "Passed " << bothOrAll( totals.testCases.total() ) | |
11204 | << pluralise( totals.testCases.total(), "test case" ) | |
11205 | << " (no assertions)."; | |
11206 | } | |
11207 | else if( totals.assertions.failed ) { | |
11208 | Colour colour( Colour::ResultError ); | |
11209 | stream << | |
11210 | "Failed " << pluralise( totals.testCases.failed, "test case" ) << ", " | |
11211 | "failed " << pluralise( totals.assertions.failed, "assertion" ) << '.'; | |
11212 | } | |
11213 | else { | |
11214 | Colour colour( Colour::ResultSuccess ); | |
11215 | stream << | |
11216 | "Passed " << bothOrAll( totals.testCases.passed ) | |
11217 | << pluralise( totals.testCases.passed, "test case" ) << | |
11218 | " with " << pluralise( totals.assertions.passed, "assertion" ) << '.'; | |
11219 | } | |
11220 | } | |
11221 | }; | |
11222 | ||
11223 | INTERNAL_CATCH_REGISTER_REPORTER( "compact", CompactReporter ) | |
11224 | ||
11225 | } // end namespace Catch | |
11226 | ||
11227 | namespace Catch { | |
11228 | // These are all here to avoid warnings about not having any out of line | |
11229 | // virtual methods | |
11230 | NonCopyable::~NonCopyable() {} | |
11231 | IShared::~IShared() {} | |
11232 | IStream::~IStream() CATCH_NOEXCEPT {} | |
11233 | FileStream::~FileStream() CATCH_NOEXCEPT {} | |
11234 | CoutStream::~CoutStream() CATCH_NOEXCEPT {} | |
11235 | DebugOutStream::~DebugOutStream() CATCH_NOEXCEPT {} | |
11236 | StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {} | |
11237 | IContext::~IContext() {} | |
11238 | IResultCapture::~IResultCapture() {} | |
11239 | ITestCase::~ITestCase() {} | |
11240 | ITestCaseRegistry::~ITestCaseRegistry() {} | |
11241 | IRegistryHub::~IRegistryHub() {} | |
11242 | IMutableRegistryHub::~IMutableRegistryHub() {} | |
11243 | IExceptionTranslator::~IExceptionTranslator() {} | |
11244 | IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {} | |
11245 | IReporter::~IReporter() {} | |
11246 | IReporterFactory::~IReporterFactory() {} | |
11247 | IReporterRegistry::~IReporterRegistry() {} | |
11248 | IStreamingReporter::~IStreamingReporter() {} | |
11249 | AssertionStats::~AssertionStats() {} | |
11250 | SectionStats::~SectionStats() {} | |
11251 | TestCaseStats::~TestCaseStats() {} | |
11252 | TestGroupStats::~TestGroupStats() {} | |
11253 | TestRunStats::~TestRunStats() {} | |
11254 | CumulativeReporterBase::SectionNode::~SectionNode() {} | |
11255 | CumulativeReporterBase::~CumulativeReporterBase() {} | |
11256 | ||
11257 | StreamingReporterBase::~StreamingReporterBase() {} | |
11258 | ConsoleReporter::~ConsoleReporter() {} | |
11259 | CompactReporter::~CompactReporter() {} | |
11260 | IRunner::~IRunner() {} | |
11261 | IMutableContext::~IMutableContext() {} | |
11262 | IConfig::~IConfig() {} | |
11263 | XmlReporter::~XmlReporter() {} | |
11264 | JunitReporter::~JunitReporter() {} | |
11265 | TestRegistry::~TestRegistry() {} | |
11266 | FreeFunctionTestCase::~FreeFunctionTestCase() {} | |
11267 | IGeneratorInfo::~IGeneratorInfo() {} | |
11268 | IGeneratorsForTest::~IGeneratorsForTest() {} | |
11269 | WildcardPattern::~WildcardPattern() {} | |
11270 | TestSpec::Pattern::~Pattern() {} | |
11271 | TestSpec::NamePattern::~NamePattern() {} | |
11272 | TestSpec::TagPattern::~TagPattern() {} | |
11273 | TestSpec::ExcludedPattern::~ExcludedPattern() {} | |
11274 | Matchers::Impl::MatcherUntypedBase::~MatcherUntypedBase() {} | |
11275 | ||
11276 | void Config::dummy() {} | |
11277 | ||
11278 | namespace TestCaseTracking { | |
11279 | ITracker::~ITracker() {} | |
11280 | TrackerBase::~TrackerBase() {} | |
11281 | SectionTracker::~SectionTracker() {} | |
11282 | IndexTracker::~IndexTracker() {} | |
11283 | } | |
11284 | } | |
11285 | ||
11286 | #ifdef __clang__ | |
11287 | #pragma clang diagnostic pop | |
11288 | #endif | |
11289 | ||
11290 | #endif | |
11291 | ||
11292 | #ifdef CATCH_CONFIG_MAIN | |
11293 | // #included from: internal/catch_default_main.hpp | |
11294 | #define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED | |
11295 | ||
11296 | #ifndef __OBJC__ | |
11297 | ||
11298 | #if defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN) | |
11299 | // Standard C/C++ Win32 Unicode wmain entry point | |
11300 | extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) { | |
11301 | #else | |
11302 | // Standard C/C++ main entry point | |
11303 | int main (int argc, char * argv[]) { | |
11304 | #endif | |
11305 | ||
11306 | int result = Catch::Session().run( argc, argv ); | |
11307 | return ( result < 0xff ? result : 0xff ); | |
11308 | } | |
11309 | ||
11310 | #else // __OBJC__ | |
11311 | ||
11312 | // Objective-C entry point | |
11313 | int main (int argc, char * const argv[]) { | |
11314 | #if !CATCH_ARC_ENABLED | |
11315 | NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; | |
11316 | #endif | |
11317 | ||
11318 | Catch::registerTestMethods(); | |
11319 | int result = Catch::Session().run( argc, (char* const*)argv ); | |
11320 | ||
11321 | #if !CATCH_ARC_ENABLED | |
11322 | [pool drain]; | |
11323 | #endif | |
11324 | ||
11325 | return ( result < 0xff ? result : 0xff ); | |
11326 | } | |
11327 | ||
11328 | #endif // __OBJC__ | |
11329 | ||
11330 | #endif | |
11331 | ||
11332 | #ifdef CLARA_CONFIG_MAIN_NOT_DEFINED | |
11333 | # undef CLARA_CONFIG_MAIN | |
11334 | #endif | |
11335 | ||
11336 | ////// | |
11337 | ||
11338 | // If this config identifier is defined then all CATCH macros are prefixed with CATCH_ | |
11339 | #ifdef CATCH_CONFIG_PREFIX_ALL | |
11340 | ||
11341 | #if defined(CATCH_CONFIG_FAST_COMPILE) | |
11342 | #define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, expr ) | |
11343 | #define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr ) | |
11344 | #else | |
11345 | #define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, expr ) | |
11346 | #define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr ) | |
11347 | #endif | |
11348 | ||
11349 | #define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", expr ) | |
11350 | #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) | |
11351 | #define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) | |
11352 | #define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "CATCH_REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, expr ) | |
11353 | ||
11354 | #define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( "CATCH_CHECK", Catch::ResultDisposition::ContinueOnFailure, expr ) | |
11355 | #define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( "CATCH_CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, expr ) | |
11356 | #define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( "CATCH_CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, expr ) | |
11357 | #define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, expr ) | |
11358 | #define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, expr ) | |
11359 | ||
11360 | #define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", expr ) | |
11361 | #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) | |
11362 | #define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) | |
11363 | #define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "CATCH_CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, expr ) | |
11364 | ||
11365 | #define CATCH_CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg ) | |
11366 | ||
11367 | #if defined(CATCH_CONFIG_FAST_COMPILE) | |
11368 | #define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT_NO_TRY( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) | |
11369 | #else | |
11370 | #define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) | |
11371 | #endif | |
11372 | ||
11373 | #define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg ) | |
11374 | #define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) | |
11375 | #define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg ) | |
11376 | #define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CATCH_CAPTURE", #msg " := " << Catch::toString(msg) ) | |
11377 | #define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CATCH_CAPTURE", #msg " := " << Catch::toString(msg) ) | |
11378 | ||
11379 | #ifdef CATCH_CONFIG_VARIADIC_MACROS | |
11380 | #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) | |
11381 | #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) | |
11382 | #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) | |
11383 | #define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) | |
11384 | #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) | |
11385 | #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) | |
11386 | #define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) | |
11387 | #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) | |
11388 | #else | |
11389 | #define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) | |
11390 | #define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) | |
11391 | #define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) | |
11392 | #define CATCH_REGISTER_TEST_CASE( function, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( function, name, description ) | |
11393 | #define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) | |
11394 | #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, msg ) | |
11395 | #define CATCH_FAIL_CHECK( msg ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, msg ) | |
11396 | #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, msg ) | |
11397 | #endif | |
11398 | #define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) | |
11399 | ||
11400 | #define CATCH_REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) | |
11401 | #define CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) | |
11402 | ||
11403 | #define CATCH_GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) | |
11404 | ||
11405 | // "BDD-style" convenience wrappers | |
11406 | #ifdef CATCH_CONFIG_VARIADIC_MACROS | |
11407 | #define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ ) | |
11408 | #define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) | |
11409 | #else | |
11410 | #define CATCH_SCENARIO( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags ) | |
11411 | #define CATCH_SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) | |
11412 | #endif | |
11413 | #define CATCH_GIVEN( desc ) CATCH_SECTION( std::string( "Given: ") + desc, "" ) | |
11414 | #define CATCH_WHEN( desc ) CATCH_SECTION( std::string( " When: ") + desc, "" ) | |
11415 | #define CATCH_AND_WHEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" ) | |
11416 | #define CATCH_THEN( desc ) CATCH_SECTION( std::string( " Then: ") + desc, "" ) | |
11417 | #define CATCH_AND_THEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" ) | |
11418 | ||
11419 | // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required | |
11420 | #else | |
11421 | ||
11422 | #if defined(CATCH_CONFIG_FAST_COMPILE) | |
11423 | #define REQUIRE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "REQUIRE", Catch::ResultDisposition::Normal, expr ) | |
11424 | #define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST_NO_TRY( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr ) | |
11425 | ||
11426 | #else | |
11427 | #define REQUIRE( expr ) INTERNAL_CATCH_TEST( "REQUIRE", Catch::ResultDisposition::Normal, expr ) | |
11428 | #define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, expr ) | |
11429 | #endif | |
11430 | ||
11431 | #define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", expr ) | |
11432 | #define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) | |
11433 | #define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) | |
11434 | #define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, expr ) | |
11435 | ||
11436 | #define CHECK( expr ) INTERNAL_CATCH_TEST( "CHECK", Catch::ResultDisposition::ContinueOnFailure, expr ) | |
11437 | #define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( "CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, expr ) | |
11438 | #define CHECKED_IF( expr ) INTERNAL_CATCH_IF( "CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, expr ) | |
11439 | #define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( "CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, expr ) | |
11440 | #define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( "CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, expr ) | |
11441 | ||
11442 | #define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( "CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", expr ) | |
11443 | #define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) | |
11444 | #define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( "CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) | |
11445 | #define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( "CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, expr ) | |
11446 | ||
11447 | #define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg ) | |
11448 | ||
11449 | #if defined(CATCH_CONFIG_FAST_COMPILE) | |
11450 | #define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT_NO_TRY( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) | |
11451 | #else | |
11452 | #define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) | |
11453 | #endif | |
11454 | ||
11455 | #define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg ) | |
11456 | #define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) | |
11457 | #define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg ) | |
11458 | #define CAPTURE( msg ) INTERNAL_CATCH_INFO( "CAPTURE", #msg " := " << Catch::toString(msg) ) | |
11459 | #define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CAPTURE", #msg " := " << Catch::toString(msg) ) | |
11460 | ||
11461 | #ifdef CATCH_CONFIG_VARIADIC_MACROS | |
11462 | #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) | |
11463 | #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) | |
11464 | #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) | |
11465 | #define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) | |
11466 | #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) | |
11467 | #define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) | |
11468 | #define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) | |
11469 | #define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) | |
11470 | #else | |
11471 | #define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) | |
11472 | #define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) | |
11473 | #define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) | |
11474 | #define REGISTER_TEST_CASE( method, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( method, name, description ) | |
11475 | #define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) | |
11476 | #define FAIL( msg ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, msg ) | |
11477 | #define FAIL_CHECK( msg ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, msg ) | |
11478 | #define SUCCEED( msg ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, msg ) | |
11479 | #endif | |
11480 | #define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) | |
11481 | ||
11482 | #define REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) | |
11483 | #define REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) | |
11484 | ||
11485 | #define GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) | |
11486 | ||
11487 | #endif | |
11488 | ||
11489 | #define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) | |
11490 | ||
11491 | // "BDD-style" convenience wrappers | |
11492 | #ifdef CATCH_CONFIG_VARIADIC_MACROS | |
11493 | #define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ ) | |
11494 | #define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) | |
11495 | #else | |
11496 | #define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags ) | |
11497 | #define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) | |
11498 | #endif | |
11499 | #define GIVEN( desc ) SECTION( std::string(" Given: ") + desc, "" ) | |
11500 | #define WHEN( desc ) SECTION( std::string(" When: ") + desc, "" ) | |
11501 | #define AND_WHEN( desc ) SECTION( std::string("And when: ") + desc, "" ) | |
11502 | #define THEN( desc ) SECTION( std::string(" Then: ") + desc, "" ) | |
11503 | #define AND_THEN( desc ) SECTION( std::string(" And: ") + desc, "" ) | |
11504 | ||
11505 | using Catch::Detail::Approx; | |
11506 | ||
11507 | #endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED | |
11508 |