]>
Commit | Line | Data |
---|---|---|
3b8e47c9 UH |
1 | /* |
2 | * Catch v2.5.0 | |
3 | * Generated: 2018-11-26 20:46:12.165372 | |
4 | * ---------------------------------------------------------- | |
5 | * This file has been merged from multiple headers. Please don't edit it directly | |
6 | * Copyright (c) 2018 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 | // start catch.hpp | |
14 | ||
15 | ||
16 | #define CATCH_VERSION_MAJOR 2 | |
17 | #define CATCH_VERSION_MINOR 5 | |
18 | #define CATCH_VERSION_PATCH 0 | |
19 | ||
20 | #ifdef __clang__ | |
21 | # pragma clang system_header | |
22 | #elif defined __GNUC__ | |
23 | # pragma GCC system_header | |
24 | #endif | |
25 | ||
26 | // start catch_suppress_warnings.h | |
27 | ||
28 | #ifdef __clang__ | |
29 | # ifdef __ICC // icpc defines the __clang__ macro | |
30 | # pragma warning(push) | |
31 | # pragma warning(disable: 161 1682) | |
32 | # else // __ICC | |
33 | # pragma clang diagnostic push | |
34 | # pragma clang diagnostic ignored "-Wpadded" | |
35 | # pragma clang diagnostic ignored "-Wswitch-enum" | |
36 | # pragma clang diagnostic ignored "-Wcovered-switch-default" | |
37 | # endif | |
38 | #elif defined __GNUC__ | |
39 | // GCC likes to warn on REQUIREs, and we cannot suppress them | |
40 | // locally because g++'s support for _Pragma is lacking in older, | |
41 | // still supported, versions | |
42 | # pragma GCC diagnostic ignored "-Wparentheses" | |
43 | # pragma GCC diagnostic push | |
44 | # pragma GCC diagnostic ignored "-Wunused-variable" | |
45 | # pragma GCC diagnostic ignored "-Wpadded" | |
46 | #endif | |
47 | // end catch_suppress_warnings.h | |
48 | #if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) | |
49 | # define CATCH_IMPL | |
50 | # define CATCH_CONFIG_ALL_PARTS | |
51 | #endif | |
52 | ||
53 | // In the impl file, we want to have access to all parts of the headers | |
54 | // Can also be used to sanely support PCHs | |
55 | #if defined(CATCH_CONFIG_ALL_PARTS) | |
56 | # define CATCH_CONFIG_EXTERNAL_INTERFACES | |
57 | # if defined(CATCH_CONFIG_DISABLE_MATCHERS) | |
58 | # undef CATCH_CONFIG_DISABLE_MATCHERS | |
59 | # endif | |
60 | # if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) | |
61 | # define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER | |
62 | # endif | |
63 | #endif | |
64 | ||
65 | #if !defined(CATCH_CONFIG_IMPL_ONLY) | |
66 | // start catch_platform.h | |
67 | ||
68 | #ifdef __APPLE__ | |
69 | # include <TargetConditionals.h> | |
70 | # if TARGET_OS_OSX == 1 | |
71 | # define CATCH_PLATFORM_MAC | |
72 | # elif TARGET_OS_IPHONE == 1 | |
73 | # define CATCH_PLATFORM_IPHONE | |
74 | # endif | |
75 | ||
76 | #elif defined(linux) || defined(__linux) || defined(__linux__) | |
77 | # define CATCH_PLATFORM_LINUX | |
78 | ||
79 | #elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__) | |
80 | # define CATCH_PLATFORM_WINDOWS | |
81 | #endif | |
82 | ||
83 | // end catch_platform.h | |
84 | ||
85 | #ifdef CATCH_IMPL | |
86 | # ifndef CLARA_CONFIG_MAIN | |
87 | # define CLARA_CONFIG_MAIN_NOT_DEFINED | |
88 | # define CLARA_CONFIG_MAIN | |
89 | # endif | |
90 | #endif | |
91 | ||
92 | // start catch_user_interfaces.h | |
93 | ||
94 | namespace Catch { | |
95 | unsigned int rngSeed(); | |
96 | } | |
97 | ||
98 | // end catch_user_interfaces.h | |
99 | // start catch_tag_alias_autoregistrar.h | |
100 | ||
101 | // start catch_common.h | |
102 | ||
103 | // start catch_compiler_capabilities.h | |
104 | ||
105 | // Detect a number of compiler features - by compiler | |
106 | // The following features are defined: | |
107 | // | |
108 | // CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported? | |
109 | // CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? | |
110 | // CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? | |
111 | // CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled? | |
112 | // **************** | |
113 | // Note to maintainers: if new toggles are added please document them | |
114 | // in configuration.md, too | |
115 | // **************** | |
116 | ||
117 | // In general each macro has a _NO_<feature name> form | |
118 | // (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature. | |
119 | // Many features, at point of detection, define an _INTERNAL_ macro, so they | |
120 | // can be combined, en-mass, with the _NO_ forms later. | |
121 | ||
122 | #ifdef __cplusplus | |
123 | ||
124 | # if (__cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L) | |
125 | # define CATCH_CPP14_OR_GREATER | |
126 | # endif | |
127 | ||
128 | # if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) | |
129 | # define CATCH_CPP17_OR_GREATER | |
130 | # endif | |
131 | ||
132 | #endif | |
133 | ||
134 | #if defined(CATCH_CPP17_OR_GREATER) | |
135 | # define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS | |
136 | #endif | |
137 | ||
138 | #ifdef __clang__ | |
139 | ||
140 | # define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ | |
141 | _Pragma( "clang diagnostic push" ) \ | |
142 | _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ | |
143 | _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") | |
144 | # define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ | |
145 | _Pragma( "clang diagnostic pop" ) | |
146 | ||
147 | # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ | |
148 | _Pragma( "clang diagnostic push" ) \ | |
149 | _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) | |
150 | # define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ | |
151 | _Pragma( "clang diagnostic pop" ) | |
152 | ||
153 | # define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ | |
154 | _Pragma( "clang diagnostic push" ) \ | |
155 | _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" ) | |
156 | # define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS \ | |
157 | _Pragma( "clang diagnostic pop" ) | |
158 | ||
159 | #endif // __clang__ | |
160 | ||
161 | //////////////////////////////////////////////////////////////////////////////// | |
162 | // Assume that non-Windows platforms support posix signals by default | |
163 | #if !defined(CATCH_PLATFORM_WINDOWS) | |
164 | #define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS | |
165 | #endif | |
166 | ||
167 | //////////////////////////////////////////////////////////////////////////////// | |
168 | // We know some environments not to support full POSIX signals | |
169 | #if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__) | |
170 | #define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS | |
171 | #endif | |
172 | ||
173 | #ifdef __OS400__ | |
174 | # define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS | |
175 | # define CATCH_CONFIG_COLOUR_NONE | |
176 | #endif | |
177 | ||
178 | //////////////////////////////////////////////////////////////////////////////// | |
179 | // Android somehow still does not support std::to_string | |
180 | #if defined(__ANDROID__) | |
181 | # define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING | |
182 | #endif | |
183 | ||
184 | //////////////////////////////////////////////////////////////////////////////// | |
185 | // Not all Windows environments support SEH properly | |
186 | #if defined(__MINGW32__) | |
187 | # define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH | |
188 | #endif | |
189 | ||
190 | //////////////////////////////////////////////////////////////////////////////// | |
191 | // PS4 | |
192 | #if defined(__ORBIS__) | |
193 | # define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE | |
194 | #endif | |
195 | ||
196 | //////////////////////////////////////////////////////////////////////////////// | |
197 | // Cygwin | |
198 | #ifdef __CYGWIN__ | |
199 | ||
200 | // Required for some versions of Cygwin to declare gettimeofday | |
201 | // see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin | |
202 | # define _BSD_SOURCE | |
203 | // some versions of cygwin (most) do not support std::to_string. Use the libstd check. | |
204 | // https://gcc.gnu.org/onlinedocs/gcc-4.8.2/libstdc++/api/a01053_source.html line 2812-2813 | |
205 | # if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \ | |
206 | && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF)) | |
207 | ||
208 | # define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING | |
209 | ||
210 | # endif | |
211 | #endif // __CYGWIN__ | |
212 | ||
213 | //////////////////////////////////////////////////////////////////////////////// | |
214 | // Visual C++ | |
215 | #ifdef _MSC_VER | |
216 | ||
217 | # if _MSC_VER >= 1900 // Visual Studio 2015 or newer | |
218 | # define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS | |
219 | # endif | |
220 | ||
221 | // Universal Windows platform does not support SEH | |
222 | // Or console colours (or console at all...) | |
223 | # if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) | |
224 | # define CATCH_CONFIG_COLOUR_NONE | |
225 | # else | |
226 | # define CATCH_INTERNAL_CONFIG_WINDOWS_SEH | |
227 | # endif | |
228 | ||
229 | // MSVC traditional preprocessor needs some workaround for __VA_ARGS__ | |
230 | // _MSVC_TRADITIONAL == 0 means new conformant preprocessor | |
231 | // _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor | |
232 | # if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL) | |
233 | # define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR | |
234 | # endif | |
235 | ||
236 | #endif // _MSC_VER | |
237 | ||
238 | //////////////////////////////////////////////////////////////////////////////// | |
239 | // Check if we are compiled with -fno-exceptions or equivalent | |
240 | #if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND) | |
241 | # define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED | |
242 | #endif | |
243 | ||
244 | //////////////////////////////////////////////////////////////////////////////// | |
245 | // DJGPP | |
246 | #ifdef __DJGPP__ | |
247 | # define CATCH_INTERNAL_CONFIG_NO_WCHAR | |
248 | #endif // __DJGPP__ | |
249 | ||
250 | //////////////////////////////////////////////////////////////////////////////// | |
251 | // Embarcadero C++Build | |
252 | #if defined(__BORLANDC__) | |
253 | #define CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN | |
254 | #endif | |
255 | ||
256 | //////////////////////////////////////////////////////////////////////////////// | |
257 | ||
258 | // Use of __COUNTER__ is suppressed during code analysis in | |
259 | // CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly | |
260 | // handled by it. | |
261 | // Otherwise all supported compilers support COUNTER macro, | |
262 | // but user still might want to turn it off | |
263 | #if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) | |
264 | #define CATCH_INTERNAL_CONFIG_COUNTER | |
265 | #endif | |
266 | ||
267 | //////////////////////////////////////////////////////////////////////////////// | |
268 | // Check if string_view is available and usable | |
269 | // The check is split apart to work around v140 (VS2015) preprocessor issue... | |
270 | #if defined(__has_include) | |
271 | #if __has_include(<string_view>) && defined(CATCH_CPP17_OR_GREATER) | |
272 | # define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW | |
273 | #endif | |
274 | #endif | |
275 | ||
276 | //////////////////////////////////////////////////////////////////////////////// | |
277 | // Check if variant is available and usable | |
278 | #if defined(__has_include) | |
279 | # if __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER) | |
280 | # if defined(__clang__) && (__clang_major__ < 8) | |
281 | // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852 | |
282 | // fix should be in clang 8, workaround in libstdc++ 8.2 | |
283 | # include <ciso646> | |
284 | # if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) | |
285 | # define CATCH_CONFIG_NO_CPP17_VARIANT | |
286 | # else | |
287 | # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT | |
288 | # endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) | |
289 | # endif // defined(__clang__) && (__clang_major__ < 8) | |
290 | # endif // __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER) | |
291 | #endif // __has_include | |
292 | ||
293 | #if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) | |
294 | # define CATCH_CONFIG_COUNTER | |
295 | #endif | |
296 | #if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) && !defined(CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH) | |
297 | # define CATCH_CONFIG_WINDOWS_SEH | |
298 | #endif | |
299 | // This is set by default, because we assume that unix compilers are posix-signal-compatible by default. | |
300 | #if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) | |
301 | # define CATCH_CONFIG_POSIX_SIGNALS | |
302 | #endif | |
303 | // This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions. | |
304 | #if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR) | |
305 | # define CATCH_CONFIG_WCHAR | |
306 | #endif | |
307 | ||
308 | #if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING) | |
309 | # define CATCH_CONFIG_CPP11_TO_STRING | |
310 | #endif | |
311 | ||
312 | #if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) | |
313 | # define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS | |
314 | #endif | |
315 | ||
316 | #if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW) | |
317 | # define CATCH_CONFIG_CPP17_STRING_VIEW | |
318 | #endif | |
319 | ||
320 | #if defined(CATCH_INTERNAL_CONFIG_CPP17_VARIANT) && !defined(CATCH_CONFIG_NO_CPP17_VARIANT) && !defined(CATCH_CONFIG_CPP17_VARIANT) | |
321 | # define CATCH_CONFIG_CPP17_VARIANT | |
322 | #endif | |
323 | ||
324 | #if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) | |
325 | # define CATCH_INTERNAL_CONFIG_NEW_CAPTURE | |
326 | #endif | |
327 | ||
328 | #if defined(CATCH_INTERNAL_CONFIG_NEW_CAPTURE) && !defined(CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NEW_CAPTURE) | |
329 | # define CATCH_CONFIG_NEW_CAPTURE | |
330 | #endif | |
331 | ||
332 | #if !defined(CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) | |
333 | # define CATCH_CONFIG_DISABLE_EXCEPTIONS | |
334 | #endif | |
335 | ||
336 | #if defined(CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_NO_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_POLYFILL_ISNAN) | |
337 | # define CATCH_CONFIG_POLYFILL_ISNAN | |
338 | #endif | |
339 | ||
340 | #if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) | |
341 | # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS | |
342 | # define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS | |
343 | #endif | |
344 | #if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) | |
345 | # define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS | |
346 | # define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS | |
347 | #endif | |
348 | #if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS) | |
349 | # define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS | |
350 | # define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS | |
351 | #endif | |
352 | ||
353 | #if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) | |
354 | #define CATCH_TRY if ((true)) | |
355 | #define CATCH_CATCH_ALL if ((false)) | |
356 | #define CATCH_CATCH_ANON(type) if ((false)) | |
357 | #else | |
358 | #define CATCH_TRY try | |
359 | #define CATCH_CATCH_ALL catch (...) | |
360 | #define CATCH_CATCH_ANON(type) catch (type) | |
361 | #endif | |
362 | ||
363 | #if defined(CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_NO_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) | |
364 | #define CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR | |
365 | #endif | |
366 | ||
367 | // end catch_compiler_capabilities.h | |
368 | #define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line | |
369 | #define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) | |
370 | #ifdef CATCH_CONFIG_COUNTER | |
371 | # define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) | |
372 | #else | |
373 | # define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) | |
374 | #endif | |
375 | ||
376 | #include <iosfwd> | |
377 | #include <string> | |
378 | #include <cstdint> | |
379 | ||
380 | // We need a dummy global operator<< so we can bring it into Catch namespace later | |
381 | struct Catch_global_namespace_dummy {}; | |
382 | std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy); | |
383 | ||
384 | namespace Catch { | |
385 | ||
386 | struct CaseSensitive { enum Choice { | |
387 | Yes, | |
388 | No | |
389 | }; }; | |
390 | ||
391 | class NonCopyable { | |
392 | NonCopyable( NonCopyable const& ) = delete; | |
393 | NonCopyable( NonCopyable && ) = delete; | |
394 | NonCopyable& operator = ( NonCopyable const& ) = delete; | |
395 | NonCopyable& operator = ( NonCopyable && ) = delete; | |
396 | ||
397 | protected: | |
398 | NonCopyable(); | |
399 | virtual ~NonCopyable(); | |
400 | }; | |
401 | ||
402 | struct SourceLineInfo { | |
403 | ||
404 | SourceLineInfo() = delete; | |
405 | SourceLineInfo( char const* _file, std::size_t _line ) noexcept | |
406 | : file( _file ), | |
407 | line( _line ) | |
408 | {} | |
409 | ||
410 | SourceLineInfo( SourceLineInfo const& other ) = default; | |
411 | SourceLineInfo( SourceLineInfo && ) = default; | |
412 | SourceLineInfo& operator = ( SourceLineInfo const& ) = default; | |
413 | SourceLineInfo& operator = ( SourceLineInfo && ) = default; | |
414 | ||
415 | bool empty() const noexcept; | |
416 | bool operator == ( SourceLineInfo const& other ) const noexcept; | |
417 | bool operator < ( SourceLineInfo const& other ) const noexcept; | |
418 | ||
419 | char const* file; | |
420 | std::size_t line; | |
421 | }; | |
422 | ||
423 | std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); | |
424 | ||
425 | // Bring in operator<< from global namespace into Catch namespace | |
426 | // This is necessary because the overload of operator<< above makes | |
427 | // lookup stop at namespace Catch | |
428 | using ::operator<<; | |
429 | ||
430 | // Use this in variadic streaming macros to allow | |
431 | // >> +StreamEndStop | |
432 | // as well as | |
433 | // >> stuff +StreamEndStop | |
434 | struct StreamEndStop { | |
435 | std::string operator+() const; | |
436 | }; | |
437 | template<typename T> | |
438 | T const& operator + ( T const& value, StreamEndStop ) { | |
439 | return value; | |
440 | } | |
441 | } | |
442 | ||
443 | #define CATCH_INTERNAL_LINEINFO \ | |
444 | ::Catch::SourceLineInfo( __FILE__, static_cast<std::size_t>( __LINE__ ) ) | |
445 | ||
446 | // end catch_common.h | |
447 | namespace Catch { | |
448 | ||
449 | struct RegistrarForTagAliases { | |
450 | RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); | |
451 | }; | |
452 | ||
453 | } // end namespace Catch | |
454 | ||
455 | #define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \ | |
456 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ | |
457 | namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \ | |
458 | CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS | |
459 | ||
460 | // end catch_tag_alias_autoregistrar.h | |
461 | // start catch_test_registry.h | |
462 | ||
463 | // start catch_interfaces_testcase.h | |
464 | ||
465 | #include <vector> | |
466 | #include <memory> | |
467 | ||
468 | namespace Catch { | |
469 | ||
470 | class TestSpec; | |
471 | ||
472 | struct ITestInvoker { | |
473 | virtual void invoke () const = 0; | |
474 | virtual ~ITestInvoker(); | |
475 | }; | |
476 | ||
477 | using ITestCasePtr = std::shared_ptr<ITestInvoker>; | |
478 | ||
479 | class TestCase; | |
480 | struct IConfig; | |
481 | ||
482 | struct ITestCaseRegistry { | |
483 | virtual ~ITestCaseRegistry(); | |
484 | virtual std::vector<TestCase> const& getAllTests() const = 0; | |
485 | virtual std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const = 0; | |
486 | }; | |
487 | ||
488 | bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); | |
489 | std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ); | |
490 | std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ); | |
491 | ||
492 | } | |
493 | ||
494 | // end catch_interfaces_testcase.h | |
495 | // start catch_stringref.h | |
496 | ||
497 | #include <cstddef> | |
498 | #include <string> | |
499 | #include <iosfwd> | |
500 | ||
501 | namespace Catch { | |
502 | ||
503 | class StringData; | |
504 | ||
505 | /// A non-owning string class (similar to the forthcoming std::string_view) | |
506 | /// Note that, because a StringRef may be a substring of another string, | |
507 | /// it may not be null terminated. c_str() must return a null terminated | |
508 | /// string, however, and so the StringRef will internally take ownership | |
509 | /// (taking a copy), if necessary. In theory this ownership is not externally | |
510 | /// visible - but it does mean (substring) StringRefs should not be shared between | |
511 | /// threads. | |
512 | class StringRef { | |
513 | public: | |
514 | using size_type = std::size_t; | |
515 | ||
516 | private: | |
517 | friend struct StringRefTestAccess; | |
518 | ||
519 | char const* m_start; | |
520 | size_type m_size; | |
521 | ||
522 | char* m_data = nullptr; | |
523 | ||
524 | void takeOwnership(); | |
525 | ||
526 | static constexpr char const* const s_empty = ""; | |
527 | ||
528 | public: // construction/ assignment | |
529 | StringRef() noexcept | |
530 | : StringRef( s_empty, 0 ) | |
531 | {} | |
532 | ||
533 | StringRef( StringRef const& other ) noexcept | |
534 | : m_start( other.m_start ), | |
535 | m_size( other.m_size ) | |
536 | {} | |
537 | ||
538 | StringRef( StringRef&& other ) noexcept | |
539 | : m_start( other.m_start ), | |
540 | m_size( other.m_size ), | |
541 | m_data( other.m_data ) | |
542 | { | |
543 | other.m_data = nullptr; | |
544 | } | |
545 | ||
546 | StringRef( char const* rawChars ) noexcept; | |
547 | ||
548 | StringRef( char const* rawChars, size_type size ) noexcept | |
549 | : m_start( rawChars ), | |
550 | m_size( size ) | |
551 | {} | |
552 | ||
553 | StringRef( std::string const& stdString ) noexcept | |
554 | : m_start( stdString.c_str() ), | |
555 | m_size( stdString.size() ) | |
556 | {} | |
557 | ||
558 | ~StringRef() noexcept { | |
559 | delete[] m_data; | |
560 | } | |
561 | ||
562 | auto operator = ( StringRef const &other ) noexcept -> StringRef& { | |
563 | delete[] m_data; | |
564 | m_data = nullptr; | |
565 | m_start = other.m_start; | |
566 | m_size = other.m_size; | |
567 | return *this; | |
568 | } | |
569 | ||
570 | operator std::string() const; | |
571 | ||
572 | void swap( StringRef& other ) noexcept; | |
573 | ||
574 | public: // operators | |
575 | auto operator == ( StringRef const& other ) const noexcept -> bool; | |
576 | auto operator != ( StringRef const& other ) const noexcept -> bool; | |
577 | ||
578 | auto operator[] ( size_type index ) const noexcept -> char; | |
579 | ||
580 | public: // named queries | |
581 | auto empty() const noexcept -> bool { | |
582 | return m_size == 0; | |
583 | } | |
584 | auto size() const noexcept -> size_type { | |
585 | return m_size; | |
586 | } | |
587 | ||
588 | auto numberOfCharacters() const noexcept -> size_type; | |
589 | auto c_str() const -> char const*; | |
590 | ||
591 | public: // substrings and searches | |
592 | auto substr( size_type start, size_type size ) const noexcept -> StringRef; | |
593 | ||
594 | // Returns the current start pointer. | |
595 | // Note that the pointer can change when if the StringRef is a substring | |
596 | auto currentData() const noexcept -> char const*; | |
597 | ||
598 | private: // ownership queries - may not be consistent between calls | |
599 | auto isOwned() const noexcept -> bool; | |
600 | auto isSubstring() const noexcept -> bool; | |
601 | }; | |
602 | ||
603 | auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string; | |
604 | auto operator + ( StringRef const& lhs, char const* rhs ) -> std::string; | |
605 | auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string; | |
606 | ||
607 | auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&; | |
608 | auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; | |
609 | ||
610 | inline auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { | |
611 | return StringRef( rawChars, size ); | |
612 | } | |
613 | ||
614 | } // namespace Catch | |
615 | ||
616 | inline auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { | |
617 | return Catch::StringRef( rawChars, size ); | |
618 | } | |
619 | ||
620 | // end catch_stringref.h | |
621 | // start catch_type_traits.hpp | |
622 | ||
623 | ||
624 | namespace Catch{ | |
625 | ||
626 | #ifdef CATCH_CPP17_OR_GREATER | |
627 | template <typename...> | |
628 | inline constexpr auto is_unique = std::true_type{}; | |
629 | ||
630 | template <typename T, typename... Rest> | |
631 | inline constexpr auto is_unique<T, Rest...> = std::bool_constant< | |
632 | (!std::is_same_v<T, Rest> && ...) && is_unique<Rest...> | |
633 | >{}; | |
634 | #else | |
635 | ||
636 | template <typename...> | |
637 | struct is_unique : std::true_type{}; | |
638 | ||
639 | template <typename T0, typename T1, typename... Rest> | |
640 | struct is_unique<T0, T1, Rest...> : std::integral_constant | |
641 | <bool, | |
642 | !std::is_same<T0, T1>::value | |
643 | && is_unique<T0, Rest...>::value | |
644 | && is_unique<T1, Rest...>::value | |
645 | >{}; | |
646 | ||
647 | #endif | |
648 | } | |
649 | ||
650 | // end catch_type_traits.hpp | |
651 | // start catch_preprocessor.hpp | |
652 | ||
653 | ||
654 | #define CATCH_RECURSION_LEVEL0(...) __VA_ARGS__ | |
655 | #define CATCH_RECURSION_LEVEL1(...) CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(__VA_ARGS__))) | |
656 | #define CATCH_RECURSION_LEVEL2(...) CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(__VA_ARGS__))) | |
657 | #define CATCH_RECURSION_LEVEL3(...) CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(__VA_ARGS__))) | |
658 | #define CATCH_RECURSION_LEVEL4(...) CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(__VA_ARGS__))) | |
659 | #define CATCH_RECURSION_LEVEL5(...) CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(__VA_ARGS__))) | |
660 | ||
661 | #ifdef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR | |
662 | #define INTERNAL_CATCH_EXPAND_VARGS(...) __VA_ARGS__ | |
663 | // MSVC needs more evaluations | |
664 | #define CATCH_RECURSION_LEVEL6(...) CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(__VA_ARGS__))) | |
665 | #define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL6(CATCH_RECURSION_LEVEL6(__VA_ARGS__)) | |
666 | #else | |
667 | #define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL5(__VA_ARGS__) | |
668 | #endif | |
669 | ||
670 | #define CATCH_REC_END(...) | |
671 | #define CATCH_REC_OUT | |
672 | ||
673 | #define CATCH_EMPTY() | |
674 | #define CATCH_DEFER(id) id CATCH_EMPTY() | |
675 | ||
676 | #define CATCH_REC_GET_END2() 0, CATCH_REC_END | |
677 | #define CATCH_REC_GET_END1(...) CATCH_REC_GET_END2 | |
678 | #define CATCH_REC_GET_END(...) CATCH_REC_GET_END1 | |
679 | #define CATCH_REC_NEXT0(test, next, ...) next CATCH_REC_OUT | |
680 | #define CATCH_REC_NEXT1(test, next) CATCH_DEFER ( CATCH_REC_NEXT0 ) ( test, next, 0) | |
681 | #define CATCH_REC_NEXT(test, next) CATCH_REC_NEXT1(CATCH_REC_GET_END test, next) | |
682 | ||
683 | #define CATCH_REC_LIST0(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) | |
684 | #define CATCH_REC_LIST1(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0) ) ( f, peek, __VA_ARGS__ ) | |
685 | #define CATCH_REC_LIST2(f, x, peek, ...) f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) | |
686 | ||
687 | #define CATCH_REC_LIST0_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) | |
688 | #define CATCH_REC_LIST1_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0_UD) ) ( f, userdata, peek, __VA_ARGS__ ) | |
689 | #define CATCH_REC_LIST2_UD(f, userdata, x, peek, ...) f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) | |
690 | ||
691 | // Applies the function macro `f` to each of the remaining parameters, inserts commas between the results, | |
692 | // and passes userdata as the first parameter to each invocation, | |
693 | // e.g. CATCH_REC_LIST_UD(f, x, a, b, c) evaluates to f(x, a), f(x, b), f(x, c) | |
694 | #define CATCH_REC_LIST_UD(f, userdata, ...) CATCH_RECURSE(CATCH_REC_LIST2_UD(f, userdata, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) | |
695 | ||
696 | #define CATCH_REC_LIST(f, ...) CATCH_RECURSE(CATCH_REC_LIST2(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) | |
697 | ||
698 | #define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param) | |
699 | #define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__ | |
700 | #define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__ | |
701 | #define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF | |
702 | ||
703 | #define INTERNAL_CATCH_REMOVE_PARENS(...) INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF __VA_ARGS__) | |
704 | ||
705 | #define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME2(Name, ...) INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME3(Name, __VA_ARGS__) | |
706 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR | |
707 | #define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME3(Name,...) Name " - " #__VA_ARGS__ | |
708 | #define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME(Name,...) INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME2(Name, INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)) | |
709 | #else | |
710 | // MSVC is adding extra space and needs more calls to properly remove () | |
711 | #define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME3(Name,...) Name " -" #__VA_ARGS__ | |
712 | #define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME1(Name, ...) INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME2(Name, __VA_ARGS__) | |
713 | #define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME(Name, ...) INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME1(Name, INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))) | |
714 | #endif | |
715 | ||
716 | // end catch_preprocessor.hpp | |
717 | namespace Catch { | |
718 | ||
719 | template<typename C> | |
720 | class TestInvokerAsMethod : public ITestInvoker { | |
721 | void (C::*m_testAsMethod)(); | |
722 | public: | |
723 | TestInvokerAsMethod( void (C::*testAsMethod)() ) noexcept : m_testAsMethod( testAsMethod ) {} | |
724 | ||
725 | void invoke() const override { | |
726 | C obj; | |
727 | (obj.*m_testAsMethod)(); | |
728 | } | |
729 | }; | |
730 | ||
731 | auto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker*; | |
732 | ||
733 | template<typename C> | |
734 | auto makeTestInvoker( void (C::*testAsMethod)() ) noexcept -> ITestInvoker* { | |
735 | return new(std::nothrow) TestInvokerAsMethod<C>( testAsMethod ); | |
736 | } | |
737 | ||
738 | struct NameAndTags { | |
739 | NameAndTags( StringRef const& name_ = StringRef(), StringRef const& tags_ = StringRef() ) noexcept; | |
740 | StringRef name; | |
741 | StringRef tags; | |
742 | }; | |
743 | ||
744 | struct AutoReg : NonCopyable { | |
745 | AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept; | |
746 | ~AutoReg(); | |
747 | }; | |
748 | ||
749 | } // end namespace Catch | |
750 | ||
751 | #if defined(CATCH_CONFIG_DISABLE) | |
752 | #define INTERNAL_CATCH_TESTCASE_NO_REGISTRATION( TestName, ... ) \ | |
753 | static void TestName() | |
754 | #define INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... ) \ | |
755 | namespace{ \ | |
756 | struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \ | |
757 | void test(); \ | |
758 | }; \ | |
759 | } \ | |
760 | void TestName::test() | |
761 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION( TestName, ... ) \ | |
762 | template<typename TestType> \ | |
763 | static void TestName() | |
764 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... ) \ | |
765 | namespace{ \ | |
766 | template<typename TestType> \ | |
767 | struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \ | |
768 | void test(); \ | |
769 | }; \ | |
770 | } \ | |
771 | template<typename TestType> \ | |
772 | void TestName::test() | |
773 | #endif | |
774 | ||
775 | /////////////////////////////////////////////////////////////////////////////// | |
776 | #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \ | |
777 | static void TestName(); \ | |
778 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ | |
779 | namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ | |
780 | CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ | |
781 | static void TestName() | |
782 | #define INTERNAL_CATCH_TESTCASE( ... ) \ | |
783 | INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ ) | |
784 | ||
785 | /////////////////////////////////////////////////////////////////////////////// | |
786 | #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ | |
787 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ | |
788 | namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &QualifiedMethod ), CATCH_INTERNAL_LINEINFO, "&" #QualifiedMethod, Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ | |
789 | CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS | |
790 | ||
791 | /////////////////////////////////////////////////////////////////////////////// | |
792 | #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\ | |
793 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ | |
794 | namespace{ \ | |
795 | struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \ | |
796 | void test(); \ | |
797 | }; \ | |
798 | Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ | |
799 | } \ | |
800 | CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ | |
801 | void TestName::test() | |
802 | #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \ | |
803 | INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ ) | |
804 | ||
805 | /////////////////////////////////////////////////////////////////////////////// | |
806 | #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ | |
807 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ | |
808 | Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ | |
809 | CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS | |
810 | ||
811 | /////////////////////////////////////////////////////////////////////////////// | |
812 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_2(TestName, TestFunc, Name, Tags, ... )\ | |
813 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ | |
814 | template<typename TestType> \ | |
815 | static void TestFunc();\ | |
816 | namespace {\ | |
817 | template<typename...Types> \ | |
818 | struct TestName{\ | |
819 | template<typename...Ts> \ | |
820 | TestName(Ts...names){\ | |
821 | CATCH_INTERNAL_CHECK_UNIQUE_TYPES(CATCH_REC_LIST(INTERNAL_CATCH_REMOVE_PARENS, __VA_ARGS__)) \ | |
822 | using expander = int[];\ | |
823 | (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ names, Tags } ), 0)... };/* NOLINT */ \ | |
824 | }\ | |
825 | };\ | |
826 | INTERNAL_CATCH_TEMPLATE_REGISTRY_INITIATE(TestName, Name, __VA_ARGS__) \ | |
827 | }\ | |
828 | CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ | |
829 | template<typename TestType> \ | |
830 | static void TestFunc() | |
831 | ||
832 | #if defined(CATCH_CPP17_OR_GREATER) | |
833 | #define CATCH_INTERNAL_CHECK_UNIQUE_TYPES(...) static_assert(Catch::is_unique<__VA_ARGS__>,"Duplicate type detected in declaration of template test case"); | |
834 | #else | |
835 | #define CATCH_INTERNAL_CHECK_UNIQUE_TYPES(...) static_assert(Catch::is_unique<__VA_ARGS__>::value,"Duplicate type detected in declaration of template test case"); | |
836 | #endif | |
837 | ||
838 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR | |
839 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \ | |
840 | INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, __VA_ARGS__ ) | |
841 | #else | |
842 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \ | |
843 | INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, __VA_ARGS__ ) ) | |
844 | #endif | |
845 | ||
846 | #define INTERNAL_CATCH_TEMPLATE_REGISTRY_INITIATE(TestName, Name, ...)\ | |
847 | static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\ | |
848 | TestName<CATCH_REC_LIST(INTERNAL_CATCH_REMOVE_PARENS, __VA_ARGS__)>(CATCH_REC_LIST_UD(INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME,Name, __VA_ARGS__));\ | |
849 | return 0;\ | |
850 | }(); | |
851 | ||
852 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, ... ) \ | |
853 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ | |
854 | namespace{ \ | |
855 | template<typename TestType> \ | |
856 | struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \ | |
857 | void test();\ | |
858 | };\ | |
859 | template<typename...Types> \ | |
860 | struct TestNameClass{\ | |
861 | template<typename...Ts> \ | |
862 | TestNameClass(Ts...names){\ | |
863 | CATCH_INTERNAL_CHECK_UNIQUE_TYPES(CATCH_REC_LIST(INTERNAL_CATCH_REMOVE_PARENS, __VA_ARGS__)) \ | |
864 | using expander = int[];\ | |
865 | (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ names, Tags } ), 0)... };/* NOLINT */ \ | |
866 | }\ | |
867 | };\ | |
868 | INTERNAL_CATCH_TEMPLATE_REGISTRY_INITIATE(TestNameClass, Name, __VA_ARGS__)\ | |
869 | }\ | |
870 | CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS\ | |
871 | template<typename TestType> \ | |
872 | void TestName<TestType>::test() | |
873 | ||
874 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR | |
875 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \ | |
876 | INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, __VA_ARGS__ ) | |
877 | #else | |
878 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \ | |
879 | INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, __VA_ARGS__ ) ) | |
880 | #endif | |
881 | ||
882 | // end catch_test_registry.h | |
883 | // start catch_capture.hpp | |
884 | ||
885 | // start catch_assertionhandler.h | |
886 | ||
887 | // start catch_assertioninfo.h | |
888 | ||
889 | // start catch_result_type.h | |
890 | ||
891 | namespace Catch { | |
892 | ||
893 | // ResultWas::OfType enum | |
894 | struct ResultWas { enum OfType { | |
895 | Unknown = -1, | |
896 | Ok = 0, | |
897 | Info = 1, | |
898 | Warning = 2, | |
899 | ||
900 | FailureBit = 0x10, | |
901 | ||
902 | ExpressionFailed = FailureBit | 1, | |
903 | ExplicitFailure = FailureBit | 2, | |
904 | ||
905 | Exception = 0x100 | FailureBit, | |
906 | ||
907 | ThrewException = Exception | 1, | |
908 | DidntThrowException = Exception | 2, | |
909 | ||
910 | FatalErrorCondition = 0x200 | FailureBit | |
911 | ||
912 | }; }; | |
913 | ||
914 | bool isOk( ResultWas::OfType resultType ); | |
915 | bool isJustInfo( int flags ); | |
916 | ||
917 | // ResultDisposition::Flags enum | |
918 | struct ResultDisposition { enum Flags { | |
919 | Normal = 0x01, | |
920 | ||
921 | ContinueOnFailure = 0x02, // Failures fail test, but execution continues | |
922 | FalseTest = 0x04, // Prefix expression with ! | |
923 | SuppressFail = 0x08 // Failures are reported but do not fail the test | |
924 | }; }; | |
925 | ||
926 | ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ); | |
927 | ||
928 | bool shouldContinueOnFailure( int flags ); | |
929 | inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } | |
930 | bool shouldSuppressFailure( int flags ); | |
931 | ||
932 | } // end namespace Catch | |
933 | ||
934 | // end catch_result_type.h | |
935 | namespace Catch { | |
936 | ||
937 | struct AssertionInfo | |
938 | { | |
939 | StringRef macroName; | |
940 | SourceLineInfo lineInfo; | |
941 | StringRef capturedExpression; | |
942 | ResultDisposition::Flags resultDisposition; | |
943 | ||
944 | // We want to delete this constructor but a compiler bug in 4.8 means | |
945 | // the struct is then treated as non-aggregate | |
946 | //AssertionInfo() = delete; | |
947 | }; | |
948 | ||
949 | } // end namespace Catch | |
950 | ||
951 | // end catch_assertioninfo.h | |
952 | // start catch_decomposer.h | |
953 | ||
954 | // start catch_tostring.h | |
955 | ||
956 | #include <vector> | |
957 | #include <cstddef> | |
958 | #include <type_traits> | |
959 | #include <string> | |
960 | // start catch_stream.h | |
961 | ||
962 | #include <iosfwd> | |
963 | #include <cstddef> | |
964 | #include <ostream> | |
965 | ||
966 | namespace Catch { | |
967 | ||
968 | std::ostream& cout(); | |
969 | std::ostream& cerr(); | |
970 | std::ostream& clog(); | |
971 | ||
972 | class StringRef; | |
973 | ||
974 | struct IStream { | |
975 | virtual ~IStream(); | |
976 | virtual std::ostream& stream() const = 0; | |
977 | }; | |
978 | ||
979 | auto makeStream( StringRef const &filename ) -> IStream const*; | |
980 | ||
981 | class ReusableStringStream { | |
982 | std::size_t m_index; | |
983 | std::ostream* m_oss; | |
984 | public: | |
985 | ReusableStringStream(); | |
986 | ~ReusableStringStream(); | |
987 | ||
988 | auto str() const -> std::string; | |
989 | ||
990 | template<typename T> | |
991 | auto operator << ( T const& value ) -> ReusableStringStream& { | |
992 | *m_oss << value; | |
993 | return *this; | |
994 | } | |
995 | auto get() -> std::ostream& { return *m_oss; } | |
996 | }; | |
997 | } | |
998 | ||
999 | // end catch_stream.h | |
1000 | ||
1001 | #ifdef CATCH_CONFIG_CPP17_STRING_VIEW | |
1002 | #include <string_view> | |
1003 | #endif | |
1004 | ||
1005 | #ifdef __OBJC__ | |
1006 | // start catch_objc_arc.hpp | |
1007 | ||
1008 | #import <Foundation/Foundation.h> | |
1009 | ||
1010 | #ifdef __has_feature | |
1011 | #define CATCH_ARC_ENABLED __has_feature(objc_arc) | |
1012 | #else | |
1013 | #define CATCH_ARC_ENABLED 0 | |
1014 | #endif | |
1015 | ||
1016 | void arcSafeRelease( NSObject* obj ); | |
1017 | id performOptionalSelector( id obj, SEL sel ); | |
1018 | ||
1019 | #if !CATCH_ARC_ENABLED | |
1020 | inline void arcSafeRelease( NSObject* obj ) { | |
1021 | [obj release]; | |
1022 | } | |
1023 | inline id performOptionalSelector( id obj, SEL sel ) { | |
1024 | if( [obj respondsToSelector: sel] ) | |
1025 | return [obj performSelector: sel]; | |
1026 | return nil; | |
1027 | } | |
1028 | #define CATCH_UNSAFE_UNRETAINED | |
1029 | #define CATCH_ARC_STRONG | |
1030 | #else | |
1031 | inline void arcSafeRelease( NSObject* ){} | |
1032 | inline id performOptionalSelector( id obj, SEL sel ) { | |
1033 | #ifdef __clang__ | |
1034 | #pragma clang diagnostic push | |
1035 | #pragma clang diagnostic ignored "-Warc-performSelector-leaks" | |
1036 | #endif | |
1037 | if( [obj respondsToSelector: sel] ) | |
1038 | return [obj performSelector: sel]; | |
1039 | #ifdef __clang__ | |
1040 | #pragma clang diagnostic pop | |
1041 | #endif | |
1042 | return nil; | |
1043 | } | |
1044 | #define CATCH_UNSAFE_UNRETAINED __unsafe_unretained | |
1045 | #define CATCH_ARC_STRONG __strong | |
1046 | #endif | |
1047 | ||
1048 | // end catch_objc_arc.hpp | |
1049 | #endif | |
1050 | ||
1051 | #ifdef _MSC_VER | |
1052 | #pragma warning(push) | |
1053 | #pragma warning(disable:4180) // We attempt to stream a function (address) by const&, which MSVC complains about but is harmless | |
1054 | #endif | |
1055 | ||
1056 | namespace Catch { | |
1057 | namespace Detail { | |
1058 | ||
1059 | extern const std::string unprintableString; | |
1060 | ||
1061 | std::string rawMemoryToString( const void *object, std::size_t size ); | |
1062 | ||
1063 | template<typename T> | |
1064 | std::string rawMemoryToString( const T& object ) { | |
1065 | return rawMemoryToString( &object, sizeof(object) ); | |
1066 | } | |
1067 | ||
1068 | template<typename T> | |
1069 | class IsStreamInsertable { | |
1070 | template<typename SS, typename TT> | |
1071 | static auto test(int) | |
1072 | -> decltype(std::declval<SS&>() << std::declval<TT>(), std::true_type()); | |
1073 | ||
1074 | template<typename, typename> | |
1075 | static auto test(...)->std::false_type; | |
1076 | ||
1077 | public: | |
1078 | static const bool value = decltype(test<std::ostream, const T&>(0))::value; | |
1079 | }; | |
1080 | ||
1081 | template<typename E> | |
1082 | std::string convertUnknownEnumToString( E e ); | |
1083 | ||
1084 | template<typename T> | |
1085 | typename std::enable_if< | |
1086 | !std::is_enum<T>::value && !std::is_base_of<std::exception, T>::value, | |
1087 | std::string>::type convertUnstreamable( T const& ) { | |
1088 | return Detail::unprintableString; | |
1089 | } | |
1090 | template<typename T> | |
1091 | typename std::enable_if< | |
1092 | !std::is_enum<T>::value && std::is_base_of<std::exception, T>::value, | |
1093 | std::string>::type convertUnstreamable(T const& ex) { | |
1094 | return ex.what(); | |
1095 | } | |
1096 | ||
1097 | template<typename T> | |
1098 | typename std::enable_if< | |
1099 | std::is_enum<T>::value | |
1100 | , std::string>::type convertUnstreamable( T const& value ) { | |
1101 | return convertUnknownEnumToString( value ); | |
1102 | } | |
1103 | ||
1104 | #if defined(_MANAGED) | |
1105 | //! Convert a CLR string to a utf8 std::string | |
1106 | template<typename T> | |
1107 | std::string clrReferenceToString( T^ ref ) { | |
1108 | if (ref == nullptr) | |
1109 | return std::string("null"); | |
1110 | auto bytes = System::Text::Encoding::UTF8->GetBytes(ref->ToString()); | |
1111 | cli::pin_ptr<System::Byte> p = &bytes[0]; | |
1112 | return std::string(reinterpret_cast<char const *>(p), bytes->Length); | |
1113 | } | |
1114 | #endif | |
1115 | ||
1116 | } // namespace Detail | |
1117 | ||
1118 | // If we decide for C++14, change these to enable_if_ts | |
1119 | template <typename T, typename = void> | |
1120 | struct StringMaker { | |
1121 | template <typename Fake = T> | |
1122 | static | |
1123 | typename std::enable_if<::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>::type | |
1124 | convert(const Fake& value) { | |
1125 | ReusableStringStream rss; | |
1126 | // NB: call using the function-like syntax to avoid ambiguity with | |
1127 | // user-defined templated operator<< under clang. | |
1128 | rss.operator<<(value); | |
1129 | return rss.str(); | |
1130 | } | |
1131 | ||
1132 | template <typename Fake = T> | |
1133 | static | |
1134 | typename std::enable_if<!::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>::type | |
1135 | convert( const Fake& value ) { | |
1136 | #if !defined(CATCH_CONFIG_FALLBACK_STRINGIFIER) | |
1137 | return Detail::convertUnstreamable(value); | |
1138 | #else | |
1139 | return CATCH_CONFIG_FALLBACK_STRINGIFIER(value); | |
1140 | #endif | |
1141 | } | |
1142 | }; | |
1143 | ||
1144 | namespace Detail { | |
1145 | ||
1146 | // This function dispatches all stringification requests inside of Catch. | |
1147 | // Should be preferably called fully qualified, like ::Catch::Detail::stringify | |
1148 | template <typename T> | |
1149 | std::string stringify(const T& e) { | |
1150 | return ::Catch::StringMaker<typename std::remove_cv<typename std::remove_reference<T>::type>::type>::convert(e); | |
1151 | } | |
1152 | ||
1153 | template<typename E> | |
1154 | std::string convertUnknownEnumToString( E e ) { | |
1155 | return ::Catch::Detail::stringify(static_cast<typename std::underlying_type<E>::type>(e)); | |
1156 | } | |
1157 | ||
1158 | #if defined(_MANAGED) | |
1159 | template <typename T> | |
1160 | std::string stringify( T^ e ) { | |
1161 | return ::Catch::StringMaker<T^>::convert(e); | |
1162 | } | |
1163 | #endif | |
1164 | ||
1165 | } // namespace Detail | |
1166 | ||
1167 | // Some predefined specializations | |
1168 | ||
1169 | template<> | |
1170 | struct StringMaker<std::string> { | |
1171 | static std::string convert(const std::string& str); | |
1172 | }; | |
1173 | ||
1174 | #ifdef CATCH_CONFIG_CPP17_STRING_VIEW | |
1175 | template<> | |
1176 | struct StringMaker<std::string_view> { | |
1177 | static std::string convert(std::string_view str); | |
1178 | }; | |
1179 | #endif | |
1180 | ||
1181 | template<> | |
1182 | struct StringMaker<char const *> { | |
1183 | static std::string convert(char const * str); | |
1184 | }; | |
1185 | template<> | |
1186 | struct StringMaker<char *> { | |
1187 | static std::string convert(char * str); | |
1188 | }; | |
1189 | ||
1190 | #ifdef CATCH_CONFIG_WCHAR | |
1191 | template<> | |
1192 | struct StringMaker<std::wstring> { | |
1193 | static std::string convert(const std::wstring& wstr); | |
1194 | }; | |
1195 | ||
1196 | # ifdef CATCH_CONFIG_CPP17_STRING_VIEW | |
1197 | template<> | |
1198 | struct StringMaker<std::wstring_view> { | |
1199 | static std::string convert(std::wstring_view str); | |
1200 | }; | |
1201 | # endif | |
1202 | ||
1203 | template<> | |
1204 | struct StringMaker<wchar_t const *> { | |
1205 | static std::string convert(wchar_t const * str); | |
1206 | }; | |
1207 | template<> | |
1208 | struct StringMaker<wchar_t *> { | |
1209 | static std::string convert(wchar_t * str); | |
1210 | }; | |
1211 | #endif | |
1212 | ||
1213 | // TBD: Should we use `strnlen` to ensure that we don't go out of the buffer, | |
1214 | // while keeping string semantics? | |
1215 | template<int SZ> | |
1216 | struct StringMaker<char[SZ]> { | |
1217 | static std::string convert(char const* str) { | |
1218 | return ::Catch::Detail::stringify(std::string{ str }); | |
1219 | } | |
1220 | }; | |
1221 | template<int SZ> | |
1222 | struct StringMaker<signed char[SZ]> { | |
1223 | static std::string convert(signed char const* str) { | |
1224 | return ::Catch::Detail::stringify(std::string{ reinterpret_cast<char const *>(str) }); | |
1225 | } | |
1226 | }; | |
1227 | template<int SZ> | |
1228 | struct StringMaker<unsigned char[SZ]> { | |
1229 | static std::string convert(unsigned char const* str) { | |
1230 | return ::Catch::Detail::stringify(std::string{ reinterpret_cast<char const *>(str) }); | |
1231 | } | |
1232 | }; | |
1233 | ||
1234 | template<> | |
1235 | struct StringMaker<int> { | |
1236 | static std::string convert(int value); | |
1237 | }; | |
1238 | template<> | |
1239 | struct StringMaker<long> { | |
1240 | static std::string convert(long value); | |
1241 | }; | |
1242 | template<> | |
1243 | struct StringMaker<long long> { | |
1244 | static std::string convert(long long value); | |
1245 | }; | |
1246 | template<> | |
1247 | struct StringMaker<unsigned int> { | |
1248 | static std::string convert(unsigned int value); | |
1249 | }; | |
1250 | template<> | |
1251 | struct StringMaker<unsigned long> { | |
1252 | static std::string convert(unsigned long value); | |
1253 | }; | |
1254 | template<> | |
1255 | struct StringMaker<unsigned long long> { | |
1256 | static std::string convert(unsigned long long value); | |
1257 | }; | |
1258 | ||
1259 | template<> | |
1260 | struct StringMaker<bool> { | |
1261 | static std::string convert(bool b); | |
1262 | }; | |
1263 | ||
1264 | template<> | |
1265 | struct StringMaker<char> { | |
1266 | static std::string convert(char c); | |
1267 | }; | |
1268 | template<> | |
1269 | struct StringMaker<signed char> { | |
1270 | static std::string convert(signed char c); | |
1271 | }; | |
1272 | template<> | |
1273 | struct StringMaker<unsigned char> { | |
1274 | static std::string convert(unsigned char c); | |
1275 | }; | |
1276 | ||
1277 | template<> | |
1278 | struct StringMaker<std::nullptr_t> { | |
1279 | static std::string convert(std::nullptr_t); | |
1280 | }; | |
1281 | ||
1282 | template<> | |
1283 | struct StringMaker<float> { | |
1284 | static std::string convert(float value); | |
1285 | }; | |
1286 | template<> | |
1287 | struct StringMaker<double> { | |
1288 | static std::string convert(double value); | |
1289 | }; | |
1290 | ||
1291 | template <typename T> | |
1292 | struct StringMaker<T*> { | |
1293 | template <typename U> | |
1294 | static std::string convert(U* p) { | |
1295 | if (p) { | |
1296 | return ::Catch::Detail::rawMemoryToString(p); | |
1297 | } else { | |
1298 | return "nullptr"; | |
1299 | } | |
1300 | } | |
1301 | }; | |
1302 | ||
1303 | template <typename R, typename C> | |
1304 | struct StringMaker<R C::*> { | |
1305 | static std::string convert(R C::* p) { | |
1306 | if (p) { | |
1307 | return ::Catch::Detail::rawMemoryToString(p); | |
1308 | } else { | |
1309 | return "nullptr"; | |
1310 | } | |
1311 | } | |
1312 | }; | |
1313 | ||
1314 | #if defined(_MANAGED) | |
1315 | template <typename T> | |
1316 | struct StringMaker<T^> { | |
1317 | static std::string convert( T^ ref ) { | |
1318 | return ::Catch::Detail::clrReferenceToString(ref); | |
1319 | } | |
1320 | }; | |
1321 | #endif | |
1322 | ||
1323 | namespace Detail { | |
1324 | template<typename InputIterator> | |
1325 | std::string rangeToString(InputIterator first, InputIterator last) { | |
1326 | ReusableStringStream rss; | |
1327 | rss << "{ "; | |
1328 | if (first != last) { | |
1329 | rss << ::Catch::Detail::stringify(*first); | |
1330 | for (++first; first != last; ++first) | |
1331 | rss << ", " << ::Catch::Detail::stringify(*first); | |
1332 | } | |
1333 | rss << " }"; | |
1334 | return rss.str(); | |
1335 | } | |
1336 | } | |
1337 | ||
1338 | #ifdef __OBJC__ | |
1339 | template<> | |
1340 | struct StringMaker<NSString*> { | |
1341 | static std::string convert(NSString * nsstring) { | |
1342 | if (!nsstring) | |
1343 | return "nil"; | |
1344 | return std::string("@") + [nsstring UTF8String]; | |
1345 | } | |
1346 | }; | |
1347 | template<> | |
1348 | struct StringMaker<NSObject*> { | |
1349 | static std::string convert(NSObject* nsObject) { | |
1350 | return ::Catch::Detail::stringify([nsObject description]); | |
1351 | } | |
1352 | ||
1353 | }; | |
1354 | namespace Detail { | |
1355 | inline std::string stringify( NSString* nsstring ) { | |
1356 | return StringMaker<NSString*>::convert( nsstring ); | |
1357 | } | |
1358 | ||
1359 | } // namespace Detail | |
1360 | #endif // __OBJC__ | |
1361 | ||
1362 | } // namespace Catch | |
1363 | ||
1364 | ////////////////////////////////////////////////////// | |
1365 | // Separate std-lib types stringification, so it can be selectively enabled | |
1366 | // This means that we do not bring in | |
1367 | ||
1368 | #if defined(CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS) | |
1369 | # define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER | |
1370 | # define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER | |
1371 | # define CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER | |
1372 | # define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER | |
1373 | #endif | |
1374 | ||
1375 | // Separate std::pair specialization | |
1376 | #if defined(CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER) | |
1377 | #include <utility> | |
1378 | namespace Catch { | |
1379 | template<typename T1, typename T2> | |
1380 | struct StringMaker<std::pair<T1, T2> > { | |
1381 | static std::string convert(const std::pair<T1, T2>& pair) { | |
1382 | ReusableStringStream rss; | |
1383 | rss << "{ " | |
1384 | << ::Catch::Detail::stringify(pair.first) | |
1385 | << ", " | |
1386 | << ::Catch::Detail::stringify(pair.second) | |
1387 | << " }"; | |
1388 | return rss.str(); | |
1389 | } | |
1390 | }; | |
1391 | } | |
1392 | #endif // CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER | |
1393 | ||
1394 | // Separate std::tuple specialization | |
1395 | #if defined(CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER) | |
1396 | #include <tuple> | |
1397 | namespace Catch { | |
1398 | namespace Detail { | |
1399 | template< | |
1400 | typename Tuple, | |
1401 | std::size_t N = 0, | |
1402 | bool = (N < std::tuple_size<Tuple>::value) | |
1403 | > | |
1404 | struct TupleElementPrinter { | |
1405 | static void print(const Tuple& tuple, std::ostream& os) { | |
1406 | os << (N ? ", " : " ") | |
1407 | << ::Catch::Detail::stringify(std::get<N>(tuple)); | |
1408 | TupleElementPrinter<Tuple, N + 1>::print(tuple, os); | |
1409 | } | |
1410 | }; | |
1411 | ||
1412 | template< | |
1413 | typename Tuple, | |
1414 | std::size_t N | |
1415 | > | |
1416 | struct TupleElementPrinter<Tuple, N, false> { | |
1417 | static void print(const Tuple&, std::ostream&) {} | |
1418 | }; | |
1419 | ||
1420 | } | |
1421 | ||
1422 | template<typename ...Types> | |
1423 | struct StringMaker<std::tuple<Types...>> { | |
1424 | static std::string convert(const std::tuple<Types...>& tuple) { | |
1425 | ReusableStringStream rss; | |
1426 | rss << '{'; | |
1427 | Detail::TupleElementPrinter<std::tuple<Types...>>::print(tuple, rss.get()); | |
1428 | rss << " }"; | |
1429 | return rss.str(); | |
1430 | } | |
1431 | }; | |
1432 | } | |
1433 | #endif // CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER | |
1434 | ||
1435 | #if defined(CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_VARIANT) | |
1436 | #include <variant> | |
1437 | namespace Catch { | |
1438 | template<> | |
1439 | struct StringMaker<std::monostate> { | |
1440 | static std::string convert(const std::monostate&) { | |
1441 | return "{ }"; | |
1442 | } | |
1443 | }; | |
1444 | ||
1445 | template<typename... Elements> | |
1446 | struct StringMaker<std::variant<Elements...>> { | |
1447 | static std::string convert(const std::variant<Elements...>& variant) { | |
1448 | if (variant.valueless_by_exception()) { | |
1449 | return "{valueless variant}"; | |
1450 | } else { | |
1451 | return std::visit( | |
1452 | [](const auto& value) { | |
1453 | return ::Catch::Detail::stringify(value); | |
1454 | }, | |
1455 | variant | |
1456 | ); | |
1457 | } | |
1458 | } | |
1459 | }; | |
1460 | } | |
1461 | #endif // CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER | |
1462 | ||
1463 | namespace Catch { | |
1464 | struct not_this_one {}; // Tag type for detecting which begin/ end are being selected | |
1465 | ||
1466 | // Import begin/ end from std here so they are considered alongside the fallback (...) overloads in this namespace | |
1467 | using std::begin; | |
1468 | using std::end; | |
1469 | ||
1470 | not_this_one begin( ... ); | |
1471 | not_this_one end( ... ); | |
1472 | ||
1473 | template <typename T> | |
1474 | struct is_range { | |
1475 | static const bool value = | |
1476 | !std::is_same<decltype(begin(std::declval<T>())), not_this_one>::value && | |
1477 | !std::is_same<decltype(end(std::declval<T>())), not_this_one>::value; | |
1478 | }; | |
1479 | ||
1480 | #if defined(_MANAGED) // Managed types are never ranges | |
1481 | template <typename T> | |
1482 | struct is_range<T^> { | |
1483 | static const bool value = false; | |
1484 | }; | |
1485 | #endif | |
1486 | ||
1487 | template<typename Range> | |
1488 | std::string rangeToString( Range const& range ) { | |
1489 | return ::Catch::Detail::rangeToString( begin( range ), end( range ) ); | |
1490 | } | |
1491 | ||
1492 | // Handle vector<bool> specially | |
1493 | template<typename Allocator> | |
1494 | std::string rangeToString( std::vector<bool, Allocator> const& v ) { | |
1495 | ReusableStringStream rss; | |
1496 | rss << "{ "; | |
1497 | bool first = true; | |
1498 | for( bool b : v ) { | |
1499 | if( first ) | |
1500 | first = false; | |
1501 | else | |
1502 | rss << ", "; | |
1503 | rss << ::Catch::Detail::stringify( b ); | |
1504 | } | |
1505 | rss << " }"; | |
1506 | return rss.str(); | |
1507 | } | |
1508 | ||
1509 | template<typename R> | |
1510 | struct StringMaker<R, typename std::enable_if<is_range<R>::value && !::Catch::Detail::IsStreamInsertable<R>::value>::type> { | |
1511 | static std::string convert( R const& range ) { | |
1512 | return rangeToString( range ); | |
1513 | } | |
1514 | }; | |
1515 | ||
1516 | template <typename T, int SZ> | |
1517 | struct StringMaker<T[SZ]> { | |
1518 | static std::string convert(T const(&arr)[SZ]) { | |
1519 | return rangeToString(arr); | |
1520 | } | |
1521 | }; | |
1522 | ||
1523 | } // namespace Catch | |
1524 | ||
1525 | // Separate std::chrono::duration specialization | |
1526 | #if defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) | |
1527 | #include <ctime> | |
1528 | #include <ratio> | |
1529 | #include <chrono> | |
1530 | ||
1531 | namespace Catch { | |
1532 | ||
1533 | template <class Ratio> | |
1534 | struct ratio_string { | |
1535 | static std::string symbol(); | |
1536 | }; | |
1537 | ||
1538 | template <class Ratio> | |
1539 | std::string ratio_string<Ratio>::symbol() { | |
1540 | Catch::ReusableStringStream rss; | |
1541 | rss << '[' << Ratio::num << '/' | |
1542 | << Ratio::den << ']'; | |
1543 | return rss.str(); | |
1544 | } | |
1545 | template <> | |
1546 | struct ratio_string<std::atto> { | |
1547 | static std::string symbol(); | |
1548 | }; | |
1549 | template <> | |
1550 | struct ratio_string<std::femto> { | |
1551 | static std::string symbol(); | |
1552 | }; | |
1553 | template <> | |
1554 | struct ratio_string<std::pico> { | |
1555 | static std::string symbol(); | |
1556 | }; | |
1557 | template <> | |
1558 | struct ratio_string<std::nano> { | |
1559 | static std::string symbol(); | |
1560 | }; | |
1561 | template <> | |
1562 | struct ratio_string<std::micro> { | |
1563 | static std::string symbol(); | |
1564 | }; | |
1565 | template <> | |
1566 | struct ratio_string<std::milli> { | |
1567 | static std::string symbol(); | |
1568 | }; | |
1569 | ||
1570 | //////////// | |
1571 | // std::chrono::duration specializations | |
1572 | template<typename Value, typename Ratio> | |
1573 | struct StringMaker<std::chrono::duration<Value, Ratio>> { | |
1574 | static std::string convert(std::chrono::duration<Value, Ratio> const& duration) { | |
1575 | ReusableStringStream rss; | |
1576 | rss << duration.count() << ' ' << ratio_string<Ratio>::symbol() << 's'; | |
1577 | return rss.str(); | |
1578 | } | |
1579 | }; | |
1580 | template<typename Value> | |
1581 | struct StringMaker<std::chrono::duration<Value, std::ratio<1>>> { | |
1582 | static std::string convert(std::chrono::duration<Value, std::ratio<1>> const& duration) { | |
1583 | ReusableStringStream rss; | |
1584 | rss << duration.count() << " s"; | |
1585 | return rss.str(); | |
1586 | } | |
1587 | }; | |
1588 | template<typename Value> | |
1589 | struct StringMaker<std::chrono::duration<Value, std::ratio<60>>> { | |
1590 | static std::string convert(std::chrono::duration<Value, std::ratio<60>> const& duration) { | |
1591 | ReusableStringStream rss; | |
1592 | rss << duration.count() << " m"; | |
1593 | return rss.str(); | |
1594 | } | |
1595 | }; | |
1596 | template<typename Value> | |
1597 | struct StringMaker<std::chrono::duration<Value, std::ratio<3600>>> { | |
1598 | static std::string convert(std::chrono::duration<Value, std::ratio<3600>> const& duration) { | |
1599 | ReusableStringStream rss; | |
1600 | rss << duration.count() << " h"; | |
1601 | return rss.str(); | |
1602 | } | |
1603 | }; | |
1604 | ||
1605 | //////////// | |
1606 | // std::chrono::time_point specialization | |
1607 | // Generic time_point cannot be specialized, only std::chrono::time_point<system_clock> | |
1608 | template<typename Clock, typename Duration> | |
1609 | struct StringMaker<std::chrono::time_point<Clock, Duration>> { | |
1610 | static std::string convert(std::chrono::time_point<Clock, Duration> const& time_point) { | |
1611 | return ::Catch::Detail::stringify(time_point.time_since_epoch()) + " since epoch"; | |
1612 | } | |
1613 | }; | |
1614 | // std::chrono::time_point<system_clock> specialization | |
1615 | template<typename Duration> | |
1616 | struct StringMaker<std::chrono::time_point<std::chrono::system_clock, Duration>> { | |
1617 | static std::string convert(std::chrono::time_point<std::chrono::system_clock, Duration> const& time_point) { | |
1618 | auto converted = std::chrono::system_clock::to_time_t(time_point); | |
1619 | ||
1620 | #ifdef _MSC_VER | |
1621 | std::tm timeInfo = {}; | |
1622 | gmtime_s(&timeInfo, &converted); | |
1623 | #else | |
1624 | std::tm* timeInfo = std::gmtime(&converted); | |
1625 | #endif | |
1626 | ||
1627 | auto const timeStampSize = sizeof("2017-01-16T17:06:45Z"); | |
1628 | char timeStamp[timeStampSize]; | |
1629 | const char * const fmt = "%Y-%m-%dT%H:%M:%SZ"; | |
1630 | ||
1631 | #ifdef _MSC_VER | |
1632 | std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); | |
1633 | #else | |
1634 | std::strftime(timeStamp, timeStampSize, fmt, timeInfo); | |
1635 | #endif | |
1636 | return std::string(timeStamp); | |
1637 | } | |
1638 | }; | |
1639 | } | |
1640 | #endif // CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER | |
1641 | ||
1642 | #ifdef _MSC_VER | |
1643 | #pragma warning(pop) | |
1644 | #endif | |
1645 | ||
1646 | // end catch_tostring.h | |
1647 | #include <iosfwd> | |
1648 | ||
1649 | #ifdef _MSC_VER | |
1650 | #pragma warning(push) | |
1651 | #pragma warning(disable:4389) // '==' : signed/unsigned mismatch | |
1652 | #pragma warning(disable:4018) // more "signed/unsigned mismatch" | |
1653 | #pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform) | |
1654 | #pragma warning(disable:4180) // qualifier applied to function type has no meaning | |
1655 | #endif | |
1656 | ||
1657 | namespace Catch { | |
1658 | ||
1659 | struct ITransientExpression { | |
1660 | auto isBinaryExpression() const -> bool { return m_isBinaryExpression; } | |
1661 | auto getResult() const -> bool { return m_result; } | |
1662 | virtual void streamReconstructedExpression( std::ostream &os ) const = 0; | |
1663 | ||
1664 | ITransientExpression( bool isBinaryExpression, bool result ) | |
1665 | : m_isBinaryExpression( isBinaryExpression ), | |
1666 | m_result( result ) | |
1667 | {} | |
1668 | ||
1669 | // We don't actually need a virtual destructor, but many static analysers | |
1670 | // complain if it's not here :-( | |
1671 | virtual ~ITransientExpression(); | |
1672 | ||
1673 | bool m_isBinaryExpression; | |
1674 | bool m_result; | |
1675 | ||
1676 | }; | |
1677 | ||
1678 | void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ); | |
1679 | ||
1680 | template<typename LhsT, typename RhsT> | |
1681 | class BinaryExpr : public ITransientExpression { | |
1682 | LhsT m_lhs; | |
1683 | StringRef m_op; | |
1684 | RhsT m_rhs; | |
1685 | ||
1686 | void streamReconstructedExpression( std::ostream &os ) const override { | |
1687 | formatReconstructedExpression | |
1688 | ( os, Catch::Detail::stringify( m_lhs ), m_op, Catch::Detail::stringify( m_rhs ) ); | |
1689 | } | |
1690 | ||
1691 | public: | |
1692 | BinaryExpr( bool comparisonResult, LhsT lhs, StringRef op, RhsT rhs ) | |
1693 | : ITransientExpression{ true, comparisonResult }, | |
1694 | m_lhs( lhs ), | |
1695 | m_op( op ), | |
1696 | m_rhs( rhs ) | |
1697 | {} | |
1698 | }; | |
1699 | ||
1700 | template<typename LhsT> | |
1701 | class UnaryExpr : public ITransientExpression { | |
1702 | LhsT m_lhs; | |
1703 | ||
1704 | void streamReconstructedExpression( std::ostream &os ) const override { | |
1705 | os << Catch::Detail::stringify( m_lhs ); | |
1706 | } | |
1707 | ||
1708 | public: | |
1709 | explicit UnaryExpr( LhsT lhs ) | |
1710 | : ITransientExpression{ false, lhs ? true : false }, | |
1711 | m_lhs( lhs ) | |
1712 | {} | |
1713 | }; | |
1714 | ||
1715 | // Specialised comparison functions to handle equality comparisons between ints and pointers (NULL deduces as an int) | |
1716 | template<typename LhsT, typename RhsT> | |
1717 | auto compareEqual( LhsT const& lhs, RhsT const& rhs ) -> bool { return static_cast<bool>(lhs == rhs); } | |
1718 | template<typename T> | |
1719 | auto compareEqual( T* const& lhs, int rhs ) -> bool { return lhs == reinterpret_cast<void const*>( rhs ); } | |
1720 | template<typename T> | |
1721 | auto compareEqual( T* const& lhs, long rhs ) -> bool { return lhs == reinterpret_cast<void const*>( rhs ); } | |
1722 | template<typename T> | |
1723 | auto compareEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) == rhs; } | |
1724 | template<typename T> | |
1725 | auto compareEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) == rhs; } | |
1726 | ||
1727 | template<typename LhsT, typename RhsT> | |
1728 | auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return static_cast<bool>(lhs != rhs); } | |
1729 | template<typename T> | |
1730 | auto compareNotEqual( T* const& lhs, int rhs ) -> bool { return lhs != reinterpret_cast<void const*>( rhs ); } | |
1731 | template<typename T> | |
1732 | auto compareNotEqual( T* const& lhs, long rhs ) -> bool { return lhs != reinterpret_cast<void const*>( rhs ); } | |
1733 | template<typename T> | |
1734 | auto compareNotEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) != rhs; } | |
1735 | template<typename T> | |
1736 | auto compareNotEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) != rhs; } | |
1737 | ||
1738 | template<typename LhsT> | |
1739 | class ExprLhs { | |
1740 | LhsT m_lhs; | |
1741 | public: | |
1742 | explicit ExprLhs( LhsT lhs ) : m_lhs( lhs ) {} | |
1743 | ||
1744 | template<typename RhsT> | |
1745 | auto operator == ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { | |
1746 | return { compareEqual( m_lhs, rhs ), m_lhs, "==", rhs }; | |
1747 | } | |
1748 | auto operator == ( bool rhs ) -> BinaryExpr<LhsT, bool> const { | |
1749 | return { m_lhs == rhs, m_lhs, "==", rhs }; | |
1750 | } | |
1751 | ||
1752 | template<typename RhsT> | |
1753 | auto operator != ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { | |
1754 | return { compareNotEqual( m_lhs, rhs ), m_lhs, "!=", rhs }; | |
1755 | } | |
1756 | auto operator != ( bool rhs ) -> BinaryExpr<LhsT, bool> const { | |
1757 | return { m_lhs != rhs, m_lhs, "!=", rhs }; | |
1758 | } | |
1759 | ||
1760 | template<typename RhsT> | |
1761 | auto operator > ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { | |
1762 | return { static_cast<bool>(m_lhs > rhs), m_lhs, ">", rhs }; | |
1763 | } | |
1764 | template<typename RhsT> | |
1765 | auto operator < ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { | |
1766 | return { static_cast<bool>(m_lhs < rhs), m_lhs, "<", rhs }; | |
1767 | } | |
1768 | template<typename RhsT> | |
1769 | auto operator >= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { | |
1770 | return { static_cast<bool>(m_lhs >= rhs), m_lhs, ">=", rhs }; | |
1771 | } | |
1772 | template<typename RhsT> | |
1773 | auto operator <= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { | |
1774 | return { static_cast<bool>(m_lhs <= rhs), m_lhs, "<=", rhs }; | |
1775 | } | |
1776 | ||
1777 | auto makeUnaryExpr() const -> UnaryExpr<LhsT> { | |
1778 | return UnaryExpr<LhsT>{ m_lhs }; | |
1779 | } | |
1780 | }; | |
1781 | ||
1782 | void handleExpression( ITransientExpression const& expr ); | |
1783 | ||
1784 | template<typename T> | |
1785 | void handleExpression( ExprLhs<T> const& expr ) { | |
1786 | handleExpression( expr.makeUnaryExpr() ); | |
1787 | } | |
1788 | ||
1789 | struct Decomposer { | |
1790 | template<typename T> | |
1791 | auto operator <= ( T const& lhs ) -> ExprLhs<T const&> { | |
1792 | return ExprLhs<T const&>{ lhs }; | |
1793 | } | |
1794 | ||
1795 | auto operator <=( bool value ) -> ExprLhs<bool> { | |
1796 | return ExprLhs<bool>{ value }; | |
1797 | } | |
1798 | }; | |
1799 | ||
1800 | } // end namespace Catch | |
1801 | ||
1802 | #ifdef _MSC_VER | |
1803 | #pragma warning(pop) | |
1804 | #endif | |
1805 | ||
1806 | // end catch_decomposer.h | |
1807 | // start catch_interfaces_capture.h | |
1808 | ||
1809 | #include <string> | |
1810 | ||
1811 | namespace Catch { | |
1812 | ||
1813 | class AssertionResult; | |
1814 | struct AssertionInfo; | |
1815 | struct SectionInfo; | |
1816 | struct SectionEndInfo; | |
1817 | struct MessageInfo; | |
1818 | struct Counts; | |
1819 | struct BenchmarkInfo; | |
1820 | struct BenchmarkStats; | |
1821 | struct AssertionReaction; | |
1822 | struct SourceLineInfo; | |
1823 | ||
1824 | struct ITransientExpression; | |
1825 | struct IGeneratorTracker; | |
1826 | ||
1827 | struct IResultCapture { | |
1828 | ||
1829 | virtual ~IResultCapture(); | |
1830 | ||
1831 | virtual bool sectionStarted( SectionInfo const& sectionInfo, | |
1832 | Counts& assertions ) = 0; | |
1833 | virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; | |
1834 | virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; | |
1835 | ||
1836 | virtual auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0; | |
1837 | ||
1838 | virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0; | |
1839 | virtual void benchmarkEnded( BenchmarkStats const& stats ) = 0; | |
1840 | ||
1841 | virtual void pushScopedMessage( MessageInfo const& message ) = 0; | |
1842 | virtual void popScopedMessage( MessageInfo const& message ) = 0; | |
1843 | ||
1844 | virtual void handleFatalErrorCondition( StringRef message ) = 0; | |
1845 | ||
1846 | virtual void handleExpr | |
1847 | ( AssertionInfo const& info, | |
1848 | ITransientExpression const& expr, | |
1849 | AssertionReaction& reaction ) = 0; | |
1850 | virtual void handleMessage | |
1851 | ( AssertionInfo const& info, | |
1852 | ResultWas::OfType resultType, | |
1853 | StringRef const& message, | |
1854 | AssertionReaction& reaction ) = 0; | |
1855 | virtual void handleUnexpectedExceptionNotThrown | |
1856 | ( AssertionInfo const& info, | |
1857 | AssertionReaction& reaction ) = 0; | |
1858 | virtual void handleUnexpectedInflightException | |
1859 | ( AssertionInfo const& info, | |
1860 | std::string const& message, | |
1861 | AssertionReaction& reaction ) = 0; | |
1862 | virtual void handleIncomplete | |
1863 | ( AssertionInfo const& info ) = 0; | |
1864 | virtual void handleNonExpr | |
1865 | ( AssertionInfo const &info, | |
1866 | ResultWas::OfType resultType, | |
1867 | AssertionReaction &reaction ) = 0; | |
1868 | ||
1869 | virtual bool lastAssertionPassed() = 0; | |
1870 | virtual void assertionPassed() = 0; | |
1871 | ||
1872 | // Deprecated, do not use: | |
1873 | virtual std::string getCurrentTestName() const = 0; | |
1874 | virtual const AssertionResult* getLastResult() const = 0; | |
1875 | virtual void exceptionEarlyReported() = 0; | |
1876 | }; | |
1877 | ||
1878 | IResultCapture& getResultCapture(); | |
1879 | } | |
1880 | ||
1881 | // end catch_interfaces_capture.h | |
1882 | namespace Catch { | |
1883 | ||
1884 | struct TestFailureException{}; | |
1885 | struct AssertionResultData; | |
1886 | struct IResultCapture; | |
1887 | class RunContext; | |
1888 | ||
1889 | class LazyExpression { | |
1890 | friend class AssertionHandler; | |
1891 | friend struct AssertionStats; | |
1892 | friend class RunContext; | |
1893 | ||
1894 | ITransientExpression const* m_transientExpression = nullptr; | |
1895 | bool m_isNegated; | |
1896 | public: | |
1897 | LazyExpression( bool isNegated ); | |
1898 | LazyExpression( LazyExpression const& other ); | |
1899 | LazyExpression& operator = ( LazyExpression const& ) = delete; | |
1900 | ||
1901 | explicit operator bool() const; | |
1902 | ||
1903 | friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&; | |
1904 | }; | |
1905 | ||
1906 | struct AssertionReaction { | |
1907 | bool shouldDebugBreak = false; | |
1908 | bool shouldThrow = false; | |
1909 | }; | |
1910 | ||
1911 | class AssertionHandler { | |
1912 | AssertionInfo m_assertionInfo; | |
1913 | AssertionReaction m_reaction; | |
1914 | bool m_completed = false; | |
1915 | IResultCapture& m_resultCapture; | |
1916 | ||
1917 | public: | |
1918 | AssertionHandler | |
1919 | ( StringRef const& macroName, | |
1920 | SourceLineInfo const& lineInfo, | |
1921 | StringRef capturedExpression, | |
1922 | ResultDisposition::Flags resultDisposition ); | |
1923 | ~AssertionHandler() { | |
1924 | if ( !m_completed ) { | |
1925 | m_resultCapture.handleIncomplete( m_assertionInfo ); | |
1926 | } | |
1927 | } | |
1928 | ||
1929 | template<typename T> | |
1930 | void handleExpr( ExprLhs<T> const& expr ) { | |
1931 | handleExpr( expr.makeUnaryExpr() ); | |
1932 | } | |
1933 | void handleExpr( ITransientExpression const& expr ); | |
1934 | ||
1935 | void handleMessage(ResultWas::OfType resultType, StringRef const& message); | |
1936 | ||
1937 | void handleExceptionThrownAsExpected(); | |
1938 | void handleUnexpectedExceptionNotThrown(); | |
1939 | void handleExceptionNotThrownAsExpected(); | |
1940 | void handleThrowingCallSkipped(); | |
1941 | void handleUnexpectedInflightException(); | |
1942 | ||
1943 | void complete(); | |
1944 | void setCompleted(); | |
1945 | ||
1946 | // query | |
1947 | auto allowThrows() const -> bool; | |
1948 | }; | |
1949 | ||
1950 | void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef const& matcherString ); | |
1951 | ||
1952 | } // namespace Catch | |
1953 | ||
1954 | // end catch_assertionhandler.h | |
1955 | // start catch_message.h | |
1956 | ||
1957 | #include <string> | |
1958 | #include <vector> | |
1959 | ||
1960 | namespace Catch { | |
1961 | ||
1962 | struct MessageInfo { | |
1963 | MessageInfo( StringRef const& _macroName, | |
1964 | SourceLineInfo const& _lineInfo, | |
1965 | ResultWas::OfType _type ); | |
1966 | ||
1967 | StringRef macroName; | |
1968 | std::string message; | |
1969 | SourceLineInfo lineInfo; | |
1970 | ResultWas::OfType type; | |
1971 | unsigned int sequence; | |
1972 | ||
1973 | bool operator == ( MessageInfo const& other ) const; | |
1974 | bool operator < ( MessageInfo const& other ) const; | |
1975 | private: | |
1976 | static unsigned int globalCount; | |
1977 | }; | |
1978 | ||
1979 | struct MessageStream { | |
1980 | ||
1981 | template<typename T> | |
1982 | MessageStream& operator << ( T const& value ) { | |
1983 | m_stream << value; | |
1984 | return *this; | |
1985 | } | |
1986 | ||
1987 | ReusableStringStream m_stream; | |
1988 | }; | |
1989 | ||
1990 | struct MessageBuilder : MessageStream { | |
1991 | MessageBuilder( StringRef const& macroName, | |
1992 | SourceLineInfo const& lineInfo, | |
1993 | ResultWas::OfType type ); | |
1994 | ||
1995 | template<typename T> | |
1996 | MessageBuilder& operator << ( T const& value ) { | |
1997 | m_stream << value; | |
1998 | return *this; | |
1999 | } | |
2000 | ||
2001 | MessageInfo m_info; | |
2002 | }; | |
2003 | ||
2004 | class ScopedMessage { | |
2005 | public: | |
2006 | explicit ScopedMessage( MessageBuilder const& builder ); | |
2007 | ~ScopedMessage(); | |
2008 | ||
2009 | MessageInfo m_info; | |
2010 | }; | |
2011 | ||
2012 | class Capturer { | |
2013 | std::vector<MessageInfo> m_messages; | |
2014 | IResultCapture& m_resultCapture = getResultCapture(); | |
2015 | size_t m_captured = 0; | |
2016 | public: | |
2017 | Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ); | |
2018 | ~Capturer(); | |
2019 | ||
2020 | void captureValue( size_t index, std::string const& value ); | |
2021 | ||
2022 | template<typename T> | |
2023 | void captureValues( size_t index, T const& value ) { | |
2024 | captureValue( index, Catch::Detail::stringify( value ) ); | |
2025 | } | |
2026 | ||
2027 | template<typename T, typename... Ts> | |
2028 | void captureValues( size_t index, T const& value, Ts const&... values ) { | |
2029 | captureValue( index, Catch::Detail::stringify(value) ); | |
2030 | captureValues( index+1, values... ); | |
2031 | } | |
2032 | }; | |
2033 | ||
2034 | } // end namespace Catch | |
2035 | ||
2036 | // end catch_message.h | |
2037 | #if !defined(CATCH_CONFIG_DISABLE) | |
2038 | ||
2039 | #if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION) | |
2040 | #define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__ | |
2041 | #else | |
2042 | #define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION" | |
2043 | #endif | |
2044 | ||
2045 | #if defined(CATCH_CONFIG_FAST_COMPILE) || defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) | |
2046 | ||
2047 | /////////////////////////////////////////////////////////////////////////////// | |
2048 | // Another way to speed-up compilation is to omit local try-catch for REQUIRE* | |
2049 | // macros. | |
2050 | #define INTERNAL_CATCH_TRY | |
2051 | #define INTERNAL_CATCH_CATCH( capturer ) | |
2052 | ||
2053 | #else // CATCH_CONFIG_FAST_COMPILE | |
2054 | ||
2055 | #define INTERNAL_CATCH_TRY try | |
2056 | #define INTERNAL_CATCH_CATCH( handler ) catch(...) { handler.handleUnexpectedInflightException(); } | |
2057 | ||
2058 | #endif | |
2059 | ||
2060 | #define INTERNAL_CATCH_REACT( handler ) handler.complete(); | |
2061 | ||
2062 | /////////////////////////////////////////////////////////////////////////////// | |
2063 | #define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \ | |
2064 | do { \ | |
2065 | Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ | |
2066 | INTERNAL_CATCH_TRY { \ | |
2067 | CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ | |
2068 | catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); \ | |
2069 | CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ | |
2070 | } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ | |
2071 | INTERNAL_CATCH_REACT( catchAssertionHandler ) \ | |
2072 | } while( (void)0, false && static_cast<bool>( !!(__VA_ARGS__) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look | |
2073 | // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&. | |
2074 | ||
2075 | /////////////////////////////////////////////////////////////////////////////// | |
2076 | #define INTERNAL_CATCH_IF( macroName, resultDisposition, ... ) \ | |
2077 | INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \ | |
2078 | if( Catch::getResultCapture().lastAssertionPassed() ) | |
2079 | ||
2080 | /////////////////////////////////////////////////////////////////////////////// | |
2081 | #define INTERNAL_CATCH_ELSE( macroName, resultDisposition, ... ) \ | |
2082 | INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \ | |
2083 | if( !Catch::getResultCapture().lastAssertionPassed() ) | |
2084 | ||
2085 | /////////////////////////////////////////////////////////////////////////////// | |
2086 | #define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \ | |
2087 | do { \ | |
2088 | Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ | |
2089 | try { \ | |
2090 | static_cast<void>(__VA_ARGS__); \ | |
2091 | catchAssertionHandler.handleExceptionNotThrownAsExpected(); \ | |
2092 | } \ | |
2093 | catch( ... ) { \ | |
2094 | catchAssertionHandler.handleUnexpectedInflightException(); \ | |
2095 | } \ | |
2096 | INTERNAL_CATCH_REACT( catchAssertionHandler ) \ | |
2097 | } while( false ) | |
2098 | ||
2099 | /////////////////////////////////////////////////////////////////////////////// | |
2100 | #define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \ | |
2101 | do { \ | |
2102 | Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition); \ | |
2103 | if( catchAssertionHandler.allowThrows() ) \ | |
2104 | try { \ | |
2105 | static_cast<void>(__VA_ARGS__); \ | |
2106 | catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ | |
2107 | } \ | |
2108 | catch( ... ) { \ | |
2109 | catchAssertionHandler.handleExceptionThrownAsExpected(); \ | |
2110 | } \ | |
2111 | else \ | |
2112 | catchAssertionHandler.handleThrowingCallSkipped(); \ | |
2113 | INTERNAL_CATCH_REACT( catchAssertionHandler ) \ | |
2114 | } while( false ) | |
2115 | ||
2116 | /////////////////////////////////////////////////////////////////////////////// | |
2117 | #define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \ | |
2118 | do { \ | |
2119 | Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \ | |
2120 | if( catchAssertionHandler.allowThrows() ) \ | |
2121 | try { \ | |
2122 | static_cast<void>(expr); \ | |
2123 | catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ | |
2124 | } \ | |
2125 | catch( exceptionType const& ) { \ | |
2126 | catchAssertionHandler.handleExceptionThrownAsExpected(); \ | |
2127 | } \ | |
2128 | catch( ... ) { \ | |
2129 | catchAssertionHandler.handleUnexpectedInflightException(); \ | |
2130 | } \ | |
2131 | else \ | |
2132 | catchAssertionHandler.handleThrowingCallSkipped(); \ | |
2133 | INTERNAL_CATCH_REACT( catchAssertionHandler ) \ | |
2134 | } while( false ) | |
2135 | ||
2136 | /////////////////////////////////////////////////////////////////////////////// | |
2137 | #define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \ | |
2138 | do { \ | |
2139 | Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::StringRef(), resultDisposition ); \ | |
2140 | catchAssertionHandler.handleMessage( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \ | |
2141 | INTERNAL_CATCH_REACT( catchAssertionHandler ) \ | |
2142 | } while( false ) | |
2143 | ||
2144 | /////////////////////////////////////////////////////////////////////////////// | |
2145 | #define INTERNAL_CATCH_CAPTURE( varName, macroName, ... ) \ | |
2146 | auto varName = Catch::Capturer( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info, #__VA_ARGS__ ); \ | |
2147 | varName.captureValues( 0, __VA_ARGS__ ) | |
2148 | ||
2149 | /////////////////////////////////////////////////////////////////////////////// | |
2150 | #define INTERNAL_CATCH_INFO( macroName, log ) \ | |
2151 | Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log ); | |
2152 | ||
2153 | /////////////////////////////////////////////////////////////////////////////// | |
2154 | // Although this is matcher-based, it can be used with just a string | |
2155 | #define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \ | |
2156 | do { \ | |
2157 | Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ | |
2158 | if( catchAssertionHandler.allowThrows() ) \ | |
2159 | try { \ | |
2160 | static_cast<void>(__VA_ARGS__); \ | |
2161 | catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ | |
2162 | } \ | |
2163 | catch( ... ) { \ | |
2164 | Catch::handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher##_catch_sr ); \ | |
2165 | } \ | |
2166 | else \ | |
2167 | catchAssertionHandler.handleThrowingCallSkipped(); \ | |
2168 | INTERNAL_CATCH_REACT( catchAssertionHandler ) \ | |
2169 | } while( false ) | |
2170 | ||
2171 | #endif // CATCH_CONFIG_DISABLE | |
2172 | ||
2173 | // end catch_capture.hpp | |
2174 | // start catch_section.h | |
2175 | ||
2176 | // start catch_section_info.h | |
2177 | ||
2178 | // start catch_totals.h | |
2179 | ||
2180 | #include <cstddef> | |
2181 | ||
2182 | namespace Catch { | |
2183 | ||
2184 | struct Counts { | |
2185 | Counts operator - ( Counts const& other ) const; | |
2186 | Counts& operator += ( Counts const& other ); | |
2187 | ||
2188 | std::size_t total() const; | |
2189 | bool allPassed() const; | |
2190 | bool allOk() const; | |
2191 | ||
2192 | std::size_t passed = 0; | |
2193 | std::size_t failed = 0; | |
2194 | std::size_t failedButOk = 0; | |
2195 | }; | |
2196 | ||
2197 | struct Totals { | |
2198 | ||
2199 | Totals operator - ( Totals const& other ) const; | |
2200 | Totals& operator += ( Totals const& other ); | |
2201 | ||
2202 | Totals delta( Totals const& prevTotals ) const; | |
2203 | ||
2204 | int error = 0; | |
2205 | Counts assertions; | |
2206 | Counts testCases; | |
2207 | }; | |
2208 | } | |
2209 | ||
2210 | // end catch_totals.h | |
2211 | #include <string> | |
2212 | ||
2213 | namespace Catch { | |
2214 | ||
2215 | struct SectionInfo { | |
2216 | SectionInfo | |
2217 | ( SourceLineInfo const& _lineInfo, | |
2218 | std::string const& _name ); | |
2219 | ||
2220 | // Deprecated | |
2221 | SectionInfo | |
2222 | ( SourceLineInfo const& _lineInfo, | |
2223 | std::string const& _name, | |
2224 | std::string const& ) : SectionInfo( _lineInfo, _name ) {} | |
2225 | ||
2226 | std::string name; | |
2227 | std::string description; // !Deprecated: this will always be empty | |
2228 | SourceLineInfo lineInfo; | |
2229 | }; | |
2230 | ||
2231 | struct SectionEndInfo { | |
2232 | SectionInfo sectionInfo; | |
2233 | Counts prevAssertions; | |
2234 | double durationInSeconds; | |
2235 | }; | |
2236 | ||
2237 | } // end namespace Catch | |
2238 | ||
2239 | // end catch_section_info.h | |
2240 | // start catch_timer.h | |
2241 | ||
2242 | #include <cstdint> | |
2243 | ||
2244 | namespace Catch { | |
2245 | ||
2246 | auto getCurrentNanosecondsSinceEpoch() -> uint64_t; | |
2247 | auto getEstimatedClockResolution() -> uint64_t; | |
2248 | ||
2249 | class Timer { | |
2250 | uint64_t m_nanoseconds = 0; | |
2251 | public: | |
2252 | void start(); | |
2253 | auto getElapsedNanoseconds() const -> uint64_t; | |
2254 | auto getElapsedMicroseconds() const -> uint64_t; | |
2255 | auto getElapsedMilliseconds() const -> unsigned int; | |
2256 | auto getElapsedSeconds() const -> double; | |
2257 | }; | |
2258 | ||
2259 | } // namespace Catch | |
2260 | ||
2261 | // end catch_timer.h | |
2262 | #include <string> | |
2263 | ||
2264 | namespace Catch { | |
2265 | ||
2266 | class Section : NonCopyable { | |
2267 | public: | |
2268 | Section( SectionInfo const& info ); | |
2269 | ~Section(); | |
2270 | ||
2271 | // This indicates whether the section should be executed or not | |
2272 | explicit operator bool() const; | |
2273 | ||
2274 | private: | |
2275 | SectionInfo m_info; | |
2276 | ||
2277 | std::string m_name; | |
2278 | Counts m_assertions; | |
2279 | bool m_sectionIncluded; | |
2280 | Timer m_timer; | |
2281 | }; | |
2282 | ||
2283 | } // end namespace Catch | |
2284 | ||
2285 | #define INTERNAL_CATCH_SECTION( ... ) \ | |
2286 | CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ | |
2287 | if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \ | |
2288 | CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS | |
2289 | ||
2290 | #define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \ | |
2291 | CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ | |
2292 | if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, (Catch::ReusableStringStream() << __VA_ARGS__).str() ) ) \ | |
2293 | CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS | |
2294 | ||
2295 | // end catch_section.h | |
2296 | // start catch_benchmark.h | |
2297 | ||
2298 | #include <cstdint> | |
2299 | #include <string> | |
2300 | ||
2301 | namespace Catch { | |
2302 | ||
2303 | class BenchmarkLooper { | |
2304 | ||
2305 | std::string m_name; | |
2306 | std::size_t m_count = 0; | |
2307 | std::size_t m_iterationsToRun = 1; | |
2308 | uint64_t m_resolution; | |
2309 | Timer m_timer; | |
2310 | ||
2311 | static auto getResolution() -> uint64_t; | |
2312 | public: | |
2313 | // Keep most of this inline as it's on the code path that is being timed | |
2314 | BenchmarkLooper( StringRef name ) | |
2315 | : m_name( name ), | |
2316 | m_resolution( getResolution() ) | |
2317 | { | |
2318 | reportStart(); | |
2319 | m_timer.start(); | |
2320 | } | |
2321 | ||
2322 | explicit operator bool() { | |
2323 | if( m_count < m_iterationsToRun ) | |
2324 | return true; | |
2325 | return needsMoreIterations(); | |
2326 | } | |
2327 | ||
2328 | void increment() { | |
2329 | ++m_count; | |
2330 | } | |
2331 | ||
2332 | void reportStart(); | |
2333 | auto needsMoreIterations() -> bool; | |
2334 | }; | |
2335 | ||
2336 | } // end namespace Catch | |
2337 | ||
2338 | #define BENCHMARK( name ) \ | |
2339 | for( Catch::BenchmarkLooper looper( name ); looper; looper.increment() ) | |
2340 | ||
2341 | // end catch_benchmark.h | |
2342 | // start catch_interfaces_exception.h | |
2343 | ||
2344 | // start catch_interfaces_registry_hub.h | |
2345 | ||
2346 | #include <string> | |
2347 | #include <memory> | |
2348 | ||
2349 | namespace Catch { | |
2350 | ||
2351 | class TestCase; | |
2352 | struct ITestCaseRegistry; | |
2353 | struct IExceptionTranslatorRegistry; | |
2354 | struct IExceptionTranslator; | |
2355 | struct IReporterRegistry; | |
2356 | struct IReporterFactory; | |
2357 | struct ITagAliasRegistry; | |
2358 | class StartupExceptionRegistry; | |
2359 | ||
2360 | using IReporterFactoryPtr = std::shared_ptr<IReporterFactory>; | |
2361 | ||
2362 | struct IRegistryHub { | |
2363 | virtual ~IRegistryHub(); | |
2364 | ||
2365 | virtual IReporterRegistry const& getReporterRegistry() const = 0; | |
2366 | virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; | |
2367 | virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0; | |
2368 | ||
2369 | virtual IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const = 0; | |
2370 | ||
2371 | virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0; | |
2372 | }; | |
2373 | ||
2374 | struct IMutableRegistryHub { | |
2375 | virtual ~IMutableRegistryHub(); | |
2376 | virtual void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) = 0; | |
2377 | virtual void registerListener( IReporterFactoryPtr const& factory ) = 0; | |
2378 | virtual void registerTest( TestCase const& testInfo ) = 0; | |
2379 | virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; | |
2380 | virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0; | |
2381 | virtual void registerStartupException() noexcept = 0; | |
2382 | }; | |
2383 | ||
2384 | IRegistryHub const& getRegistryHub(); | |
2385 | IMutableRegistryHub& getMutableRegistryHub(); | |
2386 | void cleanUp(); | |
2387 | std::string translateActiveException(); | |
2388 | ||
2389 | } | |
2390 | ||
2391 | // end catch_interfaces_registry_hub.h | |
2392 | #if defined(CATCH_CONFIG_DISABLE) | |
2393 | #define INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( translatorName, signature) \ | |
2394 | static std::string translatorName( signature ) | |
2395 | #endif | |
2396 | ||
2397 | #include <exception> | |
2398 | #include <string> | |
2399 | #include <vector> | |
2400 | ||
2401 | namespace Catch { | |
2402 | using exceptionTranslateFunction = std::string(*)(); | |
2403 | ||
2404 | struct IExceptionTranslator; | |
2405 | using ExceptionTranslators = std::vector<std::unique_ptr<IExceptionTranslator const>>; | |
2406 | ||
2407 | struct IExceptionTranslator { | |
2408 | virtual ~IExceptionTranslator(); | |
2409 | virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0; | |
2410 | }; | |
2411 | ||
2412 | struct IExceptionTranslatorRegistry { | |
2413 | virtual ~IExceptionTranslatorRegistry(); | |
2414 | ||
2415 | virtual std::string translateActiveException() const = 0; | |
2416 | }; | |
2417 | ||
2418 | class ExceptionTranslatorRegistrar { | |
2419 | template<typename T> | |
2420 | class ExceptionTranslator : public IExceptionTranslator { | |
2421 | public: | |
2422 | ||
2423 | ExceptionTranslator( std::string(*translateFunction)( T& ) ) | |
2424 | : m_translateFunction( translateFunction ) | |
2425 | {} | |
2426 | ||
2427 | std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const override { | |
2428 | try { | |
2429 | if( it == itEnd ) | |
2430 | std::rethrow_exception(std::current_exception()); | |
2431 | else | |
2432 | return (*it)->translate( it+1, itEnd ); | |
2433 | } | |
2434 | catch( T& ex ) { | |
2435 | return m_translateFunction( ex ); | |
2436 | } | |
2437 | } | |
2438 | ||
2439 | protected: | |
2440 | std::string(*m_translateFunction)( T& ); | |
2441 | }; | |
2442 | ||
2443 | public: | |
2444 | template<typename T> | |
2445 | ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) { | |
2446 | getMutableRegistryHub().registerTranslator | |
2447 | ( new ExceptionTranslator<T>( translateFunction ) ); | |
2448 | } | |
2449 | }; | |
2450 | } | |
2451 | ||
2452 | /////////////////////////////////////////////////////////////////////////////// | |
2453 | #define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \ | |
2454 | static std::string translatorName( signature ); \ | |
2455 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ | |
2456 | namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); } \ | |
2457 | CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ | |
2458 | static std::string translatorName( signature ) | |
2459 | ||
2460 | #define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) | |
2461 | ||
2462 | // end catch_interfaces_exception.h | |
2463 | // start catch_approx.h | |
2464 | ||
2465 | #include <type_traits> | |
2466 | ||
2467 | namespace Catch { | |
2468 | namespace Detail { | |
2469 | ||
2470 | class Approx { | |
2471 | private: | |
2472 | bool equalityComparisonImpl(double other) const; | |
2473 | // Validates the new margin (margin >= 0) | |
2474 | // out-of-line to avoid including stdexcept in the header | |
2475 | void setMargin(double margin); | |
2476 | // Validates the new epsilon (0 < epsilon < 1) | |
2477 | // out-of-line to avoid including stdexcept in the header | |
2478 | void setEpsilon(double epsilon); | |
2479 | ||
2480 | public: | |
2481 | explicit Approx ( double value ); | |
2482 | ||
2483 | static Approx custom(); | |
2484 | ||
2485 | Approx operator-() const; | |
2486 | ||
2487 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> | |
2488 | Approx operator()( T const& value ) { | |
2489 | Approx approx( static_cast<double>(value) ); | |
2490 | approx.m_epsilon = m_epsilon; | |
2491 | approx.m_margin = m_margin; | |
2492 | approx.m_scale = m_scale; | |
2493 | return approx; | |
2494 | } | |
2495 | ||
2496 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> | |
2497 | explicit Approx( T const& value ): Approx(static_cast<double>(value)) | |
2498 | {} | |
2499 | ||
2500 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> | |
2501 | friend bool operator == ( const T& lhs, Approx const& rhs ) { | |
2502 | auto lhs_v = static_cast<double>(lhs); | |
2503 | return rhs.equalityComparisonImpl(lhs_v); | |
2504 | } | |
2505 | ||
2506 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> | |
2507 | friend bool operator == ( Approx const& lhs, const T& rhs ) { | |
2508 | return operator==( rhs, lhs ); | |
2509 | } | |
2510 | ||
2511 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> | |
2512 | friend bool operator != ( T const& lhs, Approx const& rhs ) { | |
2513 | return !operator==( lhs, rhs ); | |
2514 | } | |
2515 | ||
2516 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> | |
2517 | friend bool operator != ( Approx const& lhs, T const& rhs ) { | |
2518 | return !operator==( rhs, lhs ); | |
2519 | } | |
2520 | ||
2521 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> | |
2522 | friend bool operator <= ( T const& lhs, Approx const& rhs ) { | |
2523 | return static_cast<double>(lhs) < rhs.m_value || lhs == rhs; | |
2524 | } | |
2525 | ||
2526 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> | |
2527 | friend bool operator <= ( Approx const& lhs, T const& rhs ) { | |
2528 | return lhs.m_value < static_cast<double>(rhs) || lhs == rhs; | |
2529 | } | |
2530 | ||
2531 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> | |
2532 | friend bool operator >= ( T const& lhs, Approx const& rhs ) { | |
2533 | return static_cast<double>(lhs) > rhs.m_value || lhs == rhs; | |
2534 | } | |
2535 | ||
2536 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> | |
2537 | friend bool operator >= ( Approx const& lhs, T const& rhs ) { | |
2538 | return lhs.m_value > static_cast<double>(rhs) || lhs == rhs; | |
2539 | } | |
2540 | ||
2541 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> | |
2542 | Approx& epsilon( T const& newEpsilon ) { | |
2543 | double epsilonAsDouble = static_cast<double>(newEpsilon); | |
2544 | setEpsilon(epsilonAsDouble); | |
2545 | return *this; | |
2546 | } | |
2547 | ||
2548 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> | |
2549 | Approx& margin( T const& newMargin ) { | |
2550 | double marginAsDouble = static_cast<double>(newMargin); | |
2551 | setMargin(marginAsDouble); | |
2552 | return *this; | |
2553 | } | |
2554 | ||
2555 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> | |
2556 | Approx& scale( T const& newScale ) { | |
2557 | m_scale = static_cast<double>(newScale); | |
2558 | return *this; | |
2559 | } | |
2560 | ||
2561 | std::string toString() const; | |
2562 | ||
2563 | private: | |
2564 | double m_epsilon; | |
2565 | double m_margin; | |
2566 | double m_scale; | |
2567 | double m_value; | |
2568 | }; | |
2569 | } // end namespace Detail | |
2570 | ||
2571 | namespace literals { | |
2572 | Detail::Approx operator "" _a(long double val); | |
2573 | Detail::Approx operator "" _a(unsigned long long val); | |
2574 | } // end namespace literals | |
2575 | ||
2576 | template<> | |
2577 | struct StringMaker<Catch::Detail::Approx> { | |
2578 | static std::string convert(Catch::Detail::Approx const& value); | |
2579 | }; | |
2580 | ||
2581 | } // end namespace Catch | |
2582 | ||
2583 | // end catch_approx.h | |
2584 | // start catch_string_manip.h | |
2585 | ||
2586 | #include <string> | |
2587 | #include <iosfwd> | |
2588 | ||
2589 | namespace Catch { | |
2590 | ||
2591 | bool startsWith( std::string const& s, std::string const& prefix ); | |
2592 | bool startsWith( std::string const& s, char prefix ); | |
2593 | bool endsWith( std::string const& s, std::string const& suffix ); | |
2594 | bool endsWith( std::string const& s, char suffix ); | |
2595 | bool contains( std::string const& s, std::string const& infix ); | |
2596 | void toLowerInPlace( std::string& s ); | |
2597 | std::string toLower( std::string const& s ); | |
2598 | std::string trim( std::string const& str ); | |
2599 | bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); | |
2600 | ||
2601 | struct pluralise { | |
2602 | pluralise( std::size_t count, std::string const& label ); | |
2603 | ||
2604 | friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ); | |
2605 | ||
2606 | std::size_t m_count; | |
2607 | std::string m_label; | |
2608 | }; | |
2609 | } | |
2610 | ||
2611 | // end catch_string_manip.h | |
2612 | #ifndef CATCH_CONFIG_DISABLE_MATCHERS | |
2613 | // start catch_capture_matchers.h | |
2614 | ||
2615 | // start catch_matchers.h | |
2616 | ||
2617 | #include <string> | |
2618 | #include <vector> | |
2619 | ||
2620 | namespace Catch { | |
2621 | namespace Matchers { | |
2622 | namespace Impl { | |
2623 | ||
2624 | template<typename ArgT> struct MatchAllOf; | |
2625 | template<typename ArgT> struct MatchAnyOf; | |
2626 | template<typename ArgT> struct MatchNotOf; | |
2627 | ||
2628 | class MatcherUntypedBase { | |
2629 | public: | |
2630 | MatcherUntypedBase() = default; | |
2631 | MatcherUntypedBase ( MatcherUntypedBase const& ) = default; | |
2632 | MatcherUntypedBase& operator = ( MatcherUntypedBase const& ) = delete; | |
2633 | std::string toString() const; | |
2634 | ||
2635 | protected: | |
2636 | virtual ~MatcherUntypedBase(); | |
2637 | virtual std::string describe() const = 0; | |
2638 | mutable std::string m_cachedToString; | |
2639 | }; | |
2640 | ||
2641 | #ifdef __clang__ | |
2642 | # pragma clang diagnostic push | |
2643 | # pragma clang diagnostic ignored "-Wnon-virtual-dtor" | |
2644 | #endif | |
2645 | ||
2646 | template<typename ObjectT> | |
2647 | struct MatcherMethod { | |
2648 | virtual bool match( ObjectT const& arg ) const = 0; | |
2649 | }; | |
2650 | ||
2651 | #ifdef __clang__ | |
2652 | # pragma clang diagnostic pop | |
2653 | #endif | |
2654 | ||
2655 | template<typename T> | |
2656 | struct MatcherBase : MatcherUntypedBase, MatcherMethod<T> { | |
2657 | ||
2658 | MatchAllOf<T> operator && ( MatcherBase const& other ) const; | |
2659 | MatchAnyOf<T> operator || ( MatcherBase const& other ) const; | |
2660 | MatchNotOf<T> operator ! () const; | |
2661 | }; | |
2662 | ||
2663 | template<typename ArgT> | |
2664 | struct MatchAllOf : MatcherBase<ArgT> { | |
2665 | bool match( ArgT const& arg ) const override { | |
2666 | for( auto matcher : m_matchers ) { | |
2667 | if (!matcher->match(arg)) | |
2668 | return false; | |
2669 | } | |
2670 | return true; | |
2671 | } | |
2672 | std::string describe() const override { | |
2673 | std::string description; | |
2674 | description.reserve( 4 + m_matchers.size()*32 ); | |
2675 | description += "( "; | |
2676 | bool first = true; | |
2677 | for( auto matcher : m_matchers ) { | |
2678 | if( first ) | |
2679 | first = false; | |
2680 | else | |
2681 | description += " and "; | |
2682 | description += matcher->toString(); | |
2683 | } | |
2684 | description += " )"; | |
2685 | return description; | |
2686 | } | |
2687 | ||
2688 | MatchAllOf<ArgT>& operator && ( MatcherBase<ArgT> const& other ) { | |
2689 | m_matchers.push_back( &other ); | |
2690 | return *this; | |
2691 | } | |
2692 | ||
2693 | std::vector<MatcherBase<ArgT> const*> m_matchers; | |
2694 | }; | |
2695 | template<typename ArgT> | |
2696 | struct MatchAnyOf : MatcherBase<ArgT> { | |
2697 | ||
2698 | bool match( ArgT const& arg ) const override { | |
2699 | for( auto matcher : m_matchers ) { | |
2700 | if (matcher->match(arg)) | |
2701 | return true; | |
2702 | } | |
2703 | return false; | |
2704 | } | |
2705 | std::string describe() const override { | |
2706 | std::string description; | |
2707 | description.reserve( 4 + m_matchers.size()*32 ); | |
2708 | description += "( "; | |
2709 | bool first = true; | |
2710 | for( auto matcher : m_matchers ) { | |
2711 | if( first ) | |
2712 | first = false; | |
2713 | else | |
2714 | description += " or "; | |
2715 | description += matcher->toString(); | |
2716 | } | |
2717 | description += " )"; | |
2718 | return description; | |
2719 | } | |
2720 | ||
2721 | MatchAnyOf<ArgT>& operator || ( MatcherBase<ArgT> const& other ) { | |
2722 | m_matchers.push_back( &other ); | |
2723 | return *this; | |
2724 | } | |
2725 | ||
2726 | std::vector<MatcherBase<ArgT> const*> m_matchers; | |
2727 | }; | |
2728 | ||
2729 | template<typename ArgT> | |
2730 | struct MatchNotOf : MatcherBase<ArgT> { | |
2731 | ||
2732 | MatchNotOf( MatcherBase<ArgT> const& underlyingMatcher ) : m_underlyingMatcher( underlyingMatcher ) {} | |
2733 | ||
2734 | bool match( ArgT const& arg ) const override { | |
2735 | return !m_underlyingMatcher.match( arg ); | |
2736 | } | |
2737 | ||
2738 | std::string describe() const override { | |
2739 | return "not " + m_underlyingMatcher.toString(); | |
2740 | } | |
2741 | MatcherBase<ArgT> const& m_underlyingMatcher; | |
2742 | }; | |
2743 | ||
2744 | template<typename T> | |
2745 | MatchAllOf<T> MatcherBase<T>::operator && ( MatcherBase const& other ) const { | |
2746 | return MatchAllOf<T>() && *this && other; | |
2747 | } | |
2748 | template<typename T> | |
2749 | MatchAnyOf<T> MatcherBase<T>::operator || ( MatcherBase const& other ) const { | |
2750 | return MatchAnyOf<T>() || *this || other; | |
2751 | } | |
2752 | template<typename T> | |
2753 | MatchNotOf<T> MatcherBase<T>::operator ! () const { | |
2754 | return MatchNotOf<T>( *this ); | |
2755 | } | |
2756 | ||
2757 | } // namespace Impl | |
2758 | ||
2759 | } // namespace Matchers | |
2760 | ||
2761 | using namespace Matchers; | |
2762 | using Matchers::Impl::MatcherBase; | |
2763 | ||
2764 | } // namespace Catch | |
2765 | ||
2766 | // end catch_matchers.h | |
2767 | // start catch_matchers_floating.h | |
2768 | ||
2769 | #include <type_traits> | |
2770 | #include <cmath> | |
2771 | ||
2772 | namespace Catch { | |
2773 | namespace Matchers { | |
2774 | ||
2775 | namespace Floating { | |
2776 | ||
2777 | enum class FloatingPointKind : uint8_t; | |
2778 | ||
2779 | struct WithinAbsMatcher : MatcherBase<double> { | |
2780 | WithinAbsMatcher(double target, double margin); | |
2781 | bool match(double const& matchee) const override; | |
2782 | std::string describe() const override; | |
2783 | private: | |
2784 | double m_target; | |
2785 | double m_margin; | |
2786 | }; | |
2787 | ||
2788 | struct WithinUlpsMatcher : MatcherBase<double> { | |
2789 | WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType); | |
2790 | bool match(double const& matchee) const override; | |
2791 | std::string describe() const override; | |
2792 | private: | |
2793 | double m_target; | |
2794 | int m_ulps; | |
2795 | FloatingPointKind m_type; | |
2796 | }; | |
2797 | ||
2798 | } // namespace Floating | |
2799 | ||
2800 | // The following functions create the actual matcher objects. | |
2801 | // This allows the types to be inferred | |
2802 | Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff); | |
2803 | Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff); | |
2804 | Floating::WithinAbsMatcher WithinAbs(double target, double margin); | |
2805 | ||
2806 | } // namespace Matchers | |
2807 | } // namespace Catch | |
2808 | ||
2809 | // end catch_matchers_floating.h | |
2810 | // start catch_matchers_generic.hpp | |
2811 | ||
2812 | #include <functional> | |
2813 | #include <string> | |
2814 | ||
2815 | namespace Catch { | |
2816 | namespace Matchers { | |
2817 | namespace Generic { | |
2818 | ||
2819 | namespace Detail { | |
2820 | std::string finalizeDescription(const std::string& desc); | |
2821 | } | |
2822 | ||
2823 | template <typename T> | |
2824 | class PredicateMatcher : public MatcherBase<T> { | |
2825 | std::function<bool(T const&)> m_predicate; | |
2826 | std::string m_description; | |
2827 | public: | |
2828 | ||
2829 | PredicateMatcher(std::function<bool(T const&)> const& elem, std::string const& descr) | |
2830 | :m_predicate(std::move(elem)), | |
2831 | m_description(Detail::finalizeDescription(descr)) | |
2832 | {} | |
2833 | ||
2834 | bool match( T const& item ) const override { | |
2835 | return m_predicate(item); | |
2836 | } | |
2837 | ||
2838 | std::string describe() const override { | |
2839 | return m_description; | |
2840 | } | |
2841 | }; | |
2842 | ||
2843 | } // namespace Generic | |
2844 | ||
2845 | // The following functions create the actual matcher objects. | |
2846 | // The user has to explicitly specify type to the function, because | |
2847 | // infering std::function<bool(T const&)> is hard (but possible) and | |
2848 | // requires a lot of TMP. | |
2849 | template<typename T> | |
2850 | Generic::PredicateMatcher<T> Predicate(std::function<bool(T const&)> const& predicate, std::string const& description = "") { | |
2851 | return Generic::PredicateMatcher<T>(predicate, description); | |
2852 | } | |
2853 | ||
2854 | } // namespace Matchers | |
2855 | } // namespace Catch | |
2856 | ||
2857 | // end catch_matchers_generic.hpp | |
2858 | // start catch_matchers_string.h | |
2859 | ||
2860 | #include <string> | |
2861 | ||
2862 | namespace Catch { | |
2863 | namespace Matchers { | |
2864 | ||
2865 | namespace StdString { | |
2866 | ||
2867 | struct CasedString | |
2868 | { | |
2869 | CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ); | |
2870 | std::string adjustString( std::string const& str ) const; | |
2871 | std::string caseSensitivitySuffix() const; | |
2872 | ||
2873 | CaseSensitive::Choice m_caseSensitivity; | |
2874 | std::string m_str; | |
2875 | }; | |
2876 | ||
2877 | struct StringMatcherBase : MatcherBase<std::string> { | |
2878 | StringMatcherBase( std::string const& operation, CasedString const& comparator ); | |
2879 | std::string describe() const override; | |
2880 | ||
2881 | CasedString m_comparator; | |
2882 | std::string m_operation; | |
2883 | }; | |
2884 | ||
2885 | struct EqualsMatcher : StringMatcherBase { | |
2886 | EqualsMatcher( CasedString const& comparator ); | |
2887 | bool match( std::string const& source ) const override; | |
2888 | }; | |
2889 | struct ContainsMatcher : StringMatcherBase { | |
2890 | ContainsMatcher( CasedString const& comparator ); | |
2891 | bool match( std::string const& source ) const override; | |
2892 | }; | |
2893 | struct StartsWithMatcher : StringMatcherBase { | |
2894 | StartsWithMatcher( CasedString const& comparator ); | |
2895 | bool match( std::string const& source ) const override; | |
2896 | }; | |
2897 | struct EndsWithMatcher : StringMatcherBase { | |
2898 | EndsWithMatcher( CasedString const& comparator ); | |
2899 | bool match( std::string const& source ) const override; | |
2900 | }; | |
2901 | ||
2902 | struct RegexMatcher : MatcherBase<std::string> { | |
2903 | RegexMatcher( std::string regex, CaseSensitive::Choice caseSensitivity ); | |
2904 | bool match( std::string const& matchee ) const override; | |
2905 | std::string describe() const override; | |
2906 | ||
2907 | private: | |
2908 | std::string m_regex; | |
2909 | CaseSensitive::Choice m_caseSensitivity; | |
2910 | }; | |
2911 | ||
2912 | } // namespace StdString | |
2913 | ||
2914 | // The following functions create the actual matcher objects. | |
2915 | // This allows the types to be inferred | |
2916 | ||
2917 | StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); | |
2918 | StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); | |
2919 | StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); | |
2920 | StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); | |
2921 | StdString::RegexMatcher Matches( std::string const& regex, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); | |
2922 | ||
2923 | } // namespace Matchers | |
2924 | } // namespace Catch | |
2925 | ||
2926 | // end catch_matchers_string.h | |
2927 | // start catch_matchers_vector.h | |
2928 | ||
2929 | #include <algorithm> | |
2930 | ||
2931 | namespace Catch { | |
2932 | namespace Matchers { | |
2933 | ||
2934 | namespace Vector { | |
2935 | namespace Detail { | |
2936 | template <typename InputIterator, typename T> | |
2937 | size_t count(InputIterator first, InputIterator last, T const& item) { | |
2938 | size_t cnt = 0; | |
2939 | for (; first != last; ++first) { | |
2940 | if (*first == item) { | |
2941 | ++cnt; | |
2942 | } | |
2943 | } | |
2944 | return cnt; | |
2945 | } | |
2946 | template <typename InputIterator, typename T> | |
2947 | bool contains(InputIterator first, InputIterator last, T const& item) { | |
2948 | for (; first != last; ++first) { | |
2949 | if (*first == item) { | |
2950 | return true; | |
2951 | } | |
2952 | } | |
2953 | return false; | |
2954 | } | |
2955 | } | |
2956 | ||
2957 | template<typename T> | |
2958 | struct ContainsElementMatcher : MatcherBase<std::vector<T>> { | |
2959 | ||
2960 | ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {} | |
2961 | ||
2962 | bool match(std::vector<T> const &v) const override { | |
2963 | for (auto const& el : v) { | |
2964 | if (el == m_comparator) { | |
2965 | return true; | |
2966 | } | |
2967 | } | |
2968 | return false; | |
2969 | } | |
2970 | ||
2971 | std::string describe() const override { | |
2972 | return "Contains: " + ::Catch::Detail::stringify( m_comparator ); | |
2973 | } | |
2974 | ||
2975 | T const& m_comparator; | |
2976 | }; | |
2977 | ||
2978 | template<typename T> | |
2979 | struct ContainsMatcher : MatcherBase<std::vector<T>> { | |
2980 | ||
2981 | ContainsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {} | |
2982 | ||
2983 | bool match(std::vector<T> const &v) const override { | |
2984 | // !TBD: see note in EqualsMatcher | |
2985 | if (m_comparator.size() > v.size()) | |
2986 | return false; | |
2987 | for (auto const& comparator : m_comparator) { | |
2988 | auto present = false; | |
2989 | for (const auto& el : v) { | |
2990 | if (el == comparator) { | |
2991 | present = true; | |
2992 | break; | |
2993 | } | |
2994 | } | |
2995 | if (!present) { | |
2996 | return false; | |
2997 | } | |
2998 | } | |
2999 | return true; | |
3000 | } | |
3001 | std::string describe() const override { | |
3002 | return "Contains: " + ::Catch::Detail::stringify( m_comparator ); | |
3003 | } | |
3004 | ||
3005 | std::vector<T> const& m_comparator; | |
3006 | }; | |
3007 | ||
3008 | template<typename T> | |
3009 | struct EqualsMatcher : MatcherBase<std::vector<T>> { | |
3010 | ||
3011 | EqualsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {} | |
3012 | ||
3013 | bool match(std::vector<T> const &v) const override { | |
3014 | // !TBD: This currently works if all elements can be compared using != | |
3015 | // - a more general approach would be via a compare template that defaults | |
3016 | // to using !=. but could be specialised for, e.g. std::vector<T> etc | |
3017 | // - then just call that directly | |
3018 | if (m_comparator.size() != v.size()) | |
3019 | return false; | |
3020 | for (std::size_t i = 0; i < v.size(); ++i) | |
3021 | if (m_comparator[i] != v[i]) | |
3022 | return false; | |
3023 | return true; | |
3024 | } | |
3025 | std::string describe() const override { | |
3026 | return "Equals: " + ::Catch::Detail::stringify( m_comparator ); | |
3027 | } | |
3028 | std::vector<T> const& m_comparator; | |
3029 | }; | |
3030 | ||
3031 | template<typename T> | |
3032 | struct UnorderedEqualsMatcher : MatcherBase<std::vector<T>> { | |
3033 | UnorderedEqualsMatcher(std::vector<T> const& target) : m_target(target) {} | |
3034 | bool match(std::vector<T> const& vec) const override { | |
3035 | // Note: This is a reimplementation of std::is_permutation, | |
3036 | // because I don't want to include <algorithm> inside the common path | |
3037 | if (m_target.size() != vec.size()) { | |
3038 | return false; | |
3039 | } | |
3040 | auto lfirst = m_target.begin(), llast = m_target.end(); | |
3041 | auto rfirst = vec.begin(), rlast = vec.end(); | |
3042 | // Cut common prefix to optimize checking of permuted parts | |
3043 | while (lfirst != llast && *lfirst == *rfirst) { | |
3044 | ++lfirst; ++rfirst; | |
3045 | } | |
3046 | if (lfirst == llast) { | |
3047 | return true; | |
3048 | } | |
3049 | ||
3050 | for (auto mid = lfirst; mid != llast; ++mid) { | |
3051 | // Skip already counted items | |
3052 | if (Detail::contains(lfirst, mid, *mid)) { | |
3053 | continue; | |
3054 | } | |
3055 | size_t num_vec = Detail::count(rfirst, rlast, *mid); | |
3056 | if (num_vec == 0 || Detail::count(lfirst, llast, *mid) != num_vec) { | |
3057 | return false; | |
3058 | } | |
3059 | } | |
3060 | ||
3061 | return true; | |
3062 | } | |
3063 | ||
3064 | std::string describe() const override { | |
3065 | return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target); | |
3066 | } | |
3067 | private: | |
3068 | std::vector<T> const& m_target; | |
3069 | }; | |
3070 | ||
3071 | } // namespace Vector | |
3072 | ||
3073 | // The following functions create the actual matcher objects. | |
3074 | // This allows the types to be inferred | |
3075 | ||
3076 | template<typename T> | |
3077 | Vector::ContainsMatcher<T> Contains( std::vector<T> const& comparator ) { | |
3078 | return Vector::ContainsMatcher<T>( comparator ); | |
3079 | } | |
3080 | ||
3081 | template<typename T> | |
3082 | Vector::ContainsElementMatcher<T> VectorContains( T const& comparator ) { | |
3083 | return Vector::ContainsElementMatcher<T>( comparator ); | |
3084 | } | |
3085 | ||
3086 | template<typename T> | |
3087 | Vector::EqualsMatcher<T> Equals( std::vector<T> const& comparator ) { | |
3088 | return Vector::EqualsMatcher<T>( comparator ); | |
3089 | } | |
3090 | ||
3091 | template<typename T> | |
3092 | Vector::UnorderedEqualsMatcher<T> UnorderedEquals(std::vector<T> const& target) { | |
3093 | return Vector::UnorderedEqualsMatcher<T>(target); | |
3094 | } | |
3095 | ||
3096 | } // namespace Matchers | |
3097 | } // namespace Catch | |
3098 | ||
3099 | // end catch_matchers_vector.h | |
3100 | namespace Catch { | |
3101 | ||
3102 | template<typename ArgT, typename MatcherT> | |
3103 | class MatchExpr : public ITransientExpression { | |
3104 | ArgT const& m_arg; | |
3105 | MatcherT m_matcher; | |
3106 | StringRef m_matcherString; | |
3107 | public: | |
3108 | MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef const& matcherString ) | |
3109 | : ITransientExpression{ true, matcher.match( arg ) }, | |
3110 | m_arg( arg ), | |
3111 | m_matcher( matcher ), | |
3112 | m_matcherString( matcherString ) | |
3113 | {} | |
3114 | ||
3115 | void streamReconstructedExpression( std::ostream &os ) const override { | |
3116 | auto matcherAsString = m_matcher.toString(); | |
3117 | os << Catch::Detail::stringify( m_arg ) << ' '; | |
3118 | if( matcherAsString == Detail::unprintableString ) | |
3119 | os << m_matcherString; | |
3120 | else | |
3121 | os << matcherAsString; | |
3122 | } | |
3123 | }; | |
3124 | ||
3125 | using StringMatcher = Matchers::Impl::MatcherBase<std::string>; | |
3126 | ||
3127 | void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString ); | |
3128 | ||
3129 | template<typename ArgT, typename MatcherT> | |
3130 | auto makeMatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef const& matcherString ) -> MatchExpr<ArgT, MatcherT> { | |
3131 | return MatchExpr<ArgT, MatcherT>( arg, matcher, matcherString ); | |
3132 | } | |
3133 | ||
3134 | } // namespace Catch | |
3135 | ||
3136 | /////////////////////////////////////////////////////////////////////////////// | |
3137 | #define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \ | |
3138 | do { \ | |
3139 | Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ | |
3140 | INTERNAL_CATCH_TRY { \ | |
3141 | catchAssertionHandler.handleExpr( Catch::makeMatchExpr( arg, matcher, #matcher##_catch_sr ) ); \ | |
3142 | } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ | |
3143 | INTERNAL_CATCH_REACT( catchAssertionHandler ) \ | |
3144 | } while( false ) | |
3145 | ||
3146 | /////////////////////////////////////////////////////////////////////////////// | |
3147 | #define INTERNAL_CATCH_THROWS_MATCHES( macroName, exceptionType, resultDisposition, matcher, ... ) \ | |
3148 | do { \ | |
3149 | Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(exceptionType) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ | |
3150 | if( catchAssertionHandler.allowThrows() ) \ | |
3151 | try { \ | |
3152 | static_cast<void>(__VA_ARGS__ ); \ | |
3153 | catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ | |
3154 | } \ | |
3155 | catch( exceptionType const& ex ) { \ | |
3156 | catchAssertionHandler.handleExpr( Catch::makeMatchExpr( ex, matcher, #matcher##_catch_sr ) ); \ | |
3157 | } \ | |
3158 | catch( ... ) { \ | |
3159 | catchAssertionHandler.handleUnexpectedInflightException(); \ | |
3160 | } \ | |
3161 | else \ | |
3162 | catchAssertionHandler.handleThrowingCallSkipped(); \ | |
3163 | INTERNAL_CATCH_REACT( catchAssertionHandler ) \ | |
3164 | } while( false ) | |
3165 | ||
3166 | // end catch_capture_matchers.h | |
3167 | #endif | |
3168 | // start catch_generators.hpp | |
3169 | ||
3170 | // start catch_interfaces_generatortracker.h | |
3171 | ||
3172 | ||
3173 | #include <memory> | |
3174 | ||
3175 | namespace Catch { | |
3176 | ||
3177 | namespace Generators { | |
3178 | class GeneratorBase { | |
3179 | protected: | |
3180 | size_t m_size = 0; | |
3181 | ||
3182 | public: | |
3183 | GeneratorBase( size_t size ) : m_size( size ) {} | |
3184 | virtual ~GeneratorBase(); | |
3185 | auto size() const -> size_t { return m_size; } | |
3186 | }; | |
3187 | using GeneratorBasePtr = std::unique_ptr<GeneratorBase>; | |
3188 | ||
3189 | } // namespace Generators | |
3190 | ||
3191 | struct IGeneratorTracker { | |
3192 | virtual ~IGeneratorTracker(); | |
3193 | virtual auto hasGenerator() const -> bool = 0; | |
3194 | virtual auto getGenerator() const -> Generators::GeneratorBasePtr const& = 0; | |
3195 | virtual void setGenerator( Generators::GeneratorBasePtr&& generator ) = 0; | |
3196 | virtual auto getIndex() const -> std::size_t = 0; | |
3197 | }; | |
3198 | ||
3199 | } // namespace Catch | |
3200 | ||
3201 | // end catch_interfaces_generatortracker.h | |
3202 | // start catch_enforce.h | |
3203 | ||
3204 | #include <stdexcept> | |
3205 | ||
3206 | namespace Catch { | |
3207 | #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) | |
3208 | template <typename Ex> | |
3209 | [[noreturn]] | |
3210 | void throw_exception(Ex const& e) { | |
3211 | throw e; | |
3212 | } | |
3213 | #else // ^^ Exceptions are enabled // Exceptions are disabled vv | |
3214 | [[noreturn]] | |
3215 | void throw_exception(std::exception const& e); | |
3216 | #endif | |
3217 | } // namespace Catch; | |
3218 | ||
3219 | #define CATCH_PREPARE_EXCEPTION( type, msg ) \ | |
3220 | type( ( Catch::ReusableStringStream() << msg ).str() ) | |
3221 | #define CATCH_INTERNAL_ERROR( msg ) \ | |
3222 | Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::logic_error, CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg)) | |
3223 | #define CATCH_ERROR( msg ) \ | |
3224 | Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::domain_error, msg )) | |
3225 | #define CATCH_RUNTIME_ERROR( msg ) \ | |
3226 | Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::runtime_error, msg )) | |
3227 | #define CATCH_ENFORCE( condition, msg ) \ | |
3228 | do{ if( !(condition) ) CATCH_ERROR( msg ); } while(false) | |
3229 | ||
3230 | // end catch_enforce.h | |
3231 | #include <memory> | |
3232 | #include <vector> | |
3233 | #include <cassert> | |
3234 | ||
3235 | #include <utility> | |
3236 | ||
3237 | namespace Catch { | |
3238 | namespace Generators { | |
3239 | ||
3240 | // !TBD move this into its own location? | |
3241 | namespace pf{ | |
3242 | template<typename T, typename... Args> | |
3243 | std::unique_ptr<T> make_unique( Args&&... args ) { | |
3244 | return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); | |
3245 | } | |
3246 | } | |
3247 | ||
3248 | template<typename T> | |
3249 | struct IGenerator { | |
3250 | virtual ~IGenerator() {} | |
3251 | virtual auto get( size_t index ) const -> T = 0; | |
3252 | }; | |
3253 | ||
3254 | template<typename T> | |
3255 | class SingleValueGenerator : public IGenerator<T> { | |
3256 | T m_value; | |
3257 | public: | |
3258 | SingleValueGenerator( T const& value ) : m_value( value ) {} | |
3259 | ||
3260 | auto get( size_t ) const -> T override { | |
3261 | return m_value; | |
3262 | } | |
3263 | }; | |
3264 | ||
3265 | template<typename T> | |
3266 | class FixedValuesGenerator : public IGenerator<T> { | |
3267 | std::vector<T> m_values; | |
3268 | ||
3269 | public: | |
3270 | FixedValuesGenerator( std::initializer_list<T> values ) : m_values( values ) {} | |
3271 | ||
3272 | auto get( size_t index ) const -> T override { | |
3273 | return m_values[index]; | |
3274 | } | |
3275 | }; | |
3276 | ||
3277 | template<typename T> | |
3278 | class RangeGenerator : public IGenerator<T> { | |
3279 | T const m_first; | |
3280 | T const m_last; | |
3281 | ||
3282 | public: | |
3283 | RangeGenerator( T const& first, T const& last ) : m_first( first ), m_last( last ) { | |
3284 | assert( m_last > m_first ); | |
3285 | } | |
3286 | ||
3287 | auto get( size_t index ) const -> T override { | |
3288 | // ToDo:: introduce a safe cast to catch potential overflows | |
3289 | return static_cast<T>(m_first+index); | |
3290 | } | |
3291 | }; | |
3292 | ||
3293 | template<typename T> | |
3294 | struct NullGenerator : IGenerator<T> { | |
3295 | auto get( size_t ) const -> T override { | |
3296 | CATCH_INTERNAL_ERROR("A Null Generator is always empty"); | |
3297 | } | |
3298 | }; | |
3299 | ||
3300 | template<typename T> | |
3301 | class Generator { | |
3302 | std::unique_ptr<IGenerator<T>> m_generator; | |
3303 | size_t m_size; | |
3304 | ||
3305 | public: | |
3306 | Generator( size_t size, std::unique_ptr<IGenerator<T>> generator ) | |
3307 | : m_generator( std::move( generator ) ), | |
3308 | m_size( size ) | |
3309 | {} | |
3310 | ||
3311 | auto size() const -> size_t { return m_size; } | |
3312 | auto operator[]( size_t index ) const -> T { | |
3313 | assert( index < m_size ); | |
3314 | return m_generator->get( index ); | |
3315 | } | |
3316 | }; | |
3317 | ||
3318 | std::vector<size_t> randomiseIndices( size_t selectionSize, size_t sourceSize ); | |
3319 | ||
3320 | template<typename T> | |
3321 | class GeneratorRandomiser : public IGenerator<T> { | |
3322 | Generator<T> m_baseGenerator; | |
3323 | ||
3324 | std::vector<size_t> m_indices; | |
3325 | public: | |
3326 | GeneratorRandomiser( Generator<T>&& baseGenerator, size_t numberOfItems ) | |
3327 | : m_baseGenerator( std::move( baseGenerator ) ), | |
3328 | m_indices( randomiseIndices( numberOfItems, m_baseGenerator.size() ) ) | |
3329 | {} | |
3330 | ||
3331 | auto get( size_t index ) const -> T override { | |
3332 | return m_baseGenerator[m_indices[index]]; | |
3333 | } | |
3334 | }; | |
3335 | ||
3336 | template<typename T> | |
3337 | struct RequiresASpecialisationFor; | |
3338 | ||
3339 | template<typename T> | |
3340 | auto all() -> Generator<T> { return RequiresASpecialisationFor<T>(); } | |
3341 | ||
3342 | template<> | |
3343 | auto all<int>() -> Generator<int>; | |
3344 | ||
3345 | template<typename T> | |
3346 | auto range( T const& first, T const& last ) -> Generator<T> { | |
3347 | return Generator<T>( (last-first), pf::make_unique<RangeGenerator<T>>( first, last ) ); | |
3348 | } | |
3349 | ||
3350 | template<typename T> | |
3351 | auto random( T const& first, T const& last ) -> Generator<T> { | |
3352 | auto gen = range( first, last ); | |
3353 | auto size = gen.size(); | |
3354 | ||
3355 | return Generator<T>( size, pf::make_unique<GeneratorRandomiser<T>>( std::move( gen ), size ) ); | |
3356 | } | |
3357 | template<typename T> | |
3358 | auto random( size_t size ) -> Generator<T> { | |
3359 | return Generator<T>( size, pf::make_unique<GeneratorRandomiser<T>>( all<T>(), size ) ); | |
3360 | } | |
3361 | ||
3362 | template<typename T> | |
3363 | auto values( std::initializer_list<T> values ) -> Generator<T> { | |
3364 | return Generator<T>( values.size(), pf::make_unique<FixedValuesGenerator<T>>( values ) ); | |
3365 | } | |
3366 | template<typename T> | |
3367 | auto value( T const& val ) -> Generator<T> { | |
3368 | return Generator<T>( 1, pf::make_unique<SingleValueGenerator<T>>( val ) ); | |
3369 | } | |
3370 | ||
3371 | template<typename T> | |
3372 | auto as() -> Generator<T> { | |
3373 | return Generator<T>( 0, pf::make_unique<NullGenerator<T>>() ); | |
3374 | } | |
3375 | ||
3376 | template<typename... Ts> | |
3377 | auto table( std::initializer_list<std::tuple<Ts...>>&& tuples ) -> Generator<std::tuple<Ts...>> { | |
3378 | return values<std::tuple<Ts...>>( std::forward<std::initializer_list<std::tuple<Ts...>>>( tuples ) ); | |
3379 | } | |
3380 | ||
3381 | template<typename T> | |
3382 | struct Generators : GeneratorBase { | |
3383 | std::vector<Generator<T>> m_generators; | |
3384 | ||
3385 | using type = T; | |
3386 | ||
3387 | Generators() : GeneratorBase( 0 ) {} | |
3388 | ||
3389 | void populate( T&& val ) { | |
3390 | m_size += 1; | |
3391 | m_generators.emplace_back( value( std::move( val ) ) ); | |
3392 | } | |
3393 | template<typename U> | |
3394 | void populate( U&& val ) { | |
3395 | populate( T( std::move( val ) ) ); | |
3396 | } | |
3397 | void populate( Generator<T>&& generator ) { | |
3398 | m_size += generator.size(); | |
3399 | m_generators.emplace_back( std::move( generator ) ); | |
3400 | } | |
3401 | ||
3402 | template<typename U, typename... Gs> | |
3403 | void populate( U&& valueOrGenerator, Gs... moreGenerators ) { | |
3404 | populate( std::forward<U>( valueOrGenerator ) ); | |
3405 | populate( std::forward<Gs>( moreGenerators )... ); | |
3406 | } | |
3407 | ||
3408 | auto operator[]( size_t index ) const -> T { | |
3409 | size_t sizes = 0; | |
3410 | for( auto const& gen : m_generators ) { | |
3411 | auto localIndex = index-sizes; | |
3412 | sizes += gen.size(); | |
3413 | if( index < sizes ) | |
3414 | return gen[localIndex]; | |
3415 | } | |
3416 | CATCH_INTERNAL_ERROR("Index '" << index << "' is out of range (" << sizes << ')'); | |
3417 | } | |
3418 | }; | |
3419 | ||
3420 | template<typename T, typename... Gs> | |
3421 | auto makeGenerators( Generator<T>&& generator, Gs... moreGenerators ) -> Generators<T> { | |
3422 | Generators<T> generators; | |
3423 | generators.m_generators.reserve( 1+sizeof...(Gs) ); | |
3424 | generators.populate( std::move( generator ), std::forward<Gs>( moreGenerators )... ); | |
3425 | return generators; | |
3426 | } | |
3427 | template<typename T> | |
3428 | auto makeGenerators( Generator<T>&& generator ) -> Generators<T> { | |
3429 | Generators<T> generators; | |
3430 | generators.populate( std::move( generator ) ); | |
3431 | return generators; | |
3432 | } | |
3433 | template<typename T, typename... Gs> | |
3434 | auto makeGenerators( T&& val, Gs... moreGenerators ) -> Generators<T> { | |
3435 | return makeGenerators( value( std::forward<T>( val ) ), std::forward<Gs>( moreGenerators )... ); | |
3436 | } | |
3437 | template<typename T, typename U, typename... Gs> | |
3438 | auto makeGenerators( U&& val, Gs... moreGenerators ) -> Generators<T> { | |
3439 | return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... ); | |
3440 | } | |
3441 | ||
3442 | auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker&; | |
3443 | ||
3444 | template<typename L> | |
3445 | // Note: The type after -> is weird, because VS2015 cannot parse | |
3446 | // the expression used in the typedef inside, when it is in | |
3447 | // return type. Yeah, ¯\_(ツ)_/¯ | |
3448 | auto generate( SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>()[0]) { | |
3449 | using UnderlyingType = typename decltype(generatorExpression())::type; | |
3450 | ||
3451 | IGeneratorTracker& tracker = acquireGeneratorTracker( lineInfo ); | |
3452 | if( !tracker.hasGenerator() ) | |
3453 | tracker.setGenerator( pf::make_unique<Generators<UnderlyingType>>( generatorExpression() ) ); | |
3454 | ||
3455 | auto const& generator = static_cast<Generators<UnderlyingType> const&>( *tracker.getGenerator() ); | |
3456 | return generator[tracker.getIndex()]; | |
3457 | } | |
3458 | ||
3459 | } // namespace Generators | |
3460 | } // namespace Catch | |
3461 | ||
3462 | #define GENERATE( ... ) \ | |
3463 | Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, []{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) | |
3464 | ||
3465 | // end catch_generators.hpp | |
3466 | ||
3467 | // These files are included here so the single_include script doesn't put them | |
3468 | // in the conditionally compiled sections | |
3469 | // start catch_test_case_info.h | |
3470 | ||
3471 | #include <string> | |
3472 | #include <vector> | |
3473 | #include <memory> | |
3474 | ||
3475 | #ifdef __clang__ | |
3476 | #pragma clang diagnostic push | |
3477 | #pragma clang diagnostic ignored "-Wpadded" | |
3478 | #endif | |
3479 | ||
3480 | namespace Catch { | |
3481 | ||
3482 | struct ITestInvoker; | |
3483 | ||
3484 | struct TestCaseInfo { | |
3485 | enum SpecialProperties{ | |
3486 | None = 0, | |
3487 | IsHidden = 1 << 1, | |
3488 | ShouldFail = 1 << 2, | |
3489 | MayFail = 1 << 3, | |
3490 | Throws = 1 << 4, | |
3491 | NonPortable = 1 << 5, | |
3492 | Benchmark = 1 << 6 | |
3493 | }; | |
3494 | ||
3495 | TestCaseInfo( std::string const& _name, | |
3496 | std::string const& _className, | |
3497 | std::string const& _description, | |
3498 | std::vector<std::string> const& _tags, | |
3499 | SourceLineInfo const& _lineInfo ); | |
3500 | ||
3501 | friend void setTags( TestCaseInfo& testCaseInfo, std::vector<std::string> tags ); | |
3502 | ||
3503 | bool isHidden() const; | |
3504 | bool throws() const; | |
3505 | bool okToFail() const; | |
3506 | bool expectedToFail() const; | |
3507 | ||
3508 | std::string tagsAsString() const; | |
3509 | ||
3510 | std::string name; | |
3511 | std::string className; | |
3512 | std::string description; | |
3513 | std::vector<std::string> tags; | |
3514 | std::vector<std::string> lcaseTags; | |
3515 | SourceLineInfo lineInfo; | |
3516 | SpecialProperties properties; | |
3517 | }; | |
3518 | ||
3519 | class TestCase : public TestCaseInfo { | |
3520 | public: | |
3521 | ||
3522 | TestCase( ITestInvoker* testCase, TestCaseInfo&& info ); | |
3523 | ||
3524 | TestCase withName( std::string const& _newName ) const; | |
3525 | ||
3526 | void invoke() const; | |
3527 | ||
3528 | TestCaseInfo const& getTestCaseInfo() const; | |
3529 | ||
3530 | bool operator == ( TestCase const& other ) const; | |
3531 | bool operator < ( TestCase const& other ) const; | |
3532 | ||
3533 | private: | |
3534 | std::shared_ptr<ITestInvoker> test; | |
3535 | }; | |
3536 | ||
3537 | TestCase makeTestCase( ITestInvoker* testCase, | |
3538 | std::string const& className, | |
3539 | NameAndTags const& nameAndTags, | |
3540 | SourceLineInfo const& lineInfo ); | |
3541 | } | |
3542 | ||
3543 | #ifdef __clang__ | |
3544 | #pragma clang diagnostic pop | |
3545 | #endif | |
3546 | ||
3547 | // end catch_test_case_info.h | |
3548 | // start catch_interfaces_runner.h | |
3549 | ||
3550 | namespace Catch { | |
3551 | ||
3552 | struct IRunner { | |
3553 | virtual ~IRunner(); | |
3554 | virtual bool aborting() const = 0; | |
3555 | }; | |
3556 | } | |
3557 | ||
3558 | // end catch_interfaces_runner.h | |
3559 | ||
3560 | #ifdef __OBJC__ | |
3561 | // start catch_objc.hpp | |
3562 | ||
3563 | #import <objc/runtime.h> | |
3564 | ||
3565 | #include <string> | |
3566 | ||
3567 | // NB. Any general catch headers included here must be included | |
3568 | // in catch.hpp first to make sure they are included by the single | |
3569 | // header for non obj-usage | |
3570 | ||
3571 | /////////////////////////////////////////////////////////////////////////////// | |
3572 | // This protocol is really only here for (self) documenting purposes, since | |
3573 | // all its methods are optional. | |
3574 | @protocol OcFixture | |
3575 | ||
3576 | @optional | |
3577 | ||
3578 | -(void) setUp; | |
3579 | -(void) tearDown; | |
3580 | ||
3581 | @end | |
3582 | ||
3583 | namespace Catch { | |
3584 | ||
3585 | class OcMethod : public ITestInvoker { | |
3586 | ||
3587 | public: | |
3588 | OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {} | |
3589 | ||
3590 | virtual void invoke() const { | |
3591 | id obj = [[m_cls alloc] init]; | |
3592 | ||
3593 | performOptionalSelector( obj, @selector(setUp) ); | |
3594 | performOptionalSelector( obj, m_sel ); | |
3595 | performOptionalSelector( obj, @selector(tearDown) ); | |
3596 | ||
3597 | arcSafeRelease( obj ); | |
3598 | } | |
3599 | private: | |
3600 | virtual ~OcMethod() {} | |
3601 | ||
3602 | Class m_cls; | |
3603 | SEL m_sel; | |
3604 | }; | |
3605 | ||
3606 | namespace Detail{ | |
3607 | ||
3608 | inline std::string getAnnotation( Class cls, | |
3609 | std::string const& annotationName, | |
3610 | std::string const& testCaseName ) { | |
3611 | NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()]; | |
3612 | SEL sel = NSSelectorFromString( selStr ); | |
3613 | arcSafeRelease( selStr ); | |
3614 | id value = performOptionalSelector( cls, sel ); | |
3615 | if( value ) | |
3616 | return [(NSString*)value UTF8String]; | |
3617 | return ""; | |
3618 | } | |
3619 | } | |
3620 | ||
3621 | inline std::size_t registerTestMethods() { | |
3622 | std::size_t noTestMethods = 0; | |
3623 | int noClasses = objc_getClassList( nullptr, 0 ); | |
3624 | ||
3625 | Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); | |
3626 | objc_getClassList( classes, noClasses ); | |
3627 | ||
3628 | for( int c = 0; c < noClasses; c++ ) { | |
3629 | Class cls = classes[c]; | |
3630 | { | |
3631 | u_int count; | |
3632 | Method* methods = class_copyMethodList( cls, &count ); | |
3633 | for( u_int m = 0; m < count ; m++ ) { | |
3634 | SEL selector = method_getName(methods[m]); | |
3635 | std::string methodName = sel_getName(selector); | |
3636 | if( startsWith( methodName, "Catch_TestCase_" ) ) { | |
3637 | std::string testCaseName = methodName.substr( 15 ); | |
3638 | std::string name = Detail::getAnnotation( cls, "Name", testCaseName ); | |
3639 | std::string desc = Detail::getAnnotation( cls, "Description", testCaseName ); | |
3640 | const char* className = class_getName( cls ); | |
3641 | ||
3642 | getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, NameAndTags( name.c_str(), desc.c_str() ), SourceLineInfo("",0) ) ); | |
3643 | noTestMethods++; | |
3644 | } | |
3645 | } | |
3646 | free(methods); | |
3647 | } | |
3648 | } | |
3649 | return noTestMethods; | |
3650 | } | |
3651 | ||
3652 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) | |
3653 | ||
3654 | namespace Matchers { | |
3655 | namespace Impl { | |
3656 | namespace NSStringMatchers { | |
3657 | ||
3658 | struct StringHolder : MatcherBase<NSString*>{ | |
3659 | StringHolder( NSString* substr ) : m_substr( [substr copy] ){} | |
3660 | StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){} | |
3661 | StringHolder() { | |
3662 | arcSafeRelease( m_substr ); | |
3663 | } | |
3664 | ||
3665 | bool match( NSString* arg ) const override { | |
3666 | return false; | |
3667 | } | |
3668 | ||
3669 | NSString* CATCH_ARC_STRONG m_substr; | |
3670 | }; | |
3671 | ||
3672 | struct Equals : StringHolder { | |
3673 | Equals( NSString* substr ) : StringHolder( substr ){} | |
3674 | ||
3675 | bool match( NSString* str ) const override { | |
3676 | return (str != nil || m_substr == nil ) && | |
3677 | [str isEqualToString:m_substr]; | |
3678 | } | |
3679 | ||
3680 | std::string describe() const override { | |
3681 | return "equals string: " + Catch::Detail::stringify( m_substr ); | |
3682 | } | |
3683 | }; | |
3684 | ||
3685 | struct Contains : StringHolder { | |
3686 | Contains( NSString* substr ) : StringHolder( substr ){} | |
3687 | ||
3688 | bool match( NSString* str ) const { | |
3689 | return (str != nil || m_substr == nil ) && | |
3690 | [str rangeOfString:m_substr].location != NSNotFound; | |
3691 | } | |
3692 | ||
3693 | std::string describe() const override { | |
3694 | return "contains string: " + Catch::Detail::stringify( m_substr ); | |
3695 | } | |
3696 | }; | |
3697 | ||
3698 | struct StartsWith : StringHolder { | |
3699 | StartsWith( NSString* substr ) : StringHolder( substr ){} | |
3700 | ||
3701 | bool match( NSString* str ) const override { | |
3702 | return (str != nil || m_substr == nil ) && | |
3703 | [str rangeOfString:m_substr].location == 0; | |
3704 | } | |
3705 | ||
3706 | std::string describe() const override { | |
3707 | return "starts with: " + Catch::Detail::stringify( m_substr ); | |
3708 | } | |
3709 | }; | |
3710 | struct EndsWith : StringHolder { | |
3711 | EndsWith( NSString* substr ) : StringHolder( substr ){} | |
3712 | ||
3713 | bool match( NSString* str ) const override { | |
3714 | return (str != nil || m_substr == nil ) && | |
3715 | [str rangeOfString:m_substr].location == [str length] - [m_substr length]; | |
3716 | } | |
3717 | ||
3718 | std::string describe() const override { | |
3719 | return "ends with: " + Catch::Detail::stringify( m_substr ); | |
3720 | } | |
3721 | }; | |
3722 | ||
3723 | } // namespace NSStringMatchers | |
3724 | } // namespace Impl | |
3725 | ||
3726 | inline Impl::NSStringMatchers::Equals | |
3727 | Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); } | |
3728 | ||
3729 | inline Impl::NSStringMatchers::Contains | |
3730 | Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); } | |
3731 | ||
3732 | inline Impl::NSStringMatchers::StartsWith | |
3733 | StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); } | |
3734 | ||
3735 | inline Impl::NSStringMatchers::EndsWith | |
3736 | EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); } | |
3737 | ||
3738 | } // namespace Matchers | |
3739 | ||
3740 | using namespace Matchers; | |
3741 | ||
3742 | #endif // CATCH_CONFIG_DISABLE_MATCHERS | |
3743 | ||
3744 | } // namespace Catch | |
3745 | ||
3746 | /////////////////////////////////////////////////////////////////////////////// | |
3747 | #define OC_MAKE_UNIQUE_NAME( root, uniqueSuffix ) root##uniqueSuffix | |
3748 | #define OC_TEST_CASE2( name, desc, uniqueSuffix ) \ | |
3749 | +(NSString*) OC_MAKE_UNIQUE_NAME( Catch_Name_test_, uniqueSuffix ) \ | |
3750 | { \ | |
3751 | return @ name; \ | |
3752 | } \ | |
3753 | +(NSString*) OC_MAKE_UNIQUE_NAME( Catch_Description_test_, uniqueSuffix ) \ | |
3754 | { \ | |
3755 | return @ desc; \ | |
3756 | } \ | |
3757 | -(void) OC_MAKE_UNIQUE_NAME( Catch_TestCase_test_, uniqueSuffix ) | |
3758 | ||
3759 | #define OC_TEST_CASE( name, desc ) OC_TEST_CASE2( name, desc, __LINE__ ) | |
3760 | ||
3761 | // end catch_objc.hpp | |
3762 | #endif | |
3763 | ||
3764 | #ifdef CATCH_CONFIG_EXTERNAL_INTERFACES | |
3765 | // start catch_external_interfaces.h | |
3766 | ||
3767 | // start catch_reporter_bases.hpp | |
3768 | ||
3769 | // start catch_interfaces_reporter.h | |
3770 | ||
3771 | // start catch_config.hpp | |
3772 | ||
3773 | // start catch_test_spec_parser.h | |
3774 | ||
3775 | #ifdef __clang__ | |
3776 | #pragma clang diagnostic push | |
3777 | #pragma clang diagnostic ignored "-Wpadded" | |
3778 | #endif | |
3779 | ||
3780 | // start catch_test_spec.h | |
3781 | ||
3782 | #ifdef __clang__ | |
3783 | #pragma clang diagnostic push | |
3784 | #pragma clang diagnostic ignored "-Wpadded" | |
3785 | #endif | |
3786 | ||
3787 | // start catch_wildcard_pattern.h | |
3788 | ||
3789 | namespace Catch | |
3790 | { | |
3791 | class WildcardPattern { | |
3792 | enum WildcardPosition { | |
3793 | NoWildcard = 0, | |
3794 | WildcardAtStart = 1, | |
3795 | WildcardAtEnd = 2, | |
3796 | WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd | |
3797 | }; | |
3798 | ||
3799 | public: | |
3800 | ||
3801 | WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity ); | |
3802 | virtual ~WildcardPattern() = default; | |
3803 | virtual bool matches( std::string const& str ) const; | |
3804 | ||
3805 | private: | |
3806 | std::string adjustCase( std::string const& str ) const; | |
3807 | CaseSensitive::Choice m_caseSensitivity; | |
3808 | WildcardPosition m_wildcard = NoWildcard; | |
3809 | std::string m_pattern; | |
3810 | }; | |
3811 | } | |
3812 | ||
3813 | // end catch_wildcard_pattern.h | |
3814 | #include <string> | |
3815 | #include <vector> | |
3816 | #include <memory> | |
3817 | ||
3818 | namespace Catch { | |
3819 | ||
3820 | class TestSpec { | |
3821 | struct Pattern { | |
3822 | virtual ~Pattern(); | |
3823 | virtual bool matches( TestCaseInfo const& testCase ) const = 0; | |
3824 | }; | |
3825 | using PatternPtr = std::shared_ptr<Pattern>; | |
3826 | ||
3827 | class NamePattern : public Pattern { | |
3828 | public: | |
3829 | NamePattern( std::string const& name ); | |
3830 | virtual ~NamePattern(); | |
3831 | virtual bool matches( TestCaseInfo const& testCase ) const override; | |
3832 | private: | |
3833 | WildcardPattern m_wildcardPattern; | |
3834 | }; | |
3835 | ||
3836 | class TagPattern : public Pattern { | |
3837 | public: | |
3838 | TagPattern( std::string const& tag ); | |
3839 | virtual ~TagPattern(); | |
3840 | virtual bool matches( TestCaseInfo const& testCase ) const override; | |
3841 | private: | |
3842 | std::string m_tag; | |
3843 | }; | |
3844 | ||
3845 | class ExcludedPattern : public Pattern { | |
3846 | public: | |
3847 | ExcludedPattern( PatternPtr const& underlyingPattern ); | |
3848 | virtual ~ExcludedPattern(); | |
3849 | virtual bool matches( TestCaseInfo const& testCase ) const override; | |
3850 | private: | |
3851 | PatternPtr m_underlyingPattern; | |
3852 | }; | |
3853 | ||
3854 | struct Filter { | |
3855 | std::vector<PatternPtr> m_patterns; | |
3856 | ||
3857 | bool matches( TestCaseInfo const& testCase ) const; | |
3858 | }; | |
3859 | ||
3860 | public: | |
3861 | bool hasFilters() const; | |
3862 | bool matches( TestCaseInfo const& testCase ) const; | |
3863 | ||
3864 | private: | |
3865 | std::vector<Filter> m_filters; | |
3866 | ||
3867 | friend class TestSpecParser; | |
3868 | }; | |
3869 | } | |
3870 | ||
3871 | #ifdef __clang__ | |
3872 | #pragma clang diagnostic pop | |
3873 | #endif | |
3874 | ||
3875 | // end catch_test_spec.h | |
3876 | // start catch_interfaces_tag_alias_registry.h | |
3877 | ||
3878 | #include <string> | |
3879 | ||
3880 | namespace Catch { | |
3881 | ||
3882 | struct TagAlias; | |
3883 | ||
3884 | struct ITagAliasRegistry { | |
3885 | virtual ~ITagAliasRegistry(); | |
3886 | // Nullptr if not present | |
3887 | virtual TagAlias const* find( std::string const& alias ) const = 0; | |
3888 | virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0; | |
3889 | ||
3890 | static ITagAliasRegistry const& get(); | |
3891 | }; | |
3892 | ||
3893 | } // end namespace Catch | |
3894 | ||
3895 | // end catch_interfaces_tag_alias_registry.h | |
3896 | namespace Catch { | |
3897 | ||
3898 | class TestSpecParser { | |
3899 | enum Mode{ None, Name, QuotedName, Tag, EscapedName }; | |
3900 | Mode m_mode = None; | |
3901 | bool m_exclusion = false; | |
3902 | std::size_t m_start = std::string::npos, m_pos = 0; | |
3903 | std::string m_arg; | |
3904 | std::vector<std::size_t> m_escapeChars; | |
3905 | TestSpec::Filter m_currentFilter; | |
3906 | TestSpec m_testSpec; | |
3907 | ITagAliasRegistry const* m_tagAliases = nullptr; | |
3908 | ||
3909 | public: | |
3910 | TestSpecParser( ITagAliasRegistry const& tagAliases ); | |
3911 | ||
3912 | TestSpecParser& parse( std::string const& arg ); | |
3913 | TestSpec testSpec(); | |
3914 | ||
3915 | private: | |
3916 | void visitChar( char c ); | |
3917 | void startNewMode( Mode mode, std::size_t start ); | |
3918 | void escape(); | |
3919 | std::string subString() const; | |
3920 | ||
3921 | template<typename T> | |
3922 | void addPattern() { | |
3923 | std::string token = subString(); | |
3924 | for( std::size_t i = 0; i < m_escapeChars.size(); ++i ) | |
3925 | token = token.substr( 0, m_escapeChars[i]-m_start-i ) + token.substr( m_escapeChars[i]-m_start-i+1 ); | |
3926 | m_escapeChars.clear(); | |
3927 | if( startsWith( token, "exclude:" ) ) { | |
3928 | m_exclusion = true; | |
3929 | token = token.substr( 8 ); | |
3930 | } | |
3931 | if( !token.empty() ) { | |
3932 | TestSpec::PatternPtr pattern = std::make_shared<T>( token ); | |
3933 | if( m_exclusion ) | |
3934 | pattern = std::make_shared<TestSpec::ExcludedPattern>( pattern ); | |
3935 | m_currentFilter.m_patterns.push_back( pattern ); | |
3936 | } | |
3937 | m_exclusion = false; | |
3938 | m_mode = None; | |
3939 | } | |
3940 | ||
3941 | void addFilter(); | |
3942 | }; | |
3943 | TestSpec parseTestSpec( std::string const& arg ); | |
3944 | ||
3945 | } // namespace Catch | |
3946 | ||
3947 | #ifdef __clang__ | |
3948 | #pragma clang diagnostic pop | |
3949 | #endif | |
3950 | ||
3951 | // end catch_test_spec_parser.h | |
3952 | // start catch_interfaces_config.h | |
3953 | ||
3954 | #include <iosfwd> | |
3955 | #include <string> | |
3956 | #include <vector> | |
3957 | #include <memory> | |
3958 | ||
3959 | namespace Catch { | |
3960 | ||
3961 | enum class Verbosity { | |
3962 | Quiet = 0, | |
3963 | Normal, | |
3964 | High | |
3965 | }; | |
3966 | ||
3967 | struct WarnAbout { enum What { | |
3968 | Nothing = 0x00, | |
3969 | NoAssertions = 0x01, | |
3970 | NoTests = 0x02 | |
3971 | }; }; | |
3972 | ||
3973 | struct ShowDurations { enum OrNot { | |
3974 | DefaultForReporter, | |
3975 | Always, | |
3976 | Never | |
3977 | }; }; | |
3978 | struct RunTests { enum InWhatOrder { | |
3979 | InDeclarationOrder, | |
3980 | InLexicographicalOrder, | |
3981 | InRandomOrder | |
3982 | }; }; | |
3983 | struct UseColour { enum YesOrNo { | |
3984 | Auto, | |
3985 | Yes, | |
3986 | No | |
3987 | }; }; | |
3988 | struct WaitForKeypress { enum When { | |
3989 | Never, | |
3990 | BeforeStart = 1, | |
3991 | BeforeExit = 2, | |
3992 | BeforeStartAndExit = BeforeStart | BeforeExit | |
3993 | }; }; | |
3994 | ||
3995 | class TestSpec; | |
3996 | ||
3997 | struct IConfig : NonCopyable { | |
3998 | ||
3999 | virtual ~IConfig(); | |
4000 | ||
4001 | virtual bool allowThrows() const = 0; | |
4002 | virtual std::ostream& stream() const = 0; | |
4003 | virtual std::string name() const = 0; | |
4004 | virtual bool includeSuccessfulResults() const = 0; | |
4005 | virtual bool shouldDebugBreak() const = 0; | |
4006 | virtual bool warnAboutMissingAssertions() const = 0; | |
4007 | virtual bool warnAboutNoTests() const = 0; | |
4008 | virtual int abortAfter() const = 0; | |
4009 | virtual bool showInvisibles() const = 0; | |
4010 | virtual ShowDurations::OrNot showDurations() const = 0; | |
4011 | virtual TestSpec const& testSpec() const = 0; | |
4012 | virtual bool hasTestFilters() const = 0; | |
4013 | virtual RunTests::InWhatOrder runOrder() const = 0; | |
4014 | virtual unsigned int rngSeed() const = 0; | |
4015 | virtual int benchmarkResolutionMultiple() const = 0; | |
4016 | virtual UseColour::YesOrNo useColour() const = 0; | |
4017 | virtual std::vector<std::string> const& getSectionsToRun() const = 0; | |
4018 | virtual Verbosity verbosity() const = 0; | |
4019 | }; | |
4020 | ||
4021 | using IConfigPtr = std::shared_ptr<IConfig const>; | |
4022 | } | |
4023 | ||
4024 | // end catch_interfaces_config.h | |
4025 | // Libstdc++ doesn't like incomplete classes for unique_ptr | |
4026 | ||
4027 | #include <memory> | |
4028 | #include <vector> | |
4029 | #include <string> | |
4030 | ||
4031 | #ifndef CATCH_CONFIG_CONSOLE_WIDTH | |
4032 | #define CATCH_CONFIG_CONSOLE_WIDTH 80 | |
4033 | #endif | |
4034 | ||
4035 | namespace Catch { | |
4036 | ||
4037 | struct IStream; | |
4038 | ||
4039 | struct ConfigData { | |
4040 | bool listTests = false; | |
4041 | bool listTags = false; | |
4042 | bool listReporters = false; | |
4043 | bool listTestNamesOnly = false; | |
4044 | ||
4045 | bool showSuccessfulTests = false; | |
4046 | bool shouldDebugBreak = false; | |
4047 | bool noThrow = false; | |
4048 | bool showHelp = false; | |
4049 | bool showInvisibles = false; | |
4050 | bool filenamesAsTags = false; | |
4051 | bool libIdentify = false; | |
4052 | ||
4053 | int abortAfter = -1; | |
4054 | unsigned int rngSeed = 0; | |
4055 | int benchmarkResolutionMultiple = 100; | |
4056 | ||
4057 | Verbosity verbosity = Verbosity::Normal; | |
4058 | WarnAbout::What warnings = WarnAbout::Nothing; | |
4059 | ShowDurations::OrNot showDurations = ShowDurations::DefaultForReporter; | |
4060 | RunTests::InWhatOrder runOrder = RunTests::InDeclarationOrder; | |
4061 | UseColour::YesOrNo useColour = UseColour::Auto; | |
4062 | WaitForKeypress::When waitForKeypress = WaitForKeypress::Never; | |
4063 | ||
4064 | std::string outputFilename; | |
4065 | std::string name; | |
4066 | std::string processName; | |
4067 | #ifndef CATCH_CONFIG_DEFAULT_REPORTER | |
4068 | #define CATCH_CONFIG_DEFAULT_REPORTER "console" | |
4069 | #endif | |
4070 | std::string reporterName = CATCH_CONFIG_DEFAULT_REPORTER; | |
4071 | #undef CATCH_CONFIG_DEFAULT_REPORTER | |
4072 | ||
4073 | std::vector<std::string> testsOrTags; | |
4074 | std::vector<std::string> sectionsToRun; | |
4075 | }; | |
4076 | ||
4077 | class Config : public IConfig { | |
4078 | public: | |
4079 | ||
4080 | Config() = default; | |
4081 | Config( ConfigData const& data ); | |
4082 | virtual ~Config() = default; | |
4083 | ||
4084 | std::string const& getFilename() const; | |
4085 | ||
4086 | bool listTests() const; | |
4087 | bool listTestNamesOnly() const; | |
4088 | bool listTags() const; | |
4089 | bool listReporters() const; | |
4090 | ||
4091 | std::string getProcessName() const; | |
4092 | std::string const& getReporterName() const; | |
4093 | ||
4094 | std::vector<std::string> const& getTestsOrTags() const; | |
4095 | std::vector<std::string> const& getSectionsToRun() const override; | |
4096 | ||
4097 | virtual TestSpec const& testSpec() const override; | |
4098 | bool hasTestFilters() const override; | |
4099 | ||
4100 | bool showHelp() const; | |
4101 | ||
4102 | // IConfig interface | |
4103 | bool allowThrows() const override; | |
4104 | std::ostream& stream() const override; | |
4105 | std::string name() const override; | |
4106 | bool includeSuccessfulResults() const override; | |
4107 | bool warnAboutMissingAssertions() const override; | |
4108 | bool warnAboutNoTests() const override; | |
4109 | ShowDurations::OrNot showDurations() const override; | |
4110 | RunTests::InWhatOrder runOrder() const override; | |
4111 | unsigned int rngSeed() const override; | |
4112 | int benchmarkResolutionMultiple() const override; | |
4113 | UseColour::YesOrNo useColour() const override; | |
4114 | bool shouldDebugBreak() const override; | |
4115 | int abortAfter() const override; | |
4116 | bool showInvisibles() const override; | |
4117 | Verbosity verbosity() const override; | |
4118 | ||
4119 | private: | |
4120 | ||
4121 | IStream const* openStream(); | |
4122 | ConfigData m_data; | |
4123 | ||
4124 | std::unique_ptr<IStream const> m_stream; | |
4125 | TestSpec m_testSpec; | |
4126 | bool m_hasTestFilters = false; | |
4127 | }; | |
4128 | ||
4129 | } // end namespace Catch | |
4130 | ||
4131 | // end catch_config.hpp | |
4132 | // start catch_assertionresult.h | |
4133 | ||
4134 | #include <string> | |
4135 | ||
4136 | namespace Catch { | |
4137 | ||
4138 | struct AssertionResultData | |
4139 | { | |
4140 | AssertionResultData() = delete; | |
4141 | ||
4142 | AssertionResultData( ResultWas::OfType _resultType, LazyExpression const& _lazyExpression ); | |
4143 | ||
4144 | std::string message; | |
4145 | mutable std::string reconstructedExpression; | |
4146 | LazyExpression lazyExpression; | |
4147 | ResultWas::OfType resultType; | |
4148 | ||
4149 | std::string reconstructExpression() const; | |
4150 | }; | |
4151 | ||
4152 | class AssertionResult { | |
4153 | public: | |
4154 | AssertionResult() = delete; | |
4155 | AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); | |
4156 | ||
4157 | bool isOk() const; | |
4158 | bool succeeded() const; | |
4159 | ResultWas::OfType getResultType() const; | |
4160 | bool hasExpression() const; | |
4161 | bool hasMessage() const; | |
4162 | std::string getExpression() const; | |
4163 | std::string getExpressionInMacro() const; | |
4164 | bool hasExpandedExpression() const; | |
4165 | std::string getExpandedExpression() const; | |
4166 | std::string getMessage() const; | |
4167 | SourceLineInfo getSourceInfo() const; | |
4168 | StringRef getTestMacroName() const; | |
4169 | ||
4170 | //protected: | |
4171 | AssertionInfo m_info; | |
4172 | AssertionResultData m_resultData; | |
4173 | }; | |
4174 | ||
4175 | } // end namespace Catch | |
4176 | ||
4177 | // end catch_assertionresult.h | |
4178 | // start catch_option.hpp | |
4179 | ||
4180 | namespace Catch { | |
4181 | ||
4182 | // An optional type | |
4183 | template<typename T> | |
4184 | class Option { | |
4185 | public: | |
4186 | Option() : nullableValue( nullptr ) {} | |
4187 | Option( T const& _value ) | |
4188 | : nullableValue( new( storage ) T( _value ) ) | |
4189 | {} | |
4190 | Option( Option const& _other ) | |
4191 | : nullableValue( _other ? new( storage ) T( *_other ) : nullptr ) | |
4192 | {} | |
4193 | ||
4194 | ~Option() { | |
4195 | reset(); | |
4196 | } | |
4197 | ||
4198 | Option& operator= ( Option const& _other ) { | |
4199 | if( &_other != this ) { | |
4200 | reset(); | |
4201 | if( _other ) | |
4202 | nullableValue = new( storage ) T( *_other ); | |
4203 | } | |
4204 | return *this; | |
4205 | } | |
4206 | Option& operator = ( T const& _value ) { | |
4207 | reset(); | |
4208 | nullableValue = new( storage ) T( _value ); | |
4209 | return *this; | |
4210 | } | |
4211 | ||
4212 | void reset() { | |
4213 | if( nullableValue ) | |
4214 | nullableValue->~T(); | |
4215 | nullableValue = nullptr; | |
4216 | } | |
4217 | ||
4218 | T& operator*() { return *nullableValue; } | |
4219 | T const& operator*() const { return *nullableValue; } | |
4220 | T* operator->() { return nullableValue; } | |
4221 | const T* operator->() const { return nullableValue; } | |
4222 | ||
4223 | T valueOr( T const& defaultValue ) const { | |
4224 | return nullableValue ? *nullableValue : defaultValue; | |
4225 | } | |
4226 | ||
4227 | bool some() const { return nullableValue != nullptr; } | |
4228 | bool none() const { return nullableValue == nullptr; } | |
4229 | ||
4230 | bool operator !() const { return nullableValue == nullptr; } | |
4231 | explicit operator bool() const { | |
4232 | return some(); | |
4233 | } | |
4234 | ||
4235 | private: | |
4236 | T *nullableValue; | |
4237 | alignas(alignof(T)) char storage[sizeof(T)]; | |
4238 | }; | |
4239 | ||
4240 | } // end namespace Catch | |
4241 | ||
4242 | // end catch_option.hpp | |
4243 | #include <string> | |
4244 | #include <iosfwd> | |
4245 | #include <map> | |
4246 | #include <set> | |
4247 | #include <memory> | |
4248 | ||
4249 | namespace Catch { | |
4250 | ||
4251 | struct ReporterConfig { | |
4252 | explicit ReporterConfig( IConfigPtr const& _fullConfig ); | |
4253 | ||
4254 | ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream ); | |
4255 | ||
4256 | std::ostream& stream() const; | |
4257 | IConfigPtr fullConfig() const; | |
4258 | ||
4259 | private: | |
4260 | std::ostream* m_stream; | |
4261 | IConfigPtr m_fullConfig; | |
4262 | }; | |
4263 | ||
4264 | struct ReporterPreferences { | |
4265 | bool shouldRedirectStdOut = false; | |
4266 | bool shouldReportAllAssertions = false; | |
4267 | }; | |
4268 | ||
4269 | template<typename T> | |
4270 | struct LazyStat : Option<T> { | |
4271 | LazyStat& operator=( T const& _value ) { | |
4272 | Option<T>::operator=( _value ); | |
4273 | used = false; | |
4274 | return *this; | |
4275 | } | |
4276 | void reset() { | |
4277 | Option<T>::reset(); | |
4278 | used = false; | |
4279 | } | |
4280 | bool used = false; | |
4281 | }; | |
4282 | ||
4283 | struct TestRunInfo { | |
4284 | TestRunInfo( std::string const& _name ); | |
4285 | std::string name; | |
4286 | }; | |
4287 | struct GroupInfo { | |
4288 | GroupInfo( std::string const& _name, | |
4289 | std::size_t _groupIndex, | |
4290 | std::size_t _groupsCount ); | |
4291 | ||
4292 | std::string name; | |
4293 | std::size_t groupIndex; | |
4294 | std::size_t groupsCounts; | |
4295 | }; | |
4296 | ||
4297 | struct AssertionStats { | |
4298 | AssertionStats( AssertionResult const& _assertionResult, | |
4299 | std::vector<MessageInfo> const& _infoMessages, | |
4300 | Totals const& _totals ); | |
4301 | ||
4302 | AssertionStats( AssertionStats const& ) = default; | |
4303 | AssertionStats( AssertionStats && ) = default; | |
4304 | AssertionStats& operator = ( AssertionStats const& ) = default; | |
4305 | AssertionStats& operator = ( AssertionStats && ) = default; | |
4306 | virtual ~AssertionStats(); | |
4307 | ||
4308 | AssertionResult assertionResult; | |
4309 | std::vector<MessageInfo> infoMessages; | |
4310 | Totals totals; | |
4311 | }; | |
4312 | ||
4313 | struct SectionStats { | |
4314 | SectionStats( SectionInfo const& _sectionInfo, | |
4315 | Counts const& _assertions, | |
4316 | double _durationInSeconds, | |
4317 | bool _missingAssertions ); | |
4318 | SectionStats( SectionStats const& ) = default; | |
4319 | SectionStats( SectionStats && ) = default; | |
4320 | SectionStats& operator = ( SectionStats const& ) = default; | |
4321 | SectionStats& operator = ( SectionStats && ) = default; | |
4322 | virtual ~SectionStats(); | |
4323 | ||
4324 | SectionInfo sectionInfo; | |
4325 | Counts assertions; | |
4326 | double durationInSeconds; | |
4327 | bool missingAssertions; | |
4328 | }; | |
4329 | ||
4330 | struct TestCaseStats { | |
4331 | TestCaseStats( TestCaseInfo const& _testInfo, | |
4332 | Totals const& _totals, | |
4333 | std::string const& _stdOut, | |
4334 | std::string const& _stdErr, | |
4335 | bool _aborting ); | |
4336 | ||
4337 | TestCaseStats( TestCaseStats const& ) = default; | |
4338 | TestCaseStats( TestCaseStats && ) = default; | |
4339 | TestCaseStats& operator = ( TestCaseStats const& ) = default; | |
4340 | TestCaseStats& operator = ( TestCaseStats && ) = default; | |
4341 | virtual ~TestCaseStats(); | |
4342 | ||
4343 | TestCaseInfo testInfo; | |
4344 | Totals totals; | |
4345 | std::string stdOut; | |
4346 | std::string stdErr; | |
4347 | bool aborting; | |
4348 | }; | |
4349 | ||
4350 | struct TestGroupStats { | |
4351 | TestGroupStats( GroupInfo const& _groupInfo, | |
4352 | Totals const& _totals, | |
4353 | bool _aborting ); | |
4354 | TestGroupStats( GroupInfo const& _groupInfo ); | |
4355 | ||
4356 | TestGroupStats( TestGroupStats const& ) = default; | |
4357 | TestGroupStats( TestGroupStats && ) = default; | |
4358 | TestGroupStats& operator = ( TestGroupStats const& ) = default; | |
4359 | TestGroupStats& operator = ( TestGroupStats && ) = default; | |
4360 | virtual ~TestGroupStats(); | |
4361 | ||
4362 | GroupInfo groupInfo; | |
4363 | Totals totals; | |
4364 | bool aborting; | |
4365 | }; | |
4366 | ||
4367 | struct TestRunStats { | |
4368 | TestRunStats( TestRunInfo const& _runInfo, | |
4369 | Totals const& _totals, | |
4370 | bool _aborting ); | |
4371 | ||
4372 | TestRunStats( TestRunStats const& ) = default; | |
4373 | TestRunStats( TestRunStats && ) = default; | |
4374 | TestRunStats& operator = ( TestRunStats const& ) = default; | |
4375 | TestRunStats& operator = ( TestRunStats && ) = default; | |
4376 | virtual ~TestRunStats(); | |
4377 | ||
4378 | TestRunInfo runInfo; | |
4379 | Totals totals; | |
4380 | bool aborting; | |
4381 | }; | |
4382 | ||
4383 | struct BenchmarkInfo { | |
4384 | std::string name; | |
4385 | }; | |
4386 | struct BenchmarkStats { | |
4387 | BenchmarkInfo info; | |
4388 | std::size_t iterations; | |
4389 | uint64_t elapsedTimeInNanoseconds; | |
4390 | }; | |
4391 | ||
4392 | struct IStreamingReporter { | |
4393 | virtual ~IStreamingReporter() = default; | |
4394 | ||
4395 | // Implementing class must also provide the following static methods: | |
4396 | // static std::string getDescription(); | |
4397 | // static std::set<Verbosity> getSupportedVerbosities() | |
4398 | ||
4399 | virtual ReporterPreferences getPreferences() const = 0; | |
4400 | ||
4401 | virtual void noMatchingTestCases( std::string const& spec ) = 0; | |
4402 | ||
4403 | virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; | |
4404 | virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0; | |
4405 | ||
4406 | virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; | |
4407 | virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; | |
4408 | ||
4409 | // *** experimental *** | |
4410 | virtual void benchmarkStarting( BenchmarkInfo const& ) {} | |
4411 | ||
4412 | virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; | |
4413 | ||
4414 | // The return value indicates if the messages buffer should be cleared: | |
4415 | virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; | |
4416 | ||
4417 | // *** experimental *** | |
4418 | virtual void benchmarkEnded( BenchmarkStats const& ) {} | |
4419 | ||
4420 | virtual void sectionEnded( SectionStats const& sectionStats ) = 0; | |
4421 | virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; | |
4422 | virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; | |
4423 | virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; | |
4424 | ||
4425 | virtual void skipTest( TestCaseInfo const& testInfo ) = 0; | |
4426 | ||
4427 | // Default empty implementation provided | |
4428 | virtual void fatalErrorEncountered( StringRef name ); | |
4429 | ||
4430 | virtual bool isMulti() const; | |
4431 | }; | |
4432 | using IStreamingReporterPtr = std::unique_ptr<IStreamingReporter>; | |
4433 | ||
4434 | struct IReporterFactory { | |
4435 | virtual ~IReporterFactory(); | |
4436 | virtual IStreamingReporterPtr create( ReporterConfig const& config ) const = 0; | |
4437 | virtual std::string getDescription() const = 0; | |
4438 | }; | |
4439 | using IReporterFactoryPtr = std::shared_ptr<IReporterFactory>; | |
4440 | ||
4441 | struct IReporterRegistry { | |
4442 | using FactoryMap = std::map<std::string, IReporterFactoryPtr>; | |
4443 | using Listeners = std::vector<IReporterFactoryPtr>; | |
4444 | ||
4445 | virtual ~IReporterRegistry(); | |
4446 | virtual IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const = 0; | |
4447 | virtual FactoryMap const& getFactories() const = 0; | |
4448 | virtual Listeners const& getListeners() const = 0; | |
4449 | }; | |
4450 | ||
4451 | } // end namespace Catch | |
4452 | ||
4453 | // end catch_interfaces_reporter.h | |
4454 | #include <algorithm> | |
4455 | #include <cstring> | |
4456 | #include <cfloat> | |
4457 | #include <cstdio> | |
4458 | #include <cassert> | |
4459 | #include <memory> | |
4460 | #include <ostream> | |
4461 | ||
4462 | namespace Catch { | |
4463 | void prepareExpandedExpression(AssertionResult& result); | |
4464 | ||
4465 | // Returns double formatted as %.3f (format expected on output) | |
4466 | std::string getFormattedDuration( double duration ); | |
4467 | ||
4468 | template<typename DerivedT> | |
4469 | struct StreamingReporterBase : IStreamingReporter { | |
4470 | ||
4471 | StreamingReporterBase( ReporterConfig const& _config ) | |
4472 | : m_config( _config.fullConfig() ), | |
4473 | stream( _config.stream() ) | |
4474 | { | |
4475 | m_reporterPrefs.shouldRedirectStdOut = false; | |
4476 | if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) ) | |
4477 | CATCH_ERROR( "Verbosity level not supported by this reporter" ); | |
4478 | } | |
4479 | ||
4480 | ReporterPreferences getPreferences() const override { | |
4481 | return m_reporterPrefs; | |
4482 | } | |
4483 | ||
4484 | static std::set<Verbosity> getSupportedVerbosities() { | |
4485 | return { Verbosity::Normal }; | |
4486 | } | |
4487 | ||
4488 | ~StreamingReporterBase() override = default; | |
4489 | ||
4490 | void noMatchingTestCases(std::string const&) override {} | |
4491 | ||
4492 | void testRunStarting(TestRunInfo const& _testRunInfo) override { | |
4493 | currentTestRunInfo = _testRunInfo; | |
4494 | } | |
4495 | void testGroupStarting(GroupInfo const& _groupInfo) override { | |
4496 | currentGroupInfo = _groupInfo; | |
4497 | } | |
4498 | ||
4499 | void testCaseStarting(TestCaseInfo const& _testInfo) override { | |
4500 | currentTestCaseInfo = _testInfo; | |
4501 | } | |
4502 | void sectionStarting(SectionInfo const& _sectionInfo) override { | |
4503 | m_sectionStack.push_back(_sectionInfo); | |
4504 | } | |
4505 | ||
4506 | void sectionEnded(SectionStats const& /* _sectionStats */) override { | |
4507 | m_sectionStack.pop_back(); | |
4508 | } | |
4509 | void testCaseEnded(TestCaseStats const& /* _testCaseStats */) override { | |
4510 | currentTestCaseInfo.reset(); | |
4511 | } | |
4512 | void testGroupEnded(TestGroupStats const& /* _testGroupStats */) override { | |
4513 | currentGroupInfo.reset(); | |
4514 | } | |
4515 | void testRunEnded(TestRunStats const& /* _testRunStats */) override { | |
4516 | currentTestCaseInfo.reset(); | |
4517 | currentGroupInfo.reset(); | |
4518 | currentTestRunInfo.reset(); | |
4519 | } | |
4520 | ||
4521 | void skipTest(TestCaseInfo const&) override { | |
4522 | // Don't do anything with this by default. | |
4523 | // It can optionally be overridden in the derived class. | |
4524 | } | |
4525 | ||
4526 | IConfigPtr m_config; | |
4527 | std::ostream& stream; | |
4528 | ||
4529 | LazyStat<TestRunInfo> currentTestRunInfo; | |
4530 | LazyStat<GroupInfo> currentGroupInfo; | |
4531 | LazyStat<TestCaseInfo> currentTestCaseInfo; | |
4532 | ||
4533 | std::vector<SectionInfo> m_sectionStack; | |
4534 | ReporterPreferences m_reporterPrefs; | |
4535 | }; | |
4536 | ||
4537 | template<typename DerivedT> | |
4538 | struct CumulativeReporterBase : IStreamingReporter { | |
4539 | template<typename T, typename ChildNodeT> | |
4540 | struct Node { | |
4541 | explicit Node( T const& _value ) : value( _value ) {} | |
4542 | virtual ~Node() {} | |
4543 | ||
4544 | using ChildNodes = std::vector<std::shared_ptr<ChildNodeT>>; | |
4545 | T value; | |
4546 | ChildNodes children; | |
4547 | }; | |
4548 | struct SectionNode { | |
4549 | explicit SectionNode(SectionStats const& _stats) : stats(_stats) {} | |
4550 | virtual ~SectionNode() = default; | |
4551 | ||
4552 | bool operator == (SectionNode const& other) const { | |
4553 | return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo; | |
4554 | } | |
4555 | bool operator == (std::shared_ptr<SectionNode> const& other) const { | |
4556 | return operator==(*other); | |
4557 | } | |
4558 | ||
4559 | SectionStats stats; | |
4560 | using ChildSections = std::vector<std::shared_ptr<SectionNode>>; | |
4561 | using Assertions = std::vector<AssertionStats>; | |
4562 | ChildSections childSections; | |
4563 | Assertions assertions; | |
4564 | std::string stdOut; | |
4565 | std::string stdErr; | |
4566 | }; | |
4567 | ||
4568 | struct BySectionInfo { | |
4569 | BySectionInfo( SectionInfo const& other ) : m_other( other ) {} | |
4570 | BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} | |
4571 | bool operator() (std::shared_ptr<SectionNode> const& node) const { | |
4572 | return ((node->stats.sectionInfo.name == m_other.name) && | |
4573 | (node->stats.sectionInfo.lineInfo == m_other.lineInfo)); | |
4574 | } | |
4575 | void operator=(BySectionInfo const&) = delete; | |
4576 | ||
4577 | private: | |
4578 | SectionInfo const& m_other; | |
4579 | }; | |
4580 | ||
4581 | using TestCaseNode = Node<TestCaseStats, SectionNode>; | |
4582 | using TestGroupNode = Node<TestGroupStats, TestCaseNode>; | |
4583 | using TestRunNode = Node<TestRunStats, TestGroupNode>; | |
4584 | ||
4585 | CumulativeReporterBase( ReporterConfig const& _config ) | |
4586 | : m_config( _config.fullConfig() ), | |
4587 | stream( _config.stream() ) | |
4588 | { | |
4589 | m_reporterPrefs.shouldRedirectStdOut = false; | |
4590 | if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) ) | |
4591 | CATCH_ERROR( "Verbosity level not supported by this reporter" ); | |
4592 | } | |
4593 | ~CumulativeReporterBase() override = default; | |
4594 | ||
4595 | ReporterPreferences getPreferences() const override { | |
4596 | return m_reporterPrefs; | |
4597 | } | |
4598 | ||
4599 | static std::set<Verbosity> getSupportedVerbosities() { | |
4600 | return { Verbosity::Normal }; | |
4601 | } | |
4602 | ||
4603 | void testRunStarting( TestRunInfo const& ) override {} | |
4604 | void testGroupStarting( GroupInfo const& ) override {} | |
4605 | ||
4606 | void testCaseStarting( TestCaseInfo const& ) override {} | |
4607 | ||
4608 | void sectionStarting( SectionInfo const& sectionInfo ) override { | |
4609 | SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); | |
4610 | std::shared_ptr<SectionNode> node; | |
4611 | if( m_sectionStack.empty() ) { | |
4612 | if( !m_rootSection ) | |
4613 | m_rootSection = std::make_shared<SectionNode>( incompleteStats ); | |
4614 | node = m_rootSection; | |
4615 | } | |
4616 | else { | |
4617 | SectionNode& parentNode = *m_sectionStack.back(); | |
4618 | auto it = | |
4619 | std::find_if( parentNode.childSections.begin(), | |
4620 | parentNode.childSections.end(), | |
4621 | BySectionInfo( sectionInfo ) ); | |
4622 | if( it == parentNode.childSections.end() ) { | |
4623 | node = std::make_shared<SectionNode>( incompleteStats ); | |
4624 | parentNode.childSections.push_back( node ); | |
4625 | } | |
4626 | else | |
4627 | node = *it; | |
4628 | } | |
4629 | m_sectionStack.push_back( node ); | |
4630 | m_deepestSection = std::move(node); | |
4631 | } | |
4632 | ||
4633 | void assertionStarting(AssertionInfo const&) override {} | |
4634 | ||
4635 | bool assertionEnded(AssertionStats const& assertionStats) override { | |
4636 | assert(!m_sectionStack.empty()); | |
4637 | // AssertionResult holds a pointer to a temporary DecomposedExpression, | |
4638 | // which getExpandedExpression() calls to build the expression string. | |
4639 | // Our section stack copy of the assertionResult will likely outlive the | |
4640 | // temporary, so it must be expanded or discarded now to avoid calling | |
4641 | // a destroyed object later. | |
4642 | prepareExpandedExpression(const_cast<AssertionResult&>( assertionStats.assertionResult ) ); | |
4643 | SectionNode& sectionNode = *m_sectionStack.back(); | |
4644 | sectionNode.assertions.push_back(assertionStats); | |
4645 | return true; | |
4646 | } | |
4647 | void sectionEnded(SectionStats const& sectionStats) override { | |
4648 | assert(!m_sectionStack.empty()); | |
4649 | SectionNode& node = *m_sectionStack.back(); | |
4650 | node.stats = sectionStats; | |
4651 | m_sectionStack.pop_back(); | |
4652 | } | |
4653 | void testCaseEnded(TestCaseStats const& testCaseStats) override { | |
4654 | auto node = std::make_shared<TestCaseNode>(testCaseStats); | |
4655 | assert(m_sectionStack.size() == 0); | |
4656 | node->children.push_back(m_rootSection); | |
4657 | m_testCases.push_back(node); | |
4658 | m_rootSection.reset(); | |
4659 | ||
4660 | assert(m_deepestSection); | |
4661 | m_deepestSection->stdOut = testCaseStats.stdOut; | |
4662 | m_deepestSection->stdErr = testCaseStats.stdErr; | |
4663 | } | |
4664 | void testGroupEnded(TestGroupStats const& testGroupStats) override { | |
4665 | auto node = std::make_shared<TestGroupNode>(testGroupStats); | |
4666 | node->children.swap(m_testCases); | |
4667 | m_testGroups.push_back(node); | |
4668 | } | |
4669 | void testRunEnded(TestRunStats const& testRunStats) override { | |
4670 | auto node = std::make_shared<TestRunNode>(testRunStats); | |
4671 | node->children.swap(m_testGroups); | |
4672 | m_testRuns.push_back(node); | |
4673 | testRunEndedCumulative(); | |
4674 | } | |
4675 | virtual void testRunEndedCumulative() = 0; | |
4676 | ||
4677 | void skipTest(TestCaseInfo const&) override {} | |
4678 | ||
4679 | IConfigPtr m_config; | |
4680 | std::ostream& stream; | |
4681 | std::vector<AssertionStats> m_assertions; | |
4682 | std::vector<std::vector<std::shared_ptr<SectionNode>>> m_sections; | |
4683 | std::vector<std::shared_ptr<TestCaseNode>> m_testCases; | |
4684 | std::vector<std::shared_ptr<TestGroupNode>> m_testGroups; | |
4685 | ||
4686 | std::vector<std::shared_ptr<TestRunNode>> m_testRuns; | |
4687 | ||
4688 | std::shared_ptr<SectionNode> m_rootSection; | |
4689 | std::shared_ptr<SectionNode> m_deepestSection; | |
4690 | std::vector<std::shared_ptr<SectionNode>> m_sectionStack; | |
4691 | ReporterPreferences m_reporterPrefs; | |
4692 | }; | |
4693 | ||
4694 | template<char C> | |
4695 | char const* getLineOfChars() { | |
4696 | static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; | |
4697 | if( !*line ) { | |
4698 | std::memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); | |
4699 | line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; | |
4700 | } | |
4701 | return line; | |
4702 | } | |
4703 | ||
4704 | struct TestEventListenerBase : StreamingReporterBase<TestEventListenerBase> { | |
4705 | TestEventListenerBase( ReporterConfig const& _config ); | |
4706 | ||
4707 | static std::set<Verbosity> getSupportedVerbosities(); | |
4708 | ||
4709 | void assertionStarting(AssertionInfo const&) override; | |
4710 | bool assertionEnded(AssertionStats const&) override; | |
4711 | }; | |
4712 | ||
4713 | } // end namespace Catch | |
4714 | ||
4715 | // end catch_reporter_bases.hpp | |
4716 | // start catch_console_colour.h | |
4717 | ||
4718 | namespace Catch { | |
4719 | ||
4720 | struct Colour { | |
4721 | enum Code { | |
4722 | None = 0, | |
4723 | ||
4724 | White, | |
4725 | Red, | |
4726 | Green, | |
4727 | Blue, | |
4728 | Cyan, | |
4729 | Yellow, | |
4730 | Grey, | |
4731 | ||
4732 | Bright = 0x10, | |
4733 | ||
4734 | BrightRed = Bright | Red, | |
4735 | BrightGreen = Bright | Green, | |
4736 | LightGrey = Bright | Grey, | |
4737 | BrightWhite = Bright | White, | |
4738 | BrightYellow = Bright | Yellow, | |
4739 | ||
4740 | // By intention | |
4741 | FileName = LightGrey, | |
4742 | Warning = BrightYellow, | |
4743 | ResultError = BrightRed, | |
4744 | ResultSuccess = BrightGreen, | |
4745 | ResultExpectedFailure = Warning, | |
4746 | ||
4747 | Error = BrightRed, | |
4748 | Success = Green, | |
4749 | ||
4750 | OriginalExpression = Cyan, | |
4751 | ReconstructedExpression = BrightYellow, | |
4752 | ||
4753 | SecondaryText = LightGrey, | |
4754 | Headers = White | |
4755 | }; | |
4756 | ||
4757 | // Use constructed object for RAII guard | |
4758 | Colour( Code _colourCode ); | |
4759 | Colour( Colour&& other ) noexcept; | |
4760 | Colour& operator=( Colour&& other ) noexcept; | |
4761 | ~Colour(); | |
4762 | ||
4763 | // Use static method for one-shot changes | |
4764 | static void use( Code _colourCode ); | |
4765 | ||
4766 | private: | |
4767 | bool m_moved = false; | |
4768 | }; | |
4769 | ||
4770 | std::ostream& operator << ( std::ostream& os, Colour const& ); | |
4771 | ||
4772 | } // end namespace Catch | |
4773 | ||
4774 | // end catch_console_colour.h | |
4775 | // start catch_reporter_registrars.hpp | |
4776 | ||
4777 | ||
4778 | namespace Catch { | |
4779 | ||
4780 | template<typename T> | |
4781 | class ReporterRegistrar { | |
4782 | ||
4783 | class ReporterFactory : public IReporterFactory { | |
4784 | ||
4785 | virtual IStreamingReporterPtr create( ReporterConfig const& config ) const override { | |
4786 | return std::unique_ptr<T>( new T( config ) ); | |
4787 | } | |
4788 | ||
4789 | virtual std::string getDescription() const override { | |
4790 | return T::getDescription(); | |
4791 | } | |
4792 | }; | |
4793 | ||
4794 | public: | |
4795 | ||
4796 | explicit ReporterRegistrar( std::string const& name ) { | |
4797 | getMutableRegistryHub().registerReporter( name, std::make_shared<ReporterFactory>() ); | |
4798 | } | |
4799 | }; | |
4800 | ||
4801 | template<typename T> | |
4802 | class ListenerRegistrar { | |
4803 | ||
4804 | class ListenerFactory : public IReporterFactory { | |
4805 | ||
4806 | virtual IStreamingReporterPtr create( ReporterConfig const& config ) const override { | |
4807 | return std::unique_ptr<T>( new T( config ) ); | |
4808 | } | |
4809 | virtual std::string getDescription() const override { | |
4810 | return std::string(); | |
4811 | } | |
4812 | }; | |
4813 | ||
4814 | public: | |
4815 | ||
4816 | ListenerRegistrar() { | |
4817 | getMutableRegistryHub().registerListener( std::make_shared<ListenerFactory>() ); | |
4818 | } | |
4819 | }; | |
4820 | } | |
4821 | ||
4822 | #if !defined(CATCH_CONFIG_DISABLE) | |
4823 | ||
4824 | #define CATCH_REGISTER_REPORTER( name, reporterType ) \ | |
4825 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ | |
4826 | namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); } \ | |
4827 | CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS | |
4828 | ||
4829 | #define CATCH_REGISTER_LISTENER( listenerType ) \ | |
4830 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ | |
4831 | namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; } \ | |
4832 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS | |
4833 | #else // CATCH_CONFIG_DISABLE | |
4834 | ||
4835 | #define CATCH_REGISTER_REPORTER(name, reporterType) | |
4836 | #define CATCH_REGISTER_LISTENER(listenerType) | |
4837 | ||
4838 | #endif // CATCH_CONFIG_DISABLE | |
4839 | ||
4840 | // end catch_reporter_registrars.hpp | |
4841 | // Allow users to base their work off existing reporters | |
4842 | // start catch_reporter_compact.h | |
4843 | ||
4844 | namespace Catch { | |
4845 | ||
4846 | struct CompactReporter : StreamingReporterBase<CompactReporter> { | |
4847 | ||
4848 | using StreamingReporterBase::StreamingReporterBase; | |
4849 | ||
4850 | ~CompactReporter() override; | |
4851 | ||
4852 | static std::string getDescription(); | |
4853 | ||
4854 | ReporterPreferences getPreferences() const override; | |
4855 | ||
4856 | void noMatchingTestCases(std::string const& spec) override; | |
4857 | ||
4858 | void assertionStarting(AssertionInfo const&) override; | |
4859 | ||
4860 | bool assertionEnded(AssertionStats const& _assertionStats) override; | |
4861 | ||
4862 | void sectionEnded(SectionStats const& _sectionStats) override; | |
4863 | ||
4864 | void testRunEnded(TestRunStats const& _testRunStats) override; | |
4865 | ||
4866 | }; | |
4867 | ||
4868 | } // end namespace Catch | |
4869 | ||
4870 | // end catch_reporter_compact.h | |
4871 | // start catch_reporter_console.h | |
4872 | ||
4873 | #if defined(_MSC_VER) | |
4874 | #pragma warning(push) | |
4875 | #pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch | |
4876 | // Note that 4062 (not all labels are handled | |
4877 | // and default is missing) is enabled | |
4878 | #endif | |
4879 | ||
4880 | namespace Catch { | |
4881 | // Fwd decls | |
4882 | struct SummaryColumn; | |
4883 | class TablePrinter; | |
4884 | ||
4885 | struct ConsoleReporter : StreamingReporterBase<ConsoleReporter> { | |
4886 | std::unique_ptr<TablePrinter> m_tablePrinter; | |
4887 | ||
4888 | ConsoleReporter(ReporterConfig const& config); | |
4889 | ~ConsoleReporter() override; | |
4890 | static std::string getDescription(); | |
4891 | ||
4892 | void noMatchingTestCases(std::string const& spec) override; | |
4893 | ||
4894 | void assertionStarting(AssertionInfo const&) override; | |
4895 | ||
4896 | bool assertionEnded(AssertionStats const& _assertionStats) override; | |
4897 | ||
4898 | void sectionStarting(SectionInfo const& _sectionInfo) override; | |
4899 | void sectionEnded(SectionStats const& _sectionStats) override; | |
4900 | ||
4901 | void benchmarkStarting(BenchmarkInfo const& info) override; | |
4902 | void benchmarkEnded(BenchmarkStats const& stats) override; | |
4903 | ||
4904 | void testCaseEnded(TestCaseStats const& _testCaseStats) override; | |
4905 | void testGroupEnded(TestGroupStats const& _testGroupStats) override; | |
4906 | void testRunEnded(TestRunStats const& _testRunStats) override; | |
4907 | ||
4908 | private: | |
4909 | ||
4910 | void lazyPrint(); | |
4911 | ||
4912 | void lazyPrintWithoutClosingBenchmarkTable(); | |
4913 | void lazyPrintRunInfo(); | |
4914 | void lazyPrintGroupInfo(); | |
4915 | void printTestCaseAndSectionHeader(); | |
4916 | ||
4917 | void printClosedHeader(std::string const& _name); | |
4918 | void printOpenHeader(std::string const& _name); | |
4919 | ||
4920 | // if string has a : in first line will set indent to follow it on | |
4921 | // subsequent lines | |
4922 | void printHeaderString(std::string const& _string, std::size_t indent = 0); | |
4923 | ||
4924 | void printTotals(Totals const& totals); | |
4925 | void printSummaryRow(std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row); | |
4926 | ||
4927 | void printTotalsDivider(Totals const& totals); | |
4928 | void printSummaryDivider(); | |
4929 | ||
4930 | private: | |
4931 | bool m_headerPrinted = false; | |
4932 | }; | |
4933 | ||
4934 | } // end namespace Catch | |
4935 | ||
4936 | #if defined(_MSC_VER) | |
4937 | #pragma warning(pop) | |
4938 | #endif | |
4939 | ||
4940 | // end catch_reporter_console.h | |
4941 | // start catch_reporter_junit.h | |
4942 | ||
4943 | // start catch_xmlwriter.h | |
4944 | ||
4945 | #include <vector> | |
4946 | ||
4947 | namespace Catch { | |
4948 | ||
4949 | class XmlEncode { | |
4950 | public: | |
4951 | enum ForWhat { ForTextNodes, ForAttributes }; | |
4952 | ||
4953 | XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ); | |
4954 | ||
4955 | void encodeTo( std::ostream& os ) const; | |
4956 | ||
4957 | friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ); | |
4958 | ||
4959 | private: | |
4960 | std::string m_str; | |
4961 | ForWhat m_forWhat; | |
4962 | }; | |
4963 | ||
4964 | class XmlWriter { | |
4965 | public: | |
4966 | ||
4967 | class ScopedElement { | |
4968 | public: | |
4969 | ScopedElement( XmlWriter* writer ); | |
4970 | ||
4971 | ScopedElement( ScopedElement&& other ) noexcept; | |
4972 | ScopedElement& operator=( ScopedElement&& other ) noexcept; | |
4973 | ||
4974 | ~ScopedElement(); | |
4975 | ||
4976 | ScopedElement& writeText( std::string const& text, bool indent = true ); | |
4977 | ||
4978 | template<typename T> | |
4979 | ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { | |
4980 | m_writer->writeAttribute( name, attribute ); | |
4981 | return *this; | |
4982 | } | |
4983 | ||
4984 | private: | |
4985 | mutable XmlWriter* m_writer = nullptr; | |
4986 | }; | |
4987 | ||
4988 | XmlWriter( std::ostream& os = Catch::cout() ); | |
4989 | ~XmlWriter(); | |
4990 | ||
4991 | XmlWriter( XmlWriter const& ) = delete; | |
4992 | XmlWriter& operator=( XmlWriter const& ) = delete; | |
4993 | ||
4994 | XmlWriter& startElement( std::string const& name ); | |
4995 | ||
4996 | ScopedElement scopedElement( std::string const& name ); | |
4997 | ||
4998 | XmlWriter& endElement(); | |
4999 | ||
5000 | XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ); | |
5001 | ||
5002 | XmlWriter& writeAttribute( std::string const& name, bool attribute ); | |
5003 | ||
5004 | template<typename T> | |
5005 | XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { | |
5006 | ReusableStringStream rss; | |
5007 | rss << attribute; | |
5008 | return writeAttribute( name, rss.str() ); | |
5009 | } | |
5010 | ||
5011 | XmlWriter& writeText( std::string const& text, bool indent = true ); | |
5012 | ||
5013 | XmlWriter& writeComment( std::string const& text ); | |
5014 | ||
5015 | void writeStylesheetRef( std::string const& url ); | |
5016 | ||
5017 | XmlWriter& writeBlankLine(); | |
5018 | ||
5019 | void ensureTagClosed(); | |
5020 | ||
5021 | private: | |
5022 | ||
5023 | void writeDeclaration(); | |
5024 | ||
5025 | void newlineIfNecessary(); | |
5026 | ||
5027 | bool m_tagIsOpen = false; | |
5028 | bool m_needsNewline = false; | |
5029 | std::vector<std::string> m_tags; | |
5030 | std::string m_indent; | |
5031 | std::ostream& m_os; | |
5032 | }; | |
5033 | ||
5034 | } | |
5035 | ||
5036 | // end catch_xmlwriter.h | |
5037 | namespace Catch { | |
5038 | ||
5039 | class JunitReporter : public CumulativeReporterBase<JunitReporter> { | |
5040 | public: | |
5041 | JunitReporter(ReporterConfig const& _config); | |
5042 | ||
5043 | ~JunitReporter() override; | |
5044 | ||
5045 | static std::string getDescription(); | |
5046 | ||
5047 | void noMatchingTestCases(std::string const& /*spec*/) override; | |
5048 | ||
5049 | void testRunStarting(TestRunInfo const& runInfo) override; | |
5050 | ||
5051 | void testGroupStarting(GroupInfo const& groupInfo) override; | |
5052 | ||
5053 | void testCaseStarting(TestCaseInfo const& testCaseInfo) override; | |
5054 | bool assertionEnded(AssertionStats const& assertionStats) override; | |
5055 | ||
5056 | void testCaseEnded(TestCaseStats const& testCaseStats) override; | |
5057 | ||
5058 | void testGroupEnded(TestGroupStats const& testGroupStats) override; | |
5059 | ||
5060 | void testRunEndedCumulative() override; | |
5061 | ||
5062 | void writeGroup(TestGroupNode const& groupNode, double suiteTime); | |
5063 | ||
5064 | void writeTestCase(TestCaseNode const& testCaseNode); | |
5065 | ||
5066 | void writeSection(std::string const& className, | |
5067 | std::string const& rootName, | |
5068 | SectionNode const& sectionNode); | |
5069 | ||
5070 | void writeAssertions(SectionNode const& sectionNode); | |
5071 | void writeAssertion(AssertionStats const& stats); | |
5072 | ||
5073 | XmlWriter xml; | |
5074 | Timer suiteTimer; | |
5075 | std::string stdOutForSuite; | |
5076 | std::string stdErrForSuite; | |
5077 | unsigned int unexpectedExceptions = 0; | |
5078 | bool m_okToFail = false; | |
5079 | }; | |
5080 | ||
5081 | } // end namespace Catch | |
5082 | ||
5083 | // end catch_reporter_junit.h | |
5084 | // start catch_reporter_xml.h | |
5085 | ||
5086 | namespace Catch { | |
5087 | class XmlReporter : public StreamingReporterBase<XmlReporter> { | |
5088 | public: | |
5089 | XmlReporter(ReporterConfig const& _config); | |
5090 | ||
5091 | ~XmlReporter() override; | |
5092 | ||
5093 | static std::string getDescription(); | |
5094 | ||
5095 | virtual std::string getStylesheetRef() const; | |
5096 | ||
5097 | void writeSourceInfo(SourceLineInfo const& sourceInfo); | |
5098 | ||
5099 | public: // StreamingReporterBase | |
5100 | ||
5101 | void noMatchingTestCases(std::string const& s) override; | |
5102 | ||
5103 | void testRunStarting(TestRunInfo const& testInfo) override; | |
5104 | ||
5105 | void testGroupStarting(GroupInfo const& groupInfo) override; | |
5106 | ||
5107 | void testCaseStarting(TestCaseInfo const& testInfo) override; | |
5108 | ||
5109 | void sectionStarting(SectionInfo const& sectionInfo) override; | |
5110 | ||
5111 | void assertionStarting(AssertionInfo const&) override; | |
5112 | ||
5113 | bool assertionEnded(AssertionStats const& assertionStats) override; | |
5114 | ||
5115 | void sectionEnded(SectionStats const& sectionStats) override; | |
5116 | ||
5117 | void testCaseEnded(TestCaseStats const& testCaseStats) override; | |
5118 | ||
5119 | void testGroupEnded(TestGroupStats const& testGroupStats) override; | |
5120 | ||
5121 | void testRunEnded(TestRunStats const& testRunStats) override; | |
5122 | ||
5123 | private: | |
5124 | Timer m_testCaseTimer; | |
5125 | XmlWriter m_xml; | |
5126 | int m_sectionDepth = 0; | |
5127 | }; | |
5128 | ||
5129 | } // end namespace Catch | |
5130 | ||
5131 | // end catch_reporter_xml.h | |
5132 | ||
5133 | // end catch_external_interfaces.h | |
5134 | #endif | |
5135 | ||
5136 | #endif // ! CATCH_CONFIG_IMPL_ONLY | |
5137 | ||
5138 | #ifdef CATCH_IMPL | |
5139 | // start catch_impl.hpp | |
5140 | ||
5141 | #ifdef __clang__ | |
5142 | #pragma clang diagnostic push | |
5143 | #pragma clang diagnostic ignored "-Wweak-vtables" | |
5144 | #endif | |
5145 | ||
5146 | // Keep these here for external reporters | |
5147 | // start catch_test_case_tracker.h | |
5148 | ||
5149 | #include <string> | |
5150 | #include <vector> | |
5151 | #include <memory> | |
5152 | ||
5153 | namespace Catch { | |
5154 | namespace TestCaseTracking { | |
5155 | ||
5156 | struct NameAndLocation { | |
5157 | std::string name; | |
5158 | SourceLineInfo location; | |
5159 | ||
5160 | NameAndLocation( std::string const& _name, SourceLineInfo const& _location ); | |
5161 | }; | |
5162 | ||
5163 | struct ITracker; | |
5164 | ||
5165 | using ITrackerPtr = std::shared_ptr<ITracker>; | |
5166 | ||
5167 | struct ITracker { | |
5168 | virtual ~ITracker(); | |
5169 | ||
5170 | // static queries | |
5171 | virtual NameAndLocation const& nameAndLocation() const = 0; | |
5172 | ||
5173 | // dynamic queries | |
5174 | virtual bool isComplete() const = 0; // Successfully completed or failed | |
5175 | virtual bool isSuccessfullyCompleted() const = 0; | |
5176 | virtual bool isOpen() const = 0; // Started but not complete | |
5177 | virtual bool hasChildren() const = 0; | |
5178 | ||
5179 | virtual ITracker& parent() = 0; | |
5180 | ||
5181 | // actions | |
5182 | virtual void close() = 0; // Successfully complete | |
5183 | virtual void fail() = 0; | |
5184 | virtual void markAsNeedingAnotherRun() = 0; | |
5185 | ||
5186 | virtual void addChild( ITrackerPtr const& child ) = 0; | |
5187 | virtual ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) = 0; | |
5188 | virtual void openChild() = 0; | |
5189 | ||
5190 | // Debug/ checking | |
5191 | virtual bool isSectionTracker() const = 0; | |
5192 | virtual bool isIndexTracker() const = 0; | |
5193 | }; | |
5194 | ||
5195 | class TrackerContext { | |
5196 | ||
5197 | enum RunState { | |
5198 | NotStarted, | |
5199 | Executing, | |
5200 | CompletedCycle | |
5201 | }; | |
5202 | ||
5203 | ITrackerPtr m_rootTracker; | |
5204 | ITracker* m_currentTracker = nullptr; | |
5205 | RunState m_runState = NotStarted; | |
5206 | ||
5207 | public: | |
5208 | ||
5209 | static TrackerContext& instance(); | |
5210 | ||
5211 | ITracker& startRun(); | |
5212 | void endRun(); | |
5213 | ||
5214 | void startCycle(); | |
5215 | void completeCycle(); | |
5216 | ||
5217 | bool completedCycle() const; | |
5218 | ITracker& currentTracker(); | |
5219 | void setCurrentTracker( ITracker* tracker ); | |
5220 | }; | |
5221 | ||
5222 | class TrackerBase : public ITracker { | |
5223 | protected: | |
5224 | enum CycleState { | |
5225 | NotStarted, | |
5226 | Executing, | |
5227 | ExecutingChildren, | |
5228 | NeedsAnotherRun, | |
5229 | CompletedSuccessfully, | |
5230 | Failed | |
5231 | }; | |
5232 | ||
5233 | using Children = std::vector<ITrackerPtr>; | |
5234 | NameAndLocation m_nameAndLocation; | |
5235 | TrackerContext& m_ctx; | |
5236 | ITracker* m_parent; | |
5237 | Children m_children; | |
5238 | CycleState m_runState = NotStarted; | |
5239 | ||
5240 | public: | |
5241 | TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); | |
5242 | ||
5243 | NameAndLocation const& nameAndLocation() const override; | |
5244 | bool isComplete() const override; | |
5245 | bool isSuccessfullyCompleted() const override; | |
5246 | bool isOpen() const override; | |
5247 | bool hasChildren() const override; | |
5248 | ||
5249 | void addChild( ITrackerPtr const& child ) override; | |
5250 | ||
5251 | ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) override; | |
5252 | ITracker& parent() override; | |
5253 | ||
5254 | void openChild() override; | |
5255 | ||
5256 | bool isSectionTracker() const override; | |
5257 | bool isIndexTracker() const override; | |
5258 | ||
5259 | void open(); | |
5260 | ||
5261 | void close() override; | |
5262 | void fail() override; | |
5263 | void markAsNeedingAnotherRun() override; | |
5264 | ||
5265 | private: | |
5266 | void moveToParent(); | |
5267 | void moveToThis(); | |
5268 | }; | |
5269 | ||
5270 | class SectionTracker : public TrackerBase { | |
5271 | std::vector<std::string> m_filters; | |
5272 | public: | |
5273 | SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); | |
5274 | ||
5275 | bool isSectionTracker() const override; | |
5276 | ||
5277 | static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ); | |
5278 | ||
5279 | void tryOpen(); | |
5280 | ||
5281 | void addInitialFilters( std::vector<std::string> const& filters ); | |
5282 | void addNextFilters( std::vector<std::string> const& filters ); | |
5283 | }; | |
5284 | ||
5285 | class IndexTracker : public TrackerBase { | |
5286 | int m_size; | |
5287 | int m_index = -1; | |
5288 | public: | |
5289 | IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size ); | |
5290 | ||
5291 | bool isIndexTracker() const override; | |
5292 | void close() override; | |
5293 | ||
5294 | static IndexTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ); | |
5295 | ||
5296 | int index() const; | |
5297 | ||
5298 | void moveNext(); | |
5299 | }; | |
5300 | ||
5301 | } // namespace TestCaseTracking | |
5302 | ||
5303 | using TestCaseTracking::ITracker; | |
5304 | using TestCaseTracking::TrackerContext; | |
5305 | using TestCaseTracking::SectionTracker; | |
5306 | using TestCaseTracking::IndexTracker; | |
5307 | ||
5308 | } // namespace Catch | |
5309 | ||
5310 | // end catch_test_case_tracker.h | |
5311 | ||
5312 | // start catch_leak_detector.h | |
5313 | ||
5314 | namespace Catch { | |
5315 | ||
5316 | struct LeakDetector { | |
5317 | LeakDetector(); | |
5318 | ~LeakDetector(); | |
5319 | }; | |
5320 | ||
5321 | } | |
5322 | // end catch_leak_detector.h | |
5323 | // Cpp files will be included in the single-header file here | |
5324 | // start catch_approx.cpp | |
5325 | ||
5326 | #include <cmath> | |
5327 | #include <limits> | |
5328 | ||
5329 | namespace { | |
5330 | ||
5331 | // Performs equivalent check of std::fabs(lhs - rhs) <= margin | |
5332 | // But without the subtraction to allow for INFINITY in comparison | |
5333 | bool marginComparison(double lhs, double rhs, double margin) { | |
5334 | return (lhs + margin >= rhs) && (rhs + margin >= lhs); | |
5335 | } | |
5336 | ||
5337 | } | |
5338 | ||
5339 | namespace Catch { | |
5340 | namespace Detail { | |
5341 | ||
5342 | Approx::Approx ( double value ) | |
5343 | : m_epsilon( std::numeric_limits<float>::epsilon()*100 ), | |
5344 | m_margin( 0.0 ), | |
5345 | m_scale( 0.0 ), | |
5346 | m_value( value ) | |
5347 | {} | |
5348 | ||
5349 | Approx Approx::custom() { | |
5350 | return Approx( 0 ); | |
5351 | } | |
5352 | ||
5353 | Approx Approx::operator-() const { | |
5354 | auto temp(*this); | |
5355 | temp.m_value = -temp.m_value; | |
5356 | return temp; | |
5357 | } | |
5358 | ||
5359 | std::string Approx::toString() const { | |
5360 | ReusableStringStream rss; | |
5361 | rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )"; | |
5362 | return rss.str(); | |
5363 | } | |
5364 | ||
5365 | bool Approx::equalityComparisonImpl(const double other) const { | |
5366 | // First try with fixed margin, then compute margin based on epsilon, scale and Approx's value | |
5367 | // Thanks to Richard Harris for his help refining the scaled margin value | |
5368 | return marginComparison(m_value, other, m_margin) || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(m_value))); | |
5369 | } | |
5370 | ||
5371 | void Approx::setMargin(double margin) { | |
5372 | CATCH_ENFORCE(margin >= 0, | |
5373 | "Invalid Approx::margin: " << margin << '.' | |
5374 | << " Approx::Margin has to be non-negative."); | |
5375 | m_margin = margin; | |
5376 | } | |
5377 | ||
5378 | void Approx::setEpsilon(double epsilon) { | |
5379 | CATCH_ENFORCE(epsilon >= 0 && epsilon <= 1.0, | |
5380 | "Invalid Approx::epsilon: " << epsilon << '.' | |
5381 | << " Approx::epsilon has to be in [0, 1]"); | |
5382 | m_epsilon = epsilon; | |
5383 | } | |
5384 | ||
5385 | } // end namespace Detail | |
5386 | ||
5387 | namespace literals { | |
5388 | Detail::Approx operator "" _a(long double val) { | |
5389 | return Detail::Approx(val); | |
5390 | } | |
5391 | Detail::Approx operator "" _a(unsigned long long val) { | |
5392 | return Detail::Approx(val); | |
5393 | } | |
5394 | } // end namespace literals | |
5395 | ||
5396 | std::string StringMaker<Catch::Detail::Approx>::convert(Catch::Detail::Approx const& value) { | |
5397 | return value.toString(); | |
5398 | } | |
5399 | ||
5400 | } // end namespace Catch | |
5401 | // end catch_approx.cpp | |
5402 | // start catch_assertionhandler.cpp | |
5403 | ||
5404 | // start catch_context.h | |
5405 | ||
5406 | #include <memory> | |
5407 | ||
5408 | namespace Catch { | |
5409 | ||
5410 | struct IResultCapture; | |
5411 | struct IRunner; | |
5412 | struct IConfig; | |
5413 | struct IMutableContext; | |
5414 | ||
5415 | using IConfigPtr = std::shared_ptr<IConfig const>; | |
5416 | ||
5417 | struct IContext | |
5418 | { | |
5419 | virtual ~IContext(); | |
5420 | ||
5421 | virtual IResultCapture* getResultCapture() = 0; | |
5422 | virtual IRunner* getRunner() = 0; | |
5423 | virtual IConfigPtr const& getConfig() const = 0; | |
5424 | }; | |
5425 | ||
5426 | struct IMutableContext : IContext | |
5427 | { | |
5428 | virtual ~IMutableContext(); | |
5429 | virtual void setResultCapture( IResultCapture* resultCapture ) = 0; | |
5430 | virtual void setRunner( IRunner* runner ) = 0; | |
5431 | virtual void setConfig( IConfigPtr const& config ) = 0; | |
5432 | ||
5433 | private: | |
5434 | static IMutableContext *currentContext; | |
5435 | friend IMutableContext& getCurrentMutableContext(); | |
5436 | friend void cleanUpContext(); | |
5437 | static void createContext(); | |
5438 | }; | |
5439 | ||
5440 | inline IMutableContext& getCurrentMutableContext() | |
5441 | { | |
5442 | if( !IMutableContext::currentContext ) | |
5443 | IMutableContext::createContext(); | |
5444 | return *IMutableContext::currentContext; | |
5445 | } | |
5446 | ||
5447 | inline IContext& getCurrentContext() | |
5448 | { | |
5449 | return getCurrentMutableContext(); | |
5450 | } | |
5451 | ||
5452 | void cleanUpContext(); | |
5453 | } | |
5454 | ||
5455 | // end catch_context.h | |
5456 | // start catch_debugger.h | |
5457 | ||
5458 | namespace Catch { | |
5459 | bool isDebuggerActive(); | |
5460 | } | |
5461 | ||
5462 | #ifdef CATCH_PLATFORM_MAC | |
5463 | ||
5464 | #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */ | |
5465 | ||
5466 | #elif defined(CATCH_PLATFORM_LINUX) | |
5467 | // If we can use inline assembler, do it because this allows us to break | |
5468 | // directly at the location of the failing check instead of breaking inside | |
5469 | // raise() called from it, i.e. one stack frame below. | |
5470 | #if defined(__GNUC__) && (defined(__i386) || defined(__x86_64)) | |
5471 | #define CATCH_TRAP() asm volatile ("int $3") /* NOLINT */ | |
5472 | #else // Fall back to the generic way. | |
5473 | #include <signal.h> | |
5474 | ||
5475 | #define CATCH_TRAP() raise(SIGTRAP) | |
5476 | #endif | |
5477 | #elif defined(_MSC_VER) | |
5478 | #define CATCH_TRAP() __debugbreak() | |
5479 | #elif defined(__MINGW32__) | |
5480 | extern "C" __declspec(dllimport) void __stdcall DebugBreak(); | |
5481 | #define CATCH_TRAP() DebugBreak() | |
5482 | #endif | |
5483 | ||
5484 | #ifdef CATCH_TRAP | |
5485 | #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } | |
5486 | #else | |
5487 | namespace Catch { | |
5488 | inline void doNothing() {} | |
5489 | } | |
5490 | #define CATCH_BREAK_INTO_DEBUGGER() Catch::doNothing() | |
5491 | #endif | |
5492 | ||
5493 | // end catch_debugger.h | |
5494 | // start catch_run_context.h | |
5495 | ||
5496 | // start catch_fatal_condition.h | |
5497 | ||
5498 | // start catch_windows_h_proxy.h | |
5499 | ||
5500 | ||
5501 | #if defined(CATCH_PLATFORM_WINDOWS) | |
5502 | ||
5503 | #if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX) | |
5504 | # define CATCH_DEFINED_NOMINMAX | |
5505 | # define NOMINMAX | |
5506 | #endif | |
5507 | #if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN) | |
5508 | # define CATCH_DEFINED_WIN32_LEAN_AND_MEAN | |
5509 | # define WIN32_LEAN_AND_MEAN | |
5510 | #endif | |
5511 | ||
5512 | #ifdef __AFXDLL | |
5513 | #include <AfxWin.h> | |
5514 | #else | |
5515 | #include <windows.h> | |
5516 | #endif | |
5517 | ||
5518 | #ifdef CATCH_DEFINED_NOMINMAX | |
5519 | # undef NOMINMAX | |
5520 | #endif | |
5521 | #ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN | |
5522 | # undef WIN32_LEAN_AND_MEAN | |
5523 | #endif | |
5524 | ||
5525 | #endif // defined(CATCH_PLATFORM_WINDOWS) | |
5526 | ||
5527 | // end catch_windows_h_proxy.h | |
5528 | #if defined( CATCH_CONFIG_WINDOWS_SEH ) | |
5529 | ||
5530 | namespace Catch { | |
5531 | ||
5532 | struct FatalConditionHandler { | |
5533 | ||
5534 | static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo); | |
5535 | FatalConditionHandler(); | |
5536 | static void reset(); | |
5537 | ~FatalConditionHandler(); | |
5538 | ||
5539 | private: | |
5540 | static bool isSet; | |
5541 | static ULONG guaranteeSize; | |
5542 | static PVOID exceptionHandlerHandle; | |
5543 | }; | |
5544 | ||
5545 | } // namespace Catch | |
5546 | ||
5547 | #elif defined ( CATCH_CONFIG_POSIX_SIGNALS ) | |
5548 | ||
5549 | #include <signal.h> | |
5550 | ||
5551 | namespace Catch { | |
5552 | ||
5553 | struct FatalConditionHandler { | |
5554 | ||
5555 | static bool isSet; | |
5556 | static struct sigaction oldSigActions[]; | |
5557 | static stack_t oldSigStack; | |
5558 | static char altStackMem[]; | |
5559 | ||
5560 | static void handleSignal( int sig ); | |
5561 | ||
5562 | FatalConditionHandler(); | |
5563 | ~FatalConditionHandler(); | |
5564 | static void reset(); | |
5565 | }; | |
5566 | ||
5567 | } // namespace Catch | |
5568 | ||
5569 | #else | |
5570 | ||
5571 | namespace Catch { | |
5572 | struct FatalConditionHandler { | |
5573 | void reset(); | |
5574 | }; | |
5575 | } | |
5576 | ||
5577 | #endif | |
5578 | ||
5579 | // end catch_fatal_condition.h | |
5580 | #include <string> | |
5581 | ||
5582 | namespace Catch { | |
5583 | ||
5584 | struct IMutableContext; | |
5585 | ||
5586 | /////////////////////////////////////////////////////////////////////////// | |
5587 | ||
5588 | class RunContext : public IResultCapture, public IRunner { | |
5589 | ||
5590 | public: | |
5591 | RunContext( RunContext const& ) = delete; | |
5592 | RunContext& operator =( RunContext const& ) = delete; | |
5593 | ||
5594 | explicit RunContext( IConfigPtr const& _config, IStreamingReporterPtr&& reporter ); | |
5595 | ||
5596 | ~RunContext() override; | |
5597 | ||
5598 | void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ); | |
5599 | void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ); | |
5600 | ||
5601 | Totals runTest(TestCase const& testCase); | |
5602 | ||
5603 | IConfigPtr config() const; | |
5604 | IStreamingReporter& reporter() const; | |
5605 | ||
5606 | public: // IResultCapture | |
5607 | ||
5608 | // Assertion handlers | |
5609 | void handleExpr | |
5610 | ( AssertionInfo const& info, | |
5611 | ITransientExpression const& expr, | |
5612 | AssertionReaction& reaction ) override; | |
5613 | void handleMessage | |
5614 | ( AssertionInfo const& info, | |
5615 | ResultWas::OfType resultType, | |
5616 | StringRef const& message, | |
5617 | AssertionReaction& reaction ) override; | |
5618 | void handleUnexpectedExceptionNotThrown | |
5619 | ( AssertionInfo const& info, | |
5620 | AssertionReaction& reaction ) override; | |
5621 | void handleUnexpectedInflightException | |
5622 | ( AssertionInfo const& info, | |
5623 | std::string const& message, | |
5624 | AssertionReaction& reaction ) override; | |
5625 | void handleIncomplete | |
5626 | ( AssertionInfo const& info ) override; | |
5627 | void handleNonExpr | |
5628 | ( AssertionInfo const &info, | |
5629 | ResultWas::OfType resultType, | |
5630 | AssertionReaction &reaction ) override; | |
5631 | ||
5632 | bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) override; | |
5633 | ||
5634 | void sectionEnded( SectionEndInfo const& endInfo ) override; | |
5635 | void sectionEndedEarly( SectionEndInfo const& endInfo ) override; | |
5636 | ||
5637 | auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override; | |
5638 | ||
5639 | void benchmarkStarting( BenchmarkInfo const& info ) override; | |
5640 | void benchmarkEnded( BenchmarkStats const& stats ) override; | |
5641 | ||
5642 | void pushScopedMessage( MessageInfo const& message ) override; | |
5643 | void popScopedMessage( MessageInfo const& message ) override; | |
5644 | ||
5645 | std::string getCurrentTestName() const override; | |
5646 | ||
5647 | const AssertionResult* getLastResult() const override; | |
5648 | ||
5649 | void exceptionEarlyReported() override; | |
5650 | ||
5651 | void handleFatalErrorCondition( StringRef message ) override; | |
5652 | ||
5653 | bool lastAssertionPassed() override; | |
5654 | ||
5655 | void assertionPassed() override; | |
5656 | ||
5657 | public: | |
5658 | // !TBD We need to do this another way! | |
5659 | bool aborting() const final; | |
5660 | ||
5661 | private: | |
5662 | ||
5663 | void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ); | |
5664 | void invokeActiveTestCase(); | |
5665 | ||
5666 | void resetAssertionInfo(); | |
5667 | bool testForMissingAssertions( Counts& assertions ); | |
5668 | ||
5669 | void assertionEnded( AssertionResult const& result ); | |
5670 | void reportExpr | |
5671 | ( AssertionInfo const &info, | |
5672 | ResultWas::OfType resultType, | |
5673 | ITransientExpression const *expr, | |
5674 | bool negated ); | |
5675 | ||
5676 | void populateReaction( AssertionReaction& reaction ); | |
5677 | ||
5678 | private: | |
5679 | ||
5680 | void handleUnfinishedSections(); | |
5681 | ||
5682 | TestRunInfo m_runInfo; | |
5683 | IMutableContext& m_context; | |
5684 | TestCase const* m_activeTestCase = nullptr; | |
5685 | ITracker* m_testCaseTracker; | |
5686 | Option<AssertionResult> m_lastResult; | |
5687 | ||
5688 | IConfigPtr m_config; | |
5689 | Totals m_totals; | |
5690 | IStreamingReporterPtr m_reporter; | |
5691 | std::vector<MessageInfo> m_messages; | |
5692 | AssertionInfo m_lastAssertionInfo; | |
5693 | std::vector<SectionEndInfo> m_unfinishedSections; | |
5694 | std::vector<ITracker*> m_activeSections; | |
5695 | TrackerContext m_trackerContext; | |
5696 | bool m_lastAssertionPassed = false; | |
5697 | bool m_shouldReportUnexpected = true; | |
5698 | bool m_includeSuccessfulResults; | |
5699 | }; | |
5700 | ||
5701 | } // end namespace Catch | |
5702 | ||
5703 | // end catch_run_context.h | |
5704 | namespace Catch { | |
5705 | ||
5706 | namespace { | |
5707 | auto operator <<( std::ostream& os, ITransientExpression const& expr ) -> std::ostream& { | |
5708 | expr.streamReconstructedExpression( os ); | |
5709 | return os; | |
5710 | } | |
5711 | } | |
5712 | ||
5713 | LazyExpression::LazyExpression( bool isNegated ) | |
5714 | : m_isNegated( isNegated ) | |
5715 | {} | |
5716 | ||
5717 | LazyExpression::LazyExpression( LazyExpression const& other ) : m_isNegated( other.m_isNegated ) {} | |
5718 | ||
5719 | LazyExpression::operator bool() const { | |
5720 | return m_transientExpression != nullptr; | |
5721 | } | |
5722 | ||
5723 | auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream& { | |
5724 | if( lazyExpr.m_isNegated ) | |
5725 | os << "!"; | |
5726 | ||
5727 | if( lazyExpr ) { | |
5728 | if( lazyExpr.m_isNegated && lazyExpr.m_transientExpression->isBinaryExpression() ) | |
5729 | os << "(" << *lazyExpr.m_transientExpression << ")"; | |
5730 | else | |
5731 | os << *lazyExpr.m_transientExpression; | |
5732 | } | |
5733 | else { | |
5734 | os << "{** error - unchecked empty expression requested **}"; | |
5735 | } | |
5736 | return os; | |
5737 | } | |
5738 | ||
5739 | AssertionHandler::AssertionHandler | |
5740 | ( StringRef const& macroName, | |
5741 | SourceLineInfo const& lineInfo, | |
5742 | StringRef capturedExpression, | |
5743 | ResultDisposition::Flags resultDisposition ) | |
5744 | : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition }, | |
5745 | m_resultCapture( getResultCapture() ) | |
5746 | {} | |
5747 | ||
5748 | void AssertionHandler::handleExpr( ITransientExpression const& expr ) { | |
5749 | m_resultCapture.handleExpr( m_assertionInfo, expr, m_reaction ); | |
5750 | } | |
5751 | void AssertionHandler::handleMessage(ResultWas::OfType resultType, StringRef const& message) { | |
5752 | m_resultCapture.handleMessage( m_assertionInfo, resultType, message, m_reaction ); | |
5753 | } | |
5754 | ||
5755 | auto AssertionHandler::allowThrows() const -> bool { | |
5756 | return getCurrentContext().getConfig()->allowThrows(); | |
5757 | } | |
5758 | ||
5759 | void AssertionHandler::complete() { | |
5760 | setCompleted(); | |
5761 | if( m_reaction.shouldDebugBreak ) { | |
5762 | ||
5763 | // If you find your debugger stopping you here then go one level up on the | |
5764 | // call-stack for the code that caused it (typically a failed assertion) | |
5765 | ||
5766 | // (To go back to the test and change execution, jump over the throw, next) | |
5767 | CATCH_BREAK_INTO_DEBUGGER(); | |
5768 | } | |
5769 | if (m_reaction.shouldThrow) { | |
5770 | #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) | |
5771 | throw Catch::TestFailureException(); | |
5772 | #else | |
5773 | CATCH_ERROR( "Test failure requires aborting test!" ); | |
5774 | #endif | |
5775 | } | |
5776 | } | |
5777 | void AssertionHandler::setCompleted() { | |
5778 | m_completed = true; | |
5779 | } | |
5780 | ||
5781 | void AssertionHandler::handleUnexpectedInflightException() { | |
5782 | m_resultCapture.handleUnexpectedInflightException( m_assertionInfo, Catch::translateActiveException(), m_reaction ); | |
5783 | } | |
5784 | ||
5785 | void AssertionHandler::handleExceptionThrownAsExpected() { | |
5786 | m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); | |
5787 | } | |
5788 | void AssertionHandler::handleExceptionNotThrownAsExpected() { | |
5789 | m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); | |
5790 | } | |
5791 | ||
5792 | void AssertionHandler::handleUnexpectedExceptionNotThrown() { | |
5793 | m_resultCapture.handleUnexpectedExceptionNotThrown( m_assertionInfo, m_reaction ); | |
5794 | } | |
5795 | ||
5796 | void AssertionHandler::handleThrowingCallSkipped() { | |
5797 | m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); | |
5798 | } | |
5799 | ||
5800 | // This is the overload that takes a string and infers the Equals matcher from it | |
5801 | // The more general overload, that takes any string matcher, is in catch_capture_matchers.cpp | |
5802 | void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef const& matcherString ) { | |
5803 | handleExceptionMatchExpr( handler, Matchers::Equals( str ), matcherString ); | |
5804 | } | |
5805 | ||
5806 | } // namespace Catch | |
5807 | // end catch_assertionhandler.cpp | |
5808 | // start catch_assertionresult.cpp | |
5809 | ||
5810 | namespace Catch { | |
5811 | AssertionResultData::AssertionResultData(ResultWas::OfType _resultType, LazyExpression const & _lazyExpression): | |
5812 | lazyExpression(_lazyExpression), | |
5813 | resultType(_resultType) {} | |
5814 | ||
5815 | std::string AssertionResultData::reconstructExpression() const { | |
5816 | ||
5817 | if( reconstructedExpression.empty() ) { | |
5818 | if( lazyExpression ) { | |
5819 | ReusableStringStream rss; | |
5820 | rss << lazyExpression; | |
5821 | reconstructedExpression = rss.str(); | |
5822 | } | |
5823 | } | |
5824 | return reconstructedExpression; | |
5825 | } | |
5826 | ||
5827 | AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) | |
5828 | : m_info( info ), | |
5829 | m_resultData( data ) | |
5830 | {} | |
5831 | ||
5832 | // Result was a success | |
5833 | bool AssertionResult::succeeded() const { | |
5834 | return Catch::isOk( m_resultData.resultType ); | |
5835 | } | |
5836 | ||
5837 | // Result was a success, or failure is suppressed | |
5838 | bool AssertionResult::isOk() const { | |
5839 | return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition ); | |
5840 | } | |
5841 | ||
5842 | ResultWas::OfType AssertionResult::getResultType() const { | |
5843 | return m_resultData.resultType; | |
5844 | } | |
5845 | ||
5846 | bool AssertionResult::hasExpression() const { | |
5847 | return m_info.capturedExpression[0] != 0; | |
5848 | } | |
5849 | ||
5850 | bool AssertionResult::hasMessage() const { | |
5851 | return !m_resultData.message.empty(); | |
5852 | } | |
5853 | ||
5854 | std::string AssertionResult::getExpression() const { | |
5855 | if( isFalseTest( m_info.resultDisposition ) ) | |
5856 | return "!(" + m_info.capturedExpression + ")"; | |
5857 | else | |
5858 | return m_info.capturedExpression; | |
5859 | } | |
5860 | ||
5861 | std::string AssertionResult::getExpressionInMacro() const { | |
5862 | std::string expr; | |
5863 | if( m_info.macroName[0] == 0 ) | |
5864 | expr = m_info.capturedExpression; | |
5865 | else { | |
5866 | expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 ); | |
5867 | expr += m_info.macroName; | |
5868 | expr += "( "; | |
5869 | expr += m_info.capturedExpression; | |
5870 | expr += " )"; | |
5871 | } | |
5872 | return expr; | |
5873 | } | |
5874 | ||
5875 | bool AssertionResult::hasExpandedExpression() const { | |
5876 | return hasExpression() && getExpandedExpression() != getExpression(); | |
5877 | } | |
5878 | ||
5879 | std::string AssertionResult::getExpandedExpression() const { | |
5880 | std::string expr = m_resultData.reconstructExpression(); | |
5881 | return expr.empty() | |
5882 | ? getExpression() | |
5883 | : expr; | |
5884 | } | |
5885 | ||
5886 | std::string AssertionResult::getMessage() const { | |
5887 | return m_resultData.message; | |
5888 | } | |
5889 | SourceLineInfo AssertionResult::getSourceInfo() const { | |
5890 | return m_info.lineInfo; | |
5891 | } | |
5892 | ||
5893 | StringRef AssertionResult::getTestMacroName() const { | |
5894 | return m_info.macroName; | |
5895 | } | |
5896 | ||
5897 | } // end namespace Catch | |
5898 | // end catch_assertionresult.cpp | |
5899 | // start catch_benchmark.cpp | |
5900 | ||
5901 | namespace Catch { | |
5902 | ||
5903 | auto BenchmarkLooper::getResolution() -> uint64_t { | |
5904 | return getEstimatedClockResolution() * getCurrentContext().getConfig()->benchmarkResolutionMultiple(); | |
5905 | } | |
5906 | ||
5907 | void BenchmarkLooper::reportStart() { | |
5908 | getResultCapture().benchmarkStarting( { m_name } ); | |
5909 | } | |
5910 | auto BenchmarkLooper::needsMoreIterations() -> bool { | |
5911 | auto elapsed = m_timer.getElapsedNanoseconds(); | |
5912 | ||
5913 | // Exponentially increasing iterations until we're confident in our timer resolution | |
5914 | if( elapsed < m_resolution ) { | |
5915 | m_iterationsToRun *= 10; | |
5916 | return true; | |
5917 | } | |
5918 | ||
5919 | getResultCapture().benchmarkEnded( { { m_name }, m_count, elapsed } ); | |
5920 | return false; | |
5921 | } | |
5922 | ||
5923 | } // end namespace Catch | |
5924 | // end catch_benchmark.cpp | |
5925 | // start catch_capture_matchers.cpp | |
5926 | ||
5927 | namespace Catch { | |
5928 | ||
5929 | using StringMatcher = Matchers::Impl::MatcherBase<std::string>; | |
5930 | ||
5931 | // This is the general overload that takes a any string matcher | |
5932 | // There is another overload, in catch_assertionhandler.h/.cpp, that only takes a string and infers | |
5933 | // the Equals matcher (so the header does not mention matchers) | |
5934 | void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString ) { | |
5935 | std::string exceptionMessage = Catch::translateActiveException(); | |
5936 | MatchExpr<std::string, StringMatcher const&> expr( exceptionMessage, matcher, matcherString ); | |
5937 | handler.handleExpr( expr ); | |
5938 | } | |
5939 | ||
5940 | } // namespace Catch | |
5941 | // end catch_capture_matchers.cpp | |
5942 | // start catch_commandline.cpp | |
5943 | ||
5944 | // start catch_commandline.h | |
5945 | ||
5946 | // start catch_clara.h | |
5947 | ||
5948 | // Use Catch's value for console width (store Clara's off to the side, if present) | |
5949 | #ifdef CLARA_CONFIG_CONSOLE_WIDTH | |
5950 | #define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH | |
5951 | #undef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH | |
5952 | #endif | |
5953 | #define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH-1 | |
5954 | ||
5955 | #ifdef __clang__ | |
5956 | #pragma clang diagnostic push | |
5957 | #pragma clang diagnostic ignored "-Wweak-vtables" | |
5958 | #pragma clang diagnostic ignored "-Wexit-time-destructors" | |
5959 | #pragma clang diagnostic ignored "-Wshadow" | |
5960 | #endif | |
5961 | ||
5962 | // start clara.hpp | |
5963 | // Copyright 2017 Two Blue Cubes Ltd. All rights reserved. | |
5964 | // | |
5965 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | |
5966 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
5967 | // | |
5968 | // See https://github.com/philsquared/Clara for more details | |
5969 | ||
5970 | // Clara v1.1.5 | |
5971 | ||
5972 | ||
5973 | #ifndef CATCH_CLARA_CONFIG_CONSOLE_WIDTH | |
5974 | #define CATCH_CLARA_CONFIG_CONSOLE_WIDTH 80 | |
5975 | #endif | |
5976 | ||
5977 | #ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH | |
5978 | #define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CLARA_CONFIG_CONSOLE_WIDTH | |
5979 | #endif | |
5980 | ||
5981 | #ifndef CLARA_CONFIG_OPTIONAL_TYPE | |
5982 | #ifdef __has_include | |
5983 | #if __has_include(<optional>) && __cplusplus >= 201703L | |
5984 | #include <optional> | |
5985 | #define CLARA_CONFIG_OPTIONAL_TYPE std::optional | |
5986 | #endif | |
5987 | #endif | |
5988 | #endif | |
5989 | ||
5990 | // ----------- #included from clara_textflow.hpp ----------- | |
5991 | ||
5992 | // TextFlowCpp | |
5993 | // | |
5994 | // A single-header library for wrapping and laying out basic text, by Phil Nash | |
5995 | // | |
5996 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | |
5997 | // file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
5998 | // | |
5999 | // This project is hosted at https://github.com/philsquared/textflowcpp | |
6000 | ||
6001 | ||
6002 | #include <cassert> | |
6003 | #include <ostream> | |
6004 | #include <sstream> | |
6005 | #include <vector> | |
6006 | ||
6007 | #ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH | |
6008 | #define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH 80 | |
6009 | #endif | |
6010 | ||
6011 | namespace Catch { | |
6012 | namespace clara { | |
6013 | namespace TextFlow { | |
6014 | ||
6015 | inline auto isWhitespace(char c) -> bool { | |
6016 | static std::string chars = " \t\n\r"; | |
6017 | return chars.find(c) != std::string::npos; | |
6018 | } | |
6019 | inline auto isBreakableBefore(char c) -> bool { | |
6020 | static std::string chars = "[({<|"; | |
6021 | return chars.find(c) != std::string::npos; | |
6022 | } | |
6023 | inline auto isBreakableAfter(char c) -> bool { | |
6024 | static std::string chars = "])}>.,:;*+-=&/\\"; | |
6025 | return chars.find(c) != std::string::npos; | |
6026 | } | |
6027 | ||
6028 | class Columns; | |
6029 | ||
6030 | class Column { | |
6031 | std::vector<std::string> m_strings; | |
6032 | size_t m_width = CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH; | |
6033 | size_t m_indent = 0; | |
6034 | size_t m_initialIndent = std::string::npos; | |
6035 | ||
6036 | public: | |
6037 | class iterator { | |
6038 | friend Column; | |
6039 | ||
6040 | Column const& m_column; | |
6041 | size_t m_stringIndex = 0; | |
6042 | size_t m_pos = 0; | |
6043 | ||
6044 | size_t m_len = 0; | |
6045 | size_t m_end = 0; | |
6046 | bool m_suffix = false; | |
6047 | ||
6048 | iterator(Column const& column, size_t stringIndex) | |
6049 | : m_column(column), | |
6050 | m_stringIndex(stringIndex) {} | |
6051 | ||
6052 | auto line() const -> std::string const& { return m_column.m_strings[m_stringIndex]; } | |
6053 | ||
6054 | auto isBoundary(size_t at) const -> bool { | |
6055 | assert(at > 0); | |
6056 | assert(at <= line().size()); | |
6057 | ||
6058 | return at == line().size() || | |
6059 | (isWhitespace(line()[at]) && !isWhitespace(line()[at - 1])) || | |
6060 | isBreakableBefore(line()[at]) || | |
6061 | isBreakableAfter(line()[at - 1]); | |
6062 | } | |
6063 | ||
6064 | void calcLength() { | |
6065 | assert(m_stringIndex < m_column.m_strings.size()); | |
6066 | ||
6067 | m_suffix = false; | |
6068 | auto width = m_column.m_width - indent(); | |
6069 | m_end = m_pos; | |
6070 | while (m_end < line().size() && line()[m_end] != '\n') | |
6071 | ++m_end; | |
6072 | ||
6073 | if (m_end < m_pos + width) { | |
6074 | m_len = m_end - m_pos; | |
6075 | } else { | |
6076 | size_t len = width; | |
6077 | while (len > 0 && !isBoundary(m_pos + len)) | |
6078 | --len; | |
6079 | while (len > 0 && isWhitespace(line()[m_pos + len - 1])) | |
6080 | --len; | |
6081 | ||
6082 | if (len > 0) { | |
6083 | m_len = len; | |
6084 | } else { | |
6085 | m_suffix = true; | |
6086 | m_len = width - 1; | |
6087 | } | |
6088 | } | |
6089 | } | |
6090 | ||
6091 | auto indent() const -> size_t { | |
6092 | auto initial = m_pos == 0 && m_stringIndex == 0 ? m_column.m_initialIndent : std::string::npos; | |
6093 | return initial == std::string::npos ? m_column.m_indent : initial; | |
6094 | } | |
6095 | ||
6096 | auto addIndentAndSuffix(std::string const &plain) const -> std::string { | |
6097 | return std::string(indent(), ' ') + (m_suffix ? plain + "-" : plain); | |
6098 | } | |
6099 | ||
6100 | public: | |
6101 | using difference_type = std::ptrdiff_t; | |
6102 | using value_type = std::string; | |
6103 | using pointer = value_type * ; | |
6104 | using reference = value_type & ; | |
6105 | using iterator_category = std::forward_iterator_tag; | |
6106 | ||
6107 | explicit iterator(Column const& column) : m_column(column) { | |
6108 | assert(m_column.m_width > m_column.m_indent); | |
6109 | assert(m_column.m_initialIndent == std::string::npos || m_column.m_width > m_column.m_initialIndent); | |
6110 | calcLength(); | |
6111 | if (m_len == 0) | |
6112 | m_stringIndex++; // Empty string | |
6113 | } | |
6114 | ||
6115 | auto operator *() const -> std::string { | |
6116 | assert(m_stringIndex < m_column.m_strings.size()); | |
6117 | assert(m_pos <= m_end); | |
6118 | return addIndentAndSuffix(line().substr(m_pos, m_len)); | |
6119 | } | |
6120 | ||
6121 | auto operator ++() -> iterator& { | |
6122 | m_pos += m_len; | |
6123 | if (m_pos < line().size() && line()[m_pos] == '\n') | |
6124 | m_pos += 1; | |
6125 | else | |
6126 | while (m_pos < line().size() && isWhitespace(line()[m_pos])) | |
6127 | ++m_pos; | |
6128 | ||
6129 | if (m_pos == line().size()) { | |
6130 | m_pos = 0; | |
6131 | ++m_stringIndex; | |
6132 | } | |
6133 | if (m_stringIndex < m_column.m_strings.size()) | |
6134 | calcLength(); | |
6135 | return *this; | |
6136 | } | |
6137 | auto operator ++(int) -> iterator { | |
6138 | iterator prev(*this); | |
6139 | operator++(); | |
6140 | return prev; | |
6141 | } | |
6142 | ||
6143 | auto operator ==(iterator const& other) const -> bool { | |
6144 | return | |
6145 | m_pos == other.m_pos && | |
6146 | m_stringIndex == other.m_stringIndex && | |
6147 | &m_column == &other.m_column; | |
6148 | } | |
6149 | auto operator !=(iterator const& other) const -> bool { | |
6150 | return !operator==(other); | |
6151 | } | |
6152 | }; | |
6153 | using const_iterator = iterator; | |
6154 | ||
6155 | explicit Column(std::string const& text) { m_strings.push_back(text); } | |
6156 | ||
6157 | auto width(size_t newWidth) -> Column& { | |
6158 | assert(newWidth > 0); | |
6159 | m_width = newWidth; | |
6160 | return *this; | |
6161 | } | |
6162 | auto indent(size_t newIndent) -> Column& { | |
6163 | m_indent = newIndent; | |
6164 | return *this; | |
6165 | } | |
6166 | auto initialIndent(size_t newIndent) -> Column& { | |
6167 | m_initialIndent = newIndent; | |
6168 | return *this; | |
6169 | } | |
6170 | ||
6171 | auto width() const -> size_t { return m_width; } | |
6172 | auto begin() const -> iterator { return iterator(*this); } | |
6173 | auto end() const -> iterator { return { *this, m_strings.size() }; } | |
6174 | ||
6175 | inline friend std::ostream& operator << (std::ostream& os, Column const& col) { | |
6176 | bool first = true; | |
6177 | for (auto line : col) { | |
6178 | if (first) | |
6179 | first = false; | |
6180 | else | |
6181 | os << "\n"; | |
6182 | os << line; | |
6183 | } | |
6184 | return os; | |
6185 | } | |
6186 | ||
6187 | auto operator + (Column const& other)->Columns; | |
6188 | ||
6189 | auto toString() const -> std::string { | |
6190 | std::ostringstream oss; | |
6191 | oss << *this; | |
6192 | return oss.str(); | |
6193 | } | |
6194 | }; | |
6195 | ||
6196 | class Spacer : public Column { | |
6197 | ||
6198 | public: | |
6199 | explicit Spacer(size_t spaceWidth) : Column("") { | |
6200 | width(spaceWidth); | |
6201 | } | |
6202 | }; | |
6203 | ||
6204 | class Columns { | |
6205 | std::vector<Column> m_columns; | |
6206 | ||
6207 | public: | |
6208 | ||
6209 | class iterator { | |
6210 | friend Columns; | |
6211 | struct EndTag {}; | |
6212 | ||
6213 | std::vector<Column> const& m_columns; | |
6214 | std::vector<Column::iterator> m_iterators; | |
6215 | size_t m_activeIterators; | |
6216 | ||
6217 | iterator(Columns const& columns, EndTag) | |
6218 | : m_columns(columns.m_columns), | |
6219 | m_activeIterators(0) { | |
6220 | m_iterators.reserve(m_columns.size()); | |
6221 | ||
6222 | for (auto const& col : m_columns) | |
6223 | m_iterators.push_back(col.end()); | |
6224 | } | |
6225 | ||
6226 | public: | |
6227 | using difference_type = std::ptrdiff_t; | |
6228 | using value_type = std::string; | |
6229 | using pointer = value_type * ; | |
6230 | using reference = value_type & ; | |
6231 | using iterator_category = std::forward_iterator_tag; | |
6232 | ||
6233 | explicit iterator(Columns const& columns) | |
6234 | : m_columns(columns.m_columns), | |
6235 | m_activeIterators(m_columns.size()) { | |
6236 | m_iterators.reserve(m_columns.size()); | |
6237 | ||
6238 | for (auto const& col : m_columns) | |
6239 | m_iterators.push_back(col.begin()); | |
6240 | } | |
6241 | ||
6242 | auto operator ==(iterator const& other) const -> bool { | |
6243 | return m_iterators == other.m_iterators; | |
6244 | } | |
6245 | auto operator !=(iterator const& other) const -> bool { | |
6246 | return m_iterators != other.m_iterators; | |
6247 | } | |
6248 | auto operator *() const -> std::string { | |
6249 | std::string row, padding; | |
6250 | ||
6251 | for (size_t i = 0; i < m_columns.size(); ++i) { | |
6252 | auto width = m_columns[i].width(); | |
6253 | if (m_iterators[i] != m_columns[i].end()) { | |
6254 | std::string col = *m_iterators[i]; | |
6255 | row += padding + col; | |
6256 | if (col.size() < width) | |
6257 | padding = std::string(width - col.size(), ' '); | |
6258 | else | |
6259 | padding = ""; | |
6260 | } else { | |
6261 | padding += std::string(width, ' '); | |
6262 | } | |
6263 | } | |
6264 | return row; | |
6265 | } | |
6266 | auto operator ++() -> iterator& { | |
6267 | for (size_t i = 0; i < m_columns.size(); ++i) { | |
6268 | if (m_iterators[i] != m_columns[i].end()) | |
6269 | ++m_iterators[i]; | |
6270 | } | |
6271 | return *this; | |
6272 | } | |
6273 | auto operator ++(int) -> iterator { | |
6274 | iterator prev(*this); | |
6275 | operator++(); | |
6276 | return prev; | |
6277 | } | |
6278 | }; | |
6279 | using const_iterator = iterator; | |
6280 | ||
6281 | auto begin() const -> iterator { return iterator(*this); } | |
6282 | auto end() const -> iterator { return { *this, iterator::EndTag() }; } | |
6283 | ||
6284 | auto operator += (Column const& col) -> Columns& { | |
6285 | m_columns.push_back(col); | |
6286 | return *this; | |
6287 | } | |
6288 | auto operator + (Column const& col) -> Columns { | |
6289 | Columns combined = *this; | |
6290 | combined += col; | |
6291 | return combined; | |
6292 | } | |
6293 | ||
6294 | inline friend std::ostream& operator << (std::ostream& os, Columns const& cols) { | |
6295 | ||
6296 | bool first = true; | |
6297 | for (auto line : cols) { | |
6298 | if (first) | |
6299 | first = false; | |
6300 | else | |
6301 | os << "\n"; | |
6302 | os << line; | |
6303 | } | |
6304 | return os; | |
6305 | } | |
6306 | ||
6307 | auto toString() const -> std::string { | |
6308 | std::ostringstream oss; | |
6309 | oss << *this; | |
6310 | return oss.str(); | |
6311 | } | |
6312 | }; | |
6313 | ||
6314 | inline auto Column::operator + (Column const& other) -> Columns { | |
6315 | Columns cols; | |
6316 | cols += *this; | |
6317 | cols += other; | |
6318 | return cols; | |
6319 | } | |
6320 | } | |
6321 | ||
6322 | } | |
6323 | } | |
6324 | ||
6325 | // ----------- end of #include from clara_textflow.hpp ----------- | |
6326 | // ........... back in clara.hpp | |
6327 | ||
6328 | #include <string> | |
6329 | #include <memory> | |
6330 | #include <set> | |
6331 | #include <algorithm> | |
6332 | ||
6333 | #if !defined(CATCH_PLATFORM_WINDOWS) && ( defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) ) | |
6334 | #define CATCH_PLATFORM_WINDOWS | |
6335 | #endif | |
6336 | ||
6337 | namespace Catch { namespace clara { | |
6338 | namespace detail { | |
6339 | ||
6340 | // Traits for extracting arg and return type of lambdas (for single argument lambdas) | |
6341 | template<typename L> | |
6342 | struct UnaryLambdaTraits : UnaryLambdaTraits<decltype( &L::operator() )> {}; | |
6343 | ||
6344 | template<typename ClassT, typename ReturnT, typename... Args> | |
6345 | struct UnaryLambdaTraits<ReturnT( ClassT::* )( Args... ) const> { | |
6346 | static const bool isValid = false; | |
6347 | }; | |
6348 | ||
6349 | template<typename ClassT, typename ReturnT, typename ArgT> | |
6350 | struct UnaryLambdaTraits<ReturnT( ClassT::* )( ArgT ) const> { | |
6351 | static const bool isValid = true; | |
6352 | using ArgType = typename std::remove_const<typename std::remove_reference<ArgT>::type>::type; | |
6353 | using ReturnType = ReturnT; | |
6354 | }; | |
6355 | ||
6356 | class TokenStream; | |
6357 | ||
6358 | // Transport for raw args (copied from main args, or supplied via init list for testing) | |
6359 | class Args { | |
6360 | friend TokenStream; | |
6361 | std::string m_exeName; | |
6362 | std::vector<std::string> m_args; | |
6363 | ||
6364 | public: | |
6365 | Args( int argc, char const* const* argv ) | |
6366 | : m_exeName(argv[0]), | |
6367 | m_args(argv + 1, argv + argc) {} | |
6368 | ||
6369 | Args( std::initializer_list<std::string> args ) | |
6370 | : m_exeName( *args.begin() ), | |
6371 | m_args( args.begin()+1, args.end() ) | |
6372 | {} | |
6373 | ||
6374 | auto exeName() const -> std::string { | |
6375 | return m_exeName; | |
6376 | } | |
6377 | }; | |
6378 | ||
6379 | // Wraps a token coming from a token stream. These may not directly correspond to strings as a single string | |
6380 | // may encode an option + its argument if the : or = form is used | |
6381 | enum class TokenType { | |
6382 | Option, Argument | |
6383 | }; | |
6384 | struct Token { | |
6385 | TokenType type; | |
6386 | std::string token; | |
6387 | }; | |
6388 | ||
6389 | inline auto isOptPrefix( char c ) -> bool { | |
6390 | return c == '-' | |
6391 | #ifdef CATCH_PLATFORM_WINDOWS | |
6392 | || c == '/' | |
6393 | #endif | |
6394 | ; | |
6395 | } | |
6396 | ||
6397 | // Abstracts iterators into args as a stream of tokens, with option arguments uniformly handled | |
6398 | class TokenStream { | |
6399 | using Iterator = std::vector<std::string>::const_iterator; | |
6400 | Iterator it; | |
6401 | Iterator itEnd; | |
6402 | std::vector<Token> m_tokenBuffer; | |
6403 | ||
6404 | void loadBuffer() { | |
6405 | m_tokenBuffer.resize( 0 ); | |
6406 | ||
6407 | // Skip any empty strings | |
6408 | while( it != itEnd && it->empty() ) | |
6409 | ++it; | |
6410 | ||
6411 | if( it != itEnd ) { | |
6412 | auto const &next = *it; | |
6413 | if( isOptPrefix( next[0] ) ) { | |
6414 | auto delimiterPos = next.find_first_of( " :=" ); | |
6415 | if( delimiterPos != std::string::npos ) { | |
6416 | m_tokenBuffer.push_back( { TokenType::Option, next.substr( 0, delimiterPos ) } ); | |
6417 | m_tokenBuffer.push_back( { TokenType::Argument, next.substr( delimiterPos + 1 ) } ); | |
6418 | } else { | |
6419 | if( next[1] != '-' && next.size() > 2 ) { | |
6420 | std::string opt = "- "; | |
6421 | for( size_t i = 1; i < next.size(); ++i ) { | |
6422 | opt[1] = next[i]; | |
6423 | m_tokenBuffer.push_back( { TokenType::Option, opt } ); | |
6424 | } | |
6425 | } else { | |
6426 | m_tokenBuffer.push_back( { TokenType::Option, next } ); | |
6427 | } | |
6428 | } | |
6429 | } else { | |
6430 | m_tokenBuffer.push_back( { TokenType::Argument, next } ); | |
6431 | } | |
6432 | } | |
6433 | } | |
6434 | ||
6435 | public: | |
6436 | explicit TokenStream( Args const &args ) : TokenStream( args.m_args.begin(), args.m_args.end() ) {} | |
6437 | ||
6438 | TokenStream( Iterator it, Iterator itEnd ) : it( it ), itEnd( itEnd ) { | |
6439 | loadBuffer(); | |
6440 | } | |
6441 | ||
6442 | explicit operator bool() const { | |
6443 | return !m_tokenBuffer.empty() || it != itEnd; | |
6444 | } | |
6445 | ||
6446 | auto count() const -> size_t { return m_tokenBuffer.size() + (itEnd - it); } | |
6447 | ||
6448 | auto operator*() const -> Token { | |
6449 | assert( !m_tokenBuffer.empty() ); | |
6450 | return m_tokenBuffer.front(); | |
6451 | } | |
6452 | ||
6453 | auto operator->() const -> Token const * { | |
6454 | assert( !m_tokenBuffer.empty() ); | |
6455 | return &m_tokenBuffer.front(); | |
6456 | } | |
6457 | ||
6458 | auto operator++() -> TokenStream & { | |
6459 | if( m_tokenBuffer.size() >= 2 ) { | |
6460 | m_tokenBuffer.erase( m_tokenBuffer.begin() ); | |
6461 | } else { | |
6462 | if( it != itEnd ) | |
6463 | ++it; | |
6464 | loadBuffer(); | |
6465 | } | |
6466 | return *this; | |
6467 | } | |
6468 | }; | |
6469 | ||
6470 | class ResultBase { | |
6471 | public: | |
6472 | enum Type { | |
6473 | Ok, LogicError, RuntimeError | |
6474 | }; | |
6475 | ||
6476 | protected: | |
6477 | ResultBase( Type type ) : m_type( type ) {} | |
6478 | virtual ~ResultBase() = default; | |
6479 | ||
6480 | virtual void enforceOk() const = 0; | |
6481 | ||
6482 | Type m_type; | |
6483 | }; | |
6484 | ||
6485 | template<typename T> | |
6486 | class ResultValueBase : public ResultBase { | |
6487 | public: | |
6488 | auto value() const -> T const & { | |
6489 | enforceOk(); | |
6490 | return m_value; | |
6491 | } | |
6492 | ||
6493 | protected: | |
6494 | ResultValueBase( Type type ) : ResultBase( type ) {} | |
6495 | ||
6496 | ResultValueBase( ResultValueBase const &other ) : ResultBase( other ) { | |
6497 | if( m_type == ResultBase::Ok ) | |
6498 | new( &m_value ) T( other.m_value ); | |
6499 | } | |
6500 | ||
6501 | ResultValueBase( Type, T const &value ) : ResultBase( Ok ) { | |
6502 | new( &m_value ) T( value ); | |
6503 | } | |
6504 | ||
6505 | auto operator=( ResultValueBase const &other ) -> ResultValueBase & { | |
6506 | if( m_type == ResultBase::Ok ) | |
6507 | m_value.~T(); | |
6508 | ResultBase::operator=(other); | |
6509 | if( m_type == ResultBase::Ok ) | |
6510 | new( &m_value ) T( other.m_value ); | |
6511 | return *this; | |
6512 | } | |
6513 | ||
6514 | ~ResultValueBase() override { | |
6515 | if( m_type == Ok ) | |
6516 | m_value.~T(); | |
6517 | } | |
6518 | ||
6519 | union { | |
6520 | T m_value; | |
6521 | }; | |
6522 | }; | |
6523 | ||
6524 | template<> | |
6525 | class ResultValueBase<void> : public ResultBase { | |
6526 | protected: | |
6527 | using ResultBase::ResultBase; | |
6528 | }; | |
6529 | ||
6530 | template<typename T = void> | |
6531 | class BasicResult : public ResultValueBase<T> { | |
6532 | public: | |
6533 | template<typename U> | |
6534 | explicit BasicResult( BasicResult<U> const &other ) | |
6535 | : ResultValueBase<T>( other.type() ), | |
6536 | m_errorMessage( other.errorMessage() ) | |
6537 | { | |
6538 | assert( type() != ResultBase::Ok ); | |
6539 | } | |
6540 | ||
6541 | template<typename U> | |
6542 | static auto ok( U const &value ) -> BasicResult { return { ResultBase::Ok, value }; } | |
6543 | static auto ok() -> BasicResult { return { ResultBase::Ok }; } | |
6544 | static auto logicError( std::string const &message ) -> BasicResult { return { ResultBase::LogicError, message }; } | |
6545 | static auto runtimeError( std::string const &message ) -> BasicResult { return { ResultBase::RuntimeError, message }; } | |
6546 | ||
6547 | explicit operator bool() const { return m_type == ResultBase::Ok; } | |
6548 | auto type() const -> ResultBase::Type { return m_type; } | |
6549 | auto errorMessage() const -> std::string { return m_errorMessage; } | |
6550 | ||
6551 | protected: | |
6552 | void enforceOk() const override { | |
6553 | ||
6554 | // Errors shouldn't reach this point, but if they do | |
6555 | // the actual error message will be in m_errorMessage | |
6556 | assert( m_type != ResultBase::LogicError ); | |
6557 | assert( m_type != ResultBase::RuntimeError ); | |
6558 | if( m_type != ResultBase::Ok ) | |
6559 | std::abort(); | |
6560 | } | |
6561 | ||
6562 | std::string m_errorMessage; // Only populated if resultType is an error | |
6563 | ||
6564 | BasicResult( ResultBase::Type type, std::string const &message ) | |
6565 | : ResultValueBase<T>(type), | |
6566 | m_errorMessage(message) | |
6567 | { | |
6568 | assert( m_type != ResultBase::Ok ); | |
6569 | } | |
6570 | ||
6571 | using ResultValueBase<T>::ResultValueBase; | |
6572 | using ResultBase::m_type; | |
6573 | }; | |
6574 | ||
6575 | enum class ParseResultType { | |
6576 | Matched, NoMatch, ShortCircuitAll, ShortCircuitSame | |
6577 | }; | |
6578 | ||
6579 | class ParseState { | |
6580 | public: | |
6581 | ||
6582 | ParseState( ParseResultType type, TokenStream const &remainingTokens ) | |
6583 | : m_type(type), | |
6584 | m_remainingTokens( remainingTokens ) | |
6585 | {} | |
6586 | ||
6587 | auto type() const -> ParseResultType { return m_type; } | |
6588 | auto remainingTokens() const -> TokenStream { return m_remainingTokens; } | |
6589 | ||
6590 | private: | |
6591 | ParseResultType m_type; | |
6592 | TokenStream m_remainingTokens; | |
6593 | }; | |
6594 | ||
6595 | using Result = BasicResult<void>; | |
6596 | using ParserResult = BasicResult<ParseResultType>; | |
6597 | using InternalParseResult = BasicResult<ParseState>; | |
6598 | ||
6599 | struct HelpColumns { | |
6600 | std::string left; | |
6601 | std::string right; | |
6602 | }; | |
6603 | ||
6604 | template<typename T> | |
6605 | inline auto convertInto( std::string const &source, T& target ) -> ParserResult { | |
6606 | std::stringstream ss; | |
6607 | ss << source; | |
6608 | ss >> target; | |
6609 | if( ss.fail() ) | |
6610 | return ParserResult::runtimeError( "Unable to convert '" + source + "' to destination type" ); | |
6611 | else | |
6612 | return ParserResult::ok( ParseResultType::Matched ); | |
6613 | } | |
6614 | inline auto convertInto( std::string const &source, std::string& target ) -> ParserResult { | |
6615 | target = source; | |
6616 | return ParserResult::ok( ParseResultType::Matched ); | |
6617 | } | |
6618 | inline auto convertInto( std::string const &source, bool &target ) -> ParserResult { | |
6619 | std::string srcLC = source; | |
6620 | std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast<char>( ::tolower(c) ); } ); | |
6621 | if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on") | |
6622 | target = true; | |
6623 | else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off") | |
6624 | target = false; | |
6625 | else | |
6626 | return ParserResult::runtimeError( "Expected a boolean value but did not recognise: '" + source + "'" ); | |
6627 | return ParserResult::ok( ParseResultType::Matched ); | |
6628 | } | |
6629 | #ifdef CLARA_CONFIG_OPTIONAL_TYPE | |
6630 | template<typename T> | |
6631 | inline auto convertInto( std::string const &source, CLARA_CONFIG_OPTIONAL_TYPE<T>& target ) -> ParserResult { | |
6632 | T temp; | |
6633 | auto result = convertInto( source, temp ); | |
6634 | if( result ) | |
6635 | target = std::move(temp); | |
6636 | return result; | |
6637 | } | |
6638 | #endif // CLARA_CONFIG_OPTIONAL_TYPE | |
6639 | ||
6640 | struct NonCopyable { | |
6641 | NonCopyable() = default; | |
6642 | NonCopyable( NonCopyable const & ) = delete; | |
6643 | NonCopyable( NonCopyable && ) = delete; | |
6644 | NonCopyable &operator=( NonCopyable const & ) = delete; | |
6645 | NonCopyable &operator=( NonCopyable && ) = delete; | |
6646 | }; | |
6647 | ||
6648 | struct BoundRef : NonCopyable { | |
6649 | virtual ~BoundRef() = default; | |
6650 | virtual auto isContainer() const -> bool { return false; } | |
6651 | virtual auto isFlag() const -> bool { return false; } | |
6652 | }; | |
6653 | struct BoundValueRefBase : BoundRef { | |
6654 | virtual auto setValue( std::string const &arg ) -> ParserResult = 0; | |
6655 | }; | |
6656 | struct BoundFlagRefBase : BoundRef { | |
6657 | virtual auto setFlag( bool flag ) -> ParserResult = 0; | |
6658 | virtual auto isFlag() const -> bool { return true; } | |
6659 | }; | |
6660 | ||
6661 | template<typename T> | |
6662 | struct BoundValueRef : BoundValueRefBase { | |
6663 | T &m_ref; | |
6664 | ||
6665 | explicit BoundValueRef( T &ref ) : m_ref( ref ) {} | |
6666 | ||
6667 | auto setValue( std::string const &arg ) -> ParserResult override { | |
6668 | return convertInto( arg, m_ref ); | |
6669 | } | |
6670 | }; | |
6671 | ||
6672 | template<typename T> | |
6673 | struct BoundValueRef<std::vector<T>> : BoundValueRefBase { | |
6674 | std::vector<T> &m_ref; | |
6675 | ||
6676 | explicit BoundValueRef( std::vector<T> &ref ) : m_ref( ref ) {} | |
6677 | ||
6678 | auto isContainer() const -> bool override { return true; } | |
6679 | ||
6680 | auto setValue( std::string const &arg ) -> ParserResult override { | |
6681 | T temp; | |
6682 | auto result = convertInto( arg, temp ); | |
6683 | if( result ) | |
6684 | m_ref.push_back( temp ); | |
6685 | return result; | |
6686 | } | |
6687 | }; | |
6688 | ||
6689 | struct BoundFlagRef : BoundFlagRefBase { | |
6690 | bool &m_ref; | |
6691 | ||
6692 | explicit BoundFlagRef( bool &ref ) : m_ref( ref ) {} | |
6693 | ||
6694 | auto setFlag( bool flag ) -> ParserResult override { | |
6695 | m_ref = flag; | |
6696 | return ParserResult::ok( ParseResultType::Matched ); | |
6697 | } | |
6698 | }; | |
6699 | ||
6700 | template<typename ReturnType> | |
6701 | struct LambdaInvoker { | |
6702 | static_assert( std::is_same<ReturnType, ParserResult>::value, "Lambda must return void or clara::ParserResult" ); | |
6703 | ||
6704 | template<typename L, typename ArgType> | |
6705 | static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult { | |
6706 | return lambda( arg ); | |
6707 | } | |
6708 | }; | |
6709 | ||
6710 | template<> | |
6711 | struct LambdaInvoker<void> { | |
6712 | template<typename L, typename ArgType> | |
6713 | static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult { | |
6714 | lambda( arg ); | |
6715 | return ParserResult::ok( ParseResultType::Matched ); | |
6716 | } | |
6717 | }; | |
6718 | ||
6719 | template<typename ArgType, typename L> | |
6720 | inline auto invokeLambda( L const &lambda, std::string const &arg ) -> ParserResult { | |
6721 | ArgType temp{}; | |
6722 | auto result = convertInto( arg, temp ); | |
6723 | return !result | |
6724 | ? result | |
6725 | : LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( lambda, temp ); | |
6726 | } | |
6727 | ||
6728 | template<typename L> | |
6729 | struct BoundLambda : BoundValueRefBase { | |
6730 | L m_lambda; | |
6731 | ||
6732 | static_assert( UnaryLambdaTraits<L>::isValid, "Supplied lambda must take exactly one argument" ); | |
6733 | explicit BoundLambda( L const &lambda ) : m_lambda( lambda ) {} | |
6734 | ||
6735 | auto setValue( std::string const &arg ) -> ParserResult override { | |
6736 | return invokeLambda<typename UnaryLambdaTraits<L>::ArgType>( m_lambda, arg ); | |
6737 | } | |
6738 | }; | |
6739 | ||
6740 | template<typename L> | |
6741 | struct BoundFlagLambda : BoundFlagRefBase { | |
6742 | L m_lambda; | |
6743 | ||
6744 | static_assert( UnaryLambdaTraits<L>::isValid, "Supplied lambda must take exactly one argument" ); | |
6745 | static_assert( std::is_same<typename UnaryLambdaTraits<L>::ArgType, bool>::value, "flags must be boolean" ); | |
6746 | ||
6747 | explicit BoundFlagLambda( L const &lambda ) : m_lambda( lambda ) {} | |
6748 | ||
6749 | auto setFlag( bool flag ) -> ParserResult override { | |
6750 | return LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( m_lambda, flag ); | |
6751 | } | |
6752 | }; | |
6753 | ||
6754 | enum class Optionality { Optional, Required }; | |
6755 | ||
6756 | struct Parser; | |
6757 | ||
6758 | class ParserBase { | |
6759 | public: | |
6760 | virtual ~ParserBase() = default; | |
6761 | virtual auto validate() const -> Result { return Result::ok(); } | |
6762 | virtual auto parse( std::string const& exeName, TokenStream const &tokens) const -> InternalParseResult = 0; | |
6763 | virtual auto cardinality() const -> size_t { return 1; } | |
6764 | ||
6765 | auto parse( Args const &args ) const -> InternalParseResult { | |
6766 | return parse( args.exeName(), TokenStream( args ) ); | |
6767 | } | |
6768 | }; | |
6769 | ||
6770 | template<typename DerivedT> | |
6771 | class ComposableParserImpl : public ParserBase { | |
6772 | public: | |
6773 | template<typename T> | |
6774 | auto operator|( T const &other ) const -> Parser; | |
6775 | ||
6776 | template<typename T> | |
6777 | auto operator+( T const &other ) const -> Parser; | |
6778 | }; | |
6779 | ||
6780 | // Common code and state for Args and Opts | |
6781 | template<typename DerivedT> | |
6782 | class ParserRefImpl : public ComposableParserImpl<DerivedT> { | |
6783 | protected: | |
6784 | Optionality m_optionality = Optionality::Optional; | |
6785 | std::shared_ptr<BoundRef> m_ref; | |
6786 | std::string m_hint; | |
6787 | std::string m_description; | |
6788 | ||
6789 | explicit ParserRefImpl( std::shared_ptr<BoundRef> const &ref ) : m_ref( ref ) {} | |
6790 | ||
6791 | public: | |
6792 | template<typename T> | |
6793 | ParserRefImpl( T &ref, std::string const &hint ) | |
6794 | : m_ref( std::make_shared<BoundValueRef<T>>( ref ) ), | |
6795 | m_hint( hint ) | |
6796 | {} | |
6797 | ||
6798 | template<typename LambdaT> | |
6799 | ParserRefImpl( LambdaT const &ref, std::string const &hint ) | |
6800 | : m_ref( std::make_shared<BoundLambda<LambdaT>>( ref ) ), | |
6801 | m_hint(hint) | |
6802 | {} | |
6803 | ||
6804 | auto operator()( std::string const &description ) -> DerivedT & { | |
6805 | m_description = description; | |
6806 | return static_cast<DerivedT &>( *this ); | |
6807 | } | |
6808 | ||
6809 | auto optional() -> DerivedT & { | |
6810 | m_optionality = Optionality::Optional; | |
6811 | return static_cast<DerivedT &>( *this ); | |
6812 | }; | |
6813 | ||
6814 | auto required() -> DerivedT & { | |
6815 | m_optionality = Optionality::Required; | |
6816 | return static_cast<DerivedT &>( *this ); | |
6817 | }; | |
6818 | ||
6819 | auto isOptional() const -> bool { | |
6820 | return m_optionality == Optionality::Optional; | |
6821 | } | |
6822 | ||
6823 | auto cardinality() const -> size_t override { | |
6824 | if( m_ref->isContainer() ) | |
6825 | return 0; | |
6826 | else | |
6827 | return 1; | |
6828 | } | |
6829 | ||
6830 | auto hint() const -> std::string { return m_hint; } | |
6831 | }; | |
6832 | ||
6833 | class ExeName : public ComposableParserImpl<ExeName> { | |
6834 | std::shared_ptr<std::string> m_name; | |
6835 | std::shared_ptr<BoundValueRefBase> m_ref; | |
6836 | ||
6837 | template<typename LambdaT> | |
6838 | static auto makeRef(LambdaT const &lambda) -> std::shared_ptr<BoundValueRefBase> { | |
6839 | return std::make_shared<BoundLambda<LambdaT>>( lambda) ; | |
6840 | } | |
6841 | ||
6842 | public: | |
6843 | ExeName() : m_name( std::make_shared<std::string>( "<executable>" ) ) {} | |
6844 | ||
6845 | explicit ExeName( std::string &ref ) : ExeName() { | |
6846 | m_ref = std::make_shared<BoundValueRef<std::string>>( ref ); | |
6847 | } | |
6848 | ||
6849 | template<typename LambdaT> | |
6850 | explicit ExeName( LambdaT const& lambda ) : ExeName() { | |
6851 | m_ref = std::make_shared<BoundLambda<LambdaT>>( lambda ); | |
6852 | } | |
6853 | ||
6854 | // The exe name is not parsed out of the normal tokens, but is handled specially | |
6855 | auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override { | |
6856 | return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) ); | |
6857 | } | |
6858 | ||
6859 | auto name() const -> std::string { return *m_name; } | |
6860 | auto set( std::string const& newName ) -> ParserResult { | |
6861 | ||
6862 | auto lastSlash = newName.find_last_of( "\\/" ); | |
6863 | auto filename = ( lastSlash == std::string::npos ) | |
6864 | ? newName | |
6865 | : newName.substr( lastSlash+1 ); | |
6866 | ||
6867 | *m_name = filename; | |
6868 | if( m_ref ) | |
6869 | return m_ref->setValue( filename ); | |
6870 | else | |
6871 | return ParserResult::ok( ParseResultType::Matched ); | |
6872 | } | |
6873 | }; | |
6874 | ||
6875 | class Arg : public ParserRefImpl<Arg> { | |
6876 | public: | |
6877 | using ParserRefImpl::ParserRefImpl; | |
6878 | ||
6879 | auto parse( std::string const &, TokenStream const &tokens ) const -> InternalParseResult override { | |
6880 | auto validationResult = validate(); | |
6881 | if( !validationResult ) | |
6882 | return InternalParseResult( validationResult ); | |
6883 | ||
6884 | auto remainingTokens = tokens; | |
6885 | auto const &token = *remainingTokens; | |
6886 | if( token.type != TokenType::Argument ) | |
6887 | return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) ); | |
6888 | ||
6889 | assert( !m_ref->isFlag() ); | |
6890 | auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() ); | |
6891 | ||
6892 | auto result = valueRef->setValue( remainingTokens->token ); | |
6893 | if( !result ) | |
6894 | return InternalParseResult( result ); | |
6895 | else | |
6896 | return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) ); | |
6897 | } | |
6898 | }; | |
6899 | ||
6900 | inline auto normaliseOpt( std::string const &optName ) -> std::string { | |
6901 | #ifdef CATCH_PLATFORM_WINDOWS | |
6902 | if( optName[0] == '/' ) | |
6903 | return "-" + optName.substr( 1 ); | |
6904 | else | |
6905 | #endif | |
6906 | return optName; | |
6907 | } | |
6908 | ||
6909 | class Opt : public ParserRefImpl<Opt> { | |
6910 | protected: | |
6911 | std::vector<std::string> m_optNames; | |
6912 | ||
6913 | public: | |
6914 | template<typename LambdaT> | |
6915 | explicit Opt( LambdaT const &ref ) : ParserRefImpl( std::make_shared<BoundFlagLambda<LambdaT>>( ref ) ) {} | |
6916 | ||
6917 | explicit Opt( bool &ref ) : ParserRefImpl( std::make_shared<BoundFlagRef>( ref ) ) {} | |
6918 | ||
6919 | template<typename LambdaT> | |
6920 | Opt( LambdaT const &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {} | |
6921 | ||
6922 | template<typename T> | |
6923 | Opt( T &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {} | |
6924 | ||
6925 | auto operator[]( std::string const &optName ) -> Opt & { | |
6926 | m_optNames.push_back( optName ); | |
6927 | return *this; | |
6928 | } | |
6929 | ||
6930 | auto getHelpColumns() const -> std::vector<HelpColumns> { | |
6931 | std::ostringstream oss; | |
6932 | bool first = true; | |
6933 | for( auto const &opt : m_optNames ) { | |
6934 | if (first) | |
6935 | first = false; | |
6936 | else | |
6937 | oss << ", "; | |
6938 | oss << opt; | |
6939 | } | |
6940 | if( !m_hint.empty() ) | |
6941 | oss << " <" << m_hint << ">"; | |
6942 | return { { oss.str(), m_description } }; | |
6943 | } | |
6944 | ||
6945 | auto isMatch( std::string const &optToken ) const -> bool { | |
6946 | auto normalisedToken = normaliseOpt( optToken ); | |
6947 | for( auto const &name : m_optNames ) { | |
6948 | if( normaliseOpt( name ) == normalisedToken ) | |
6949 | return true; | |
6950 | } | |
6951 | return false; | |
6952 | } | |
6953 | ||
6954 | using ParserBase::parse; | |
6955 | ||
6956 | auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override { | |
6957 | auto validationResult = validate(); | |
6958 | if( !validationResult ) | |
6959 | return InternalParseResult( validationResult ); | |
6960 | ||
6961 | auto remainingTokens = tokens; | |
6962 | if( remainingTokens && remainingTokens->type == TokenType::Option ) { | |
6963 | auto const &token = *remainingTokens; | |
6964 | if( isMatch(token.token ) ) { | |
6965 | if( m_ref->isFlag() ) { | |
6966 | auto flagRef = static_cast<detail::BoundFlagRefBase*>( m_ref.get() ); | |
6967 | auto result = flagRef->setFlag( true ); | |
6968 | if( !result ) | |
6969 | return InternalParseResult( result ); | |
6970 | if( result.value() == ParseResultType::ShortCircuitAll ) | |
6971 | return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) ); | |
6972 | } else { | |
6973 | auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() ); | |
6974 | ++remainingTokens; | |
6975 | if( !remainingTokens ) | |
6976 | return InternalParseResult::runtimeError( "Expected argument following " + token.token ); | |
6977 | auto const &argToken = *remainingTokens; | |
6978 | if( argToken.type != TokenType::Argument ) | |
6979 | return InternalParseResult::runtimeError( "Expected argument following " + token.token ); | |
6980 | auto result = valueRef->setValue( argToken.token ); | |
6981 | if( !result ) | |
6982 | return InternalParseResult( result ); | |
6983 | if( result.value() == ParseResultType::ShortCircuitAll ) | |
6984 | return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) ); | |
6985 | } | |
6986 | return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) ); | |
6987 | } | |
6988 | } | |
6989 | return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) ); | |
6990 | } | |
6991 | ||
6992 | auto validate() const -> Result override { | |
6993 | if( m_optNames.empty() ) | |
6994 | return Result::logicError( "No options supplied to Opt" ); | |
6995 | for( auto const &name : m_optNames ) { | |
6996 | if( name.empty() ) | |
6997 | return Result::logicError( "Option name cannot be empty" ); | |
6998 | #ifdef CATCH_PLATFORM_WINDOWS | |
6999 | if( name[0] != '-' && name[0] != '/' ) | |
7000 | return Result::logicError( "Option name must begin with '-' or '/'" ); | |
7001 | #else | |
7002 | if( name[0] != '-' ) | |
7003 | return Result::logicError( "Option name must begin with '-'" ); | |
7004 | #endif | |
7005 | } | |
7006 | return ParserRefImpl::validate(); | |
7007 | } | |
7008 | }; | |
7009 | ||
7010 | struct Help : Opt { | |
7011 | Help( bool &showHelpFlag ) | |
7012 | : Opt([&]( bool flag ) { | |
7013 | showHelpFlag = flag; | |
7014 | return ParserResult::ok( ParseResultType::ShortCircuitAll ); | |
7015 | }) | |
7016 | { | |
7017 | static_cast<Opt &>( *this ) | |
7018 | ("display usage information") | |
7019 | ["-?"]["-h"]["--help"] | |
7020 | .optional(); | |
7021 | } | |
7022 | }; | |
7023 | ||
7024 | struct Parser : ParserBase { | |
7025 | ||
7026 | mutable ExeName m_exeName; | |
7027 | std::vector<Opt> m_options; | |
7028 | std::vector<Arg> m_args; | |
7029 | ||
7030 | auto operator|=( ExeName const &exeName ) -> Parser & { | |
7031 | m_exeName = exeName; | |
7032 | return *this; | |
7033 | } | |
7034 | ||
7035 | auto operator|=( Arg const &arg ) -> Parser & { | |
7036 | m_args.push_back(arg); | |
7037 | return *this; | |
7038 | } | |
7039 | ||
7040 | auto operator|=( Opt const &opt ) -> Parser & { | |
7041 | m_options.push_back(opt); | |
7042 | return *this; | |
7043 | } | |
7044 | ||
7045 | auto operator|=( Parser const &other ) -> Parser & { | |
7046 | m_options.insert(m_options.end(), other.m_options.begin(), other.m_options.end()); | |
7047 | m_args.insert(m_args.end(), other.m_args.begin(), other.m_args.end()); | |
7048 | return *this; | |
7049 | } | |
7050 | ||
7051 | template<typename T> | |
7052 | auto operator|( T const &other ) const -> Parser { | |
7053 | return Parser( *this ) |= other; | |
7054 | } | |
7055 | ||
7056 | // Forward deprecated interface with '+' instead of '|' | |
7057 | template<typename T> | |
7058 | auto operator+=( T const &other ) -> Parser & { return operator|=( other ); } | |
7059 | template<typename T> | |
7060 | auto operator+( T const &other ) const -> Parser { return operator|( other ); } | |
7061 | ||
7062 | auto getHelpColumns() const -> std::vector<HelpColumns> { | |
7063 | std::vector<HelpColumns> cols; | |
7064 | for (auto const &o : m_options) { | |
7065 | auto childCols = o.getHelpColumns(); | |
7066 | cols.insert( cols.end(), childCols.begin(), childCols.end() ); | |
7067 | } | |
7068 | return cols; | |
7069 | } | |
7070 | ||
7071 | void writeToStream( std::ostream &os ) const { | |
7072 | if (!m_exeName.name().empty()) { | |
7073 | os << "usage:\n" << " " << m_exeName.name() << " "; | |
7074 | bool required = true, first = true; | |
7075 | for( auto const &arg : m_args ) { | |
7076 | if (first) | |
7077 | first = false; | |
7078 | else | |
7079 | os << " "; | |
7080 | if( arg.isOptional() && required ) { | |
7081 | os << "["; | |
7082 | required = false; | |
7083 | } | |
7084 | os << "<" << arg.hint() << ">"; | |
7085 | if( arg.cardinality() == 0 ) | |
7086 | os << " ... "; | |
7087 | } | |
7088 | if( !required ) | |
7089 | os << "]"; | |
7090 | if( !m_options.empty() ) | |
7091 | os << " options"; | |
7092 | os << "\n\nwhere options are:" << std::endl; | |
7093 | } | |
7094 | ||
7095 | auto rows = getHelpColumns(); | |
7096 | size_t consoleWidth = CATCH_CLARA_CONFIG_CONSOLE_WIDTH; | |
7097 | size_t optWidth = 0; | |
7098 | for( auto const &cols : rows ) | |
7099 | optWidth = (std::max)(optWidth, cols.left.size() + 2); | |
7100 | ||
7101 | optWidth = (std::min)(optWidth, consoleWidth/2); | |
7102 | ||
7103 | for( auto const &cols : rows ) { | |
7104 | auto row = | |
7105 | TextFlow::Column( cols.left ).width( optWidth ).indent( 2 ) + | |
7106 | TextFlow::Spacer(4) + | |
7107 | TextFlow::Column( cols.right ).width( consoleWidth - 7 - optWidth ); | |
7108 | os << row << std::endl; | |
7109 | } | |
7110 | } | |
7111 | ||
7112 | friend auto operator<<( std::ostream &os, Parser const &parser ) -> std::ostream& { | |
7113 | parser.writeToStream( os ); | |
7114 | return os; | |
7115 | } | |
7116 | ||
7117 | auto validate() const -> Result override { | |
7118 | for( auto const &opt : m_options ) { | |
7119 | auto result = opt.validate(); | |
7120 | if( !result ) | |
7121 | return result; | |
7122 | } | |
7123 | for( auto const &arg : m_args ) { | |
7124 | auto result = arg.validate(); | |
7125 | if( !result ) | |
7126 | return result; | |
7127 | } | |
7128 | return Result::ok(); | |
7129 | } | |
7130 | ||
7131 | using ParserBase::parse; | |
7132 | ||
7133 | auto parse( std::string const& exeName, TokenStream const &tokens ) const -> InternalParseResult override { | |
7134 | ||
7135 | struct ParserInfo { | |
7136 | ParserBase const* parser = nullptr; | |
7137 | size_t count = 0; | |
7138 | }; | |
7139 | const size_t totalParsers = m_options.size() + m_args.size(); | |
7140 | assert( totalParsers < 512 ); | |
7141 | // ParserInfo parseInfos[totalParsers]; // <-- this is what we really want to do | |
7142 | ParserInfo parseInfos[512]; | |
7143 | ||
7144 | { | |
7145 | size_t i = 0; | |
7146 | for (auto const &opt : m_options) parseInfos[i++].parser = &opt; | |
7147 | for (auto const &arg : m_args) parseInfos[i++].parser = &arg; | |
7148 | } | |
7149 | ||
7150 | m_exeName.set( exeName ); | |
7151 | ||
7152 | auto result = InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) ); | |
7153 | while( result.value().remainingTokens() ) { | |
7154 | bool tokenParsed = false; | |
7155 | ||
7156 | for( size_t i = 0; i < totalParsers; ++i ) { | |
7157 | auto& parseInfo = parseInfos[i]; | |
7158 | if( parseInfo.parser->cardinality() == 0 || parseInfo.count < parseInfo.parser->cardinality() ) { | |
7159 | result = parseInfo.parser->parse(exeName, result.value().remainingTokens()); | |
7160 | if (!result) | |
7161 | return result; | |
7162 | if (result.value().type() != ParseResultType::NoMatch) { | |
7163 | tokenParsed = true; | |
7164 | ++parseInfo.count; | |
7165 | break; | |
7166 | } | |
7167 | } | |
7168 | } | |
7169 | ||
7170 | if( result.value().type() == ParseResultType::ShortCircuitAll ) | |
7171 | return result; | |
7172 | if( !tokenParsed ) | |
7173 | return InternalParseResult::runtimeError( "Unrecognised token: " + result.value().remainingTokens()->token ); | |
7174 | } | |
7175 | // !TBD Check missing required options | |
7176 | return result; | |
7177 | } | |
7178 | }; | |
7179 | ||
7180 | template<typename DerivedT> | |
7181 | template<typename T> | |
7182 | auto ComposableParserImpl<DerivedT>::operator|( T const &other ) const -> Parser { | |
7183 | return Parser() | static_cast<DerivedT const &>( *this ) | other; | |
7184 | } | |
7185 | } // namespace detail | |
7186 | ||
7187 | // A Combined parser | |
7188 | using detail::Parser; | |
7189 | ||
7190 | // A parser for options | |
7191 | using detail::Opt; | |
7192 | ||
7193 | // A parser for arguments | |
7194 | using detail::Arg; | |
7195 | ||
7196 | // Wrapper for argc, argv from main() | |
7197 | using detail::Args; | |
7198 | ||
7199 | // Specifies the name of the executable | |
7200 | using detail::ExeName; | |
7201 | ||
7202 | // Convenience wrapper for option parser that specifies the help option | |
7203 | using detail::Help; | |
7204 | ||
7205 | // enum of result types from a parse | |
7206 | using detail::ParseResultType; | |
7207 | ||
7208 | // Result type for parser operation | |
7209 | using detail::ParserResult; | |
7210 | ||
7211 | }} // namespace Catch::clara | |
7212 | ||
7213 | // end clara.hpp | |
7214 | #ifdef __clang__ | |
7215 | #pragma clang diagnostic pop | |
7216 | #endif | |
7217 | ||
7218 | // Restore Clara's value for console width, if present | |
7219 | #ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH | |
7220 | #define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH | |
7221 | #undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH | |
7222 | #endif | |
7223 | ||
7224 | // end catch_clara.h | |
7225 | namespace Catch { | |
7226 | ||
7227 | clara::Parser makeCommandLineParser( ConfigData& config ); | |
7228 | ||
7229 | } // end namespace Catch | |
7230 | ||
7231 | // end catch_commandline.h | |
7232 | #include <fstream> | |
7233 | #include <ctime> | |
7234 | ||
7235 | namespace Catch { | |
7236 | ||
7237 | clara::Parser makeCommandLineParser( ConfigData& config ) { | |
7238 | ||
7239 | using namespace clara; | |
7240 | ||
7241 | auto const setWarning = [&]( std::string const& warning ) { | |
7242 | auto warningSet = [&]() { | |
7243 | if( warning == "NoAssertions" ) | |
7244 | return WarnAbout::NoAssertions; | |
7245 | ||
7246 | if ( warning == "NoTests" ) | |
7247 | return WarnAbout::NoTests; | |
7248 | ||
7249 | return WarnAbout::Nothing; | |
7250 | }(); | |
7251 | ||
7252 | if (warningSet == WarnAbout::Nothing) | |
7253 | return ParserResult::runtimeError( "Unrecognised warning: '" + warning + "'" ); | |
7254 | config.warnings = static_cast<WarnAbout::What>( config.warnings | warningSet ); | |
7255 | return ParserResult::ok( ParseResultType::Matched ); | |
7256 | }; | |
7257 | auto const loadTestNamesFromFile = [&]( std::string const& filename ) { | |
7258 | std::ifstream f( filename.c_str() ); | |
7259 | if( !f.is_open() ) | |
7260 | return ParserResult::runtimeError( "Unable to load input file: '" + filename + "'" ); | |
7261 | ||
7262 | std::string line; | |
7263 | while( std::getline( f, line ) ) { | |
7264 | line = trim(line); | |
7265 | if( !line.empty() && !startsWith( line, '#' ) ) { | |
7266 | if( !startsWith( line, '"' ) ) | |
7267 | line = '"' + line + '"'; | |
7268 | config.testsOrTags.push_back( line + ',' ); | |
7269 | } | |
7270 | } | |
7271 | return ParserResult::ok( ParseResultType::Matched ); | |
7272 | }; | |
7273 | auto const setTestOrder = [&]( std::string const& order ) { | |
7274 | if( startsWith( "declared", order ) ) | |
7275 | config.runOrder = RunTests::InDeclarationOrder; | |
7276 | else if( startsWith( "lexical", order ) ) | |
7277 | config.runOrder = RunTests::InLexicographicalOrder; | |
7278 | else if( startsWith( "random", order ) ) | |
7279 | config.runOrder = RunTests::InRandomOrder; | |
7280 | else | |
7281 | return clara::ParserResult::runtimeError( "Unrecognised ordering: '" + order + "'" ); | |
7282 | return ParserResult::ok( ParseResultType::Matched ); | |
7283 | }; | |
7284 | auto const setRngSeed = [&]( std::string const& seed ) { | |
7285 | if( seed != "time" ) | |
7286 | return clara::detail::convertInto( seed, config.rngSeed ); | |
7287 | config.rngSeed = static_cast<unsigned int>( std::time(nullptr) ); | |
7288 | return ParserResult::ok( ParseResultType::Matched ); | |
7289 | }; | |
7290 | auto const setColourUsage = [&]( std::string const& useColour ) { | |
7291 | auto mode = toLower( useColour ); | |
7292 | ||
7293 | if( mode == "yes" ) | |
7294 | config.useColour = UseColour::Yes; | |
7295 | else if( mode == "no" ) | |
7296 | config.useColour = UseColour::No; | |
7297 | else if( mode == "auto" ) | |
7298 | config.useColour = UseColour::Auto; | |
7299 | else | |
7300 | return ParserResult::runtimeError( "colour mode must be one of: auto, yes or no. '" + useColour + "' not recognised" ); | |
7301 | return ParserResult::ok( ParseResultType::Matched ); | |
7302 | }; | |
7303 | auto const setWaitForKeypress = [&]( std::string const& keypress ) { | |
7304 | auto keypressLc = toLower( keypress ); | |
7305 | if( keypressLc == "start" ) | |
7306 | config.waitForKeypress = WaitForKeypress::BeforeStart; | |
7307 | else if( keypressLc == "exit" ) | |
7308 | config.waitForKeypress = WaitForKeypress::BeforeExit; | |
7309 | else if( keypressLc == "both" ) | |
7310 | config.waitForKeypress = WaitForKeypress::BeforeStartAndExit; | |
7311 | else | |
7312 | return ParserResult::runtimeError( "keypress argument must be one of: start, exit or both. '" + keypress + "' not recognised" ); | |
7313 | return ParserResult::ok( ParseResultType::Matched ); | |
7314 | }; | |
7315 | auto const setVerbosity = [&]( std::string const& verbosity ) { | |
7316 | auto lcVerbosity = toLower( verbosity ); | |
7317 | if( lcVerbosity == "quiet" ) | |
7318 | config.verbosity = Verbosity::Quiet; | |
7319 | else if( lcVerbosity == "normal" ) | |
7320 | config.verbosity = Verbosity::Normal; | |
7321 | else if( lcVerbosity == "high" ) | |
7322 | config.verbosity = Verbosity::High; | |
7323 | else | |
7324 | return ParserResult::runtimeError( "Unrecognised verbosity, '" + verbosity + "'" ); | |
7325 | return ParserResult::ok( ParseResultType::Matched ); | |
7326 | }; | |
7327 | auto const setReporter = [&]( std::string const& reporter ) { | |
7328 | IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); | |
7329 | ||
7330 | auto lcReporter = toLower( reporter ); | |
7331 | auto result = factories.find( lcReporter ); | |
7332 | ||
7333 | if( factories.end() != result ) | |
7334 | config.reporterName = lcReporter; | |
7335 | else | |
7336 | return ParserResult::runtimeError( "Unrecognized reporter, '" + reporter + "'. Check available with --list-reporters" ); | |
7337 | return ParserResult::ok( ParseResultType::Matched ); | |
7338 | }; | |
7339 | ||
7340 | auto cli | |
7341 | = ExeName( config.processName ) | |
7342 | | Help( config.showHelp ) | |
7343 | | Opt( config.listTests ) | |
7344 | ["-l"]["--list-tests"] | |
7345 | ( "list all/matching test cases" ) | |
7346 | | Opt( config.listTags ) | |
7347 | ["-t"]["--list-tags"] | |
7348 | ( "list all/matching tags" ) | |
7349 | | Opt( config.showSuccessfulTests ) | |
7350 | ["-s"]["--success"] | |
7351 | ( "include successful tests in output" ) | |
7352 | | Opt( config.shouldDebugBreak ) | |
7353 | ["-b"]["--break"] | |
7354 | ( "break into debugger on failure" ) | |
7355 | | Opt( config.noThrow ) | |
7356 | ["-e"]["--nothrow"] | |
7357 | ( "skip exception tests" ) | |
7358 | | Opt( config.showInvisibles ) | |
7359 | ["-i"]["--invisibles"] | |
7360 | ( "show invisibles (tabs, newlines)" ) | |
7361 | | Opt( config.outputFilename, "filename" ) | |
7362 | ["-o"]["--out"] | |
7363 | ( "output filename" ) | |
7364 | | Opt( setReporter, "name" ) | |
7365 | ["-r"]["--reporter"] | |
7366 | ( "reporter to use (defaults to console)" ) | |
7367 | | Opt( config.name, "name" ) | |
7368 | ["-n"]["--name"] | |
7369 | ( "suite name" ) | |
7370 | | Opt( [&]( bool ){ config.abortAfter = 1; } ) | |
7371 | ["-a"]["--abort"] | |
7372 | ( "abort at first failure" ) | |
7373 | | Opt( [&]( int x ){ config.abortAfter = x; }, "no. failures" ) | |
7374 | ["-x"]["--abortx"] | |
7375 | ( "abort after x failures" ) | |
7376 | | Opt( setWarning, "warning name" ) | |
7377 | ["-w"]["--warn"] | |
7378 | ( "enable warnings" ) | |
7379 | | Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" ) | |
7380 | ["-d"]["--durations"] | |
7381 | ( "show test durations" ) | |
7382 | | Opt( loadTestNamesFromFile, "filename" ) | |
7383 | ["-f"]["--input-file"] | |
7384 | ( "load test names to run from a file" ) | |
7385 | | Opt( config.filenamesAsTags ) | |
7386 | ["-#"]["--filenames-as-tags"] | |
7387 | ( "adds a tag for the filename" ) | |
7388 | | Opt( config.sectionsToRun, "section name" ) | |
7389 | ["-c"]["--section"] | |
7390 | ( "specify section to run" ) | |
7391 | | Opt( setVerbosity, "quiet|normal|high" ) | |
7392 | ["-v"]["--verbosity"] | |
7393 | ( "set output verbosity" ) | |
7394 | | Opt( config.listTestNamesOnly ) | |
7395 | ["--list-test-names-only"] | |
7396 | ( "list all/matching test cases names only" ) | |
7397 | | Opt( config.listReporters ) | |
7398 | ["--list-reporters"] | |
7399 | ( "list all reporters" ) | |
7400 | | Opt( setTestOrder, "decl|lex|rand" ) | |
7401 | ["--order"] | |
7402 | ( "test case order (defaults to decl)" ) | |
7403 | | Opt( setRngSeed, "'time'|number" ) | |
7404 | ["--rng-seed"] | |
7405 | ( "set a specific seed for random numbers" ) | |
7406 | | Opt( setColourUsage, "yes|no" ) | |
7407 | ["--use-colour"] | |
7408 | ( "should output be colourised" ) | |
7409 | | Opt( config.libIdentify ) | |
7410 | ["--libidentify"] | |
7411 | ( "report name and version according to libidentify standard" ) | |
7412 | | Opt( setWaitForKeypress, "start|exit|both" ) | |
7413 | ["--wait-for-keypress"] | |
7414 | ( "waits for a keypress before exiting" ) | |
7415 | | Opt( config.benchmarkResolutionMultiple, "multiplier" ) | |
7416 | ["--benchmark-resolution-multiple"] | |
7417 | ( "multiple of clock resolution to run benchmarks" ) | |
7418 | ||
7419 | | Arg( config.testsOrTags, "test name|pattern|tags" ) | |
7420 | ( "which test or tests to use" ); | |
7421 | ||
7422 | return cli; | |
7423 | } | |
7424 | ||
7425 | } // end namespace Catch | |
7426 | // end catch_commandline.cpp | |
7427 | // start catch_common.cpp | |
7428 | ||
7429 | #include <cstring> | |
7430 | #include <ostream> | |
7431 | ||
7432 | namespace Catch { | |
7433 | ||
7434 | bool SourceLineInfo::empty() const noexcept { | |
7435 | return file[0] == '\0'; | |
7436 | } | |
7437 | bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const noexcept { | |
7438 | return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0); | |
7439 | } | |
7440 | bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const noexcept { | |
7441 | // We can assume that the same file will usually have the same pointer. | |
7442 | // Thus, if the pointers are the same, there is no point in calling the strcmp | |
7443 | return line < other.line || ( line == other.line && file != other.file && (std::strcmp(file, other.file) < 0)); | |
7444 | } | |
7445 | ||
7446 | std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { | |
7447 | #ifndef __GNUG__ | |
7448 | os << info.file << '(' << info.line << ')'; | |
7449 | #else | |
7450 | os << info.file << ':' << info.line; | |
7451 | #endif | |
7452 | return os; | |
7453 | } | |
7454 | ||
7455 | std::string StreamEndStop::operator+() const { | |
7456 | return std::string(); | |
7457 | } | |
7458 | ||
7459 | NonCopyable::NonCopyable() = default; | |
7460 | NonCopyable::~NonCopyable() = default; | |
7461 | ||
7462 | } | |
7463 | // end catch_common.cpp | |
7464 | // start catch_config.cpp | |
7465 | ||
7466 | namespace Catch { | |
7467 | ||
7468 | Config::Config( ConfigData const& data ) | |
7469 | : m_data( data ), | |
7470 | m_stream( openStream() ) | |
7471 | { | |
7472 | TestSpecParser parser(ITagAliasRegistry::get()); | |
7473 | if (data.testsOrTags.empty()) { | |
7474 | parser.parse("~[.]"); // All not hidden tests | |
7475 | } | |
7476 | else { | |
7477 | m_hasTestFilters = true; | |
7478 | for( auto const& testOrTags : data.testsOrTags ) | |
7479 | parser.parse( testOrTags ); | |
7480 | } | |
7481 | m_testSpec = parser.testSpec(); | |
7482 | } | |
7483 | ||
7484 | std::string const& Config::getFilename() const { | |
7485 | return m_data.outputFilename ; | |
7486 | } | |
7487 | ||
7488 | bool Config::listTests() const { return m_data.listTests; } | |
7489 | bool Config::listTestNamesOnly() const { return m_data.listTestNamesOnly; } | |
7490 | bool Config::listTags() const { return m_data.listTags; } | |
7491 | bool Config::listReporters() const { return m_data.listReporters; } | |
7492 | ||
7493 | std::string Config::getProcessName() const { return m_data.processName; } | |
7494 | std::string const& Config::getReporterName() const { return m_data.reporterName; } | |
7495 | ||
7496 | std::vector<std::string> const& Config::getTestsOrTags() const { return m_data.testsOrTags; } | |
7497 | std::vector<std::string> const& Config::getSectionsToRun() const { return m_data.sectionsToRun; } | |
7498 | ||
7499 | TestSpec const& Config::testSpec() const { return m_testSpec; } | |
7500 | bool Config::hasTestFilters() const { return m_hasTestFilters; } | |
7501 | ||
7502 | bool Config::showHelp() const { return m_data.showHelp; } | |
7503 | ||
7504 | // IConfig interface | |
7505 | bool Config::allowThrows() const { return !m_data.noThrow; } | |
7506 | std::ostream& Config::stream() const { return m_stream->stream(); } | |
7507 | std::string Config::name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } | |
7508 | bool Config::includeSuccessfulResults() const { return m_data.showSuccessfulTests; } | |
7509 | bool Config::warnAboutMissingAssertions() const { return !!(m_data.warnings & WarnAbout::NoAssertions); } | |
7510 | bool Config::warnAboutNoTests() const { return !!(m_data.warnings & WarnAbout::NoTests); } | |
7511 | ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; } | |
7512 | RunTests::InWhatOrder Config::runOrder() const { return m_data.runOrder; } | |
7513 | unsigned int Config::rngSeed() const { return m_data.rngSeed; } | |
7514 | int Config::benchmarkResolutionMultiple() const { return m_data.benchmarkResolutionMultiple; } | |
7515 | UseColour::YesOrNo Config::useColour() const { return m_data.useColour; } | |
7516 | bool Config::shouldDebugBreak() const { return m_data.shouldDebugBreak; } | |
7517 | int Config::abortAfter() const { return m_data.abortAfter; } | |
7518 | bool Config::showInvisibles() const { return m_data.showInvisibles; } | |
7519 | Verbosity Config::verbosity() const { return m_data.verbosity; } | |
7520 | ||
7521 | IStream const* Config::openStream() { | |
7522 | return Catch::makeStream(m_data.outputFilename); | |
7523 | } | |
7524 | ||
7525 | } // end namespace Catch | |
7526 | // end catch_config.cpp | |
7527 | // start catch_console_colour.cpp | |
7528 | ||
7529 | #if defined(__clang__) | |
7530 | # pragma clang diagnostic push | |
7531 | # pragma clang diagnostic ignored "-Wexit-time-destructors" | |
7532 | #endif | |
7533 | ||
7534 | // start catch_errno_guard.h | |
7535 | ||
7536 | namespace Catch { | |
7537 | ||
7538 | class ErrnoGuard { | |
7539 | public: | |
7540 | ErrnoGuard(); | |
7541 | ~ErrnoGuard(); | |
7542 | private: | |
7543 | int m_oldErrno; | |
7544 | }; | |
7545 | ||
7546 | } | |
7547 | ||
7548 | // end catch_errno_guard.h | |
7549 | #include <sstream> | |
7550 | ||
7551 | namespace Catch { | |
7552 | namespace { | |
7553 | ||
7554 | struct IColourImpl { | |
7555 | virtual ~IColourImpl() = default; | |
7556 | virtual void use( Colour::Code _colourCode ) = 0; | |
7557 | }; | |
7558 | ||
7559 | struct NoColourImpl : IColourImpl { | |
7560 | void use( Colour::Code ) {} | |
7561 | ||
7562 | static IColourImpl* instance() { | |
7563 | static NoColourImpl s_instance; | |
7564 | return &s_instance; | |
7565 | } | |
7566 | }; | |
7567 | ||
7568 | } // anon namespace | |
7569 | } // namespace Catch | |
7570 | ||
7571 | #if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI ) | |
7572 | # ifdef CATCH_PLATFORM_WINDOWS | |
7573 | # define CATCH_CONFIG_COLOUR_WINDOWS | |
7574 | # else | |
7575 | # define CATCH_CONFIG_COLOUR_ANSI | |
7576 | # endif | |
7577 | #endif | |
7578 | ||
7579 | #if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) ///////////////////////////////////////// | |
7580 | ||
7581 | namespace Catch { | |
7582 | namespace { | |
7583 | ||
7584 | class Win32ColourImpl : public IColourImpl { | |
7585 | public: | |
7586 | Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) | |
7587 | { | |
7588 | CONSOLE_SCREEN_BUFFER_INFO csbiInfo; | |
7589 | GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); | |
7590 | originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY ); | |
7591 | originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY ); | |
7592 | } | |
7593 | ||
7594 | virtual void use( Colour::Code _colourCode ) override { | |
7595 | switch( _colourCode ) { | |
7596 | case Colour::None: return setTextAttribute( originalForegroundAttributes ); | |
7597 | case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); | |
7598 | case Colour::Red: return setTextAttribute( FOREGROUND_RED ); | |
7599 | case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); | |
7600 | case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE ); | |
7601 | case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN ); | |
7602 | case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN ); | |
7603 | case Colour::Grey: return setTextAttribute( 0 ); | |
7604 | ||
7605 | case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY ); | |
7606 | case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED ); | |
7607 | case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); | |
7608 | case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); | |
7609 | case Colour::BrightYellow: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN ); | |
7610 | ||
7611 | case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" ); | |
7612 | ||
7613 | default: | |
7614 | CATCH_ERROR( "Unknown colour requested" ); | |
7615 | } | |
7616 | } | |
7617 | ||
7618 | private: | |
7619 | void setTextAttribute( WORD _textAttribute ) { | |
7620 | SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes ); | |
7621 | } | |
7622 | HANDLE stdoutHandle; | |
7623 | WORD originalForegroundAttributes; | |
7624 | WORD originalBackgroundAttributes; | |
7625 | }; | |
7626 | ||
7627 | IColourImpl* platformColourInstance() { | |
7628 | static Win32ColourImpl s_instance; | |
7629 | ||
7630 | IConfigPtr config = getCurrentContext().getConfig(); | |
7631 | UseColour::YesOrNo colourMode = config | |
7632 | ? config->useColour() | |
7633 | : UseColour::Auto; | |
7634 | if( colourMode == UseColour::Auto ) | |
7635 | colourMode = UseColour::Yes; | |
7636 | return colourMode == UseColour::Yes | |
7637 | ? &s_instance | |
7638 | : NoColourImpl::instance(); | |
7639 | } | |
7640 | ||
7641 | } // end anon namespace | |
7642 | } // end namespace Catch | |
7643 | ||
7644 | #elif defined( CATCH_CONFIG_COLOUR_ANSI ) ////////////////////////////////////// | |
7645 | ||
7646 | #include <unistd.h> | |
7647 | ||
7648 | namespace Catch { | |
7649 | namespace { | |
7650 | ||
7651 | // use POSIX/ ANSI console terminal codes | |
7652 | // Thanks to Adam Strzelecki for original contribution | |
7653 | // (http://github.com/nanoant) | |
7654 | // https://github.com/philsquared/Catch/pull/131 | |
7655 | class PosixColourImpl : public IColourImpl { | |
7656 | public: | |
7657 | virtual void use( Colour::Code _colourCode ) override { | |
7658 | switch( _colourCode ) { | |
7659 | case Colour::None: | |
7660 | case Colour::White: return setColour( "[0m" ); | |
7661 | case Colour::Red: return setColour( "[0;31m" ); | |
7662 | case Colour::Green: return setColour( "[0;32m" ); | |
7663 | case Colour::Blue: return setColour( "[0;34m" ); | |
7664 | case Colour::Cyan: return setColour( "[0;36m" ); | |
7665 | case Colour::Yellow: return setColour( "[0;33m" ); | |
7666 | case Colour::Grey: return setColour( "[1;30m" ); | |
7667 | ||
7668 | case Colour::LightGrey: return setColour( "[0;37m" ); | |
7669 | case Colour::BrightRed: return setColour( "[1;31m" ); | |
7670 | case Colour::BrightGreen: return setColour( "[1;32m" ); | |
7671 | case Colour::BrightWhite: return setColour( "[1;37m" ); | |
7672 | case Colour::BrightYellow: return setColour( "[1;33m" ); | |
7673 | ||
7674 | case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" ); | |
7675 | default: CATCH_INTERNAL_ERROR( "Unknown colour requested" ); | |
7676 | } | |
7677 | } | |
7678 | static IColourImpl* instance() { | |
7679 | static PosixColourImpl s_instance; | |
7680 | return &s_instance; | |
7681 | } | |
7682 | ||
7683 | private: | |
7684 | void setColour( const char* _escapeCode ) { | |
7685 | Catch::cout() << '\033' << _escapeCode; | |
7686 | } | |
7687 | }; | |
7688 | ||
7689 | bool useColourOnPlatform() { | |
7690 | return | |
7691 | #ifdef CATCH_PLATFORM_MAC | |
7692 | !isDebuggerActive() && | |
7693 | #endif | |
7694 | #if !(defined(__DJGPP__) && defined(__STRICT_ANSI__)) | |
7695 | isatty(STDOUT_FILENO) | |
7696 | #else | |
7697 | false | |
7698 | #endif | |
7699 | ; | |
7700 | } | |
7701 | IColourImpl* platformColourInstance() { | |
7702 | ErrnoGuard guard; | |
7703 | IConfigPtr config = getCurrentContext().getConfig(); | |
7704 | UseColour::YesOrNo colourMode = config | |
7705 | ? config->useColour() | |
7706 | : UseColour::Auto; | |
7707 | if( colourMode == UseColour::Auto ) | |
7708 | colourMode = useColourOnPlatform() | |
7709 | ? UseColour::Yes | |
7710 | : UseColour::No; | |
7711 | return colourMode == UseColour::Yes | |
7712 | ? PosixColourImpl::instance() | |
7713 | : NoColourImpl::instance(); | |
7714 | } | |
7715 | ||
7716 | } // end anon namespace | |
7717 | } // end namespace Catch | |
7718 | ||
7719 | #else // not Windows or ANSI /////////////////////////////////////////////// | |
7720 | ||
7721 | namespace Catch { | |
7722 | ||
7723 | static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); } | |
7724 | ||
7725 | } // end namespace Catch | |
7726 | ||
7727 | #endif // Windows/ ANSI/ None | |
7728 | ||
7729 | namespace Catch { | |
7730 | ||
7731 | Colour::Colour( Code _colourCode ) { use( _colourCode ); } | |
7732 | Colour::Colour( Colour&& rhs ) noexcept { | |
7733 | m_moved = rhs.m_moved; | |
7734 | rhs.m_moved = true; | |
7735 | } | |
7736 | Colour& Colour::operator=( Colour&& rhs ) noexcept { | |
7737 | m_moved = rhs.m_moved; | |
7738 | rhs.m_moved = true; | |
7739 | return *this; | |
7740 | } | |
7741 | ||
7742 | Colour::~Colour(){ if( !m_moved ) use( None ); } | |
7743 | ||
7744 | void Colour::use( Code _colourCode ) { | |
7745 | static IColourImpl* impl = platformColourInstance(); | |
7746 | impl->use( _colourCode ); | |
7747 | } | |
7748 | ||
7749 | std::ostream& operator << ( std::ostream& os, Colour const& ) { | |
7750 | return os; | |
7751 | } | |
7752 | ||
7753 | } // end namespace Catch | |
7754 | ||
7755 | #if defined(__clang__) | |
7756 | # pragma clang diagnostic pop | |
7757 | #endif | |
7758 | ||
7759 | // end catch_console_colour.cpp | |
7760 | // start catch_context.cpp | |
7761 | ||
7762 | namespace Catch { | |
7763 | ||
7764 | class Context : public IMutableContext, NonCopyable { | |
7765 | ||
7766 | public: // IContext | |
7767 | virtual IResultCapture* getResultCapture() override { | |
7768 | return m_resultCapture; | |
7769 | } | |
7770 | virtual IRunner* getRunner() override { | |
7771 | return m_runner; | |
7772 | } | |
7773 | ||
7774 | virtual IConfigPtr const& getConfig() const override { | |
7775 | return m_config; | |
7776 | } | |
7777 | ||
7778 | virtual ~Context() override; | |
7779 | ||
7780 | public: // IMutableContext | |
7781 | virtual void setResultCapture( IResultCapture* resultCapture ) override { | |
7782 | m_resultCapture = resultCapture; | |
7783 | } | |
7784 | virtual void setRunner( IRunner* runner ) override { | |
7785 | m_runner = runner; | |
7786 | } | |
7787 | virtual void setConfig( IConfigPtr const& config ) override { | |
7788 | m_config = config; | |
7789 | } | |
7790 | ||
7791 | friend IMutableContext& getCurrentMutableContext(); | |
7792 | ||
7793 | private: | |
7794 | IConfigPtr m_config; | |
7795 | IRunner* m_runner = nullptr; | |
7796 | IResultCapture* m_resultCapture = nullptr; | |
7797 | }; | |
7798 | ||
7799 | IMutableContext *IMutableContext::currentContext = nullptr; | |
7800 | ||
7801 | void IMutableContext::createContext() | |
7802 | { | |
7803 | currentContext = new Context(); | |
7804 | } | |
7805 | ||
7806 | void cleanUpContext() { | |
7807 | delete IMutableContext::currentContext; | |
7808 | IMutableContext::currentContext = nullptr; | |
7809 | } | |
7810 | IContext::~IContext() = default; | |
7811 | IMutableContext::~IMutableContext() = default; | |
7812 | Context::~Context() = default; | |
7813 | } | |
7814 | // end catch_context.cpp | |
7815 | // start catch_debug_console.cpp | |
7816 | ||
7817 | // start catch_debug_console.h | |
7818 | ||
7819 | #include <string> | |
7820 | ||
7821 | namespace Catch { | |
7822 | void writeToDebugConsole( std::string const& text ); | |
7823 | } | |
7824 | ||
7825 | // end catch_debug_console.h | |
7826 | #ifdef CATCH_PLATFORM_WINDOWS | |
7827 | ||
7828 | namespace Catch { | |
7829 | void writeToDebugConsole( std::string const& text ) { | |
7830 | ::OutputDebugStringA( text.c_str() ); | |
7831 | } | |
7832 | } | |
7833 | ||
7834 | #else | |
7835 | ||
7836 | namespace Catch { | |
7837 | void writeToDebugConsole( std::string const& text ) { | |
7838 | // !TBD: Need a version for Mac/ XCode and other IDEs | |
7839 | Catch::cout() << text; | |
7840 | } | |
7841 | } | |
7842 | ||
7843 | #endif // Platform | |
7844 | // end catch_debug_console.cpp | |
7845 | // start catch_debugger.cpp | |
7846 | ||
7847 | #ifdef CATCH_PLATFORM_MAC | |
7848 | ||
7849 | # include <assert.h> | |
7850 | # include <stdbool.h> | |
7851 | # include <sys/types.h> | |
7852 | # include <unistd.h> | |
7853 | # include <sys/sysctl.h> | |
7854 | # include <cstddef> | |
7855 | # include <ostream> | |
7856 | ||
7857 | namespace Catch { | |
7858 | ||
7859 | // The following function is taken directly from the following technical note: | |
7860 | // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html | |
7861 | ||
7862 | // Returns true if the current process is being debugged (either | |
7863 | // running under the debugger or has a debugger attached post facto). | |
7864 | bool isDebuggerActive(){ | |
7865 | ||
7866 | int mib[4]; | |
7867 | struct kinfo_proc info; | |
7868 | std::size_t size; | |
7869 | ||
7870 | // Initialize the flags so that, if sysctl fails for some bizarre | |
7871 | // reason, we get a predictable result. | |
7872 | ||
7873 | info.kp_proc.p_flag = 0; | |
7874 | ||
7875 | // Initialize mib, which tells sysctl the info we want, in this case | |
7876 | // we're looking for information about a specific process ID. | |
7877 | ||
7878 | mib[0] = CTL_KERN; | |
7879 | mib[1] = KERN_PROC; | |
7880 | mib[2] = KERN_PROC_PID; | |
7881 | mib[3] = getpid(); | |
7882 | ||
7883 | // Call sysctl. | |
7884 | ||
7885 | size = sizeof(info); | |
7886 | if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, nullptr, 0) != 0 ) { | |
7887 | Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; | |
7888 | return false; | |
7889 | } | |
7890 | ||
7891 | // We're being debugged if the P_TRACED flag is set. | |
7892 | ||
7893 | return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); | |
7894 | } | |
7895 | } // namespace Catch | |
7896 | ||
7897 | #elif defined(CATCH_PLATFORM_LINUX) | |
7898 | #include <fstream> | |
7899 | #include <string> | |
7900 | ||
7901 | namespace Catch{ | |
7902 | // The standard POSIX way of detecting a debugger is to attempt to | |
7903 | // ptrace() the process, but this needs to be done from a child and not | |
7904 | // this process itself to still allow attaching to this process later | |
7905 | // if wanted, so is rather heavy. Under Linux we have the PID of the | |
7906 | // "debugger" (which doesn't need to be gdb, of course, it could also | |
7907 | // be strace, for example) in /proc/$PID/status, so just get it from | |
7908 | // there instead. | |
7909 | bool isDebuggerActive(){ | |
7910 | // Libstdc++ has a bug, where std::ifstream sets errno to 0 | |
7911 | // This way our users can properly assert over errno values | |
7912 | ErrnoGuard guard; | |
7913 | std::ifstream in("/proc/self/status"); | |
7914 | for( std::string line; std::getline(in, line); ) { | |
7915 | static const int PREFIX_LEN = 11; | |
7916 | if( line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0 ) { | |
7917 | // We're traced if the PID is not 0 and no other PID starts | |
7918 | // with 0 digit, so it's enough to check for just a single | |
7919 | // character. | |
7920 | return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0'; | |
7921 | } | |
7922 | } | |
7923 | ||
7924 | return false; | |
7925 | } | |
7926 | } // namespace Catch | |
7927 | #elif defined(_MSC_VER) | |
7928 | extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); | |
7929 | namespace Catch { | |
7930 | bool isDebuggerActive() { | |
7931 | return IsDebuggerPresent() != 0; | |
7932 | } | |
7933 | } | |
7934 | #elif defined(__MINGW32__) | |
7935 | extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); | |
7936 | namespace Catch { | |
7937 | bool isDebuggerActive() { | |
7938 | return IsDebuggerPresent() != 0; | |
7939 | } | |
7940 | } | |
7941 | #else | |
7942 | namespace Catch { | |
7943 | bool isDebuggerActive() { return false; } | |
7944 | } | |
7945 | #endif // Platform | |
7946 | // end catch_debugger.cpp | |
7947 | // start catch_decomposer.cpp | |
7948 | ||
7949 | namespace Catch { | |
7950 | ||
7951 | ITransientExpression::~ITransientExpression() = default; | |
7952 | ||
7953 | void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ) { | |
7954 | if( lhs.size() + rhs.size() < 40 && | |
7955 | lhs.find('\n') == std::string::npos && | |
7956 | rhs.find('\n') == std::string::npos ) | |
7957 | os << lhs << " " << op << " " << rhs; | |
7958 | else | |
7959 | os << lhs << "\n" << op << "\n" << rhs; | |
7960 | } | |
7961 | } | |
7962 | // end catch_decomposer.cpp | |
7963 | // start catch_enforce.cpp | |
7964 | ||
7965 | namespace Catch { | |
7966 | #if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER) | |
7967 | [[noreturn]] | |
7968 | void throw_exception(std::exception const& e) { | |
7969 | Catch::cerr() << "Catch will terminate because it needed to throw an exception.\n" | |
7970 | << "The message was: " << e.what() << '\n'; | |
7971 | std::terminate(); | |
7972 | } | |
7973 | #endif | |
7974 | } // namespace Catch; | |
7975 | // end catch_enforce.cpp | |
7976 | // start catch_errno_guard.cpp | |
7977 | ||
7978 | #include <cerrno> | |
7979 | ||
7980 | namespace Catch { | |
7981 | ErrnoGuard::ErrnoGuard():m_oldErrno(errno){} | |
7982 | ErrnoGuard::~ErrnoGuard() { errno = m_oldErrno; } | |
7983 | } | |
7984 | // end catch_errno_guard.cpp | |
7985 | // start catch_exception_translator_registry.cpp | |
7986 | ||
7987 | // start catch_exception_translator_registry.h | |
7988 | ||
7989 | #include <vector> | |
7990 | #include <string> | |
7991 | #include <memory> | |
7992 | ||
7993 | namespace Catch { | |
7994 | ||
7995 | class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { | |
7996 | public: | |
7997 | ~ExceptionTranslatorRegistry(); | |
7998 | virtual void registerTranslator( const IExceptionTranslator* translator ); | |
7999 | virtual std::string translateActiveException() const override; | |
8000 | std::string tryTranslators() const; | |
8001 | ||
8002 | private: | |
8003 | std::vector<std::unique_ptr<IExceptionTranslator const>> m_translators; | |
8004 | }; | |
8005 | } | |
8006 | ||
8007 | // end catch_exception_translator_registry.h | |
8008 | #ifdef __OBJC__ | |
8009 | #import "Foundation/Foundation.h" | |
8010 | #endif | |
8011 | ||
8012 | namespace Catch { | |
8013 | ||
8014 | ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() { | |
8015 | } | |
8016 | ||
8017 | void ExceptionTranslatorRegistry::registerTranslator( const IExceptionTranslator* translator ) { | |
8018 | m_translators.push_back( std::unique_ptr<const IExceptionTranslator>( translator ) ); | |
8019 | } | |
8020 | ||
8021 | #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) | |
8022 | std::string ExceptionTranslatorRegistry::translateActiveException() const { | |
8023 | try { | |
8024 | #ifdef __OBJC__ | |
8025 | // In Objective-C try objective-c exceptions first | |
8026 | @try { | |
8027 | return tryTranslators(); | |
8028 | } | |
8029 | @catch (NSException *exception) { | |
8030 | return Catch::Detail::stringify( [exception description] ); | |
8031 | } | |
8032 | #else | |
8033 | // Compiling a mixed mode project with MSVC means that CLR | |
8034 | // exceptions will be caught in (...) as well. However, these | |
8035 | // do not fill-in std::current_exception and thus lead to crash | |
8036 | // when attempting rethrow. | |
8037 | // /EHa switch also causes structured exceptions to be caught | |
8038 | // here, but they fill-in current_exception properly, so | |
8039 | // at worst the output should be a little weird, instead of | |
8040 | // causing a crash. | |
8041 | if (std::current_exception() == nullptr) { | |
8042 | return "Non C++ exception. Possibly a CLR exception."; | |
8043 | } | |
8044 | return tryTranslators(); | |
8045 | #endif | |
8046 | } | |
8047 | catch( TestFailureException& ) { | |
8048 | std::rethrow_exception(std::current_exception()); | |
8049 | } | |
8050 | catch( std::exception& ex ) { | |
8051 | return ex.what(); | |
8052 | } | |
8053 | catch( std::string& msg ) { | |
8054 | return msg; | |
8055 | } | |
8056 | catch( const char* msg ) { | |
8057 | return msg; | |
8058 | } | |
8059 | catch(...) { | |
8060 | return "Unknown exception"; | |
8061 | } | |
8062 | } | |
8063 | ||
8064 | #else // ^^ Exceptions are enabled // Exceptions are disabled vv | |
8065 | std::string ExceptionTranslatorRegistry::translateActiveException() const { | |
8066 | CATCH_INTERNAL_ERROR("Attempted to translate active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!"); | |
8067 | } | |
8068 | #endif | |
8069 | ||
8070 | std::string ExceptionTranslatorRegistry::tryTranslators() const { | |
8071 | if( m_translators.empty() ) | |
8072 | std::rethrow_exception(std::current_exception()); | |
8073 | else | |
8074 | return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() ); | |
8075 | } | |
8076 | } | |
8077 | // end catch_exception_translator_registry.cpp | |
8078 | // start catch_fatal_condition.cpp | |
8079 | ||
8080 | #if defined(__GNUC__) | |
8081 | # pragma GCC diagnostic push | |
8082 | # pragma GCC diagnostic ignored "-Wmissing-field-initializers" | |
8083 | #endif | |
8084 | ||
8085 | #if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS ) | |
8086 | ||
8087 | namespace { | |
8088 | // Report the error condition | |
8089 | void reportFatal( char const * const message ) { | |
8090 | Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message ); | |
8091 | } | |
8092 | } | |
8093 | ||
8094 | #endif // signals/SEH handling | |
8095 | ||
8096 | #if defined( CATCH_CONFIG_WINDOWS_SEH ) | |
8097 | ||
8098 | namespace Catch { | |
8099 | struct SignalDefs { DWORD id; const char* name; }; | |
8100 | ||
8101 | // There is no 1-1 mapping between signals and windows exceptions. | |
8102 | // Windows can easily distinguish between SO and SigSegV, | |
8103 | // but SigInt, SigTerm, etc are handled differently. | |
8104 | static SignalDefs signalDefs[] = { | |
8105 | { EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal" }, | |
8106 | { EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" }, | |
8107 | { EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" }, | |
8108 | { EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" }, | |
8109 | }; | |
8110 | ||
8111 | LONG CALLBACK FatalConditionHandler::handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) { | |
8112 | for (auto const& def : signalDefs) { | |
8113 | if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) { | |
8114 | reportFatal(def.name); | |
8115 | } | |
8116 | } | |
8117 | // If its not an exception we care about, pass it along. | |
8118 | // This stops us from eating debugger breaks etc. | |
8119 | return EXCEPTION_CONTINUE_SEARCH; | |
8120 | } | |
8121 | ||
8122 | FatalConditionHandler::FatalConditionHandler() { | |
8123 | isSet = true; | |
8124 | // 32k seems enough for Catch to handle stack overflow, | |
8125 | // but the value was found experimentally, so there is no strong guarantee | |
8126 | guaranteeSize = 32 * 1024; | |
8127 | exceptionHandlerHandle = nullptr; | |
8128 | // Register as first handler in current chain | |
8129 | exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException); | |
8130 | // Pass in guarantee size to be filled | |
8131 | SetThreadStackGuarantee(&guaranteeSize); | |
8132 | } | |
8133 | ||
8134 | void FatalConditionHandler::reset() { | |
8135 | if (isSet) { | |
8136 | RemoveVectoredExceptionHandler(exceptionHandlerHandle); | |
8137 | SetThreadStackGuarantee(&guaranteeSize); | |
8138 | exceptionHandlerHandle = nullptr; | |
8139 | isSet = false; | |
8140 | } | |
8141 | } | |
8142 | ||
8143 | FatalConditionHandler::~FatalConditionHandler() { | |
8144 | reset(); | |
8145 | } | |
8146 | ||
8147 | bool FatalConditionHandler::isSet = false; | |
8148 | ULONG FatalConditionHandler::guaranteeSize = 0; | |
8149 | PVOID FatalConditionHandler::exceptionHandlerHandle = nullptr; | |
8150 | ||
8151 | } // namespace Catch | |
8152 | ||
8153 | #elif defined( CATCH_CONFIG_POSIX_SIGNALS ) | |
8154 | ||
8155 | namespace Catch { | |
8156 | ||
8157 | struct SignalDefs { | |
8158 | int id; | |
8159 | const char* name; | |
8160 | }; | |
8161 | ||
8162 | // 32kb for the alternate stack seems to be sufficient. However, this value | |
8163 | // is experimentally determined, so that's not guaranteed. | |
8164 | constexpr static std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ; | |
8165 | ||
8166 | static SignalDefs signalDefs[] = { | |
8167 | { SIGINT, "SIGINT - Terminal interrupt signal" }, | |
8168 | { SIGILL, "SIGILL - Illegal instruction signal" }, | |
8169 | { SIGFPE, "SIGFPE - Floating point error signal" }, | |
8170 | { SIGSEGV, "SIGSEGV - Segmentation violation signal" }, | |
8171 | { SIGTERM, "SIGTERM - Termination request signal" }, | |
8172 | { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } | |
8173 | }; | |
8174 | ||
8175 | void FatalConditionHandler::handleSignal( int sig ) { | |
8176 | char const * name = "<unknown signal>"; | |
8177 | for (auto const& def : signalDefs) { | |
8178 | if (sig == def.id) { | |
8179 | name = def.name; | |
8180 | break; | |
8181 | } | |
8182 | } | |
8183 | reset(); | |
8184 | reportFatal(name); | |
8185 | raise( sig ); | |
8186 | } | |
8187 | ||
8188 | FatalConditionHandler::FatalConditionHandler() { | |
8189 | isSet = true; | |
8190 | stack_t sigStack; | |
8191 | sigStack.ss_sp = altStackMem; | |
8192 | sigStack.ss_size = sigStackSize; | |
8193 | sigStack.ss_flags = 0; | |
8194 | sigaltstack(&sigStack, &oldSigStack); | |
8195 | struct sigaction sa = { }; | |
8196 | ||
8197 | sa.sa_handler = handleSignal; | |
8198 | sa.sa_flags = SA_ONSTACK; | |
8199 | for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) { | |
8200 | sigaction(signalDefs[i].id, &sa, &oldSigActions[i]); | |
8201 | } | |
8202 | } | |
8203 | ||
8204 | FatalConditionHandler::~FatalConditionHandler() { | |
8205 | reset(); | |
8206 | } | |
8207 | ||
8208 | void FatalConditionHandler::reset() { | |
8209 | if( isSet ) { | |
8210 | // Set signals back to previous values -- hopefully nobody overwrote them in the meantime | |
8211 | for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) { | |
8212 | sigaction(signalDefs[i].id, &oldSigActions[i], nullptr); | |
8213 | } | |
8214 | // Return the old stack | |
8215 | sigaltstack(&oldSigStack, nullptr); | |
8216 | isSet = false; | |
8217 | } | |
8218 | } | |
8219 | ||
8220 | bool FatalConditionHandler::isSet = false; | |
8221 | struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {}; | |
8222 | stack_t FatalConditionHandler::oldSigStack = {}; | |
8223 | char FatalConditionHandler::altStackMem[sigStackSize] = {}; | |
8224 | ||
8225 | } // namespace Catch | |
8226 | ||
8227 | #else | |
8228 | ||
8229 | namespace Catch { | |
8230 | void FatalConditionHandler::reset() {} | |
8231 | } | |
8232 | ||
8233 | #endif // signals/SEH handling | |
8234 | ||
8235 | #if defined(__GNUC__) | |
8236 | # pragma GCC diagnostic pop | |
8237 | #endif | |
8238 | // end catch_fatal_condition.cpp | |
8239 | // start catch_generators.cpp | |
8240 | ||
8241 | // start catch_random_number_generator.h | |
8242 | ||
8243 | #include <algorithm> | |
8244 | #include <random> | |
8245 | ||
8246 | namespace Catch { | |
8247 | ||
8248 | struct IConfig; | |
8249 | ||
8250 | std::mt19937& rng(); | |
8251 | void seedRng( IConfig const& config ); | |
8252 | unsigned int rngSeed(); | |
8253 | ||
8254 | } | |
8255 | ||
8256 | // end catch_random_number_generator.h | |
8257 | #include <limits> | |
8258 | #include <set> | |
8259 | ||
8260 | namespace Catch { | |
8261 | ||
8262 | IGeneratorTracker::~IGeneratorTracker() {} | |
8263 | ||
8264 | namespace Generators { | |
8265 | ||
8266 | GeneratorBase::~GeneratorBase() {} | |
8267 | ||
8268 | std::vector<size_t> randomiseIndices( size_t selectionSize, size_t sourceSize ) { | |
8269 | ||
8270 | assert( selectionSize <= sourceSize ); | |
8271 | std::vector<size_t> indices; | |
8272 | indices.reserve( selectionSize ); | |
8273 | std::uniform_int_distribution<size_t> uid( 0, sourceSize-1 ); | |
8274 | ||
8275 | std::set<size_t> seen; | |
8276 | // !TBD: improve this algorithm | |
8277 | while( indices.size() < selectionSize ) { | |
8278 | auto index = uid( rng() ); | |
8279 | if( seen.insert( index ).second ) | |
8280 | indices.push_back( index ); | |
8281 | } | |
8282 | return indices; | |
8283 | } | |
8284 | ||
8285 | auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { | |
8286 | return getResultCapture().acquireGeneratorTracker( lineInfo ); | |
8287 | } | |
8288 | ||
8289 | template<> | |
8290 | auto all<int>() -> Generator<int> { | |
8291 | return range( std::numeric_limits<int>::min(), std::numeric_limits<int>::max() ); | |
8292 | } | |
8293 | ||
8294 | } // namespace Generators | |
8295 | } // namespace Catch | |
8296 | // end catch_generators.cpp | |
8297 | // start catch_interfaces_capture.cpp | |
8298 | ||
8299 | namespace Catch { | |
8300 | IResultCapture::~IResultCapture() = default; | |
8301 | } | |
8302 | // end catch_interfaces_capture.cpp | |
8303 | // start catch_interfaces_config.cpp | |
8304 | ||
8305 | namespace Catch { | |
8306 | IConfig::~IConfig() = default; | |
8307 | } | |
8308 | // end catch_interfaces_config.cpp | |
8309 | // start catch_interfaces_exception.cpp | |
8310 | ||
8311 | namespace Catch { | |
8312 | IExceptionTranslator::~IExceptionTranslator() = default; | |
8313 | IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() = default; | |
8314 | } | |
8315 | // end catch_interfaces_exception.cpp | |
8316 | // start catch_interfaces_registry_hub.cpp | |
8317 | ||
8318 | namespace Catch { | |
8319 | IRegistryHub::~IRegistryHub() = default; | |
8320 | IMutableRegistryHub::~IMutableRegistryHub() = default; | |
8321 | } | |
8322 | // end catch_interfaces_registry_hub.cpp | |
8323 | // start catch_interfaces_reporter.cpp | |
8324 | ||
8325 | // start catch_reporter_listening.h | |
8326 | ||
8327 | namespace Catch { | |
8328 | ||
8329 | class ListeningReporter : public IStreamingReporter { | |
8330 | using Reporters = std::vector<IStreamingReporterPtr>; | |
8331 | Reporters m_listeners; | |
8332 | IStreamingReporterPtr m_reporter = nullptr; | |
8333 | ReporterPreferences m_preferences; | |
8334 | ||
8335 | public: | |
8336 | ListeningReporter(); | |
8337 | ||
8338 | void addListener( IStreamingReporterPtr&& listener ); | |
8339 | void addReporter( IStreamingReporterPtr&& reporter ); | |
8340 | ||
8341 | public: // IStreamingReporter | |
8342 | ||
8343 | ReporterPreferences getPreferences() const override; | |
8344 | ||
8345 | void noMatchingTestCases( std::string const& spec ) override; | |
8346 | ||
8347 | static std::set<Verbosity> getSupportedVerbosities(); | |
8348 | ||
8349 | void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) override; | |
8350 | void benchmarkEnded( BenchmarkStats const& benchmarkStats ) override; | |
8351 | ||
8352 | void testRunStarting( TestRunInfo const& testRunInfo ) override; | |
8353 | void testGroupStarting( GroupInfo const& groupInfo ) override; | |
8354 | void testCaseStarting( TestCaseInfo const& testInfo ) override; | |
8355 | void sectionStarting( SectionInfo const& sectionInfo ) override; | |
8356 | void assertionStarting( AssertionInfo const& assertionInfo ) override; | |
8357 | ||
8358 | // The return value indicates if the messages buffer should be cleared: | |
8359 | bool assertionEnded( AssertionStats const& assertionStats ) override; | |
8360 | void sectionEnded( SectionStats const& sectionStats ) override; | |
8361 | void testCaseEnded( TestCaseStats const& testCaseStats ) override; | |
8362 | void testGroupEnded( TestGroupStats const& testGroupStats ) override; | |
8363 | void testRunEnded( TestRunStats const& testRunStats ) override; | |
8364 | ||
8365 | void skipTest( TestCaseInfo const& testInfo ) override; | |
8366 | bool isMulti() const override; | |
8367 | ||
8368 | }; | |
8369 | ||
8370 | } // end namespace Catch | |
8371 | ||
8372 | // end catch_reporter_listening.h | |
8373 | namespace Catch { | |
8374 | ||
8375 | ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig ) | |
8376 | : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} | |
8377 | ||
8378 | ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream ) | |
8379 | : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} | |
8380 | ||
8381 | std::ostream& ReporterConfig::stream() const { return *m_stream; } | |
8382 | IConfigPtr ReporterConfig::fullConfig() const { return m_fullConfig; } | |
8383 | ||
8384 | TestRunInfo::TestRunInfo( std::string const& _name ) : name( _name ) {} | |
8385 | ||
8386 | GroupInfo::GroupInfo( std::string const& _name, | |
8387 | std::size_t _groupIndex, | |
8388 | std::size_t _groupsCount ) | |
8389 | : name( _name ), | |
8390 | groupIndex( _groupIndex ), | |
8391 | groupsCounts( _groupsCount ) | |
8392 | {} | |
8393 | ||
8394 | AssertionStats::AssertionStats( AssertionResult const& _assertionResult, | |
8395 | std::vector<MessageInfo> const& _infoMessages, | |
8396 | Totals const& _totals ) | |
8397 | : assertionResult( _assertionResult ), | |
8398 | infoMessages( _infoMessages ), | |
8399 | totals( _totals ) | |
8400 | { | |
8401 | assertionResult.m_resultData.lazyExpression.m_transientExpression = _assertionResult.m_resultData.lazyExpression.m_transientExpression; | |
8402 | ||
8403 | if( assertionResult.hasMessage() ) { | |
8404 | // Copy message into messages list. | |
8405 | // !TBD This should have been done earlier, somewhere | |
8406 | MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); | |
8407 | builder << assertionResult.getMessage(); | |
8408 | builder.m_info.message = builder.m_stream.str(); | |
8409 | ||
8410 | infoMessages.push_back( builder.m_info ); | |
8411 | } | |
8412 | } | |
8413 | ||
8414 | AssertionStats::~AssertionStats() = default; | |
8415 | ||
8416 | SectionStats::SectionStats( SectionInfo const& _sectionInfo, | |
8417 | Counts const& _assertions, | |
8418 | double _durationInSeconds, | |
8419 | bool _missingAssertions ) | |
8420 | : sectionInfo( _sectionInfo ), | |
8421 | assertions( _assertions ), | |
8422 | durationInSeconds( _durationInSeconds ), | |
8423 | missingAssertions( _missingAssertions ) | |
8424 | {} | |
8425 | ||
8426 | SectionStats::~SectionStats() = default; | |
8427 | ||
8428 | TestCaseStats::TestCaseStats( TestCaseInfo const& _testInfo, | |
8429 | Totals const& _totals, | |
8430 | std::string const& _stdOut, | |
8431 | std::string const& _stdErr, | |
8432 | bool _aborting ) | |
8433 | : testInfo( _testInfo ), | |
8434 | totals( _totals ), | |
8435 | stdOut( _stdOut ), | |
8436 | stdErr( _stdErr ), | |
8437 | aborting( _aborting ) | |
8438 | {} | |
8439 | ||
8440 | TestCaseStats::~TestCaseStats() = default; | |
8441 | ||
8442 | TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo, | |
8443 | Totals const& _totals, | |
8444 | bool _aborting ) | |
8445 | : groupInfo( _groupInfo ), | |
8446 | totals( _totals ), | |
8447 | aborting( _aborting ) | |
8448 | {} | |
8449 | ||
8450 | TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo ) | |
8451 | : groupInfo( _groupInfo ), | |
8452 | aborting( false ) | |
8453 | {} | |
8454 | ||
8455 | TestGroupStats::~TestGroupStats() = default; | |
8456 | ||
8457 | TestRunStats::TestRunStats( TestRunInfo const& _runInfo, | |
8458 | Totals const& _totals, | |
8459 | bool _aborting ) | |
8460 | : runInfo( _runInfo ), | |
8461 | totals( _totals ), | |
8462 | aborting( _aborting ) | |
8463 | {} | |
8464 | ||
8465 | TestRunStats::~TestRunStats() = default; | |
8466 | ||
8467 | void IStreamingReporter::fatalErrorEncountered( StringRef ) {} | |
8468 | bool IStreamingReporter::isMulti() const { return false; } | |
8469 | ||
8470 | IReporterFactory::~IReporterFactory() = default; | |
8471 | IReporterRegistry::~IReporterRegistry() = default; | |
8472 | ||
8473 | } // end namespace Catch | |
8474 | // end catch_interfaces_reporter.cpp | |
8475 | // start catch_interfaces_runner.cpp | |
8476 | ||
8477 | namespace Catch { | |
8478 | IRunner::~IRunner() = default; | |
8479 | } | |
8480 | // end catch_interfaces_runner.cpp | |
8481 | // start catch_interfaces_testcase.cpp | |
8482 | ||
8483 | namespace Catch { | |
8484 | ITestInvoker::~ITestInvoker() = default; | |
8485 | ITestCaseRegistry::~ITestCaseRegistry() = default; | |
8486 | } | |
8487 | // end catch_interfaces_testcase.cpp | |
8488 | // start catch_leak_detector.cpp | |
8489 | ||
8490 | #ifdef CATCH_CONFIG_WINDOWS_CRTDBG | |
8491 | #include <crtdbg.h> | |
8492 | ||
8493 | namespace Catch { | |
8494 | ||
8495 | LeakDetector::LeakDetector() { | |
8496 | int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); | |
8497 | flag |= _CRTDBG_LEAK_CHECK_DF; | |
8498 | flag |= _CRTDBG_ALLOC_MEM_DF; | |
8499 | _CrtSetDbgFlag(flag); | |
8500 | _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); | |
8501 | _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); | |
8502 | // Change this to leaking allocation's number to break there | |
8503 | _CrtSetBreakAlloc(-1); | |
8504 | } | |
8505 | } | |
8506 | ||
8507 | #else | |
8508 | ||
8509 | Catch::LeakDetector::LeakDetector() {} | |
8510 | ||
8511 | #endif | |
8512 | ||
8513 | Catch::LeakDetector::~LeakDetector() { | |
8514 | Catch::cleanUp(); | |
8515 | } | |
8516 | // end catch_leak_detector.cpp | |
8517 | // start catch_list.cpp | |
8518 | ||
8519 | // start catch_list.h | |
8520 | ||
8521 | #include <set> | |
8522 | ||
8523 | namespace Catch { | |
8524 | ||
8525 | std::size_t listTests( Config const& config ); | |
8526 | ||
8527 | std::size_t listTestsNamesOnly( Config const& config ); | |
8528 | ||
8529 | struct TagInfo { | |
8530 | void add( std::string const& spelling ); | |
8531 | std::string all() const; | |
8532 | ||
8533 | std::set<std::string> spellings; | |
8534 | std::size_t count = 0; | |
8535 | }; | |
8536 | ||
8537 | std::size_t listTags( Config const& config ); | |
8538 | ||
8539 | std::size_t listReporters(); | |
8540 | ||
8541 | Option<std::size_t> list( Config const& config ); | |
8542 | ||
8543 | } // end namespace Catch | |
8544 | ||
8545 | // end catch_list.h | |
8546 | // start catch_text.h | |
8547 | ||
8548 | namespace Catch { | |
8549 | using namespace clara::TextFlow; | |
8550 | } | |
8551 | ||
8552 | // end catch_text.h | |
8553 | #include <limits> | |
8554 | #include <algorithm> | |
8555 | #include <iomanip> | |
8556 | ||
8557 | namespace Catch { | |
8558 | ||
8559 | std::size_t listTests( Config const& config ) { | |
8560 | TestSpec testSpec = config.testSpec(); | |
8561 | if( config.hasTestFilters() ) | |
8562 | Catch::cout() << "Matching test cases:\n"; | |
8563 | else { | |
8564 | Catch::cout() << "All available test cases:\n"; | |
8565 | } | |
8566 | ||
8567 | auto matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); | |
8568 | for( auto const& testCaseInfo : matchedTestCases ) { | |
8569 | Colour::Code colour = testCaseInfo.isHidden() | |
8570 | ? Colour::SecondaryText | |
8571 | : Colour::None; | |
8572 | Colour colourGuard( colour ); | |
8573 | ||
8574 | Catch::cout() << Column( testCaseInfo.name ).initialIndent( 2 ).indent( 4 ) << "\n"; | |
8575 | if( config.verbosity() >= Verbosity::High ) { | |
8576 | Catch::cout() << Column( Catch::Detail::stringify( testCaseInfo.lineInfo ) ).indent(4) << std::endl; | |
8577 | std::string description = testCaseInfo.description; | |
8578 | if( description.empty() ) | |
8579 | description = "(NO DESCRIPTION)"; | |
8580 | Catch::cout() << Column( description ).indent(4) << std::endl; | |
8581 | } | |
8582 | if( !testCaseInfo.tags.empty() ) | |
8583 | Catch::cout() << Column( testCaseInfo.tagsAsString() ).indent( 6 ) << "\n"; | |
8584 | } | |
8585 | ||
8586 | if( !config.hasTestFilters() ) | |
8587 | Catch::cout() << pluralise( matchedTestCases.size(), "test case" ) << '\n' << std::endl; | |
8588 | else | |
8589 | Catch::cout() << pluralise( matchedTestCases.size(), "matching test case" ) << '\n' << std::endl; | |
8590 | return matchedTestCases.size(); | |
8591 | } | |
8592 | ||
8593 | std::size_t listTestsNamesOnly( Config const& config ) { | |
8594 | TestSpec testSpec = config.testSpec(); | |
8595 | std::size_t matchedTests = 0; | |
8596 | std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); | |
8597 | for( auto const& testCaseInfo : matchedTestCases ) { | |
8598 | matchedTests++; | |
8599 | if( startsWith( testCaseInfo.name, '#' ) ) | |
8600 | Catch::cout() << '"' << testCaseInfo.name << '"'; | |
8601 | else | |
8602 | Catch::cout() << testCaseInfo.name; | |
8603 | if ( config.verbosity() >= Verbosity::High ) | |
8604 | Catch::cout() << "\t@" << testCaseInfo.lineInfo; | |
8605 | Catch::cout() << std::endl; | |
8606 | } | |
8607 | return matchedTests; | |
8608 | } | |
8609 | ||
8610 | void TagInfo::add( std::string const& spelling ) { | |
8611 | ++count; | |
8612 | spellings.insert( spelling ); | |
8613 | } | |
8614 | ||
8615 | std::string TagInfo::all() const { | |
8616 | std::string out; | |
8617 | for( auto const& spelling : spellings ) | |
8618 | out += "[" + spelling + "]"; | |
8619 | return out; | |
8620 | } | |
8621 | ||
8622 | std::size_t listTags( Config const& config ) { | |
8623 | TestSpec testSpec = config.testSpec(); | |
8624 | if( config.hasTestFilters() ) | |
8625 | Catch::cout() << "Tags for matching test cases:\n"; | |
8626 | else { | |
8627 | Catch::cout() << "All available tags:\n"; | |
8628 | } | |
8629 | ||
8630 | std::map<std::string, TagInfo> tagCounts; | |
8631 | ||
8632 | std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); | |
8633 | for( auto const& testCase : matchedTestCases ) { | |
8634 | for( auto const& tagName : testCase.getTestCaseInfo().tags ) { | |
8635 | std::string lcaseTagName = toLower( tagName ); | |
8636 | auto countIt = tagCounts.find( lcaseTagName ); | |
8637 | if( countIt == tagCounts.end() ) | |
8638 | countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; | |
8639 | countIt->second.add( tagName ); | |
8640 | } | |
8641 | } | |
8642 | ||
8643 | for( auto const& tagCount : tagCounts ) { | |
8644 | ReusableStringStream rss; | |
8645 | rss << " " << std::setw(2) << tagCount.second.count << " "; | |
8646 | auto str = rss.str(); | |
8647 | auto wrapper = Column( tagCount.second.all() ) | |
8648 | .initialIndent( 0 ) | |
8649 | .indent( str.size() ) | |
8650 | .width( CATCH_CONFIG_CONSOLE_WIDTH-10 ); | |
8651 | Catch::cout() << str << wrapper << '\n'; | |
8652 | } | |
8653 | Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl; | |
8654 | return tagCounts.size(); | |
8655 | } | |
8656 | ||
8657 | std::size_t listReporters() { | |
8658 | Catch::cout() << "Available reporters:\n"; | |
8659 | IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); | |
8660 | std::size_t maxNameLen = 0; | |
8661 | for( auto const& factoryKvp : factories ) | |
8662 | maxNameLen = (std::max)( maxNameLen, factoryKvp.first.size() ); | |
8663 | ||
8664 | for( auto const& factoryKvp : factories ) { | |
8665 | Catch::cout() | |
8666 | << Column( factoryKvp.first + ":" ) | |
8667 | .indent(2) | |
8668 | .width( 5+maxNameLen ) | |
8669 | + Column( factoryKvp.second->getDescription() ) | |
8670 | .initialIndent(0) | |
8671 | .indent(2) | |
8672 | .width( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) | |
8673 | << "\n"; | |
8674 | } | |
8675 | Catch::cout() << std::endl; | |
8676 | return factories.size(); | |
8677 | } | |
8678 | ||
8679 | Option<std::size_t> list( Config const& config ) { | |
8680 | Option<std::size_t> listedCount; | |
8681 | if( config.listTests() ) | |
8682 | listedCount = listedCount.valueOr(0) + listTests( config ); | |
8683 | if( config.listTestNamesOnly() ) | |
8684 | listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config ); | |
8685 | if( config.listTags() ) | |
8686 | listedCount = listedCount.valueOr(0) + listTags( config ); | |
8687 | if( config.listReporters() ) | |
8688 | listedCount = listedCount.valueOr(0) + listReporters(); | |
8689 | return listedCount; | |
8690 | } | |
8691 | ||
8692 | } // end namespace Catch | |
8693 | // end catch_list.cpp | |
8694 | // start catch_matchers.cpp | |
8695 | ||
8696 | namespace Catch { | |
8697 | namespace Matchers { | |
8698 | namespace Impl { | |
8699 | ||
8700 | std::string MatcherUntypedBase::toString() const { | |
8701 | if( m_cachedToString.empty() ) | |
8702 | m_cachedToString = describe(); | |
8703 | return m_cachedToString; | |
8704 | } | |
8705 | ||
8706 | MatcherUntypedBase::~MatcherUntypedBase() = default; | |
8707 | ||
8708 | } // namespace Impl | |
8709 | } // namespace Matchers | |
8710 | ||
8711 | using namespace Matchers; | |
8712 | using Matchers::Impl::MatcherBase; | |
8713 | ||
8714 | } // namespace Catch | |
8715 | // end catch_matchers.cpp | |
8716 | // start catch_matchers_floating.cpp | |
8717 | ||
8718 | // start catch_polyfills.hpp | |
8719 | ||
8720 | namespace Catch { | |
8721 | bool isnan(float f); | |
8722 | bool isnan(double d); | |
8723 | } | |
8724 | ||
8725 | // end catch_polyfills.hpp | |
8726 | // start catch_to_string.hpp | |
8727 | ||
8728 | #include <string> | |
8729 | ||
8730 | namespace Catch { | |
8731 | template <typename T> | |
8732 | std::string to_string(T const& t) { | |
8733 | #if defined(CATCH_CONFIG_CPP11_TO_STRING) | |
8734 | return std::to_string(t); | |
8735 | #else | |
8736 | ReusableStringStream rss; | |
8737 | rss << t; | |
8738 | return rss.str(); | |
8739 | #endif | |
8740 | } | |
8741 | } // end namespace Catch | |
8742 | ||
8743 | // end catch_to_string.hpp | |
8744 | #include <cstdlib> | |
8745 | #include <cstdint> | |
8746 | #include <cstring> | |
8747 | ||
8748 | namespace Catch { | |
8749 | namespace Matchers { | |
8750 | namespace Floating { | |
8751 | enum class FloatingPointKind : uint8_t { | |
8752 | Float, | |
8753 | Double | |
8754 | }; | |
8755 | } | |
8756 | } | |
8757 | } | |
8758 | ||
8759 | namespace { | |
8760 | ||
8761 | template <typename T> | |
8762 | struct Converter; | |
8763 | ||
8764 | template <> | |
8765 | struct Converter<float> { | |
8766 | static_assert(sizeof(float) == sizeof(int32_t), "Important ULP matcher assumption violated"); | |
8767 | Converter(float f) { | |
8768 | std::memcpy(&i, &f, sizeof(f)); | |
8769 | } | |
8770 | int32_t i; | |
8771 | }; | |
8772 | ||
8773 | template <> | |
8774 | struct Converter<double> { | |
8775 | static_assert(sizeof(double) == sizeof(int64_t), "Important ULP matcher assumption violated"); | |
8776 | Converter(double d) { | |
8777 | std::memcpy(&i, &d, sizeof(d)); | |
8778 | } | |
8779 | int64_t i; | |
8780 | }; | |
8781 | ||
8782 | template <typename T> | |
8783 | auto convert(T t) -> Converter<T> { | |
8784 | return Converter<T>(t); | |
8785 | } | |
8786 | ||
8787 | template <typename FP> | |
8788 | bool almostEqualUlps(FP lhs, FP rhs, int maxUlpDiff) { | |
8789 | // Comparison with NaN should always be false. | |
8790 | // This way we can rule it out before getting into the ugly details | |
8791 | if (Catch::isnan(lhs) || Catch::isnan(rhs)) { | |
8792 | return false; | |
8793 | } | |
8794 | ||
8795 | auto lc = convert(lhs); | |
8796 | auto rc = convert(rhs); | |
8797 | ||
8798 | if ((lc.i < 0) != (rc.i < 0)) { | |
8799 | // Potentially we can have +0 and -0 | |
8800 | return lhs == rhs; | |
8801 | } | |
8802 | ||
8803 | auto ulpDiff = std::abs(lc.i - rc.i); | |
8804 | return ulpDiff <= maxUlpDiff; | |
8805 | } | |
8806 | ||
8807 | } | |
8808 | ||
8809 | namespace Catch { | |
8810 | namespace Matchers { | |
8811 | namespace Floating { | |
8812 | WithinAbsMatcher::WithinAbsMatcher(double target, double margin) | |
8813 | :m_target{ target }, m_margin{ margin } { | |
8814 | CATCH_ENFORCE(margin >= 0, "Invalid margin: " << margin << '.' | |
8815 | << " Margin has to be non-negative."); | |
8816 | } | |
8817 | ||
8818 | // Performs equivalent check of std::fabs(lhs - rhs) <= margin | |
8819 | // But without the subtraction to allow for INFINITY in comparison | |
8820 | bool WithinAbsMatcher::match(double const& matchee) const { | |
8821 | return (matchee + m_margin >= m_target) && (m_target + m_margin >= matchee); | |
8822 | } | |
8823 | ||
8824 | std::string WithinAbsMatcher::describe() const { | |
8825 | return "is within " + ::Catch::Detail::stringify(m_margin) + " of " + ::Catch::Detail::stringify(m_target); | |
8826 | } | |
8827 | ||
8828 | WithinUlpsMatcher::WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType) | |
8829 | :m_target{ target }, m_ulps{ ulps }, m_type{ baseType } { | |
8830 | CATCH_ENFORCE(ulps >= 0, "Invalid ULP setting: " << ulps << '.' | |
8831 | << " ULPs have to be non-negative."); | |
8832 | } | |
8833 | ||
8834 | #if defined(__clang__) | |
8835 | #pragma clang diagnostic push | |
8836 | // Clang <3.5 reports on the default branch in the switch below | |
8837 | #pragma clang diagnostic ignored "-Wunreachable-code" | |
8838 | #endif | |
8839 | ||
8840 | bool WithinUlpsMatcher::match(double const& matchee) const { | |
8841 | switch (m_type) { | |
8842 | case FloatingPointKind::Float: | |
8843 | return almostEqualUlps<float>(static_cast<float>(matchee), static_cast<float>(m_target), m_ulps); | |
8844 | case FloatingPointKind::Double: | |
8845 | return almostEqualUlps<double>(matchee, m_target, m_ulps); | |
8846 | default: | |
8847 | CATCH_INTERNAL_ERROR( "Unknown FloatingPointKind value" ); | |
8848 | } | |
8849 | } | |
8850 | ||
8851 | #if defined(__clang__) | |
8852 | #pragma clang diagnostic pop | |
8853 | #endif | |
8854 | ||
8855 | std::string WithinUlpsMatcher::describe() const { | |
8856 | return "is within " + Catch::to_string(m_ulps) + " ULPs of " + ::Catch::Detail::stringify(m_target) + ((m_type == FloatingPointKind::Float)? "f" : ""); | |
8857 | } | |
8858 | ||
8859 | }// namespace Floating | |
8860 | ||
8861 | Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff) { | |
8862 | return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Double); | |
8863 | } | |
8864 | ||
8865 | Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff) { | |
8866 | return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Float); | |
8867 | } | |
8868 | ||
8869 | Floating::WithinAbsMatcher WithinAbs(double target, double margin) { | |
8870 | return Floating::WithinAbsMatcher(target, margin); | |
8871 | } | |
8872 | ||
8873 | } // namespace Matchers | |
8874 | } // namespace Catch | |
8875 | ||
8876 | // end catch_matchers_floating.cpp | |
8877 | // start catch_matchers_generic.cpp | |
8878 | ||
8879 | std::string Catch::Matchers::Generic::Detail::finalizeDescription(const std::string& desc) { | |
8880 | if (desc.empty()) { | |
8881 | return "matches undescribed predicate"; | |
8882 | } else { | |
8883 | return "matches predicate: \"" + desc + '"'; | |
8884 | } | |
8885 | } | |
8886 | // end catch_matchers_generic.cpp | |
8887 | // start catch_matchers_string.cpp | |
8888 | ||
8889 | #include <regex> | |
8890 | ||
8891 | namespace Catch { | |
8892 | namespace Matchers { | |
8893 | ||
8894 | namespace StdString { | |
8895 | ||
8896 | CasedString::CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ) | |
8897 | : m_caseSensitivity( caseSensitivity ), | |
8898 | m_str( adjustString( str ) ) | |
8899 | {} | |
8900 | std::string CasedString::adjustString( std::string const& str ) const { | |
8901 | return m_caseSensitivity == CaseSensitive::No | |
8902 | ? toLower( str ) | |
8903 | : str; | |
8904 | } | |
8905 | std::string CasedString::caseSensitivitySuffix() const { | |
8906 | return m_caseSensitivity == CaseSensitive::No | |
8907 | ? " (case insensitive)" | |
8908 | : std::string(); | |
8909 | } | |
8910 | ||
8911 | StringMatcherBase::StringMatcherBase( std::string const& operation, CasedString const& comparator ) | |
8912 | : m_comparator( comparator ), | |
8913 | m_operation( operation ) { | |
8914 | } | |
8915 | ||
8916 | std::string StringMatcherBase::describe() const { | |
8917 | std::string description; | |
8918 | description.reserve(5 + m_operation.size() + m_comparator.m_str.size() + | |
8919 | m_comparator.caseSensitivitySuffix().size()); | |
8920 | description += m_operation; | |
8921 | description += ": \""; | |
8922 | description += m_comparator.m_str; | |
8923 | description += "\""; | |
8924 | description += m_comparator.caseSensitivitySuffix(); | |
8925 | return description; | |
8926 | } | |
8927 | ||
8928 | EqualsMatcher::EqualsMatcher( CasedString const& comparator ) : StringMatcherBase( "equals", comparator ) {} | |
8929 | ||
8930 | bool EqualsMatcher::match( std::string const& source ) const { | |
8931 | return m_comparator.adjustString( source ) == m_comparator.m_str; | |
8932 | } | |
8933 | ||
8934 | ContainsMatcher::ContainsMatcher( CasedString const& comparator ) : StringMatcherBase( "contains", comparator ) {} | |
8935 | ||
8936 | bool ContainsMatcher::match( std::string const& source ) const { | |
8937 | return contains( m_comparator.adjustString( source ), m_comparator.m_str ); | |
8938 | } | |
8939 | ||
8940 | StartsWithMatcher::StartsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "starts with", comparator ) {} | |
8941 | ||
8942 | bool StartsWithMatcher::match( std::string const& source ) const { | |
8943 | return startsWith( m_comparator.adjustString( source ), m_comparator.m_str ); | |
8944 | } | |
8945 | ||
8946 | EndsWithMatcher::EndsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "ends with", comparator ) {} | |
8947 | ||
8948 | bool EndsWithMatcher::match( std::string const& source ) const { | |
8949 | return endsWith( m_comparator.adjustString( source ), m_comparator.m_str ); | |
8950 | } | |
8951 | ||
8952 | RegexMatcher::RegexMatcher(std::string regex, CaseSensitive::Choice caseSensitivity): m_regex(std::move(regex)), m_caseSensitivity(caseSensitivity) {} | |
8953 | ||
8954 | bool RegexMatcher::match(std::string const& matchee) const { | |
8955 | auto flags = std::regex::ECMAScript; // ECMAScript is the default syntax option anyway | |
8956 | if (m_caseSensitivity == CaseSensitive::Choice::No) { | |
8957 | flags |= std::regex::icase; | |
8958 | } | |
8959 | auto reg = std::regex(m_regex, flags); | |
8960 | return std::regex_match(matchee, reg); | |
8961 | } | |
8962 | ||
8963 | std::string RegexMatcher::describe() const { | |
8964 | return "matches " + ::Catch::Detail::stringify(m_regex) + ((m_caseSensitivity == CaseSensitive::Choice::Yes)? " case sensitively" : " case insensitively"); | |
8965 | } | |
8966 | ||
8967 | } // namespace StdString | |
8968 | ||
8969 | StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity ) { | |
8970 | return StdString::EqualsMatcher( StdString::CasedString( str, caseSensitivity) ); | |
8971 | } | |
8972 | StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity ) { | |
8973 | return StdString::ContainsMatcher( StdString::CasedString( str, caseSensitivity) ); | |
8974 | } | |
8975 | StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) { | |
8976 | return StdString::EndsWithMatcher( StdString::CasedString( str, caseSensitivity) ); | |
8977 | } | |
8978 | StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) { | |
8979 | return StdString::StartsWithMatcher( StdString::CasedString( str, caseSensitivity) ); | |
8980 | } | |
8981 | ||
8982 | StdString::RegexMatcher Matches(std::string const& regex, CaseSensitive::Choice caseSensitivity) { | |
8983 | return StdString::RegexMatcher(regex, caseSensitivity); | |
8984 | } | |
8985 | ||
8986 | } // namespace Matchers | |
8987 | } // namespace Catch | |
8988 | // end catch_matchers_string.cpp | |
8989 | // start catch_message.cpp | |
8990 | ||
8991 | // start catch_uncaught_exceptions.h | |
8992 | ||
8993 | namespace Catch { | |
8994 | bool uncaught_exceptions(); | |
8995 | } // end namespace Catch | |
8996 | ||
8997 | // end catch_uncaught_exceptions.h | |
8998 | #include <cassert> | |
8999 | #include <stack> | |
9000 | ||
9001 | namespace Catch { | |
9002 | ||
9003 | MessageInfo::MessageInfo( StringRef const& _macroName, | |
9004 | SourceLineInfo const& _lineInfo, | |
9005 | ResultWas::OfType _type ) | |
9006 | : macroName( _macroName ), | |
9007 | lineInfo( _lineInfo ), | |
9008 | type( _type ), | |
9009 | sequence( ++globalCount ) | |
9010 | {} | |
9011 | ||
9012 | bool MessageInfo::operator==( MessageInfo const& other ) const { | |
9013 | return sequence == other.sequence; | |
9014 | } | |
9015 | ||
9016 | bool MessageInfo::operator<( MessageInfo const& other ) const { | |
9017 | return sequence < other.sequence; | |
9018 | } | |
9019 | ||
9020 | // This may need protecting if threading support is added | |
9021 | unsigned int MessageInfo::globalCount = 0; | |
9022 | ||
9023 | //////////////////////////////////////////////////////////////////////////// | |
9024 | ||
9025 | Catch::MessageBuilder::MessageBuilder( StringRef const& macroName, | |
9026 | SourceLineInfo const& lineInfo, | |
9027 | ResultWas::OfType type ) | |
9028 | :m_info(macroName, lineInfo, type) {} | |
9029 | ||
9030 | //////////////////////////////////////////////////////////////////////////// | |
9031 | ||
9032 | ScopedMessage::ScopedMessage( MessageBuilder const& builder ) | |
9033 | : m_info( builder.m_info ) | |
9034 | { | |
9035 | m_info.message = builder.m_stream.str(); | |
9036 | getResultCapture().pushScopedMessage( m_info ); | |
9037 | } | |
9038 | ||
9039 | ScopedMessage::~ScopedMessage() { | |
9040 | if ( !uncaught_exceptions() ){ | |
9041 | getResultCapture().popScopedMessage(m_info); | |
9042 | } | |
9043 | } | |
9044 | ||
9045 | Capturer::Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ) { | |
9046 | auto trimmed = [&] (size_t start, size_t end) { | |
9047 | while (names[start] == ',' || isspace(names[start])) { | |
9048 | ++start; | |
9049 | } | |
9050 | while (names[end] == ',' || isspace(names[end])) { | |
9051 | --end; | |
9052 | } | |
9053 | return names.substr(start, end - start + 1); | |
9054 | }; | |
9055 | ||
9056 | size_t start = 0; | |
9057 | std::stack<char> openings; | |
9058 | for (size_t pos = 0; pos < names.size(); ++pos) { | |
9059 | char c = names[pos]; | |
9060 | switch (c) { | |
9061 | case '[': | |
9062 | case '{': | |
9063 | case '(': | |
9064 | // It is basically impossible to disambiguate between | |
9065 | // comparison and start of template args in this context | |
9066 | // case '<': | |
9067 | openings.push(c); | |
9068 | break; | |
9069 | case ']': | |
9070 | case '}': | |
9071 | case ')': | |
9072 | // case '>': | |
9073 | openings.pop(); | |
9074 | break; | |
9075 | case ',': | |
9076 | if (start != pos && openings.size() == 0) { | |
9077 | m_messages.emplace_back(macroName, lineInfo, resultType); | |
9078 | m_messages.back().message = trimmed(start, pos); | |
9079 | m_messages.back().message += " := "; | |
9080 | start = pos; | |
9081 | } | |
9082 | } | |
9083 | } | |
9084 | assert(openings.size() == 0 && "Mismatched openings"); | |
9085 | m_messages.emplace_back(macroName, lineInfo, resultType); | |
9086 | m_messages.back().message = trimmed(start, names.size() - 1); | |
9087 | m_messages.back().message += " := "; | |
9088 | } | |
9089 | Capturer::~Capturer() { | |
9090 | if ( !uncaught_exceptions() ){ | |
9091 | assert( m_captured == m_messages.size() ); | |
9092 | for( size_t i = 0; i < m_captured; ++i ) | |
9093 | m_resultCapture.popScopedMessage( m_messages[i] ); | |
9094 | } | |
9095 | } | |
9096 | ||
9097 | void Capturer::captureValue( size_t index, std::string const& value ) { | |
9098 | assert( index < m_messages.size() ); | |
9099 | m_messages[index].message += value; | |
9100 | m_resultCapture.pushScopedMessage( m_messages[index] ); | |
9101 | m_captured++; | |
9102 | } | |
9103 | ||
9104 | } // end namespace Catch | |
9105 | // end catch_message.cpp | |
9106 | // start catch_output_redirect.cpp | |
9107 | ||
9108 | // start catch_output_redirect.h | |
9109 | #ifndef TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H | |
9110 | #define TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H | |
9111 | ||
9112 | #include <cstdio> | |
9113 | #include <iosfwd> | |
9114 | #include <string> | |
9115 | ||
9116 | namespace Catch { | |
9117 | ||
9118 | class RedirectedStream { | |
9119 | std::ostream& m_originalStream; | |
9120 | std::ostream& m_redirectionStream; | |
9121 | std::streambuf* m_prevBuf; | |
9122 | ||
9123 | public: | |
9124 | RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream ); | |
9125 | ~RedirectedStream(); | |
9126 | }; | |
9127 | ||
9128 | class RedirectedStdOut { | |
9129 | ReusableStringStream m_rss; | |
9130 | RedirectedStream m_cout; | |
9131 | public: | |
9132 | RedirectedStdOut(); | |
9133 | auto str() const -> std::string; | |
9134 | }; | |
9135 | ||
9136 | // StdErr has two constituent streams in C++, std::cerr and std::clog | |
9137 | // This means that we need to redirect 2 streams into 1 to keep proper | |
9138 | // order of writes | |
9139 | class RedirectedStdErr { | |
9140 | ReusableStringStream m_rss; | |
9141 | RedirectedStream m_cerr; | |
9142 | RedirectedStream m_clog; | |
9143 | public: | |
9144 | RedirectedStdErr(); | |
9145 | auto str() const -> std::string; | |
9146 | }; | |
9147 | ||
9148 | #if defined(CATCH_CONFIG_NEW_CAPTURE) | |
9149 | ||
9150 | // Windows's implementation of std::tmpfile is terrible (it tries | |
9151 | // to create a file inside system folder, thus requiring elevated | |
9152 | // privileges for the binary), so we have to use tmpnam(_s) and | |
9153 | // create the file ourselves there. | |
9154 | class TempFile { | |
9155 | public: | |
9156 | TempFile(TempFile const&) = delete; | |
9157 | TempFile& operator=(TempFile const&) = delete; | |
9158 | TempFile(TempFile&&) = delete; | |
9159 | TempFile& operator=(TempFile&&) = delete; | |
9160 | ||
9161 | TempFile(); | |
9162 | ~TempFile(); | |
9163 | ||
9164 | std::FILE* getFile(); | |
9165 | std::string getContents(); | |
9166 | ||
9167 | private: | |
9168 | std::FILE* m_file = nullptr; | |
9169 | #if defined(_MSC_VER) | |
9170 | char m_buffer[L_tmpnam] = { 0 }; | |
9171 | #endif | |
9172 | }; | |
9173 | ||
9174 | class OutputRedirect { | |
9175 | public: | |
9176 | OutputRedirect(OutputRedirect const&) = delete; | |
9177 | OutputRedirect& operator=(OutputRedirect const&) = delete; | |
9178 | OutputRedirect(OutputRedirect&&) = delete; | |
9179 | OutputRedirect& operator=(OutputRedirect&&) = delete; | |
9180 | ||
9181 | OutputRedirect(std::string& stdout_dest, std::string& stderr_dest); | |
9182 | ~OutputRedirect(); | |
9183 | ||
9184 | private: | |
9185 | int m_originalStdout = -1; | |
9186 | int m_originalStderr = -1; | |
9187 | TempFile m_stdoutFile; | |
9188 | TempFile m_stderrFile; | |
9189 | std::string& m_stdoutDest; | |
9190 | std::string& m_stderrDest; | |
9191 | }; | |
9192 | ||
9193 | #endif | |
9194 | ||
9195 | } // end namespace Catch | |
9196 | ||
9197 | #endif // TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H | |
9198 | // end catch_output_redirect.h | |
9199 | #include <cstdio> | |
9200 | #include <cstring> | |
9201 | #include <fstream> | |
9202 | #include <sstream> | |
9203 | #include <stdexcept> | |
9204 | ||
9205 | #if defined(CATCH_CONFIG_NEW_CAPTURE) | |
9206 | #if defined(_MSC_VER) | |
9207 | #include <io.h> //_dup and _dup2 | |
9208 | #define dup _dup | |
9209 | #define dup2 _dup2 | |
9210 | #define fileno _fileno | |
9211 | #else | |
9212 | #include <unistd.h> // dup and dup2 | |
9213 | #endif | |
9214 | #endif | |
9215 | ||
9216 | namespace Catch { | |
9217 | ||
9218 | RedirectedStream::RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream ) | |
9219 | : m_originalStream( originalStream ), | |
9220 | m_redirectionStream( redirectionStream ), | |
9221 | m_prevBuf( m_originalStream.rdbuf() ) | |
9222 | { | |
9223 | m_originalStream.rdbuf( m_redirectionStream.rdbuf() ); | |
9224 | } | |
9225 | ||
9226 | RedirectedStream::~RedirectedStream() { | |
9227 | m_originalStream.rdbuf( m_prevBuf ); | |
9228 | } | |
9229 | ||
9230 | RedirectedStdOut::RedirectedStdOut() : m_cout( Catch::cout(), m_rss.get() ) {} | |
9231 | auto RedirectedStdOut::str() const -> std::string { return m_rss.str(); } | |
9232 | ||
9233 | RedirectedStdErr::RedirectedStdErr() | |
9234 | : m_cerr( Catch::cerr(), m_rss.get() ), | |
9235 | m_clog( Catch::clog(), m_rss.get() ) | |
9236 | {} | |
9237 | auto RedirectedStdErr::str() const -> std::string { return m_rss.str(); } | |
9238 | ||
9239 | #if defined(CATCH_CONFIG_NEW_CAPTURE) | |
9240 | ||
9241 | #if defined(_MSC_VER) | |
9242 | TempFile::TempFile() { | |
9243 | if (tmpnam_s(m_buffer)) { | |
9244 | CATCH_RUNTIME_ERROR("Could not get a temp filename"); | |
9245 | } | |
9246 | if (fopen_s(&m_file, m_buffer, "w")) { | |
9247 | char buffer[100]; | |
9248 | if (strerror_s(buffer, errno)) { | |
9249 | CATCH_RUNTIME_ERROR("Could not translate errno to a string"); | |
9250 | } | |
9251 | CATCH_RUNTIME_ERROR("Coul dnot open the temp file: '" << m_buffer << "' because: " << buffer); | |
9252 | } | |
9253 | } | |
9254 | #else | |
9255 | TempFile::TempFile() { | |
9256 | m_file = std::tmpfile(); | |
9257 | if (!m_file) { | |
9258 | CATCH_RUNTIME_ERROR("Could not create a temp file."); | |
9259 | } | |
9260 | } | |
9261 | ||
9262 | #endif | |
9263 | ||
9264 | TempFile::~TempFile() { | |
9265 | // TBD: What to do about errors here? | |
9266 | std::fclose(m_file); | |
9267 | // We manually create the file on Windows only, on Linux | |
9268 | // it will be autodeleted | |
9269 | #if defined(_MSC_VER) | |
9270 | std::remove(m_buffer); | |
9271 | #endif | |
9272 | } | |
9273 | ||
9274 | FILE* TempFile::getFile() { | |
9275 | return m_file; | |
9276 | } | |
9277 | ||
9278 | std::string TempFile::getContents() { | |
9279 | std::stringstream sstr; | |
9280 | char buffer[100] = {}; | |
9281 | std::rewind(m_file); | |
9282 | while (std::fgets(buffer, sizeof(buffer), m_file)) { | |
9283 | sstr << buffer; | |
9284 | } | |
9285 | return sstr.str(); | |
9286 | } | |
9287 | ||
9288 | OutputRedirect::OutputRedirect(std::string& stdout_dest, std::string& stderr_dest) : | |
9289 | m_originalStdout(dup(1)), | |
9290 | m_originalStderr(dup(2)), | |
9291 | m_stdoutDest(stdout_dest), | |
9292 | m_stderrDest(stderr_dest) { | |
9293 | dup2(fileno(m_stdoutFile.getFile()), 1); | |
9294 | dup2(fileno(m_stderrFile.getFile()), 2); | |
9295 | } | |
9296 | ||
9297 | OutputRedirect::~OutputRedirect() { | |
9298 | Catch::cout() << std::flush; | |
9299 | fflush(stdout); | |
9300 | // Since we support overriding these streams, we flush cerr | |
9301 | // even though std::cerr is unbuffered | |
9302 | Catch::cerr() << std::flush; | |
9303 | Catch::clog() << std::flush; | |
9304 | fflush(stderr); | |
9305 | ||
9306 | dup2(m_originalStdout, 1); | |
9307 | dup2(m_originalStderr, 2); | |
9308 | ||
9309 | m_stdoutDest += m_stdoutFile.getContents(); | |
9310 | m_stderrDest += m_stderrFile.getContents(); | |
9311 | } | |
9312 | ||
9313 | #endif // CATCH_CONFIG_NEW_CAPTURE | |
9314 | ||
9315 | } // namespace Catch | |
9316 | ||
9317 | #if defined(CATCH_CONFIG_NEW_CAPTURE) | |
9318 | #if defined(_MSC_VER) | |
9319 | #undef dup | |
9320 | #undef dup2 | |
9321 | #undef fileno | |
9322 | #endif | |
9323 | #endif | |
9324 | // end catch_output_redirect.cpp | |
9325 | // start catch_polyfills.cpp | |
9326 | ||
9327 | #include <cmath> | |
9328 | ||
9329 | namespace Catch { | |
9330 | ||
9331 | #if !defined(CATCH_CONFIG_POLYFILL_ISNAN) | |
9332 | bool isnan(float f) { | |
9333 | return std::isnan(f); | |
9334 | } | |
9335 | bool isnan(double d) { | |
9336 | return std::isnan(d); | |
9337 | } | |
9338 | #else | |
9339 | // For now we only use this for embarcadero | |
9340 | bool isnan(float f) { | |
9341 | return std::_isnan(f); | |
9342 | } | |
9343 | bool isnan(double d) { | |
9344 | return std::_isnan(d); | |
9345 | } | |
9346 | #endif | |
9347 | ||
9348 | } // end namespace Catch | |
9349 | // end catch_polyfills.cpp | |
9350 | // start catch_random_number_generator.cpp | |
9351 | ||
9352 | namespace Catch { | |
9353 | ||
9354 | std::mt19937& rng() { | |
9355 | static std::mt19937 s_rng; | |
9356 | return s_rng; | |
9357 | } | |
9358 | ||
9359 | void seedRng( IConfig const& config ) { | |
9360 | if( config.rngSeed() != 0 ) { | |
9361 | std::srand( config.rngSeed() ); | |
9362 | rng().seed( config.rngSeed() ); | |
9363 | } | |
9364 | } | |
9365 | ||
9366 | unsigned int rngSeed() { | |
9367 | return getCurrentContext().getConfig()->rngSeed(); | |
9368 | } | |
9369 | } | |
9370 | // end catch_random_number_generator.cpp | |
9371 | // start catch_registry_hub.cpp | |
9372 | ||
9373 | // start catch_test_case_registry_impl.h | |
9374 | ||
9375 | #include <vector> | |
9376 | #include <set> | |
9377 | #include <algorithm> | |
9378 | #include <ios> | |
9379 | ||
9380 | namespace Catch { | |
9381 | ||
9382 | class TestCase; | |
9383 | struct IConfig; | |
9384 | ||
9385 | std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ); | |
9386 | bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); | |
9387 | ||
9388 | void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions ); | |
9389 | ||
9390 | std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ); | |
9391 | std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ); | |
9392 | ||
9393 | class TestRegistry : public ITestCaseRegistry { | |
9394 | public: | |
9395 | virtual ~TestRegistry() = default; | |
9396 | ||
9397 | virtual void registerTest( TestCase const& testCase ); | |
9398 | ||
9399 | std::vector<TestCase> const& getAllTests() const override; | |
9400 | std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const override; | |
9401 | ||
9402 | private: | |
9403 | std::vector<TestCase> m_functions; | |
9404 | mutable RunTests::InWhatOrder m_currentSortOrder = RunTests::InDeclarationOrder; | |
9405 | mutable std::vector<TestCase> m_sortedFunctions; | |
9406 | std::size_t m_unnamedCount = 0; | |
9407 | std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised | |
9408 | }; | |
9409 | ||
9410 | /////////////////////////////////////////////////////////////////////////// | |
9411 | ||
9412 | class TestInvokerAsFunction : public ITestInvoker { | |
9413 | void(*m_testAsFunction)(); | |
9414 | public: | |
9415 | TestInvokerAsFunction( void(*testAsFunction)() ) noexcept; | |
9416 | ||
9417 | void invoke() const override; | |
9418 | }; | |
9419 | ||
9420 | std::string extractClassName( StringRef const& classOrQualifiedMethodName ); | |
9421 | ||
9422 | /////////////////////////////////////////////////////////////////////////// | |
9423 | ||
9424 | } // end namespace Catch | |
9425 | ||
9426 | // end catch_test_case_registry_impl.h | |
9427 | // start catch_reporter_registry.h | |
9428 | ||
9429 | #include <map> | |
9430 | ||
9431 | namespace Catch { | |
9432 | ||
9433 | class ReporterRegistry : public IReporterRegistry { | |
9434 | ||
9435 | public: | |
9436 | ||
9437 | ~ReporterRegistry() override; | |
9438 | ||
9439 | IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const override; | |
9440 | ||
9441 | void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ); | |
9442 | void registerListener( IReporterFactoryPtr const& factory ); | |
9443 | ||
9444 | FactoryMap const& getFactories() const override; | |
9445 | Listeners const& getListeners() const override; | |
9446 | ||
9447 | private: | |
9448 | FactoryMap m_factories; | |
9449 | Listeners m_listeners; | |
9450 | }; | |
9451 | } | |
9452 | ||
9453 | // end catch_reporter_registry.h | |
9454 | // start catch_tag_alias_registry.h | |
9455 | ||
9456 | // start catch_tag_alias.h | |
9457 | ||
9458 | #include <string> | |
9459 | ||
9460 | namespace Catch { | |
9461 | ||
9462 | struct TagAlias { | |
9463 | TagAlias(std::string const& _tag, SourceLineInfo _lineInfo); | |
9464 | ||
9465 | std::string tag; | |
9466 | SourceLineInfo lineInfo; | |
9467 | }; | |
9468 | ||
9469 | } // end namespace Catch | |
9470 | ||
9471 | // end catch_tag_alias.h | |
9472 | #include <map> | |
9473 | ||
9474 | namespace Catch { | |
9475 | ||
9476 | class TagAliasRegistry : public ITagAliasRegistry { | |
9477 | public: | |
9478 | ~TagAliasRegistry() override; | |
9479 | TagAlias const* find( std::string const& alias ) const override; | |
9480 | std::string expandAliases( std::string const& unexpandedTestSpec ) const override; | |
9481 | void add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ); | |
9482 | ||
9483 | private: | |
9484 | std::map<std::string, TagAlias> m_registry; | |
9485 | }; | |
9486 | ||
9487 | } // end namespace Catch | |
9488 | ||
9489 | // end catch_tag_alias_registry.h | |
9490 | // start catch_startup_exception_registry.h | |
9491 | ||
9492 | #include <vector> | |
9493 | #include <exception> | |
9494 | ||
9495 | namespace Catch { | |
9496 | ||
9497 | class StartupExceptionRegistry { | |
9498 | public: | |
9499 | void add(std::exception_ptr const& exception) noexcept; | |
9500 | std::vector<std::exception_ptr> const& getExceptions() const noexcept; | |
9501 | private: | |
9502 | std::vector<std::exception_ptr> m_exceptions; | |
9503 | }; | |
9504 | ||
9505 | } // end namespace Catch | |
9506 | ||
9507 | // end catch_startup_exception_registry.h | |
9508 | // start catch_singletons.hpp | |
9509 | ||
9510 | namespace Catch { | |
9511 | ||
9512 | struct ISingleton { | |
9513 | virtual ~ISingleton(); | |
9514 | }; | |
9515 | ||
9516 | void addSingleton( ISingleton* singleton ); | |
9517 | void cleanupSingletons(); | |
9518 | ||
9519 | template<typename SingletonImplT, typename InterfaceT = SingletonImplT, typename MutableInterfaceT = InterfaceT> | |
9520 | class Singleton : SingletonImplT, public ISingleton { | |
9521 | ||
9522 | static auto getInternal() -> Singleton* { | |
9523 | static Singleton* s_instance = nullptr; | |
9524 | if( !s_instance ) { | |
9525 | s_instance = new Singleton; | |
9526 | addSingleton( s_instance ); | |
9527 | } | |
9528 | return s_instance; | |
9529 | } | |
9530 | ||
9531 | public: | |
9532 | static auto get() -> InterfaceT const& { | |
9533 | return *getInternal(); | |
9534 | } | |
9535 | static auto getMutable() -> MutableInterfaceT& { | |
9536 | return *getInternal(); | |
9537 | } | |
9538 | }; | |
9539 | ||
9540 | } // namespace Catch | |
9541 | ||
9542 | // end catch_singletons.hpp | |
9543 | namespace Catch { | |
9544 | ||
9545 | namespace { | |
9546 | ||
9547 | class RegistryHub : public IRegistryHub, public IMutableRegistryHub, | |
9548 | private NonCopyable { | |
9549 | ||
9550 | public: // IRegistryHub | |
9551 | RegistryHub() = default; | |
9552 | IReporterRegistry const& getReporterRegistry() const override { | |
9553 | return m_reporterRegistry; | |
9554 | } | |
9555 | ITestCaseRegistry const& getTestCaseRegistry() const override { | |
9556 | return m_testCaseRegistry; | |
9557 | } | |
9558 | IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const override { | |
9559 | return m_exceptionTranslatorRegistry; | |
9560 | } | |
9561 | ITagAliasRegistry const& getTagAliasRegistry() const override { | |
9562 | return m_tagAliasRegistry; | |
9563 | } | |
9564 | StartupExceptionRegistry const& getStartupExceptionRegistry() const override { | |
9565 | return m_exceptionRegistry; | |
9566 | } | |
9567 | ||
9568 | public: // IMutableRegistryHub | |
9569 | void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) override { | |
9570 | m_reporterRegistry.registerReporter( name, factory ); | |
9571 | } | |
9572 | void registerListener( IReporterFactoryPtr const& factory ) override { | |
9573 | m_reporterRegistry.registerListener( factory ); | |
9574 | } | |
9575 | void registerTest( TestCase const& testInfo ) override { | |
9576 | m_testCaseRegistry.registerTest( testInfo ); | |
9577 | } | |
9578 | void registerTranslator( const IExceptionTranslator* translator ) override { | |
9579 | m_exceptionTranslatorRegistry.registerTranslator( translator ); | |
9580 | } | |
9581 | void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) override { | |
9582 | m_tagAliasRegistry.add( alias, tag, lineInfo ); | |
9583 | } | |
9584 | void registerStartupException() noexcept override { | |
9585 | m_exceptionRegistry.add(std::current_exception()); | |
9586 | } | |
9587 | ||
9588 | private: | |
9589 | TestRegistry m_testCaseRegistry; | |
9590 | ReporterRegistry m_reporterRegistry; | |
9591 | ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; | |
9592 | TagAliasRegistry m_tagAliasRegistry; | |
9593 | StartupExceptionRegistry m_exceptionRegistry; | |
9594 | }; | |
9595 | } | |
9596 | ||
9597 | using RegistryHubSingleton = Singleton<RegistryHub, IRegistryHub, IMutableRegistryHub>; | |
9598 | ||
9599 | IRegistryHub const& getRegistryHub() { | |
9600 | return RegistryHubSingleton::get(); | |
9601 | } | |
9602 | IMutableRegistryHub& getMutableRegistryHub() { | |
9603 | return RegistryHubSingleton::getMutable(); | |
9604 | } | |
9605 | void cleanUp() { | |
9606 | cleanupSingletons(); | |
9607 | cleanUpContext(); | |
9608 | } | |
9609 | std::string translateActiveException() { | |
9610 | return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); | |
9611 | } | |
9612 | ||
9613 | } // end namespace Catch | |
9614 | // end catch_registry_hub.cpp | |
9615 | // start catch_reporter_registry.cpp | |
9616 | ||
9617 | namespace Catch { | |
9618 | ||
9619 | ReporterRegistry::~ReporterRegistry() = default; | |
9620 | ||
9621 | IStreamingReporterPtr ReporterRegistry::create( std::string const& name, IConfigPtr const& config ) const { | |
9622 | auto it = m_factories.find( name ); | |
9623 | if( it == m_factories.end() ) | |
9624 | return nullptr; | |
9625 | return it->second->create( ReporterConfig( config ) ); | |
9626 | } | |
9627 | ||
9628 | void ReporterRegistry::registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) { | |
9629 | m_factories.emplace(name, factory); | |
9630 | } | |
9631 | void ReporterRegistry::registerListener( IReporterFactoryPtr const& factory ) { | |
9632 | m_listeners.push_back( factory ); | |
9633 | } | |
9634 | ||
9635 | IReporterRegistry::FactoryMap const& ReporterRegistry::getFactories() const { | |
9636 | return m_factories; | |
9637 | } | |
9638 | IReporterRegistry::Listeners const& ReporterRegistry::getListeners() const { | |
9639 | return m_listeners; | |
9640 | } | |
9641 | ||
9642 | } | |
9643 | // end catch_reporter_registry.cpp | |
9644 | // start catch_result_type.cpp | |
9645 | ||
9646 | namespace Catch { | |
9647 | ||
9648 | bool isOk( ResultWas::OfType resultType ) { | |
9649 | return ( resultType & ResultWas::FailureBit ) == 0; | |
9650 | } | |
9651 | bool isJustInfo( int flags ) { | |
9652 | return flags == ResultWas::Info; | |
9653 | } | |
9654 | ||
9655 | ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { | |
9656 | return static_cast<ResultDisposition::Flags>( static_cast<int>( lhs ) | static_cast<int>( rhs ) ); | |
9657 | } | |
9658 | ||
9659 | bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } | |
9660 | bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } | |
9661 | ||
9662 | } // end namespace Catch | |
9663 | // end catch_result_type.cpp | |
9664 | // start catch_run_context.cpp | |
9665 | ||
9666 | #include <cassert> | |
9667 | #include <algorithm> | |
9668 | #include <sstream> | |
9669 | ||
9670 | namespace Catch { | |
9671 | ||
9672 | namespace Generators { | |
9673 | struct GeneratorTracker : TestCaseTracking::TrackerBase, IGeneratorTracker { | |
9674 | size_t m_index = static_cast<size_t>( -1 ); | |
9675 | GeneratorBasePtr m_generator; | |
9676 | ||
9677 | GeneratorTracker( TestCaseTracking::NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) | |
9678 | : TrackerBase( nameAndLocation, ctx, parent ) | |
9679 | {} | |
9680 | ~GeneratorTracker(); | |
9681 | ||
9682 | static GeneratorTracker& acquire( TrackerContext& ctx, TestCaseTracking::NameAndLocation const& nameAndLocation ) { | |
9683 | std::shared_ptr<GeneratorTracker> tracker; | |
9684 | ||
9685 | ITracker& currentTracker = ctx.currentTracker(); | |
9686 | if( TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { | |
9687 | assert( childTracker ); | |
9688 | assert( childTracker->isIndexTracker() ); | |
9689 | tracker = std::static_pointer_cast<GeneratorTracker>( childTracker ); | |
9690 | } | |
9691 | else { | |
9692 | tracker = std::make_shared<GeneratorTracker>( nameAndLocation, ctx, ¤tTracker ); | |
9693 | currentTracker.addChild( tracker ); | |
9694 | } | |
9695 | ||
9696 | if( !ctx.completedCycle() && !tracker->isComplete() ) { | |
9697 | if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun ) | |
9698 | tracker->moveNext(); | |
9699 | tracker->open(); | |
9700 | } | |
9701 | ||
9702 | return *tracker; | |
9703 | } | |
9704 | ||
9705 | void moveNext() { | |
9706 | m_index++; | |
9707 | m_children.clear(); | |
9708 | } | |
9709 | ||
9710 | // TrackerBase interface | |
9711 | bool isIndexTracker() const override { return true; } | |
9712 | auto hasGenerator() const -> bool override { | |
9713 | return !!m_generator; | |
9714 | } | |
9715 | void close() override { | |
9716 | TrackerBase::close(); | |
9717 | if( m_runState == CompletedSuccessfully && m_index < m_generator->size()-1 ) | |
9718 | m_runState = Executing; | |
9719 | } | |
9720 | ||
9721 | // IGeneratorTracker interface | |
9722 | auto getGenerator() const -> GeneratorBasePtr const& override { | |
9723 | return m_generator; | |
9724 | } | |
9725 | void setGenerator( GeneratorBasePtr&& generator ) override { | |
9726 | m_generator = std::move( generator ); | |
9727 | } | |
9728 | auto getIndex() const -> size_t override { | |
9729 | return m_index; | |
9730 | } | |
9731 | }; | |
9732 | GeneratorTracker::~GeneratorTracker() {} | |
9733 | } | |
9734 | ||
9735 | RunContext::RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter) | |
9736 | : m_runInfo(_config->name()), | |
9737 | m_context(getCurrentMutableContext()), | |
9738 | m_config(_config), | |
9739 | m_reporter(std::move(reporter)), | |
9740 | m_lastAssertionInfo{ StringRef(), SourceLineInfo("",0), StringRef(), ResultDisposition::Normal }, | |
9741 | m_includeSuccessfulResults( m_config->includeSuccessfulResults() || m_reporter->getPreferences().shouldReportAllAssertions ) | |
9742 | { | |
9743 | m_context.setRunner(this); | |
9744 | m_context.setConfig(m_config); | |
9745 | m_context.setResultCapture(this); | |
9746 | m_reporter->testRunStarting(m_runInfo); | |
9747 | } | |
9748 | ||
9749 | RunContext::~RunContext() { | |
9750 | m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, aborting())); | |
9751 | } | |
9752 | ||
9753 | void RunContext::testGroupStarting(std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount) { | |
9754 | m_reporter->testGroupStarting(GroupInfo(testSpec, groupIndex, groupsCount)); | |
9755 | } | |
9756 | ||
9757 | void RunContext::testGroupEnded(std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount) { | |
9758 | m_reporter->testGroupEnded(TestGroupStats(GroupInfo(testSpec, groupIndex, groupsCount), totals, aborting())); | |
9759 | } | |
9760 | ||
9761 | Totals RunContext::runTest(TestCase const& testCase) { | |
9762 | Totals prevTotals = m_totals; | |
9763 | ||
9764 | std::string redirectedCout; | |
9765 | std::string redirectedCerr; | |
9766 | ||
9767 | auto const& testInfo = testCase.getTestCaseInfo(); | |
9768 | ||
9769 | m_reporter->testCaseStarting(testInfo); | |
9770 | ||
9771 | m_activeTestCase = &testCase; | |
9772 | ||
9773 | ITracker& rootTracker = m_trackerContext.startRun(); | |
9774 | assert(rootTracker.isSectionTracker()); | |
9775 | static_cast<SectionTracker&>(rootTracker).addInitialFilters(m_config->getSectionsToRun()); | |
9776 | do { | |
9777 | m_trackerContext.startCycle(); | |
9778 | m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(testInfo.name, testInfo.lineInfo)); | |
9779 | runCurrentTest(redirectedCout, redirectedCerr); | |
9780 | } while (!m_testCaseTracker->isSuccessfullyCompleted() && !aborting()); | |
9781 | ||
9782 | Totals deltaTotals = m_totals.delta(prevTotals); | |
9783 | if (testInfo.expectedToFail() && deltaTotals.testCases.passed > 0) { | |
9784 | deltaTotals.assertions.failed++; | |
9785 | deltaTotals.testCases.passed--; | |
9786 | deltaTotals.testCases.failed++; | |
9787 | } | |
9788 | m_totals.testCases += deltaTotals.testCases; | |
9789 | m_reporter->testCaseEnded(TestCaseStats(testInfo, | |
9790 | deltaTotals, | |
9791 | redirectedCout, | |
9792 | redirectedCerr, | |
9793 | aborting())); | |
9794 | ||
9795 | m_activeTestCase = nullptr; | |
9796 | m_testCaseTracker = nullptr; | |
9797 | ||
9798 | return deltaTotals; | |
9799 | } | |
9800 | ||
9801 | IConfigPtr RunContext::config() const { | |
9802 | return m_config; | |
9803 | } | |
9804 | ||
9805 | IStreamingReporter& RunContext::reporter() const { | |
9806 | return *m_reporter; | |
9807 | } | |
9808 | ||
9809 | void RunContext::assertionEnded(AssertionResult const & result) { | |
9810 | if (result.getResultType() == ResultWas::Ok) { | |
9811 | m_totals.assertions.passed++; | |
9812 | m_lastAssertionPassed = true; | |
9813 | } else if (!result.isOk()) { | |
9814 | m_lastAssertionPassed = false; | |
9815 | if( m_activeTestCase->getTestCaseInfo().okToFail() ) | |
9816 | m_totals.assertions.failedButOk++; | |
9817 | else | |
9818 | m_totals.assertions.failed++; | |
9819 | } | |
9820 | else { | |
9821 | m_lastAssertionPassed = true; | |
9822 | } | |
9823 | ||
9824 | // We have no use for the return value (whether messages should be cleared), because messages were made scoped | |
9825 | // and should be let to clear themselves out. | |
9826 | static_cast<void>(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals))); | |
9827 | ||
9828 | // Reset working state | |
9829 | resetAssertionInfo(); | |
9830 | m_lastResult = result; | |
9831 | } | |
9832 | void RunContext::resetAssertionInfo() { | |
9833 | m_lastAssertionInfo.macroName = StringRef(); | |
9834 | m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"_sr; | |
9835 | } | |
9836 | ||
9837 | bool RunContext::sectionStarted(SectionInfo const & sectionInfo, Counts & assertions) { | |
9838 | ITracker& sectionTracker = SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(sectionInfo.name, sectionInfo.lineInfo)); | |
9839 | if (!sectionTracker.isOpen()) | |
9840 | return false; | |
9841 | m_activeSections.push_back(§ionTracker); | |
9842 | ||
9843 | m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; | |
9844 | ||
9845 | m_reporter->sectionStarting(sectionInfo); | |
9846 | ||
9847 | assertions = m_totals.assertions; | |
9848 | ||
9849 | return true; | |
9850 | } | |
9851 | auto RunContext::acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { | |
9852 | using namespace Generators; | |
9853 | GeneratorTracker& tracker = GeneratorTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( "generator", lineInfo ) ); | |
9854 | assert( tracker.isOpen() ); | |
9855 | m_lastAssertionInfo.lineInfo = lineInfo; | |
9856 | return tracker; | |
9857 | } | |
9858 | ||
9859 | bool RunContext::testForMissingAssertions(Counts& assertions) { | |
9860 | if (assertions.total() != 0) | |
9861 | return false; | |
9862 | if (!m_config->warnAboutMissingAssertions()) | |
9863 | return false; | |
9864 | if (m_trackerContext.currentTracker().hasChildren()) | |
9865 | return false; | |
9866 | m_totals.assertions.failed++; | |
9867 | assertions.failed++; | |
9868 | return true; | |
9869 | } | |
9870 | ||
9871 | void RunContext::sectionEnded(SectionEndInfo const & endInfo) { | |
9872 | Counts assertions = m_totals.assertions - endInfo.prevAssertions; | |
9873 | bool missingAssertions = testForMissingAssertions(assertions); | |
9874 | ||
9875 | if (!m_activeSections.empty()) { | |
9876 | m_activeSections.back()->close(); | |
9877 | m_activeSections.pop_back(); | |
9878 | } | |
9879 | ||
9880 | m_reporter->sectionEnded(SectionStats(endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions)); | |
9881 | m_messages.clear(); | |
9882 | } | |
9883 | ||
9884 | void RunContext::sectionEndedEarly(SectionEndInfo const & endInfo) { | |
9885 | if (m_unfinishedSections.empty()) | |
9886 | m_activeSections.back()->fail(); | |
9887 | else | |
9888 | m_activeSections.back()->close(); | |
9889 | m_activeSections.pop_back(); | |
9890 | ||
9891 | m_unfinishedSections.push_back(endInfo); | |
9892 | } | |
9893 | void RunContext::benchmarkStarting( BenchmarkInfo const& info ) { | |
9894 | m_reporter->benchmarkStarting( info ); | |
9895 | } | |
9896 | void RunContext::benchmarkEnded( BenchmarkStats const& stats ) { | |
9897 | m_reporter->benchmarkEnded( stats ); | |
9898 | } | |
9899 | ||
9900 | void RunContext::pushScopedMessage(MessageInfo const & message) { | |
9901 | m_messages.push_back(message); | |
9902 | } | |
9903 | ||
9904 | void RunContext::popScopedMessage(MessageInfo const & message) { | |
9905 | m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end()); | |
9906 | } | |
9907 | ||
9908 | std::string RunContext::getCurrentTestName() const { | |
9909 | return m_activeTestCase | |
9910 | ? m_activeTestCase->getTestCaseInfo().name | |
9911 | : std::string(); | |
9912 | } | |
9913 | ||
9914 | const AssertionResult * RunContext::getLastResult() const { | |
9915 | return &(*m_lastResult); | |
9916 | } | |
9917 | ||
9918 | void RunContext::exceptionEarlyReported() { | |
9919 | m_shouldReportUnexpected = false; | |
9920 | } | |
9921 | ||
9922 | void RunContext::handleFatalErrorCondition( StringRef message ) { | |
9923 | // First notify reporter that bad things happened | |
9924 | m_reporter->fatalErrorEncountered(message); | |
9925 | ||
9926 | // Don't rebuild the result -- the stringification itself can cause more fatal errors | |
9927 | // Instead, fake a result data. | |
9928 | AssertionResultData tempResult( ResultWas::FatalErrorCondition, { false } ); | |
9929 | tempResult.message = message; | |
9930 | AssertionResult result(m_lastAssertionInfo, tempResult); | |
9931 | ||
9932 | assertionEnded(result); | |
9933 | ||
9934 | handleUnfinishedSections(); | |
9935 | ||
9936 | // Recreate section for test case (as we will lose the one that was in scope) | |
9937 | auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); | |
9938 | SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name); | |
9939 | ||
9940 | Counts assertions; | |
9941 | assertions.failed = 1; | |
9942 | SectionStats testCaseSectionStats(testCaseSection, assertions, 0, false); | |
9943 | m_reporter->sectionEnded(testCaseSectionStats); | |
9944 | ||
9945 | auto const& testInfo = m_activeTestCase->getTestCaseInfo(); | |
9946 | ||
9947 | Totals deltaTotals; | |
9948 | deltaTotals.testCases.failed = 1; | |
9949 | deltaTotals.assertions.failed = 1; | |
9950 | m_reporter->testCaseEnded(TestCaseStats(testInfo, | |
9951 | deltaTotals, | |
9952 | std::string(), | |
9953 | std::string(), | |
9954 | false)); | |
9955 | m_totals.testCases.failed++; | |
9956 | testGroupEnded(std::string(), m_totals, 1, 1); | |
9957 | m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, false)); | |
9958 | } | |
9959 | ||
9960 | bool RunContext::lastAssertionPassed() { | |
9961 | return m_lastAssertionPassed; | |
9962 | } | |
9963 | ||
9964 | void RunContext::assertionPassed() { | |
9965 | m_lastAssertionPassed = true; | |
9966 | ++m_totals.assertions.passed; | |
9967 | resetAssertionInfo(); | |
9968 | } | |
9969 | ||
9970 | bool RunContext::aborting() const { | |
9971 | return m_totals.assertions.failed >= static_cast<std::size_t>(m_config->abortAfter()); | |
9972 | } | |
9973 | ||
9974 | void RunContext::runCurrentTest(std::string & redirectedCout, std::string & redirectedCerr) { | |
9975 | auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); | |
9976 | SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name); | |
9977 | m_reporter->sectionStarting(testCaseSection); | |
9978 | Counts prevAssertions = m_totals.assertions; | |
9979 | double duration = 0; | |
9980 | m_shouldReportUnexpected = true; | |
9981 | m_lastAssertionInfo = { "TEST_CASE"_sr, testCaseInfo.lineInfo, StringRef(), ResultDisposition::Normal }; | |
9982 | ||
9983 | seedRng(*m_config); | |
9984 | ||
9985 | Timer timer; | |
9986 | CATCH_TRY { | |
9987 | if (m_reporter->getPreferences().shouldRedirectStdOut) { | |
9988 | #if !defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) | |
9989 | RedirectedStdOut redirectedStdOut; | |
9990 | RedirectedStdErr redirectedStdErr; | |
9991 | ||
9992 | timer.start(); | |
9993 | invokeActiveTestCase(); | |
9994 | redirectedCout += redirectedStdOut.str(); | |
9995 | redirectedCerr += redirectedStdErr.str(); | |
9996 | #else | |
9997 | OutputRedirect r(redirectedCout, redirectedCerr); | |
9998 | timer.start(); | |
9999 | invokeActiveTestCase(); | |
10000 | #endif | |
10001 | } else { | |
10002 | timer.start(); | |
10003 | invokeActiveTestCase(); | |
10004 | } | |
10005 | duration = timer.getElapsedSeconds(); | |
10006 | } CATCH_CATCH_ANON (TestFailureException&) { | |
10007 | // This just means the test was aborted due to failure | |
10008 | } CATCH_CATCH_ALL { | |
10009 | // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions | |
10010 | // are reported without translation at the point of origin. | |
10011 | if( m_shouldReportUnexpected ) { | |
10012 | AssertionReaction dummyReaction; | |
10013 | handleUnexpectedInflightException( m_lastAssertionInfo, translateActiveException(), dummyReaction ); | |
10014 | } | |
10015 | } | |
10016 | Counts assertions = m_totals.assertions - prevAssertions; | |
10017 | bool missingAssertions = testForMissingAssertions(assertions); | |
10018 | ||
10019 | m_testCaseTracker->close(); | |
10020 | handleUnfinishedSections(); | |
10021 | m_messages.clear(); | |
10022 | ||
10023 | SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions); | |
10024 | m_reporter->sectionEnded(testCaseSectionStats); | |
10025 | } | |
10026 | ||
10027 | void RunContext::invokeActiveTestCase() { | |
10028 | FatalConditionHandler fatalConditionHandler; // Handle signals | |
10029 | m_activeTestCase->invoke(); | |
10030 | fatalConditionHandler.reset(); | |
10031 | } | |
10032 | ||
10033 | void RunContext::handleUnfinishedSections() { | |
10034 | // If sections ended prematurely due to an exception we stored their | |
10035 | // infos here so we can tear them down outside the unwind process. | |
10036 | for (auto it = m_unfinishedSections.rbegin(), | |
10037 | itEnd = m_unfinishedSections.rend(); | |
10038 | it != itEnd; | |
10039 | ++it) | |
10040 | sectionEnded(*it); | |
10041 | m_unfinishedSections.clear(); | |
10042 | } | |
10043 | ||
10044 | void RunContext::handleExpr( | |
10045 | AssertionInfo const& info, | |
10046 | ITransientExpression const& expr, | |
10047 | AssertionReaction& reaction | |
10048 | ) { | |
10049 | m_reporter->assertionStarting( info ); | |
10050 | ||
10051 | bool negated = isFalseTest( info.resultDisposition ); | |
10052 | bool result = expr.getResult() != negated; | |
10053 | ||
10054 | if( result ) { | |
10055 | if (!m_includeSuccessfulResults) { | |
10056 | assertionPassed(); | |
10057 | } | |
10058 | else { | |
10059 | reportExpr(info, ResultWas::Ok, &expr, negated); | |
10060 | } | |
10061 | } | |
10062 | else { | |
10063 | reportExpr(info, ResultWas::ExpressionFailed, &expr, negated ); | |
10064 | populateReaction( reaction ); | |
10065 | } | |
10066 | } | |
10067 | void RunContext::reportExpr( | |
10068 | AssertionInfo const &info, | |
10069 | ResultWas::OfType resultType, | |
10070 | ITransientExpression const *expr, | |
10071 | bool negated ) { | |
10072 | ||
10073 | m_lastAssertionInfo = info; | |
10074 | AssertionResultData data( resultType, LazyExpression( negated ) ); | |
10075 | ||
10076 | AssertionResult assertionResult{ info, data }; | |
10077 | assertionResult.m_resultData.lazyExpression.m_transientExpression = expr; | |
10078 | ||
10079 | assertionEnded( assertionResult ); | |
10080 | } | |
10081 | ||
10082 | void RunContext::handleMessage( | |
10083 | AssertionInfo const& info, | |
10084 | ResultWas::OfType resultType, | |
10085 | StringRef const& message, | |
10086 | AssertionReaction& reaction | |
10087 | ) { | |
10088 | m_reporter->assertionStarting( info ); | |
10089 | ||
10090 | m_lastAssertionInfo = info; | |
10091 | ||
10092 | AssertionResultData data( resultType, LazyExpression( false ) ); | |
10093 | data.message = message; | |
10094 | AssertionResult assertionResult{ m_lastAssertionInfo, data }; | |
10095 | assertionEnded( assertionResult ); | |
10096 | if( !assertionResult.isOk() ) | |
10097 | populateReaction( reaction ); | |
10098 | } | |
10099 | void RunContext::handleUnexpectedExceptionNotThrown( | |
10100 | AssertionInfo const& info, | |
10101 | AssertionReaction& reaction | |
10102 | ) { | |
10103 | handleNonExpr(info, Catch::ResultWas::DidntThrowException, reaction); | |
10104 | } | |
10105 | ||
10106 | void RunContext::handleUnexpectedInflightException( | |
10107 | AssertionInfo const& info, | |
10108 | std::string const& message, | |
10109 | AssertionReaction& reaction | |
10110 | ) { | |
10111 | m_lastAssertionInfo = info; | |
10112 | ||
10113 | AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); | |
10114 | data.message = message; | |
10115 | AssertionResult assertionResult{ info, data }; | |
10116 | assertionEnded( assertionResult ); | |
10117 | populateReaction( reaction ); | |
10118 | } | |
10119 | ||
10120 | void RunContext::populateReaction( AssertionReaction& reaction ) { | |
10121 | reaction.shouldDebugBreak = m_config->shouldDebugBreak(); | |
10122 | reaction.shouldThrow = aborting() || (m_lastAssertionInfo.resultDisposition & ResultDisposition::Normal); | |
10123 | } | |
10124 | ||
10125 | void RunContext::handleIncomplete( | |
10126 | AssertionInfo const& info | |
10127 | ) { | |
10128 | m_lastAssertionInfo = info; | |
10129 | ||
10130 | AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); | |
10131 | data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"; | |
10132 | AssertionResult assertionResult{ info, data }; | |
10133 | assertionEnded( assertionResult ); | |
10134 | } | |
10135 | void RunContext::handleNonExpr( | |
10136 | AssertionInfo const &info, | |
10137 | ResultWas::OfType resultType, | |
10138 | AssertionReaction &reaction | |
10139 | ) { | |
10140 | m_lastAssertionInfo = info; | |
10141 | ||
10142 | AssertionResultData data( resultType, LazyExpression( false ) ); | |
10143 | AssertionResult assertionResult{ info, data }; | |
10144 | assertionEnded( assertionResult ); | |
10145 | ||
10146 | if( !assertionResult.isOk() ) | |
10147 | populateReaction( reaction ); | |
10148 | } | |
10149 | ||
10150 | IResultCapture& getResultCapture() { | |
10151 | if (auto* capture = getCurrentContext().getResultCapture()) | |
10152 | return *capture; | |
10153 | else | |
10154 | CATCH_INTERNAL_ERROR("No result capture instance"); | |
10155 | } | |
10156 | } | |
10157 | // end catch_run_context.cpp | |
10158 | // start catch_section.cpp | |
10159 | ||
10160 | namespace Catch { | |
10161 | ||
10162 | Section::Section( SectionInfo const& info ) | |
10163 | : m_info( info ), | |
10164 | m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) ) | |
10165 | { | |
10166 | m_timer.start(); | |
10167 | } | |
10168 | ||
10169 | Section::~Section() { | |
10170 | if( m_sectionIncluded ) { | |
10171 | SectionEndInfo endInfo{ m_info, m_assertions, m_timer.getElapsedSeconds() }; | |
10172 | if( uncaught_exceptions() ) | |
10173 | getResultCapture().sectionEndedEarly( endInfo ); | |
10174 | else | |
10175 | getResultCapture().sectionEnded( endInfo ); | |
10176 | } | |
10177 | } | |
10178 | ||
10179 | // This indicates whether the section should be executed or not | |
10180 | Section::operator bool() const { | |
10181 | return m_sectionIncluded; | |
10182 | } | |
10183 | ||
10184 | } // end namespace Catch | |
10185 | // end catch_section.cpp | |
10186 | // start catch_section_info.cpp | |
10187 | ||
10188 | namespace Catch { | |
10189 | ||
10190 | SectionInfo::SectionInfo | |
10191 | ( SourceLineInfo const& _lineInfo, | |
10192 | std::string const& _name ) | |
10193 | : name( _name ), | |
10194 | lineInfo( _lineInfo ) | |
10195 | {} | |
10196 | ||
10197 | } // end namespace Catch | |
10198 | // end catch_section_info.cpp | |
10199 | // start catch_session.cpp | |
10200 | ||
10201 | // start catch_session.h | |
10202 | ||
10203 | #include <memory> | |
10204 | ||
10205 | namespace Catch { | |
10206 | ||
10207 | class Session : NonCopyable { | |
10208 | public: | |
10209 | ||
10210 | Session(); | |
10211 | ~Session() override; | |
10212 | ||
10213 | void showHelp() const; | |
10214 | void libIdentify(); | |
10215 | ||
10216 | int applyCommandLine( int argc, char const * const * argv ); | |
10217 | #if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE) | |
10218 | int applyCommandLine( int argc, wchar_t const * const * argv ); | |
10219 | #endif | |
10220 | ||
10221 | void useConfigData( ConfigData const& configData ); | |
10222 | ||
10223 | template<typename CharT> | |
10224 | int run(int argc, CharT const * const argv[]) { | |
10225 | if (m_startupExceptions) | |
10226 | return 1; | |
10227 | int returnCode = applyCommandLine(argc, argv); | |
10228 | if (returnCode == 0) | |
10229 | returnCode = run(); | |
10230 | return returnCode; | |
10231 | } | |
10232 | ||
10233 | int run(); | |
10234 | ||
10235 | clara::Parser const& cli() const; | |
10236 | void cli( clara::Parser const& newParser ); | |
10237 | ConfigData& configData(); | |
10238 | Config& config(); | |
10239 | private: | |
10240 | int runInternal(); | |
10241 | ||
10242 | clara::Parser m_cli; | |
10243 | ConfigData m_configData; | |
10244 | std::shared_ptr<Config> m_config; | |
10245 | bool m_startupExceptions = false; | |
10246 | }; | |
10247 | ||
10248 | } // end namespace Catch | |
10249 | ||
10250 | // end catch_session.h | |
10251 | // start catch_version.h | |
10252 | ||
10253 | #include <iosfwd> | |
10254 | ||
10255 | namespace Catch { | |
10256 | ||
10257 | // Versioning information | |
10258 | struct Version { | |
10259 | Version( Version const& ) = delete; | |
10260 | Version& operator=( Version const& ) = delete; | |
10261 | Version( unsigned int _majorVersion, | |
10262 | unsigned int _minorVersion, | |
10263 | unsigned int _patchNumber, | |
10264 | char const * const _branchName, | |
10265 | unsigned int _buildNumber ); | |
10266 | ||
10267 | unsigned int const majorVersion; | |
10268 | unsigned int const minorVersion; | |
10269 | unsigned int const patchNumber; | |
10270 | ||
10271 | // buildNumber is only used if branchName is not null | |
10272 | char const * const branchName; | |
10273 | unsigned int const buildNumber; | |
10274 | ||
10275 | friend std::ostream& operator << ( std::ostream& os, Version const& version ); | |
10276 | }; | |
10277 | ||
10278 | Version const& libraryVersion(); | |
10279 | } | |
10280 | ||
10281 | // end catch_version.h | |
10282 | #include <cstdlib> | |
10283 | #include <iomanip> | |
10284 | ||
10285 | namespace Catch { | |
10286 | ||
10287 | namespace { | |
10288 | const int MaxExitCode = 255; | |
10289 | ||
10290 | IStreamingReporterPtr createReporter(std::string const& reporterName, IConfigPtr const& config) { | |
10291 | auto reporter = Catch::getRegistryHub().getReporterRegistry().create(reporterName, config); | |
10292 | CATCH_ENFORCE(reporter, "No reporter registered with name: '" << reporterName << "'"); | |
10293 | ||
10294 | return reporter; | |
10295 | } | |
10296 | ||
10297 | IStreamingReporterPtr makeReporter(std::shared_ptr<Config> const& config) { | |
10298 | if (Catch::getRegistryHub().getReporterRegistry().getListeners().empty()) { | |
10299 | return createReporter(config->getReporterName(), config); | |
10300 | } | |
10301 | ||
10302 | auto multi = std::unique_ptr<ListeningReporter>(new ListeningReporter); | |
10303 | ||
10304 | auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners(); | |
10305 | for (auto const& listener : listeners) { | |
10306 | multi->addListener(listener->create(Catch::ReporterConfig(config))); | |
10307 | } | |
10308 | multi->addReporter(createReporter(config->getReporterName(), config)); | |
10309 | return std::move(multi); | |
10310 | } | |
10311 | ||
10312 | Catch::Totals runTests(std::shared_ptr<Config> const& config) { | |
10313 | auto reporter = makeReporter(config); | |
10314 | ||
10315 | RunContext context(config, std::move(reporter)); | |
10316 | ||
10317 | Totals totals; | |
10318 | ||
10319 | context.testGroupStarting(config->name(), 1, 1); | |
10320 | ||
10321 | TestSpec testSpec = config->testSpec(); | |
10322 | ||
10323 | auto const& allTestCases = getAllTestCasesSorted(*config); | |
10324 | for (auto const& testCase : allTestCases) { | |
10325 | if (!context.aborting() && matchTest(testCase, testSpec, *config)) | |
10326 | totals += context.runTest(testCase); | |
10327 | else | |
10328 | context.reporter().skipTest(testCase); | |
10329 | } | |
10330 | ||
10331 | if (config->warnAboutNoTests() && totals.testCases.total() == 0) { | |
10332 | ReusableStringStream testConfig; | |
10333 | ||
10334 | bool first = true; | |
10335 | for (const auto& input : config->getTestsOrTags()) { | |
10336 | if (!first) { testConfig << ' '; } | |
10337 | first = false; | |
10338 | testConfig << input; | |
10339 | } | |
10340 | ||
10341 | context.reporter().noMatchingTestCases(testConfig.str()); | |
10342 | totals.error = -1; | |
10343 | } | |
10344 | ||
10345 | context.testGroupEnded(config->name(), totals, 1, 1); | |
10346 | return totals; | |
10347 | } | |
10348 | ||
10349 | void applyFilenamesAsTags(Catch::IConfig const& config) { | |
10350 | auto& tests = const_cast<std::vector<TestCase>&>(getAllTestCasesSorted(config)); | |
10351 | for (auto& testCase : tests) { | |
10352 | auto tags = testCase.tags; | |
10353 | ||
10354 | std::string filename = testCase.lineInfo.file; | |
10355 | auto lastSlash = filename.find_last_of("\\/"); | |
10356 | if (lastSlash != std::string::npos) { | |
10357 | filename.erase(0, lastSlash); | |
10358 | filename[0] = '#'; | |
10359 | } | |
10360 | ||
10361 | auto lastDot = filename.find_last_of('.'); | |
10362 | if (lastDot != std::string::npos) { | |
10363 | filename.erase(lastDot); | |
10364 | } | |
10365 | ||
10366 | tags.push_back(std::move(filename)); | |
10367 | setTags(testCase, tags); | |
10368 | } | |
10369 | } | |
10370 | ||
10371 | } // anon namespace | |
10372 | ||
10373 | Session::Session() { | |
10374 | static bool alreadyInstantiated = false; | |
10375 | if( alreadyInstantiated ) { | |
10376 | CATCH_TRY { CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); } | |
10377 | CATCH_CATCH_ALL { getMutableRegistryHub().registerStartupException(); } | |
10378 | } | |
10379 | ||
10380 | // There cannot be exceptions at startup in no-exception mode. | |
10381 | #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) | |
10382 | const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions(); | |
10383 | if ( !exceptions.empty() ) { | |
10384 | m_startupExceptions = true; | |
10385 | Colour colourGuard( Colour::Red ); | |
10386 | Catch::cerr() << "Errors occurred during startup!" << '\n'; | |
10387 | // iterate over all exceptions and notify user | |
10388 | for ( const auto& ex_ptr : exceptions ) { | |
10389 | try { | |
10390 | std::rethrow_exception(ex_ptr); | |
10391 | } catch ( std::exception const& ex ) { | |
10392 | Catch::cerr() << Column( ex.what() ).indent(2) << '\n'; | |
10393 | } | |
10394 | } | |
10395 | } | |
10396 | #endif | |
10397 | ||
10398 | alreadyInstantiated = true; | |
10399 | m_cli = makeCommandLineParser( m_configData ); | |
10400 | } | |
10401 | Session::~Session() { | |
10402 | Catch::cleanUp(); | |
10403 | } | |
10404 | ||
10405 | void Session::showHelp() const { | |
10406 | Catch::cout() | |
10407 | << "\nCatch v" << libraryVersion() << "\n" | |
10408 | << m_cli << std::endl | |
10409 | << "For more detailed usage please see the project docs\n" << std::endl; | |
10410 | } | |
10411 | void Session::libIdentify() { | |
10412 | Catch::cout() | |
10413 | << std::left << std::setw(16) << "description: " << "A Catch test executable\n" | |
10414 | << std::left << std::setw(16) << "category: " << "testframework\n" | |
10415 | << std::left << std::setw(16) << "framework: " << "Catch Test\n" | |
10416 | << std::left << std::setw(16) << "version: " << libraryVersion() << std::endl; | |
10417 | } | |
10418 | ||
10419 | int Session::applyCommandLine( int argc, char const * const * argv ) { | |
10420 | if( m_startupExceptions ) | |
10421 | return 1; | |
10422 | ||
10423 | auto result = m_cli.parse( clara::Args( argc, argv ) ); | |
10424 | if( !result ) { | |
10425 | Catch::cerr() | |
10426 | << Colour( Colour::Red ) | |
10427 | << "\nError(s) in input:\n" | |
10428 | << Column( result.errorMessage() ).indent( 2 ) | |
10429 | << "\n\n"; | |
10430 | Catch::cerr() << "Run with -? for usage\n" << std::endl; | |
10431 | return MaxExitCode; | |
10432 | } | |
10433 | ||
10434 | if( m_configData.showHelp ) | |
10435 | showHelp(); | |
10436 | if( m_configData.libIdentify ) | |
10437 | libIdentify(); | |
10438 | m_config.reset(); | |
10439 | return 0; | |
10440 | } | |
10441 | ||
10442 | #if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE) | |
10443 | int Session::applyCommandLine( int argc, wchar_t const * const * argv ) { | |
10444 | ||
10445 | char **utf8Argv = new char *[ argc ]; | |
10446 | ||
10447 | for ( int i = 0; i < argc; ++i ) { | |
10448 | int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL ); | |
10449 | ||
10450 | utf8Argv[ i ] = new char[ bufSize ]; | |
10451 | ||
10452 | WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL ); | |
10453 | } | |
10454 | ||
10455 | int returnCode = applyCommandLine( argc, utf8Argv ); | |
10456 | ||
10457 | for ( int i = 0; i < argc; ++i ) | |
10458 | delete [] utf8Argv[ i ]; | |
10459 | ||
10460 | delete [] utf8Argv; | |
10461 | ||
10462 | return returnCode; | |
10463 | } | |
10464 | #endif | |
10465 | ||
10466 | void Session::useConfigData( ConfigData const& configData ) { | |
10467 | m_configData = configData; | |
10468 | m_config.reset(); | |
10469 | } | |
10470 | ||
10471 | int Session::run() { | |
10472 | if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) { | |
10473 | Catch::cout() << "...waiting for enter/ return before starting" << std::endl; | |
10474 | static_cast<void>(std::getchar()); | |
10475 | } | |
10476 | int exitCode = runInternal(); | |
10477 | if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) { | |
10478 | Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << std::endl; | |
10479 | static_cast<void>(std::getchar()); | |
10480 | } | |
10481 | return exitCode; | |
10482 | } | |
10483 | ||
10484 | clara::Parser const& Session::cli() const { | |
10485 | return m_cli; | |
10486 | } | |
10487 | void Session::cli( clara::Parser const& newParser ) { | |
10488 | m_cli = newParser; | |
10489 | } | |
10490 | ConfigData& Session::configData() { | |
10491 | return m_configData; | |
10492 | } | |
10493 | Config& Session::config() { | |
10494 | if( !m_config ) | |
10495 | m_config = std::make_shared<Config>( m_configData ); | |
10496 | return *m_config; | |
10497 | } | |
10498 | ||
10499 | int Session::runInternal() { | |
10500 | if( m_startupExceptions ) | |
10501 | return 1; | |
10502 | ||
10503 | if (m_configData.showHelp || m_configData.libIdentify) { | |
10504 | return 0; | |
10505 | } | |
10506 | ||
10507 | CATCH_TRY { | |
10508 | config(); // Force config to be constructed | |
10509 | ||
10510 | seedRng( *m_config ); | |
10511 | ||
10512 | if( m_configData.filenamesAsTags ) | |
10513 | applyFilenamesAsTags( *m_config ); | |
10514 | ||
10515 | // Handle list request | |
10516 | if( Option<std::size_t> listed = list( config() ) ) | |
10517 | return static_cast<int>( *listed ); | |
10518 | ||
10519 | auto totals = runTests( m_config ); | |
10520 | // Note that on unices only the lower 8 bits are usually used, clamping | |
10521 | // the return value to 255 prevents false negative when some multiple | |
10522 | // of 256 tests has failed | |
10523 | return (std::min) (MaxExitCode, (std::max) (totals.error, static_cast<int>(totals.assertions.failed))); | |
10524 | } | |
10525 | #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) | |
10526 | catch( std::exception& ex ) { | |
10527 | Catch::cerr() << ex.what() << std::endl; | |
10528 | return MaxExitCode; | |
10529 | } | |
10530 | #endif | |
10531 | } | |
10532 | ||
10533 | } // end namespace Catch | |
10534 | // end catch_session.cpp | |
10535 | // start catch_singletons.cpp | |
10536 | ||
10537 | #include <vector> | |
10538 | ||
10539 | namespace Catch { | |
10540 | ||
10541 | namespace { | |
10542 | static auto getSingletons() -> std::vector<ISingleton*>*& { | |
10543 | static std::vector<ISingleton*>* g_singletons = nullptr; | |
10544 | if( !g_singletons ) | |
10545 | g_singletons = new std::vector<ISingleton*>(); | |
10546 | return g_singletons; | |
10547 | } | |
10548 | } | |
10549 | ||
10550 | ISingleton::~ISingleton() {} | |
10551 | ||
10552 | void addSingleton(ISingleton* singleton ) { | |
10553 | getSingletons()->push_back( singleton ); | |
10554 | } | |
10555 | void cleanupSingletons() { | |
10556 | auto& singletons = getSingletons(); | |
10557 | for( auto singleton : *singletons ) | |
10558 | delete singleton; | |
10559 | delete singletons; | |
10560 | singletons = nullptr; | |
10561 | } | |
10562 | ||
10563 | } // namespace Catch | |
10564 | // end catch_singletons.cpp | |
10565 | // start catch_startup_exception_registry.cpp | |
10566 | ||
10567 | namespace Catch { | |
10568 | void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept { | |
10569 | CATCH_TRY { | |
10570 | m_exceptions.push_back(exception); | |
10571 | } CATCH_CATCH_ALL { | |
10572 | // If we run out of memory during start-up there's really not a lot more we can do about it | |
10573 | std::terminate(); | |
10574 | } | |
10575 | } | |
10576 | ||
10577 | std::vector<std::exception_ptr> const& StartupExceptionRegistry::getExceptions() const noexcept { | |
10578 | return m_exceptions; | |
10579 | } | |
10580 | ||
10581 | } // end namespace Catch | |
10582 | // end catch_startup_exception_registry.cpp | |
10583 | // start catch_stream.cpp | |
10584 | ||
10585 | #include <cstdio> | |
10586 | #include <iostream> | |
10587 | #include <fstream> | |
10588 | #include <sstream> | |
10589 | #include <vector> | |
10590 | #include <memory> | |
10591 | ||
10592 | namespace Catch { | |
10593 | ||
10594 | Catch::IStream::~IStream() = default; | |
10595 | ||
10596 | namespace detail { namespace { | |
10597 | template<typename WriterF, std::size_t bufferSize=256> | |
10598 | class StreamBufImpl : public std::streambuf { | |
10599 | char data[bufferSize]; | |
10600 | WriterF m_writer; | |
10601 | ||
10602 | public: | |
10603 | StreamBufImpl() { | |
10604 | setp( data, data + sizeof(data) ); | |
10605 | } | |
10606 | ||
10607 | ~StreamBufImpl() noexcept { | |
10608 | StreamBufImpl::sync(); | |
10609 | } | |
10610 | ||
10611 | private: | |
10612 | int overflow( int c ) override { | |
10613 | sync(); | |
10614 | ||
10615 | if( c != EOF ) { | |
10616 | if( pbase() == epptr() ) | |
10617 | m_writer( std::string( 1, static_cast<char>( c ) ) ); | |
10618 | else | |
10619 | sputc( static_cast<char>( c ) ); | |
10620 | } | |
10621 | return 0; | |
10622 | } | |
10623 | ||
10624 | int sync() override { | |
10625 | if( pbase() != pptr() ) { | |
10626 | m_writer( std::string( pbase(), static_cast<std::string::size_type>( pptr() - pbase() ) ) ); | |
10627 | setp( pbase(), epptr() ); | |
10628 | } | |
10629 | return 0; | |
10630 | } | |
10631 | }; | |
10632 | ||
10633 | /////////////////////////////////////////////////////////////////////////// | |
10634 | ||
10635 | struct OutputDebugWriter { | |
10636 | ||
10637 | void operator()( std::string const&str ) { | |
10638 | writeToDebugConsole( str ); | |
10639 | } | |
10640 | }; | |
10641 | ||
10642 | /////////////////////////////////////////////////////////////////////////// | |
10643 | ||
10644 | class FileStream : public IStream { | |
10645 | mutable std::ofstream m_ofs; | |
10646 | public: | |
10647 | FileStream( StringRef filename ) { | |
10648 | m_ofs.open( filename.c_str() ); | |
10649 | CATCH_ENFORCE( !m_ofs.fail(), "Unable to open file: '" << filename << "'" ); | |
10650 | } | |
10651 | ~FileStream() override = default; | |
10652 | public: // IStream | |
10653 | std::ostream& stream() const override { | |
10654 | return m_ofs; | |
10655 | } | |
10656 | }; | |
10657 | ||
10658 | /////////////////////////////////////////////////////////////////////////// | |
10659 | ||
10660 | class CoutStream : public IStream { | |
10661 | mutable std::ostream m_os; | |
10662 | public: | |
10663 | // Store the streambuf from cout up-front because | |
10664 | // cout may get redirected when running tests | |
10665 | CoutStream() : m_os( Catch::cout().rdbuf() ) {} | |
10666 | ~CoutStream() override = default; | |
10667 | ||
10668 | public: // IStream | |
10669 | std::ostream& stream() const override { return m_os; } | |
10670 | }; | |
10671 | ||
10672 | /////////////////////////////////////////////////////////////////////////// | |
10673 | ||
10674 | class DebugOutStream : public IStream { | |
10675 | std::unique_ptr<StreamBufImpl<OutputDebugWriter>> m_streamBuf; | |
10676 | mutable std::ostream m_os; | |
10677 | public: | |
10678 | DebugOutStream() | |
10679 | : m_streamBuf( new StreamBufImpl<OutputDebugWriter>() ), | |
10680 | m_os( m_streamBuf.get() ) | |
10681 | {} | |
10682 | ||
10683 | ~DebugOutStream() override = default; | |
10684 | ||
10685 | public: // IStream | |
10686 | std::ostream& stream() const override { return m_os; } | |
10687 | }; | |
10688 | ||
10689 | }} // namespace anon::detail | |
10690 | ||
10691 | /////////////////////////////////////////////////////////////////////////// | |
10692 | ||
10693 | auto makeStream( StringRef const &filename ) -> IStream const* { | |
10694 | if( filename.empty() ) | |
10695 | return new detail::CoutStream(); | |
10696 | else if( filename[0] == '%' ) { | |
10697 | if( filename == "%debug" ) | |
10698 | return new detail::DebugOutStream(); | |
10699 | else | |
10700 | CATCH_ERROR( "Unrecognised stream: '" << filename << "'" ); | |
10701 | } | |
10702 | else | |
10703 | return new detail::FileStream( filename ); | |
10704 | } | |
10705 | ||
10706 | // This class encapsulates the idea of a pool of ostringstreams that can be reused. | |
10707 | struct StringStreams { | |
10708 | std::vector<std::unique_ptr<std::ostringstream>> m_streams; | |
10709 | std::vector<std::size_t> m_unused; | |
10710 | std::ostringstream m_referenceStream; // Used for copy state/ flags from | |
10711 | ||
10712 | auto add() -> std::size_t { | |
10713 | if( m_unused.empty() ) { | |
10714 | m_streams.push_back( std::unique_ptr<std::ostringstream>( new std::ostringstream ) ); | |
10715 | return m_streams.size()-1; | |
10716 | } | |
10717 | else { | |
10718 | auto index = m_unused.back(); | |
10719 | m_unused.pop_back(); | |
10720 | return index; | |
10721 | } | |
10722 | } | |
10723 | ||
10724 | void release( std::size_t index ) { | |
10725 | m_streams[index]->copyfmt( m_referenceStream ); // Restore initial flags and other state | |
10726 | m_unused.push_back(index); | |
10727 | } | |
10728 | }; | |
10729 | ||
10730 | ReusableStringStream::ReusableStringStream() | |
10731 | : m_index( Singleton<StringStreams>::getMutable().add() ), | |
10732 | m_oss( Singleton<StringStreams>::getMutable().m_streams[m_index].get() ) | |
10733 | {} | |
10734 | ||
10735 | ReusableStringStream::~ReusableStringStream() { | |
10736 | static_cast<std::ostringstream*>( m_oss )->str(""); | |
10737 | m_oss->clear(); | |
10738 | Singleton<StringStreams>::getMutable().release( m_index ); | |
10739 | } | |
10740 | ||
10741 | auto ReusableStringStream::str() const -> std::string { | |
10742 | return static_cast<std::ostringstream*>( m_oss )->str(); | |
10743 | } | |
10744 | ||
10745 | /////////////////////////////////////////////////////////////////////////// | |
10746 | ||
10747 | #ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions | |
10748 | std::ostream& cout() { return std::cout; } | |
10749 | std::ostream& cerr() { return std::cerr; } | |
10750 | std::ostream& clog() { return std::clog; } | |
10751 | #endif | |
10752 | } | |
10753 | // end catch_stream.cpp | |
10754 | // start catch_string_manip.cpp | |
10755 | ||
10756 | #include <algorithm> | |
10757 | #include <ostream> | |
10758 | #include <cstring> | |
10759 | #include <cctype> | |
10760 | ||
10761 | namespace Catch { | |
10762 | ||
10763 | namespace { | |
10764 | char toLowerCh(char c) { | |
10765 | return static_cast<char>( std::tolower( c ) ); | |
10766 | } | |
10767 | } | |
10768 | ||
10769 | bool startsWith( std::string const& s, std::string const& prefix ) { | |
10770 | return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin()); | |
10771 | } | |
10772 | bool startsWith( std::string const& s, char prefix ) { | |
10773 | return !s.empty() && s[0] == prefix; | |
10774 | } | |
10775 | bool endsWith( std::string const& s, std::string const& suffix ) { | |
10776 | return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin()); | |
10777 | } | |
10778 | bool endsWith( std::string const& s, char suffix ) { | |
10779 | return !s.empty() && s[s.size()-1] == suffix; | |
10780 | } | |
10781 | bool contains( std::string const& s, std::string const& infix ) { | |
10782 | return s.find( infix ) != std::string::npos; | |
10783 | } | |
10784 | void toLowerInPlace( std::string& s ) { | |
10785 | std::transform( s.begin(), s.end(), s.begin(), toLowerCh ); | |
10786 | } | |
10787 | std::string toLower( std::string const& s ) { | |
10788 | std::string lc = s; | |
10789 | toLowerInPlace( lc ); | |
10790 | return lc; | |
10791 | } | |
10792 | std::string trim( std::string const& str ) { | |
10793 | static char const* whitespaceChars = "\n\r\t "; | |
10794 | std::string::size_type start = str.find_first_not_of( whitespaceChars ); | |
10795 | std::string::size_type end = str.find_last_not_of( whitespaceChars ); | |
10796 | ||
10797 | return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string(); | |
10798 | } | |
10799 | ||
10800 | bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { | |
10801 | bool replaced = false; | |
10802 | std::size_t i = str.find( replaceThis ); | |
10803 | while( i != std::string::npos ) { | |
10804 | replaced = true; | |
10805 | str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() ); | |
10806 | if( i < str.size()-withThis.size() ) | |
10807 | i = str.find( replaceThis, i+withThis.size() ); | |
10808 | else | |
10809 | i = std::string::npos; | |
10810 | } | |
10811 | return replaced; | |
10812 | } | |
10813 | ||
10814 | pluralise::pluralise( std::size_t count, std::string const& label ) | |
10815 | : m_count( count ), | |
10816 | m_label( label ) | |
10817 | {} | |
10818 | ||
10819 | std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { | |
10820 | os << pluraliser.m_count << ' ' << pluraliser.m_label; | |
10821 | if( pluraliser.m_count != 1 ) | |
10822 | os << 's'; | |
10823 | return os; | |
10824 | } | |
10825 | ||
10826 | } | |
10827 | // end catch_string_manip.cpp | |
10828 | // start catch_stringref.cpp | |
10829 | ||
10830 | #if defined(__clang__) | |
10831 | # pragma clang diagnostic push | |
10832 | # pragma clang diagnostic ignored "-Wexit-time-destructors" | |
10833 | #endif | |
10834 | ||
10835 | #include <ostream> | |
10836 | #include <cstring> | |
10837 | #include <cstdint> | |
10838 | ||
10839 | namespace { | |
10840 | const uint32_t byte_2_lead = 0xC0; | |
10841 | const uint32_t byte_3_lead = 0xE0; | |
10842 | const uint32_t byte_4_lead = 0xF0; | |
10843 | } | |
10844 | ||
10845 | namespace Catch { | |
10846 | StringRef::StringRef( char const* rawChars ) noexcept | |
10847 | : StringRef( rawChars, static_cast<StringRef::size_type>(std::strlen(rawChars) ) ) | |
10848 | {} | |
10849 | ||
10850 | StringRef::operator std::string() const { | |
10851 | return std::string( m_start, m_size ); | |
10852 | } | |
10853 | ||
10854 | void StringRef::swap( StringRef& other ) noexcept { | |
10855 | std::swap( m_start, other.m_start ); | |
10856 | std::swap( m_size, other.m_size ); | |
10857 | std::swap( m_data, other.m_data ); | |
10858 | } | |
10859 | ||
10860 | auto StringRef::c_str() const -> char const* { | |
10861 | if( isSubstring() ) | |
10862 | const_cast<StringRef*>( this )->takeOwnership(); | |
10863 | return m_start; | |
10864 | } | |
10865 | auto StringRef::currentData() const noexcept -> char const* { | |
10866 | return m_start; | |
10867 | } | |
10868 | ||
10869 | auto StringRef::isOwned() const noexcept -> bool { | |
10870 | return m_data != nullptr; | |
10871 | } | |
10872 | auto StringRef::isSubstring() const noexcept -> bool { | |
10873 | return m_start[m_size] != '\0'; | |
10874 | } | |
10875 | ||
10876 | void StringRef::takeOwnership() { | |
10877 | if( !isOwned() ) { | |
10878 | m_data = new char[m_size+1]; | |
10879 | memcpy( m_data, m_start, m_size ); | |
10880 | m_data[m_size] = '\0'; | |
10881 | m_start = m_data; | |
10882 | } | |
10883 | } | |
10884 | auto StringRef::substr( size_type start, size_type size ) const noexcept -> StringRef { | |
10885 | if( start < m_size ) | |
10886 | return StringRef( m_start+start, size ); | |
10887 | else | |
10888 | return StringRef(); | |
10889 | } | |
10890 | auto StringRef::operator == ( StringRef const& other ) const noexcept -> bool { | |
10891 | return | |
10892 | size() == other.size() && | |
10893 | (std::strncmp( m_start, other.m_start, size() ) == 0); | |
10894 | } | |
10895 | auto StringRef::operator != ( StringRef const& other ) const noexcept -> bool { | |
10896 | return !operator==( other ); | |
10897 | } | |
10898 | ||
10899 | auto StringRef::operator[](size_type index) const noexcept -> char { | |
10900 | return m_start[index]; | |
10901 | } | |
10902 | ||
10903 | auto StringRef::numberOfCharacters() const noexcept -> size_type { | |
10904 | size_type noChars = m_size; | |
10905 | // Make adjustments for uft encodings | |
10906 | for( size_type i=0; i < m_size; ++i ) { | |
10907 | char c = m_start[i]; | |
10908 | if( ( c & byte_2_lead ) == byte_2_lead ) { | |
10909 | noChars--; | |
10910 | if (( c & byte_3_lead ) == byte_3_lead ) | |
10911 | noChars--; | |
10912 | if( ( c & byte_4_lead ) == byte_4_lead ) | |
10913 | noChars--; | |
10914 | } | |
10915 | } | |
10916 | return noChars; | |
10917 | } | |
10918 | ||
10919 | auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string { | |
10920 | std::string str; | |
10921 | str.reserve( lhs.size() + rhs.size() ); | |
10922 | str += lhs; | |
10923 | str += rhs; | |
10924 | return str; | |
10925 | } | |
10926 | auto operator + ( StringRef const& lhs, const char* rhs ) -> std::string { | |
10927 | return std::string( lhs ) + std::string( rhs ); | |
10928 | } | |
10929 | auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string { | |
10930 | return std::string( lhs ) + std::string( rhs ); | |
10931 | } | |
10932 | ||
10933 | auto operator << ( std::ostream& os, StringRef const& str ) -> std::ostream& { | |
10934 | return os.write(str.currentData(), str.size()); | |
10935 | } | |
10936 | ||
10937 | auto operator+=( std::string& lhs, StringRef const& rhs ) -> std::string& { | |
10938 | lhs.append(rhs.currentData(), rhs.size()); | |
10939 | return lhs; | |
10940 | } | |
10941 | ||
10942 | } // namespace Catch | |
10943 | ||
10944 | #if defined(__clang__) | |
10945 | # pragma clang diagnostic pop | |
10946 | #endif | |
10947 | // end catch_stringref.cpp | |
10948 | // start catch_tag_alias.cpp | |
10949 | ||
10950 | namespace Catch { | |
10951 | TagAlias::TagAlias(std::string const & _tag, SourceLineInfo _lineInfo): tag(_tag), lineInfo(_lineInfo) {} | |
10952 | } | |
10953 | // end catch_tag_alias.cpp | |
10954 | // start catch_tag_alias_autoregistrar.cpp | |
10955 | ||
10956 | namespace Catch { | |
10957 | ||
10958 | RegistrarForTagAliases::RegistrarForTagAliases(char const* alias, char const* tag, SourceLineInfo const& lineInfo) { | |
10959 | CATCH_TRY { | |
10960 | getMutableRegistryHub().registerTagAlias(alias, tag, lineInfo); | |
10961 | } CATCH_CATCH_ALL { | |
10962 | // Do not throw when constructing global objects, instead register the exception to be processed later | |
10963 | getMutableRegistryHub().registerStartupException(); | |
10964 | } | |
10965 | } | |
10966 | ||
10967 | } | |
10968 | // end catch_tag_alias_autoregistrar.cpp | |
10969 | // start catch_tag_alias_registry.cpp | |
10970 | ||
10971 | #include <sstream> | |
10972 | ||
10973 | namespace Catch { | |
10974 | ||
10975 | TagAliasRegistry::~TagAliasRegistry() {} | |
10976 | ||
10977 | TagAlias const* TagAliasRegistry::find( std::string const& alias ) const { | |
10978 | auto it = m_registry.find( alias ); | |
10979 | if( it != m_registry.end() ) | |
10980 | return &(it->second); | |
10981 | else | |
10982 | return nullptr; | |
10983 | } | |
10984 | ||
10985 | std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { | |
10986 | std::string expandedTestSpec = unexpandedTestSpec; | |
10987 | for( auto const& registryKvp : m_registry ) { | |
10988 | std::size_t pos = expandedTestSpec.find( registryKvp.first ); | |
10989 | if( pos != std::string::npos ) { | |
10990 | expandedTestSpec = expandedTestSpec.substr( 0, pos ) + | |
10991 | registryKvp.second.tag + | |
10992 | expandedTestSpec.substr( pos + registryKvp.first.size() ); | |
10993 | } | |
10994 | } | |
10995 | return expandedTestSpec; | |
10996 | } | |
10997 | ||
10998 | void TagAliasRegistry::add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) { | |
10999 | CATCH_ENFORCE( startsWith(alias, "[@") && endsWith(alias, ']'), | |
11000 | "error: tag alias, '" << alias << "' is not of the form [@alias name].\n" << lineInfo ); | |
11001 | ||
11002 | CATCH_ENFORCE( m_registry.insert(std::make_pair(alias, TagAlias(tag, lineInfo))).second, | |
11003 | "error: tag alias, '" << alias << "' already registered.\n" | |
11004 | << "\tFirst seen at: " << find(alias)->lineInfo << "\n" | |
11005 | << "\tRedefined at: " << lineInfo ); | |
11006 | } | |
11007 | ||
11008 | ITagAliasRegistry::~ITagAliasRegistry() {} | |
11009 | ||
11010 | ITagAliasRegistry const& ITagAliasRegistry::get() { | |
11011 | return getRegistryHub().getTagAliasRegistry(); | |
11012 | } | |
11013 | ||
11014 | } // end namespace Catch | |
11015 | // end catch_tag_alias_registry.cpp | |
11016 | // start catch_test_case_info.cpp | |
11017 | ||
11018 | #include <cctype> | |
11019 | #include <exception> | |
11020 | #include <algorithm> | |
11021 | #include <sstream> | |
11022 | ||
11023 | namespace Catch { | |
11024 | ||
11025 | namespace { | |
11026 | TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { | |
11027 | if( startsWith( tag, '.' ) || | |
11028 | tag == "!hide" ) | |
11029 | return TestCaseInfo::IsHidden; | |
11030 | else if( tag == "!throws" ) | |
11031 | return TestCaseInfo::Throws; | |
11032 | else if( tag == "!shouldfail" ) | |
11033 | return TestCaseInfo::ShouldFail; | |
11034 | else if( tag == "!mayfail" ) | |
11035 | return TestCaseInfo::MayFail; | |
11036 | else if( tag == "!nonportable" ) | |
11037 | return TestCaseInfo::NonPortable; | |
11038 | else if( tag == "!benchmark" ) | |
11039 | return static_cast<TestCaseInfo::SpecialProperties>( TestCaseInfo::Benchmark | TestCaseInfo::IsHidden ); | |
11040 | else | |
11041 | return TestCaseInfo::None; | |
11042 | } | |
11043 | bool isReservedTag( std::string const& tag ) { | |
11044 | return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( static_cast<unsigned char>(tag[0]) ); | |
11045 | } | |
11046 | void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { | |
11047 | CATCH_ENFORCE( !isReservedTag(tag), | |
11048 | "Tag name: [" << tag << "] is not allowed.\n" | |
11049 | << "Tag names starting with non alpha-numeric characters are reserved\n" | |
11050 | << _lineInfo ); | |
11051 | } | |
11052 | } | |
11053 | ||
11054 | TestCase makeTestCase( ITestInvoker* _testCase, | |
11055 | std::string const& _className, | |
11056 | NameAndTags const& nameAndTags, | |
11057 | SourceLineInfo const& _lineInfo ) | |
11058 | { | |
11059 | bool isHidden = false; | |
11060 | ||
11061 | // Parse out tags | |
11062 | std::vector<std::string> tags; | |
11063 | std::string desc, tag; | |
11064 | bool inTag = false; | |
11065 | std::string _descOrTags = nameAndTags.tags; | |
11066 | for (char c : _descOrTags) { | |
11067 | if( !inTag ) { | |
11068 | if( c == '[' ) | |
11069 | inTag = true; | |
11070 | else | |
11071 | desc += c; | |
11072 | } | |
11073 | else { | |
11074 | if( c == ']' ) { | |
11075 | TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag ); | |
11076 | if( ( prop & TestCaseInfo::IsHidden ) != 0 ) | |
11077 | isHidden = true; | |
11078 | else if( prop == TestCaseInfo::None ) | |
11079 | enforceNotReservedTag( tag, _lineInfo ); | |
11080 | ||
11081 | tags.push_back( tag ); | |
11082 | tag.clear(); | |
11083 | inTag = false; | |
11084 | } | |
11085 | else | |
11086 | tag += c; | |
11087 | } | |
11088 | } | |
11089 | if( isHidden ) { | |
11090 | tags.push_back( "." ); | |
11091 | } | |
11092 | ||
11093 | TestCaseInfo info( nameAndTags.name, _className, desc, tags, _lineInfo ); | |
11094 | return TestCase( _testCase, std::move(info) ); | |
11095 | } | |
11096 | ||
11097 | void setTags( TestCaseInfo& testCaseInfo, std::vector<std::string> tags ) { | |
11098 | std::sort(begin(tags), end(tags)); | |
11099 | tags.erase(std::unique(begin(tags), end(tags)), end(tags)); | |
11100 | testCaseInfo.lcaseTags.clear(); | |
11101 | ||
11102 | for( auto const& tag : tags ) { | |
11103 | std::string lcaseTag = toLower( tag ); | |
11104 | testCaseInfo.properties = static_cast<TestCaseInfo::SpecialProperties>( testCaseInfo.properties | parseSpecialTag( lcaseTag ) ); | |
11105 | testCaseInfo.lcaseTags.push_back( lcaseTag ); | |
11106 | } | |
11107 | testCaseInfo.tags = std::move(tags); | |
11108 | } | |
11109 | ||
11110 | TestCaseInfo::TestCaseInfo( std::string const& _name, | |
11111 | std::string const& _className, | |
11112 | std::string const& _description, | |
11113 | std::vector<std::string> const& _tags, | |
11114 | SourceLineInfo const& _lineInfo ) | |
11115 | : name( _name ), | |
11116 | className( _className ), | |
11117 | description( _description ), | |
11118 | lineInfo( _lineInfo ), | |
11119 | properties( None ) | |
11120 | { | |
11121 | setTags( *this, _tags ); | |
11122 | } | |
11123 | ||
11124 | bool TestCaseInfo::isHidden() const { | |
11125 | return ( properties & IsHidden ) != 0; | |
11126 | } | |
11127 | bool TestCaseInfo::throws() const { | |
11128 | return ( properties & Throws ) != 0; | |
11129 | } | |
11130 | bool TestCaseInfo::okToFail() const { | |
11131 | return ( properties & (ShouldFail | MayFail ) ) != 0; | |
11132 | } | |
11133 | bool TestCaseInfo::expectedToFail() const { | |
11134 | return ( properties & (ShouldFail ) ) != 0; | |
11135 | } | |
11136 | ||
11137 | std::string TestCaseInfo::tagsAsString() const { | |
11138 | std::string ret; | |
11139 | // '[' and ']' per tag | |
11140 | std::size_t full_size = 2 * tags.size(); | |
11141 | for (const auto& tag : tags) { | |
11142 | full_size += tag.size(); | |
11143 | } | |
11144 | ret.reserve(full_size); | |
11145 | for (const auto& tag : tags) { | |
11146 | ret.push_back('['); | |
11147 | ret.append(tag); | |
11148 | ret.push_back(']'); | |
11149 | } | |
11150 | ||
11151 | return ret; | |
11152 | } | |
11153 | ||
11154 | TestCase::TestCase( ITestInvoker* testCase, TestCaseInfo&& info ) : TestCaseInfo( std::move(info) ), test( testCase ) {} | |
11155 | ||
11156 | TestCase TestCase::withName( std::string const& _newName ) const { | |
11157 | TestCase other( *this ); | |
11158 | other.name = _newName; | |
11159 | return other; | |
11160 | } | |
11161 | ||
11162 | void TestCase::invoke() const { | |
11163 | test->invoke(); | |
11164 | } | |
11165 | ||
11166 | bool TestCase::operator == ( TestCase const& other ) const { | |
11167 | return test.get() == other.test.get() && | |
11168 | name == other.name && | |
11169 | className == other.className; | |
11170 | } | |
11171 | ||
11172 | bool TestCase::operator < ( TestCase const& other ) const { | |
11173 | return name < other.name; | |
11174 | } | |
11175 | ||
11176 | TestCaseInfo const& TestCase::getTestCaseInfo() const | |
11177 | { | |
11178 | return *this; | |
11179 | } | |
11180 | ||
11181 | } // end namespace Catch | |
11182 | // end catch_test_case_info.cpp | |
11183 | // start catch_test_case_registry_impl.cpp | |
11184 | ||
11185 | #include <sstream> | |
11186 | ||
11187 | namespace Catch { | |
11188 | ||
11189 | std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) { | |
11190 | ||
11191 | std::vector<TestCase> sorted = unsortedTestCases; | |
11192 | ||
11193 | switch( config.runOrder() ) { | |
11194 | case RunTests::InLexicographicalOrder: | |
11195 | std::sort( sorted.begin(), sorted.end() ); | |
11196 | break; | |
11197 | case RunTests::InRandomOrder: | |
11198 | seedRng( config ); | |
11199 | std::shuffle( sorted.begin(), sorted.end(), rng() ); | |
11200 | break; | |
11201 | case RunTests::InDeclarationOrder: | |
11202 | // already in declaration order | |
11203 | break; | |
11204 | } | |
11205 | return sorted; | |
11206 | } | |
11207 | bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) { | |
11208 | return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() ); | |
11209 | } | |
11210 | ||
11211 | void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions ) { | |
11212 | std::set<TestCase> seenFunctions; | |
11213 | for( auto const& function : functions ) { | |
11214 | auto prev = seenFunctions.insert( function ); | |
11215 | CATCH_ENFORCE( prev.second, | |
11216 | "error: TEST_CASE( \"" << function.name << "\" ) already defined.\n" | |
11217 | << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" | |
11218 | << "\tRedefined at " << function.getTestCaseInfo().lineInfo ); | |
11219 | } | |
11220 | } | |
11221 | ||
11222 | std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ) { | |
11223 | std::vector<TestCase> filtered; | |
11224 | filtered.reserve( testCases.size() ); | |
11225 | for( auto const& testCase : testCases ) | |
11226 | if( matchTest( testCase, testSpec, config ) ) | |
11227 | filtered.push_back( testCase ); | |
11228 | return filtered; | |
11229 | } | |
11230 | std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ) { | |
11231 | return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config ); | |
11232 | } | |
11233 | ||
11234 | void TestRegistry::registerTest( TestCase const& testCase ) { | |
11235 | std::string name = testCase.getTestCaseInfo().name; | |
11236 | if( name.empty() ) { | |
11237 | ReusableStringStream rss; | |
11238 | rss << "Anonymous test case " << ++m_unnamedCount; | |
11239 | return registerTest( testCase.withName( rss.str() ) ); | |
11240 | } | |
11241 | m_functions.push_back( testCase ); | |
11242 | } | |
11243 | ||
11244 | std::vector<TestCase> const& TestRegistry::getAllTests() const { | |
11245 | return m_functions; | |
11246 | } | |
11247 | std::vector<TestCase> const& TestRegistry::getAllTestsSorted( IConfig const& config ) const { | |
11248 | if( m_sortedFunctions.empty() ) | |
11249 | enforceNoDuplicateTestCases( m_functions ); | |
11250 | ||
11251 | if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) { | |
11252 | m_sortedFunctions = sortTests( config, m_functions ); | |
11253 | m_currentSortOrder = config.runOrder(); | |
11254 | } | |
11255 | return m_sortedFunctions; | |
11256 | } | |
11257 | ||
11258 | /////////////////////////////////////////////////////////////////////////// | |
11259 | TestInvokerAsFunction::TestInvokerAsFunction( void(*testAsFunction)() ) noexcept : m_testAsFunction( testAsFunction ) {} | |
11260 | ||
11261 | void TestInvokerAsFunction::invoke() const { | |
11262 | m_testAsFunction(); | |
11263 | } | |
11264 | ||
11265 | std::string extractClassName( StringRef const& classOrQualifiedMethodName ) { | |
11266 | std::string className = classOrQualifiedMethodName; | |
11267 | if( startsWith( className, '&' ) ) | |
11268 | { | |
11269 | std::size_t lastColons = className.rfind( "::" ); | |
11270 | std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); | |
11271 | if( penultimateColons == std::string::npos ) | |
11272 | penultimateColons = 1; | |
11273 | className = className.substr( penultimateColons, lastColons-penultimateColons ); | |
11274 | } | |
11275 | return className; | |
11276 | } | |
11277 | ||
11278 | } // end namespace Catch | |
11279 | // end catch_test_case_registry_impl.cpp | |
11280 | // start catch_test_case_tracker.cpp | |
11281 | ||
11282 | #include <algorithm> | |
11283 | #include <cassert> | |
11284 | #include <stdexcept> | |
11285 | #include <memory> | |
11286 | #include <sstream> | |
11287 | ||
11288 | #if defined(__clang__) | |
11289 | # pragma clang diagnostic push | |
11290 | # pragma clang diagnostic ignored "-Wexit-time-destructors" | |
11291 | #endif | |
11292 | ||
11293 | namespace Catch { | |
11294 | namespace TestCaseTracking { | |
11295 | ||
11296 | NameAndLocation::NameAndLocation( std::string const& _name, SourceLineInfo const& _location ) | |
11297 | : name( _name ), | |
11298 | location( _location ) | |
11299 | {} | |
11300 | ||
11301 | ITracker::~ITracker() = default; | |
11302 | ||
11303 | TrackerContext& TrackerContext::instance() { | |
11304 | static TrackerContext s_instance; | |
11305 | return s_instance; | |
11306 | } | |
11307 | ||
11308 | ITracker& TrackerContext::startRun() { | |
11309 | m_rootTracker = std::make_shared<SectionTracker>( NameAndLocation( "{root}", CATCH_INTERNAL_LINEINFO ), *this, nullptr ); | |
11310 | m_currentTracker = nullptr; | |
11311 | m_runState = Executing; | |
11312 | return *m_rootTracker; | |
11313 | } | |
11314 | ||
11315 | void TrackerContext::endRun() { | |
11316 | m_rootTracker.reset(); | |
11317 | m_currentTracker = nullptr; | |
11318 | m_runState = NotStarted; | |
11319 | } | |
11320 | ||
11321 | void TrackerContext::startCycle() { | |
11322 | m_currentTracker = m_rootTracker.get(); | |
11323 | m_runState = Executing; | |
11324 | } | |
11325 | void TrackerContext::completeCycle() { | |
11326 | m_runState = CompletedCycle; | |
11327 | } | |
11328 | ||
11329 | bool TrackerContext::completedCycle() const { | |
11330 | return m_runState == CompletedCycle; | |
11331 | } | |
11332 | ITracker& TrackerContext::currentTracker() { | |
11333 | return *m_currentTracker; | |
11334 | } | |
11335 | void TrackerContext::setCurrentTracker( ITracker* tracker ) { | |
11336 | m_currentTracker = tracker; | |
11337 | } | |
11338 | ||
11339 | TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) | |
11340 | : m_nameAndLocation( nameAndLocation ), | |
11341 | m_ctx( ctx ), | |
11342 | m_parent( parent ) | |
11343 | {} | |
11344 | ||
11345 | NameAndLocation const& TrackerBase::nameAndLocation() const { | |
11346 | return m_nameAndLocation; | |
11347 | } | |
11348 | bool TrackerBase::isComplete() const { | |
11349 | return m_runState == CompletedSuccessfully || m_runState == Failed; | |
11350 | } | |
11351 | bool TrackerBase::isSuccessfullyCompleted() const { | |
11352 | return m_runState == CompletedSuccessfully; | |
11353 | } | |
11354 | bool TrackerBase::isOpen() const { | |
11355 | return m_runState != NotStarted && !isComplete(); | |
11356 | } | |
11357 | bool TrackerBase::hasChildren() const { | |
11358 | return !m_children.empty(); | |
11359 | } | |
11360 | ||
11361 | void TrackerBase::addChild( ITrackerPtr const& child ) { | |
11362 | m_children.push_back( child ); | |
11363 | } | |
11364 | ||
11365 | ITrackerPtr TrackerBase::findChild( NameAndLocation const& nameAndLocation ) { | |
11366 | auto it = std::find_if( m_children.begin(), m_children.end(), | |
11367 | [&nameAndLocation]( ITrackerPtr const& tracker ){ | |
11368 | return | |
11369 | tracker->nameAndLocation().location == nameAndLocation.location && | |
11370 | tracker->nameAndLocation().name == nameAndLocation.name; | |
11371 | } ); | |
11372 | return( it != m_children.end() ) | |
11373 | ? *it | |
11374 | : nullptr; | |
11375 | } | |
11376 | ITracker& TrackerBase::parent() { | |
11377 | assert( m_parent ); // Should always be non-null except for root | |
11378 | return *m_parent; | |
11379 | } | |
11380 | ||
11381 | void TrackerBase::openChild() { | |
11382 | if( m_runState != ExecutingChildren ) { | |
11383 | m_runState = ExecutingChildren; | |
11384 | if( m_parent ) | |
11385 | m_parent->openChild(); | |
11386 | } | |
11387 | } | |
11388 | ||
11389 | bool TrackerBase::isSectionTracker() const { return false; } | |
11390 | bool TrackerBase::isIndexTracker() const { return false; } | |
11391 | ||
11392 | void TrackerBase::open() { | |
11393 | m_runState = Executing; | |
11394 | moveToThis(); | |
11395 | if( m_parent ) | |
11396 | m_parent->openChild(); | |
11397 | } | |
11398 | ||
11399 | void TrackerBase::close() { | |
11400 | ||
11401 | // Close any still open children (e.g. generators) | |
11402 | while( &m_ctx.currentTracker() != this ) | |
11403 | m_ctx.currentTracker().close(); | |
11404 | ||
11405 | switch( m_runState ) { | |
11406 | case NeedsAnotherRun: | |
11407 | break; | |
11408 | ||
11409 | case Executing: | |
11410 | m_runState = CompletedSuccessfully; | |
11411 | break; | |
11412 | case ExecutingChildren: | |
11413 | if( m_children.empty() || m_children.back()->isComplete() ) | |
11414 | m_runState = CompletedSuccessfully; | |
11415 | break; | |
11416 | ||
11417 | case NotStarted: | |
11418 | case CompletedSuccessfully: | |
11419 | case Failed: | |
11420 | CATCH_INTERNAL_ERROR( "Illogical state: " << m_runState ); | |
11421 | ||
11422 | default: | |
11423 | CATCH_INTERNAL_ERROR( "Unknown state: " << m_runState ); | |
11424 | } | |
11425 | moveToParent(); | |
11426 | m_ctx.completeCycle(); | |
11427 | } | |
11428 | void TrackerBase::fail() { | |
11429 | m_runState = Failed; | |
11430 | if( m_parent ) | |
11431 | m_parent->markAsNeedingAnotherRun(); | |
11432 | moveToParent(); | |
11433 | m_ctx.completeCycle(); | |
11434 | } | |
11435 | void TrackerBase::markAsNeedingAnotherRun() { | |
11436 | m_runState = NeedsAnotherRun; | |
11437 | } | |
11438 | ||
11439 | void TrackerBase::moveToParent() { | |
11440 | assert( m_parent ); | |
11441 | m_ctx.setCurrentTracker( m_parent ); | |
11442 | } | |
11443 | void TrackerBase::moveToThis() { | |
11444 | m_ctx.setCurrentTracker( this ); | |
11445 | } | |
11446 | ||
11447 | SectionTracker::SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) | |
11448 | : TrackerBase( nameAndLocation, ctx, parent ) | |
11449 | { | |
11450 | if( parent ) { | |
11451 | while( !parent->isSectionTracker() ) | |
11452 | parent = &parent->parent(); | |
11453 | ||
11454 | SectionTracker& parentSection = static_cast<SectionTracker&>( *parent ); | |
11455 | addNextFilters( parentSection.m_filters ); | |
11456 | } | |
11457 | } | |
11458 | ||
11459 | bool SectionTracker::isSectionTracker() const { return true; } | |
11460 | ||
11461 | SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) { | |
11462 | std::shared_ptr<SectionTracker> section; | |
11463 | ||
11464 | ITracker& currentTracker = ctx.currentTracker(); | |
11465 | if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { | |
11466 | assert( childTracker ); | |
11467 | assert( childTracker->isSectionTracker() ); | |
11468 | section = std::static_pointer_cast<SectionTracker>( childTracker ); | |
11469 | } | |
11470 | else { | |
11471 | section = std::make_shared<SectionTracker>( nameAndLocation, ctx, ¤tTracker ); | |
11472 | currentTracker.addChild( section ); | |
11473 | } | |
11474 | if( !ctx.completedCycle() ) | |
11475 | section->tryOpen(); | |
11476 | return *section; | |
11477 | } | |
11478 | ||
11479 | void SectionTracker::tryOpen() { | |
11480 | if( !isComplete() && (m_filters.empty() || m_filters[0].empty() || m_filters[0] == m_nameAndLocation.name ) ) | |
11481 | open(); | |
11482 | } | |
11483 | ||
11484 | void SectionTracker::addInitialFilters( std::vector<std::string> const& filters ) { | |
11485 | if( !filters.empty() ) { | |
11486 | m_filters.push_back(""); // Root - should never be consulted | |
11487 | m_filters.push_back(""); // Test Case - not a section filter | |
11488 | m_filters.insert( m_filters.end(), filters.begin(), filters.end() ); | |
11489 | } | |
11490 | } | |
11491 | void SectionTracker::addNextFilters( std::vector<std::string> const& filters ) { | |
11492 | if( filters.size() > 1 ) | |
11493 | m_filters.insert( m_filters.end(), ++filters.begin(), filters.end() ); | |
11494 | } | |
11495 | ||
11496 | IndexTracker::IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size ) | |
11497 | : TrackerBase( nameAndLocation, ctx, parent ), | |
11498 | m_size( size ) | |
11499 | {} | |
11500 | ||
11501 | bool IndexTracker::isIndexTracker() const { return true; } | |
11502 | ||
11503 | IndexTracker& IndexTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ) { | |
11504 | std::shared_ptr<IndexTracker> tracker; | |
11505 | ||
11506 | ITracker& currentTracker = ctx.currentTracker(); | |
11507 | if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { | |
11508 | assert( childTracker ); | |
11509 | assert( childTracker->isIndexTracker() ); | |
11510 | tracker = std::static_pointer_cast<IndexTracker>( childTracker ); | |
11511 | } | |
11512 | else { | |
11513 | tracker = std::make_shared<IndexTracker>( nameAndLocation, ctx, ¤tTracker, size ); | |
11514 | currentTracker.addChild( tracker ); | |
11515 | } | |
11516 | ||
11517 | if( !ctx.completedCycle() && !tracker->isComplete() ) { | |
11518 | if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun ) | |
11519 | tracker->moveNext(); | |
11520 | tracker->open(); | |
11521 | } | |
11522 | ||
11523 | return *tracker; | |
11524 | } | |
11525 | ||
11526 | int IndexTracker::index() const { return m_index; } | |
11527 | ||
11528 | void IndexTracker::moveNext() { | |
11529 | m_index++; | |
11530 | m_children.clear(); | |
11531 | } | |
11532 | ||
11533 | void IndexTracker::close() { | |
11534 | TrackerBase::close(); | |
11535 | if( m_runState == CompletedSuccessfully && m_index < m_size-1 ) | |
11536 | m_runState = Executing; | |
11537 | } | |
11538 | ||
11539 | } // namespace TestCaseTracking | |
11540 | ||
11541 | using TestCaseTracking::ITracker; | |
11542 | using TestCaseTracking::TrackerContext; | |
11543 | using TestCaseTracking::SectionTracker; | |
11544 | using TestCaseTracking::IndexTracker; | |
11545 | ||
11546 | } // namespace Catch | |
11547 | ||
11548 | #if defined(__clang__) | |
11549 | # pragma clang diagnostic pop | |
11550 | #endif | |
11551 | // end catch_test_case_tracker.cpp | |
11552 | // start catch_test_registry.cpp | |
11553 | ||
11554 | namespace Catch { | |
11555 | ||
11556 | auto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker* { | |
11557 | return new(std::nothrow) TestInvokerAsFunction( testAsFunction ); | |
11558 | } | |
11559 | ||
11560 | NameAndTags::NameAndTags( StringRef const& name_ , StringRef const& tags_ ) noexcept : name( name_ ), tags( tags_ ) {} | |
11561 | ||
11562 | AutoReg::AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept { | |
11563 | CATCH_TRY { | |
11564 | getMutableRegistryHub() | |
11565 | .registerTest( | |
11566 | makeTestCase( | |
11567 | invoker, | |
11568 | extractClassName( classOrMethod ), | |
11569 | nameAndTags, | |
11570 | lineInfo)); | |
11571 | } CATCH_CATCH_ALL { | |
11572 | // Do not throw when constructing global objects, instead register the exception to be processed later | |
11573 | getMutableRegistryHub().registerStartupException(); | |
11574 | } | |
11575 | } | |
11576 | ||
11577 | AutoReg::~AutoReg() = default; | |
11578 | } | |
11579 | // end catch_test_registry.cpp | |
11580 | // start catch_test_spec.cpp | |
11581 | ||
11582 | #include <algorithm> | |
11583 | #include <string> | |
11584 | #include <vector> | |
11585 | #include <memory> | |
11586 | ||
11587 | namespace Catch { | |
11588 | ||
11589 | TestSpec::Pattern::~Pattern() = default; | |
11590 | TestSpec::NamePattern::~NamePattern() = default; | |
11591 | TestSpec::TagPattern::~TagPattern() = default; | |
11592 | TestSpec::ExcludedPattern::~ExcludedPattern() = default; | |
11593 | ||
11594 | TestSpec::NamePattern::NamePattern( std::string const& name ) | |
11595 | : m_wildcardPattern( toLower( name ), CaseSensitive::No ) | |
11596 | {} | |
11597 | bool TestSpec::NamePattern::matches( TestCaseInfo const& testCase ) const { | |
11598 | return m_wildcardPattern.matches( toLower( testCase.name ) ); | |
11599 | } | |
11600 | ||
11601 | TestSpec::TagPattern::TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} | |
11602 | bool TestSpec::TagPattern::matches( TestCaseInfo const& testCase ) const { | |
11603 | return std::find(begin(testCase.lcaseTags), | |
11604 | end(testCase.lcaseTags), | |
11605 | m_tag) != end(testCase.lcaseTags); | |
11606 | } | |
11607 | ||
11608 | TestSpec::ExcludedPattern::ExcludedPattern( PatternPtr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} | |
11609 | bool TestSpec::ExcludedPattern::matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); } | |
11610 | ||
11611 | bool TestSpec::Filter::matches( TestCaseInfo const& testCase ) const { | |
11612 | // All patterns in a filter must match for the filter to be a match | |
11613 | for( auto const& pattern : m_patterns ) { | |
11614 | if( !pattern->matches( testCase ) ) | |
11615 | return false; | |
11616 | } | |
11617 | return true; | |
11618 | } | |
11619 | ||
11620 | bool TestSpec::hasFilters() const { | |
11621 | return !m_filters.empty(); | |
11622 | } | |
11623 | bool TestSpec::matches( TestCaseInfo const& testCase ) const { | |
11624 | // A TestSpec matches if any filter matches | |
11625 | for( auto const& filter : m_filters ) | |
11626 | if( filter.matches( testCase ) ) | |
11627 | return true; | |
11628 | return false; | |
11629 | } | |
11630 | } | |
11631 | // end catch_test_spec.cpp | |
11632 | // start catch_test_spec_parser.cpp | |
11633 | ||
11634 | namespace Catch { | |
11635 | ||
11636 | TestSpecParser::TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {} | |
11637 | ||
11638 | TestSpecParser& TestSpecParser::parse( std::string const& arg ) { | |
11639 | m_mode = None; | |
11640 | m_exclusion = false; | |
11641 | m_start = std::string::npos; | |
11642 | m_arg = m_tagAliases->expandAliases( arg ); | |
11643 | m_escapeChars.clear(); | |
11644 | for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) | |
11645 | visitChar( m_arg[m_pos] ); | |
11646 | if( m_mode == Name ) | |
11647 | addPattern<TestSpec::NamePattern>(); | |
11648 | return *this; | |
11649 | } | |
11650 | TestSpec TestSpecParser::testSpec() { | |
11651 | addFilter(); | |
11652 | return m_testSpec; | |
11653 | } | |
11654 | ||
11655 | void TestSpecParser::visitChar( char c ) { | |
11656 | if( m_mode == None ) { | |
11657 | switch( c ) { | |
11658 | case ' ': return; | |
11659 | case '~': m_exclusion = true; return; | |
11660 | case '[': return startNewMode( Tag, ++m_pos ); | |
11661 | case '"': return startNewMode( QuotedName, ++m_pos ); | |
11662 | case '\\': return escape(); | |
11663 | default: startNewMode( Name, m_pos ); break; | |
11664 | } | |
11665 | } | |
11666 | if( m_mode == Name ) { | |
11667 | if( c == ',' ) { | |
11668 | addPattern<TestSpec::NamePattern>(); | |
11669 | addFilter(); | |
11670 | } | |
11671 | else if( c == '[' ) { | |
11672 | if( subString() == "exclude:" ) | |
11673 | m_exclusion = true; | |
11674 | else | |
11675 | addPattern<TestSpec::NamePattern>(); | |
11676 | startNewMode( Tag, ++m_pos ); | |
11677 | } | |
11678 | else if( c == '\\' ) | |
11679 | escape(); | |
11680 | } | |
11681 | else if( m_mode == EscapedName ) | |
11682 | m_mode = Name; | |
11683 | else if( m_mode == QuotedName && c == '"' ) | |
11684 | addPattern<TestSpec::NamePattern>(); | |
11685 | else if( m_mode == Tag && c == ']' ) | |
11686 | addPattern<TestSpec::TagPattern>(); | |
11687 | } | |
11688 | void TestSpecParser::startNewMode( Mode mode, std::size_t start ) { | |
11689 | m_mode = mode; | |
11690 | m_start = start; | |
11691 | } | |
11692 | void TestSpecParser::escape() { | |
11693 | if( m_mode == None ) | |
11694 | m_start = m_pos; | |
11695 | m_mode = EscapedName; | |
11696 | m_escapeChars.push_back( m_pos ); | |
11697 | } | |
11698 | std::string TestSpecParser::subString() const { return m_arg.substr( m_start, m_pos - m_start ); } | |
11699 | ||
11700 | void TestSpecParser::addFilter() { | |
11701 | if( !m_currentFilter.m_patterns.empty() ) { | |
11702 | m_testSpec.m_filters.push_back( m_currentFilter ); | |
11703 | m_currentFilter = TestSpec::Filter(); | |
11704 | } | |
11705 | } | |
11706 | ||
11707 | TestSpec parseTestSpec( std::string const& arg ) { | |
11708 | return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); | |
11709 | } | |
11710 | ||
11711 | } // namespace Catch | |
11712 | // end catch_test_spec_parser.cpp | |
11713 | // start catch_timer.cpp | |
11714 | ||
11715 | #include <chrono> | |
11716 | ||
11717 | static const uint64_t nanosecondsInSecond = 1000000000; | |
11718 | ||
11719 | namespace Catch { | |
11720 | ||
11721 | auto getCurrentNanosecondsSinceEpoch() -> uint64_t { | |
11722 | return std::chrono::duration_cast<std::chrono::nanoseconds>( std::chrono::high_resolution_clock::now().time_since_epoch() ).count(); | |
11723 | } | |
11724 | ||
11725 | namespace { | |
11726 | auto estimateClockResolution() -> uint64_t { | |
11727 | uint64_t sum = 0; | |
11728 | static const uint64_t iterations = 1000000; | |
11729 | ||
11730 | auto startTime = getCurrentNanosecondsSinceEpoch(); | |
11731 | ||
11732 | for( std::size_t i = 0; i < iterations; ++i ) { | |
11733 | ||
11734 | uint64_t ticks; | |
11735 | uint64_t baseTicks = getCurrentNanosecondsSinceEpoch(); | |
11736 | do { | |
11737 | ticks = getCurrentNanosecondsSinceEpoch(); | |
11738 | } while( ticks == baseTicks ); | |
11739 | ||
11740 | auto delta = ticks - baseTicks; | |
11741 | sum += delta; | |
11742 | ||
11743 | // If we have been calibrating for over 3 seconds -- the clock | |
11744 | // is terrible and we should move on. | |
11745 | // TBD: How to signal that the measured resolution is probably wrong? | |
11746 | if (ticks > startTime + 3 * nanosecondsInSecond) { | |
11747 | return sum / i; | |
11748 | } | |
11749 | } | |
11750 | ||
11751 | // We're just taking the mean, here. To do better we could take the std. dev and exclude outliers | |
11752 | // - and potentially do more iterations if there's a high variance. | |
11753 | return sum/iterations; | |
11754 | } | |
11755 | } | |
11756 | auto getEstimatedClockResolution() -> uint64_t { | |
11757 | static auto s_resolution = estimateClockResolution(); | |
11758 | return s_resolution; | |
11759 | } | |
11760 | ||
11761 | void Timer::start() { | |
11762 | m_nanoseconds = getCurrentNanosecondsSinceEpoch(); | |
11763 | } | |
11764 | auto Timer::getElapsedNanoseconds() const -> uint64_t { | |
11765 | return getCurrentNanosecondsSinceEpoch() - m_nanoseconds; | |
11766 | } | |
11767 | auto Timer::getElapsedMicroseconds() const -> uint64_t { | |
11768 | return getElapsedNanoseconds()/1000; | |
11769 | } | |
11770 | auto Timer::getElapsedMilliseconds() const -> unsigned int { | |
11771 | return static_cast<unsigned int>(getElapsedMicroseconds()/1000); | |
11772 | } | |
11773 | auto Timer::getElapsedSeconds() const -> double { | |
11774 | return getElapsedMicroseconds()/1000000.0; | |
11775 | } | |
11776 | ||
11777 | } // namespace Catch | |
11778 | // end catch_timer.cpp | |
11779 | // start catch_tostring.cpp | |
11780 | ||
11781 | #if defined(__clang__) | |
11782 | # pragma clang diagnostic push | |
11783 | # pragma clang diagnostic ignored "-Wexit-time-destructors" | |
11784 | # pragma clang diagnostic ignored "-Wglobal-constructors" | |
11785 | #endif | |
11786 | ||
11787 | // Enable specific decls locally | |
11788 | #if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) | |
11789 | #define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER | |
11790 | #endif | |
11791 | ||
11792 | #include <cmath> | |
11793 | #include <iomanip> | |
11794 | ||
11795 | namespace Catch { | |
11796 | ||
11797 | namespace Detail { | |
11798 | ||
11799 | const std::string unprintableString = "{?}"; | |
11800 | ||
11801 | namespace { | |
11802 | const int hexThreshold = 255; | |
11803 | ||
11804 | struct Endianness { | |
11805 | enum Arch { Big, Little }; | |
11806 | ||
11807 | static Arch which() { | |
11808 | union _{ | |
11809 | int asInt; | |
11810 | char asChar[sizeof (int)]; | |
11811 | } u; | |
11812 | ||
11813 | u.asInt = 1; | |
11814 | return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little; | |
11815 | } | |
11816 | }; | |
11817 | } | |
11818 | ||
11819 | std::string rawMemoryToString( const void *object, std::size_t size ) { | |
11820 | // Reverse order for little endian architectures | |
11821 | int i = 0, end = static_cast<int>( size ), inc = 1; | |
11822 | if( Endianness::which() == Endianness::Little ) { | |
11823 | i = end-1; | |
11824 | end = inc = -1; | |
11825 | } | |
11826 | ||
11827 | unsigned char const *bytes = static_cast<unsigned char const *>(object); | |
11828 | ReusableStringStream rss; | |
11829 | rss << "0x" << std::setfill('0') << std::hex; | |
11830 | for( ; i != end; i += inc ) | |
11831 | rss << std::setw(2) << static_cast<unsigned>(bytes[i]); | |
11832 | return rss.str(); | |
11833 | } | |
11834 | } | |
11835 | ||
11836 | template<typename T> | |
11837 | std::string fpToString( T value, int precision ) { | |
11838 | if (Catch::isnan(value)) { | |
11839 | return "nan"; | |
11840 | } | |
11841 | ||
11842 | ReusableStringStream rss; | |
11843 | rss << std::setprecision( precision ) | |
11844 | << std::fixed | |
11845 | << value; | |
11846 | std::string d = rss.str(); | |
11847 | std::size_t i = d.find_last_not_of( '0' ); | |
11848 | if( i != std::string::npos && i != d.size()-1 ) { | |
11849 | if( d[i] == '.' ) | |
11850 | i++; | |
11851 | d = d.substr( 0, i+1 ); | |
11852 | } | |
11853 | return d; | |
11854 | } | |
11855 | ||
11856 | //// ======================================================= //// | |
11857 | // | |
11858 | // Out-of-line defs for full specialization of StringMaker | |
11859 | // | |
11860 | //// ======================================================= //// | |
11861 | ||
11862 | std::string StringMaker<std::string>::convert(const std::string& str) { | |
11863 | if (!getCurrentContext().getConfig()->showInvisibles()) { | |
11864 | return '"' + str + '"'; | |
11865 | } | |
11866 | ||
11867 | std::string s("\""); | |
11868 | for (char c : str) { | |
11869 | switch (c) { | |
11870 | case '\n': | |
11871 | s.append("\\n"); | |
11872 | break; | |
11873 | case '\t': | |
11874 | s.append("\\t"); | |
11875 | break; | |
11876 | default: | |
11877 | s.push_back(c); | |
11878 | break; | |
11879 | } | |
11880 | } | |
11881 | s.append("\""); | |
11882 | return s; | |
11883 | } | |
11884 | ||
11885 | #ifdef CATCH_CONFIG_CPP17_STRING_VIEW | |
11886 | std::string StringMaker<std::string_view>::convert(std::string_view str) { | |
11887 | return ::Catch::Detail::stringify(std::string{ str }); | |
11888 | } | |
11889 | #endif | |
11890 | ||
11891 | std::string StringMaker<char const*>::convert(char const* str) { | |
11892 | if (str) { | |
11893 | return ::Catch::Detail::stringify(std::string{ str }); | |
11894 | } else { | |
11895 | return{ "{null string}" }; | |
11896 | } | |
11897 | } | |
11898 | std::string StringMaker<char*>::convert(char* str) { | |
11899 | if (str) { | |
11900 | return ::Catch::Detail::stringify(std::string{ str }); | |
11901 | } else { | |
11902 | return{ "{null string}" }; | |
11903 | } | |
11904 | } | |
11905 | ||
11906 | #ifdef CATCH_CONFIG_WCHAR | |
11907 | std::string StringMaker<std::wstring>::convert(const std::wstring& wstr) { | |
11908 | std::string s; | |
11909 | s.reserve(wstr.size()); | |
11910 | for (auto c : wstr) { | |
11911 | s += (c <= 0xff) ? static_cast<char>(c) : '?'; | |
11912 | } | |
11913 | return ::Catch::Detail::stringify(s); | |
11914 | } | |
11915 | ||
11916 | # ifdef CATCH_CONFIG_CPP17_STRING_VIEW | |
11917 | std::string StringMaker<std::wstring_view>::convert(std::wstring_view str) { | |
11918 | return StringMaker<std::wstring>::convert(std::wstring(str)); | |
11919 | } | |
11920 | # endif | |
11921 | ||
11922 | std::string StringMaker<wchar_t const*>::convert(wchar_t const * str) { | |
11923 | if (str) { | |
11924 | return ::Catch::Detail::stringify(std::wstring{ str }); | |
11925 | } else { | |
11926 | return{ "{null string}" }; | |
11927 | } | |
11928 | } | |
11929 | std::string StringMaker<wchar_t *>::convert(wchar_t * str) { | |
11930 | if (str) { | |
11931 | return ::Catch::Detail::stringify(std::wstring{ str }); | |
11932 | } else { | |
11933 | return{ "{null string}" }; | |
11934 | } | |
11935 | } | |
11936 | #endif | |
11937 | ||
11938 | std::string StringMaker<int>::convert(int value) { | |
11939 | return ::Catch::Detail::stringify(static_cast<long long>(value)); | |
11940 | } | |
11941 | std::string StringMaker<long>::convert(long value) { | |
11942 | return ::Catch::Detail::stringify(static_cast<long long>(value)); | |
11943 | } | |
11944 | std::string StringMaker<long long>::convert(long long value) { | |
11945 | ReusableStringStream rss; | |
11946 | rss << value; | |
11947 | if (value > Detail::hexThreshold) { | |
11948 | rss << " (0x" << std::hex << value << ')'; | |
11949 | } | |
11950 | return rss.str(); | |
11951 | } | |
11952 | ||
11953 | std::string StringMaker<unsigned int>::convert(unsigned int value) { | |
11954 | return ::Catch::Detail::stringify(static_cast<unsigned long long>(value)); | |
11955 | } | |
11956 | std::string StringMaker<unsigned long>::convert(unsigned long value) { | |
11957 | return ::Catch::Detail::stringify(static_cast<unsigned long long>(value)); | |
11958 | } | |
11959 | std::string StringMaker<unsigned long long>::convert(unsigned long long value) { | |
11960 | ReusableStringStream rss; | |
11961 | rss << value; | |
11962 | if (value > Detail::hexThreshold) { | |
11963 | rss << " (0x" << std::hex << value << ')'; | |
11964 | } | |
11965 | return rss.str(); | |
11966 | } | |
11967 | ||
11968 | std::string StringMaker<bool>::convert(bool b) { | |
11969 | return b ? "true" : "false"; | |
11970 | } | |
11971 | ||
11972 | std::string StringMaker<signed char>::convert(signed char value) { | |
11973 | if (value == '\r') { | |
11974 | return "'\\r'"; | |
11975 | } else if (value == '\f') { | |
11976 | return "'\\f'"; | |
11977 | } else if (value == '\n') { | |
11978 | return "'\\n'"; | |
11979 | } else if (value == '\t') { | |
11980 | return "'\\t'"; | |
11981 | } else if ('\0' <= value && value < ' ') { | |
11982 | return ::Catch::Detail::stringify(static_cast<unsigned int>(value)); | |
11983 | } else { | |
11984 | char chstr[] = "' '"; | |
11985 | chstr[1] = value; | |
11986 | return chstr; | |
11987 | } | |
11988 | } | |
11989 | std::string StringMaker<char>::convert(char c) { | |
11990 | return ::Catch::Detail::stringify(static_cast<signed char>(c)); | |
11991 | } | |
11992 | std::string StringMaker<unsigned char>::convert(unsigned char c) { | |
11993 | return ::Catch::Detail::stringify(static_cast<char>(c)); | |
11994 | } | |
11995 | ||
11996 | std::string StringMaker<std::nullptr_t>::convert(std::nullptr_t) { | |
11997 | return "nullptr"; | |
11998 | } | |
11999 | ||
12000 | std::string StringMaker<float>::convert(float value) { | |
12001 | return fpToString(value, 5) + 'f'; | |
12002 | } | |
12003 | std::string StringMaker<double>::convert(double value) { | |
12004 | return fpToString(value, 10); | |
12005 | } | |
12006 | ||
12007 | std::string ratio_string<std::atto>::symbol() { return "a"; } | |
12008 | std::string ratio_string<std::femto>::symbol() { return "f"; } | |
12009 | std::string ratio_string<std::pico>::symbol() { return "p"; } | |
12010 | std::string ratio_string<std::nano>::symbol() { return "n"; } | |
12011 | std::string ratio_string<std::micro>::symbol() { return "u"; } | |
12012 | std::string ratio_string<std::milli>::symbol() { return "m"; } | |
12013 | ||
12014 | } // end namespace Catch | |
12015 | ||
12016 | #if defined(__clang__) | |
12017 | # pragma clang diagnostic pop | |
12018 | #endif | |
12019 | ||
12020 | // end catch_tostring.cpp | |
12021 | // start catch_totals.cpp | |
12022 | ||
12023 | namespace Catch { | |
12024 | ||
12025 | Counts Counts::operator - ( Counts const& other ) const { | |
12026 | Counts diff; | |
12027 | diff.passed = passed - other.passed; | |
12028 | diff.failed = failed - other.failed; | |
12029 | diff.failedButOk = failedButOk - other.failedButOk; | |
12030 | return diff; | |
12031 | } | |
12032 | ||
12033 | Counts& Counts::operator += ( Counts const& other ) { | |
12034 | passed += other.passed; | |
12035 | failed += other.failed; | |
12036 | failedButOk += other.failedButOk; | |
12037 | return *this; | |
12038 | } | |
12039 | ||
12040 | std::size_t Counts::total() const { | |
12041 | return passed + failed + failedButOk; | |
12042 | } | |
12043 | bool Counts::allPassed() const { | |
12044 | return failed == 0 && failedButOk == 0; | |
12045 | } | |
12046 | bool Counts::allOk() const { | |
12047 | return failed == 0; | |
12048 | } | |
12049 | ||
12050 | Totals Totals::operator - ( Totals const& other ) const { | |
12051 | Totals diff; | |
12052 | diff.assertions = assertions - other.assertions; | |
12053 | diff.testCases = testCases - other.testCases; | |
12054 | return diff; | |
12055 | } | |
12056 | ||
12057 | Totals& Totals::operator += ( Totals const& other ) { | |
12058 | assertions += other.assertions; | |
12059 | testCases += other.testCases; | |
12060 | return *this; | |
12061 | } | |
12062 | ||
12063 | Totals Totals::delta( Totals const& prevTotals ) const { | |
12064 | Totals diff = *this - prevTotals; | |
12065 | if( diff.assertions.failed > 0 ) | |
12066 | ++diff.testCases.failed; | |
12067 | else if( diff.assertions.failedButOk > 0 ) | |
12068 | ++diff.testCases.failedButOk; | |
12069 | else | |
12070 | ++diff.testCases.passed; | |
12071 | return diff; | |
12072 | } | |
12073 | ||
12074 | } | |
12075 | // end catch_totals.cpp | |
12076 | // start catch_uncaught_exceptions.cpp | |
12077 | ||
12078 | #include <exception> | |
12079 | ||
12080 | namespace Catch { | |
12081 | bool uncaught_exceptions() { | |
12082 | #if defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) | |
12083 | return std::uncaught_exceptions() > 0; | |
12084 | #else | |
12085 | return std::uncaught_exception(); | |
12086 | #endif | |
12087 | } | |
12088 | } // end namespace Catch | |
12089 | // end catch_uncaught_exceptions.cpp | |
12090 | // start catch_version.cpp | |
12091 | ||
12092 | #include <ostream> | |
12093 | ||
12094 | namespace Catch { | |
12095 | ||
12096 | Version::Version | |
12097 | ( unsigned int _majorVersion, | |
12098 | unsigned int _minorVersion, | |
12099 | unsigned int _patchNumber, | |
12100 | char const * const _branchName, | |
12101 | unsigned int _buildNumber ) | |
12102 | : majorVersion( _majorVersion ), | |
12103 | minorVersion( _minorVersion ), | |
12104 | patchNumber( _patchNumber ), | |
12105 | branchName( _branchName ), | |
12106 | buildNumber( _buildNumber ) | |
12107 | {} | |
12108 | ||
12109 | std::ostream& operator << ( std::ostream& os, Version const& version ) { | |
12110 | os << version.majorVersion << '.' | |
12111 | << version.minorVersion << '.' | |
12112 | << version.patchNumber; | |
12113 | // branchName is never null -> 0th char is \0 if it is empty | |
12114 | if (version.branchName[0]) { | |
12115 | os << '-' << version.branchName | |
12116 | << '.' << version.buildNumber; | |
12117 | } | |
12118 | return os; | |
12119 | } | |
12120 | ||
12121 | Version const& libraryVersion() { | |
12122 | static Version version( 2, 5, 0, "", 0 ); | |
12123 | return version; | |
12124 | } | |
12125 | ||
12126 | } | |
12127 | // end catch_version.cpp | |
12128 | // start catch_wildcard_pattern.cpp | |
12129 | ||
12130 | #include <sstream> | |
12131 | ||
12132 | namespace Catch { | |
12133 | ||
12134 | WildcardPattern::WildcardPattern( std::string const& pattern, | |
12135 | CaseSensitive::Choice caseSensitivity ) | |
12136 | : m_caseSensitivity( caseSensitivity ), | |
12137 | m_pattern( adjustCase( pattern ) ) | |
12138 | { | |
12139 | if( startsWith( m_pattern, '*' ) ) { | |
12140 | m_pattern = m_pattern.substr( 1 ); | |
12141 | m_wildcard = WildcardAtStart; | |
12142 | } | |
12143 | if( endsWith( m_pattern, '*' ) ) { | |
12144 | m_pattern = m_pattern.substr( 0, m_pattern.size()-1 ); | |
12145 | m_wildcard = static_cast<WildcardPosition>( m_wildcard | WildcardAtEnd ); | |
12146 | } | |
12147 | } | |
12148 | ||
12149 | bool WildcardPattern::matches( std::string const& str ) const { | |
12150 | switch( m_wildcard ) { | |
12151 | case NoWildcard: | |
12152 | return m_pattern == adjustCase( str ); | |
12153 | case WildcardAtStart: | |
12154 | return endsWith( adjustCase( str ), m_pattern ); | |
12155 | case WildcardAtEnd: | |
12156 | return startsWith( adjustCase( str ), m_pattern ); | |
12157 | case WildcardAtBothEnds: | |
12158 | return contains( adjustCase( str ), m_pattern ); | |
12159 | default: | |
12160 | CATCH_INTERNAL_ERROR( "Unknown enum" ); | |
12161 | } | |
12162 | } | |
12163 | ||
12164 | std::string WildcardPattern::adjustCase( std::string const& str ) const { | |
12165 | return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str; | |
12166 | } | |
12167 | } | |
12168 | // end catch_wildcard_pattern.cpp | |
12169 | // start catch_xmlwriter.cpp | |
12170 | ||
12171 | #include <iomanip> | |
12172 | ||
12173 | using uchar = unsigned char; | |
12174 | ||
12175 | namespace Catch { | |
12176 | ||
12177 | namespace { | |
12178 | ||
12179 | size_t trailingBytes(unsigned char c) { | |
12180 | if ((c & 0xE0) == 0xC0) { | |
12181 | return 2; | |
12182 | } | |
12183 | if ((c & 0xF0) == 0xE0) { | |
12184 | return 3; | |
12185 | } | |
12186 | if ((c & 0xF8) == 0xF0) { | |
12187 | return 4; | |
12188 | } | |
12189 | CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered"); | |
12190 | } | |
12191 | ||
12192 | uint32_t headerValue(unsigned char c) { | |
12193 | if ((c & 0xE0) == 0xC0) { | |
12194 | return c & 0x1F; | |
12195 | } | |
12196 | if ((c & 0xF0) == 0xE0) { | |
12197 | return c & 0x0F; | |
12198 | } | |
12199 | if ((c & 0xF8) == 0xF0) { | |
12200 | return c & 0x07; | |
12201 | } | |
12202 | CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered"); | |
12203 | } | |
12204 | ||
12205 | void hexEscapeChar(std::ostream& os, unsigned char c) { | |
12206 | os << "\\x" | |
12207 | << std::uppercase << std::hex << std::setfill('0') << std::setw(2) | |
12208 | << static_cast<int>(c); | |
12209 | } | |
12210 | ||
12211 | } // anonymous namespace | |
12212 | ||
12213 | XmlEncode::XmlEncode( std::string const& str, ForWhat forWhat ) | |
12214 | : m_str( str ), | |
12215 | m_forWhat( forWhat ) | |
12216 | {} | |
12217 | ||
12218 | void XmlEncode::encodeTo( std::ostream& os ) const { | |
12219 | // Apostrophe escaping not necessary if we always use " to write attributes | |
12220 | // (see: http://www.w3.org/TR/xml/#syntax) | |
12221 | ||
12222 | for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) { | |
12223 | uchar c = m_str[idx]; | |
12224 | switch (c) { | |
12225 | case '<': os << "<"; break; | |
12226 | case '&': os << "&"; break; | |
12227 | ||
12228 | case '>': | |
12229 | // See: http://www.w3.org/TR/xml/#syntax | |
12230 | if (idx > 2 && m_str[idx - 1] == ']' && m_str[idx - 2] == ']') | |
12231 | os << ">"; | |
12232 | else | |
12233 | os << c; | |
12234 | break; | |
12235 | ||
12236 | case '\"': | |
12237 | if (m_forWhat == ForAttributes) | |
12238 | os << """; | |
12239 | else | |
12240 | os << c; | |
12241 | break; | |
12242 | ||
12243 | default: | |
12244 | // Check for control characters and invalid utf-8 | |
12245 | ||
12246 | // Escape control characters in standard ascii | |
12247 | // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0 | |
12248 | if (c < 0x09 || (c > 0x0D && c < 0x20) || c == 0x7F) { | |
12249 | hexEscapeChar(os, c); | |
12250 | break; | |
12251 | } | |
12252 | ||
12253 | // Plain ASCII: Write it to stream | |
12254 | if (c < 0x7F) { | |
12255 | os << c; | |
12256 | break; | |
12257 | } | |
12258 | ||
12259 | // UTF-8 territory | |
12260 | // Check if the encoding is valid and if it is not, hex escape bytes. | |
12261 | // Important: We do not check the exact decoded values for validity, only the encoding format | |
12262 | // First check that this bytes is a valid lead byte: | |
12263 | // This means that it is not encoded as 1111 1XXX | |
12264 | // Or as 10XX XXXX | |
12265 | if (c < 0xC0 || | |
12266 | c >= 0xF8) { | |
12267 | hexEscapeChar(os, c); | |
12268 | break; | |
12269 | } | |
12270 | ||
12271 | auto encBytes = trailingBytes(c); | |
12272 | // Are there enough bytes left to avoid accessing out-of-bounds memory? | |
12273 | if (idx + encBytes - 1 >= m_str.size()) { | |
12274 | hexEscapeChar(os, c); | |
12275 | break; | |
12276 | } | |
12277 | // The header is valid, check data | |
12278 | // The next encBytes bytes must together be a valid utf-8 | |
12279 | // This means: bitpattern 10XX XXXX and the extracted value is sane (ish) | |
12280 | bool valid = true; | |
12281 | uint32_t value = headerValue(c); | |
12282 | for (std::size_t n = 1; n < encBytes; ++n) { | |
12283 | uchar nc = m_str[idx + n]; | |
12284 | valid &= ((nc & 0xC0) == 0x80); | |
12285 | value = (value << 6) | (nc & 0x3F); | |
12286 | } | |
12287 | ||
12288 | if ( | |
12289 | // Wrong bit pattern of following bytes | |
12290 | (!valid) || | |
12291 | // Overlong encodings | |
12292 | (value < 0x80) || | |
12293 | (0x80 <= value && value < 0x800 && encBytes > 2) || | |
12294 | (0x800 < value && value < 0x10000 && encBytes > 3) || | |
12295 | // Encoded value out of range | |
12296 | (value >= 0x110000) | |
12297 | ) { | |
12298 | hexEscapeChar(os, c); | |
12299 | break; | |
12300 | } | |
12301 | ||
12302 | // If we got here, this is in fact a valid(ish) utf-8 sequence | |
12303 | for (std::size_t n = 0; n < encBytes; ++n) { | |
12304 | os << m_str[idx + n]; | |
12305 | } | |
12306 | idx += encBytes - 1; | |
12307 | break; | |
12308 | } | |
12309 | } | |
12310 | } | |
12311 | ||
12312 | std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { | |
12313 | xmlEncode.encodeTo( os ); | |
12314 | return os; | |
12315 | } | |
12316 | ||
12317 | XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer ) | |
12318 | : m_writer( writer ) | |
12319 | {} | |
12320 | ||
12321 | XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) noexcept | |
12322 | : m_writer( other.m_writer ){ | |
12323 | other.m_writer = nullptr; | |
12324 | } | |
12325 | XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) noexcept { | |
12326 | if ( m_writer ) { | |
12327 | m_writer->endElement(); | |
12328 | } | |
12329 | m_writer = other.m_writer; | |
12330 | other.m_writer = nullptr; | |
12331 | return *this; | |
12332 | } | |
12333 | ||
12334 | XmlWriter::ScopedElement::~ScopedElement() { | |
12335 | if( m_writer ) | |
12336 | m_writer->endElement(); | |
12337 | } | |
12338 | ||
12339 | XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, bool indent ) { | |
12340 | m_writer->writeText( text, indent ); | |
12341 | return *this; | |
12342 | } | |
12343 | ||
12344 | XmlWriter::XmlWriter( std::ostream& os ) : m_os( os ) | |
12345 | { | |
12346 | writeDeclaration(); | |
12347 | } | |
12348 | ||
12349 | XmlWriter::~XmlWriter() { | |
12350 | while( !m_tags.empty() ) | |
12351 | endElement(); | |
12352 | } | |
12353 | ||
12354 | XmlWriter& XmlWriter::startElement( std::string const& name ) { | |
12355 | ensureTagClosed(); | |
12356 | newlineIfNecessary(); | |
12357 | m_os << m_indent << '<' << name; | |
12358 | m_tags.push_back( name ); | |
12359 | m_indent += " "; | |
12360 | m_tagIsOpen = true; | |
12361 | return *this; | |
12362 | } | |
12363 | ||
12364 | XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name ) { | |
12365 | ScopedElement scoped( this ); | |
12366 | startElement( name ); | |
12367 | return scoped; | |
12368 | } | |
12369 | ||
12370 | XmlWriter& XmlWriter::endElement() { | |
12371 | newlineIfNecessary(); | |
12372 | m_indent = m_indent.substr( 0, m_indent.size()-2 ); | |
12373 | if( m_tagIsOpen ) { | |
12374 | m_os << "/>"; | |
12375 | m_tagIsOpen = false; | |
12376 | } | |
12377 | else { | |
12378 | m_os << m_indent << "</" << m_tags.back() << ">"; | |
12379 | } | |
12380 | m_os << std::endl; | |
12381 | m_tags.pop_back(); | |
12382 | return *this; | |
12383 | } | |
12384 | ||
12385 | XmlWriter& XmlWriter::writeAttribute( std::string const& name, std::string const& attribute ) { | |
12386 | if( !name.empty() && !attribute.empty() ) | |
12387 | m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"'; | |
12388 | return *this; | |
12389 | } | |
12390 | ||
12391 | XmlWriter& XmlWriter::writeAttribute( std::string const& name, bool attribute ) { | |
12392 | m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"'; | |
12393 | return *this; | |
12394 | } | |
12395 | ||
12396 | XmlWriter& XmlWriter::writeText( std::string const& text, bool indent ) { | |
12397 | if( !text.empty() ){ | |
12398 | bool tagWasOpen = m_tagIsOpen; | |
12399 | ensureTagClosed(); | |
12400 | if( tagWasOpen && indent ) | |
12401 | m_os << m_indent; | |
12402 | m_os << XmlEncode( text ); | |
12403 | m_needsNewline = true; | |
12404 | } | |
12405 | return *this; | |
12406 | } | |
12407 | ||
12408 | XmlWriter& XmlWriter::writeComment( std::string const& text ) { | |
12409 | ensureTagClosed(); | |
12410 | m_os << m_indent << "<!--" << text << "-->"; | |
12411 | m_needsNewline = true; | |
12412 | return *this; | |
12413 | } | |
12414 | ||
12415 | void XmlWriter::writeStylesheetRef( std::string const& url ) { | |
12416 | m_os << "<?xml-stylesheet type=\"text/xsl\" href=\"" << url << "\"?>\n"; | |
12417 | } | |
12418 | ||
12419 | XmlWriter& XmlWriter::writeBlankLine() { | |
12420 | ensureTagClosed(); | |
12421 | m_os << '\n'; | |
12422 | return *this; | |
12423 | } | |
12424 | ||
12425 | void XmlWriter::ensureTagClosed() { | |
12426 | if( m_tagIsOpen ) { | |
12427 | m_os << ">" << std::endl; | |
12428 | m_tagIsOpen = false; | |
12429 | } | |
12430 | } | |
12431 | ||
12432 | void XmlWriter::writeDeclaration() { | |
12433 | m_os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; | |
12434 | } | |
12435 | ||
12436 | void XmlWriter::newlineIfNecessary() { | |
12437 | if( m_needsNewline ) { | |
12438 | m_os << std::endl; | |
12439 | m_needsNewline = false; | |
12440 | } | |
12441 | } | |
12442 | } | |
12443 | // end catch_xmlwriter.cpp | |
12444 | // start catch_reporter_bases.cpp | |
12445 | ||
12446 | #include <cstring> | |
12447 | #include <cfloat> | |
12448 | #include <cstdio> | |
12449 | #include <cassert> | |
12450 | #include <memory> | |
12451 | ||
12452 | namespace Catch { | |
12453 | void prepareExpandedExpression(AssertionResult& result) { | |
12454 | result.getExpandedExpression(); | |
12455 | } | |
12456 | ||
12457 | // Because formatting using c++ streams is stateful, drop down to C is required | |
12458 | // Alternatively we could use stringstream, but its performance is... not good. | |
12459 | std::string getFormattedDuration( double duration ) { | |
12460 | // Max exponent + 1 is required to represent the whole part | |
12461 | // + 1 for decimal point | |
12462 | // + 3 for the 3 decimal places | |
12463 | // + 1 for null terminator | |
12464 | const std::size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1; | |
12465 | char buffer[maxDoubleSize]; | |
12466 | ||
12467 | // Save previous errno, to prevent sprintf from overwriting it | |
12468 | ErrnoGuard guard; | |
12469 | #ifdef _MSC_VER | |
12470 | sprintf_s(buffer, "%.3f", duration); | |
12471 | #else | |
12472 | sprintf(buffer, "%.3f", duration); | |
12473 | #endif | |
12474 | return std::string(buffer); | |
12475 | } | |
12476 | ||
12477 | TestEventListenerBase::TestEventListenerBase(ReporterConfig const & _config) | |
12478 | :StreamingReporterBase(_config) {} | |
12479 | ||
12480 | std::set<Verbosity> TestEventListenerBase::getSupportedVerbosities() { | |
12481 | return { Verbosity::Quiet, Verbosity::Normal, Verbosity::High }; | |
12482 | } | |
12483 | ||
12484 | void TestEventListenerBase::assertionStarting(AssertionInfo const &) {} | |
12485 | ||
12486 | bool TestEventListenerBase::assertionEnded(AssertionStats const &) { | |
12487 | return false; | |
12488 | } | |
12489 | ||
12490 | } // end namespace Catch | |
12491 | // end catch_reporter_bases.cpp | |
12492 | // start catch_reporter_compact.cpp | |
12493 | ||
12494 | namespace { | |
12495 | ||
12496 | #ifdef CATCH_PLATFORM_MAC | |
12497 | const char* failedString() { return "FAILED"; } | |
12498 | const char* passedString() { return "PASSED"; } | |
12499 | #else | |
12500 | const char* failedString() { return "failed"; } | |
12501 | const char* passedString() { return "passed"; } | |
12502 | #endif | |
12503 | ||
12504 | // Colour::LightGrey | |
12505 | Catch::Colour::Code dimColour() { return Catch::Colour::FileName; } | |
12506 | ||
12507 | std::string bothOrAll( std::size_t count ) { | |
12508 | return count == 1 ? std::string() : | |
12509 | count == 2 ? "both " : "all " ; | |
12510 | } | |
12511 | ||
12512 | } // anon namespace | |
12513 | ||
12514 | namespace Catch { | |
12515 | namespace { | |
12516 | // Colour, message variants: | |
12517 | // - white: No tests ran. | |
12518 | // - red: Failed [both/all] N test cases, failed [both/all] M assertions. | |
12519 | // - white: Passed [both/all] N test cases (no assertions). | |
12520 | // - red: Failed N tests cases, failed M assertions. | |
12521 | // - green: Passed [both/all] N tests cases with M assertions. | |
12522 | void printTotals(std::ostream& out, const Totals& totals) { | |
12523 | if (totals.testCases.total() == 0) { | |
12524 | out << "No tests ran."; | |
12525 | } else if (totals.testCases.failed == totals.testCases.total()) { | |
12526 | Colour colour(Colour::ResultError); | |
12527 | const std::string qualify_assertions_failed = | |
12528 | totals.assertions.failed == totals.assertions.total() ? | |
12529 | bothOrAll(totals.assertions.failed) : std::string(); | |
12530 | out << | |
12531 | "Failed " << bothOrAll(totals.testCases.failed) | |
12532 | << pluralise(totals.testCases.failed, "test case") << ", " | |
12533 | "failed " << qualify_assertions_failed << | |
12534 | pluralise(totals.assertions.failed, "assertion") << '.'; | |
12535 | } else if (totals.assertions.total() == 0) { | |
12536 | out << | |
12537 | "Passed " << bothOrAll(totals.testCases.total()) | |
12538 | << pluralise(totals.testCases.total(), "test case") | |
12539 | << " (no assertions)."; | |
12540 | } else if (totals.assertions.failed) { | |
12541 | Colour colour(Colour::ResultError); | |
12542 | out << | |
12543 | "Failed " << pluralise(totals.testCases.failed, "test case") << ", " | |
12544 | "failed " << pluralise(totals.assertions.failed, "assertion") << '.'; | |
12545 | } else { | |
12546 | Colour colour(Colour::ResultSuccess); | |
12547 | out << | |
12548 | "Passed " << bothOrAll(totals.testCases.passed) | |
12549 | << pluralise(totals.testCases.passed, "test case") << | |
12550 | " with " << pluralise(totals.assertions.passed, "assertion") << '.'; | |
12551 | } | |
12552 | } | |
12553 | ||
12554 | // Implementation of CompactReporter formatting | |
12555 | class AssertionPrinter { | |
12556 | public: | |
12557 | AssertionPrinter& operator= (AssertionPrinter const&) = delete; | |
12558 | AssertionPrinter(AssertionPrinter const&) = delete; | |
12559 | AssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages) | |
12560 | : stream(_stream) | |
12561 | , result(_stats.assertionResult) | |
12562 | , messages(_stats.infoMessages) | |
12563 | , itMessage(_stats.infoMessages.begin()) | |
12564 | , printInfoMessages(_printInfoMessages) {} | |
12565 | ||
12566 | void print() { | |
12567 | printSourceInfo(); | |
12568 | ||
12569 | itMessage = messages.begin(); | |
12570 | ||
12571 | switch (result.getResultType()) { | |
12572 | case ResultWas::Ok: | |
12573 | printResultType(Colour::ResultSuccess, passedString()); | |
12574 | printOriginalExpression(); | |
12575 | printReconstructedExpression(); | |
12576 | if (!result.hasExpression()) | |
12577 | printRemainingMessages(Colour::None); | |
12578 | else | |
12579 | printRemainingMessages(); | |
12580 | break; | |
12581 | case ResultWas::ExpressionFailed: | |
12582 | if (result.isOk()) | |
12583 | printResultType(Colour::ResultSuccess, failedString() + std::string(" - but was ok")); | |
12584 | else | |
12585 | printResultType(Colour::Error, failedString()); | |
12586 | printOriginalExpression(); | |
12587 | printReconstructedExpression(); | |
12588 | printRemainingMessages(); | |
12589 | break; | |
12590 | case ResultWas::ThrewException: | |
12591 | printResultType(Colour::Error, failedString()); | |
12592 | printIssue("unexpected exception with message:"); | |
12593 | printMessage(); | |
12594 | printExpressionWas(); | |
12595 | printRemainingMessages(); | |
12596 | break; | |
12597 | case ResultWas::FatalErrorCondition: | |
12598 | printResultType(Colour::Error, failedString()); | |
12599 | printIssue("fatal error condition with message:"); | |
12600 | printMessage(); | |
12601 | printExpressionWas(); | |
12602 | printRemainingMessages(); | |
12603 | break; | |
12604 | case ResultWas::DidntThrowException: | |
12605 | printResultType(Colour::Error, failedString()); | |
12606 | printIssue("expected exception, got none"); | |
12607 | printExpressionWas(); | |
12608 | printRemainingMessages(); | |
12609 | break; | |
12610 | case ResultWas::Info: | |
12611 | printResultType(Colour::None, "info"); | |
12612 | printMessage(); | |
12613 | printRemainingMessages(); | |
12614 | break; | |
12615 | case ResultWas::Warning: | |
12616 | printResultType(Colour::None, "warning"); | |
12617 | printMessage(); | |
12618 | printRemainingMessages(); | |
12619 | break; | |
12620 | case ResultWas::ExplicitFailure: | |
12621 | printResultType(Colour::Error, failedString()); | |
12622 | printIssue("explicitly"); | |
12623 | printRemainingMessages(Colour::None); | |
12624 | break; | |
12625 | // These cases are here to prevent compiler warnings | |
12626 | case ResultWas::Unknown: | |
12627 | case ResultWas::FailureBit: | |
12628 | case ResultWas::Exception: | |
12629 | printResultType(Colour::Error, "** internal error **"); | |
12630 | break; | |
12631 | } | |
12632 | } | |
12633 | ||
12634 | private: | |
12635 | void printSourceInfo() const { | |
12636 | Colour colourGuard(Colour::FileName); | |
12637 | stream << result.getSourceInfo() << ':'; | |
12638 | } | |
12639 | ||
12640 | void printResultType(Colour::Code colour, std::string const& passOrFail) const { | |
12641 | if (!passOrFail.empty()) { | |
12642 | { | |
12643 | Colour colourGuard(colour); | |
12644 | stream << ' ' << passOrFail; | |
12645 | } | |
12646 | stream << ':'; | |
12647 | } | |
12648 | } | |
12649 | ||
12650 | void printIssue(std::string const& issue) const { | |
12651 | stream << ' ' << issue; | |
12652 | } | |
12653 | ||
12654 | void printExpressionWas() { | |
12655 | if (result.hasExpression()) { | |
12656 | stream << ';'; | |
12657 | { | |
12658 | Colour colour(dimColour()); | |
12659 | stream << " expression was:"; | |
12660 | } | |
12661 | printOriginalExpression(); | |
12662 | } | |
12663 | } | |
12664 | ||
12665 | void printOriginalExpression() const { | |
12666 | if (result.hasExpression()) { | |
12667 | stream << ' ' << result.getExpression(); | |
12668 | } | |
12669 | } | |
12670 | ||
12671 | void printReconstructedExpression() const { | |
12672 | if (result.hasExpandedExpression()) { | |
12673 | { | |
12674 | Colour colour(dimColour()); | |
12675 | stream << " for: "; | |
12676 | } | |
12677 | stream << result.getExpandedExpression(); | |
12678 | } | |
12679 | } | |
12680 | ||
12681 | void printMessage() { | |
12682 | if (itMessage != messages.end()) { | |
12683 | stream << " '" << itMessage->message << '\''; | |
12684 | ++itMessage; | |
12685 | } | |
12686 | } | |
12687 | ||
12688 | void printRemainingMessages(Colour::Code colour = dimColour()) { | |
12689 | if (itMessage == messages.end()) | |
12690 | return; | |
12691 | ||
12692 | // using messages.end() directly yields (or auto) compilation error: | |
12693 | std::vector<MessageInfo>::const_iterator itEnd = messages.end(); | |
12694 | const std::size_t N = static_cast<std::size_t>(std::distance(itMessage, itEnd)); | |
12695 | ||
12696 | { | |
12697 | Colour colourGuard(colour); | |
12698 | stream << " with " << pluralise(N, "message") << ':'; | |
12699 | } | |
12700 | ||
12701 | for (; itMessage != itEnd; ) { | |
12702 | // If this assertion is a warning ignore any INFO messages | |
12703 | if (printInfoMessages || itMessage->type != ResultWas::Info) { | |
12704 | stream << " '" << itMessage->message << '\''; | |
12705 | if (++itMessage != itEnd) { | |
12706 | Colour colourGuard(dimColour()); | |
12707 | stream << " and"; | |
12708 | } | |
12709 | } | |
12710 | } | |
12711 | } | |
12712 | ||
12713 | private: | |
12714 | std::ostream& stream; | |
12715 | AssertionResult const& result; | |
12716 | std::vector<MessageInfo> messages; | |
12717 | std::vector<MessageInfo>::const_iterator itMessage; | |
12718 | bool printInfoMessages; | |
12719 | }; | |
12720 | ||
12721 | } // anon namespace | |
12722 | ||
12723 | std::string CompactReporter::getDescription() { | |
12724 | return "Reports test results on a single line, suitable for IDEs"; | |
12725 | } | |
12726 | ||
12727 | ReporterPreferences CompactReporter::getPreferences() const { | |
12728 | return m_reporterPrefs; | |
12729 | } | |
12730 | ||
12731 | void CompactReporter::noMatchingTestCases( std::string const& spec ) { | |
12732 | stream << "No test cases matched '" << spec << '\'' << std::endl; | |
12733 | } | |
12734 | ||
12735 | void CompactReporter::assertionStarting( AssertionInfo const& ) {} | |
12736 | ||
12737 | bool CompactReporter::assertionEnded( AssertionStats const& _assertionStats ) { | |
12738 | AssertionResult const& result = _assertionStats.assertionResult; | |
12739 | ||
12740 | bool printInfoMessages = true; | |
12741 | ||
12742 | // Drop out if result was successful and we're not printing those | |
12743 | if( !m_config->includeSuccessfulResults() && result.isOk() ) { | |
12744 | if( result.getResultType() != ResultWas::Warning ) | |
12745 | return false; | |
12746 | printInfoMessages = false; | |
12747 | } | |
12748 | ||
12749 | AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); | |
12750 | printer.print(); | |
12751 | ||
12752 | stream << std::endl; | |
12753 | return true; | |
12754 | } | |
12755 | ||
12756 | void CompactReporter::sectionEnded(SectionStats const& _sectionStats) { | |
12757 | if (m_config->showDurations() == ShowDurations::Always) { | |
12758 | stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; | |
12759 | } | |
12760 | } | |
12761 | ||
12762 | void CompactReporter::testRunEnded( TestRunStats const& _testRunStats ) { | |
12763 | printTotals( stream, _testRunStats.totals ); | |
12764 | stream << '\n' << std::endl; | |
12765 | StreamingReporterBase::testRunEnded( _testRunStats ); | |
12766 | } | |
12767 | ||
12768 | CompactReporter::~CompactReporter() {} | |
12769 | ||
12770 | CATCH_REGISTER_REPORTER( "compact", CompactReporter ) | |
12771 | ||
12772 | } // end namespace Catch | |
12773 | // end catch_reporter_compact.cpp | |
12774 | // start catch_reporter_console.cpp | |
12775 | ||
12776 | #include <cfloat> | |
12777 | #include <cstdio> | |
12778 | ||
12779 | #if defined(_MSC_VER) | |
12780 | #pragma warning(push) | |
12781 | #pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch | |
12782 | // Note that 4062 (not all labels are handled | |
12783 | // and default is missing) is enabled | |
12784 | #endif | |
12785 | ||
12786 | namespace Catch { | |
12787 | ||
12788 | namespace { | |
12789 | ||
12790 | // Formatter impl for ConsoleReporter | |
12791 | class ConsoleAssertionPrinter { | |
12792 | public: | |
12793 | ConsoleAssertionPrinter& operator= (ConsoleAssertionPrinter const&) = delete; | |
12794 | ConsoleAssertionPrinter(ConsoleAssertionPrinter const&) = delete; | |
12795 | ConsoleAssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages) | |
12796 | : stream(_stream), | |
12797 | stats(_stats), | |
12798 | result(_stats.assertionResult), | |
12799 | colour(Colour::None), | |
12800 | message(result.getMessage()), | |
12801 | messages(_stats.infoMessages), | |
12802 | printInfoMessages(_printInfoMessages) { | |
12803 | switch (result.getResultType()) { | |
12804 | case ResultWas::Ok: | |
12805 | colour = Colour::Success; | |
12806 | passOrFail = "PASSED"; | |
12807 | //if( result.hasMessage() ) | |
12808 | if (_stats.infoMessages.size() == 1) | |
12809 | messageLabel = "with message"; | |
12810 | if (_stats.infoMessages.size() > 1) | |
12811 | messageLabel = "with messages"; | |
12812 | break; | |
12813 | case ResultWas::ExpressionFailed: | |
12814 | if (result.isOk()) { | |
12815 | colour = Colour::Success; | |
12816 | passOrFail = "FAILED - but was ok"; | |
12817 | } else { | |
12818 | colour = Colour::Error; | |
12819 | passOrFail = "FAILED"; | |
12820 | } | |
12821 | if (_stats.infoMessages.size() == 1) | |
12822 | messageLabel = "with message"; | |
12823 | if (_stats.infoMessages.size() > 1) | |
12824 | messageLabel = "with messages"; | |
12825 | break; | |
12826 | case ResultWas::ThrewException: | |
12827 | colour = Colour::Error; | |
12828 | passOrFail = "FAILED"; | |
12829 | messageLabel = "due to unexpected exception with "; | |
12830 | if (_stats.infoMessages.size() == 1) | |
12831 | messageLabel += "message"; | |
12832 | if (_stats.infoMessages.size() > 1) | |
12833 | messageLabel += "messages"; | |
12834 | break; | |
12835 | case ResultWas::FatalErrorCondition: | |
12836 | colour = Colour::Error; | |
12837 | passOrFail = "FAILED"; | |
12838 | messageLabel = "due to a fatal error condition"; | |
12839 | break; | |
12840 | case ResultWas::DidntThrowException: | |
12841 | colour = Colour::Error; | |
12842 | passOrFail = "FAILED"; | |
12843 | messageLabel = "because no exception was thrown where one was expected"; | |
12844 | break; | |
12845 | case ResultWas::Info: | |
12846 | messageLabel = "info"; | |
12847 | break; | |
12848 | case ResultWas::Warning: | |
12849 | messageLabel = "warning"; | |
12850 | break; | |
12851 | case ResultWas::ExplicitFailure: | |
12852 | passOrFail = "FAILED"; | |
12853 | colour = Colour::Error; | |
12854 | if (_stats.infoMessages.size() == 1) | |
12855 | messageLabel = "explicitly with message"; | |
12856 | if (_stats.infoMessages.size() > 1) | |
12857 | messageLabel = "explicitly with messages"; | |
12858 | break; | |
12859 | // These cases are here to prevent compiler warnings | |
12860 | case ResultWas::Unknown: | |
12861 | case ResultWas::FailureBit: | |
12862 | case ResultWas::Exception: | |
12863 | passOrFail = "** internal error **"; | |
12864 | colour = Colour::Error; | |
12865 | break; | |
12866 | } | |
12867 | } | |
12868 | ||
12869 | void print() const { | |
12870 | printSourceInfo(); | |
12871 | if (stats.totals.assertions.total() > 0) { | |
12872 | printResultType(); | |
12873 | printOriginalExpression(); | |
12874 | printReconstructedExpression(); | |
12875 | } else { | |
12876 | stream << '\n'; | |
12877 | } | |
12878 | printMessage(); | |
12879 | } | |
12880 | ||
12881 | private: | |
12882 | void printResultType() const { | |
12883 | if (!passOrFail.empty()) { | |
12884 | Colour colourGuard(colour); | |
12885 | stream << passOrFail << ":\n"; | |
12886 | } | |
12887 | } | |
12888 | void printOriginalExpression() const { | |
12889 | if (result.hasExpression()) { | |
12890 | Colour colourGuard(Colour::OriginalExpression); | |
12891 | stream << " "; | |
12892 | stream << result.getExpressionInMacro(); | |
12893 | stream << '\n'; | |
12894 | } | |
12895 | } | |
12896 | void printReconstructedExpression() const { | |
12897 | if (result.hasExpandedExpression()) { | |
12898 | stream << "with expansion:\n"; | |
12899 | Colour colourGuard(Colour::ReconstructedExpression); | |
12900 | stream << Column(result.getExpandedExpression()).indent(2) << '\n'; | |
12901 | } | |
12902 | } | |
12903 | void printMessage() const { | |
12904 | if (!messageLabel.empty()) | |
12905 | stream << messageLabel << ':' << '\n'; | |
12906 | for (auto const& msg : messages) { | |
12907 | // If this assertion is a warning ignore any INFO messages | |
12908 | if (printInfoMessages || msg.type != ResultWas::Info) | |
12909 | stream << Column(msg.message).indent(2) << '\n'; | |
12910 | } | |
12911 | } | |
12912 | void printSourceInfo() const { | |
12913 | Colour colourGuard(Colour::FileName); | |
12914 | stream << result.getSourceInfo() << ": "; | |
12915 | } | |
12916 | ||
12917 | std::ostream& stream; | |
12918 | AssertionStats const& stats; | |
12919 | AssertionResult const& result; | |
12920 | Colour::Code colour; | |
12921 | std::string passOrFail; | |
12922 | std::string messageLabel; | |
12923 | std::string message; | |
12924 | std::vector<MessageInfo> messages; | |
12925 | bool printInfoMessages; | |
12926 | }; | |
12927 | ||
12928 | std::size_t makeRatio(std::size_t number, std::size_t total) { | |
12929 | std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number / total : 0; | |
12930 | return (ratio == 0 && number > 0) ? 1 : ratio; | |
12931 | } | |
12932 | ||
12933 | std::size_t& findMax(std::size_t& i, std::size_t& j, std::size_t& k) { | |
12934 | if (i > j && i > k) | |
12935 | return i; | |
12936 | else if (j > k) | |
12937 | return j; | |
12938 | else | |
12939 | return k; | |
12940 | } | |
12941 | ||
12942 | struct ColumnInfo { | |
12943 | enum Justification { Left, Right }; | |
12944 | std::string name; | |
12945 | int width; | |
12946 | Justification justification; | |
12947 | }; | |
12948 | struct ColumnBreak {}; | |
12949 | struct RowBreak {}; | |
12950 | ||
12951 | class Duration { | |
12952 | enum class Unit { | |
12953 | Auto, | |
12954 | Nanoseconds, | |
12955 | Microseconds, | |
12956 | Milliseconds, | |
12957 | Seconds, | |
12958 | Minutes | |
12959 | }; | |
12960 | static const uint64_t s_nanosecondsInAMicrosecond = 1000; | |
12961 | static const uint64_t s_nanosecondsInAMillisecond = 1000 * s_nanosecondsInAMicrosecond; | |
12962 | static const uint64_t s_nanosecondsInASecond = 1000 * s_nanosecondsInAMillisecond; | |
12963 | static const uint64_t s_nanosecondsInAMinute = 60 * s_nanosecondsInASecond; | |
12964 | ||
12965 | uint64_t m_inNanoseconds; | |
12966 | Unit m_units; | |
12967 | ||
12968 | public: | |
12969 | explicit Duration(uint64_t inNanoseconds, Unit units = Unit::Auto) | |
12970 | : m_inNanoseconds(inNanoseconds), | |
12971 | m_units(units) { | |
12972 | if (m_units == Unit::Auto) { | |
12973 | if (m_inNanoseconds < s_nanosecondsInAMicrosecond) | |
12974 | m_units = Unit::Nanoseconds; | |
12975 | else if (m_inNanoseconds < s_nanosecondsInAMillisecond) | |
12976 | m_units = Unit::Microseconds; | |
12977 | else if (m_inNanoseconds < s_nanosecondsInASecond) | |
12978 | m_units = Unit::Milliseconds; | |
12979 | else if (m_inNanoseconds < s_nanosecondsInAMinute) | |
12980 | m_units = Unit::Seconds; | |
12981 | else | |
12982 | m_units = Unit::Minutes; | |
12983 | } | |
12984 | ||
12985 | } | |
12986 | ||
12987 | auto value() const -> double { | |
12988 | switch (m_units) { | |
12989 | case Unit::Microseconds: | |
12990 | return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMicrosecond); | |
12991 | case Unit::Milliseconds: | |
12992 | return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMillisecond); | |
12993 | case Unit::Seconds: | |
12994 | return m_inNanoseconds / static_cast<double>(s_nanosecondsInASecond); | |
12995 | case Unit::Minutes: | |
12996 | return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMinute); | |
12997 | default: | |
12998 | return static_cast<double>(m_inNanoseconds); | |
12999 | } | |
13000 | } | |
13001 | auto unitsAsString() const -> std::string { | |
13002 | switch (m_units) { | |
13003 | case Unit::Nanoseconds: | |
13004 | return "ns"; | |
13005 | case Unit::Microseconds: | |
13006 | return "µs"; | |
13007 | case Unit::Milliseconds: | |
13008 | return "ms"; | |
13009 | case Unit::Seconds: | |
13010 | return "s"; | |
13011 | case Unit::Minutes: | |
13012 | return "m"; | |
13013 | default: | |
13014 | return "** internal error **"; | |
13015 | } | |
13016 | ||
13017 | } | |
13018 | friend auto operator << (std::ostream& os, Duration const& duration) -> std::ostream& { | |
13019 | return os << duration.value() << " " << duration.unitsAsString(); | |
13020 | } | |
13021 | }; | |
13022 | } // end anon namespace | |
13023 | ||
13024 | class TablePrinter { | |
13025 | std::ostream& m_os; | |
13026 | std::vector<ColumnInfo> m_columnInfos; | |
13027 | std::ostringstream m_oss; | |
13028 | int m_currentColumn = -1; | |
13029 | bool m_isOpen = false; | |
13030 | ||
13031 | public: | |
13032 | TablePrinter( std::ostream& os, std::vector<ColumnInfo> columnInfos ) | |
13033 | : m_os( os ), | |
13034 | m_columnInfos( std::move( columnInfos ) ) {} | |
13035 | ||
13036 | auto columnInfos() const -> std::vector<ColumnInfo> const& { | |
13037 | return m_columnInfos; | |
13038 | } | |
13039 | ||
13040 | void open() { | |
13041 | if (!m_isOpen) { | |
13042 | m_isOpen = true; | |
13043 | *this << RowBreak(); | |
13044 | for (auto const& info : m_columnInfos) | |
13045 | *this << info.name << ColumnBreak(); | |
13046 | *this << RowBreak(); | |
13047 | m_os << Catch::getLineOfChars<'-'>() << "\n"; | |
13048 | } | |
13049 | } | |
13050 | void close() { | |
13051 | if (m_isOpen) { | |
13052 | *this << RowBreak(); | |
13053 | m_os << std::endl; | |
13054 | m_isOpen = false; | |
13055 | } | |
13056 | } | |
13057 | ||
13058 | template<typename T> | |
13059 | friend TablePrinter& operator << (TablePrinter& tp, T const& value) { | |
13060 | tp.m_oss << value; | |
13061 | return tp; | |
13062 | } | |
13063 | ||
13064 | friend TablePrinter& operator << (TablePrinter& tp, ColumnBreak) { | |
13065 | auto colStr = tp.m_oss.str(); | |
13066 | // This takes account of utf8 encodings | |
13067 | auto strSize = Catch::StringRef(colStr).numberOfCharacters(); | |
13068 | tp.m_oss.str(""); | |
13069 | tp.open(); | |
13070 | if (tp.m_currentColumn == static_cast<int>(tp.m_columnInfos.size() - 1)) { | |
13071 | tp.m_currentColumn = -1; | |
13072 | tp.m_os << "\n"; | |
13073 | } | |
13074 | tp.m_currentColumn++; | |
13075 | ||
13076 | auto colInfo = tp.m_columnInfos[tp.m_currentColumn]; | |
13077 | auto padding = (strSize + 2 < static_cast<std::size_t>(colInfo.width)) | |
13078 | ? std::string(colInfo.width - (strSize + 2), ' ') | |
13079 | : std::string(); | |
13080 | if (colInfo.justification == ColumnInfo::Left) | |
13081 | tp.m_os << colStr << padding << " "; | |
13082 | else | |
13083 | tp.m_os << padding << colStr << " "; | |
13084 | return tp; | |
13085 | } | |
13086 | ||
13087 | friend TablePrinter& operator << (TablePrinter& tp, RowBreak) { | |
13088 | if (tp.m_currentColumn > 0) { | |
13089 | tp.m_os << "\n"; | |
13090 | tp.m_currentColumn = -1; | |
13091 | } | |
13092 | return tp; | |
13093 | } | |
13094 | }; | |
13095 | ||
13096 | ConsoleReporter::ConsoleReporter(ReporterConfig const& config) | |
13097 | : StreamingReporterBase(config), | |
13098 | m_tablePrinter(new TablePrinter(config.stream(), | |
13099 | { | |
13100 | { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 32, ColumnInfo::Left }, | |
13101 | { "iters", 8, ColumnInfo::Right }, | |
13102 | { "elapsed ns", 14, ColumnInfo::Right }, | |
13103 | { "average", 14, ColumnInfo::Right } | |
13104 | })) {} | |
13105 | ConsoleReporter::~ConsoleReporter() = default; | |
13106 | ||
13107 | std::string ConsoleReporter::getDescription() { | |
13108 | return "Reports test results as plain lines of text"; | |
13109 | } | |
13110 | ||
13111 | void ConsoleReporter::noMatchingTestCases(std::string const& spec) { | |
13112 | stream << "No test cases matched '" << spec << '\'' << std::endl; | |
13113 | } | |
13114 | ||
13115 | void ConsoleReporter::assertionStarting(AssertionInfo const&) {} | |
13116 | ||
13117 | bool ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) { | |
13118 | AssertionResult const& result = _assertionStats.assertionResult; | |
13119 | ||
13120 | bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); | |
13121 | ||
13122 | // Drop out if result was successful but we're not printing them. | |
13123 | if (!includeResults && result.getResultType() != ResultWas::Warning) | |
13124 | return false; | |
13125 | ||
13126 | lazyPrint(); | |
13127 | ||
13128 | ConsoleAssertionPrinter printer(stream, _assertionStats, includeResults); | |
13129 | printer.print(); | |
13130 | stream << std::endl; | |
13131 | return true; | |
13132 | } | |
13133 | ||
13134 | void ConsoleReporter::sectionStarting(SectionInfo const& _sectionInfo) { | |
13135 | m_headerPrinted = false; | |
13136 | StreamingReporterBase::sectionStarting(_sectionInfo); | |
13137 | } | |
13138 | void ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) { | |
13139 | m_tablePrinter->close(); | |
13140 | if (_sectionStats.missingAssertions) { | |
13141 | lazyPrint(); | |
13142 | Colour colour(Colour::ResultError); | |
13143 | if (m_sectionStack.size() > 1) | |
13144 | stream << "\nNo assertions in section"; | |
13145 | else | |
13146 | stream << "\nNo assertions in test case"; | |
13147 | stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; | |
13148 | } | |
13149 | if (m_config->showDurations() == ShowDurations::Always) { | |
13150 | stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; | |
13151 | } | |
13152 | if (m_headerPrinted) { | |
13153 | m_headerPrinted = false; | |
13154 | } | |
13155 | StreamingReporterBase::sectionEnded(_sectionStats); | |
13156 | } | |
13157 | ||
13158 | void ConsoleReporter::benchmarkStarting(BenchmarkInfo const& info) { | |
13159 | lazyPrintWithoutClosingBenchmarkTable(); | |
13160 | ||
13161 | auto nameCol = Column( info.name ).width( static_cast<std::size_t>( m_tablePrinter->columnInfos()[0].width - 2 ) ); | |
13162 | ||
13163 | bool firstLine = true; | |
13164 | for (auto line : nameCol) { | |
13165 | if (!firstLine) | |
13166 | (*m_tablePrinter) << ColumnBreak() << ColumnBreak() << ColumnBreak(); | |
13167 | else | |
13168 | firstLine = false; | |
13169 | ||
13170 | (*m_tablePrinter) << line << ColumnBreak(); | |
13171 | } | |
13172 | } | |
13173 | void ConsoleReporter::benchmarkEnded(BenchmarkStats const& stats) { | |
13174 | Duration average(stats.elapsedTimeInNanoseconds / stats.iterations); | |
13175 | (*m_tablePrinter) | |
13176 | << stats.iterations << ColumnBreak() | |
13177 | << stats.elapsedTimeInNanoseconds << ColumnBreak() | |
13178 | << average << ColumnBreak(); | |
13179 | } | |
13180 | ||
13181 | void ConsoleReporter::testCaseEnded(TestCaseStats const& _testCaseStats) { | |
13182 | m_tablePrinter->close(); | |
13183 | StreamingReporterBase::testCaseEnded(_testCaseStats); | |
13184 | m_headerPrinted = false; | |
13185 | } | |
13186 | void ConsoleReporter::testGroupEnded(TestGroupStats const& _testGroupStats) { | |
13187 | if (currentGroupInfo.used) { | |
13188 | printSummaryDivider(); | |
13189 | stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; | |
13190 | printTotals(_testGroupStats.totals); | |
13191 | stream << '\n' << std::endl; | |
13192 | } | |
13193 | StreamingReporterBase::testGroupEnded(_testGroupStats); | |
13194 | } | |
13195 | void ConsoleReporter::testRunEnded(TestRunStats const& _testRunStats) { | |
13196 | printTotalsDivider(_testRunStats.totals); | |
13197 | printTotals(_testRunStats.totals); | |
13198 | stream << std::endl; | |
13199 | StreamingReporterBase::testRunEnded(_testRunStats); | |
13200 | } | |
13201 | ||
13202 | void ConsoleReporter::lazyPrint() { | |
13203 | ||
13204 | m_tablePrinter->close(); | |
13205 | lazyPrintWithoutClosingBenchmarkTable(); | |
13206 | } | |
13207 | ||
13208 | void ConsoleReporter::lazyPrintWithoutClosingBenchmarkTable() { | |
13209 | ||
13210 | if (!currentTestRunInfo.used) | |
13211 | lazyPrintRunInfo(); | |
13212 | if (!currentGroupInfo.used) | |
13213 | lazyPrintGroupInfo(); | |
13214 | ||
13215 | if (!m_headerPrinted) { | |
13216 | printTestCaseAndSectionHeader(); | |
13217 | m_headerPrinted = true; | |
13218 | } | |
13219 | } | |
13220 | void ConsoleReporter::lazyPrintRunInfo() { | |
13221 | stream << '\n' << getLineOfChars<'~'>() << '\n'; | |
13222 | Colour colour(Colour::SecondaryText); | |
13223 | stream << currentTestRunInfo->name | |
13224 | << " is a Catch v" << libraryVersion() << " host application.\n" | |
13225 | << "Run with -? for options\n\n"; | |
13226 | ||
13227 | if (m_config->rngSeed() != 0) | |
13228 | stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n"; | |
13229 | ||
13230 | currentTestRunInfo.used = true; | |
13231 | } | |
13232 | void ConsoleReporter::lazyPrintGroupInfo() { | |
13233 | if (!currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1) { | |
13234 | printClosedHeader("Group: " + currentGroupInfo->name); | |
13235 | currentGroupInfo.used = true; | |
13236 | } | |
13237 | } | |
13238 | void ConsoleReporter::printTestCaseAndSectionHeader() { | |
13239 | assert(!m_sectionStack.empty()); | |
13240 | printOpenHeader(currentTestCaseInfo->name); | |
13241 | ||
13242 | if (m_sectionStack.size() > 1) { | |
13243 | Colour colourGuard(Colour::Headers); | |
13244 | ||
13245 | auto | |
13246 | it = m_sectionStack.begin() + 1, // Skip first section (test case) | |
13247 | itEnd = m_sectionStack.end(); | |
13248 | for (; it != itEnd; ++it) | |
13249 | printHeaderString(it->name, 2); | |
13250 | } | |
13251 | ||
13252 | SourceLineInfo lineInfo = m_sectionStack.back().lineInfo; | |
13253 | ||
13254 | if (!lineInfo.empty()) { | |
13255 | stream << getLineOfChars<'-'>() << '\n'; | |
13256 | Colour colourGuard(Colour::FileName); | |
13257 | stream << lineInfo << '\n'; | |
13258 | } | |
13259 | stream << getLineOfChars<'.'>() << '\n' << std::endl; | |
13260 | } | |
13261 | ||
13262 | void ConsoleReporter::printClosedHeader(std::string const& _name) { | |
13263 | printOpenHeader(_name); | |
13264 | stream << getLineOfChars<'.'>() << '\n'; | |
13265 | } | |
13266 | void ConsoleReporter::printOpenHeader(std::string const& _name) { | |
13267 | stream << getLineOfChars<'-'>() << '\n'; | |
13268 | { | |
13269 | Colour colourGuard(Colour::Headers); | |
13270 | printHeaderString(_name); | |
13271 | } | |
13272 | } | |
13273 | ||
13274 | // if string has a : in first line will set indent to follow it on | |
13275 | // subsequent lines | |
13276 | void ConsoleReporter::printHeaderString(std::string const& _string, std::size_t indent) { | |
13277 | std::size_t i = _string.find(": "); | |
13278 | if (i != std::string::npos) | |
13279 | i += 2; | |
13280 | else | |
13281 | i = 0; | |
13282 | stream << Column(_string).indent(indent + i).initialIndent(indent) << '\n'; | |
13283 | } | |
13284 | ||
13285 | struct SummaryColumn { | |
13286 | ||
13287 | SummaryColumn( std::string _label, Colour::Code _colour ) | |
13288 | : label( std::move( _label ) ), | |
13289 | colour( _colour ) {} | |
13290 | SummaryColumn addRow( std::size_t count ) { | |
13291 | ReusableStringStream rss; | |
13292 | rss << count; | |
13293 | std::string row = rss.str(); | |
13294 | for (auto& oldRow : rows) { | |
13295 | while (oldRow.size() < row.size()) | |
13296 | oldRow = ' ' + oldRow; | |
13297 | while (oldRow.size() > row.size()) | |
13298 | row = ' ' + row; | |
13299 | } | |
13300 | rows.push_back(row); | |
13301 | return *this; | |
13302 | } | |
13303 | ||
13304 | std::string label; | |
13305 | Colour::Code colour; | |
13306 | std::vector<std::string> rows; | |
13307 | ||
13308 | }; | |
13309 | ||
13310 | void ConsoleReporter::printTotals( Totals const& totals ) { | |
13311 | if (totals.testCases.total() == 0) { | |
13312 | stream << Colour(Colour::Warning) << "No tests ran\n"; | |
13313 | } else if (totals.assertions.total() > 0 && totals.testCases.allPassed()) { | |
13314 | stream << Colour(Colour::ResultSuccess) << "All tests passed"; | |
13315 | stream << " (" | |
13316 | << pluralise(totals.assertions.passed, "assertion") << " in " | |
13317 | << pluralise(totals.testCases.passed, "test case") << ')' | |
13318 | << '\n'; | |
13319 | } else { | |
13320 | ||
13321 | std::vector<SummaryColumn> columns; | |
13322 | columns.push_back(SummaryColumn("", Colour::None) | |
13323 | .addRow(totals.testCases.total()) | |
13324 | .addRow(totals.assertions.total())); | |
13325 | columns.push_back(SummaryColumn("passed", Colour::Success) | |
13326 | .addRow(totals.testCases.passed) | |
13327 | .addRow(totals.assertions.passed)); | |
13328 | columns.push_back(SummaryColumn("failed", Colour::ResultError) | |
13329 | .addRow(totals.testCases.failed) | |
13330 | .addRow(totals.assertions.failed)); | |
13331 | columns.push_back(SummaryColumn("failed as expected", Colour::ResultExpectedFailure) | |
13332 | .addRow(totals.testCases.failedButOk) | |
13333 | .addRow(totals.assertions.failedButOk)); | |
13334 | ||
13335 | printSummaryRow("test cases", columns, 0); | |
13336 | printSummaryRow("assertions", columns, 1); | |
13337 | } | |
13338 | } | |
13339 | void ConsoleReporter::printSummaryRow(std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row) { | |
13340 | for (auto col : cols) { | |
13341 | std::string value = col.rows[row]; | |
13342 | if (col.label.empty()) { | |
13343 | stream << label << ": "; | |
13344 | if (value != "0") | |
13345 | stream << value; | |
13346 | else | |
13347 | stream << Colour(Colour::Warning) << "- none -"; | |
13348 | } else if (value != "0") { | |
13349 | stream << Colour(Colour::LightGrey) << " | "; | |
13350 | stream << Colour(col.colour) | |
13351 | << value << ' ' << col.label; | |
13352 | } | |
13353 | } | |
13354 | stream << '\n'; | |
13355 | } | |
13356 | ||
13357 | void ConsoleReporter::printTotalsDivider(Totals const& totals) { | |
13358 | if (totals.testCases.total() > 0) { | |
13359 | std::size_t failedRatio = makeRatio(totals.testCases.failed, totals.testCases.total()); | |
13360 | std::size_t failedButOkRatio = makeRatio(totals.testCases.failedButOk, totals.testCases.total()); | |
13361 | std::size_t passedRatio = makeRatio(totals.testCases.passed, totals.testCases.total()); | |
13362 | while (failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH - 1) | |
13363 | findMax(failedRatio, failedButOkRatio, passedRatio)++; | |
13364 | while (failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH - 1) | |
13365 | findMax(failedRatio, failedButOkRatio, passedRatio)--; | |
13366 | ||
13367 | stream << Colour(Colour::Error) << std::string(failedRatio, '='); | |
13368 | stream << Colour(Colour::ResultExpectedFailure) << std::string(failedButOkRatio, '='); | |
13369 | if (totals.testCases.allPassed()) | |
13370 | stream << Colour(Colour::ResultSuccess) << std::string(passedRatio, '='); | |
13371 | else | |
13372 | stream << Colour(Colour::Success) << std::string(passedRatio, '='); | |
13373 | } else { | |
13374 | stream << Colour(Colour::Warning) << std::string(CATCH_CONFIG_CONSOLE_WIDTH - 1, '='); | |
13375 | } | |
13376 | stream << '\n'; | |
13377 | } | |
13378 | void ConsoleReporter::printSummaryDivider() { | |
13379 | stream << getLineOfChars<'-'>() << '\n'; | |
13380 | } | |
13381 | ||
13382 | CATCH_REGISTER_REPORTER("console", ConsoleReporter) | |
13383 | ||
13384 | } // end namespace Catch | |
13385 | ||
13386 | #if defined(_MSC_VER) | |
13387 | #pragma warning(pop) | |
13388 | #endif | |
13389 | // end catch_reporter_console.cpp | |
13390 | // start catch_reporter_junit.cpp | |
13391 | ||
13392 | #include <cassert> | |
13393 | #include <sstream> | |
13394 | #include <ctime> | |
13395 | #include <algorithm> | |
13396 | ||
13397 | namespace Catch { | |
13398 | ||
13399 | namespace { | |
13400 | std::string getCurrentTimestamp() { | |
13401 | // Beware, this is not reentrant because of backward compatibility issues | |
13402 | // Also, UTC only, again because of backward compatibility (%z is C++11) | |
13403 | time_t rawtime; | |
13404 | std::time(&rawtime); | |
13405 | auto const timeStampSize = sizeof("2017-01-16T17:06:45Z"); | |
13406 | ||
13407 | #ifdef _MSC_VER | |
13408 | std::tm timeInfo = {}; | |
13409 | gmtime_s(&timeInfo, &rawtime); | |
13410 | #else | |
13411 | std::tm* timeInfo; | |
13412 | timeInfo = std::gmtime(&rawtime); | |
13413 | #endif | |
13414 | ||
13415 | char timeStamp[timeStampSize]; | |
13416 | const char * const fmt = "%Y-%m-%dT%H:%M:%SZ"; | |
13417 | ||
13418 | #ifdef _MSC_VER | |
13419 | std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); | |
13420 | #else | |
13421 | std::strftime(timeStamp, timeStampSize, fmt, timeInfo); | |
13422 | #endif | |
13423 | return std::string(timeStamp); | |
13424 | } | |
13425 | ||
13426 | std::string fileNameTag(const std::vector<std::string> &tags) { | |
13427 | auto it = std::find_if(begin(tags), | |
13428 | end(tags), | |
13429 | [] (std::string const& tag) {return tag.front() == '#'; }); | |
13430 | if (it != tags.end()) | |
13431 | return it->substr(1); | |
13432 | return std::string(); | |
13433 | } | |
13434 | } // anonymous namespace | |
13435 | ||
13436 | JunitReporter::JunitReporter( ReporterConfig const& _config ) | |
13437 | : CumulativeReporterBase( _config ), | |
13438 | xml( _config.stream() ) | |
13439 | { | |
13440 | m_reporterPrefs.shouldRedirectStdOut = true; | |
13441 | m_reporterPrefs.shouldReportAllAssertions = true; | |
13442 | } | |
13443 | ||
13444 | JunitReporter::~JunitReporter() {} | |
13445 | ||
13446 | std::string JunitReporter::getDescription() { | |
13447 | return "Reports test results in an XML format that looks like Ant's junitreport target"; | |
13448 | } | |
13449 | ||
13450 | void JunitReporter::noMatchingTestCases( std::string const& /*spec*/ ) {} | |
13451 | ||
13452 | void JunitReporter::testRunStarting( TestRunInfo const& runInfo ) { | |
13453 | CumulativeReporterBase::testRunStarting( runInfo ); | |
13454 | xml.startElement( "testsuites" ); | |
13455 | } | |
13456 | ||
13457 | void JunitReporter::testGroupStarting( GroupInfo const& groupInfo ) { | |
13458 | suiteTimer.start(); | |
13459 | stdOutForSuite.clear(); | |
13460 | stdErrForSuite.clear(); | |
13461 | unexpectedExceptions = 0; | |
13462 | CumulativeReporterBase::testGroupStarting( groupInfo ); | |
13463 | } | |
13464 | ||
13465 | void JunitReporter::testCaseStarting( TestCaseInfo const& testCaseInfo ) { | |
13466 | m_okToFail = testCaseInfo.okToFail(); | |
13467 | } | |
13468 | ||
13469 | bool JunitReporter::assertionEnded( AssertionStats const& assertionStats ) { | |
13470 | if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail ) | |
13471 | unexpectedExceptions++; | |
13472 | return CumulativeReporterBase::assertionEnded( assertionStats ); | |
13473 | } | |
13474 | ||
13475 | void JunitReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { | |
13476 | stdOutForSuite += testCaseStats.stdOut; | |
13477 | stdErrForSuite += testCaseStats.stdErr; | |
13478 | CumulativeReporterBase::testCaseEnded( testCaseStats ); | |
13479 | } | |
13480 | ||
13481 | void JunitReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { | |
13482 | double suiteTime = suiteTimer.getElapsedSeconds(); | |
13483 | CumulativeReporterBase::testGroupEnded( testGroupStats ); | |
13484 | writeGroup( *m_testGroups.back(), suiteTime ); | |
13485 | } | |
13486 | ||
13487 | void JunitReporter::testRunEndedCumulative() { | |
13488 | xml.endElement(); | |
13489 | } | |
13490 | ||
13491 | void JunitReporter::writeGroup( TestGroupNode const& groupNode, double suiteTime ) { | |
13492 | XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); | |
13493 | TestGroupStats const& stats = groupNode.value; | |
13494 | xml.writeAttribute( "name", stats.groupInfo.name ); | |
13495 | xml.writeAttribute( "errors", unexpectedExceptions ); | |
13496 | xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions ); | |
13497 | xml.writeAttribute( "tests", stats.totals.assertions.total() ); | |
13498 | xml.writeAttribute( "hostname", "tbd" ); // !TBD | |
13499 | if( m_config->showDurations() == ShowDurations::Never ) | |
13500 | xml.writeAttribute( "time", "" ); | |
13501 | else | |
13502 | xml.writeAttribute( "time", suiteTime ); | |
13503 | xml.writeAttribute( "timestamp", getCurrentTimestamp() ); | |
13504 | ||
13505 | // Write test cases | |
13506 | for( auto const& child : groupNode.children ) | |
13507 | writeTestCase( *child ); | |
13508 | ||
13509 | xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite ), false ); | |
13510 | xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite ), false ); | |
13511 | } | |
13512 | ||
13513 | void JunitReporter::writeTestCase( TestCaseNode const& testCaseNode ) { | |
13514 | TestCaseStats const& stats = testCaseNode.value; | |
13515 | ||
13516 | // All test cases have exactly one section - which represents the | |
13517 | // test case itself. That section may have 0-n nested sections | |
13518 | assert( testCaseNode.children.size() == 1 ); | |
13519 | SectionNode const& rootSection = *testCaseNode.children.front(); | |
13520 | ||
13521 | std::string className = stats.testInfo.className; | |
13522 | ||
13523 | if( className.empty() ) { | |
13524 | className = fileNameTag(stats.testInfo.tags); | |
13525 | if ( className.empty() ) | |
13526 | className = "global"; | |
13527 | } | |
13528 | ||
13529 | if ( !m_config->name().empty() ) | |
13530 | className = m_config->name() + "." + className; | |
13531 | ||
13532 | writeSection( className, "", rootSection ); | |
13533 | } | |
13534 | ||
13535 | void JunitReporter::writeSection( std::string const& className, | |
13536 | std::string const& rootName, | |
13537 | SectionNode const& sectionNode ) { | |
13538 | std::string name = trim( sectionNode.stats.sectionInfo.name ); | |
13539 | if( !rootName.empty() ) | |
13540 | name = rootName + '/' + name; | |
13541 | ||
13542 | if( !sectionNode.assertions.empty() || | |
13543 | !sectionNode.stdOut.empty() || | |
13544 | !sectionNode.stdErr.empty() ) { | |
13545 | XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); | |
13546 | if( className.empty() ) { | |
13547 | xml.writeAttribute( "classname", name ); | |
13548 | xml.writeAttribute( "name", "root" ); | |
13549 | } | |
13550 | else { | |
13551 | xml.writeAttribute( "classname", className ); | |
13552 | xml.writeAttribute( "name", name ); | |
13553 | } | |
13554 | xml.writeAttribute( "time", ::Catch::Detail::stringify( sectionNode.stats.durationInSeconds ) ); | |
13555 | ||
13556 | writeAssertions( sectionNode ); | |
13557 | ||
13558 | if( !sectionNode.stdOut.empty() ) | |
13559 | xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false ); | |
13560 | if( !sectionNode.stdErr.empty() ) | |
13561 | xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false ); | |
13562 | } | |
13563 | for( auto const& childNode : sectionNode.childSections ) | |
13564 | if( className.empty() ) | |
13565 | writeSection( name, "", *childNode ); | |
13566 | else | |
13567 | writeSection( className, name, *childNode ); | |
13568 | } | |
13569 | ||
13570 | void JunitReporter::writeAssertions( SectionNode const& sectionNode ) { | |
13571 | for( auto const& assertion : sectionNode.assertions ) | |
13572 | writeAssertion( assertion ); | |
13573 | } | |
13574 | ||
13575 | void JunitReporter::writeAssertion( AssertionStats const& stats ) { | |
13576 | AssertionResult const& result = stats.assertionResult; | |
13577 | if( !result.isOk() ) { | |
13578 | std::string elementName; | |
13579 | switch( result.getResultType() ) { | |
13580 | case ResultWas::ThrewException: | |
13581 | case ResultWas::FatalErrorCondition: | |
13582 | elementName = "error"; | |
13583 | break; | |
13584 | case ResultWas::ExplicitFailure: | |
13585 | elementName = "failure"; | |
13586 | break; | |
13587 | case ResultWas::ExpressionFailed: | |
13588 | elementName = "failure"; | |
13589 | break; | |
13590 | case ResultWas::DidntThrowException: | |
13591 | elementName = "failure"; | |
13592 | break; | |
13593 | ||
13594 | // We should never see these here: | |
13595 | case ResultWas::Info: | |
13596 | case ResultWas::Warning: | |
13597 | case ResultWas::Ok: | |
13598 | case ResultWas::Unknown: | |
13599 | case ResultWas::FailureBit: | |
13600 | case ResultWas::Exception: | |
13601 | elementName = "internalError"; | |
13602 | break; | |
13603 | } | |
13604 | ||
13605 | XmlWriter::ScopedElement e = xml.scopedElement( elementName ); | |
13606 | ||
13607 | xml.writeAttribute( "message", result.getExpandedExpression() ); | |
13608 | xml.writeAttribute( "type", result.getTestMacroName() ); | |
13609 | ||
13610 | ReusableStringStream rss; | |
13611 | if( !result.getMessage().empty() ) | |
13612 | rss << result.getMessage() << '\n'; | |
13613 | for( auto const& msg : stats.infoMessages ) | |
13614 | if( msg.type == ResultWas::Info ) | |
13615 | rss << msg.message << '\n'; | |
13616 | ||
13617 | rss << "at " << result.getSourceInfo(); | |
13618 | xml.writeText( rss.str(), false ); | |
13619 | } | |
13620 | } | |
13621 | ||
13622 | CATCH_REGISTER_REPORTER( "junit", JunitReporter ) | |
13623 | ||
13624 | } // end namespace Catch | |
13625 | // end catch_reporter_junit.cpp | |
13626 | // start catch_reporter_listening.cpp | |
13627 | ||
13628 | #include <cassert> | |
13629 | ||
13630 | namespace Catch { | |
13631 | ||
13632 | ListeningReporter::ListeningReporter() { | |
13633 | // We will assume that listeners will always want all assertions | |
13634 | m_preferences.shouldReportAllAssertions = true; | |
13635 | } | |
13636 | ||
13637 | void ListeningReporter::addListener( IStreamingReporterPtr&& listener ) { | |
13638 | m_listeners.push_back( std::move( listener ) ); | |
13639 | } | |
13640 | ||
13641 | void ListeningReporter::addReporter(IStreamingReporterPtr&& reporter) { | |
13642 | assert(!m_reporter && "Listening reporter can wrap only 1 real reporter"); | |
13643 | m_reporter = std::move( reporter ); | |
13644 | m_preferences.shouldRedirectStdOut = m_reporter->getPreferences().shouldRedirectStdOut; | |
13645 | } | |
13646 | ||
13647 | ReporterPreferences ListeningReporter::getPreferences() const { | |
13648 | return m_preferences; | |
13649 | } | |
13650 | ||
13651 | std::set<Verbosity> ListeningReporter::getSupportedVerbosities() { | |
13652 | return std::set<Verbosity>{ }; | |
13653 | } | |
13654 | ||
13655 | void ListeningReporter::noMatchingTestCases( std::string const& spec ) { | |
13656 | for ( auto const& listener : m_listeners ) { | |
13657 | listener->noMatchingTestCases( spec ); | |
13658 | } | |
13659 | m_reporter->noMatchingTestCases( spec ); | |
13660 | } | |
13661 | ||
13662 | void ListeningReporter::benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) { | |
13663 | for ( auto const& listener : m_listeners ) { | |
13664 | listener->benchmarkStarting( benchmarkInfo ); | |
13665 | } | |
13666 | m_reporter->benchmarkStarting( benchmarkInfo ); | |
13667 | } | |
13668 | void ListeningReporter::benchmarkEnded( BenchmarkStats const& benchmarkStats ) { | |
13669 | for ( auto const& listener : m_listeners ) { | |
13670 | listener->benchmarkEnded( benchmarkStats ); | |
13671 | } | |
13672 | m_reporter->benchmarkEnded( benchmarkStats ); | |
13673 | } | |
13674 | ||
13675 | void ListeningReporter::testRunStarting( TestRunInfo const& testRunInfo ) { | |
13676 | for ( auto const& listener : m_listeners ) { | |
13677 | listener->testRunStarting( testRunInfo ); | |
13678 | } | |
13679 | m_reporter->testRunStarting( testRunInfo ); | |
13680 | } | |
13681 | ||
13682 | void ListeningReporter::testGroupStarting( GroupInfo const& groupInfo ) { | |
13683 | for ( auto const& listener : m_listeners ) { | |
13684 | listener->testGroupStarting( groupInfo ); | |
13685 | } | |
13686 | m_reporter->testGroupStarting( groupInfo ); | |
13687 | } | |
13688 | ||
13689 | void ListeningReporter::testCaseStarting( TestCaseInfo const& testInfo ) { | |
13690 | for ( auto const& listener : m_listeners ) { | |
13691 | listener->testCaseStarting( testInfo ); | |
13692 | } | |
13693 | m_reporter->testCaseStarting( testInfo ); | |
13694 | } | |
13695 | ||
13696 | void ListeningReporter::sectionStarting( SectionInfo const& sectionInfo ) { | |
13697 | for ( auto const& listener : m_listeners ) { | |
13698 | listener->sectionStarting( sectionInfo ); | |
13699 | } | |
13700 | m_reporter->sectionStarting( sectionInfo ); | |
13701 | } | |
13702 | ||
13703 | void ListeningReporter::assertionStarting( AssertionInfo const& assertionInfo ) { | |
13704 | for ( auto const& listener : m_listeners ) { | |
13705 | listener->assertionStarting( assertionInfo ); | |
13706 | } | |
13707 | m_reporter->assertionStarting( assertionInfo ); | |
13708 | } | |
13709 | ||
13710 | // The return value indicates if the messages buffer should be cleared: | |
13711 | bool ListeningReporter::assertionEnded( AssertionStats const& assertionStats ) { | |
13712 | for( auto const& listener : m_listeners ) { | |
13713 | static_cast<void>( listener->assertionEnded( assertionStats ) ); | |
13714 | } | |
13715 | return m_reporter->assertionEnded( assertionStats ); | |
13716 | } | |
13717 | ||
13718 | void ListeningReporter::sectionEnded( SectionStats const& sectionStats ) { | |
13719 | for ( auto const& listener : m_listeners ) { | |
13720 | listener->sectionEnded( sectionStats ); | |
13721 | } | |
13722 | m_reporter->sectionEnded( sectionStats ); | |
13723 | } | |
13724 | ||
13725 | void ListeningReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { | |
13726 | for ( auto const& listener : m_listeners ) { | |
13727 | listener->testCaseEnded( testCaseStats ); | |
13728 | } | |
13729 | m_reporter->testCaseEnded( testCaseStats ); | |
13730 | } | |
13731 | ||
13732 | void ListeningReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { | |
13733 | for ( auto const& listener : m_listeners ) { | |
13734 | listener->testGroupEnded( testGroupStats ); | |
13735 | } | |
13736 | m_reporter->testGroupEnded( testGroupStats ); | |
13737 | } | |
13738 | ||
13739 | void ListeningReporter::testRunEnded( TestRunStats const& testRunStats ) { | |
13740 | for ( auto const& listener : m_listeners ) { | |
13741 | listener->testRunEnded( testRunStats ); | |
13742 | } | |
13743 | m_reporter->testRunEnded( testRunStats ); | |
13744 | } | |
13745 | ||
13746 | void ListeningReporter::skipTest( TestCaseInfo const& testInfo ) { | |
13747 | for ( auto const& listener : m_listeners ) { | |
13748 | listener->skipTest( testInfo ); | |
13749 | } | |
13750 | m_reporter->skipTest( testInfo ); | |
13751 | } | |
13752 | ||
13753 | bool ListeningReporter::isMulti() const { | |
13754 | return true; | |
13755 | } | |
13756 | ||
13757 | } // end namespace Catch | |
13758 | // end catch_reporter_listening.cpp | |
13759 | // start catch_reporter_xml.cpp | |
13760 | ||
13761 | #if defined(_MSC_VER) | |
13762 | #pragma warning(push) | |
13763 | #pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch | |
13764 | // Note that 4062 (not all labels are handled | |
13765 | // and default is missing) is enabled | |
13766 | #endif | |
13767 | ||
13768 | namespace Catch { | |
13769 | XmlReporter::XmlReporter( ReporterConfig const& _config ) | |
13770 | : StreamingReporterBase( _config ), | |
13771 | m_xml(_config.stream()) | |
13772 | { | |
13773 | m_reporterPrefs.shouldRedirectStdOut = true; | |
13774 | m_reporterPrefs.shouldReportAllAssertions = true; | |
13775 | } | |
13776 | ||
13777 | XmlReporter::~XmlReporter() = default; | |
13778 | ||
13779 | std::string XmlReporter::getDescription() { | |
13780 | return "Reports test results as an XML document"; | |
13781 | } | |
13782 | ||
13783 | std::string XmlReporter::getStylesheetRef() const { | |
13784 | return std::string(); | |
13785 | } | |
13786 | ||
13787 | void XmlReporter::writeSourceInfo( SourceLineInfo const& sourceInfo ) { | |
13788 | m_xml | |
13789 | .writeAttribute( "filename", sourceInfo.file ) | |
13790 | .writeAttribute( "line", sourceInfo.line ); | |
13791 | } | |
13792 | ||
13793 | void XmlReporter::noMatchingTestCases( std::string const& s ) { | |
13794 | StreamingReporterBase::noMatchingTestCases( s ); | |
13795 | } | |
13796 | ||
13797 | void XmlReporter::testRunStarting( TestRunInfo const& testInfo ) { | |
13798 | StreamingReporterBase::testRunStarting( testInfo ); | |
13799 | std::string stylesheetRef = getStylesheetRef(); | |
13800 | if( !stylesheetRef.empty() ) | |
13801 | m_xml.writeStylesheetRef( stylesheetRef ); | |
13802 | m_xml.startElement( "Catch" ); | |
13803 | if( !m_config->name().empty() ) | |
13804 | m_xml.writeAttribute( "name", m_config->name() ); | |
13805 | if( m_config->rngSeed() != 0 ) | |
13806 | m_xml.scopedElement( "Randomness" ) | |
13807 | .writeAttribute( "seed", m_config->rngSeed() ); | |
13808 | } | |
13809 | ||
13810 | void XmlReporter::testGroupStarting( GroupInfo const& groupInfo ) { | |
13811 | StreamingReporterBase::testGroupStarting( groupInfo ); | |
13812 | m_xml.startElement( "Group" ) | |
13813 | .writeAttribute( "name", groupInfo.name ); | |
13814 | } | |
13815 | ||
13816 | void XmlReporter::testCaseStarting( TestCaseInfo const& testInfo ) { | |
13817 | StreamingReporterBase::testCaseStarting(testInfo); | |
13818 | m_xml.startElement( "TestCase" ) | |
13819 | .writeAttribute( "name", trim( testInfo.name ) ) | |
13820 | .writeAttribute( "description", testInfo.description ) | |
13821 | .writeAttribute( "tags", testInfo.tagsAsString() ); | |
13822 | ||
13823 | writeSourceInfo( testInfo.lineInfo ); | |
13824 | ||
13825 | if ( m_config->showDurations() == ShowDurations::Always ) | |
13826 | m_testCaseTimer.start(); | |
13827 | m_xml.ensureTagClosed(); | |
13828 | } | |
13829 | ||
13830 | void XmlReporter::sectionStarting( SectionInfo const& sectionInfo ) { | |
13831 | StreamingReporterBase::sectionStarting( sectionInfo ); | |
13832 | if( m_sectionDepth++ > 0 ) { | |
13833 | m_xml.startElement( "Section" ) | |
13834 | .writeAttribute( "name", trim( sectionInfo.name ) ); | |
13835 | writeSourceInfo( sectionInfo.lineInfo ); | |
13836 | m_xml.ensureTagClosed(); | |
13837 | } | |
13838 | } | |
13839 | ||
13840 | void XmlReporter::assertionStarting( AssertionInfo const& ) { } | |
13841 | ||
13842 | bool XmlReporter::assertionEnded( AssertionStats const& assertionStats ) { | |
13843 | ||
13844 | AssertionResult const& result = assertionStats.assertionResult; | |
13845 | ||
13846 | bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); | |
13847 | ||
13848 | if( includeResults || result.getResultType() == ResultWas::Warning ) { | |
13849 | // Print any info messages in <Info> tags. | |
13850 | for( auto const& msg : assertionStats.infoMessages ) { | |
13851 | if( msg.type == ResultWas::Info && includeResults ) { | |
13852 | m_xml.scopedElement( "Info" ) | |
13853 | .writeText( msg.message ); | |
13854 | } else if ( msg.type == ResultWas::Warning ) { | |
13855 | m_xml.scopedElement( "Warning" ) | |
13856 | .writeText( msg.message ); | |
13857 | } | |
13858 | } | |
13859 | } | |
13860 | ||
13861 | // Drop out if result was successful but we're not printing them. | |
13862 | if( !includeResults && result.getResultType() != ResultWas::Warning ) | |
13863 | return true; | |
13864 | ||
13865 | // Print the expression if there is one. | |
13866 | if( result.hasExpression() ) { | |
13867 | m_xml.startElement( "Expression" ) | |
13868 | .writeAttribute( "success", result.succeeded() ) | |
13869 | .writeAttribute( "type", result.getTestMacroName() ); | |
13870 | ||
13871 | writeSourceInfo( result.getSourceInfo() ); | |
13872 | ||
13873 | m_xml.scopedElement( "Original" ) | |
13874 | .writeText( result.getExpression() ); | |
13875 | m_xml.scopedElement( "Expanded" ) | |
13876 | .writeText( result.getExpandedExpression() ); | |
13877 | } | |
13878 | ||
13879 | // And... Print a result applicable to each result type. | |
13880 | switch( result.getResultType() ) { | |
13881 | case ResultWas::ThrewException: | |
13882 | m_xml.startElement( "Exception" ); | |
13883 | writeSourceInfo( result.getSourceInfo() ); | |
13884 | m_xml.writeText( result.getMessage() ); | |
13885 | m_xml.endElement(); | |
13886 | break; | |
13887 | case ResultWas::FatalErrorCondition: | |
13888 | m_xml.startElement( "FatalErrorCondition" ); | |
13889 | writeSourceInfo( result.getSourceInfo() ); | |
13890 | m_xml.writeText( result.getMessage() ); | |
13891 | m_xml.endElement(); | |
13892 | break; | |
13893 | case ResultWas::Info: | |
13894 | m_xml.scopedElement( "Info" ) | |
13895 | .writeText( result.getMessage() ); | |
13896 | break; | |
13897 | case ResultWas::Warning: | |
13898 | // Warning will already have been written | |
13899 | break; | |
13900 | case ResultWas::ExplicitFailure: | |
13901 | m_xml.startElement( "Failure" ); | |
13902 | writeSourceInfo( result.getSourceInfo() ); | |
13903 | m_xml.writeText( result.getMessage() ); | |
13904 | m_xml.endElement(); | |
13905 | break; | |
13906 | default: | |
13907 | break; | |
13908 | } | |
13909 | ||
13910 | if( result.hasExpression() ) | |
13911 | m_xml.endElement(); | |
13912 | ||
13913 | return true; | |
13914 | } | |
13915 | ||
13916 | void XmlReporter::sectionEnded( SectionStats const& sectionStats ) { | |
13917 | StreamingReporterBase::sectionEnded( sectionStats ); | |
13918 | if( --m_sectionDepth > 0 ) { | |
13919 | XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); | |
13920 | e.writeAttribute( "successes", sectionStats.assertions.passed ); | |
13921 | e.writeAttribute( "failures", sectionStats.assertions.failed ); | |
13922 | e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); | |
13923 | ||
13924 | if ( m_config->showDurations() == ShowDurations::Always ) | |
13925 | e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); | |
13926 | ||
13927 | m_xml.endElement(); | |
13928 | } | |
13929 | } | |
13930 | ||
13931 | void XmlReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { | |
13932 | StreamingReporterBase::testCaseEnded( testCaseStats ); | |
13933 | XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); | |
13934 | e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); | |
13935 | ||
13936 | if ( m_config->showDurations() == ShowDurations::Always ) | |
13937 | e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); | |
13938 | ||
13939 | if( !testCaseStats.stdOut.empty() ) | |
13940 | m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), false ); | |
13941 | if( !testCaseStats.stdErr.empty() ) | |
13942 | m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), false ); | |
13943 | ||
13944 | m_xml.endElement(); | |
13945 | } | |
13946 | ||
13947 | void XmlReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { | |
13948 | StreamingReporterBase::testGroupEnded( testGroupStats ); | |
13949 | // TODO: Check testGroupStats.aborting and act accordingly. | |
13950 | m_xml.scopedElement( "OverallResults" ) | |
13951 | .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) | |
13952 | .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) | |
13953 | .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); | |
13954 | m_xml.endElement(); | |
13955 | } | |
13956 | ||
13957 | void XmlReporter::testRunEnded( TestRunStats const& testRunStats ) { | |
13958 | StreamingReporterBase::testRunEnded( testRunStats ); | |
13959 | m_xml.scopedElement( "OverallResults" ) | |
13960 | .writeAttribute( "successes", testRunStats.totals.assertions.passed ) | |
13961 | .writeAttribute( "failures", testRunStats.totals.assertions.failed ) | |
13962 | .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); | |
13963 | m_xml.endElement(); | |
13964 | } | |
13965 | ||
13966 | CATCH_REGISTER_REPORTER( "xml", XmlReporter ) | |
13967 | ||
13968 | } // end namespace Catch | |
13969 | ||
13970 | #if defined(_MSC_VER) | |
13971 | #pragma warning(pop) | |
13972 | #endif | |
13973 | // end catch_reporter_xml.cpp | |
13974 | ||
13975 | namespace Catch { | |
13976 | LeakDetector leakDetector; | |
13977 | } | |
13978 | ||
13979 | #ifdef __clang__ | |
13980 | #pragma clang diagnostic pop | |
13981 | #endif | |
13982 | ||
13983 | // end catch_impl.hpp | |
13984 | #endif | |
13985 | ||
13986 | #ifdef CATCH_CONFIG_MAIN | |
13987 | // start catch_default_main.hpp | |
13988 | ||
13989 | #ifndef __OBJC__ | |
13990 | ||
13991 | #if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN) | |
13992 | // Standard C/C++ Win32 Unicode wmain entry point | |
13993 | extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) { | |
13994 | #else | |
13995 | // Standard C/C++ main entry point | |
13996 | int main (int argc, char * argv[]) { | |
13997 | #endif | |
13998 | ||
13999 | return Catch::Session().run( argc, argv ); | |
14000 | } | |
14001 | ||
14002 | #else // __OBJC__ | |
14003 | ||
14004 | // Objective-C entry point | |
14005 | int main (int argc, char * const argv[]) { | |
14006 | #if !CATCH_ARC_ENABLED | |
14007 | NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; | |
14008 | #endif | |
14009 | ||
14010 | Catch::registerTestMethods(); | |
14011 | int result = Catch::Session().run( argc, (char**)argv ); | |
14012 | ||
14013 | #if !CATCH_ARC_ENABLED | |
14014 | [pool drain]; | |
14015 | #endif | |
14016 | ||
14017 | return result; | |
14018 | } | |
14019 | ||
14020 | #endif // __OBJC__ | |
14021 | ||
14022 | // end catch_default_main.hpp | |
14023 | #endif | |
14024 | ||
14025 | #if !defined(CATCH_CONFIG_IMPL_ONLY) | |
14026 | ||
14027 | #ifdef CLARA_CONFIG_MAIN_NOT_DEFINED | |
14028 | # undef CLARA_CONFIG_MAIN | |
14029 | #endif | |
14030 | ||
14031 | #if !defined(CATCH_CONFIG_DISABLE) | |
14032 | ////// | |
14033 | // If this config identifier is defined then all CATCH macros are prefixed with CATCH_ | |
14034 | #ifdef CATCH_CONFIG_PREFIX_ALL | |
14035 | ||
14036 | #define CATCH_REQUIRE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ ) | |
14037 | #define CATCH_REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) | |
14038 | ||
14039 | #define CATCH_REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", __VA_ARGS__ ) | |
14040 | #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) | |
14041 | #define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) | |
14042 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) | |
14043 | #define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr ) | |
14044 | #endif// CATCH_CONFIG_DISABLE_MATCHERS | |
14045 | #define CATCH_REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ ) | |
14046 | ||
14047 | #define CATCH_CHECK( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) | |
14048 | #define CATCH_CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) | |
14049 | #define CATCH_CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CATCH_CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) | |
14050 | #define CATCH_CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) | |
14051 | #define CATCH_CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ ) | |
14052 | ||
14053 | #define CATCH_CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", __VA_ARGS__ ) | |
14054 | #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) | |
14055 | #define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) | |
14056 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) | |
14057 | #define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) | |
14058 | #endif // CATCH_CONFIG_DISABLE_MATCHERS | |
14059 | #define CATCH_CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) | |
14060 | ||
14061 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) | |
14062 | #define CATCH_CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg ) | |
14063 | ||
14064 | #define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) | |
14065 | #endif // CATCH_CONFIG_DISABLE_MATCHERS | |
14066 | ||
14067 | #define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg ) | |
14068 | #define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) | |
14069 | #define CATCH_CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CATCH_CAPTURE",__VA_ARGS__ ) | |
14070 | ||
14071 | #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) | |
14072 | #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) | |
14073 | #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) | |
14074 | #define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) | |
14075 | #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) | |
14076 | #define CATCH_DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ ) | |
14077 | #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) | |
14078 | #define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) | |
14079 | #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) | |
14080 | ||
14081 | #define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE() | |
14082 | ||
14083 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR | |
14084 | #define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) | |
14085 | #define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) | |
14086 | #else | |
14087 | #define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) ) | |
14088 | #define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) ) | |
14089 | #endif | |
14090 | ||
14091 | #if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE) | |
14092 | #define CATCH_STATIC_REQUIRE( ... ) static_assert( __VA_ARGS__ , #__VA_ARGS__ ); CATCH_SUCCEED( #__VA_ARGS__ ) | |
14093 | #define CATCH_STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); CATCH_SUCCEED( #__VA_ARGS__ ) | |
14094 | #else | |
14095 | #define CATCH_STATIC_REQUIRE( ... ) CATCH_REQUIRE( __VA_ARGS__ ) | |
14096 | #define CATCH_STATIC_REQUIRE_FALSE( ... ) CATCH_REQUIRE_FALSE( __VA_ARGS__ ) | |
14097 | #endif | |
14098 | ||
14099 | // "BDD-style" convenience wrappers | |
14100 | #define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ ) | |
14101 | #define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) | |
14102 | #define CATCH_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc ) | |
14103 | #define CATCH_AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc ) | |
14104 | #define CATCH_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc ) | |
14105 | #define CATCH_AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc ) | |
14106 | #define CATCH_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc ) | |
14107 | #define CATCH_AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc ) | |
14108 | ||
14109 | // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required | |
14110 | #else | |
14111 | ||
14112 | #define REQUIRE( ... ) INTERNAL_CATCH_TEST( "REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ ) | |
14113 | #define REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) | |
14114 | ||
14115 | #define REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ ) | |
14116 | #define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) | |
14117 | #define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) | |
14118 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) | |
14119 | #define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr ) | |
14120 | #endif // CATCH_CONFIG_DISABLE_MATCHERS | |
14121 | #define REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ ) | |
14122 | ||
14123 | #define CHECK( ... ) INTERNAL_CATCH_TEST( "CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) | |
14124 | #define CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) | |
14125 | #define CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) | |
14126 | #define CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) | |
14127 | #define CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ ) | |
14128 | ||
14129 | #define CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) | |
14130 | #define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) | |
14131 | #define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) | |
14132 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) | |
14133 | #define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) | |
14134 | #endif // CATCH_CONFIG_DISABLE_MATCHERS | |
14135 | #define CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) | |
14136 | ||
14137 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) | |
14138 | #define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg ) | |
14139 | ||
14140 | #define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) | |
14141 | #endif // CATCH_CONFIG_DISABLE_MATCHERS | |
14142 | ||
14143 | #define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg ) | |
14144 | #define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) | |
14145 | #define CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CAPTURE",__VA_ARGS__ ) | |
14146 | ||
14147 | #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) | |
14148 | #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) | |
14149 | #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) | |
14150 | #define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) | |
14151 | #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) | |
14152 | #define DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ ) | |
14153 | #define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) | |
14154 | #define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) | |
14155 | #define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) | |
14156 | #define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE() | |
14157 | ||
14158 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR | |
14159 | #define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) | |
14160 | #define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) | |
14161 | #else | |
14162 | #define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) ) | |
14163 | #define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) ) | |
14164 | #endif | |
14165 | ||
14166 | #if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE) | |
14167 | #define STATIC_REQUIRE( ... ) static_assert( __VA_ARGS__, #__VA_ARGS__ ); SUCCEED( #__VA_ARGS__ ) | |
14168 | #define STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); SUCCEED( "!(" #__VA_ARGS__ ")" ) | |
14169 | #else | |
14170 | #define STATIC_REQUIRE( ... ) REQUIRE( __VA_ARGS__ ) | |
14171 | #define STATIC_REQUIRE_FALSE( ... ) REQUIRE_FALSE( __VA_ARGS__ ) | |
14172 | #endif | |
14173 | ||
14174 | #endif | |
14175 | ||
14176 | #define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) | |
14177 | ||
14178 | // "BDD-style" convenience wrappers | |
14179 | #define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ ) | |
14180 | #define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) | |
14181 | ||
14182 | #define GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc ) | |
14183 | #define AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc ) | |
14184 | #define WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc ) | |
14185 | #define AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc ) | |
14186 | #define THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc ) | |
14187 | #define AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc ) | |
14188 | ||
14189 | using Catch::Detail::Approx; | |
14190 | ||
14191 | #else // CATCH_CONFIG_DISABLE | |
14192 | ||
14193 | ////// | |
14194 | // If this config identifier is defined then all CATCH macros are prefixed with CATCH_ | |
14195 | #ifdef CATCH_CONFIG_PREFIX_ALL | |
14196 | ||
14197 | #define CATCH_REQUIRE( ... ) (void)(0) | |
14198 | #define CATCH_REQUIRE_FALSE( ... ) (void)(0) | |
14199 | ||
14200 | #define CATCH_REQUIRE_THROWS( ... ) (void)(0) | |
14201 | #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0) | |
14202 | #define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) (void)(0) | |
14203 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) | |
14204 | #define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) | |
14205 | #endif// CATCH_CONFIG_DISABLE_MATCHERS | |
14206 | #define CATCH_REQUIRE_NOTHROW( ... ) (void)(0) | |
14207 | ||
14208 | #define CATCH_CHECK( ... ) (void)(0) | |
14209 | #define CATCH_CHECK_FALSE( ... ) (void)(0) | |
14210 | #define CATCH_CHECKED_IF( ... ) if (__VA_ARGS__) | |
14211 | #define CATCH_CHECKED_ELSE( ... ) if (!(__VA_ARGS__)) | |
14212 | #define CATCH_CHECK_NOFAIL( ... ) (void)(0) | |
14213 | ||
14214 | #define CATCH_CHECK_THROWS( ... ) (void)(0) | |
14215 | #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) (void)(0) | |
14216 | #define CATCH_CHECK_THROWS_WITH( expr, matcher ) (void)(0) | |
14217 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) | |
14218 | #define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) | |
14219 | #endif // CATCH_CONFIG_DISABLE_MATCHERS | |
14220 | #define CATCH_CHECK_NOTHROW( ... ) (void)(0) | |
14221 | ||
14222 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) | |
14223 | #define CATCH_CHECK_THAT( arg, matcher ) (void)(0) | |
14224 | ||
14225 | #define CATCH_REQUIRE_THAT( arg, matcher ) (void)(0) | |
14226 | #endif // CATCH_CONFIG_DISABLE_MATCHERS | |
14227 | ||
14228 | #define CATCH_INFO( msg ) (void)(0) | |
14229 | #define CATCH_WARN( msg ) (void)(0) | |
14230 | #define CATCH_CAPTURE( msg ) (void)(0) | |
14231 | ||
14232 | #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) | |
14233 | #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) | |
14234 | #define CATCH_METHOD_AS_TEST_CASE( method, ... ) | |
14235 | #define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0) | |
14236 | #define CATCH_SECTION( ... ) | |
14237 | #define CATCH_DYNAMIC_SECTION( ... ) | |
14238 | #define CATCH_FAIL( ... ) (void)(0) | |
14239 | #define CATCH_FAIL_CHECK( ... ) (void)(0) | |
14240 | #define CATCH_SUCCEED( ... ) (void)(0) | |
14241 | ||
14242 | #define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) | |
14243 | ||
14244 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR | |
14245 | #define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) ) | |
14246 | #define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className ) | |
14247 | #else | |
14248 | #define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) ) ) | |
14249 | #define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className ) ) | |
14250 | #endif | |
14251 | ||
14252 | // "BDD-style" convenience wrappers | |
14253 | #define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) | |
14254 | #define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className ) | |
14255 | #define CATCH_GIVEN( desc ) | |
14256 | #define CATCH_AND_GIVEN( desc ) | |
14257 | #define CATCH_WHEN( desc ) | |
14258 | #define CATCH_AND_WHEN( desc ) | |
14259 | #define CATCH_THEN( desc ) | |
14260 | #define CATCH_AND_THEN( desc ) | |
14261 | ||
14262 | #define CATCH_STATIC_REQUIRE( ... ) (void)(0) | |
14263 | #define CATCH_STATIC_REQUIRE_FALSE( ... ) (void)(0) | |
14264 | ||
14265 | // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required | |
14266 | #else | |
14267 | ||
14268 | #define REQUIRE( ... ) (void)(0) | |
14269 | #define REQUIRE_FALSE( ... ) (void)(0) | |
14270 | ||
14271 | #define REQUIRE_THROWS( ... ) (void)(0) | |
14272 | #define REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0) | |
14273 | #define REQUIRE_THROWS_WITH( expr, matcher ) (void)(0) | |
14274 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) | |
14275 | #define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) | |
14276 | #endif // CATCH_CONFIG_DISABLE_MATCHERS | |
14277 | #define REQUIRE_NOTHROW( ... ) (void)(0) | |
14278 | ||
14279 | #define CHECK( ... ) (void)(0) | |
14280 | #define CHECK_FALSE( ... ) (void)(0) | |
14281 | #define CHECKED_IF( ... ) if (__VA_ARGS__) | |
14282 | #define CHECKED_ELSE( ... ) if (!(__VA_ARGS__)) | |
14283 | #define CHECK_NOFAIL( ... ) (void)(0) | |
14284 | ||
14285 | #define CHECK_THROWS( ... ) (void)(0) | |
14286 | #define CHECK_THROWS_AS( expr, exceptionType ) (void)(0) | |
14287 | #define CHECK_THROWS_WITH( expr, matcher ) (void)(0) | |
14288 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) | |
14289 | #define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) | |
14290 | #endif // CATCH_CONFIG_DISABLE_MATCHERS | |
14291 | #define CHECK_NOTHROW( ... ) (void)(0) | |
14292 | ||
14293 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) | |
14294 | #define CHECK_THAT( arg, matcher ) (void)(0) | |
14295 | ||
14296 | #define REQUIRE_THAT( arg, matcher ) (void)(0) | |
14297 | #endif // CATCH_CONFIG_DISABLE_MATCHERS | |
14298 | ||
14299 | #define INFO( msg ) (void)(0) | |
14300 | #define WARN( msg ) (void)(0) | |
14301 | #define CAPTURE( msg ) (void)(0) | |
14302 | ||
14303 | #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) | |
14304 | #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) | |
14305 | #define METHOD_AS_TEST_CASE( method, ... ) | |
14306 | #define REGISTER_TEST_CASE( Function, ... ) (void)(0) | |
14307 | #define SECTION( ... ) | |
14308 | #define DYNAMIC_SECTION( ... ) | |
14309 | #define FAIL( ... ) (void)(0) | |
14310 | #define FAIL_CHECK( ... ) (void)(0) | |
14311 | #define SUCCEED( ... ) (void)(0) | |
14312 | #define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) | |
14313 | ||
14314 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR | |
14315 | #define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) ) | |
14316 | #define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className ) | |
14317 | #else | |
14318 | #define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) ) ) | |
14319 | #define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className ) ) | |
14320 | #endif | |
14321 | ||
14322 | #define STATIC_REQUIRE( ... ) (void)(0) | |
14323 | #define STATIC_REQUIRE_FALSE( ... ) (void)(0) | |
14324 | ||
14325 | #endif | |
14326 | ||
14327 | #define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) | |
14328 | ||
14329 | // "BDD-style" convenience wrappers | |
14330 | #define SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) ) | |
14331 | #define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className ) | |
14332 | ||
14333 | #define GIVEN( desc ) | |
14334 | #define AND_GIVEN( desc ) | |
14335 | #define WHEN( desc ) | |
14336 | #define AND_WHEN( desc ) | |
14337 | #define THEN( desc ) | |
14338 | #define AND_THEN( desc ) | |
14339 | ||
14340 | using Catch::Detail::Approx; | |
14341 | ||
14342 | #endif | |
14343 | ||
14344 | #endif // ! CATCH_CONFIG_IMPL_ONLY | |
14345 | ||
14346 | // start catch_reenable_warnings.h | |
14347 | ||
14348 | ||
14349 | #ifdef __clang__ | |
14350 | # ifdef __ICC // icpc defines the __clang__ macro | |
14351 | # pragma warning(pop) | |
14352 | # else | |
14353 | # pragma clang diagnostic pop | |
14354 | # endif | |
14355 | #elif defined __GNUC__ | |
14356 | # pragma GCC diagnostic pop | |
14357 | #endif | |
14358 | ||
14359 | // end catch_reenable_warnings.h | |
14360 | // end catch.hpp | |
14361 | #endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED | |
14362 |