1 /*
2 * Catch v2.7.0
3 * Generated: 2019-03-07 21:34:30.252164
4 * ----------------------------------------------------------
5 * This file has been merged from multiple headers. Please don't edit it directly
6 * Copyright (c) 2019 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 7
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 // Because REQUIREs trigger GCC's -Wparentheses, and because still
40 // supported version of g++ have only buggy support for _Pragmas,
41 // Wparentheses have to be suppressed globally.
42 # pragma GCC diagnostic ignored "-Wparentheses" // See #674 for details
43
44 # pragma GCC diagnostic push
45 # pragma GCC diagnostic ignored "-Wunused-variable"
46 # pragma GCC diagnostic ignored "-Wpadded"
47 #endif
48 // end catch_suppress_warnings.h
49 #if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER)
50 # define CATCH_IMPL
51 # define CATCH_CONFIG_ALL_PARTS
52 #endif
53
54 // In the impl file, we want to have access to all parts of the headers
55 // Can also be used to sanely support PCHs
56 #if defined(CATCH_CONFIG_ALL_PARTS)
57 # define CATCH_CONFIG_EXTERNAL_INTERFACES
58 # if defined(CATCH_CONFIG_DISABLE_MATCHERS)
59 # undef CATCH_CONFIG_DISABLE_MATCHERS
60 # endif
61 # if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER)
62 # define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER
63 # endif
64 #endif
65
66 #if !defined(CATCH_CONFIG_IMPL_ONLY)
67 // start catch_platform.h
68
69 #ifdef __APPLE__
70 # include <TargetConditionals.h>
71 # if TARGET_OS_OSX == 1
72 # define CATCH_PLATFORM_MAC
73 # elif TARGET_OS_IPHONE == 1
74 # define CATCH_PLATFORM_IPHONE
75 # endif
76
77 #elif defined(linux) || defined(__linux) || defined(__linux__)
78 # define CATCH_PLATFORM_LINUX
79
80 #elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__)
81 # define CATCH_PLATFORM_WINDOWS
82 #endif
83
84 // end catch_platform.h
85
86 #ifdef CATCH_IMPL
87 # ifndef CLARA_CONFIG_MAIN
88 # define CLARA_CONFIG_MAIN_NOT_DEFINED
89 # define CLARA_CONFIG_MAIN
90 # endif
91 #endif
92
93 // start catch_user_interfaces.h
94
95 namespace Catch {
96 unsigned int rngSeed();
97 }
98
99 // end catch_user_interfaces.h
100 // start catch_tag_alias_autoregistrar.h
101
102 // start catch_common.h
103
104 // start catch_compiler_capabilities.h
105
106 // Detect a number of compiler features - by compiler
107 // The following features are defined:
108 //
109 // CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported?
110 // CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported?
111 // CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported?
112 // CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled?
113 // ****************
114 // Note to maintainers: if new toggles are added please document them
115 // in configuration.md, too
116 // ****************
117
118 // In general each macro has a _NO_<feature name> form
119 // (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature.
120 // Many features, at point of detection, define an _INTERNAL_ macro, so they
121 // can be combined, en-mass, with the _NO_ forms later.
122
123 #ifdef __cplusplus
124
125 # if (__cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L)
126 # define CATCH_CPP14_OR_GREATER
127 # endif
128
129 # if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
130 # define CATCH_CPP17_OR_GREATER
131 # endif
132
133 #endif
134
135 #if defined(CATCH_CPP17_OR_GREATER)
136 # define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
137 #endif
138
139 #ifdef __clang__
140
141 # define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
142 _Pragma( "clang diagnostic push" ) \
143 _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \
144 _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"")
145 # define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
146 _Pragma( "clang diagnostic pop" )
147
148 # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
149 _Pragma( "clang diagnostic push" ) \
150 _Pragma( "clang diagnostic ignored \"-Wparentheses\"" )
151 # define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
152 _Pragma( "clang diagnostic pop" )
153
154 # define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \
155 _Pragma( "clang diagnostic push" ) \
156 _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" )
157 # define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS \
158 _Pragma( "clang diagnostic pop" )
159
160 #endif // __clang__
161
162 ////////////////////////////////////////////////////////////////////////////////
163 // Assume that non-Windows platforms support posix signals by default
164 #if !defined(CATCH_PLATFORM_WINDOWS)
165 #define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS
166 #endif
167
168 ////////////////////////////////////////////////////////////////////////////////
169 // We know some environments not to support full POSIX signals
170 #if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__)
171 #define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS
172 #endif
173
174 #ifdef __OS400__
175 # define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS
176 # define CATCH_CONFIG_COLOUR_NONE
177 #endif
178
179 ////////////////////////////////////////////////////////////////////////////////
180 // Android somehow still does not support std::to_string
181 #if defined(__ANDROID__)
182 # define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING
183 #endif
184
185 ////////////////////////////////////////////////////////////////////////////////
186 // Not all Windows environments support SEH properly
187 #if defined(__MINGW32__)
188 # define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH
189 #endif
190
191 ////////////////////////////////////////////////////////////////////////////////
192 // PS4
193 #if defined(__ORBIS__)
194 # define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE
195 #endif
196
197 ////////////////////////////////////////////////////////////////////////////////
198 // Cygwin
199 #ifdef __CYGWIN__
200
201 // Required for some versions of Cygwin to declare gettimeofday
202 // see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin
203 # define _BSD_SOURCE
204 // some versions of cygwin (most) do not support std::to_string. Use the libstd check.
205 // https://gcc.gnu.org/onlinedocs/gcc-4.8.2/libstdc++/api/a01053_source.html line 2812-2813
206 # if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \
207 && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF))
208
209 # define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING
210
211 # endif
212 #endif // __CYGWIN__
213
214 ////////////////////////////////////////////////////////////////////////////////
215 // Visual C++
216 #ifdef _MSC_VER
217
218 # if _MSC_VER >= 1900 // Visual Studio 2015 or newer
219 # define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
220 # endif
221
222 // Universal Windows platform does not support SEH
223 // Or console colours (or console at all...)
224 # if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)
225 # define CATCH_CONFIG_COLOUR_NONE
226 # else
227 # define CATCH_INTERNAL_CONFIG_WINDOWS_SEH
228 # endif
229
230 // MSVC traditional preprocessor needs some workaround for __VA_ARGS__
231 // _MSVC_TRADITIONAL == 0 means new conformant preprocessor
232 // _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor
233 # if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL)
234 # define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
235 # endif
236
237 #endif // _MSC_VER
238
239 ////////////////////////////////////////////////////////////////////////////////
240 // Check if we are compiled with -fno-exceptions or equivalent
241 #if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND)
242 # define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED
243 #endif
244
245 ////////////////////////////////////////////////////////////////////////////////
246 // DJGPP
247 #ifdef __DJGPP__
248 # define CATCH_INTERNAL_CONFIG_NO_WCHAR
249 #endif // __DJGPP__
250
251 ////////////////////////////////////////////////////////////////////////////////
252 // Embarcadero C++Build
253 #if defined(__BORLANDC__)
254 #define CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN
255 #endif
256
257 ////////////////////////////////////////////////////////////////////////////////
258
259 // Use of __COUNTER__ is suppressed during code analysis in
260 // CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly
261 // handled by it.
262 // Otherwise all supported compilers support COUNTER macro,
263 // but user still might want to turn it off
264 #if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L )
265 #define CATCH_INTERNAL_CONFIG_COUNTER
266 #endif
267
268 ////////////////////////////////////////////////////////////////////////////////
269 // Check if string_view is available and usable
270 // The check is split apart to work around v140 (VS2015) preprocessor issue...
271 #if defined(__has_include)
272 #if __has_include(<string_view>) && defined(CATCH_CPP17_OR_GREATER)
273 # define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW
274 #endif
275 #endif
276
277 ////////////////////////////////////////////////////////////////////////////////
278 // Check if optional is available and usable
279 #if defined(__has_include)
280 # if __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)
281 # define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL
282 # endif // __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)
283 #endif // __has_include
284
285 ////////////////////////////////////////////////////////////////////////////////
286 // Check if variant is available and usable
287 #if defined(__has_include)
288 # if __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
289 # if defined(__clang__) && (__clang_major__ < 8)
290 // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852
291 // fix should be in clang 8, workaround in libstdc++ 8.2
292 # include <ciso646>
293 # if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
294 # define CATCH_CONFIG_NO_CPP17_VARIANT
295 # else
296 # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT
297 # endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
298 # else
299 # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT
300 # endif // defined(__clang__) && (__clang_major__ < 8)
301 # endif // __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
302 #endif // __has_include
303
304 #if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER)
305 # define CATCH_CONFIG_COUNTER
306 #endif
307 #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)
308 # define CATCH_CONFIG_WINDOWS_SEH
309 #endif
310 // This is set by default, because we assume that unix compilers are posix-signal-compatible by default.
311 #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)
312 # define CATCH_CONFIG_POSIX_SIGNALS
313 #endif
314 // This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions.
315 #if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR)
316 # define CATCH_CONFIG_WCHAR
317 #endif
318
319 #if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING)
320 # define CATCH_CONFIG_CPP11_TO_STRING
321 #endif
322
323 #if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL)
324 # define CATCH_CONFIG_CPP17_OPTIONAL
325 #endif
326
327 #if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
328 # define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
329 #endif
330
331 #if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW)
332 # define CATCH_CONFIG_CPP17_STRING_VIEW
333 #endif
334
335 #if defined(CATCH_INTERNAL_CONFIG_CPP17_VARIANT) && !defined(CATCH_CONFIG_NO_CPP17_VARIANT) && !defined(CATCH_CONFIG_CPP17_VARIANT)
336 # define CATCH_CONFIG_CPP17_VARIANT
337 #endif
338
339 #if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT)
340 # define CATCH_INTERNAL_CONFIG_NEW_CAPTURE
341 #endif
342
343 #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)
344 # define CATCH_CONFIG_NEW_CAPTURE
345 #endif
346
347 #if !defined(CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
348 # define CATCH_CONFIG_DISABLE_EXCEPTIONS
349 #endif
350
351 #if defined(CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_NO_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_POLYFILL_ISNAN)
352 # define CATCH_CONFIG_POLYFILL_ISNAN
353 #endif
354
355 #if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS)
356 # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS
357 # define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS
358 #endif
359 #if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS)
360 # define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
361 # define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
362 #endif
363 #if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS)
364 # define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS
365 # define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS
366 #endif
367
368 #if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
369 #define CATCH_TRY if ((true))
370 #define CATCH_CATCH_ALL if ((false))
371 #define CATCH_CATCH_ANON(type) if ((false))
372 #else
373 #define CATCH_TRY try
374 #define CATCH_CATCH_ALL catch (...)
375 #define CATCH_CATCH_ANON(type) catch (type)
376 #endif
377
378 #if defined(CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_NO_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR)
379 #define CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
380 #endif
381
382 // end catch_compiler_capabilities.h
383 #define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line
384 #define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line )
385 #ifdef CATCH_CONFIG_COUNTER
386 # define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ )
387 #else
388 # define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ )
389 #endif
390
391 #include <iosfwd>
392 #include <string>
393 #include <cstdint>
394
395 // We need a dummy global operator<< so we can bring it into Catch namespace later
396 struct Catch_global_namespace_dummy {};
397 std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy);
398
399 namespace Catch {
400
401 struct CaseSensitive { enum Choice {
402 Yes,
403 No
404 }; };
405
406 class NonCopyable {
407 NonCopyable( NonCopyable const& ) = delete;
408 NonCopyable( NonCopyable && ) = delete;
409 NonCopyable& operator = ( NonCopyable const& ) = delete;
410 NonCopyable& operator = ( NonCopyable && ) = delete;
411
412 protected:
413 NonCopyable();
414 virtual ~NonCopyable();
415 };
416
417 struct SourceLineInfo {
418
419 SourceLineInfo() = delete;
SourceLineInfoCatch::SourceLineInfo420 SourceLineInfo( char const* _file, std::size_t _line ) noexcept
421 : file( _file ),
422 line( _line )
423 {}
424
425 SourceLineInfo( SourceLineInfo const& other ) = default;
426 SourceLineInfo& operator = ( SourceLineInfo const& ) = default;
427 SourceLineInfo( SourceLineInfo&& ) noexcept = default;
428 SourceLineInfo& operator = ( SourceLineInfo&& ) noexcept = default;
429
430 bool empty() const noexcept;
431 bool operator == ( SourceLineInfo const& other ) const noexcept;
432 bool operator < ( SourceLineInfo const& other ) const noexcept;
433
434 char const* file;
435 std::size_t line;
436 };
437
438 std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info );
439
440 // Bring in operator<< from global namespace into Catch namespace
441 // This is necessary because the overload of operator<< above makes
442 // lookup stop at namespace Catch
443 using ::operator<<;
444
445 // Use this in variadic streaming macros to allow
446 // >> +StreamEndStop
447 // as well as
448 // >> stuff +StreamEndStop
449 struct StreamEndStop {
450 std::string operator+() const;
451 };
452 template<typename T>
operator +(T const & value,StreamEndStop)453 T const& operator + ( T const& value, StreamEndStop ) {
454 return value;
455 }
456 }
457
458 #define CATCH_INTERNAL_LINEINFO \
459 ::Catch::SourceLineInfo( __FILE__, static_cast<std::size_t>( __LINE__ ) )
460
461 // end catch_common.h
462 namespace Catch {
463
464 struct RegistrarForTagAliases {
465 RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo );
466 };
467
468 } // end namespace Catch
469
470 #define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \
471 CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
472 namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \
473 CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
474
475 // end catch_tag_alias_autoregistrar.h
476 // start catch_test_registry.h
477
478 // start catch_interfaces_testcase.h
479
480 #include <vector>
481
482 namespace Catch {
483
484 class TestSpec;
485
486 struct ITestInvoker {
487 virtual void invoke () const = 0;
488 virtual ~ITestInvoker();
489 };
490
491 class TestCase;
492 struct IConfig;
493
494 struct ITestCaseRegistry {
495 virtual ~ITestCaseRegistry();
496 virtual std::vector<TestCase> const& getAllTests() const = 0;
497 virtual std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const = 0;
498 };
499
500 bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config );
501 std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config );
502 std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config );
503
504 }
505
506 // end catch_interfaces_testcase.h
507 // start catch_stringref.h
508
509 #include <cstddef>
510 #include <string>
511 #include <iosfwd>
512
513 namespace Catch {
514
515 /// A non-owning string class (similar to the forthcoming std::string_view)
516 /// Note that, because a StringRef may be a substring of another string,
517 /// it may not be null terminated. c_str() must return a null terminated
518 /// string, however, and so the StringRef will internally take ownership
519 /// (taking a copy), if necessary. In theory this ownership is not externally
520 /// visible - but it does mean (substring) StringRefs should not be shared between
521 /// threads.
522 class StringRef {
523 public:
524 using size_type = std::size_t;
525
526 private:
527 friend struct StringRefTestAccess;
528
529 char const* m_start;
530 size_type m_size;
531
532 char* m_data = nullptr;
533
534 void takeOwnership();
535
536 static constexpr char const* const s_empty = "";
537
538 public: // construction/ assignment
StringRef()539 StringRef() noexcept
540 : StringRef( s_empty, 0 )
541 {}
542
StringRef(StringRef const & other)543 StringRef( StringRef const& other ) noexcept
544 : m_start( other.m_start ),
545 m_size( other.m_size )
546 {}
547
StringRef(StringRef && other)548 StringRef( StringRef&& other ) noexcept
549 : m_start( other.m_start ),
550 m_size( other.m_size ),
551 m_data( other.m_data )
552 {
553 other.m_data = nullptr;
554 }
555
556 StringRef( char const* rawChars ) noexcept;
557
StringRef(char const * rawChars,size_type size)558 StringRef( char const* rawChars, size_type size ) noexcept
559 : m_start( rawChars ),
560 m_size( size )
561 {}
562
StringRef(std::string const & stdString)563 StringRef( std::string const& stdString ) noexcept
564 : m_start( stdString.c_str() ),
565 m_size( stdString.size() )
566 {}
567
~StringRef()568 ~StringRef() noexcept {
569 delete[] m_data;
570 }
571
operator =(StringRef const & other)572 auto operator = ( StringRef const &other ) noexcept -> StringRef& {
573 delete[] m_data;
574 m_data = nullptr;
575 m_start = other.m_start;
576 m_size = other.m_size;
577 return *this;
578 }
579
580 operator std::string() const;
581
582 void swap( StringRef& other ) noexcept;
583
584 public: // operators
585 auto operator == ( StringRef const& other ) const noexcept -> bool;
586 auto operator != ( StringRef const& other ) const noexcept -> bool;
587
588 auto operator[] ( size_type index ) const noexcept -> char;
589
590 public: // named queries
empty() const591 auto empty() const noexcept -> bool {
592 return m_size == 0;
593 }
size() const594 auto size() const noexcept -> size_type {
595 return m_size;
596 }
597
598 auto numberOfCharacters() const noexcept -> size_type;
599 auto c_str() const -> char const*;
600
601 public: // substrings and searches
602 auto substr( size_type start, size_type size ) const noexcept -> StringRef;
603
604 // Returns the current start pointer.
605 // Note that the pointer can change when if the StringRef is a substring
606 auto currentData() const noexcept -> char const*;
607
608 private: // ownership queries - may not be consistent between calls
609 auto isOwned() const noexcept -> bool;
610 auto isSubstring() const noexcept -> bool;
611 };
612
613 auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string;
614 auto operator + ( StringRef const& lhs, char const* rhs ) -> std::string;
615 auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string;
616
617 auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&;
618 auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&;
619
operator ""_sr(char const * rawChars,std::size_t size)620 inline auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef {
621 return StringRef( rawChars, size );
622 }
623
624 } // namespace Catch
625
operator ""_catch_sr(char const * rawChars,std::size_t size)626 inline auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef {
627 return Catch::StringRef( rawChars, size );
628 }
629
630 // end catch_stringref.h
631 // start catch_type_traits.hpp
632
633
634 #include <type_traits>
635
636 namespace Catch{
637
638 #ifdef CATCH_CPP17_OR_GREATER
639 template <typename...>
640 inline constexpr auto is_unique = std::true_type{};
641
642 template <typename T, typename... Rest>
643 inline constexpr auto is_unique<T, Rest...> = std::bool_constant<
644 (!std::is_same_v<T, Rest> && ...) && is_unique<Rest...>
645 >{};
646 #else
647
648 template <typename...>
649 struct is_unique : std::true_type{};
650
651 template <typename T0, typename T1, typename... Rest>
652 struct is_unique<T0, T1, Rest...> : std::integral_constant
653 <bool,
654 !std::is_same<T0, T1>::value
655 && is_unique<T0, Rest...>::value
656 && is_unique<T1, Rest...>::value
657 >{};
658
659 #endif
660 }
661
662 // end catch_type_traits.hpp
663 // start catch_preprocessor.hpp
664
665
666 #define CATCH_RECURSION_LEVEL0(...) __VA_ARGS__
667 #define CATCH_RECURSION_LEVEL1(...) CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(__VA_ARGS__)))
668 #define CATCH_RECURSION_LEVEL2(...) CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(__VA_ARGS__)))
669 #define CATCH_RECURSION_LEVEL3(...) CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(__VA_ARGS__)))
670 #define CATCH_RECURSION_LEVEL4(...) CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(__VA_ARGS__)))
671 #define CATCH_RECURSION_LEVEL5(...) CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(__VA_ARGS__)))
672
673 #ifdef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
674 #define INTERNAL_CATCH_EXPAND_VARGS(...) __VA_ARGS__
675 // MSVC needs more evaluations
676 #define CATCH_RECURSION_LEVEL6(...) CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(__VA_ARGS__)))
677 #define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL6(CATCH_RECURSION_LEVEL6(__VA_ARGS__))
678 #else
679 #define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL5(__VA_ARGS__)
680 #endif
681
682 #define CATCH_REC_END(...)
683 #define CATCH_REC_OUT
684
685 #define CATCH_EMPTY()
686 #define CATCH_DEFER(id) id CATCH_EMPTY()
687
688 #define CATCH_REC_GET_END2() 0, CATCH_REC_END
689 #define CATCH_REC_GET_END1(...) CATCH_REC_GET_END2
690 #define CATCH_REC_GET_END(...) CATCH_REC_GET_END1
691 #define CATCH_REC_NEXT0(test, next, ...) next CATCH_REC_OUT
692 #define CATCH_REC_NEXT1(test, next) CATCH_DEFER ( CATCH_REC_NEXT0 ) ( test, next, 0)
693 #define CATCH_REC_NEXT(test, next) CATCH_REC_NEXT1(CATCH_REC_GET_END test, next)
694
695 #define CATCH_REC_LIST0(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ )
696 #define CATCH_REC_LIST1(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0) ) ( f, peek, __VA_ARGS__ )
697 #define CATCH_REC_LIST2(f, x, peek, ...) f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ )
698
699 #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__ )
700 #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__ )
701 #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__ )
702
703 // Applies the function macro `f` to each of the remaining parameters, inserts commas between the results,
704 // and passes userdata as the first parameter to each invocation,
705 // e.g. CATCH_REC_LIST_UD(f, x, a, b, c) evaluates to f(x, a), f(x, b), f(x, c)
706 #define CATCH_REC_LIST_UD(f, userdata, ...) CATCH_RECURSE(CATCH_REC_LIST2_UD(f, userdata, __VA_ARGS__, ()()(), ()()(), ()()(), 0))
707
708 #define CATCH_REC_LIST(f, ...) CATCH_RECURSE(CATCH_REC_LIST2(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0))
709
710 #define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param)
711 #define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__
712 #define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__
713 #define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF
714 #define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__)
715 #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
716 #define INTERNAL_CATCH_STRINGIZE2(...) #__VA_ARGS__
717 #define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param))
718 #else
719 // MSVC is adding extra space and needs another indirection to expand INTERNAL_CATCH_NOINTERNAL_CATCH_DEF
720 #define INTERNAL_CATCH_STRINGIZE2(...) INTERNAL_CATCH_STRINGIZE3(__VA_ARGS__)
721 #define INTERNAL_CATCH_STRINGIZE3(...) #__VA_ARGS__
722 #define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1)
723 #endif
724
725 #define INTERNAL_CATCH_REMOVE_PARENS(...) INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF __VA_ARGS__)
726
727 #define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME2(Name, ...) INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME3(Name, __VA_ARGS__)
728 #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
729 #define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME3(Name,...) Name " - " #__VA_ARGS__
730 #define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME(Name,...) INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME2(Name, INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))
731 #else
732 // MSVC is adding extra space and needs more calls to properly remove ()
733 #define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME3(Name,...) Name " -" #__VA_ARGS__
734 #define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME1(Name, ...) INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME2(Name, __VA_ARGS__)
735 #define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME(Name, ...) INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME1(Name, INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)))
736 #endif
737
738 #define INTERNAL_CATCH_MAKE_TYPE_LIST(types) Catch::TypeList<INTERNAL_CATCH_REMOVE_PARENS(types)>
739
740 #define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(types)\
741 CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,INTERNAL_CATCH_REMOVE_PARENS(types))
742
743 // end catch_preprocessor.hpp
744 // start catch_meta.hpp
745
746
747 #include <type_traits>
748
749 namespace Catch {
750 template< typename... >
751 struct TypeList {};
752
753 template< typename... >
754 struct append;
755
756 template< template<typename...> class L1
757 , typename...E1
758 , template<typename...> class L2
759 , typename...E2
760 >
761 struct append< L1<E1...>, L2<E2...> > {
762 using type = L1<E1..., E2...>;
763 };
764
765 template< template<typename...> class L1
766 , typename...E1
767 , template<typename...> class L2
768 , typename...E2
769 , typename...Rest
770 >
771 struct append< L1<E1...>, L2<E2...>, Rest...> {
772 using type = typename append< L1<E1..., E2...>, Rest... >::type;
773 };
774
775 template< template<typename...> class
776 , typename...
777 >
778 struct rewrap;
779
780 template< template<typename...> class Container
781 , template<typename...> class List
782 , typename...elems
783 >
784 struct rewrap<Container, List<elems...>> {
785 using type = TypeList< Container< elems... > >;
786 };
787
788 template< template<typename...> class Container
789 , template<typename...> class List
790 , class...Elems
791 , typename...Elements>
792 struct rewrap<Container, List<Elems...>, Elements...> {
793 using type = typename append<TypeList<Container<Elems...>>, typename rewrap<Container, Elements...>::type>::type;
794 };
795
796 template< template<typename...> class...Containers >
797 struct combine {
798 template< typename...Types >
799 struct with_types {
800 template< template <typename...> class Final >
801 struct into {
802 using type = typename append<Final<>, typename rewrap<Containers, Types...>::type...>::type;
803 };
804 };
805 };
806
807 template<typename T>
808 struct always_false : std::false_type {};
809
810 } // namespace Catch
811
812 // end catch_meta.hpp
813 namespace Catch {
814
815 template<typename C>
816 class TestInvokerAsMethod : public ITestInvoker {
817 void (C::*m_testAsMethod)();
818 public:
TestInvokerAsMethod(void (C::* testAsMethod)())819 TestInvokerAsMethod( void (C::*testAsMethod)() ) noexcept : m_testAsMethod( testAsMethod ) {}
820
invoke() const821 void invoke() const override {
822 C obj;
823 (obj.*m_testAsMethod)();
824 }
825 };
826
827 auto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker*;
828
829 template<typename C>
makeTestInvoker(void (C::* testAsMethod)())830 auto makeTestInvoker( void (C::*testAsMethod)() ) noexcept -> ITestInvoker* {
831 return new(std::nothrow) TestInvokerAsMethod<C>( testAsMethod );
832 }
833
834 struct NameAndTags {
835 NameAndTags( StringRef const& name_ = StringRef(), StringRef const& tags_ = StringRef() ) noexcept;
836 StringRef name;
837 StringRef tags;
838 };
839
840 struct AutoReg : NonCopyable {
841 AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept;
842 ~AutoReg();
843 };
844
845 } // end namespace Catch
846
847 #if defined(CATCH_CONFIG_DISABLE)
848 #define INTERNAL_CATCH_TESTCASE_NO_REGISTRATION( TestName, ... ) \
849 static void TestName()
850 #define INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... ) \
851 namespace{ \
852 struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \
853 void test(); \
854 }; \
855 } \
856 void TestName::test()
857 #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION( TestName, ... ) \
858 template<typename TestType> \
859 static void TestName()
860 #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... ) \
861 namespace{ \
862 template<typename TestType> \
863 struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
864 void test(); \
865 }; \
866 } \
867 template<typename TestType> \
868 void TestName::test()
869 #endif
870
871 ///////////////////////////////////////////////////////////////////////////////
872 #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \
873 static void TestName(); \
874 CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
875 namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \
876 CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
877 static void TestName()
878 #define INTERNAL_CATCH_TESTCASE( ... ) \
879 INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ )
880
881 ///////////////////////////////////////////////////////////////////////////////
882 #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \
883 CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
884 namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &QualifiedMethod ), CATCH_INTERNAL_LINEINFO, "&" #QualifiedMethod, Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \
885 CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
886
887 ///////////////////////////////////////////////////////////////////////////////
888 #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\
889 CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
890 namespace{ \
891 struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \
892 void test(); \
893 }; \
894 Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \
895 } \
896 CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
897 void TestName::test()
898 #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \
899 INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ )
900
901 ///////////////////////////////////////////////////////////////////////////////
902 #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \
903 CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
904 Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \
905 CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
906
907 ///////////////////////////////////////////////////////////////////////////////
908 #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_2(TestName, TestFunc, Name, Tags, ... )\
909 CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
910 template<typename TestType> \
911 static void TestFunc();\
912 namespace {\
913 template<typename...Types> \
914 struct TestName{\
915 template<typename...Ts> \
916 TestName(Ts...names){\
917 CATCH_INTERNAL_CHECK_UNIQUE_TYPES(CATCH_REC_LIST(INTERNAL_CATCH_REMOVE_PARENS, __VA_ARGS__)) \
918 using expander = int[];\
919 (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ names, Tags } ), 0)... };/* NOLINT */ \
920 }\
921 };\
922 INTERNAL_CATCH_TEMPLATE_REGISTRY_INITIATE(TestName, Name, __VA_ARGS__) \
923 }\
924 CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
925 template<typename TestType> \
926 static void TestFunc()
927
928 #if defined(CATCH_CPP17_OR_GREATER)
929 #define CATCH_INTERNAL_CHECK_UNIQUE_TYPES(...) static_assert(Catch::is_unique<__VA_ARGS__>,"Duplicate type detected in declaration of template test case");
930 #else
931 #define CATCH_INTERNAL_CHECK_UNIQUE_TYPES(...) static_assert(Catch::is_unique<__VA_ARGS__>::value,"Duplicate type detected in declaration of template test case");
932 #endif
933
934 #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
935 #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \
936 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__ )
937 #else
938 #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \
939 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__ ) )
940 #endif
941
942 #define INTERNAL_CATCH_TEMPLATE_REGISTRY_INITIATE(TestName, Name, ...)\
943 static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
944 TestName<CATCH_REC_LIST(INTERNAL_CATCH_REMOVE_PARENS, __VA_ARGS__)>(CATCH_REC_LIST_UD(INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME,Name, __VA_ARGS__));\
945 return 0;\
946 }();
947
948 #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(TestName, TestFuncName, Name, Tags, TmplTypes, TypesList) \
949 CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
950 template<typename TestType> static void TestFuncName(); \
951 namespace { \
952 template<typename... Types> \
953 struct TestName { \
954 TestName() { \
955 CATCH_INTERNAL_CHECK_UNIQUE_TYPES(Types...) \
956 int index = 0; \
957 using expander = int[]; \
958 constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\
959 constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\
960 constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\
961 (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFuncName<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + "<" + std::string(types_list[index % num_types]) + ">", Tags } ), index++, 0)... };/* NOLINT */\
962 } \
963 }; \
964 static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \
965 using TestInit = Catch::combine<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)> \
966 ::with_types<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(TypesList)>::into<TestName>::type; \
967 TestInit(); \
968 return 0; \
969 }(); \
970 } \
971 CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
972 template<typename TestType> \
973 static void TestFuncName()
974
975 #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
976 #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\
977 INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(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__)
978 #else
979 #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\
980 INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( 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__ ) )
981 #endif
982
983 #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, ... ) \
984 CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
985 namespace{ \
986 template<typename TestType> \
987 struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
988 void test();\
989 };\
990 template<typename...Types> \
991 struct TestNameClass{\
992 template<typename...Ts> \
993 TestNameClass(Ts...names){\
994 CATCH_INTERNAL_CHECK_UNIQUE_TYPES(CATCH_REC_LIST(INTERNAL_CATCH_REMOVE_PARENS, __VA_ARGS__)) \
995 using expander = int[];\
996 (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ names, Tags } ), 0)... };/* NOLINT */ \
997 }\
998 };\
999 INTERNAL_CATCH_TEMPLATE_REGISTRY_INITIATE(TestNameClass, Name, __VA_ARGS__)\
1000 }\
1001 CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS\
1002 template<typename TestType> \
1003 void TestName<TestType>::test()
1004
1005 #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
1006 #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \
1007 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__ )
1008 #else
1009 #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \
1010 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__ ) )
1011 #endif
1012
1013 #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2(TestNameClass, TestName, ClassName, Name, Tags, TmplTypes, TypesList)\
1014 CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
1015 template<typename TestType> \
1016 struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
1017 void test();\
1018 };\
1019 namespace {\
1020 template<typename...Types>\
1021 struct TestNameClass{\
1022 TestNameClass(){\
1023 CATCH_INTERNAL_CHECK_UNIQUE_TYPES(Types...)\
1024 int index = 0;\
1025 using expander = int[];\
1026 constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\
1027 constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\
1028 constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\
1029 (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + "<" + std::string(types_list[index % num_types]) + ">", Tags } ), index++, 0)... };/* NOLINT */ \
1030 }\
1031 };\
1032 static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
1033 using TestInit = Catch::combine<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>\
1034 ::with_types<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(TypesList)>::into<TestNameClass>::type;\
1035 TestInit();\
1036 return 0;\
1037 }(); \
1038 }\
1039 CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
1040 template<typename TestType> \
1041 void TestName<TestType>::test()
1042
1043 #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
1044 #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\
1045 INTERNAL_CATCH_TEMPLATE_PRODUCT_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____ ), 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____ ), ClassName, Name, Tags, __VA_ARGS__ )
1046 #else
1047 #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\
1048 INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_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____ ), 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____ ), ClassName, Name, Tags, __VA_ARGS__ ) )
1049 #endif
1050
1051 // end catch_test_registry.h
1052 // start catch_capture.hpp
1053
1054 // start catch_assertionhandler.h
1055
1056 // start catch_assertioninfo.h
1057
1058 // start catch_result_type.h
1059
1060 namespace Catch {
1061
1062 // ResultWas::OfType enum
1063 struct ResultWas { enum OfType {
1064 Unknown = -1,
1065 Ok = 0,
1066 Info = 1,
1067 Warning = 2,
1068
1069 FailureBit = 0x10,
1070
1071 ExpressionFailed = FailureBit | 1,
1072 ExplicitFailure = FailureBit | 2,
1073
1074 Exception = 0x100 | FailureBit,
1075
1076 ThrewException = Exception | 1,
1077 DidntThrowException = Exception | 2,
1078
1079 FatalErrorCondition = 0x200 | FailureBit
1080
1081 }; };
1082
1083 bool isOk( ResultWas::OfType resultType );
1084 bool isJustInfo( int flags );
1085
1086 // ResultDisposition::Flags enum
1087 struct ResultDisposition { enum Flags {
1088 Normal = 0x01,
1089
1090 ContinueOnFailure = 0x02, // Failures fail test, but execution continues
1091 FalseTest = 0x04, // Prefix expression with !
1092 SuppressFail = 0x08 // Failures are reported but do not fail the test
1093 }; };
1094
1095 ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs );
1096
1097 bool shouldContinueOnFailure( int flags );
isFalseTest(int flags)1098 inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; }
1099 bool shouldSuppressFailure( int flags );
1100
1101 } // end namespace Catch
1102
1103 // end catch_result_type.h
1104 namespace Catch {
1105
1106 struct AssertionInfo
1107 {
1108 StringRef macroName;
1109 SourceLineInfo lineInfo;
1110 StringRef capturedExpression;
1111 ResultDisposition::Flags resultDisposition;
1112
1113 // We want to delete this constructor but a compiler bug in 4.8 means
1114 // the struct is then treated as non-aggregate
1115 //AssertionInfo() = delete;
1116 };
1117
1118 } // end namespace Catch
1119
1120 // end catch_assertioninfo.h
1121 // start catch_decomposer.h
1122
1123 // start catch_tostring.h
1124
1125 #include <vector>
1126 #include <cstddef>
1127 #include <type_traits>
1128 #include <string>
1129 // start catch_stream.h
1130
1131 #include <iosfwd>
1132 #include <cstddef>
1133 #include <ostream>
1134
1135 namespace Catch {
1136
1137 std::ostream& cout();
1138 std::ostream& cerr();
1139 std::ostream& clog();
1140
1141 class StringRef;
1142
1143 struct IStream {
1144 virtual ~IStream();
1145 virtual std::ostream& stream() const = 0;
1146 };
1147
1148 auto makeStream( StringRef const &filename ) -> IStream const*;
1149
1150 class ReusableStringStream {
1151 std::size_t m_index;
1152 std::ostream* m_oss;
1153 public:
1154 ReusableStringStream();
1155 ~ReusableStringStream();
1156
1157 auto str() const -> std::string;
1158
1159 template<typename T>
operator <<(T const & value)1160 auto operator << ( T const& value ) -> ReusableStringStream& {
1161 *m_oss << value;
1162 return *this;
1163 }
get()1164 auto get() -> std::ostream& { return *m_oss; }
1165 };
1166 }
1167
1168 // end catch_stream.h
1169
1170 #ifdef CATCH_CONFIG_CPP17_STRING_VIEW
1171 #include <string_view>
1172 #endif
1173
1174 #ifdef __OBJC__
1175 // start catch_objc_arc.hpp
1176
1177 #import <Foundation/Foundation.h>
1178
1179 #ifdef __has_feature
1180 #define CATCH_ARC_ENABLED __has_feature(objc_arc)
1181 #else
1182 #define CATCH_ARC_ENABLED 0
1183 #endif
1184
1185 void arcSafeRelease( NSObject* obj );
1186 id performOptionalSelector( id obj, SEL sel );
1187
1188 #if !CATCH_ARC_ENABLED
arcSafeRelease(NSObject * obj)1189 inline void arcSafeRelease( NSObject* obj ) {
1190 [obj release];
1191 }
performOptionalSelector(id obj,SEL sel)1192 inline id performOptionalSelector( id obj, SEL sel ) {
1193 if( [obj respondsToSelector: sel] )
1194 return [obj performSelector: sel];
1195 return nil;
1196 }
1197 #define CATCH_UNSAFE_UNRETAINED
1198 #define CATCH_ARC_STRONG
1199 #else
arcSafeRelease(NSObject *)1200 inline void arcSafeRelease( NSObject* ){}
performOptionalSelector(id obj,SEL sel)1201 inline id performOptionalSelector( id obj, SEL sel ) {
1202 #ifdef __clang__
1203 #pragma clang diagnostic push
1204 #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
1205 #endif
1206 if( [obj respondsToSelector: sel] )
1207 return [obj performSelector: sel];
1208 #ifdef __clang__
1209 #pragma clang diagnostic pop
1210 #endif
1211 return nil;
1212 }
1213 #define CATCH_UNSAFE_UNRETAINED __unsafe_unretained
1214 #define CATCH_ARC_STRONG __strong
1215 #endif
1216
1217 // end catch_objc_arc.hpp
1218 #endif
1219
1220 #ifdef _MSC_VER
1221 #pragma warning(push)
1222 #pragma warning(disable:4180) // We attempt to stream a function (address) by const&, which MSVC complains about but is harmless
1223 #endif
1224
1225 namespace Catch {
1226 namespace Detail {
1227
1228 extern const std::string unprintableString;
1229
1230 std::string rawMemoryToString( const void *object, std::size_t size );
1231
1232 template<typename T>
rawMemoryToString(const T & object)1233 std::string rawMemoryToString( const T& object ) {
1234 return rawMemoryToString( &object, sizeof(object) );
1235 }
1236
1237 template<typename T>
1238 class IsStreamInsertable {
1239 template<typename SS, typename TT>
1240 static auto test(int)
1241 -> decltype(std::declval<SS&>() << std::declval<TT>(), std::true_type());
1242
1243 template<typename, typename>
1244 static auto test(...)->std::false_type;
1245
1246 public:
1247 static const bool value = decltype(test<std::ostream, const T&>(0))::value;
1248 };
1249
1250 template<typename E>
1251 std::string convertUnknownEnumToString( E e );
1252
1253 template<typename T>
1254 typename std::enable_if<
1255 !std::is_enum<T>::value && !std::is_base_of<std::exception, T>::value,
convertUnstreamable(T const &)1256 std::string>::type convertUnstreamable( T const& ) {
1257 return Detail::unprintableString;
1258 }
1259 template<typename T>
1260 typename std::enable_if<
1261 !std::is_enum<T>::value && std::is_base_of<std::exception, T>::value,
convertUnstreamable(T const & ex)1262 std::string>::type convertUnstreamable(T const& ex) {
1263 return ex.what();
1264 }
1265
1266 template<typename T>
1267 typename std::enable_if<
1268 std::is_enum<T>::value
convertUnstreamable(T const & value)1269 , std::string>::type convertUnstreamable( T const& value ) {
1270 return convertUnknownEnumToString( value );
1271 }
1272
1273 #if defined(_MANAGED)
1274 //! Convert a CLR string to a utf8 std::string
1275 template<typename T>
1276 std::string clrReferenceToString( T^ ref ) {
1277 if (ref == nullptr)
1278 return std::string("null");
1279 auto bytes = System::Text::Encoding::UTF8->GetBytes(ref->ToString());
1280 cli::pin_ptr<System::Byte> p = &bytes[0];
1281 return std::string(reinterpret_cast<char const *>(p), bytes->Length);
1282 }
1283 #endif
1284
1285 } // namespace Detail
1286
1287 // If we decide for C++14, change these to enable_if_ts
1288 template <typename T, typename = void>
1289 struct StringMaker {
1290 template <typename Fake = T>
1291 static
1292 typename std::enable_if<::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>::type
convertCatch::StringMaker1293 convert(const Fake& value) {
1294 ReusableStringStream rss;
1295 // NB: call using the function-like syntax to avoid ambiguity with
1296 // user-defined templated operator<< under clang.
1297 rss.operator<<(value);
1298 return rss.str();
1299 }
1300
1301 template <typename Fake = T>
1302 static
1303 typename std::enable_if<!::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>::type
convertCatch::StringMaker1304 convert( const Fake& value ) {
1305 #if !defined(CATCH_CONFIG_FALLBACK_STRINGIFIER)
1306 return Detail::convertUnstreamable(value);
1307 #else
1308 return CATCH_CONFIG_FALLBACK_STRINGIFIER(value);
1309 #endif
1310 }
1311 };
1312
1313 namespace Detail {
1314
1315 // This function dispatches all stringification requests inside of Catch.
1316 // Should be preferably called fully qualified, like ::Catch::Detail::stringify
1317 template <typename T>
stringify(const T & e)1318 std::string stringify(const T& e) {
1319 return ::Catch::StringMaker<typename std::remove_cv<typename std::remove_reference<T>::type>::type>::convert(e);
1320 }
1321
1322 template<typename E>
convertUnknownEnumToString(E e)1323 std::string convertUnknownEnumToString( E e ) {
1324 return ::Catch::Detail::stringify(static_cast<typename std::underlying_type<E>::type>(e));
1325 }
1326
1327 #if defined(_MANAGED)
1328 template <typename T>
1329 std::string stringify( T^ e ) {
1330 return ::Catch::StringMaker<T^>::convert(e);
1331 }
1332 #endif
1333
1334 } // namespace Detail
1335
1336 // Some predefined specializations
1337
1338 template<>
1339 struct StringMaker<std::string> {
1340 static std::string convert(const std::string& str);
1341 };
1342
1343 #ifdef CATCH_CONFIG_CPP17_STRING_VIEW
1344 template<>
1345 struct StringMaker<std::string_view> {
1346 static std::string convert(std::string_view str);
1347 };
1348 #endif
1349
1350 template<>
1351 struct StringMaker<char const *> {
1352 static std::string convert(char const * str);
1353 };
1354 template<>
1355 struct StringMaker<char *> {
1356 static std::string convert(char * str);
1357 };
1358
1359 #ifdef CATCH_CONFIG_WCHAR
1360 template<>
1361 struct StringMaker<std::wstring> {
1362 static std::string convert(const std::wstring& wstr);
1363 };
1364
1365 # ifdef CATCH_CONFIG_CPP17_STRING_VIEW
1366 template<>
1367 struct StringMaker<std::wstring_view> {
1368 static std::string convert(std::wstring_view str);
1369 };
1370 # endif
1371
1372 template<>
1373 struct StringMaker<wchar_t const *> {
1374 static std::string convert(wchar_t const * str);
1375 };
1376 template<>
1377 struct StringMaker<wchar_t *> {
1378 static std::string convert(wchar_t * str);
1379 };
1380 #endif
1381
1382 // TBD: Should we use `strnlen` to ensure that we don't go out of the buffer,
1383 // while keeping string semantics?
1384 template<int SZ>
1385 struct StringMaker<char[SZ]> {
convertCatch::StringMaker1386 static std::string convert(char const* str) {
1387 return ::Catch::Detail::stringify(std::string{ str });
1388 }
1389 };
1390 template<int SZ>
1391 struct StringMaker<signed char[SZ]> {
convertCatch::StringMaker1392 static std::string convert(signed char const* str) {
1393 return ::Catch::Detail::stringify(std::string{ reinterpret_cast<char const *>(str) });
1394 }
1395 };
1396 template<int SZ>
1397 struct StringMaker<unsigned char[SZ]> {
convertCatch::StringMaker1398 static std::string convert(unsigned char const* str) {
1399 return ::Catch::Detail::stringify(std::string{ reinterpret_cast<char const *>(str) });
1400 }
1401 };
1402
1403 template<>
1404 struct StringMaker<int> {
1405 static std::string convert(int value);
1406 };
1407 template<>
1408 struct StringMaker<long> {
1409 static std::string convert(long value);
1410 };
1411 template<>
1412 struct StringMaker<long long> {
1413 static std::string convert(long long value);
1414 };
1415 template<>
1416 struct StringMaker<unsigned int> {
1417 static std::string convert(unsigned int value);
1418 };
1419 template<>
1420 struct StringMaker<unsigned long> {
1421 static std::string convert(unsigned long value);
1422 };
1423 template<>
1424 struct StringMaker<unsigned long long> {
1425 static std::string convert(unsigned long long value);
1426 };
1427
1428 template<>
1429 struct StringMaker<bool> {
1430 static std::string convert(bool b);
1431 };
1432
1433 template<>
1434 struct StringMaker<char> {
1435 static std::string convert(char c);
1436 };
1437 template<>
1438 struct StringMaker<signed char> {
1439 static std::string convert(signed char c);
1440 };
1441 template<>
1442 struct StringMaker<unsigned char> {
1443 static std::string convert(unsigned char c);
1444 };
1445
1446 template<>
1447 struct StringMaker<std::nullptr_t> {
1448 static std::string convert(std::nullptr_t);
1449 };
1450
1451 template<>
1452 struct StringMaker<float> {
1453 static std::string convert(float value);
1454 };
1455 template<>
1456 struct StringMaker<double> {
1457 static std::string convert(double value);
1458 };
1459
1460 template <typename T>
1461 struct StringMaker<T*> {
1462 template <typename U>
convertCatch::StringMaker1463 static std::string convert(U* p) {
1464 if (p) {
1465 return ::Catch::Detail::rawMemoryToString(p);
1466 } else {
1467 return "nullptr";
1468 }
1469 }
1470 };
1471
1472 template <typename R, typename C>
1473 struct StringMaker<R C::*> {
convertCatch::StringMaker1474 static std::string convert(R C::* p) {
1475 if (p) {
1476 return ::Catch::Detail::rawMemoryToString(p);
1477 } else {
1478 return "nullptr";
1479 }
1480 }
1481 };
1482
1483 #if defined(_MANAGED)
1484 template <typename T>
1485 struct StringMaker<T^> {
1486 static std::string convert( T^ ref ) {
1487 return ::Catch::Detail::clrReferenceToString(ref);
1488 }
1489 };
1490 #endif
1491
1492 namespace Detail {
1493 template<typename InputIterator>
rangeToString(InputIterator first,InputIterator last)1494 std::string rangeToString(InputIterator first, InputIterator last) {
1495 ReusableStringStream rss;
1496 rss << "{ ";
1497 if (first != last) {
1498 rss << ::Catch::Detail::stringify(*first);
1499 for (++first; first != last; ++first)
1500 rss << ", " << ::Catch::Detail::stringify(*first);
1501 }
1502 rss << " }";
1503 return rss.str();
1504 }
1505 }
1506
1507 #ifdef __OBJC__
1508 template<>
1509 struct StringMaker<NSString*> {
convertCatch::StringMaker1510 static std::string convert(NSString * nsstring) {
1511 if (!nsstring)
1512 return "nil";
1513 return std::string("@") + [nsstring UTF8String];
1514 }
1515 };
1516 template<>
1517 struct StringMaker<NSObject*> {
convertCatch::StringMaker1518 static std::string convert(NSObject* nsObject) {
1519 return ::Catch::Detail::stringify([nsObject description]);
1520 }
1521
1522 };
1523 namespace Detail {
stringify(NSString * nsstring)1524 inline std::string stringify( NSString* nsstring ) {
1525 return StringMaker<NSString*>::convert( nsstring );
1526 }
1527
1528 } // namespace Detail
1529 #endif // __OBJC__
1530
1531 } // namespace Catch
1532
1533 //////////////////////////////////////////////////////
1534 // Separate std-lib types stringification, so it can be selectively enabled
1535 // This means that we do not bring in
1536
1537 #if defined(CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS)
1538 # define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
1539 # define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER
1540 # define CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
1541 # define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER
1542 # define CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER
1543 #endif
1544
1545 // Separate std::pair specialization
1546 #if defined(CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER)
1547 #include <utility>
1548 namespace Catch {
1549 template<typename T1, typename T2>
1550 struct StringMaker<std::pair<T1, T2> > {
convertCatch::StringMaker1551 static std::string convert(const std::pair<T1, T2>& pair) {
1552 ReusableStringStream rss;
1553 rss << "{ "
1554 << ::Catch::Detail::stringify(pair.first)
1555 << ", "
1556 << ::Catch::Detail::stringify(pair.second)
1557 << " }";
1558 return rss.str();
1559 }
1560 };
1561 }
1562 #endif // CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
1563
1564 #if defined(CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_OPTIONAL)
1565 #include <optional>
1566 namespace Catch {
1567 template<typename T>
1568 struct StringMaker<std::optional<T> > {
convertCatch::StringMaker1569 static std::string convert(const std::optional<T>& optional) {
1570 ReusableStringStream rss;
1571 if (optional.has_value()) {
1572 rss << ::Catch::Detail::stringify(*optional);
1573 } else {
1574 rss << "{ }";
1575 }
1576 return rss.str();
1577 }
1578 };
1579 }
1580 #endif // CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER
1581
1582 // Separate std::tuple specialization
1583 #if defined(CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER)
1584 #include <tuple>
1585 namespace Catch {
1586 namespace Detail {
1587 template<
1588 typename Tuple,
1589 std::size_t N = 0,
1590 bool = (N < std::tuple_size<Tuple>::value)
1591 >
1592 struct TupleElementPrinter {
printCatch::Detail::TupleElementPrinter1593 static void print(const Tuple& tuple, std::ostream& os) {
1594 os << (N ? ", " : " ")
1595 << ::Catch::Detail::stringify(std::get<N>(tuple));
1596 TupleElementPrinter<Tuple, N + 1>::print(tuple, os);
1597 }
1598 };
1599
1600 template<
1601 typename Tuple,
1602 std::size_t N
1603 >
1604 struct TupleElementPrinter<Tuple, N, false> {
printCatch::Detail::TupleElementPrinter1605 static void print(const Tuple&, std::ostream&) {}
1606 };
1607
1608 }
1609
1610 template<typename ...Types>
1611 struct StringMaker<std::tuple<Types...>> {
convertCatch::StringMaker1612 static std::string convert(const std::tuple<Types...>& tuple) {
1613 ReusableStringStream rss;
1614 rss << '{';
1615 Detail::TupleElementPrinter<std::tuple<Types...>>::print(tuple, rss.get());
1616 rss << " }";
1617 return rss.str();
1618 }
1619 };
1620 }
1621 #endif // CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER
1622
1623 #if defined(CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_VARIANT)
1624 #include <variant>
1625 namespace Catch {
1626 template<>
1627 struct StringMaker<std::monostate> {
convertCatch::StringMaker1628 static std::string convert(const std::monostate&) {
1629 return "{ }";
1630 }
1631 };
1632
1633 template<typename... Elements>
1634 struct StringMaker<std::variant<Elements...>> {
convertCatch::StringMaker1635 static std::string convert(const std::variant<Elements...>& variant) {
1636 if (variant.valueless_by_exception()) {
1637 return "{valueless variant}";
1638 } else {
1639 return std::visit(
1640 [](const auto& value) {
1641 return ::Catch::Detail::stringify(value);
1642 },
1643 variant
1644 );
1645 }
1646 }
1647 };
1648 }
1649 #endif // CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
1650
1651 namespace Catch {
1652 struct not_this_one {}; // Tag type for detecting which begin/ end are being selected
1653
1654 // Import begin/ end from std here so they are considered alongside the fallback (...) overloads in this namespace
1655 using std::begin;
1656 using std::end;
1657
1658 not_this_one begin( ... );
1659 not_this_one end( ... );
1660
1661 template <typename T>
1662 struct is_range {
1663 static const bool value =
1664 !std::is_same<decltype(begin(std::declval<T>())), not_this_one>::value &&
1665 !std::is_same<decltype(end(std::declval<T>())), not_this_one>::value;
1666 };
1667
1668 #if defined(_MANAGED) // Managed types are never ranges
1669 template <typename T>
1670 struct is_range<T^> {
1671 static const bool value = false;
1672 };
1673 #endif
1674
1675 template<typename Range>
rangeToString(Range const & range)1676 std::string rangeToString( Range const& range ) {
1677 return ::Catch::Detail::rangeToString( begin( range ), end( range ) );
1678 }
1679
1680 // Handle vector<bool> specially
1681 template<typename Allocator>
rangeToString(std::vector<bool,Allocator> const & v)1682 std::string rangeToString( std::vector<bool, Allocator> const& v ) {
1683 ReusableStringStream rss;
1684 rss << "{ ";
1685 bool first = true;
1686 for( bool b : v ) {
1687 if( first )
1688 first = false;
1689 else
1690 rss << ", ";
1691 rss << ::Catch::Detail::stringify( b );
1692 }
1693 rss << " }";
1694 return rss.str();
1695 }
1696
1697 template<typename R>
1698 struct StringMaker<R, typename std::enable_if<is_range<R>::value && !::Catch::Detail::IsStreamInsertable<R>::value>::type> {
convertCatch::StringMaker1699 static std::string convert( R const& range ) {
1700 return rangeToString( range );
1701 }
1702 };
1703
1704 template <typename T, int SZ>
1705 struct StringMaker<T[SZ]> {
convertCatch::StringMaker1706 static std::string convert(T const(&arr)[SZ]) {
1707 return rangeToString(arr);
1708 }
1709 };
1710
1711 } // namespace Catch
1712
1713 // Separate std::chrono::duration specialization
1714 #if defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER)
1715 #include <ctime>
1716 #include <ratio>
1717 #include <chrono>
1718
1719 namespace Catch {
1720
1721 template <class Ratio>
1722 struct ratio_string {
1723 static std::string symbol();
1724 };
1725
1726 template <class Ratio>
symbol()1727 std::string ratio_string<Ratio>::symbol() {
1728 Catch::ReusableStringStream rss;
1729 rss << '[' << Ratio::num << '/'
1730 << Ratio::den << ']';
1731 return rss.str();
1732 }
1733 template <>
1734 struct ratio_string<std::atto> {
1735 static std::string symbol();
1736 };
1737 template <>
1738 struct ratio_string<std::femto> {
1739 static std::string symbol();
1740 };
1741 template <>
1742 struct ratio_string<std::pico> {
1743 static std::string symbol();
1744 };
1745 template <>
1746 struct ratio_string<std::nano> {
1747 static std::string symbol();
1748 };
1749 template <>
1750 struct ratio_string<std::micro> {
1751 static std::string symbol();
1752 };
1753 template <>
1754 struct ratio_string<std::milli> {
1755 static std::string symbol();
1756 };
1757
1758 ////////////
1759 // std::chrono::duration specializations
1760 template<typename Value, typename Ratio>
1761 struct StringMaker<std::chrono::duration<Value, Ratio>> {
convertCatch::StringMaker1762 static std::string convert(std::chrono::duration<Value, Ratio> const& duration) {
1763 ReusableStringStream rss;
1764 rss << duration.count() << ' ' << ratio_string<Ratio>::symbol() << 's';
1765 return rss.str();
1766 }
1767 };
1768 template<typename Value>
1769 struct StringMaker<std::chrono::duration<Value, std::ratio<1>>> {
convertCatch::StringMaker1770 static std::string convert(std::chrono::duration<Value, std::ratio<1>> const& duration) {
1771 ReusableStringStream rss;
1772 rss << duration.count() << " s";
1773 return rss.str();
1774 }
1775 };
1776 template<typename Value>
1777 struct StringMaker<std::chrono::duration<Value, std::ratio<60>>> {
convertCatch::StringMaker1778 static std::string convert(std::chrono::duration<Value, std::ratio<60>> const& duration) {
1779 ReusableStringStream rss;
1780 rss << duration.count() << " m";
1781 return rss.str();
1782 }
1783 };
1784 template<typename Value>
1785 struct StringMaker<std::chrono::duration<Value, std::ratio<3600>>> {
convertCatch::StringMaker1786 static std::string convert(std::chrono::duration<Value, std::ratio<3600>> const& duration) {
1787 ReusableStringStream rss;
1788 rss << duration.count() << " h";
1789 return rss.str();
1790 }
1791 };
1792
1793 ////////////
1794 // std::chrono::time_point specialization
1795 // Generic time_point cannot be specialized, only std::chrono::time_point<system_clock>
1796 template<typename Clock, typename Duration>
1797 struct StringMaker<std::chrono::time_point<Clock, Duration>> {
convertCatch::StringMaker1798 static std::string convert(std::chrono::time_point<Clock, Duration> const& time_point) {
1799 return ::Catch::Detail::stringify(time_point.time_since_epoch()) + " since epoch";
1800 }
1801 };
1802 // std::chrono::time_point<system_clock> specialization
1803 template<typename Duration>
1804 struct StringMaker<std::chrono::time_point<std::chrono::system_clock, Duration>> {
convertCatch::StringMaker1805 static std::string convert(std::chrono::time_point<std::chrono::system_clock, Duration> const& time_point) {
1806 auto converted = std::chrono::system_clock::to_time_t(time_point);
1807
1808 #ifdef _MSC_VER
1809 std::tm timeInfo = {};
1810 gmtime_s(&timeInfo, &converted);
1811 #else
1812 std::tm* timeInfo = std::gmtime(&converted);
1813 #endif
1814
1815 auto const timeStampSize = sizeof("2017-01-16T17:06:45Z");
1816 char timeStamp[timeStampSize];
1817 const char * const fmt = "%Y-%m-%dT%H:%M:%SZ";
1818
1819 #ifdef _MSC_VER
1820 std::strftime(timeStamp, timeStampSize, fmt, &timeInfo);
1821 #else
1822 std::strftime(timeStamp, timeStampSize, fmt, timeInfo);
1823 #endif
1824 return std::string(timeStamp);
1825 }
1826 };
1827 }
1828 #endif // CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER
1829
1830 #ifdef _MSC_VER
1831 #pragma warning(pop)
1832 #endif
1833
1834 // end catch_tostring.h
1835 #include <iosfwd>
1836
1837 #ifdef _MSC_VER
1838 #pragma warning(push)
1839 #pragma warning(disable:4389) // '==' : signed/unsigned mismatch
1840 #pragma warning(disable:4018) // more "signed/unsigned mismatch"
1841 #pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform)
1842 #pragma warning(disable:4180) // qualifier applied to function type has no meaning
1843 #pragma warning(disable:4800) // Forcing result to true or false
1844 #endif
1845
1846 namespace Catch {
1847
1848 struct ITransientExpression {
isBinaryExpressionCatch::ITransientExpression1849 auto isBinaryExpression() const -> bool { return m_isBinaryExpression; }
getResultCatch::ITransientExpression1850 auto getResult() const -> bool { return m_result; }
1851 virtual void streamReconstructedExpression( std::ostream &os ) const = 0;
1852
ITransientExpressionCatch::ITransientExpression1853 ITransientExpression( bool isBinaryExpression, bool result )
1854 : m_isBinaryExpression( isBinaryExpression ),
1855 m_result( result )
1856 {}
1857
1858 // We don't actually need a virtual destructor, but many static analysers
1859 // complain if it's not here :-(
1860 virtual ~ITransientExpression();
1861
1862 bool m_isBinaryExpression;
1863 bool m_result;
1864
1865 };
1866
1867 void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs );
1868
1869 template<typename LhsT, typename RhsT>
1870 class BinaryExpr : public ITransientExpression {
1871 LhsT m_lhs;
1872 StringRef m_op;
1873 RhsT m_rhs;
1874
streamReconstructedExpression(std::ostream & os) const1875 void streamReconstructedExpression( std::ostream &os ) const override {
1876 formatReconstructedExpression
1877 ( os, Catch::Detail::stringify( m_lhs ), m_op, Catch::Detail::stringify( m_rhs ) );
1878 }
1879
1880 public:
BinaryExpr(bool comparisonResult,LhsT lhs,StringRef op,RhsT rhs)1881 BinaryExpr( bool comparisonResult, LhsT lhs, StringRef op, RhsT rhs )
1882 : ITransientExpression{ true, comparisonResult },
1883 m_lhs( lhs ),
1884 m_op( op ),
1885 m_rhs( rhs )
1886 {}
1887
1888 template<typename T>
operator &&(T) const1889 auto operator && ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
1890 static_assert(always_false<T>::value,
1891 "chained comparisons are not supported inside assertions, "
1892 "wrap the expression inside parentheses, or decompose it");
1893 }
1894
1895 template<typename T>
operator ||(T) const1896 auto operator || ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
1897 static_assert(always_false<T>::value,
1898 "chained comparisons are not supported inside assertions, "
1899 "wrap the expression inside parentheses, or decompose it");
1900 }
1901
1902 template<typename T>
operator ==(T) const1903 auto operator == ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
1904 static_assert(always_false<T>::value,
1905 "chained comparisons are not supported inside assertions, "
1906 "wrap the expression inside parentheses, or decompose it");
1907 }
1908
1909 template<typename T>
operator !=(T) const1910 auto operator != ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
1911 static_assert(always_false<T>::value,
1912 "chained comparisons are not supported inside assertions, "
1913 "wrap the expression inside parentheses, or decompose it");
1914 }
1915
1916 template<typename T>
operator >(T) const1917 auto operator > ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
1918 static_assert(always_false<T>::value,
1919 "chained comparisons are not supported inside assertions, "
1920 "wrap the expression inside parentheses, or decompose it");
1921 }
1922
1923 template<typename T>
operator <(T) const1924 auto operator < ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
1925 static_assert(always_false<T>::value,
1926 "chained comparisons are not supported inside assertions, "
1927 "wrap the expression inside parentheses, or decompose it");
1928 }
1929
1930 template<typename T>
operator >=(T) const1931 auto operator >= ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
1932 static_assert(always_false<T>::value,
1933 "chained comparisons are not supported inside assertions, "
1934 "wrap the expression inside parentheses, or decompose it");
1935 }
1936
1937 template<typename T>
operator <=(T) const1938 auto operator <= ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
1939 static_assert(always_false<T>::value,
1940 "chained comparisons are not supported inside assertions, "
1941 "wrap the expression inside parentheses, or decompose it");
1942 }
1943 };
1944
1945 template<typename LhsT>
1946 class UnaryExpr : public ITransientExpression {
1947 LhsT m_lhs;
1948
streamReconstructedExpression(std::ostream & os) const1949 void streamReconstructedExpression( std::ostream &os ) const override {
1950 os << Catch::Detail::stringify( m_lhs );
1951 }
1952
1953 public:
UnaryExpr(LhsT lhs)1954 explicit UnaryExpr( LhsT lhs )
1955 : ITransientExpression{ false, static_cast<bool>(lhs) },
1956 m_lhs( lhs )
1957 {}
1958 };
1959
1960 // Specialised comparison functions to handle equality comparisons between ints and pointers (NULL deduces as an int)
1961 template<typename LhsT, typename RhsT>
compareEqual(LhsT const & lhs,RhsT const & rhs)1962 auto compareEqual( LhsT const& lhs, RhsT const& rhs ) -> bool { return static_cast<bool>(lhs == rhs); }
1963 template<typename T>
compareEqual(T * const & lhs,int rhs)1964 auto compareEqual( T* const& lhs, int rhs ) -> bool { return lhs == reinterpret_cast<void const*>( rhs ); }
1965 template<typename T>
compareEqual(T * const & lhs,long rhs)1966 auto compareEqual( T* const& lhs, long rhs ) -> bool { return lhs == reinterpret_cast<void const*>( rhs ); }
1967 template<typename T>
compareEqual(int lhs,T * const & rhs)1968 auto compareEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) == rhs; }
1969 template<typename T>
compareEqual(long lhs,T * const & rhs)1970 auto compareEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) == rhs; }
1971
1972 template<typename LhsT, typename RhsT>
compareNotEqual(LhsT const & lhs,RhsT && rhs)1973 auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return static_cast<bool>(lhs != rhs); }
1974 template<typename T>
compareNotEqual(T * const & lhs,int rhs)1975 auto compareNotEqual( T* const& lhs, int rhs ) -> bool { return lhs != reinterpret_cast<void const*>( rhs ); }
1976 template<typename T>
compareNotEqual(T * const & lhs,long rhs)1977 auto compareNotEqual( T* const& lhs, long rhs ) -> bool { return lhs != reinterpret_cast<void const*>( rhs ); }
1978 template<typename T>
compareNotEqual(int lhs,T * const & rhs)1979 auto compareNotEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) != rhs; }
1980 template<typename T>
compareNotEqual(long lhs,T * const & rhs)1981 auto compareNotEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) != rhs; }
1982
1983 template<typename LhsT>
1984 class ExprLhs {
1985 LhsT m_lhs;
1986 public:
ExprLhs(LhsT lhs)1987 explicit ExprLhs( LhsT lhs ) : m_lhs( lhs ) {}
1988
1989 template<typename RhsT>
operator ==(RhsT const & rhs)1990 auto operator == ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
1991 return { compareEqual( m_lhs, rhs ), m_lhs, "==", rhs };
1992 }
operator ==(bool rhs)1993 auto operator == ( bool rhs ) -> BinaryExpr<LhsT, bool> const {
1994 return { m_lhs == rhs, m_lhs, "==", rhs };
1995 }
1996
1997 template<typename RhsT>
operator !=(RhsT const & rhs)1998 auto operator != ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
1999 return { compareNotEqual( m_lhs, rhs ), m_lhs, "!=", rhs };
2000 }
operator !=(bool rhs)2001 auto operator != ( bool rhs ) -> BinaryExpr<LhsT, bool> const {
2002 return { m_lhs != rhs, m_lhs, "!=", rhs };
2003 }
2004
2005 template<typename RhsT>
operator >(RhsT const & rhs)2006 auto operator > ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
2007 return { static_cast<bool>(m_lhs > rhs), m_lhs, ">", rhs };
2008 }
2009 template<typename RhsT>
operator <(RhsT const & rhs)2010 auto operator < ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
2011 return { static_cast<bool>(m_lhs < rhs), m_lhs, "<", rhs };
2012 }
2013 template<typename RhsT>
operator >=(RhsT const & rhs)2014 auto operator >= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
2015 return { static_cast<bool>(m_lhs >= rhs), m_lhs, ">=", rhs };
2016 }
2017 template<typename RhsT>
operator <=(RhsT const & rhs)2018 auto operator <= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const {
2019 return { static_cast<bool>(m_lhs <= rhs), m_lhs, "<=", rhs };
2020 }
2021
2022 template<typename RhsT>
operator &&(RhsT const &)2023 auto operator && ( RhsT const& ) -> BinaryExpr<LhsT, RhsT const&> const {
2024 static_assert(always_false<RhsT>::value,
2025 "operator&& is not supported inside assertions, "
2026 "wrap the expression inside parentheses, or decompose it");
2027 }
2028
2029 template<typename RhsT>
operator ||(RhsT const &)2030 auto operator || ( RhsT const& ) -> BinaryExpr<LhsT, RhsT const&> const {
2031 static_assert(always_false<RhsT>::value,
2032 "operator|| is not supported inside assertions, "
2033 "wrap the expression inside parentheses, or decompose it");
2034 }
2035
makeUnaryExpr() const2036 auto makeUnaryExpr() const -> UnaryExpr<LhsT> {
2037 return UnaryExpr<LhsT>{ m_lhs };
2038 }
2039 };
2040
2041 void handleExpression( ITransientExpression const& expr );
2042
2043 template<typename T>
handleExpression(ExprLhs<T> const & expr)2044 void handleExpression( ExprLhs<T> const& expr ) {
2045 handleExpression( expr.makeUnaryExpr() );
2046 }
2047
2048 struct Decomposer {
2049 template<typename T>
operator <=Catch::Decomposer2050 auto operator <= ( T const& lhs ) -> ExprLhs<T const&> {
2051 return ExprLhs<T const&>{ lhs };
2052 }
2053
operator <=Catch::Decomposer2054 auto operator <=( bool value ) -> ExprLhs<bool> {
2055 return ExprLhs<bool>{ value };
2056 }
2057 };
2058
2059 } // end namespace Catch
2060
2061 #ifdef _MSC_VER
2062 #pragma warning(pop)
2063 #endif
2064
2065 // end catch_decomposer.h
2066 // start catch_interfaces_capture.h
2067
2068 #include <string>
2069
2070 namespace Catch {
2071
2072 class AssertionResult;
2073 struct AssertionInfo;
2074 struct SectionInfo;
2075 struct SectionEndInfo;
2076 struct MessageInfo;
2077 struct MessageBuilder;
2078 struct Counts;
2079 struct BenchmarkInfo;
2080 struct BenchmarkStats;
2081 struct AssertionReaction;
2082 struct SourceLineInfo;
2083
2084 struct ITransientExpression;
2085 struct IGeneratorTracker;
2086
2087 struct IResultCapture {
2088
2089 virtual ~IResultCapture();
2090
2091 virtual bool sectionStarted( SectionInfo const& sectionInfo,
2092 Counts& assertions ) = 0;
2093 virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0;
2094 virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0;
2095
2096 virtual auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0;
2097
2098 virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0;
2099 virtual void benchmarkEnded( BenchmarkStats const& stats ) = 0;
2100
2101 virtual void pushScopedMessage( MessageInfo const& message ) = 0;
2102 virtual void popScopedMessage( MessageInfo const& message ) = 0;
2103
2104 virtual void emplaceUnscopedMessage( MessageBuilder const& builder ) = 0;
2105
2106 virtual void handleFatalErrorCondition( StringRef message ) = 0;
2107
2108 virtual void handleExpr
2109 ( AssertionInfo const& info,
2110 ITransientExpression const& expr,
2111 AssertionReaction& reaction ) = 0;
2112 virtual void handleMessage
2113 ( AssertionInfo const& info,
2114 ResultWas::OfType resultType,
2115 StringRef const& message,
2116 AssertionReaction& reaction ) = 0;
2117 virtual void handleUnexpectedExceptionNotThrown
2118 ( AssertionInfo const& info,
2119 AssertionReaction& reaction ) = 0;
2120 virtual void handleUnexpectedInflightException
2121 ( AssertionInfo const& info,
2122 std::string const& message,
2123 AssertionReaction& reaction ) = 0;
2124 virtual void handleIncomplete
2125 ( AssertionInfo const& info ) = 0;
2126 virtual void handleNonExpr
2127 ( AssertionInfo const &info,
2128 ResultWas::OfType resultType,
2129 AssertionReaction &reaction ) = 0;
2130
2131 virtual bool lastAssertionPassed() = 0;
2132 virtual void assertionPassed() = 0;
2133
2134 // Deprecated, do not use:
2135 virtual std::string getCurrentTestName() const = 0;
2136 virtual const AssertionResult* getLastResult() const = 0;
2137 virtual void exceptionEarlyReported() = 0;
2138 };
2139
2140 IResultCapture& getResultCapture();
2141 }
2142
2143 // end catch_interfaces_capture.h
2144 namespace Catch {
2145
2146 struct TestFailureException{};
2147 struct AssertionResultData;
2148 struct IResultCapture;
2149 class RunContext;
2150
2151 class LazyExpression {
2152 friend class AssertionHandler;
2153 friend struct AssertionStats;
2154 friend class RunContext;
2155
2156 ITransientExpression const* m_transientExpression = nullptr;
2157 bool m_isNegated;
2158 public:
2159 LazyExpression( bool isNegated );
2160 LazyExpression( LazyExpression const& other );
2161 LazyExpression& operator = ( LazyExpression const& ) = delete;
2162
2163 explicit operator bool() const;
2164
2165 friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&;
2166 };
2167
2168 struct AssertionReaction {
2169 bool shouldDebugBreak = false;
2170 bool shouldThrow = false;
2171 };
2172
2173 class AssertionHandler {
2174 AssertionInfo m_assertionInfo;
2175 AssertionReaction m_reaction;
2176 bool m_completed = false;
2177 IResultCapture& m_resultCapture;
2178
2179 public:
2180 AssertionHandler
2181 ( StringRef const& macroName,
2182 SourceLineInfo const& lineInfo,
2183 StringRef capturedExpression,
2184 ResultDisposition::Flags resultDisposition );
~AssertionHandler()2185 ~AssertionHandler() {
2186 if ( !m_completed ) {
2187 m_resultCapture.handleIncomplete( m_assertionInfo );
2188 }
2189 }
2190
2191 template<typename T>
handleExpr(ExprLhs<T> const & expr)2192 void handleExpr( ExprLhs<T> const& expr ) {
2193 handleExpr( expr.makeUnaryExpr() );
2194 }
2195 void handleExpr( ITransientExpression const& expr );
2196
2197 void handleMessage(ResultWas::OfType resultType, StringRef const& message);
2198
2199 void handleExceptionThrownAsExpected();
2200 void handleUnexpectedExceptionNotThrown();
2201 void handleExceptionNotThrownAsExpected();
2202 void handleThrowingCallSkipped();
2203 void handleUnexpectedInflightException();
2204
2205 void complete();
2206 void setCompleted();
2207
2208 // query
2209 auto allowThrows() const -> bool;
2210 };
2211
2212 void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef const& matcherString );
2213
2214 } // namespace Catch
2215
2216 // end catch_assertionhandler.h
2217 // start catch_message.h
2218
2219 #include <string>
2220 #include <vector>
2221
2222 namespace Catch {
2223
2224 struct MessageInfo {
2225 MessageInfo( StringRef const& _macroName,
2226 SourceLineInfo const& _lineInfo,
2227 ResultWas::OfType _type );
2228
2229 StringRef macroName;
2230 std::string message;
2231 SourceLineInfo lineInfo;
2232 ResultWas::OfType type;
2233 unsigned int sequence;
2234
2235 bool operator == ( MessageInfo const& other ) const;
2236 bool operator < ( MessageInfo const& other ) const;
2237 private:
2238 static unsigned int globalCount;
2239 };
2240
2241 struct MessageStream {
2242
2243 template<typename T>
operator <<Catch::MessageStream2244 MessageStream& operator << ( T const& value ) {
2245 m_stream << value;
2246 return *this;
2247 }
2248
2249 ReusableStringStream m_stream;
2250 };
2251
2252 struct MessageBuilder : MessageStream {
2253 MessageBuilder( StringRef const& macroName,
2254 SourceLineInfo const& lineInfo,
2255 ResultWas::OfType type );
2256
2257 template<typename T>
operator <<Catch::MessageBuilder2258 MessageBuilder& operator << ( T const& value ) {
2259 m_stream << value;
2260 return *this;
2261 }
2262
2263 MessageInfo m_info;
2264 };
2265
2266 class ScopedMessage {
2267 public:
2268 explicit ScopedMessage( MessageBuilder const& builder );
2269 ScopedMessage( ScopedMessage& duplicate ) = delete;
2270 ScopedMessage( ScopedMessage&& old );
2271 ~ScopedMessage();
2272
2273 MessageInfo m_info;
2274 bool m_moved;
2275 };
2276
2277 class Capturer {
2278 std::vector<MessageInfo> m_messages;
2279 IResultCapture& m_resultCapture = getResultCapture();
2280 size_t m_captured = 0;
2281 public:
2282 Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names );
2283 ~Capturer();
2284
2285 void captureValue( size_t index, std::string const& value );
2286
2287 template<typename T>
captureValues(size_t index,T const & value)2288 void captureValues( size_t index, T const& value ) {
2289 captureValue( index, Catch::Detail::stringify( value ) );
2290 }
2291
2292 template<typename T, typename... Ts>
captureValues(size_t index,T const & value,Ts const &...values)2293 void captureValues( size_t index, T const& value, Ts const&... values ) {
2294 captureValue( index, Catch::Detail::stringify(value) );
2295 captureValues( index+1, values... );
2296 }
2297 };
2298
2299 } // end namespace Catch
2300
2301 // end catch_message.h
2302 #if !defined(CATCH_CONFIG_DISABLE)
2303
2304 #if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION)
2305 #define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__
2306 #else
2307 #define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION"
2308 #endif
2309
2310 #if defined(CATCH_CONFIG_FAST_COMPILE) || defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
2311
2312 ///////////////////////////////////////////////////////////////////////////////
2313 // Another way to speed-up compilation is to omit local try-catch for REQUIRE*
2314 // macros.
2315 #define INTERNAL_CATCH_TRY
2316 #define INTERNAL_CATCH_CATCH( capturer )
2317
2318 #else // CATCH_CONFIG_FAST_COMPILE
2319
2320 #define INTERNAL_CATCH_TRY try
2321 #define INTERNAL_CATCH_CATCH( handler ) catch(...) { handler.handleUnexpectedInflightException(); }
2322
2323 #endif
2324
2325 #define INTERNAL_CATCH_REACT( handler ) handler.complete();
2326
2327 ///////////////////////////////////////////////////////////////////////////////
2328 #define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \
2329 do { \
2330 Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
2331 INTERNAL_CATCH_TRY { \
2332 CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
2333 catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); \
2334 CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
2335 } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
2336 INTERNAL_CATCH_REACT( catchAssertionHandler ) \
2337 } 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
2338 // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&.
2339
2340 ///////////////////////////////////////////////////////////////////////////////
2341 #define INTERNAL_CATCH_IF( macroName, resultDisposition, ... ) \
2342 INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \
2343 if( Catch::getResultCapture().lastAssertionPassed() )
2344
2345 ///////////////////////////////////////////////////////////////////////////////
2346 #define INTERNAL_CATCH_ELSE( macroName, resultDisposition, ... ) \
2347 INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \
2348 if( !Catch::getResultCapture().lastAssertionPassed() )
2349
2350 ///////////////////////////////////////////////////////////////////////////////
2351 #define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \
2352 do { \
2353 Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
2354 try { \
2355 static_cast<void>(__VA_ARGS__); \
2356 catchAssertionHandler.handleExceptionNotThrownAsExpected(); \
2357 } \
2358 catch( ... ) { \
2359 catchAssertionHandler.handleUnexpectedInflightException(); \
2360 } \
2361 INTERNAL_CATCH_REACT( catchAssertionHandler ) \
2362 } while( false )
2363
2364 ///////////////////////////////////////////////////////////////////////////////
2365 #define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \
2366 do { \
2367 Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition); \
2368 if( catchAssertionHandler.allowThrows() ) \
2369 try { \
2370 static_cast<void>(__VA_ARGS__); \
2371 catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
2372 } \
2373 catch( ... ) { \
2374 catchAssertionHandler.handleExceptionThrownAsExpected(); \
2375 } \
2376 else \
2377 catchAssertionHandler.handleThrowingCallSkipped(); \
2378 INTERNAL_CATCH_REACT( catchAssertionHandler ) \
2379 } while( false )
2380
2381 ///////////////////////////////////////////////////////////////////////////////
2382 #define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \
2383 do { \
2384 Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \
2385 if( catchAssertionHandler.allowThrows() ) \
2386 try { \
2387 static_cast<void>(expr); \
2388 catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
2389 } \
2390 catch( exceptionType const& ) { \
2391 catchAssertionHandler.handleExceptionThrownAsExpected(); \
2392 } \
2393 catch( ... ) { \
2394 catchAssertionHandler.handleUnexpectedInflightException(); \
2395 } \
2396 else \
2397 catchAssertionHandler.handleThrowingCallSkipped(); \
2398 INTERNAL_CATCH_REACT( catchAssertionHandler ) \
2399 } while( false )
2400
2401 ///////////////////////////////////////////////////////////////////////////////
2402 #define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \
2403 do { \
2404 Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::StringRef(), resultDisposition ); \
2405 catchAssertionHandler.handleMessage( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \
2406 INTERNAL_CATCH_REACT( catchAssertionHandler ) \
2407 } while( false )
2408
2409 ///////////////////////////////////////////////////////////////////////////////
2410 #define INTERNAL_CATCH_CAPTURE( varName, macroName, ... ) \
2411 auto varName = Catch::Capturer( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info, #__VA_ARGS__ ); \
2412 varName.captureValues( 0, __VA_ARGS__ )
2413
2414 ///////////////////////////////////////////////////////////////////////////////
2415 #define INTERNAL_CATCH_INFO( macroName, log ) \
2416 Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log );
2417
2418 ///////////////////////////////////////////////////////////////////////////////
2419 #define INTERNAL_CATCH_UNSCOPED_INFO( macroName, log ) \
2420 Catch::getResultCapture().emplaceUnscopedMessage( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log )
2421
2422 ///////////////////////////////////////////////////////////////////////////////
2423 // Although this is matcher-based, it can be used with just a string
2424 #define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \
2425 do { \
2426 Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
2427 if( catchAssertionHandler.allowThrows() ) \
2428 try { \
2429 static_cast<void>(__VA_ARGS__); \
2430 catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
2431 } \
2432 catch( ... ) { \
2433 Catch::handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher##_catch_sr ); \
2434 } \
2435 else \
2436 catchAssertionHandler.handleThrowingCallSkipped(); \
2437 INTERNAL_CATCH_REACT( catchAssertionHandler ) \
2438 } while( false )
2439
2440 #endif // CATCH_CONFIG_DISABLE
2441
2442 // end catch_capture.hpp
2443 // start catch_section.h
2444
2445 // start catch_section_info.h
2446
2447 // start catch_totals.h
2448
2449 #include <cstddef>
2450
2451 namespace Catch {
2452
2453 struct Counts {
2454 Counts operator - ( Counts const& other ) const;
2455 Counts& operator += ( Counts const& other );
2456
2457 std::size_t total() const;
2458 bool allPassed() const;
2459 bool allOk() const;
2460
2461 std::size_t passed = 0;
2462 std::size_t failed = 0;
2463 std::size_t failedButOk = 0;
2464 };
2465
2466 struct Totals {
2467
2468 Totals operator - ( Totals const& other ) const;
2469 Totals& operator += ( Totals const& other );
2470
2471 Totals delta( Totals const& prevTotals ) const;
2472
2473 int error = 0;
2474 Counts assertions;
2475 Counts testCases;
2476 };
2477 }
2478
2479 // end catch_totals.h
2480 #include <string>
2481
2482 namespace Catch {
2483
2484 struct SectionInfo {
2485 SectionInfo
2486 ( SourceLineInfo const& _lineInfo,
2487 std::string const& _name );
2488
2489 // Deprecated
SectionInfoCatch::SectionInfo2490 SectionInfo
2491 ( SourceLineInfo const& _lineInfo,
2492 std::string const& _name,
2493 std::string const& ) : SectionInfo( _lineInfo, _name ) {}
2494
2495 std::string name;
2496 std::string description; // !Deprecated: this will always be empty
2497 SourceLineInfo lineInfo;
2498 };
2499
2500 struct SectionEndInfo {
2501 SectionInfo sectionInfo;
2502 Counts prevAssertions;
2503 double durationInSeconds;
2504 };
2505
2506 } // end namespace Catch
2507
2508 // end catch_section_info.h
2509 // start catch_timer.h
2510
2511 #include <cstdint>
2512
2513 namespace Catch {
2514
2515 auto getCurrentNanosecondsSinceEpoch() -> uint64_t;
2516 auto getEstimatedClockResolution() -> uint64_t;
2517
2518 class Timer {
2519 uint64_t m_nanoseconds = 0;
2520 public:
2521 void start();
2522 auto getElapsedNanoseconds() const -> uint64_t;
2523 auto getElapsedMicroseconds() const -> uint64_t;
2524 auto getElapsedMilliseconds() const -> unsigned int;
2525 auto getElapsedSeconds() const -> double;
2526 };
2527
2528 } // namespace Catch
2529
2530 // end catch_timer.h
2531 #include <string>
2532
2533 namespace Catch {
2534
2535 class Section : NonCopyable {
2536 public:
2537 Section( SectionInfo const& info );
2538 ~Section();
2539
2540 // This indicates whether the section should be executed or not
2541 explicit operator bool() const;
2542
2543 private:
2544 SectionInfo m_info;
2545
2546 std::string m_name;
2547 Counts m_assertions;
2548 bool m_sectionIncluded;
2549 Timer m_timer;
2550 };
2551
2552 } // end namespace Catch
2553
2554 #define INTERNAL_CATCH_SECTION( ... ) \
2555 CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \
2556 if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \
2557 CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS
2558
2559 #define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \
2560 CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \
2561 if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, (Catch::ReusableStringStream() << __VA_ARGS__).str() ) ) \
2562 CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS
2563
2564 // end catch_section.h
2565 // start catch_benchmark.h
2566
2567 #include <cstdint>
2568 #include <string>
2569
2570 namespace Catch {
2571
2572 class BenchmarkLooper {
2573
2574 std::string m_name;
2575 std::size_t m_count = 0;
2576 std::size_t m_iterationsToRun = 1;
2577 uint64_t m_resolution;
2578 Timer m_timer;
2579
2580 static auto getResolution() -> uint64_t;
2581 public:
2582 // Keep most of this inline as it's on the code path that is being timed
BenchmarkLooper(StringRef name)2583 BenchmarkLooper( StringRef name )
2584 : m_name( name ),
2585 m_resolution( getResolution() )
2586 {
2587 reportStart();
2588 m_timer.start();
2589 }
2590
operator bool()2591 explicit operator bool() {
2592 if( m_count < m_iterationsToRun )
2593 return true;
2594 return needsMoreIterations();
2595 }
2596
increment()2597 void increment() {
2598 ++m_count;
2599 }
2600
2601 void reportStart();
2602 auto needsMoreIterations() -> bool;
2603 };
2604
2605 } // end namespace Catch
2606
2607 #define BENCHMARK( name ) \
2608 for( Catch::BenchmarkLooper looper( name ); looper; looper.increment() )
2609
2610 // end catch_benchmark.h
2611 // start catch_interfaces_exception.h
2612
2613 // start catch_interfaces_registry_hub.h
2614
2615 #include <string>
2616 #include <memory>
2617
2618 namespace Catch {
2619
2620 class TestCase;
2621 struct ITestCaseRegistry;
2622 struct IExceptionTranslatorRegistry;
2623 struct IExceptionTranslator;
2624 struct IReporterRegistry;
2625 struct IReporterFactory;
2626 struct ITagAliasRegistry;
2627 class StartupExceptionRegistry;
2628
2629 using IReporterFactoryPtr = std::shared_ptr<IReporterFactory>;
2630
2631 struct IRegistryHub {
2632 virtual ~IRegistryHub();
2633
2634 virtual IReporterRegistry const& getReporterRegistry() const = 0;
2635 virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0;
2636 virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0;
2637
2638 virtual IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const = 0;
2639
2640 virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0;
2641 };
2642
2643 struct IMutableRegistryHub {
2644 virtual ~IMutableRegistryHub();
2645 virtual void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) = 0;
2646 virtual void registerListener( IReporterFactoryPtr const& factory ) = 0;
2647 virtual void registerTest( TestCase const& testInfo ) = 0;
2648 virtual void registerTranslator( const IExceptionTranslator* translator ) = 0;
2649 virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0;
2650 virtual void registerStartupException() noexcept = 0;
2651 };
2652
2653 IRegistryHub const& getRegistryHub();
2654 IMutableRegistryHub& getMutableRegistryHub();
2655 void cleanUp();
2656 std::string translateActiveException();
2657
2658 }
2659
2660 // end catch_interfaces_registry_hub.h
2661 #if defined(CATCH_CONFIG_DISABLE)
2662 #define INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( translatorName, signature) \
2663 static std::string translatorName( signature )
2664 #endif
2665
2666 #include <exception>
2667 #include <string>
2668 #include <vector>
2669
2670 namespace Catch {
2671 using exceptionTranslateFunction = std::string(*)();
2672
2673 struct IExceptionTranslator;
2674 using ExceptionTranslators = std::vector<std::unique_ptr<IExceptionTranslator const>>;
2675
2676 struct IExceptionTranslator {
2677 virtual ~IExceptionTranslator();
2678 virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0;
2679 };
2680
2681 struct IExceptionTranslatorRegistry {
2682 virtual ~IExceptionTranslatorRegistry();
2683
2684 virtual std::string translateActiveException() const = 0;
2685 };
2686
2687 class ExceptionTranslatorRegistrar {
2688 template<typename T>
2689 class ExceptionTranslator : public IExceptionTranslator {
2690 public:
2691
ExceptionTranslator(std::string (* translateFunction)(T &))2692 ExceptionTranslator( std::string(*translateFunction)( T& ) )
2693 : m_translateFunction( translateFunction )
2694 {}
2695
translate(ExceptionTranslators::const_iterator it,ExceptionTranslators::const_iterator itEnd) const2696 std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const override {
2697 try {
2698 if( it == itEnd )
2699 std::rethrow_exception(std::current_exception());
2700 else
2701 return (*it)->translate( it+1, itEnd );
2702 }
2703 catch( T& ex ) {
2704 return m_translateFunction( ex );
2705 }
2706 }
2707
2708 protected:
2709 std::string(*m_translateFunction)( T& );
2710 };
2711
2712 public:
2713 template<typename T>
ExceptionTranslatorRegistrar(std::string (* translateFunction)(T &))2714 ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) {
2715 getMutableRegistryHub().registerTranslator
2716 ( new ExceptionTranslator<T>( translateFunction ) );
2717 }
2718 };
2719 }
2720
2721 ///////////////////////////////////////////////////////////////////////////////
2722 #define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \
2723 static std::string translatorName( signature ); \
2724 CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
2725 namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); } \
2726 CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
2727 static std::string translatorName( signature )
2728
2729 #define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )
2730
2731 // end catch_interfaces_exception.h
2732 // start catch_approx.h
2733
2734 #include <type_traits>
2735
2736 namespace Catch {
2737 namespace Detail {
2738
2739 class Approx {
2740 private:
2741 bool equalityComparisonImpl(double other) const;
2742 // Validates the new margin (margin >= 0)
2743 // out-of-line to avoid including stdexcept in the header
2744 void setMargin(double margin);
2745 // Validates the new epsilon (0 < epsilon < 1)
2746 // out-of-line to avoid including stdexcept in the header
2747 void setEpsilon(double epsilon);
2748
2749 public:
2750 explicit Approx ( double value );
2751
2752 static Approx custom();
2753
2754 Approx operator-() const;
2755
2756 template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
operator ()(T const & value)2757 Approx operator()( T const& value ) {
2758 Approx approx( static_cast<double>(value) );
2759 approx.m_epsilon = m_epsilon;
2760 approx.m_margin = m_margin;
2761 approx.m_scale = m_scale;
2762 return approx;
2763 }
2764
2765 template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
Approx(T const & value)2766 explicit Approx( T const& value ): Approx(static_cast<double>(value))
2767 {}
2768
2769 template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
operator ==(const T & lhs,Approx const & rhs)2770 friend bool operator == ( const T& lhs, Approx const& rhs ) {
2771 auto lhs_v = static_cast<double>(lhs);
2772 return rhs.equalityComparisonImpl(lhs_v);
2773 }
2774
2775 template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
operator ==(Approx const & lhs,const T & rhs)2776 friend bool operator == ( Approx const& lhs, const T& rhs ) {
2777 return operator==( rhs, lhs );
2778 }
2779
2780 template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
operator !=(T const & lhs,Approx const & rhs)2781 friend bool operator != ( T const& lhs, Approx const& rhs ) {
2782 return !operator==( lhs, rhs );
2783 }
2784
2785 template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
operator !=(Approx const & lhs,T const & rhs)2786 friend bool operator != ( Approx const& lhs, T const& rhs ) {
2787 return !operator==( rhs, lhs );
2788 }
2789
2790 template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
operator <=(T const & lhs,Approx const & rhs)2791 friend bool operator <= ( T const& lhs, Approx const& rhs ) {
2792 return static_cast<double>(lhs) < rhs.m_value || lhs == rhs;
2793 }
2794
2795 template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
operator <=(Approx const & lhs,T const & rhs)2796 friend bool operator <= ( Approx const& lhs, T const& rhs ) {
2797 return lhs.m_value < static_cast<double>(rhs) || lhs == rhs;
2798 }
2799
2800 template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
operator >=(T const & lhs,Approx const & rhs)2801 friend bool operator >= ( T const& lhs, Approx const& rhs ) {
2802 return static_cast<double>(lhs) > rhs.m_value || lhs == rhs;
2803 }
2804
2805 template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
operator >=(Approx const & lhs,T const & rhs)2806 friend bool operator >= ( Approx const& lhs, T const& rhs ) {
2807 return lhs.m_value > static_cast<double>(rhs) || lhs == rhs;
2808 }
2809
2810 template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
epsilon(T const & newEpsilon)2811 Approx& epsilon( T const& newEpsilon ) {
2812 double epsilonAsDouble = static_cast<double>(newEpsilon);
2813 setEpsilon(epsilonAsDouble);
2814 return *this;
2815 }
2816
2817 template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
margin(T const & newMargin)2818 Approx& margin( T const& newMargin ) {
2819 double marginAsDouble = static_cast<double>(newMargin);
2820 setMargin(marginAsDouble);
2821 return *this;
2822 }
2823
2824 template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
scale(T const & newScale)2825 Approx& scale( T const& newScale ) {
2826 m_scale = static_cast<double>(newScale);
2827 return *this;
2828 }
2829
2830 std::string toString() const;
2831
2832 private:
2833 double m_epsilon;
2834 double m_margin;
2835 double m_scale;
2836 double m_value;
2837 };
2838 } // end namespace Detail
2839
2840 namespace literals {
2841 Detail::Approx operator "" _a(long double val);
2842 Detail::Approx operator "" _a(unsigned long long val);
2843 } // end namespace literals
2844
2845 template<>
2846 struct StringMaker<Catch::Detail::Approx> {
2847 static std::string convert(Catch::Detail::Approx const& value);
2848 };
2849
2850 } // end namespace Catch
2851
2852 // end catch_approx.h
2853 // start catch_string_manip.h
2854
2855 #include <string>
2856 #include <iosfwd>
2857
2858 namespace Catch {
2859
2860 bool startsWith( std::string const& s, std::string const& prefix );
2861 bool startsWith( std::string const& s, char prefix );
2862 bool endsWith( std::string const& s, std::string const& suffix );
2863 bool endsWith( std::string const& s, char suffix );
2864 bool contains( std::string const& s, std::string const& infix );
2865 void toLowerInPlace( std::string& s );
2866 std::string toLower( std::string const& s );
2867 std::string trim( std::string const& str );
2868 bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis );
2869
2870 struct pluralise {
2871 pluralise( std::size_t count, std::string const& label );
2872
2873 friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser );
2874
2875 std::size_t m_count;
2876 std::string m_label;
2877 };
2878 }
2879
2880 // end catch_string_manip.h
2881 #ifndef CATCH_CONFIG_DISABLE_MATCHERS
2882 // start catch_capture_matchers.h
2883
2884 // start catch_matchers.h
2885
2886 #include <string>
2887 #include <vector>
2888
2889 namespace Catch {
2890 namespace Matchers {
2891 namespace Impl {
2892
2893 template<typename ArgT> struct MatchAllOf;
2894 template<typename ArgT> struct MatchAnyOf;
2895 template<typename ArgT> struct MatchNotOf;
2896
2897 class MatcherUntypedBase {
2898 public:
2899 MatcherUntypedBase() = default;
2900 MatcherUntypedBase ( MatcherUntypedBase const& ) = default;
2901 MatcherUntypedBase& operator = ( MatcherUntypedBase const& ) = delete;
2902 std::string toString() const;
2903
2904 protected:
2905 virtual ~MatcherUntypedBase();
2906 virtual std::string describe() const = 0;
2907 mutable std::string m_cachedToString;
2908 };
2909
2910 #ifdef __clang__
2911 # pragma clang diagnostic push
2912 # pragma clang diagnostic ignored "-Wnon-virtual-dtor"
2913 #endif
2914
2915 template<typename ObjectT>
2916 struct MatcherMethod {
2917 virtual bool match( ObjectT const& arg ) const = 0;
2918 };
2919
2920 #ifdef __clang__
2921 # pragma clang diagnostic pop
2922 #endif
2923
2924 template<typename T>
2925 struct MatcherBase : MatcherUntypedBase, MatcherMethod<T> {
2926
2927 MatchAllOf<T> operator && ( MatcherBase const& other ) const;
2928 MatchAnyOf<T> operator || ( MatcherBase const& other ) const;
2929 MatchNotOf<T> operator ! () const;
2930 };
2931
2932 template<typename ArgT>
2933 struct MatchAllOf : MatcherBase<ArgT> {
matchCatch::Matchers::Impl::MatchAllOf2934 bool match( ArgT const& arg ) const override {
2935 for( auto matcher : m_matchers ) {
2936 if (!matcher->match(arg))
2937 return false;
2938 }
2939 return true;
2940 }
describeCatch::Matchers::Impl::MatchAllOf2941 std::string describe() const override {
2942 std::string description;
2943 description.reserve( 4 + m_matchers.size()*32 );
2944 description += "( ";
2945 bool first = true;
2946 for( auto matcher : m_matchers ) {
2947 if( first )
2948 first = false;
2949 else
2950 description += " and ";
2951 description += matcher->toString();
2952 }
2953 description += " )";
2954 return description;
2955 }
2956
operator &&Catch::Matchers::Impl::MatchAllOf2957 MatchAllOf<ArgT>& operator && ( MatcherBase<ArgT> const& other ) {
2958 m_matchers.push_back( &other );
2959 return *this;
2960 }
2961
2962 std::vector<MatcherBase<ArgT> const*> m_matchers;
2963 };
2964 template<typename ArgT>
2965 struct MatchAnyOf : MatcherBase<ArgT> {
2966
matchCatch::Matchers::Impl::MatchAnyOf2967 bool match( ArgT const& arg ) const override {
2968 for( auto matcher : m_matchers ) {
2969 if (matcher->match(arg))
2970 return true;
2971 }
2972 return false;
2973 }
describeCatch::Matchers::Impl::MatchAnyOf2974 std::string describe() const override {
2975 std::string description;
2976 description.reserve( 4 + m_matchers.size()*32 );
2977 description += "( ";
2978 bool first = true;
2979 for( auto matcher : m_matchers ) {
2980 if( first )
2981 first = false;
2982 else
2983 description += " or ";
2984 description += matcher->toString();
2985 }
2986 description += " )";
2987 return description;
2988 }
2989
operator ||Catch::Matchers::Impl::MatchAnyOf2990 MatchAnyOf<ArgT>& operator || ( MatcherBase<ArgT> const& other ) {
2991 m_matchers.push_back( &other );
2992 return *this;
2993 }
2994
2995 std::vector<MatcherBase<ArgT> const*> m_matchers;
2996 };
2997
2998 template<typename ArgT>
2999 struct MatchNotOf : MatcherBase<ArgT> {
3000
MatchNotOfCatch::Matchers::Impl::MatchNotOf3001 MatchNotOf( MatcherBase<ArgT> const& underlyingMatcher ) : m_underlyingMatcher( underlyingMatcher ) {}
3002
matchCatch::Matchers::Impl::MatchNotOf3003 bool match( ArgT const& arg ) const override {
3004 return !m_underlyingMatcher.match( arg );
3005 }
3006
describeCatch::Matchers::Impl::MatchNotOf3007 std::string describe() const override {
3008 return "not " + m_underlyingMatcher.toString();
3009 }
3010 MatcherBase<ArgT> const& m_underlyingMatcher;
3011 };
3012
3013 template<typename T>
operator &&(MatcherBase const & other) const3014 MatchAllOf<T> MatcherBase<T>::operator && ( MatcherBase const& other ) const {
3015 return MatchAllOf<T>() && *this && other;
3016 }
3017 template<typename T>
operator ||(MatcherBase const & other) const3018 MatchAnyOf<T> MatcherBase<T>::operator || ( MatcherBase const& other ) const {
3019 return MatchAnyOf<T>() || *this || other;
3020 }
3021 template<typename T>
operator !() const3022 MatchNotOf<T> MatcherBase<T>::operator ! () const {
3023 return MatchNotOf<T>( *this );
3024 }
3025
3026 } // namespace Impl
3027
3028 } // namespace Matchers
3029
3030 using namespace Matchers;
3031 using Matchers::Impl::MatcherBase;
3032
3033 } // namespace Catch
3034
3035 // end catch_matchers.h
3036 // start catch_matchers_floating.h
3037
3038 #include <type_traits>
3039 #include <cmath>
3040
3041 namespace Catch {
3042 namespace Matchers {
3043
3044 namespace Floating {
3045
3046 enum class FloatingPointKind : uint8_t;
3047
3048 struct WithinAbsMatcher : MatcherBase<double> {
3049 WithinAbsMatcher(double target, double margin);
3050 bool match(double const& matchee) const override;
3051 std::string describe() const override;
3052 private:
3053 double m_target;
3054 double m_margin;
3055 };
3056
3057 struct WithinUlpsMatcher : MatcherBase<double> {
3058 WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType);
3059 bool match(double const& matchee) const override;
3060 std::string describe() const override;
3061 private:
3062 double m_target;
3063 int m_ulps;
3064 FloatingPointKind m_type;
3065 };
3066
3067 } // namespace Floating
3068
3069 // The following functions create the actual matcher objects.
3070 // This allows the types to be inferred
3071 Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff);
3072 Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff);
3073 Floating::WithinAbsMatcher WithinAbs(double target, double margin);
3074
3075 } // namespace Matchers
3076 } // namespace Catch
3077
3078 // end catch_matchers_floating.h
3079 // start catch_matchers_generic.hpp
3080
3081 #include <functional>
3082 #include <string>
3083
3084 namespace Catch {
3085 namespace Matchers {
3086 namespace Generic {
3087
3088 namespace Detail {
3089 std::string finalizeDescription(const std::string& desc);
3090 }
3091
3092 template <typename T>
3093 class PredicateMatcher : public MatcherBase<T> {
3094 std::function<bool(T const&)> m_predicate;
3095 std::string m_description;
3096 public:
3097
PredicateMatcher(std::function<bool (T const &)> const & elem,std::string const & descr)3098 PredicateMatcher(std::function<bool(T const&)> const& elem, std::string const& descr)
3099 :m_predicate(std::move(elem)),
3100 m_description(Detail::finalizeDescription(descr))
3101 {}
3102
match(T const & item) const3103 bool match( T const& item ) const override {
3104 return m_predicate(item);
3105 }
3106
describe() const3107 std::string describe() const override {
3108 return m_description;
3109 }
3110 };
3111
3112 } // namespace Generic
3113
3114 // The following functions create the actual matcher objects.
3115 // The user has to explicitly specify type to the function, because
3116 // infering std::function<bool(T const&)> is hard (but possible) and
3117 // requires a lot of TMP.
3118 template<typename T>
Predicate(std::function<bool (T const &)> const & predicate,std::string const & description="")3119 Generic::PredicateMatcher<T> Predicate(std::function<bool(T const&)> const& predicate, std::string const& description = "") {
3120 return Generic::PredicateMatcher<T>(predicate, description);
3121 }
3122
3123 } // namespace Matchers
3124 } // namespace Catch
3125
3126 // end catch_matchers_generic.hpp
3127 // start catch_matchers_string.h
3128
3129 #include <string>
3130
3131 namespace Catch {
3132 namespace Matchers {
3133
3134 namespace StdString {
3135
3136 struct CasedString
3137 {
3138 CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity );
3139 std::string adjustString( std::string const& str ) const;
3140 std::string caseSensitivitySuffix() const;
3141
3142 CaseSensitive::Choice m_caseSensitivity;
3143 std::string m_str;
3144 };
3145
3146 struct StringMatcherBase : MatcherBase<std::string> {
3147 StringMatcherBase( std::string const& operation, CasedString const& comparator );
3148 std::string describe() const override;
3149
3150 CasedString m_comparator;
3151 std::string m_operation;
3152 };
3153
3154 struct EqualsMatcher : StringMatcherBase {
3155 EqualsMatcher( CasedString const& comparator );
3156 bool match( std::string const& source ) const override;
3157 };
3158 struct ContainsMatcher : StringMatcherBase {
3159 ContainsMatcher( CasedString const& comparator );
3160 bool match( std::string const& source ) const override;
3161 };
3162 struct StartsWithMatcher : StringMatcherBase {
3163 StartsWithMatcher( CasedString const& comparator );
3164 bool match( std::string const& source ) const override;
3165 };
3166 struct EndsWithMatcher : StringMatcherBase {
3167 EndsWithMatcher( CasedString const& comparator );
3168 bool match( std::string const& source ) const override;
3169 };
3170
3171 struct RegexMatcher : MatcherBase<std::string> {
3172 RegexMatcher( std::string regex, CaseSensitive::Choice caseSensitivity );
3173 bool match( std::string const& matchee ) const override;
3174 std::string describe() const override;
3175
3176 private:
3177 std::string m_regex;
3178 CaseSensitive::Choice m_caseSensitivity;
3179 };
3180
3181 } // namespace StdString
3182
3183 // The following functions create the actual matcher objects.
3184 // This allows the types to be inferred
3185
3186 StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );
3187 StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );
3188 StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );
3189 StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );
3190 StdString::RegexMatcher Matches( std::string const& regex, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes );
3191
3192 } // namespace Matchers
3193 } // namespace Catch
3194
3195 // end catch_matchers_string.h
3196 // start catch_matchers_vector.h
3197
3198 #include <algorithm>
3199
3200 namespace Catch {
3201 namespace Matchers {
3202
3203 namespace Vector {
3204 namespace Detail {
3205 template <typename InputIterator, typename T>
count(InputIterator first,InputIterator last,T const & item)3206 size_t count(InputIterator first, InputIterator last, T const& item) {
3207 size_t cnt = 0;
3208 for (; first != last; ++first) {
3209 if (*first == item) {
3210 ++cnt;
3211 }
3212 }
3213 return cnt;
3214 }
3215 template <typename InputIterator, typename T>
contains(InputIterator first,InputIterator last,T const & item)3216 bool contains(InputIterator first, InputIterator last, T const& item) {
3217 for (; first != last; ++first) {
3218 if (*first == item) {
3219 return true;
3220 }
3221 }
3222 return false;
3223 }
3224 }
3225
3226 template<typename T>
3227 struct ContainsElementMatcher : MatcherBase<std::vector<T>> {
3228
ContainsElementMatcherCatch::Matchers::Vector::ContainsElementMatcher3229 ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {}
3230
matchCatch::Matchers::Vector::ContainsElementMatcher3231 bool match(std::vector<T> const &v) const override {
3232 for (auto const& el : v) {
3233 if (el == m_comparator) {
3234 return true;
3235 }
3236 }
3237 return false;
3238 }
3239
describeCatch::Matchers::Vector::ContainsElementMatcher3240 std::string describe() const override {
3241 return "Contains: " + ::Catch::Detail::stringify( m_comparator );
3242 }
3243
3244 T const& m_comparator;
3245 };
3246
3247 template<typename T>
3248 struct ContainsMatcher : MatcherBase<std::vector<T>> {
3249
ContainsMatcherCatch::Matchers::Vector::ContainsMatcher3250 ContainsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {}
3251
matchCatch::Matchers::Vector::ContainsMatcher3252 bool match(std::vector<T> const &v) const override {
3253 // !TBD: see note in EqualsMatcher
3254 if (m_comparator.size() > v.size())
3255 return false;
3256 for (auto const& comparator : m_comparator) {
3257 auto present = false;
3258 for (const auto& el : v) {
3259 if (el == comparator) {
3260 present = true;
3261 break;
3262 }
3263 }
3264 if (!present) {
3265 return false;
3266 }
3267 }
3268 return true;
3269 }
describeCatch::Matchers::Vector::ContainsMatcher3270 std::string describe() const override {
3271 return "Contains: " + ::Catch::Detail::stringify( m_comparator );
3272 }
3273
3274 std::vector<T> const& m_comparator;
3275 };
3276
3277 template<typename T>
3278 struct EqualsMatcher : MatcherBase<std::vector<T>> {
3279
EqualsMatcherCatch::Matchers::Vector::EqualsMatcher3280 EqualsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {}
3281
matchCatch::Matchers::Vector::EqualsMatcher3282 bool match(std::vector<T> const &v) const override {
3283 // !TBD: This currently works if all elements can be compared using !=
3284 // - a more general approach would be via a compare template that defaults
3285 // to using !=. but could be specialised for, e.g. std::vector<T> etc
3286 // - then just call that directly
3287 if (m_comparator.size() != v.size())
3288 return false;
3289 for (std::size_t i = 0; i < v.size(); ++i)
3290 if (m_comparator[i] != v[i])
3291 return false;
3292 return true;
3293 }
describeCatch::Matchers::Vector::EqualsMatcher3294 std::string describe() const override {
3295 return "Equals: " + ::Catch::Detail::stringify( m_comparator );
3296 }
3297 std::vector<T> const& m_comparator;
3298 };
3299
3300 template<typename T>
3301 struct UnorderedEqualsMatcher : MatcherBase<std::vector<T>> {
UnorderedEqualsMatcherCatch::Matchers::Vector::UnorderedEqualsMatcher3302 UnorderedEqualsMatcher(std::vector<T> const& target) : m_target(target) {}
matchCatch::Matchers::Vector::UnorderedEqualsMatcher3303 bool match(std::vector<T> const& vec) const override {
3304 // Note: This is a reimplementation of std::is_permutation,
3305 // because I don't want to include <algorithm> inside the common path
3306 if (m_target.size() != vec.size()) {
3307 return false;
3308 }
3309 auto lfirst = m_target.begin(), llast = m_target.end();
3310 auto rfirst = vec.begin(), rlast = vec.end();
3311 // Cut common prefix to optimize checking of permuted parts
3312 while (lfirst != llast && *lfirst == *rfirst) {
3313 ++lfirst; ++rfirst;
3314 }
3315 if (lfirst == llast) {
3316 return true;
3317 }
3318
3319 for (auto mid = lfirst; mid != llast; ++mid) {
3320 // Skip already counted items
3321 if (Detail::contains(lfirst, mid, *mid)) {
3322 continue;
3323 }
3324 size_t num_vec = Detail::count(rfirst, rlast, *mid);
3325 if (num_vec == 0 || Detail::count(lfirst, llast, *mid) != num_vec) {
3326 return false;
3327 }
3328 }
3329
3330 return true;
3331 }
3332
describeCatch::Matchers::Vector::UnorderedEqualsMatcher3333 std::string describe() const override {
3334 return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target);
3335 }
3336 private:
3337 std::vector<T> const& m_target;
3338 };
3339
3340 } // namespace Vector
3341
3342 // The following functions create the actual matcher objects.
3343 // This allows the types to be inferred
3344
3345 template<typename T>
Contains(std::vector<T> const & comparator)3346 Vector::ContainsMatcher<T> Contains( std::vector<T> const& comparator ) {
3347 return Vector::ContainsMatcher<T>( comparator );
3348 }
3349
3350 template<typename T>
VectorContains(T const & comparator)3351 Vector::ContainsElementMatcher<T> VectorContains( T const& comparator ) {
3352 return Vector::ContainsElementMatcher<T>( comparator );
3353 }
3354
3355 template<typename T>
Equals(std::vector<T> const & comparator)3356 Vector::EqualsMatcher<T> Equals( std::vector<T> const& comparator ) {
3357 return Vector::EqualsMatcher<T>( comparator );
3358 }
3359
3360 template<typename T>
UnorderedEquals(std::vector<T> const & target)3361 Vector::UnorderedEqualsMatcher<T> UnorderedEquals(std::vector<T> const& target) {
3362 return Vector::UnorderedEqualsMatcher<T>(target);
3363 }
3364
3365 } // namespace Matchers
3366 } // namespace Catch
3367
3368 // end catch_matchers_vector.h
3369 namespace Catch {
3370
3371 template<typename ArgT, typename MatcherT>
3372 class MatchExpr : public ITransientExpression {
3373 ArgT const& m_arg;
3374 MatcherT m_matcher;
3375 StringRef m_matcherString;
3376 public:
MatchExpr(ArgT const & arg,MatcherT const & matcher,StringRef const & matcherString)3377 MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef const& matcherString )
3378 : ITransientExpression{ true, matcher.match( arg ) },
3379 m_arg( arg ),
3380 m_matcher( matcher ),
3381 m_matcherString( matcherString )
3382 {}
3383
streamReconstructedExpression(std::ostream & os) const3384 void streamReconstructedExpression( std::ostream &os ) const override {
3385 auto matcherAsString = m_matcher.toString();
3386 os << Catch::Detail::stringify( m_arg ) << ' ';
3387 if( matcherAsString == Detail::unprintableString )
3388 os << m_matcherString;
3389 else
3390 os << matcherAsString;
3391 }
3392 };
3393
3394 using StringMatcher = Matchers::Impl::MatcherBase<std::string>;
3395
3396 void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString );
3397
3398 template<typename ArgT, typename MatcherT>
makeMatchExpr(ArgT const & arg,MatcherT const & matcher,StringRef const & matcherString)3399 auto makeMatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef const& matcherString ) -> MatchExpr<ArgT, MatcherT> {
3400 return MatchExpr<ArgT, MatcherT>( arg, matcher, matcherString );
3401 }
3402
3403 } // namespace Catch
3404
3405 ///////////////////////////////////////////////////////////////////////////////
3406 #define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \
3407 do { \
3408 Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
3409 INTERNAL_CATCH_TRY { \
3410 catchAssertionHandler.handleExpr( Catch::makeMatchExpr( arg, matcher, #matcher##_catch_sr ) ); \
3411 } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
3412 INTERNAL_CATCH_REACT( catchAssertionHandler ) \
3413 } while( false )
3414
3415 ///////////////////////////////////////////////////////////////////////////////
3416 #define INTERNAL_CATCH_THROWS_MATCHES( macroName, exceptionType, resultDisposition, matcher, ... ) \
3417 do { \
3418 Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(exceptionType) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
3419 if( catchAssertionHandler.allowThrows() ) \
3420 try { \
3421 static_cast<void>(__VA_ARGS__ ); \
3422 catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
3423 } \
3424 catch( exceptionType const& ex ) { \
3425 catchAssertionHandler.handleExpr( Catch::makeMatchExpr( ex, matcher, #matcher##_catch_sr ) ); \
3426 } \
3427 catch( ... ) { \
3428 catchAssertionHandler.handleUnexpectedInflightException(); \
3429 } \
3430 else \
3431 catchAssertionHandler.handleThrowingCallSkipped(); \
3432 INTERNAL_CATCH_REACT( catchAssertionHandler ) \
3433 } while( false )
3434
3435 // end catch_capture_matchers.h
3436 #endif
3437 // start catch_generators.hpp
3438
3439 // start catch_interfaces_generatortracker.h
3440
3441
3442 #include <memory>
3443
3444 namespace Catch {
3445
3446 namespace Generators {
3447 class GeneratorUntypedBase {
3448 public:
3449 GeneratorUntypedBase() = default;
3450 virtual ~GeneratorUntypedBase();
3451 // Attempts to move the generator to the next element
3452 //
3453 // Returns true iff the move succeeded (and a valid element
3454 // can be retrieved).
3455 virtual bool next() = 0;
3456 };
3457 using GeneratorBasePtr = std::unique_ptr<GeneratorUntypedBase>;
3458
3459 } // namespace Generators
3460
3461 struct IGeneratorTracker {
3462 virtual ~IGeneratorTracker();
3463 virtual auto hasGenerator() const -> bool = 0;
3464 virtual auto getGenerator() const -> Generators::GeneratorBasePtr const& = 0;
3465 virtual void setGenerator( Generators::GeneratorBasePtr&& generator ) = 0;
3466 };
3467
3468 } // namespace Catch
3469
3470 // end catch_interfaces_generatortracker.h
3471 // start catch_enforce.h
3472
3473 #include <stdexcept>
3474
3475 namespace Catch {
3476 #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
3477 template <typename Ex>
3478 [[noreturn]]
throw_exception(Ex const & e)3479 void throw_exception(Ex const& e) {
3480 throw e;
3481 }
3482 #else // ^^ Exceptions are enabled // Exceptions are disabled vv
3483 [[noreturn]]
3484 void throw_exception(std::exception const& e);
3485 #endif
3486 } // namespace Catch;
3487
3488 #define CATCH_PREPARE_EXCEPTION( type, msg ) \
3489 type( ( Catch::ReusableStringStream() << msg ).str() )
3490 #define CATCH_INTERNAL_ERROR( msg ) \
3491 Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::logic_error, CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg))
3492 #define CATCH_ERROR( msg ) \
3493 Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::domain_error, msg ))
3494 #define CATCH_RUNTIME_ERROR( msg ) \
3495 Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::runtime_error, msg ))
3496 #define CATCH_ENFORCE( condition, msg ) \
3497 do{ if( !(condition) ) CATCH_ERROR( msg ); } while(false)
3498
3499 // end catch_enforce.h
3500 #include <memory>
3501 #include <vector>
3502 #include <cassert>
3503
3504 #include <utility>
3505 #include <exception>
3506
3507 namespace Catch {
3508
3509 class GeneratorException : public std::exception {
3510 const char* const m_msg = "";
3511
3512 public:
GeneratorException(const char * msg)3513 GeneratorException(const char* msg):
3514 m_msg(msg)
3515 {}
3516
3517 const char* what() const noexcept override final;
3518 };
3519
3520 namespace Generators {
3521
3522 // !TBD move this into its own location?
3523 namespace pf{
3524 template<typename T, typename... Args>
make_unique(Args &&...args)3525 std::unique_ptr<T> make_unique( Args&&... args ) {
3526 return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
3527 }
3528 }
3529
3530 template<typename T>
3531 struct IGenerator : GeneratorUntypedBase {
3532 virtual ~IGenerator() = default;
3533
3534 // Returns the current element of the generator
3535 //
3536 // \Precondition The generator is either freshly constructed,
3537 // or the last call to `next()` returned true
3538 virtual T const& get() const = 0;
3539 using type = T;
3540 };
3541
3542 template<typename T>
3543 class SingleValueGenerator final : public IGenerator<T> {
3544 T m_value;
3545 public:
SingleValueGenerator(T const & value)3546 SingleValueGenerator(T const& value) : m_value( value ) {}
SingleValueGenerator(T && value)3547 SingleValueGenerator(T&& value) : m_value(std::move(value)) {}
3548
get() const3549 T const& get() const override {
3550 return m_value;
3551 }
next()3552 bool next() override {
3553 return false;
3554 }
3555 };
3556
3557 template<typename T>
3558 class FixedValuesGenerator final : public IGenerator<T> {
3559 std::vector<T> m_values;
3560 size_t m_idx = 0;
3561 public:
FixedValuesGenerator(std::initializer_list<T> values)3562 FixedValuesGenerator( std::initializer_list<T> values ) : m_values( values ) {}
3563
get() const3564 T const& get() const override {
3565 return m_values[m_idx];
3566 }
next()3567 bool next() override {
3568 ++m_idx;
3569 return m_idx < m_values.size();
3570 }
3571 };
3572
3573 template <typename T>
3574 class GeneratorWrapper final {
3575 std::unique_ptr<IGenerator<T>> m_generator;
3576 public:
GeneratorWrapper(std::unique_ptr<IGenerator<T>> generator)3577 GeneratorWrapper(std::unique_ptr<IGenerator<T>> generator):
3578 m_generator(std::move(generator))
3579 {}
get() const3580 T const& get() const {
3581 return m_generator->get();
3582 }
next()3583 bool next() {
3584 return m_generator->next();
3585 }
3586 };
3587
3588 template <typename T>
value(T && value)3589 GeneratorWrapper<T> value(T&& value) {
3590 return GeneratorWrapper<T>(pf::make_unique<SingleValueGenerator<T>>(std::forward<T>(value)));
3591 }
3592 template <typename T>
values(std::initializer_list<T> values)3593 GeneratorWrapper<T> values(std::initializer_list<T> values) {
3594 return GeneratorWrapper<T>(pf::make_unique<FixedValuesGenerator<T>>(values));
3595 }
3596
3597 template<typename T>
3598 class Generators : public IGenerator<T> {
3599 std::vector<GeneratorWrapper<T>> m_generators;
3600 size_t m_current = 0;
3601
populate(GeneratorWrapper<T> && generator)3602 void populate(GeneratorWrapper<T>&& generator) {
3603 m_generators.emplace_back(std::move(generator));
3604 }
populate(T && val)3605 void populate(T&& val) {
3606 m_generators.emplace_back(value(std::move(val)));
3607 }
3608 template<typename U>
populate(U && val)3609 void populate(U&& val) {
3610 populate(T(std::move(val)));
3611 }
3612 template<typename U, typename... Gs>
populate(U && valueOrGenerator,Gs...moreGenerators)3613 void populate(U&& valueOrGenerator, Gs... moreGenerators) {
3614 populate(std::forward<U>(valueOrGenerator));
3615 populate(std::forward<Gs>(moreGenerators)...);
3616 }
3617
3618 public:
3619 template <typename... Gs>
Generators(Gs...moreGenerators)3620 Generators(Gs... moreGenerators) {
3621 m_generators.reserve(sizeof...(Gs));
3622 populate(std::forward<Gs>(moreGenerators)...);
3623 }
3624
get() const3625 T const& get() const override {
3626 return m_generators[m_current].get();
3627 }
3628
next()3629 bool next() override {
3630 if (m_current >= m_generators.size()) {
3631 return false;
3632 }
3633 const bool current_status = m_generators[m_current].next();
3634 if (!current_status) {
3635 ++m_current;
3636 }
3637 return m_current < m_generators.size();
3638 }
3639 };
3640
3641 template<typename... Ts>
table(std::initializer_list<std::tuple<typename std::decay<Ts>::type...>> tuples)3642 GeneratorWrapper<std::tuple<Ts...>> table( std::initializer_list<std::tuple<typename std::decay<Ts>::type...>> tuples ) {
3643 return values<std::tuple<Ts...>>( tuples );
3644 }
3645
3646 // Tag type to signal that a generator sequence should convert arguments to a specific type
3647 template <typename T>
3648 struct as {};
3649
3650 template<typename T, typename... Gs>
makeGenerators(GeneratorWrapper<T> && generator,Gs...moreGenerators)3651 auto makeGenerators( GeneratorWrapper<T>&& generator, Gs... moreGenerators ) -> Generators<T> {
3652 return Generators<T>(std::move(generator), std::forward<Gs>(moreGenerators)...);
3653 }
3654 template<typename T>
makeGenerators(GeneratorWrapper<T> && generator)3655 auto makeGenerators( GeneratorWrapper<T>&& generator ) -> Generators<T> {
3656 return Generators<T>(std::move(generator));
3657 }
3658 template<typename T, typename... Gs>
makeGenerators(T && val,Gs...moreGenerators)3659 auto makeGenerators( T&& val, Gs... moreGenerators ) -> Generators<T> {
3660 return makeGenerators( value( std::forward<T>( val ) ), std::forward<Gs>( moreGenerators )... );
3661 }
3662 template<typename T, typename U, typename... Gs>
makeGenerators(as<T>,U && val,Gs...moreGenerators)3663 auto makeGenerators( as<T>, U&& val, Gs... moreGenerators ) -> Generators<T> {
3664 return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... );
3665 }
3666
3667 auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker&;
3668
3669 template<typename L>
3670 // Note: The type after -> is weird, because VS2015 cannot parse
3671 // the expression used in the typedef inside, when it is in
3672 // return type. Yeah.
generate(SourceLineInfo const & lineInfo,L const & generatorExpression)3673 auto generate( SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>().get()) {
3674 using UnderlyingType = typename decltype(generatorExpression())::type;
3675
3676 IGeneratorTracker& tracker = acquireGeneratorTracker( lineInfo );
3677 if (!tracker.hasGenerator()) {
3678 tracker.setGenerator(pf::make_unique<Generators<UnderlyingType>>(generatorExpression()));
3679 }
3680
3681 auto const& generator = static_cast<IGenerator<UnderlyingType> const&>( *tracker.getGenerator() );
3682 return generator.get();
3683 }
3684
3685 } // namespace Generators
3686 } // namespace Catch
3687
3688 #define GENERATE( ... ) \
3689 Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, []{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } )
3690
3691 // end catch_generators.hpp
3692 // start catch_generators_generic.hpp
3693
3694 namespace Catch {
3695 namespace Generators {
3696
3697 template <typename T>
3698 class TakeGenerator : public IGenerator<T> {
3699 GeneratorWrapper<T> m_generator;
3700 size_t m_returned = 0;
3701 size_t m_target;
3702 public:
TakeGenerator(size_t target,GeneratorWrapper<T> && generator)3703 TakeGenerator(size_t target, GeneratorWrapper<T>&& generator):
3704 m_generator(std::move(generator)),
3705 m_target(target)
3706 {
3707 assert(target != 0 && "Empty generators are not allowed");
3708 }
get() const3709 T const& get() const override {
3710 return m_generator.get();
3711 }
next()3712 bool next() override {
3713 ++m_returned;
3714 if (m_returned >= m_target) {
3715 return false;
3716 }
3717
3718 const auto success = m_generator.next();
3719 // If the underlying generator does not contain enough values
3720 // then we cut short as well
3721 if (!success) {
3722 m_returned = m_target;
3723 }
3724 return success;
3725 }
3726 };
3727
3728 template <typename T>
take(size_t target,GeneratorWrapper<T> && generator)3729 GeneratorWrapper<T> take(size_t target, GeneratorWrapper<T>&& generator) {
3730 return GeneratorWrapper<T>(pf::make_unique<TakeGenerator<T>>(target, std::move(generator)));
3731 }
3732
3733 template <typename T, typename Predicate>
3734 class FilterGenerator : public IGenerator<T> {
3735 GeneratorWrapper<T> m_generator;
3736 Predicate m_predicate;
3737 public:
3738 template <typename P = Predicate>
FilterGenerator(P && pred,GeneratorWrapper<T> && generator)3739 FilterGenerator(P&& pred, GeneratorWrapper<T>&& generator):
3740 m_generator(std::move(generator)),
3741 m_predicate(std::forward<P>(pred))
3742 {
3743 if (!m_predicate(m_generator.get())) {
3744 // It might happen that there are no values that pass the
3745 // filter. In that case we throw an exception.
3746 auto has_initial_value = next();
3747 if (!has_initial_value) {
3748 Catch::throw_exception(GeneratorException("No valid value found in filtered generator"));
3749 }
3750 }
3751 }
3752
get() const3753 T const& get() const override {
3754 return m_generator.get();
3755 }
3756
next()3757 bool next() override {
3758 bool success = m_generator.next();
3759 if (!success) {
3760 return false;
3761 }
3762 while (!m_predicate(m_generator.get()) && (success = m_generator.next()) == true);
3763 return success;
3764 }
3765 };
3766
3767 template <typename T, typename Predicate>
filter(Predicate && pred,GeneratorWrapper<T> && generator)3768 GeneratorWrapper<T> filter(Predicate&& pred, GeneratorWrapper<T>&& generator) {
3769 return GeneratorWrapper<T>(std::unique_ptr<IGenerator<T>>(pf::make_unique<FilterGenerator<T, Predicate>>(std::forward<Predicate>(pred), std::move(generator))));
3770 }
3771
3772 template <typename T>
3773 class RepeatGenerator : public IGenerator<T> {
3774 GeneratorWrapper<T> m_generator;
3775 mutable std::vector<T> m_returned;
3776 size_t m_target_repeats;
3777 size_t m_current_repeat = 0;
3778 size_t m_repeat_index = 0;
3779 public:
RepeatGenerator(size_t repeats,GeneratorWrapper<T> && generator)3780 RepeatGenerator(size_t repeats, GeneratorWrapper<T>&& generator):
3781 m_generator(std::move(generator)),
3782 m_target_repeats(repeats)
3783 {
3784 assert(m_target_repeats > 0 && "Repeat generator must repeat at least once");
3785 }
3786
get() const3787 T const& get() const override {
3788 if (m_current_repeat == 0) {
3789 m_returned.push_back(m_generator.get());
3790 return m_returned.back();
3791 }
3792 return m_returned[m_repeat_index];
3793 }
3794
next()3795 bool next() override {
3796 // There are 2 basic cases:
3797 // 1) We are still reading the generator
3798 // 2) We are reading our own cache
3799
3800 // In the first case, we need to poke the underlying generator.
3801 // If it happily moves, we are left in that state, otherwise it is time to start reading from our cache
3802 if (m_current_repeat == 0) {
3803 const auto success = m_generator.next();
3804 if (!success) {
3805 ++m_current_repeat;
3806 }
3807 return m_current_repeat < m_target_repeats;
3808 }
3809
3810 // In the second case, we need to move indices forward and check that we haven't run up against the end
3811 ++m_repeat_index;
3812 if (m_repeat_index == m_returned.size()) {
3813 m_repeat_index = 0;
3814 ++m_current_repeat;
3815 }
3816 return m_current_repeat < m_target_repeats;
3817 }
3818 };
3819
3820 template <typename T>
repeat(size_t repeats,GeneratorWrapper<T> && generator)3821 GeneratorWrapper<T> repeat(size_t repeats, GeneratorWrapper<T>&& generator) {
3822 return GeneratorWrapper<T>(pf::make_unique<RepeatGenerator<T>>(repeats, std::move(generator)));
3823 }
3824
3825 template <typename T, typename U, typename Func>
3826 class MapGenerator : public IGenerator<T> {
3827 // TBD: provide static assert for mapping function, for friendly error message
3828 GeneratorWrapper<U> m_generator;
3829 Func m_function;
3830 // To avoid returning dangling reference, we have to save the values
3831 T m_cache;
3832 public:
3833 template <typename F2 = Func>
MapGenerator(F2 && function,GeneratorWrapper<U> && generator)3834 MapGenerator(F2&& function, GeneratorWrapper<U>&& generator) :
3835 m_generator(std::move(generator)),
3836 m_function(std::forward<F2>(function)),
3837 m_cache(m_function(m_generator.get()))
3838 {}
3839
get() const3840 T const& get() const override {
3841 return m_cache;
3842 }
next()3843 bool next() override {
3844 const auto success = m_generator.next();
3845 if (success) {
3846 m_cache = m_function(m_generator.get());
3847 }
3848 return success;
3849 }
3850 };
3851
3852 template <typename T, typename U, typename Func>
map(Func && function,GeneratorWrapper<U> && generator)3853 GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) {
3854 return GeneratorWrapper<T>(
3855 pf::make_unique<MapGenerator<T, U, Func>>(std::forward<Func>(function), std::move(generator))
3856 );
3857 }
3858 template <typename T, typename Func>
map(Func && function,GeneratorWrapper<T> && generator)3859 GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<T>&& generator) {
3860 return GeneratorWrapper<T>(
3861 pf::make_unique<MapGenerator<T, T, Func>>(std::forward<Func>(function), std::move(generator))
3862 );
3863 }
3864
3865 template <typename T>
3866 class ChunkGenerator final : public IGenerator<std::vector<T>> {
3867 std::vector<T> m_chunk;
3868 size_t m_chunk_size;
3869 GeneratorWrapper<T> m_generator;
3870 bool m_used_up = false;
3871 public:
ChunkGenerator(size_t size,GeneratorWrapper<T> generator)3872 ChunkGenerator(size_t size, GeneratorWrapper<T> generator) :
3873 m_chunk_size(size), m_generator(std::move(generator))
3874 {
3875 m_chunk.reserve(m_chunk_size);
3876 m_chunk.push_back(m_generator.get());
3877 for (size_t i = 1; i < m_chunk_size; ++i) {
3878 if (!m_generator.next()) {
3879 Catch::throw_exception(GeneratorException("Not enough values to initialize the first chunk"));
3880 }
3881 m_chunk.push_back(m_generator.get());
3882 }
3883 }
get() const3884 std::vector<T> const& get() const override {
3885 return m_chunk;
3886 }
next()3887 bool next() override {
3888 m_chunk.clear();
3889 for (size_t idx = 0; idx < m_chunk_size; ++idx) {
3890 if (!m_generator.next()) {
3891 return false;
3892 }
3893 m_chunk.push_back(m_generator.get());
3894 }
3895 return true;
3896 }
3897 };
3898
3899 template <typename T>
chunk(size_t size,GeneratorWrapper<T> && generator)3900 GeneratorWrapper<std::vector<T>> chunk(size_t size, GeneratorWrapper<T>&& generator) {
3901 return GeneratorWrapper<std::vector<T>>(
3902 pf::make_unique<ChunkGenerator<T>>(size, std::move(generator))
3903 );
3904 }
3905
3906 } // namespace Generators
3907 } // namespace Catch
3908
3909 // end catch_generators_generic.hpp
3910 // start catch_generators_specific.hpp
3911
3912 // start catch_context.h
3913
3914 #include <memory>
3915
3916 namespace Catch {
3917
3918 struct IResultCapture;
3919 struct IRunner;
3920 struct IConfig;
3921 struct IMutableContext;
3922
3923 using IConfigPtr = std::shared_ptr<IConfig const>;
3924
3925 struct IContext
3926 {
3927 virtual ~IContext();
3928
3929 virtual IResultCapture* getResultCapture() = 0;
3930 virtual IRunner* getRunner() = 0;
3931 virtual IConfigPtr const& getConfig() const = 0;
3932 };
3933
3934 struct IMutableContext : IContext
3935 {
3936 virtual ~IMutableContext();
3937 virtual void setResultCapture( IResultCapture* resultCapture ) = 0;
3938 virtual void setRunner( IRunner* runner ) = 0;
3939 virtual void setConfig( IConfigPtr const& config ) = 0;
3940
3941 private:
3942 static IMutableContext *currentContext;
3943 friend IMutableContext& getCurrentMutableContext();
3944 friend void cleanUpContext();
3945 static void createContext();
3946 };
3947
getCurrentMutableContext()3948 inline IMutableContext& getCurrentMutableContext()
3949 {
3950 if( !IMutableContext::currentContext )
3951 IMutableContext::createContext();
3952 return *IMutableContext::currentContext;
3953 }
3954
getCurrentContext()3955 inline IContext& getCurrentContext()
3956 {
3957 return getCurrentMutableContext();
3958 }
3959
3960 void cleanUpContext();
3961 }
3962
3963 // end catch_context.h
3964 // start catch_interfaces_config.h
3965
3966 #include <iosfwd>
3967 #include <string>
3968 #include <vector>
3969 #include <memory>
3970
3971 namespace Catch {
3972
3973 enum class Verbosity {
3974 Quiet = 0,
3975 Normal,
3976 High
3977 };
3978
3979 struct WarnAbout { enum What {
3980 Nothing = 0x00,
3981 NoAssertions = 0x01,
3982 NoTests = 0x02
3983 }; };
3984
3985 struct ShowDurations { enum OrNot {
3986 DefaultForReporter,
3987 Always,
3988 Never
3989 }; };
3990 struct RunTests { enum InWhatOrder {
3991 InDeclarationOrder,
3992 InLexicographicalOrder,
3993 InRandomOrder
3994 }; };
3995 struct UseColour { enum YesOrNo {
3996 Auto,
3997 Yes,
3998 No
3999 }; };
4000 struct WaitForKeypress { enum When {
4001 Never,
4002 BeforeStart = 1,
4003 BeforeExit = 2,
4004 BeforeStartAndExit = BeforeStart | BeforeExit
4005 }; };
4006
4007 class TestSpec;
4008
4009 struct IConfig : NonCopyable {
4010
4011 virtual ~IConfig();
4012
4013 virtual bool allowThrows() const = 0;
4014 virtual std::ostream& stream() const = 0;
4015 virtual std::string name() const = 0;
4016 virtual bool includeSuccessfulResults() const = 0;
4017 virtual bool shouldDebugBreak() const = 0;
4018 virtual bool warnAboutMissingAssertions() const = 0;
4019 virtual bool warnAboutNoTests() const = 0;
4020 virtual int abortAfter() const = 0;
4021 virtual bool showInvisibles() const = 0;
4022 virtual ShowDurations::OrNot showDurations() const = 0;
4023 virtual TestSpec const& testSpec() const = 0;
4024 virtual bool hasTestFilters() const = 0;
4025 virtual RunTests::InWhatOrder runOrder() const = 0;
4026 virtual unsigned int rngSeed() const = 0;
4027 virtual int benchmarkResolutionMultiple() const = 0;
4028 virtual UseColour::YesOrNo useColour() const = 0;
4029 virtual std::vector<std::string> const& getSectionsToRun() const = 0;
4030 virtual Verbosity verbosity() const = 0;
4031 };
4032
4033 using IConfigPtr = std::shared_ptr<IConfig const>;
4034 }
4035
4036 // end catch_interfaces_config.h
4037 #include <random>
4038
4039 namespace Catch {
4040 namespace Generators {
4041
4042 template <typename Float>
4043 class RandomFloatingGenerator final : public IGenerator<Float> {
4044 // FIXME: What is the right seed?
4045 std::minstd_rand m_rand;
4046 std::uniform_real_distribution<Float> m_dist;
4047 Float m_current_number;
4048 public:
4049
RandomFloatingGenerator(Float a,Float b)4050 RandomFloatingGenerator(Float a, Float b):
4051 m_rand(getCurrentContext().getConfig()->rngSeed()),
4052 m_dist(a, b) {
4053 static_cast<void>(next());
4054 }
4055
get() const4056 Float const& get() const override {
4057 return m_current_number;
4058 }
next()4059 bool next() override {
4060 m_current_number = m_dist(m_rand);
4061 return true;
4062 }
4063 };
4064
4065 template <typename Integer>
4066 class RandomIntegerGenerator final : public IGenerator<Integer> {
4067 std::minstd_rand m_rand;
4068 std::uniform_int_distribution<Integer> m_dist;
4069 Integer m_current_number;
4070 public:
4071
RandomIntegerGenerator(Integer a,Integer b)4072 RandomIntegerGenerator(Integer a, Integer b):
4073 m_rand(getCurrentContext().getConfig()->rngSeed()),
4074 m_dist(a, b) {
4075 static_cast<void>(next());
4076 }
4077
get() const4078 Integer const& get() const override {
4079 return m_current_number;
4080 }
next()4081 bool next() override {
4082 m_current_number = m_dist(m_rand);
4083 return true;
4084 }
4085 };
4086
4087 // TODO: Ideally this would be also constrained against the various char types,
4088 // but I don't expect users to run into that in practice.
4089 template <typename T>
4090 typename std::enable_if<std::is_integral<T>::value && !std::is_same<T, bool>::value,
4091 GeneratorWrapper<T>>::type
random(T a,T b)4092 random(T a, T b) {
4093 return GeneratorWrapper<T>(
4094 pf::make_unique<RandomIntegerGenerator<T>>(a, b)
4095 );
4096 }
4097
4098 template <typename T>
4099 typename std::enable_if<std::is_floating_point<T>::value,
4100 GeneratorWrapper<T>>::type
random(T a,T b)4101 random(T a, T b) {
4102 return GeneratorWrapper<T>(
4103 pf::make_unique<RandomFloatingGenerator<T>>(a, b)
4104 );
4105 }
4106
4107 template <typename T>
4108 class RangeGenerator final : public IGenerator<T> {
4109 T m_current;
4110 T m_end;
4111 T m_step;
4112 bool m_positive;
4113
4114 public:
RangeGenerator(T const & start,T const & end,T const & step)4115 RangeGenerator(T const& start, T const& end, T const& step):
4116 m_current(start),
4117 m_end(end),
4118 m_step(step),
4119 m_positive(m_step > T(0))
4120 {
4121 assert(m_current != m_end && "Range start and end cannot be equal");
4122 assert(m_step != T(0) && "Step size cannot be zero");
4123 assert(((m_positive && m_current <= m_end) || (!m_positive && m_current >= m_end)) && "Step moves away from end");
4124 }
4125
RangeGenerator(T const & start,T const & end)4126 RangeGenerator(T const& start, T const& end):
4127 RangeGenerator(start, end, (start < end) ? T(1) : T(-1))
4128 {}
4129
get() const4130 T const& get() const override {
4131 return m_current;
4132 }
4133
next()4134 bool next() override {
4135 m_current += m_step;
4136 return (m_positive) ? (m_current < m_end) : (m_current > m_end);
4137 }
4138 };
4139
4140 template <typename T>
range(T const & start,T const & end,T const & step)4141 GeneratorWrapper<T> range(T const& start, T const& end, T const& step) {
4142 static_assert(std::is_integral<T>::value && !std::is_same<T, bool>::value, "Type must be an integer");
4143 return GeneratorWrapper<T>(pf::make_unique<RangeGenerator<T>>(start, end, step));
4144 }
4145
4146 template <typename T>
range(T const & start,T const & end)4147 GeneratorWrapper<T> range(T const& start, T const& end) {
4148 static_assert(std::is_integral<T>::value && !std::is_same<T, bool>::value, "Type must be an integer");
4149 return GeneratorWrapper<T>(pf::make_unique<RangeGenerator<T>>(start, end));
4150 }
4151
4152 } // namespace Generators
4153 } // namespace Catch
4154
4155 // end catch_generators_specific.hpp
4156
4157 // These files are included here so the single_include script doesn't put them
4158 // in the conditionally compiled sections
4159 // start catch_test_case_info.h
4160
4161 #include <string>
4162 #include <vector>
4163 #include <memory>
4164
4165 #ifdef __clang__
4166 #pragma clang diagnostic push
4167 #pragma clang diagnostic ignored "-Wpadded"
4168 #endif
4169
4170 namespace Catch {
4171
4172 struct ITestInvoker;
4173
4174 struct TestCaseInfo {
4175 enum SpecialProperties{
4176 None = 0,
4177 IsHidden = 1 << 1,
4178 ShouldFail = 1 << 2,
4179 MayFail = 1 << 3,
4180 Throws = 1 << 4,
4181 NonPortable = 1 << 5,
4182 Benchmark = 1 << 6
4183 };
4184
4185 TestCaseInfo( std::string const& _name,
4186 std::string const& _className,
4187 std::string const& _description,
4188 std::vector<std::string> const& _tags,
4189 SourceLineInfo const& _lineInfo );
4190
4191 friend void setTags( TestCaseInfo& testCaseInfo, std::vector<std::string> tags );
4192
4193 bool isHidden() const;
4194 bool throws() const;
4195 bool okToFail() const;
4196 bool expectedToFail() const;
4197
4198 std::string tagsAsString() const;
4199
4200 std::string name;
4201 std::string className;
4202 std::string description;
4203 std::vector<std::string> tags;
4204 std::vector<std::string> lcaseTags;
4205 SourceLineInfo lineInfo;
4206 SpecialProperties properties;
4207 };
4208
4209 class TestCase : public TestCaseInfo {
4210 public:
4211
4212 TestCase( ITestInvoker* testCase, TestCaseInfo&& info );
4213
4214 TestCase withName( std::string const& _newName ) const;
4215
4216 void invoke() const;
4217
4218 TestCaseInfo const& getTestCaseInfo() const;
4219
4220 bool operator == ( TestCase const& other ) const;
4221 bool operator < ( TestCase const& other ) const;
4222
4223 private:
4224 std::shared_ptr<ITestInvoker> test;
4225 };
4226
4227 TestCase makeTestCase( ITestInvoker* testCase,
4228 std::string const& className,
4229 NameAndTags const& nameAndTags,
4230 SourceLineInfo const& lineInfo );
4231 }
4232
4233 #ifdef __clang__
4234 #pragma clang diagnostic pop
4235 #endif
4236
4237 // end catch_test_case_info.h
4238 // start catch_interfaces_runner.h
4239
4240 namespace Catch {
4241
4242 struct IRunner {
4243 virtual ~IRunner();
4244 virtual bool aborting() const = 0;
4245 };
4246 }
4247
4248 // end catch_interfaces_runner.h
4249
4250 #ifdef __OBJC__
4251 // start catch_objc.hpp
4252
4253 #import <objc/runtime.h>
4254
4255 #include <string>
4256
4257 // NB. Any general catch headers included here must be included
4258 // in catch.hpp first to make sure they are included by the single
4259 // header for non obj-usage
4260
4261 ///////////////////////////////////////////////////////////////////////////////
4262 // This protocol is really only here for (self) documenting purposes, since
4263 // all its methods are optional.
4264 @protocol OcFixture
4265
4266 @optional
4267
4268 -(void) setUp;
4269 -(void) tearDown;
4270
4271 @end
4272
4273 namespace Catch {
4274
4275 class OcMethod : public ITestInvoker {
4276
4277 public:
OcMethod(Class cls,SEL sel)4278 OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {}
4279
invoke() const4280 virtual void invoke() const {
4281 id obj = [[m_cls alloc] init];
4282
4283 performOptionalSelector( obj, @selector(setUp) );
4284 performOptionalSelector( obj, m_sel );
4285 performOptionalSelector( obj, @selector(tearDown) );
4286
4287 arcSafeRelease( obj );
4288 }
4289 private:
~OcMethod()4290 virtual ~OcMethod() {}
4291
4292 Class m_cls;
4293 SEL m_sel;
4294 };
4295
4296 namespace Detail{
4297
getAnnotation(Class cls,std::string const & annotationName,std::string const & testCaseName)4298 inline std::string getAnnotation( Class cls,
4299 std::string const& annotationName,
4300 std::string const& testCaseName ) {
4301 NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()];
4302 SEL sel = NSSelectorFromString( selStr );
4303 arcSafeRelease( selStr );
4304 id value = performOptionalSelector( cls, sel );
4305 if( value )
4306 return [(NSString*)value UTF8String];
4307 return "";
4308 }
4309 }
4310
registerTestMethods()4311 inline std::size_t registerTestMethods() {
4312 std::size_t noTestMethods = 0;
4313 int noClasses = objc_getClassList( nullptr, 0 );
4314
4315 Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses);
4316 objc_getClassList( classes, noClasses );
4317
4318 for( int c = 0; c < noClasses; c++ ) {
4319 Class cls = classes[c];
4320 {
4321 u_int count;
4322 Method* methods = class_copyMethodList( cls, &count );
4323 for( u_int m = 0; m < count ; m++ ) {
4324 SEL selector = method_getName(methods[m]);
4325 std::string methodName = sel_getName(selector);
4326 if( startsWith( methodName, "Catch_TestCase_" ) ) {
4327 std::string testCaseName = methodName.substr( 15 );
4328 std::string name = Detail::getAnnotation( cls, "Name", testCaseName );
4329 std::string desc = Detail::getAnnotation( cls, "Description", testCaseName );
4330 const char* className = class_getName( cls );
4331
4332 getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, NameAndTags( name.c_str(), desc.c_str() ), SourceLineInfo("",0) ) );
4333 noTestMethods++;
4334 }
4335 }
4336 free(methods);
4337 }
4338 }
4339 return noTestMethods;
4340 }
4341
4342 #if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
4343
4344 namespace Matchers {
4345 namespace Impl {
4346 namespace NSStringMatchers {
4347
4348 struct StringHolder : MatcherBase<NSString*>{
StringHolderCatch::Matchers::Impl::NSStringMatchers::StringHolder4349 StringHolder( NSString* substr ) : m_substr( [substr copy] ){}
StringHolderCatch::Matchers::Impl::NSStringMatchers::StringHolder4350 StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){}
StringHolderCatch::Matchers::Impl::NSStringMatchers::StringHolder4351 StringHolder() {
4352 arcSafeRelease( m_substr );
4353 }
4354
matchCatch::Matchers::Impl::NSStringMatchers::StringHolder4355 bool match( NSString* arg ) const override {
4356 return false;
4357 }
4358
4359 NSString* CATCH_ARC_STRONG m_substr;
4360 };
4361
4362 struct Equals : StringHolder {
EqualsCatch::Matchers::Impl::NSStringMatchers::Equals4363 Equals( NSString* substr ) : StringHolder( substr ){}
4364
matchCatch::Matchers::Impl::NSStringMatchers::Equals4365 bool match( NSString* str ) const override {
4366 return (str != nil || m_substr == nil ) &&
4367 [str isEqualToString:m_substr];
4368 }
4369
describeCatch::Matchers::Impl::NSStringMatchers::Equals4370 std::string describe() const override {
4371 return "equals string: " + Catch::Detail::stringify( m_substr );
4372 }
4373 };
4374
4375 struct Contains : StringHolder {
ContainsCatch::Matchers::Impl::NSStringMatchers::Contains4376 Contains( NSString* substr ) : StringHolder( substr ){}
4377
matchCatch::Matchers::Impl::NSStringMatchers::Contains4378 bool match( NSString* str ) const {
4379 return (str != nil || m_substr == nil ) &&
4380 [str rangeOfString:m_substr].location != NSNotFound;
4381 }
4382
describeCatch::Matchers::Impl::NSStringMatchers::Contains4383 std::string describe() const override {
4384 return "contains string: " + Catch::Detail::stringify( m_substr );
4385 }
4386 };
4387
4388 struct StartsWith : StringHolder {
StartsWithCatch::Matchers::Impl::NSStringMatchers::StartsWith4389 StartsWith( NSString* substr ) : StringHolder( substr ){}
4390
matchCatch::Matchers::Impl::NSStringMatchers::StartsWith4391 bool match( NSString* str ) const override {
4392 return (str != nil || m_substr == nil ) &&
4393 [str rangeOfString:m_substr].location == 0;
4394 }
4395
describeCatch::Matchers::Impl::NSStringMatchers::StartsWith4396 std::string describe() const override {
4397 return "starts with: " + Catch::Detail::stringify( m_substr );
4398 }
4399 };
4400 struct EndsWith : StringHolder {
EndsWithCatch::Matchers::Impl::NSStringMatchers::EndsWith4401 EndsWith( NSString* substr ) : StringHolder( substr ){}
4402
matchCatch::Matchers::Impl::NSStringMatchers::EndsWith4403 bool match( NSString* str ) const override {
4404 return (str != nil || m_substr == nil ) &&
4405 [str rangeOfString:m_substr].location == [str length] - [m_substr length];
4406 }
4407
describeCatch::Matchers::Impl::NSStringMatchers::EndsWith4408 std::string describe() const override {
4409 return "ends with: " + Catch::Detail::stringify( m_substr );
4410 }
4411 };
4412
4413 } // namespace NSStringMatchers
4414 } // namespace Impl
4415
4416 inline Impl::NSStringMatchers::Equals
Equals(NSString * substr)4417 Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); }
4418
4419 inline Impl::NSStringMatchers::Contains
Contains(NSString * substr)4420 Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); }
4421
4422 inline Impl::NSStringMatchers::StartsWith
StartsWith(NSString * substr)4423 StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); }
4424
4425 inline Impl::NSStringMatchers::EndsWith
EndsWith(NSString * substr)4426 EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); }
4427
4428 } // namespace Matchers
4429
4430 using namespace Matchers;
4431
4432 #endif // CATCH_CONFIG_DISABLE_MATCHERS
4433
4434 } // namespace Catch
4435
4436 ///////////////////////////////////////////////////////////////////////////////
4437 #define OC_MAKE_UNIQUE_NAME( root, uniqueSuffix ) root##uniqueSuffix
4438 #define OC_TEST_CASE2( name, desc, uniqueSuffix ) \
4439 +(NSString*) OC_MAKE_UNIQUE_NAME( Catch_Name_test_, uniqueSuffix ) \
4440 { \
4441 return @ name; \
4442 } \
4443 +(NSString*) OC_MAKE_UNIQUE_NAME( Catch_Description_test_, uniqueSuffix ) \
4444 { \
4445 return @ desc; \
4446 } \
4447 -(void) OC_MAKE_UNIQUE_NAME( Catch_TestCase_test_, uniqueSuffix )
4448
4449 #define OC_TEST_CASE( name, desc ) OC_TEST_CASE2( name, desc, __LINE__ )
4450
4451 // end catch_objc.hpp
4452 #endif
4453
4454 #ifdef CATCH_CONFIG_EXTERNAL_INTERFACES
4455 // start catch_external_interfaces.h
4456
4457 // start catch_reporter_bases.hpp
4458
4459 // start catch_interfaces_reporter.h
4460
4461 // start catch_config.hpp
4462
4463 // start catch_test_spec_parser.h
4464
4465 #ifdef __clang__
4466 #pragma clang diagnostic push
4467 #pragma clang diagnostic ignored "-Wpadded"
4468 #endif
4469
4470 // start catch_test_spec.h
4471
4472 #ifdef __clang__
4473 #pragma clang diagnostic push
4474 #pragma clang diagnostic ignored "-Wpadded"
4475 #endif
4476
4477 // start catch_wildcard_pattern.h
4478
4479 namespace Catch
4480 {
4481 class WildcardPattern {
4482 enum WildcardPosition {
4483 NoWildcard = 0,
4484 WildcardAtStart = 1,
4485 WildcardAtEnd = 2,
4486 WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd
4487 };
4488
4489 public:
4490
4491 WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity );
4492 virtual ~WildcardPattern() = default;
4493 virtual bool matches( std::string const& str ) const;
4494
4495 private:
4496 std::string adjustCase( std::string const& str ) const;
4497 CaseSensitive::Choice m_caseSensitivity;
4498 WildcardPosition m_wildcard = NoWildcard;
4499 std::string m_pattern;
4500 };
4501 }
4502
4503 // end catch_wildcard_pattern.h
4504 #include <string>
4505 #include <vector>
4506 #include <memory>
4507
4508 namespace Catch {
4509
4510 class TestSpec {
4511 struct Pattern {
4512 virtual ~Pattern();
4513 virtual bool matches( TestCaseInfo const& testCase ) const = 0;
4514 };
4515 using PatternPtr = std::shared_ptr<Pattern>;
4516
4517 class NamePattern : public Pattern {
4518 public:
4519 NamePattern( std::string const& name );
4520 virtual ~NamePattern();
4521 virtual bool matches( TestCaseInfo const& testCase ) const override;
4522 private:
4523 WildcardPattern m_wildcardPattern;
4524 };
4525
4526 class TagPattern : public Pattern {
4527 public:
4528 TagPattern( std::string const& tag );
4529 virtual ~TagPattern();
4530 virtual bool matches( TestCaseInfo const& testCase ) const override;
4531 private:
4532 std::string m_tag;
4533 };
4534
4535 class ExcludedPattern : public Pattern {
4536 public:
4537 ExcludedPattern( PatternPtr const& underlyingPattern );
4538 virtual ~ExcludedPattern();
4539 virtual bool matches( TestCaseInfo const& testCase ) const override;
4540 private:
4541 PatternPtr m_underlyingPattern;
4542 };
4543
4544 struct Filter {
4545 std::vector<PatternPtr> m_patterns;
4546
4547 bool matches( TestCaseInfo const& testCase ) const;
4548 };
4549
4550 public:
4551 bool hasFilters() const;
4552 bool matches( TestCaseInfo const& testCase ) const;
4553
4554 private:
4555 std::vector<Filter> m_filters;
4556
4557 friend class TestSpecParser;
4558 };
4559 }
4560
4561 #ifdef __clang__
4562 #pragma clang diagnostic pop
4563 #endif
4564
4565 // end catch_test_spec.h
4566 // start catch_interfaces_tag_alias_registry.h
4567
4568 #include <string>
4569
4570 namespace Catch {
4571
4572 struct TagAlias;
4573
4574 struct ITagAliasRegistry {
4575 virtual ~ITagAliasRegistry();
4576 // Nullptr if not present
4577 virtual TagAlias const* find( std::string const& alias ) const = 0;
4578 virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0;
4579
4580 static ITagAliasRegistry const& get();
4581 };
4582
4583 } // end namespace Catch
4584
4585 // end catch_interfaces_tag_alias_registry.h
4586 namespace Catch {
4587
4588 class TestSpecParser {
4589 enum Mode{ None, Name, QuotedName, Tag, EscapedName };
4590 Mode m_mode = None;
4591 bool m_exclusion = false;
4592 std::size_t m_start = std::string::npos, m_pos = 0;
4593 std::string m_arg;
4594 std::vector<std::size_t> m_escapeChars;
4595 TestSpec::Filter m_currentFilter;
4596 TestSpec m_testSpec;
4597 ITagAliasRegistry const* m_tagAliases = nullptr;
4598
4599 public:
4600 TestSpecParser( ITagAliasRegistry const& tagAliases );
4601
4602 TestSpecParser& parse( std::string const& arg );
4603 TestSpec testSpec();
4604
4605 private:
4606 void visitChar( char c );
4607 void startNewMode( Mode mode, std::size_t start );
4608 void escape();
4609 std::string subString() const;
4610
4611 template<typename T>
addPattern()4612 void addPattern() {
4613 std::string token = subString();
4614 for( std::size_t i = 0; i < m_escapeChars.size(); ++i )
4615 token = token.substr( 0, m_escapeChars[i]-m_start-i ) + token.substr( m_escapeChars[i]-m_start-i+1 );
4616 m_escapeChars.clear();
4617 if( startsWith( token, "exclude:" ) ) {
4618 m_exclusion = true;
4619 token = token.substr( 8 );
4620 }
4621 if( !token.empty() ) {
4622 TestSpec::PatternPtr pattern = std::make_shared<T>( token );
4623 if( m_exclusion )
4624 pattern = std::make_shared<TestSpec::ExcludedPattern>( pattern );
4625 m_currentFilter.m_patterns.push_back( pattern );
4626 }
4627 m_exclusion = false;
4628 m_mode = None;
4629 }
4630
4631 void addFilter();
4632 };
4633 TestSpec parseTestSpec( std::string const& arg );
4634
4635 } // namespace Catch
4636
4637 #ifdef __clang__
4638 #pragma clang diagnostic pop
4639 #endif
4640
4641 // end catch_test_spec_parser.h
4642 // Libstdc++ doesn't like incomplete classes for unique_ptr
4643
4644 #include <memory>
4645 #include <vector>
4646 #include <string>
4647
4648 #ifndef CATCH_CONFIG_CONSOLE_WIDTH
4649 #define CATCH_CONFIG_CONSOLE_WIDTH 80
4650 #endif
4651
4652 namespace Catch {
4653
4654 struct IStream;
4655
4656 struct ConfigData {
4657 bool listTests = false;
4658 bool listTags = false;
4659 bool listReporters = false;
4660 bool listTestNamesOnly = false;
4661
4662 bool showSuccessfulTests = false;
4663 bool shouldDebugBreak = false;
4664 bool noThrow = false;
4665 bool showHelp = false;
4666 bool showInvisibles = false;
4667 bool filenamesAsTags = false;
4668 bool libIdentify = false;
4669
4670 int abortAfter = -1;
4671 unsigned int rngSeed = 0;
4672 int benchmarkResolutionMultiple = 100;
4673
4674 Verbosity verbosity = Verbosity::Normal;
4675 WarnAbout::What warnings = WarnAbout::Nothing;
4676 ShowDurations::OrNot showDurations = ShowDurations::DefaultForReporter;
4677 RunTests::InWhatOrder runOrder = RunTests::InDeclarationOrder;
4678 UseColour::YesOrNo useColour = UseColour::Auto;
4679 WaitForKeypress::When waitForKeypress = WaitForKeypress::Never;
4680
4681 std::string outputFilename;
4682 std::string name;
4683 std::string processName;
4684 #ifndef CATCH_CONFIG_DEFAULT_REPORTER
4685 #define CATCH_CONFIG_DEFAULT_REPORTER "console"
4686 #endif
4687 std::string reporterName = CATCH_CONFIG_DEFAULT_REPORTER;
4688 #undef CATCH_CONFIG_DEFAULT_REPORTER
4689
4690 std::vector<std::string> testsOrTags;
4691 std::vector<std::string> sectionsToRun;
4692 };
4693
4694 class Config : public IConfig {
4695 public:
4696
4697 Config() = default;
4698 Config( ConfigData const& data );
4699 virtual ~Config() = default;
4700
4701 std::string const& getFilename() const;
4702
4703 bool listTests() const;
4704 bool listTestNamesOnly() const;
4705 bool listTags() const;
4706 bool listReporters() const;
4707
4708 std::string getProcessName() const;
4709 std::string const& getReporterName() const;
4710
4711 std::vector<std::string> const& getTestsOrTags() const;
4712 std::vector<std::string> const& getSectionsToRun() const override;
4713
4714 virtual TestSpec const& testSpec() const override;
4715 bool hasTestFilters() const override;
4716
4717 bool showHelp() const;
4718
4719 // IConfig interface
4720 bool allowThrows() const override;
4721 std::ostream& stream() const override;
4722 std::string name() const override;
4723 bool includeSuccessfulResults() const override;
4724 bool warnAboutMissingAssertions() const override;
4725 bool warnAboutNoTests() const override;
4726 ShowDurations::OrNot showDurations() const override;
4727 RunTests::InWhatOrder runOrder() const override;
4728 unsigned int rngSeed() const override;
4729 int benchmarkResolutionMultiple() const override;
4730 UseColour::YesOrNo useColour() const override;
4731 bool shouldDebugBreak() const override;
4732 int abortAfter() const override;
4733 bool showInvisibles() const override;
4734 Verbosity verbosity() const override;
4735
4736 private:
4737
4738 IStream const* openStream();
4739 ConfigData m_data;
4740
4741 std::unique_ptr<IStream const> m_stream;
4742 TestSpec m_testSpec;
4743 bool m_hasTestFilters = false;
4744 };
4745
4746 } // end namespace Catch
4747
4748 // end catch_config.hpp
4749 // start catch_assertionresult.h
4750
4751 #include <string>
4752
4753 namespace Catch {
4754
4755 struct AssertionResultData
4756 {
4757 AssertionResultData() = delete;
4758
4759 AssertionResultData( ResultWas::OfType _resultType, LazyExpression const& _lazyExpression );
4760
4761 std::string message;
4762 mutable std::string reconstructedExpression;
4763 LazyExpression lazyExpression;
4764 ResultWas::OfType resultType;
4765
4766 std::string reconstructExpression() const;
4767 };
4768
4769 class AssertionResult {
4770 public:
4771 AssertionResult() = delete;
4772 AssertionResult( AssertionInfo const& info, AssertionResultData const& data );
4773
4774 bool isOk() const;
4775 bool succeeded() const;
4776 ResultWas::OfType getResultType() const;
4777 bool hasExpression() const;
4778 bool hasMessage() const;
4779 std::string getExpression() const;
4780 std::string getExpressionInMacro() const;
4781 bool hasExpandedExpression() const;
4782 std::string getExpandedExpression() const;
4783 std::string getMessage() const;
4784 SourceLineInfo getSourceInfo() const;
4785 StringRef getTestMacroName() const;
4786
4787 //protected:
4788 AssertionInfo m_info;
4789 AssertionResultData m_resultData;
4790 };
4791
4792 } // end namespace Catch
4793
4794 // end catch_assertionresult.h
4795 // start catch_option.hpp
4796
4797 namespace Catch {
4798
4799 // An optional type
4800 template<typename T>
4801 class Option {
4802 public:
Option()4803 Option() : nullableValue( nullptr ) {}
Option(T const & _value)4804 Option( T const& _value )
4805 : nullableValue( new( storage ) T( _value ) )
4806 {}
Option(Option const & _other)4807 Option( Option const& _other )
4808 : nullableValue( _other ? new( storage ) T( *_other ) : nullptr )
4809 {}
4810
~Option()4811 ~Option() {
4812 reset();
4813 }
4814
operator =(Option const & _other)4815 Option& operator= ( Option const& _other ) {
4816 if( &_other != this ) {
4817 reset();
4818 if( _other )
4819 nullableValue = new( storage ) T( *_other );
4820 }
4821 return *this;
4822 }
operator =(T const & _value)4823 Option& operator = ( T const& _value ) {
4824 reset();
4825 nullableValue = new( storage ) T( _value );
4826 return *this;
4827 }
4828
reset()4829 void reset() {
4830 if( nullableValue )
4831 nullableValue->~T();
4832 nullableValue = nullptr;
4833 }
4834
operator *()4835 T& operator*() { return *nullableValue; }
operator *() const4836 T const& operator*() const { return *nullableValue; }
operator ->()4837 T* operator->() { return nullableValue; }
operator ->() const4838 const T* operator->() const { return nullableValue; }
4839
valueOr(T const & defaultValue) const4840 T valueOr( T const& defaultValue ) const {
4841 return nullableValue ? *nullableValue : defaultValue;
4842 }
4843
some() const4844 bool some() const { return nullableValue != nullptr; }
none() const4845 bool none() const { return nullableValue == nullptr; }
4846
operator !() const4847 bool operator !() const { return nullableValue == nullptr; }
operator bool() const4848 explicit operator bool() const {
4849 return some();
4850 }
4851
4852 private:
4853 T *nullableValue;
4854 alignas(alignof(T)) char storage[sizeof(T)];
4855 };
4856
4857 } // end namespace Catch
4858
4859 // end catch_option.hpp
4860 #include <string>
4861 #include <iosfwd>
4862 #include <map>
4863 #include <set>
4864 #include <memory>
4865
4866 namespace Catch {
4867
4868 struct ReporterConfig {
4869 explicit ReporterConfig( IConfigPtr const& _fullConfig );
4870
4871 ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream );
4872
4873 std::ostream& stream() const;
4874 IConfigPtr fullConfig() const;
4875
4876 private:
4877 std::ostream* m_stream;
4878 IConfigPtr m_fullConfig;
4879 };
4880
4881 struct ReporterPreferences {
4882 bool shouldRedirectStdOut = false;
4883 bool shouldReportAllAssertions = false;
4884 };
4885
4886 template<typename T>
4887 struct LazyStat : Option<T> {
operator =Catch::LazyStat4888 LazyStat& operator=( T const& _value ) {
4889 Option<T>::operator=( _value );
4890 used = false;
4891 return *this;
4892 }
resetCatch::LazyStat4893 void reset() {
4894 Option<T>::reset();
4895 used = false;
4896 }
4897 bool used = false;
4898 };
4899
4900 struct TestRunInfo {
4901 TestRunInfo( std::string const& _name );
4902 std::string name;
4903 };
4904 struct GroupInfo {
4905 GroupInfo( std::string const& _name,
4906 std::size_t _groupIndex,
4907 std::size_t _groupsCount );
4908
4909 std::string name;
4910 std::size_t groupIndex;
4911 std::size_t groupsCounts;
4912 };
4913
4914 struct AssertionStats {
4915 AssertionStats( AssertionResult const& _assertionResult,
4916 std::vector<MessageInfo> const& _infoMessages,
4917 Totals const& _totals );
4918
4919 AssertionStats( AssertionStats const& ) = default;
4920 AssertionStats( AssertionStats && ) = default;
4921 AssertionStats& operator = ( AssertionStats const& ) = delete;
4922 AssertionStats& operator = ( AssertionStats && ) = delete;
4923 virtual ~AssertionStats();
4924
4925 AssertionResult assertionResult;
4926 std::vector<MessageInfo> infoMessages;
4927 Totals totals;
4928 };
4929
4930 struct SectionStats {
4931 SectionStats( SectionInfo const& _sectionInfo,
4932 Counts const& _assertions,
4933 double _durationInSeconds,
4934 bool _missingAssertions );
4935 SectionStats( SectionStats const& ) = default;
4936 SectionStats( SectionStats && ) = default;
4937 SectionStats& operator = ( SectionStats const& ) = default;
4938 SectionStats& operator = ( SectionStats && ) = default;
4939 virtual ~SectionStats();
4940
4941 SectionInfo sectionInfo;
4942 Counts assertions;
4943 double durationInSeconds;
4944 bool missingAssertions;
4945 };
4946
4947 struct TestCaseStats {
4948 TestCaseStats( TestCaseInfo const& _testInfo,
4949 Totals const& _totals,
4950 std::string const& _stdOut,
4951 std::string const& _stdErr,
4952 bool _aborting );
4953
4954 TestCaseStats( TestCaseStats const& ) = default;
4955 TestCaseStats( TestCaseStats && ) = default;
4956 TestCaseStats& operator = ( TestCaseStats const& ) = default;
4957 TestCaseStats& operator = ( TestCaseStats && ) = default;
4958 virtual ~TestCaseStats();
4959
4960 TestCaseInfo testInfo;
4961 Totals totals;
4962 std::string stdOut;
4963 std::string stdErr;
4964 bool aborting;
4965 };
4966
4967 struct TestGroupStats {
4968 TestGroupStats( GroupInfo const& _groupInfo,
4969 Totals const& _totals,
4970 bool _aborting );
4971 TestGroupStats( GroupInfo const& _groupInfo );
4972
4973 TestGroupStats( TestGroupStats const& ) = default;
4974 TestGroupStats( TestGroupStats && ) = default;
4975 TestGroupStats& operator = ( TestGroupStats const& ) = default;
4976 TestGroupStats& operator = ( TestGroupStats && ) = default;
4977 virtual ~TestGroupStats();
4978
4979 GroupInfo groupInfo;
4980 Totals totals;
4981 bool aborting;
4982 };
4983
4984 struct TestRunStats {
4985 TestRunStats( TestRunInfo const& _runInfo,
4986 Totals const& _totals,
4987 bool _aborting );
4988
4989 TestRunStats( TestRunStats const& ) = default;
4990 TestRunStats( TestRunStats && ) = default;
4991 TestRunStats& operator = ( TestRunStats const& ) = default;
4992 TestRunStats& operator = ( TestRunStats && ) = default;
4993 virtual ~TestRunStats();
4994
4995 TestRunInfo runInfo;
4996 Totals totals;
4997 bool aborting;
4998 };
4999
5000 struct BenchmarkInfo {
5001 std::string name;
5002 };
5003 struct BenchmarkStats {
5004 BenchmarkInfo info;
5005 std::size_t iterations;
5006 uint64_t elapsedTimeInNanoseconds;
5007 };
5008
5009 struct IStreamingReporter {
5010 virtual ~IStreamingReporter() = default;
5011
5012 // Implementing class must also provide the following static methods:
5013 // static std::string getDescription();
5014 // static std::set<Verbosity> getSupportedVerbosities()
5015
5016 virtual ReporterPreferences getPreferences() const = 0;
5017
5018 virtual void noMatchingTestCases( std::string const& spec ) = 0;
5019
5020 virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0;
5021 virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0;
5022
5023 virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0;
5024 virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0;
5025
5026 // *** experimental ***
benchmarkStartingCatch::IStreamingReporter5027 virtual void benchmarkStarting( BenchmarkInfo const& ) {}
5028
5029 virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0;
5030
5031 // The return value indicates if the messages buffer should be cleared:
5032 virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0;
5033
5034 // *** experimental ***
benchmarkEndedCatch::IStreamingReporter5035 virtual void benchmarkEnded( BenchmarkStats const& ) {}
5036
5037 virtual void sectionEnded( SectionStats const& sectionStats ) = 0;
5038 virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0;
5039 virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0;
5040 virtual void testRunEnded( TestRunStats const& testRunStats ) = 0;
5041
5042 virtual void skipTest( TestCaseInfo const& testInfo ) = 0;
5043
5044 // Default empty implementation provided
5045 virtual void fatalErrorEncountered( StringRef name );
5046
5047 virtual bool isMulti() const;
5048 };
5049 using IStreamingReporterPtr = std::unique_ptr<IStreamingReporter>;
5050
5051 struct IReporterFactory {
5052 virtual ~IReporterFactory();
5053 virtual IStreamingReporterPtr create( ReporterConfig const& config ) const = 0;
5054 virtual std::string getDescription() const = 0;
5055 };
5056 using IReporterFactoryPtr = std::shared_ptr<IReporterFactory>;
5057
5058 struct IReporterRegistry {
5059 using FactoryMap = std::map<std::string, IReporterFactoryPtr>;
5060 using Listeners = std::vector<IReporterFactoryPtr>;
5061
5062 virtual ~IReporterRegistry();
5063 virtual IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const = 0;
5064 virtual FactoryMap const& getFactories() const = 0;
5065 virtual Listeners const& getListeners() const = 0;
5066 };
5067
5068 } // end namespace Catch
5069
5070 // end catch_interfaces_reporter.h
5071 #include <algorithm>
5072 #include <cstring>
5073 #include <cfloat>
5074 #include <cstdio>
5075 #include <cassert>
5076 #include <memory>
5077 #include <ostream>
5078
5079 namespace Catch {
5080 void prepareExpandedExpression(AssertionResult& result);
5081
5082 // Returns double formatted as %.3f (format expected on output)
5083 std::string getFormattedDuration( double duration );
5084
5085 template<typename DerivedT>
5086 struct StreamingReporterBase : IStreamingReporter {
5087
StreamingReporterBaseCatch::StreamingReporterBase5088 StreamingReporterBase( ReporterConfig const& _config )
5089 : m_config( _config.fullConfig() ),
5090 stream( _config.stream() )
5091 {
5092 m_reporterPrefs.shouldRedirectStdOut = false;
5093 if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) )
5094 CATCH_ERROR( "Verbosity level not supported by this reporter" );
5095 }
5096
getPreferencesCatch::StreamingReporterBase5097 ReporterPreferences getPreferences() const override {
5098 return m_reporterPrefs;
5099 }
5100
getSupportedVerbositiesCatch::StreamingReporterBase5101 static std::set<Verbosity> getSupportedVerbosities() {
5102 return { Verbosity::Normal };
5103 }
5104
5105 ~StreamingReporterBase() override = default;
5106
noMatchingTestCasesCatch::StreamingReporterBase5107 void noMatchingTestCases(std::string const&) override {}
5108
testRunStartingCatch::StreamingReporterBase5109 void testRunStarting(TestRunInfo const& _testRunInfo) override {
5110 currentTestRunInfo = _testRunInfo;
5111 }
testGroupStartingCatch::StreamingReporterBase5112 void testGroupStarting(GroupInfo const& _groupInfo) override {
5113 currentGroupInfo = _groupInfo;
5114 }
5115
testCaseStartingCatch::StreamingReporterBase5116 void testCaseStarting(TestCaseInfo const& _testInfo) override {
5117 currentTestCaseInfo = _testInfo;
5118 }
sectionStartingCatch::StreamingReporterBase5119 void sectionStarting(SectionInfo const& _sectionInfo) override {
5120 m_sectionStack.push_back(_sectionInfo);
5121 }
5122
sectionEndedCatch::StreamingReporterBase5123 void sectionEnded(SectionStats const& /* _sectionStats */) override {
5124 m_sectionStack.pop_back();
5125 }
testCaseEndedCatch::StreamingReporterBase5126 void testCaseEnded(TestCaseStats const& /* _testCaseStats */) override {
5127 currentTestCaseInfo.reset();
5128 }
testGroupEndedCatch::StreamingReporterBase5129 void testGroupEnded(TestGroupStats const& /* _testGroupStats */) override {
5130 currentGroupInfo.reset();
5131 }
testRunEndedCatch::StreamingReporterBase5132 void testRunEnded(TestRunStats const& /* _testRunStats */) override {
5133 currentTestCaseInfo.reset();
5134 currentGroupInfo.reset();
5135 currentTestRunInfo.reset();
5136 }
5137
skipTestCatch::StreamingReporterBase5138 void skipTest(TestCaseInfo const&) override {
5139 // Don't do anything with this by default.
5140 // It can optionally be overridden in the derived class.
5141 }
5142
5143 IConfigPtr m_config;
5144 std::ostream& stream;
5145
5146 LazyStat<TestRunInfo> currentTestRunInfo;
5147 LazyStat<GroupInfo> currentGroupInfo;
5148 LazyStat<TestCaseInfo> currentTestCaseInfo;
5149
5150 std::vector<SectionInfo> m_sectionStack;
5151 ReporterPreferences m_reporterPrefs;
5152 };
5153
5154 template<typename DerivedT>
5155 struct CumulativeReporterBase : IStreamingReporter {
5156 template<typename T, typename ChildNodeT>
5157 struct Node {
NodeCatch::CumulativeReporterBase::Node5158 explicit Node( T const& _value ) : value( _value ) {}
~NodeCatch::CumulativeReporterBase::Node5159 virtual ~Node() {}
5160
5161 using ChildNodes = std::vector<std::shared_ptr<ChildNodeT>>;
5162 T value;
5163 ChildNodes children;
5164 };
5165 struct SectionNode {
SectionNodeCatch::CumulativeReporterBase::SectionNode5166 explicit SectionNode(SectionStats const& _stats) : stats(_stats) {}
5167 virtual ~SectionNode() = default;
5168
operator ==Catch::CumulativeReporterBase::SectionNode5169 bool operator == (SectionNode const& other) const {
5170 return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo;
5171 }
operator ==Catch::CumulativeReporterBase::SectionNode5172 bool operator == (std::shared_ptr<SectionNode> const& other) const {
5173 return operator==(*other);
5174 }
5175
5176 SectionStats stats;
5177 using ChildSections = std::vector<std::shared_ptr<SectionNode>>;
5178 using Assertions = std::vector<AssertionStats>;
5179 ChildSections childSections;
5180 Assertions assertions;
5181 std::string stdOut;
5182 std::string stdErr;
5183 };
5184
5185 struct BySectionInfo {
BySectionInfoCatch::CumulativeReporterBase::BySectionInfo5186 BySectionInfo( SectionInfo const& other ) : m_other( other ) {}
BySectionInfoCatch::CumulativeReporterBase::BySectionInfo5187 BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {}
operator ()Catch::CumulativeReporterBase::BySectionInfo5188 bool operator() (std::shared_ptr<SectionNode> const& node) const {
5189 return ((node->stats.sectionInfo.name == m_other.name) &&
5190 (node->stats.sectionInfo.lineInfo == m_other.lineInfo));
5191 }
5192 void operator=(BySectionInfo const&) = delete;
5193
5194 private:
5195 SectionInfo const& m_other;
5196 };
5197
5198 using TestCaseNode = Node<TestCaseStats, SectionNode>;
5199 using TestGroupNode = Node<TestGroupStats, TestCaseNode>;
5200 using TestRunNode = Node<TestRunStats, TestGroupNode>;
5201
CumulativeReporterBaseCatch::CumulativeReporterBase5202 CumulativeReporterBase( ReporterConfig const& _config )
5203 : m_config( _config.fullConfig() ),
5204 stream( _config.stream() )
5205 {
5206 m_reporterPrefs.shouldRedirectStdOut = false;
5207 if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) )
5208 CATCH_ERROR( "Verbosity level not supported by this reporter" );
5209 }
5210 ~CumulativeReporterBase() override = default;
5211
getPreferencesCatch::CumulativeReporterBase5212 ReporterPreferences getPreferences() const override {
5213 return m_reporterPrefs;
5214 }
5215
getSupportedVerbositiesCatch::CumulativeReporterBase5216 static std::set<Verbosity> getSupportedVerbosities() {
5217 return { Verbosity::Normal };
5218 }
5219
testRunStartingCatch::CumulativeReporterBase5220 void testRunStarting( TestRunInfo const& ) override {}
testGroupStartingCatch::CumulativeReporterBase5221 void testGroupStarting( GroupInfo const& ) override {}
5222
testCaseStartingCatch::CumulativeReporterBase5223 void testCaseStarting( TestCaseInfo const& ) override {}
5224
sectionStartingCatch::CumulativeReporterBase5225 void sectionStarting( SectionInfo const& sectionInfo ) override {
5226 SectionStats incompleteStats( sectionInfo, Counts(), 0, false );
5227 std::shared_ptr<SectionNode> node;
5228 if( m_sectionStack.empty() ) {
5229 if( !m_rootSection )
5230 m_rootSection = std::make_shared<SectionNode>( incompleteStats );
5231 node = m_rootSection;
5232 }
5233 else {
5234 SectionNode& parentNode = *m_sectionStack.back();
5235 auto it =
5236 std::find_if( parentNode.childSections.begin(),
5237 parentNode.childSections.end(),
5238 BySectionInfo( sectionInfo ) );
5239 if( it == parentNode.childSections.end() ) {
5240 node = std::make_shared<SectionNode>( incompleteStats );
5241 parentNode.childSections.push_back( node );
5242 }
5243 else
5244 node = *it;
5245 }
5246 m_sectionStack.push_back( node );
5247 m_deepestSection = std::move(node);
5248 }
5249
assertionStartingCatch::CumulativeReporterBase5250 void assertionStarting(AssertionInfo const&) override {}
5251
assertionEndedCatch::CumulativeReporterBase5252 bool assertionEnded(AssertionStats const& assertionStats) override {
5253 assert(!m_sectionStack.empty());
5254 // AssertionResult holds a pointer to a temporary DecomposedExpression,
5255 // which getExpandedExpression() calls to build the expression string.
5256 // Our section stack copy of the assertionResult will likely outlive the
5257 // temporary, so it must be expanded or discarded now to avoid calling
5258 // a destroyed object later.
5259 prepareExpandedExpression(const_cast<AssertionResult&>( assertionStats.assertionResult ) );
5260 SectionNode& sectionNode = *m_sectionStack.back();
5261 sectionNode.assertions.push_back(assertionStats);
5262 return true;
5263 }
sectionEndedCatch::CumulativeReporterBase5264 void sectionEnded(SectionStats const& sectionStats) override {
5265 assert(!m_sectionStack.empty());
5266 SectionNode& node = *m_sectionStack.back();
5267 node.stats = sectionStats;
5268 m_sectionStack.pop_back();
5269 }
testCaseEndedCatch::CumulativeReporterBase5270 void testCaseEnded(TestCaseStats const& testCaseStats) override {
5271 auto node = std::make_shared<TestCaseNode>(testCaseStats);
5272 assert(m_sectionStack.size() == 0);
5273 node->children.push_back(m_rootSection);
5274 m_testCases.push_back(node);
5275 m_rootSection.reset();
5276
5277 assert(m_deepestSection);
5278 m_deepestSection->stdOut = testCaseStats.stdOut;
5279 m_deepestSection->stdErr = testCaseStats.stdErr;
5280 }
testGroupEndedCatch::CumulativeReporterBase5281 void testGroupEnded(TestGroupStats const& testGroupStats) override {
5282 auto node = std::make_shared<TestGroupNode>(testGroupStats);
5283 node->children.swap(m_testCases);
5284 m_testGroups.push_back(node);
5285 }
testRunEndedCatch::CumulativeReporterBase5286 void testRunEnded(TestRunStats const& testRunStats) override {
5287 auto node = std::make_shared<TestRunNode>(testRunStats);
5288 node->children.swap(m_testGroups);
5289 m_testRuns.push_back(node);
5290 testRunEndedCumulative();
5291 }
5292 virtual void testRunEndedCumulative() = 0;
5293
skipTestCatch::CumulativeReporterBase5294 void skipTest(TestCaseInfo const&) override {}
5295
5296 IConfigPtr m_config;
5297 std::ostream& stream;
5298 std::vector<AssertionStats> m_assertions;
5299 std::vector<std::vector<std::shared_ptr<SectionNode>>> m_sections;
5300 std::vector<std::shared_ptr<TestCaseNode>> m_testCases;
5301 std::vector<std::shared_ptr<TestGroupNode>> m_testGroups;
5302
5303 std::vector<std::shared_ptr<TestRunNode>> m_testRuns;
5304
5305 std::shared_ptr<SectionNode> m_rootSection;
5306 std::shared_ptr<SectionNode> m_deepestSection;
5307 std::vector<std::shared_ptr<SectionNode>> m_sectionStack;
5308 ReporterPreferences m_reporterPrefs;
5309 };
5310
5311 template<char C>
getLineOfChars()5312 char const* getLineOfChars() {
5313 static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0};
5314 if( !*line ) {
5315 std::memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 );
5316 line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0;
5317 }
5318 return line;
5319 }
5320
5321 struct TestEventListenerBase : StreamingReporterBase<TestEventListenerBase> {
5322 TestEventListenerBase( ReporterConfig const& _config );
5323
5324 static std::set<Verbosity> getSupportedVerbosities();
5325
5326 void assertionStarting(AssertionInfo const&) override;
5327 bool assertionEnded(AssertionStats const&) override;
5328 };
5329
5330 } // end namespace Catch
5331
5332 // end catch_reporter_bases.hpp
5333 // start catch_console_colour.h
5334
5335 namespace Catch {
5336
5337 struct Colour {
5338 enum Code {
5339 None = 0,
5340
5341 White,
5342 Red,
5343 Green,
5344 Blue,
5345 Cyan,
5346 Yellow,
5347 Grey,
5348
5349 Bright = 0x10,
5350
5351 BrightRed = Bright | Red,
5352 BrightGreen = Bright | Green,
5353 LightGrey = Bright | Grey,
5354 BrightWhite = Bright | White,
5355 BrightYellow = Bright | Yellow,
5356
5357 // By intention
5358 FileName = LightGrey,
5359 Warning = BrightYellow,
5360 ResultError = BrightRed,
5361 ResultSuccess = BrightGreen,
5362 ResultExpectedFailure = Warning,
5363
5364 Error = BrightRed,
5365 Success = Green,
5366
5367 OriginalExpression = Cyan,
5368 ReconstructedExpression = BrightYellow,
5369
5370 SecondaryText = LightGrey,
5371 Headers = White
5372 };
5373
5374 // Use constructed object for RAII guard
5375 Colour( Code _colourCode );
5376 Colour( Colour&& other ) noexcept;
5377 Colour& operator=( Colour&& other ) noexcept;
5378 ~Colour();
5379
5380 // Use static method for one-shot changes
5381 static void use( Code _colourCode );
5382
5383 private:
5384 bool m_moved = false;
5385 };
5386
5387 std::ostream& operator << ( std::ostream& os, Colour const& );
5388
5389 } // end namespace Catch
5390
5391 // end catch_console_colour.h
5392 // start catch_reporter_registrars.hpp
5393
5394
5395 namespace Catch {
5396
5397 template<typename T>
5398 class ReporterRegistrar {
5399
5400 class ReporterFactory : public IReporterFactory {
5401
create(ReporterConfig const & config) const5402 virtual IStreamingReporterPtr create( ReporterConfig const& config ) const override {
5403 return std::unique_ptr<T>( new T( config ) );
5404 }
5405
getDescription() const5406 virtual std::string getDescription() const override {
5407 return T::getDescription();
5408 }
5409 };
5410
5411 public:
5412
ReporterRegistrar(std::string const & name)5413 explicit ReporterRegistrar( std::string const& name ) {
5414 getMutableRegistryHub().registerReporter( name, std::make_shared<ReporterFactory>() );
5415 }
5416 };
5417
5418 template<typename T>
5419 class ListenerRegistrar {
5420
5421 class ListenerFactory : public IReporterFactory {
5422
create(ReporterConfig const & config) const5423 virtual IStreamingReporterPtr create( ReporterConfig const& config ) const override {
5424 return std::unique_ptr<T>( new T( config ) );
5425 }
getDescription() const5426 virtual std::string getDescription() const override {
5427 return std::string();
5428 }
5429 };
5430
5431 public:
5432
ListenerRegistrar()5433 ListenerRegistrar() {
5434 getMutableRegistryHub().registerListener( std::make_shared<ListenerFactory>() );
5435 }
5436 };
5437 }
5438
5439 #if !defined(CATCH_CONFIG_DISABLE)
5440
5441 #define CATCH_REGISTER_REPORTER( name, reporterType ) \
5442 CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
5443 namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); } \
5444 CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
5445
5446 #define CATCH_REGISTER_LISTENER( listenerType ) \
5447 CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
5448 namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; } \
5449 CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
5450 #else // CATCH_CONFIG_DISABLE
5451
5452 #define CATCH_REGISTER_REPORTER(name, reporterType)
5453 #define CATCH_REGISTER_LISTENER(listenerType)
5454
5455 #endif // CATCH_CONFIG_DISABLE
5456
5457 // end catch_reporter_registrars.hpp
5458 // Allow users to base their work off existing reporters
5459 // start catch_reporter_compact.h
5460
5461 namespace Catch {
5462
5463 struct CompactReporter : StreamingReporterBase<CompactReporter> {
5464
5465 using StreamingReporterBase::StreamingReporterBase;
5466
5467 ~CompactReporter() override;
5468
5469 static std::string getDescription();
5470
5471 ReporterPreferences getPreferences() const override;
5472
5473 void noMatchingTestCases(std::string const& spec) override;
5474
5475 void assertionStarting(AssertionInfo const&) override;
5476
5477 bool assertionEnded(AssertionStats const& _assertionStats) override;
5478
5479 void sectionEnded(SectionStats const& _sectionStats) override;
5480
5481 void testRunEnded(TestRunStats const& _testRunStats) override;
5482
5483 };
5484
5485 } // end namespace Catch
5486
5487 // end catch_reporter_compact.h
5488 // start catch_reporter_console.h
5489
5490 #if defined(_MSC_VER)
5491 #pragma warning(push)
5492 #pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch
5493 // Note that 4062 (not all labels are handled
5494 // and default is missing) is enabled
5495 #endif
5496
5497 namespace Catch {
5498 // Fwd decls
5499 struct SummaryColumn;
5500 class TablePrinter;
5501
5502 struct ConsoleReporter : StreamingReporterBase<ConsoleReporter> {
5503 std::unique_ptr<TablePrinter> m_tablePrinter;
5504
5505 ConsoleReporter(ReporterConfig const& config);
5506 ~ConsoleReporter() override;
5507 static std::string getDescription();
5508
5509 void noMatchingTestCases(std::string const& spec) override;
5510
5511 void assertionStarting(AssertionInfo const&) override;
5512
5513 bool assertionEnded(AssertionStats const& _assertionStats) override;
5514
5515 void sectionStarting(SectionInfo const& _sectionInfo) override;
5516 void sectionEnded(SectionStats const& _sectionStats) override;
5517
5518 void benchmarkStarting(BenchmarkInfo const& info) override;
5519 void benchmarkEnded(BenchmarkStats const& stats) override;
5520
5521 void testCaseEnded(TestCaseStats const& _testCaseStats) override;
5522 void testGroupEnded(TestGroupStats const& _testGroupStats) override;
5523 void testRunEnded(TestRunStats const& _testRunStats) override;
5524
5525 private:
5526
5527 void lazyPrint();
5528
5529 void lazyPrintWithoutClosingBenchmarkTable();
5530 void lazyPrintRunInfo();
5531 void lazyPrintGroupInfo();
5532 void printTestCaseAndSectionHeader();
5533
5534 void printClosedHeader(std::string const& _name);
5535 void printOpenHeader(std::string const& _name);
5536
5537 // if string has a : in first line will set indent to follow it on
5538 // subsequent lines
5539 void printHeaderString(std::string const& _string, std::size_t indent = 0);
5540
5541 void printTotals(Totals const& totals);
5542 void printSummaryRow(std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row);
5543
5544 void printTotalsDivider(Totals const& totals);
5545 void printSummaryDivider();
5546
5547 private:
5548 bool m_headerPrinted = false;
5549 };
5550
5551 } // end namespace Catch
5552
5553 #if defined(_MSC_VER)
5554 #pragma warning(pop)
5555 #endif
5556
5557 // end catch_reporter_console.h
5558 // start catch_reporter_junit.h
5559
5560 // start catch_xmlwriter.h
5561
5562 #include <vector>
5563
5564 namespace Catch {
5565
5566 class XmlEncode {
5567 public:
5568 enum ForWhat { ForTextNodes, ForAttributes };
5569
5570 XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes );
5571
5572 void encodeTo( std::ostream& os ) const;
5573
5574 friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode );
5575
5576 private:
5577 std::string m_str;
5578 ForWhat m_forWhat;
5579 };
5580
5581 class XmlWriter {
5582 public:
5583
5584 class ScopedElement {
5585 public:
5586 ScopedElement( XmlWriter* writer );
5587
5588 ScopedElement( ScopedElement&& other ) noexcept;
5589 ScopedElement& operator=( ScopedElement&& other ) noexcept;
5590
5591 ~ScopedElement();
5592
5593 ScopedElement& writeText( std::string const& text, bool indent = true );
5594
5595 template<typename T>
writeAttribute(std::string const & name,T const & attribute)5596 ScopedElement& writeAttribute( std::string const& name, T const& attribute ) {
5597 m_writer->writeAttribute( name, attribute );
5598 return *this;
5599 }
5600
5601 private:
5602 mutable XmlWriter* m_writer = nullptr;
5603 };
5604
5605 XmlWriter( std::ostream& os = Catch::cout() );
5606 ~XmlWriter();
5607
5608 XmlWriter( XmlWriter const& ) = delete;
5609 XmlWriter& operator=( XmlWriter const& ) = delete;
5610
5611 XmlWriter& startElement( std::string const& name );
5612
5613 ScopedElement scopedElement( std::string const& name );
5614
5615 XmlWriter& endElement();
5616
5617 XmlWriter& writeAttribute( std::string const& name, std::string const& attribute );
5618
5619 XmlWriter& writeAttribute( std::string const& name, bool attribute );
5620
5621 template<typename T>
writeAttribute(std::string const & name,T const & attribute)5622 XmlWriter& writeAttribute( std::string const& name, T const& attribute ) {
5623 ReusableStringStream rss;
5624 rss << attribute;
5625 return writeAttribute( name, rss.str() );
5626 }
5627
5628 XmlWriter& writeText( std::string const& text, bool indent = true );
5629
5630 XmlWriter& writeComment( std::string const& text );
5631
5632 void writeStylesheetRef( std::string const& url );
5633
5634 XmlWriter& writeBlankLine();
5635
5636 void ensureTagClosed();
5637
5638 private:
5639
5640 void writeDeclaration();
5641
5642 void newlineIfNecessary();
5643
5644 bool m_tagIsOpen = false;
5645 bool m_needsNewline = false;
5646 std::vector<std::string> m_tags;
5647 std::string m_indent;
5648 std::ostream& m_os;
5649 };
5650
5651 }
5652
5653 // end catch_xmlwriter.h
5654 namespace Catch {
5655
5656 class JunitReporter : public CumulativeReporterBase<JunitReporter> {
5657 public:
5658 JunitReporter(ReporterConfig const& _config);
5659
5660 ~JunitReporter() override;
5661
5662 static std::string getDescription();
5663
5664 void noMatchingTestCases(std::string const& /*spec*/) override;
5665
5666 void testRunStarting(TestRunInfo const& runInfo) override;
5667
5668 void testGroupStarting(GroupInfo const& groupInfo) override;
5669
5670 void testCaseStarting(TestCaseInfo const& testCaseInfo) override;
5671 bool assertionEnded(AssertionStats const& assertionStats) override;
5672
5673 void testCaseEnded(TestCaseStats const& testCaseStats) override;
5674
5675 void testGroupEnded(TestGroupStats const& testGroupStats) override;
5676
5677 void testRunEndedCumulative() override;
5678
5679 void writeGroup(TestGroupNode const& groupNode, double suiteTime);
5680
5681 void writeTestCase(TestCaseNode const& testCaseNode);
5682
5683 void writeSection(std::string const& className,
5684 std::string const& rootName,
5685 SectionNode const& sectionNode);
5686
5687 void writeAssertions(SectionNode const& sectionNode);
5688 void writeAssertion(AssertionStats const& stats);
5689
5690 XmlWriter xml;
5691 Timer suiteTimer;
5692 std::string stdOutForSuite;
5693 std::string stdErrForSuite;
5694 unsigned int unexpectedExceptions = 0;
5695 bool m_okToFail = false;
5696 };
5697
5698 } // end namespace Catch
5699
5700 // end catch_reporter_junit.h
5701 // start catch_reporter_xml.h
5702
5703 namespace Catch {
5704 class XmlReporter : public StreamingReporterBase<XmlReporter> {
5705 public:
5706 XmlReporter(ReporterConfig const& _config);
5707
5708 ~XmlReporter() override;
5709
5710 static std::string getDescription();
5711
5712 virtual std::string getStylesheetRef() const;
5713
5714 void writeSourceInfo(SourceLineInfo const& sourceInfo);
5715
5716 public: // StreamingReporterBase
5717
5718 void noMatchingTestCases(std::string const& s) override;
5719
5720 void testRunStarting(TestRunInfo const& testInfo) override;
5721
5722 void testGroupStarting(GroupInfo const& groupInfo) override;
5723
5724 void testCaseStarting(TestCaseInfo const& testInfo) override;
5725
5726 void sectionStarting(SectionInfo const& sectionInfo) override;
5727
5728 void assertionStarting(AssertionInfo const&) override;
5729
5730 bool assertionEnded(AssertionStats const& assertionStats) override;
5731
5732 void sectionEnded(SectionStats const& sectionStats) override;
5733
5734 void testCaseEnded(TestCaseStats const& testCaseStats) override;
5735
5736 void testGroupEnded(TestGroupStats const& testGroupStats) override;
5737
5738 void testRunEnded(TestRunStats const& testRunStats) override;
5739
5740 private:
5741 Timer m_testCaseTimer;
5742 XmlWriter m_xml;
5743 int m_sectionDepth = 0;
5744 };
5745
5746 } // end namespace Catch
5747
5748 // end catch_reporter_xml.h
5749
5750 // end catch_external_interfaces.h
5751 #endif
5752
5753 #endif // ! CATCH_CONFIG_IMPL_ONLY
5754
5755 #ifdef CATCH_IMPL
5756 // start catch_impl.hpp
5757
5758 #ifdef __clang__
5759 #pragma clang diagnostic push
5760 #pragma clang diagnostic ignored "-Wweak-vtables"
5761 #endif
5762
5763 // Keep these here for external reporters
5764 // start catch_test_case_tracker.h
5765
5766 #include <string>
5767 #include <vector>
5768 #include <memory>
5769
5770 namespace Catch {
5771 namespace TestCaseTracking {
5772
5773 struct NameAndLocation {
5774 std::string name;
5775 SourceLineInfo location;
5776
5777 NameAndLocation( std::string const& _name, SourceLineInfo const& _location );
5778 };
5779
5780 struct ITracker;
5781
5782 using ITrackerPtr = std::shared_ptr<ITracker>;
5783
5784 struct ITracker {
5785 virtual ~ITracker();
5786
5787 // static queries
5788 virtual NameAndLocation const& nameAndLocation() const = 0;
5789
5790 // dynamic queries
5791 virtual bool isComplete() const = 0; // Successfully completed or failed
5792 virtual bool isSuccessfullyCompleted() const = 0;
5793 virtual bool isOpen() const = 0; // Started but not complete
5794 virtual bool hasChildren() const = 0;
5795
5796 virtual ITracker& parent() = 0;
5797
5798 // actions
5799 virtual void close() = 0; // Successfully complete
5800 virtual void fail() = 0;
5801 virtual void markAsNeedingAnotherRun() = 0;
5802
5803 virtual void addChild( ITrackerPtr const& child ) = 0;
5804 virtual ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) = 0;
5805 virtual void openChild() = 0;
5806
5807 // Debug/ checking
5808 virtual bool isSectionTracker() const = 0;
5809 virtual bool isGeneratorTracker() const = 0;
5810 };
5811
5812 class TrackerContext {
5813
5814 enum RunState {
5815 NotStarted,
5816 Executing,
5817 CompletedCycle
5818 };
5819
5820 ITrackerPtr m_rootTracker;
5821 ITracker* m_currentTracker = nullptr;
5822 RunState m_runState = NotStarted;
5823
5824 public:
5825
5826 static TrackerContext& instance();
5827
5828 ITracker& startRun();
5829 void endRun();
5830
5831 void startCycle();
5832 void completeCycle();
5833
5834 bool completedCycle() const;
5835 ITracker& currentTracker();
5836 void setCurrentTracker( ITracker* tracker );
5837 };
5838
5839 class TrackerBase : public ITracker {
5840 protected:
5841 enum CycleState {
5842 NotStarted,
5843 Executing,
5844 ExecutingChildren,
5845 NeedsAnotherRun,
5846 CompletedSuccessfully,
5847 Failed
5848 };
5849
5850 using Children = std::vector<ITrackerPtr>;
5851 NameAndLocation m_nameAndLocation;
5852 TrackerContext& m_ctx;
5853 ITracker* m_parent;
5854 Children m_children;
5855 CycleState m_runState = NotStarted;
5856
5857 public:
5858 TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent );
5859
5860 NameAndLocation const& nameAndLocation() const override;
5861 bool isComplete() const override;
5862 bool isSuccessfullyCompleted() const override;
5863 bool isOpen() const override;
5864 bool hasChildren() const override;
5865
5866 void addChild( ITrackerPtr const& child ) override;
5867
5868 ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) override;
5869 ITracker& parent() override;
5870
5871 void openChild() override;
5872
5873 bool isSectionTracker() const override;
5874 bool isGeneratorTracker() const override;
5875
5876 void open();
5877
5878 void close() override;
5879 void fail() override;
5880 void markAsNeedingAnotherRun() override;
5881
5882 private:
5883 void moveToParent();
5884 void moveToThis();
5885 };
5886
5887 class SectionTracker : public TrackerBase {
5888 std::vector<std::string> m_filters;
5889 public:
5890 SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent );
5891
5892 bool isSectionTracker() const override;
5893
5894 bool isComplete() const override;
5895
5896 static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation );
5897
5898 void tryOpen();
5899
5900 void addInitialFilters( std::vector<std::string> const& filters );
5901 void addNextFilters( std::vector<std::string> const& filters );
5902 };
5903
5904 } // namespace TestCaseTracking
5905
5906 using TestCaseTracking::ITracker;
5907 using TestCaseTracking::TrackerContext;
5908 using TestCaseTracking::SectionTracker;
5909
5910 } // namespace Catch
5911
5912 // end catch_test_case_tracker.h
5913
5914 // start catch_leak_detector.h
5915
5916 namespace Catch {
5917
5918 struct LeakDetector {
5919 LeakDetector();
5920 ~LeakDetector();
5921 };
5922
5923 }
5924 // end catch_leak_detector.h
5925 // Cpp files will be included in the single-header file here
5926 // start catch_approx.cpp
5927
5928 #include <cmath>
5929 #include <limits>
5930
5931 namespace {
5932
5933 // Performs equivalent check of std::fabs(lhs - rhs) <= margin
5934 // But without the subtraction to allow for INFINITY in comparison
marginComparison(double lhs,double rhs,double margin)5935 bool marginComparison(double lhs, double rhs, double margin) {
5936 return (lhs + margin >= rhs) && (rhs + margin >= lhs);
5937 }
5938
5939 }
5940
5941 namespace Catch {
5942 namespace Detail {
5943
Approx(double value)5944 Approx::Approx ( double value )
5945 : m_epsilon( std::numeric_limits<float>::epsilon()*100 ),
5946 m_margin( 0.0 ),
5947 m_scale( 0.0 ),
5948 m_value( value )
5949 {}
5950
custom()5951 Approx Approx::custom() {
5952 return Approx( 0 );
5953 }
5954
operator -() const5955 Approx Approx::operator-() const {
5956 auto temp(*this);
5957 temp.m_value = -temp.m_value;
5958 return temp;
5959 }
5960
toString() const5961 std::string Approx::toString() const {
5962 ReusableStringStream rss;
5963 rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )";
5964 return rss.str();
5965 }
5966
equalityComparisonImpl(const double other) const5967 bool Approx::equalityComparisonImpl(const double other) const {
5968 // First try with fixed margin, then compute margin based on epsilon, scale and Approx's value
5969 // Thanks to Richard Harris for his help refining the scaled margin value
5970 return marginComparison(m_value, other, m_margin) || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(m_value)));
5971 }
5972
setMargin(double margin)5973 void Approx::setMargin(double margin) {
5974 CATCH_ENFORCE(margin >= 0,
5975 "Invalid Approx::margin: " << margin << '.'
5976 << " Approx::Margin has to be non-negative.");
5977 m_margin = margin;
5978 }
5979
setEpsilon(double epsilon)5980 void Approx::setEpsilon(double epsilon) {
5981 CATCH_ENFORCE(epsilon >= 0 && epsilon <= 1.0,
5982 "Invalid Approx::epsilon: " << epsilon << '.'
5983 << " Approx::epsilon has to be in [0, 1]");
5984 m_epsilon = epsilon;
5985 }
5986
5987 } // end namespace Detail
5988
5989 namespace literals {
operator ""_a(long double val)5990 Detail::Approx operator "" _a(long double val) {
5991 return Detail::Approx(val);
5992 }
operator ""_a(unsigned long long val)5993 Detail::Approx operator "" _a(unsigned long long val) {
5994 return Detail::Approx(val);
5995 }
5996 } // end namespace literals
5997
convert(Catch::Detail::Approx const & value)5998 std::string StringMaker<Catch::Detail::Approx>::convert(Catch::Detail::Approx const& value) {
5999 return value.toString();
6000 }
6001
6002 } // end namespace Catch
6003 // end catch_approx.cpp
6004 // start catch_assertionhandler.cpp
6005
6006 // start catch_debugger.h
6007
6008 namespace Catch {
6009 bool isDebuggerActive();
6010 }
6011
6012 #ifdef CATCH_PLATFORM_MAC
6013
6014 #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */
6015
6016 #elif defined(CATCH_PLATFORM_LINUX)
6017 // If we can use inline assembler, do it because this allows us to break
6018 // directly at the location of the failing check instead of breaking inside
6019 // raise() called from it, i.e. one stack frame below.
6020 #if defined(__GNUC__) && (defined(__i386) || defined(__x86_64))
6021 #define CATCH_TRAP() asm volatile ("int $3") /* NOLINT */
6022 #else // Fall back to the generic way.
6023 #include <signal.h>
6024
6025 #define CATCH_TRAP() raise(SIGTRAP)
6026 #endif
6027 #elif defined(_MSC_VER)
6028 #define CATCH_TRAP() __debugbreak()
6029 #elif defined(__MINGW32__)
6030 extern "C" __declspec(dllimport) void __stdcall DebugBreak();
6031 #define CATCH_TRAP() DebugBreak()
6032 #endif
6033
6034 #ifdef CATCH_TRAP
6035 #define CATCH_BREAK_INTO_DEBUGGER() []{ if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } }()
6036 #else
6037 #define CATCH_BREAK_INTO_DEBUGGER() []{}()
6038 #endif
6039
6040 // end catch_debugger.h
6041 // start catch_run_context.h
6042
6043 // start catch_fatal_condition.h
6044
6045 // start catch_windows_h_proxy.h
6046
6047
6048 #if defined(CATCH_PLATFORM_WINDOWS)
6049
6050 #if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX)
6051 # define CATCH_DEFINED_NOMINMAX
6052 # define NOMINMAX
6053 #endif
6054 #if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN)
6055 # define CATCH_DEFINED_WIN32_LEAN_AND_MEAN
6056 # define WIN32_LEAN_AND_MEAN
6057 #endif
6058
6059 #ifdef __AFXDLL
6060 #include <AfxWin.h>
6061 #else
6062 #include <windows.h>
6063 #endif
6064
6065 #ifdef CATCH_DEFINED_NOMINMAX
6066 # undef NOMINMAX
6067 #endif
6068 #ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN
6069 # undef WIN32_LEAN_AND_MEAN
6070 #endif
6071
6072 #endif // defined(CATCH_PLATFORM_WINDOWS)
6073
6074 // end catch_windows_h_proxy.h
6075 #if defined( CATCH_CONFIG_WINDOWS_SEH )
6076
6077 namespace Catch {
6078
6079 struct FatalConditionHandler {
6080
6081 static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo);
6082 FatalConditionHandler();
6083 static void reset();
6084 ~FatalConditionHandler();
6085
6086 private:
6087 static bool isSet;
6088 static ULONG guaranteeSize;
6089 static PVOID exceptionHandlerHandle;
6090 };
6091
6092 } // namespace Catch
6093
6094 #elif defined ( CATCH_CONFIG_POSIX_SIGNALS )
6095
6096 #include <signal.h>
6097
6098 namespace Catch {
6099
6100 struct FatalConditionHandler {
6101
6102 static bool isSet;
6103 static struct sigaction oldSigActions[];
6104 static stack_t oldSigStack;
6105 static char altStackMem[];
6106
6107 static void handleSignal( int sig );
6108
6109 FatalConditionHandler();
6110 ~FatalConditionHandler();
6111 static void reset();
6112 };
6113
6114 } // namespace Catch
6115
6116 #else
6117
6118 namespace Catch {
6119 struct FatalConditionHandler {
6120 void reset();
6121 };
6122 }
6123
6124 #endif
6125
6126 // end catch_fatal_condition.h
6127 #include <string>
6128
6129 namespace Catch {
6130
6131 struct IMutableContext;
6132
6133 ///////////////////////////////////////////////////////////////////////////
6134
6135 class RunContext : public IResultCapture, public IRunner {
6136
6137 public:
6138 RunContext( RunContext const& ) = delete;
6139 RunContext& operator =( RunContext const& ) = delete;
6140
6141 explicit RunContext( IConfigPtr const& _config, IStreamingReporterPtr&& reporter );
6142
6143 ~RunContext() override;
6144
6145 void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount );
6146 void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount );
6147
6148 Totals runTest(TestCase const& testCase);
6149
6150 IConfigPtr config() const;
6151 IStreamingReporter& reporter() const;
6152
6153 public: // IResultCapture
6154
6155 // Assertion handlers
6156 void handleExpr
6157 ( AssertionInfo const& info,
6158 ITransientExpression const& expr,
6159 AssertionReaction& reaction ) override;
6160 void handleMessage
6161 ( AssertionInfo const& info,
6162 ResultWas::OfType resultType,
6163 StringRef const& message,
6164 AssertionReaction& reaction ) override;
6165 void handleUnexpectedExceptionNotThrown
6166 ( AssertionInfo const& info,
6167 AssertionReaction& reaction ) override;
6168 void handleUnexpectedInflightException
6169 ( AssertionInfo const& info,
6170 std::string const& message,
6171 AssertionReaction& reaction ) override;
6172 void handleIncomplete
6173 ( AssertionInfo const& info ) override;
6174 void handleNonExpr
6175 ( AssertionInfo const &info,
6176 ResultWas::OfType resultType,
6177 AssertionReaction &reaction ) override;
6178
6179 bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) override;
6180
6181 void sectionEnded( SectionEndInfo const& endInfo ) override;
6182 void sectionEndedEarly( SectionEndInfo const& endInfo ) override;
6183
6184 auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override;
6185
6186 void benchmarkStarting( BenchmarkInfo const& info ) override;
6187 void benchmarkEnded( BenchmarkStats const& stats ) override;
6188
6189 void pushScopedMessage( MessageInfo const& message ) override;
6190 void popScopedMessage( MessageInfo const& message ) override;
6191
6192 void emplaceUnscopedMessage( MessageBuilder const& builder ) override;
6193
6194 std::string getCurrentTestName() const override;
6195
6196 const AssertionResult* getLastResult() const override;
6197
6198 void exceptionEarlyReported() override;
6199
6200 void handleFatalErrorCondition( StringRef message ) override;
6201
6202 bool lastAssertionPassed() override;
6203
6204 void assertionPassed() override;
6205
6206 public:
6207 // !TBD We need to do this another way!
6208 bool aborting() const final;
6209
6210 private:
6211
6212 void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr );
6213 void invokeActiveTestCase();
6214
6215 void resetAssertionInfo();
6216 bool testForMissingAssertions( Counts& assertions );
6217
6218 void assertionEnded( AssertionResult const& result );
6219 void reportExpr
6220 ( AssertionInfo const &info,
6221 ResultWas::OfType resultType,
6222 ITransientExpression const *expr,
6223 bool negated );
6224
6225 void populateReaction( AssertionReaction& reaction );
6226
6227 private:
6228
6229 void handleUnfinishedSections();
6230
6231 TestRunInfo m_runInfo;
6232 IMutableContext& m_context;
6233 TestCase const* m_activeTestCase = nullptr;
6234 ITracker* m_testCaseTracker = nullptr;
6235 Option<AssertionResult> m_lastResult;
6236
6237 IConfigPtr m_config;
6238 Totals m_totals;
6239 IStreamingReporterPtr m_reporter;
6240 std::vector<MessageInfo> m_messages;
6241 std::vector<ScopedMessage> m_messageScopes; /* Keeps owners of so-called unscoped messages. */
6242 AssertionInfo m_lastAssertionInfo;
6243 std::vector<SectionEndInfo> m_unfinishedSections;
6244 std::vector<ITracker*> m_activeSections;
6245 TrackerContext m_trackerContext;
6246 bool m_lastAssertionPassed = false;
6247 bool m_shouldReportUnexpected = true;
6248 bool m_includeSuccessfulResults;
6249 };
6250
6251 } // end namespace Catch
6252
6253 // end catch_run_context.h
6254 namespace Catch {
6255
6256 namespace {
operator <<(std::ostream & os,ITransientExpression const & expr)6257 auto operator <<( std::ostream& os, ITransientExpression const& expr ) -> std::ostream& {
6258 expr.streamReconstructedExpression( os );
6259 return os;
6260 }
6261 }
6262
LazyExpression(bool isNegated)6263 LazyExpression::LazyExpression( bool isNegated )
6264 : m_isNegated( isNegated )
6265 {}
6266
LazyExpression(LazyExpression const & other)6267 LazyExpression::LazyExpression( LazyExpression const& other ) : m_isNegated( other.m_isNegated ) {}
6268
operator bool() const6269 LazyExpression::operator bool() const {
6270 return m_transientExpression != nullptr;
6271 }
6272
operator <<(std::ostream & os,LazyExpression const & lazyExpr)6273 auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream& {
6274 if( lazyExpr.m_isNegated )
6275 os << "!";
6276
6277 if( lazyExpr ) {
6278 if( lazyExpr.m_isNegated && lazyExpr.m_transientExpression->isBinaryExpression() )
6279 os << "(" << *lazyExpr.m_transientExpression << ")";
6280 else
6281 os << *lazyExpr.m_transientExpression;
6282 }
6283 else {
6284 os << "{** error - unchecked empty expression requested **}";
6285 }
6286 return os;
6287 }
6288
AssertionHandler(StringRef const & macroName,SourceLineInfo const & lineInfo,StringRef capturedExpression,ResultDisposition::Flags resultDisposition)6289 AssertionHandler::AssertionHandler
6290 ( StringRef const& macroName,
6291 SourceLineInfo const& lineInfo,
6292 StringRef capturedExpression,
6293 ResultDisposition::Flags resultDisposition )
6294 : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition },
6295 m_resultCapture( getResultCapture() )
6296 {}
6297
handleExpr(ITransientExpression const & expr)6298 void AssertionHandler::handleExpr( ITransientExpression const& expr ) {
6299 m_resultCapture.handleExpr( m_assertionInfo, expr, m_reaction );
6300 }
handleMessage(ResultWas::OfType resultType,StringRef const & message)6301 void AssertionHandler::handleMessage(ResultWas::OfType resultType, StringRef const& message) {
6302 m_resultCapture.handleMessage( m_assertionInfo, resultType, message, m_reaction );
6303 }
6304
allowThrows() const6305 auto AssertionHandler::allowThrows() const -> bool {
6306 return getCurrentContext().getConfig()->allowThrows();
6307 }
6308
complete()6309 void AssertionHandler::complete() {
6310 setCompleted();
6311 if( m_reaction.shouldDebugBreak ) {
6312
6313 // If you find your debugger stopping you here then go one level up on the
6314 // call-stack for the code that caused it (typically a failed assertion)
6315
6316 // (To go back to the test and change execution, jump over the throw, next)
6317 CATCH_BREAK_INTO_DEBUGGER();
6318 }
6319 if (m_reaction.shouldThrow) {
6320 #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
6321 throw Catch::TestFailureException();
6322 #else
6323 CATCH_ERROR( "Test failure requires aborting test!" );
6324 #endif
6325 }
6326 }
setCompleted()6327 void AssertionHandler::setCompleted() {
6328 m_completed = true;
6329 }
6330
handleUnexpectedInflightException()6331 void AssertionHandler::handleUnexpectedInflightException() {
6332 m_resultCapture.handleUnexpectedInflightException( m_assertionInfo, Catch::translateActiveException(), m_reaction );
6333 }
6334
handleExceptionThrownAsExpected()6335 void AssertionHandler::handleExceptionThrownAsExpected() {
6336 m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);
6337 }
handleExceptionNotThrownAsExpected()6338 void AssertionHandler::handleExceptionNotThrownAsExpected() {
6339 m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);
6340 }
6341
handleUnexpectedExceptionNotThrown()6342 void AssertionHandler::handleUnexpectedExceptionNotThrown() {
6343 m_resultCapture.handleUnexpectedExceptionNotThrown( m_assertionInfo, m_reaction );
6344 }
6345
handleThrowingCallSkipped()6346 void AssertionHandler::handleThrowingCallSkipped() {
6347 m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);
6348 }
6349
6350 // This is the overload that takes a string and infers the Equals matcher from it
6351 // The more general overload, that takes any string matcher, is in catch_capture_matchers.cpp
handleExceptionMatchExpr(AssertionHandler & handler,std::string const & str,StringRef const & matcherString)6352 void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef const& matcherString ) {
6353 handleExceptionMatchExpr( handler, Matchers::Equals( str ), matcherString );
6354 }
6355
6356 } // namespace Catch
6357 // end catch_assertionhandler.cpp
6358 // start catch_assertionresult.cpp
6359
6360 namespace Catch {
AssertionResultData(ResultWas::OfType _resultType,LazyExpression const & _lazyExpression)6361 AssertionResultData::AssertionResultData(ResultWas::OfType _resultType, LazyExpression const & _lazyExpression):
6362 lazyExpression(_lazyExpression),
6363 resultType(_resultType) {}
6364
reconstructExpression() const6365 std::string AssertionResultData::reconstructExpression() const {
6366
6367 if( reconstructedExpression.empty() ) {
6368 if( lazyExpression ) {
6369 ReusableStringStream rss;
6370 rss << lazyExpression;
6371 reconstructedExpression = rss.str();
6372 }
6373 }
6374 return reconstructedExpression;
6375 }
6376
AssertionResult(AssertionInfo const & info,AssertionResultData const & data)6377 AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data )
6378 : m_info( info ),
6379 m_resultData( data )
6380 {}
6381
6382 // Result was a success
succeeded() const6383 bool AssertionResult::succeeded() const {
6384 return Catch::isOk( m_resultData.resultType );
6385 }
6386
6387 // Result was a success, or failure is suppressed
isOk() const6388 bool AssertionResult::isOk() const {
6389 return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition );
6390 }
6391
getResultType() const6392 ResultWas::OfType AssertionResult::getResultType() const {
6393 return m_resultData.resultType;
6394 }
6395
hasExpression() const6396 bool AssertionResult::hasExpression() const {
6397 return m_info.capturedExpression[0] != 0;
6398 }
6399
hasMessage() const6400 bool AssertionResult::hasMessage() const {
6401 return !m_resultData.message.empty();
6402 }
6403
getExpression() const6404 std::string AssertionResult::getExpression() const {
6405 if( isFalseTest( m_info.resultDisposition ) )
6406 return "!(" + m_info.capturedExpression + ")";
6407 else
6408 return m_info.capturedExpression;
6409 }
6410
getExpressionInMacro() const6411 std::string AssertionResult::getExpressionInMacro() const {
6412 std::string expr;
6413 if( m_info.macroName[0] == 0 )
6414 expr = m_info.capturedExpression;
6415 else {
6416 expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 );
6417 expr += m_info.macroName;
6418 expr += "( ";
6419 expr += m_info.capturedExpression;
6420 expr += " )";
6421 }
6422 return expr;
6423 }
6424
hasExpandedExpression() const6425 bool AssertionResult::hasExpandedExpression() const {
6426 return hasExpression() && getExpandedExpression() != getExpression();
6427 }
6428
getExpandedExpression() const6429 std::string AssertionResult::getExpandedExpression() const {
6430 std::string expr = m_resultData.reconstructExpression();
6431 return expr.empty()
6432 ? getExpression()
6433 : expr;
6434 }
6435
getMessage() const6436 std::string AssertionResult::getMessage() const {
6437 return m_resultData.message;
6438 }
getSourceInfo() const6439 SourceLineInfo AssertionResult::getSourceInfo() const {
6440 return m_info.lineInfo;
6441 }
6442
getTestMacroName() const6443 StringRef AssertionResult::getTestMacroName() const {
6444 return m_info.macroName;
6445 }
6446
6447 } // end namespace Catch
6448 // end catch_assertionresult.cpp
6449 // start catch_benchmark.cpp
6450
6451 namespace Catch {
6452
getResolution()6453 auto BenchmarkLooper::getResolution() -> uint64_t {
6454 return getEstimatedClockResolution() * getCurrentContext().getConfig()->benchmarkResolutionMultiple();
6455 }
6456
reportStart()6457 void BenchmarkLooper::reportStart() {
6458 getResultCapture().benchmarkStarting( { m_name } );
6459 }
needsMoreIterations()6460 auto BenchmarkLooper::needsMoreIterations() -> bool {
6461 auto elapsed = m_timer.getElapsedNanoseconds();
6462
6463 // Exponentially increasing iterations until we're confident in our timer resolution
6464 if( elapsed < m_resolution ) {
6465 m_iterationsToRun *= 10;
6466 return true;
6467 }
6468
6469 getResultCapture().benchmarkEnded( { { m_name }, m_count, elapsed } );
6470 return false;
6471 }
6472
6473 } // end namespace Catch
6474 // end catch_benchmark.cpp
6475 // start catch_capture_matchers.cpp
6476
6477 namespace Catch {
6478
6479 using StringMatcher = Matchers::Impl::MatcherBase<std::string>;
6480
6481 // This is the general overload that takes a any string matcher
6482 // There is another overload, in catch_assertionhandler.h/.cpp, that only takes a string and infers
6483 // the Equals matcher (so the header does not mention matchers)
handleExceptionMatchExpr(AssertionHandler & handler,StringMatcher const & matcher,StringRef const & matcherString)6484 void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString ) {
6485 std::string exceptionMessage = Catch::translateActiveException();
6486 MatchExpr<std::string, StringMatcher const&> expr( exceptionMessage, matcher, matcherString );
6487 handler.handleExpr( expr );
6488 }
6489
6490 } // namespace Catch
6491 // end catch_capture_matchers.cpp
6492 // start catch_commandline.cpp
6493
6494 // start catch_commandline.h
6495
6496 // start catch_clara.h
6497
6498 // Use Catch's value for console width (store Clara's off to the side, if present)
6499 #ifdef CLARA_CONFIG_CONSOLE_WIDTH
6500 #define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH
6501 #undef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH
6502 #endif
6503 #define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH-1
6504
6505 #ifdef __clang__
6506 #pragma clang diagnostic push
6507 #pragma clang diagnostic ignored "-Wweak-vtables"
6508 #pragma clang diagnostic ignored "-Wexit-time-destructors"
6509 #pragma clang diagnostic ignored "-Wshadow"
6510 #endif
6511
6512 // start clara.hpp
6513 // Copyright 2017 Two Blue Cubes Ltd. All rights reserved.
6514 //
6515 // Distributed under the Boost Software License, Version 1.0. (See accompanying
6516 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6517 //
6518 // See https://github.com/philsquared/Clara for more details
6519
6520 // Clara v1.1.5
6521
6522
6523 #ifndef CATCH_CLARA_CONFIG_CONSOLE_WIDTH
6524 #define CATCH_CLARA_CONFIG_CONSOLE_WIDTH 80
6525 #endif
6526
6527 #ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH
6528 #define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CLARA_CONFIG_CONSOLE_WIDTH
6529 #endif
6530
6531 #ifndef CLARA_CONFIG_OPTIONAL_TYPE
6532 #ifdef __has_include
6533 #if __has_include(<optional>) && __cplusplus >= 201703L
6534 #include <optional>
6535 #define CLARA_CONFIG_OPTIONAL_TYPE std::optional
6536 #endif
6537 #endif
6538 #endif
6539
6540 // ----------- #included from clara_textflow.hpp -----------
6541
6542 // TextFlowCpp
6543 //
6544 // A single-header library for wrapping and laying out basic text, by Phil Nash
6545 //
6546 // Distributed under the Boost Software License, Version 1.0. (See accompanying
6547 // file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6548 //
6549 // This project is hosted at https://github.com/philsquared/textflowcpp
6550
6551
6552 #include <cassert>
6553 #include <ostream>
6554 #include <sstream>
6555 #include <vector>
6556
6557 #ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH
6558 #define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH 80
6559 #endif
6560
6561 namespace Catch {
6562 namespace clara {
6563 namespace TextFlow {
6564
isWhitespace(char c)6565 inline auto isWhitespace(char c) -> bool {
6566 static std::string chars = " \t\n\r";
6567 return chars.find(c) != std::string::npos;
6568 }
isBreakableBefore(char c)6569 inline auto isBreakableBefore(char c) -> bool {
6570 static std::string chars = "[({<|";
6571 return chars.find(c) != std::string::npos;
6572 }
isBreakableAfter(char c)6573 inline auto isBreakableAfter(char c) -> bool {
6574 static std::string chars = "])}>.,:;*+-=&/\\";
6575 return chars.find(c) != std::string::npos;
6576 }
6577
6578 class Columns;
6579
6580 class Column {
6581 std::vector<std::string> m_strings;
6582 size_t m_width = CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH;
6583 size_t m_indent = 0;
6584 size_t m_initialIndent = std::string::npos;
6585
6586 public:
6587 class iterator {
6588 friend Column;
6589
6590 Column const& m_column;
6591 size_t m_stringIndex = 0;
6592 size_t m_pos = 0;
6593
6594 size_t m_len = 0;
6595 size_t m_end = 0;
6596 bool m_suffix = false;
6597
iterator(Column const & column,size_t stringIndex)6598 iterator(Column const& column, size_t stringIndex)
6599 : m_column(column),
6600 m_stringIndex(stringIndex) {}
6601
line() const6602 auto line() const -> std::string const& { return m_column.m_strings[m_stringIndex]; }
6603
isBoundary(size_t at) const6604 auto isBoundary(size_t at) const -> bool {
6605 assert(at > 0);
6606 assert(at <= line().size());
6607
6608 return at == line().size() ||
6609 (isWhitespace(line()[at]) && !isWhitespace(line()[at - 1])) ||
6610 isBreakableBefore(line()[at]) ||
6611 isBreakableAfter(line()[at - 1]);
6612 }
6613
calcLength()6614 void calcLength() {
6615 assert(m_stringIndex < m_column.m_strings.size());
6616
6617 m_suffix = false;
6618 auto width = m_column.m_width - indent();
6619 m_end = m_pos;
6620 while (m_end < line().size() && line()[m_end] != '\n')
6621 ++m_end;
6622
6623 if (m_end < m_pos + width) {
6624 m_len = m_end - m_pos;
6625 } else {
6626 size_t len = width;
6627 while (len > 0 && !isBoundary(m_pos + len))
6628 --len;
6629 while (len > 0 && isWhitespace(line()[m_pos + len - 1]))
6630 --len;
6631
6632 if (len > 0) {
6633 m_len = len;
6634 } else {
6635 m_suffix = true;
6636 m_len = width - 1;
6637 }
6638 }
6639 }
6640
indent() const6641 auto indent() const -> size_t {
6642 auto initial = m_pos == 0 && m_stringIndex == 0 ? m_column.m_initialIndent : std::string::npos;
6643 return initial == std::string::npos ? m_column.m_indent : initial;
6644 }
6645
addIndentAndSuffix(std::string const & plain) const6646 auto addIndentAndSuffix(std::string const &plain) const -> std::string {
6647 return std::string(indent(), ' ') + (m_suffix ? plain + "-" : plain);
6648 }
6649
6650 public:
6651 using difference_type = std::ptrdiff_t;
6652 using value_type = std::string;
6653 using pointer = value_type * ;
6654 using reference = value_type & ;
6655 using iterator_category = std::forward_iterator_tag;
6656
iterator(Column const & column)6657 explicit iterator(Column const& column) : m_column(column) {
6658 assert(m_column.m_width > m_column.m_indent);
6659 assert(m_column.m_initialIndent == std::string::npos || m_column.m_width > m_column.m_initialIndent);
6660 calcLength();
6661 if (m_len == 0)
6662 m_stringIndex++; // Empty string
6663 }
6664
operator *() const6665 auto operator *() const -> std::string {
6666 assert(m_stringIndex < m_column.m_strings.size());
6667 assert(m_pos <= m_end);
6668 return addIndentAndSuffix(line().substr(m_pos, m_len));
6669 }
6670
operator ++()6671 auto operator ++() -> iterator& {
6672 m_pos += m_len;
6673 if (m_pos < line().size() && line()[m_pos] == '\n')
6674 m_pos += 1;
6675 else
6676 while (m_pos < line().size() && isWhitespace(line()[m_pos]))
6677 ++m_pos;
6678
6679 if (m_pos == line().size()) {
6680 m_pos = 0;
6681 ++m_stringIndex;
6682 }
6683 if (m_stringIndex < m_column.m_strings.size())
6684 calcLength();
6685 return *this;
6686 }
operator ++(int)6687 auto operator ++(int) -> iterator {
6688 iterator prev(*this);
6689 operator++();
6690 return prev;
6691 }
6692
operator ==(iterator const & other) const6693 auto operator ==(iterator const& other) const -> bool {
6694 return
6695 m_pos == other.m_pos &&
6696 m_stringIndex == other.m_stringIndex &&
6697 &m_column == &other.m_column;
6698 }
operator !=(iterator const & other) const6699 auto operator !=(iterator const& other) const -> bool {
6700 return !operator==(other);
6701 }
6702 };
6703 using const_iterator = iterator;
6704
Column(std::string const & text)6705 explicit Column(std::string const& text) { m_strings.push_back(text); }
6706
width(size_t newWidth)6707 auto width(size_t newWidth) -> Column& {
6708 assert(newWidth > 0);
6709 m_width = newWidth;
6710 return *this;
6711 }
indent(size_t newIndent)6712 auto indent(size_t newIndent) -> Column& {
6713 m_indent = newIndent;
6714 return *this;
6715 }
initialIndent(size_t newIndent)6716 auto initialIndent(size_t newIndent) -> Column& {
6717 m_initialIndent = newIndent;
6718 return *this;
6719 }
6720
width() const6721 auto width() const -> size_t { return m_width; }
begin() const6722 auto begin() const -> iterator { return iterator(*this); }
end() const6723 auto end() const -> iterator { return { *this, m_strings.size() }; }
6724
operator <<(std::ostream & os,Column const & col)6725 inline friend std::ostream& operator << (std::ostream& os, Column const& col) {
6726 bool first = true;
6727 for (auto line : col) {
6728 if (first)
6729 first = false;
6730 else
6731 os << "\n";
6732 os << line;
6733 }
6734 return os;
6735 }
6736
6737 auto operator + (Column const& other)->Columns;
6738
toString() const6739 auto toString() const -> std::string {
6740 std::ostringstream oss;
6741 oss << *this;
6742 return oss.str();
6743 }
6744 };
6745
6746 class Spacer : public Column {
6747
6748 public:
Spacer(size_t spaceWidth)6749 explicit Spacer(size_t spaceWidth) : Column("") {
6750 width(spaceWidth);
6751 }
6752 };
6753
6754 class Columns {
6755 std::vector<Column> m_columns;
6756
6757 public:
6758
6759 class iterator {
6760 friend Columns;
6761 struct EndTag {};
6762
6763 std::vector<Column> const& m_columns;
6764 std::vector<Column::iterator> m_iterators;
6765 size_t m_activeIterators;
6766
iterator(Columns const & columns,EndTag)6767 iterator(Columns const& columns, EndTag)
6768 : m_columns(columns.m_columns),
6769 m_activeIterators(0) {
6770 m_iterators.reserve(m_columns.size());
6771
6772 for (auto const& col : m_columns)
6773 m_iterators.push_back(col.end());
6774 }
6775
6776 public:
6777 using difference_type = std::ptrdiff_t;
6778 using value_type = std::string;
6779 using pointer = value_type * ;
6780 using reference = value_type & ;
6781 using iterator_category = std::forward_iterator_tag;
6782
iterator(Columns const & columns)6783 explicit iterator(Columns const& columns)
6784 : m_columns(columns.m_columns),
6785 m_activeIterators(m_columns.size()) {
6786 m_iterators.reserve(m_columns.size());
6787
6788 for (auto const& col : m_columns)
6789 m_iterators.push_back(col.begin());
6790 }
6791
operator ==(iterator const & other) const6792 auto operator ==(iterator const& other) const -> bool {
6793 return m_iterators == other.m_iterators;
6794 }
operator !=(iterator const & other) const6795 auto operator !=(iterator const& other) const -> bool {
6796 return m_iterators != other.m_iterators;
6797 }
operator *() const6798 auto operator *() const -> std::string {
6799 std::string row, padding;
6800
6801 for (size_t i = 0; i < m_columns.size(); ++i) {
6802 auto width = m_columns[i].width();
6803 if (m_iterators[i] != m_columns[i].end()) {
6804 std::string col = *m_iterators[i];
6805 row += padding + col;
6806 if (col.size() < width)
6807 padding = std::string(width - col.size(), ' ');
6808 else
6809 padding = "";
6810 } else {
6811 padding += std::string(width, ' ');
6812 }
6813 }
6814 return row;
6815 }
operator ++()6816 auto operator ++() -> iterator& {
6817 for (size_t i = 0; i < m_columns.size(); ++i) {
6818 if (m_iterators[i] != m_columns[i].end())
6819 ++m_iterators[i];
6820 }
6821 return *this;
6822 }
operator ++(int)6823 auto operator ++(int) -> iterator {
6824 iterator prev(*this);
6825 operator++();
6826 return prev;
6827 }
6828 };
6829 using const_iterator = iterator;
6830
begin() const6831 auto begin() const -> iterator { return iterator(*this); }
end() const6832 auto end() const -> iterator { return { *this, iterator::EndTag() }; }
6833
operator +=(Column const & col)6834 auto operator += (Column const& col) -> Columns& {
6835 m_columns.push_back(col);
6836 return *this;
6837 }
operator +(Column const & col)6838 auto operator + (Column const& col) -> Columns {
6839 Columns combined = *this;
6840 combined += col;
6841 return combined;
6842 }
6843
operator <<(std::ostream & os,Columns const & cols)6844 inline friend std::ostream& operator << (std::ostream& os, Columns const& cols) {
6845
6846 bool first = true;
6847 for (auto line : cols) {
6848 if (first)
6849 first = false;
6850 else
6851 os << "\n";
6852 os << line;
6853 }
6854 return os;
6855 }
6856
toString() const6857 auto toString() const -> std::string {
6858 std::ostringstream oss;
6859 oss << *this;
6860 return oss.str();
6861 }
6862 };
6863
operator +(Column const & other)6864 inline auto Column::operator + (Column const& other) -> Columns {
6865 Columns cols;
6866 cols += *this;
6867 cols += other;
6868 return cols;
6869 }
6870 }
6871
6872 }
6873 }
6874
6875 // ----------- end of #include from clara_textflow.hpp -----------
6876 // ........... back in clara.hpp
6877
6878 #include <cctype>
6879 #include <string>
6880 #include <memory>
6881 #include <set>
6882 #include <algorithm>
6883
6884 #if !defined(CATCH_PLATFORM_WINDOWS) && ( defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) )
6885 #define CATCH_PLATFORM_WINDOWS
6886 #endif
6887
6888 namespace Catch { namespace clara {
6889 namespace detail {
6890
6891 // Traits for extracting arg and return type of lambdas (for single argument lambdas)
6892 template<typename L>
6893 struct UnaryLambdaTraits : UnaryLambdaTraits<decltype( &L::operator() )> {};
6894
6895 template<typename ClassT, typename ReturnT, typename... Args>
6896 struct UnaryLambdaTraits<ReturnT( ClassT::* )( Args... ) const> {
6897 static const bool isValid = false;
6898 };
6899
6900 template<typename ClassT, typename ReturnT, typename ArgT>
6901 struct UnaryLambdaTraits<ReturnT( ClassT::* )( ArgT ) const> {
6902 static const bool isValid = true;
6903 using ArgType = typename std::remove_const<typename std::remove_reference<ArgT>::type>::type;
6904 using ReturnType = ReturnT;
6905 };
6906
6907 class TokenStream;
6908
6909 // Transport for raw args (copied from main args, or supplied via init list for testing)
6910 class Args {
6911 friend TokenStream;
6912 std::string m_exeName;
6913 std::vector<std::string> m_args;
6914
6915 public:
Args(int argc,char const * const * argv)6916 Args( int argc, char const* const* argv )
6917 : m_exeName(argv[0]),
6918 m_args(argv + 1, argv + argc) {}
6919
Args(std::initializer_list<std::string> args)6920 Args( std::initializer_list<std::string> args )
6921 : m_exeName( *args.begin() ),
6922 m_args( args.begin()+1, args.end() )
6923 {}
6924
exeName() const6925 auto exeName() const -> std::string {
6926 return m_exeName;
6927 }
6928 };
6929
6930 // Wraps a token coming from a token stream. These may not directly correspond to strings as a single string
6931 // may encode an option + its argument if the : or = form is used
6932 enum class TokenType {
6933 Option, Argument
6934 };
6935 struct Token {
6936 TokenType type;
6937 std::string token;
6938 };
6939
isOptPrefix(char c)6940 inline auto isOptPrefix( char c ) -> bool {
6941 return c == '-'
6942 #ifdef CATCH_PLATFORM_WINDOWS
6943 || c == '/'
6944 #endif
6945 ;
6946 }
6947
6948 // Abstracts iterators into args as a stream of tokens, with option arguments uniformly handled
6949 class TokenStream {
6950 using Iterator = std::vector<std::string>::const_iterator;
6951 Iterator it;
6952 Iterator itEnd;
6953 std::vector<Token> m_tokenBuffer;
6954
loadBuffer()6955 void loadBuffer() {
6956 m_tokenBuffer.resize( 0 );
6957
6958 // Skip any empty strings
6959 while( it != itEnd && it->empty() )
6960 ++it;
6961
6962 if( it != itEnd ) {
6963 auto const &next = *it;
6964 if( isOptPrefix( next[0] ) ) {
6965 auto delimiterPos = next.find_first_of( " :=" );
6966 if( delimiterPos != std::string::npos ) {
6967 m_tokenBuffer.push_back( { TokenType::Option, next.substr( 0, delimiterPos ) } );
6968 m_tokenBuffer.push_back( { TokenType::Argument, next.substr( delimiterPos + 1 ) } );
6969 } else {
6970 if( next[1] != '-' && next.size() > 2 ) {
6971 std::string opt = "- ";
6972 for( size_t i = 1; i < next.size(); ++i ) {
6973 opt[1] = next[i];
6974 m_tokenBuffer.push_back( { TokenType::Option, opt } );
6975 }
6976 } else {
6977 m_tokenBuffer.push_back( { TokenType::Option, next } );
6978 }
6979 }
6980 } else {
6981 m_tokenBuffer.push_back( { TokenType::Argument, next } );
6982 }
6983 }
6984 }
6985
6986 public:
TokenStream(Args const & args)6987 explicit TokenStream( Args const &args ) : TokenStream( args.m_args.begin(), args.m_args.end() ) {}
6988
TokenStream(Iterator it,Iterator itEnd)6989 TokenStream( Iterator it, Iterator itEnd ) : it( it ), itEnd( itEnd ) {
6990 loadBuffer();
6991 }
6992
operator bool() const6993 explicit operator bool() const {
6994 return !m_tokenBuffer.empty() || it != itEnd;
6995 }
6996
count() const6997 auto count() const -> size_t { return m_tokenBuffer.size() + (itEnd - it); }
6998
operator *() const6999 auto operator*() const -> Token {
7000 assert( !m_tokenBuffer.empty() );
7001 return m_tokenBuffer.front();
7002 }
7003
operator ->() const7004 auto operator->() const -> Token const * {
7005 assert( !m_tokenBuffer.empty() );
7006 return &m_tokenBuffer.front();
7007 }
7008
operator ++()7009 auto operator++() -> TokenStream & {
7010 if( m_tokenBuffer.size() >= 2 ) {
7011 m_tokenBuffer.erase( m_tokenBuffer.begin() );
7012 } else {
7013 if( it != itEnd )
7014 ++it;
7015 loadBuffer();
7016 }
7017 return *this;
7018 }
7019 };
7020
7021 class ResultBase {
7022 public:
7023 enum Type {
7024 Ok, LogicError, RuntimeError
7025 };
7026
7027 protected:
ResultBase(Type type)7028 ResultBase( Type type ) : m_type( type ) {}
7029 virtual ~ResultBase() = default;
7030
7031 virtual void enforceOk() const = 0;
7032
7033 Type m_type;
7034 };
7035
7036 template<typename T>
7037 class ResultValueBase : public ResultBase {
7038 public:
value() const7039 auto value() const -> T const & {
7040 enforceOk();
7041 return m_value;
7042 }
7043
7044 protected:
ResultValueBase(Type type)7045 ResultValueBase( Type type ) : ResultBase( type ) {}
7046
ResultValueBase(ResultValueBase const & other)7047 ResultValueBase( ResultValueBase const &other ) : ResultBase( other ) {
7048 if( m_type == ResultBase::Ok )
7049 new( &m_value ) T( other.m_value );
7050 }
7051
ResultValueBase(Type,T const & value)7052 ResultValueBase( Type, T const &value ) : ResultBase( Ok ) {
7053 new( &m_value ) T( value );
7054 }
7055
operator =(ResultValueBase const & other)7056 auto operator=( ResultValueBase const &other ) -> ResultValueBase & {
7057 if( m_type == ResultBase::Ok )
7058 m_value.~T();
7059 ResultBase::operator=(other);
7060 if( m_type == ResultBase::Ok )
7061 new( &m_value ) T( other.m_value );
7062 return *this;
7063 }
7064
~ResultValueBase()7065 ~ResultValueBase() override {
7066 if( m_type == Ok )
7067 m_value.~T();
7068 }
7069
7070 union {
7071 T m_value;
7072 };
7073 };
7074
7075 template<>
7076 class ResultValueBase<void> : public ResultBase {
7077 protected:
7078 using ResultBase::ResultBase;
7079 };
7080
7081 template<typename T = void>
7082 class BasicResult : public ResultValueBase<T> {
7083 public:
7084 template<typename U>
BasicResult(BasicResult<U> const & other)7085 explicit BasicResult( BasicResult<U> const &other )
7086 : ResultValueBase<T>( other.type() ),
7087 m_errorMessage( other.errorMessage() )
7088 {
7089 assert( type() != ResultBase::Ok );
7090 }
7091
7092 template<typename U>
ok(U const & value)7093 static auto ok( U const &value ) -> BasicResult { return { ResultBase::Ok, value }; }
ok()7094 static auto ok() -> BasicResult { return { ResultBase::Ok }; }
logicError(std::string const & message)7095 static auto logicError( std::string const &message ) -> BasicResult { return { ResultBase::LogicError, message }; }
runtimeError(std::string const & message)7096 static auto runtimeError( std::string const &message ) -> BasicResult { return { ResultBase::RuntimeError, message }; }
7097
operator bool() const7098 explicit operator bool() const { return m_type == ResultBase::Ok; }
type() const7099 auto type() const -> ResultBase::Type { return m_type; }
errorMessage() const7100 auto errorMessage() const -> std::string { return m_errorMessage; }
7101
7102 protected:
enforceOk() const7103 void enforceOk() const override {
7104
7105 // Errors shouldn't reach this point, but if they do
7106 // the actual error message will be in m_errorMessage
7107 assert( m_type != ResultBase::LogicError );
7108 assert( m_type != ResultBase::RuntimeError );
7109 if( m_type != ResultBase::Ok )
7110 std::abort();
7111 }
7112
7113 std::string m_errorMessage; // Only populated if resultType is an error
7114
BasicResult(ResultBase::Type type,std::string const & message)7115 BasicResult( ResultBase::Type type, std::string const &message )
7116 : ResultValueBase<T>(type),
7117 m_errorMessage(message)
7118 {
7119 assert( m_type != ResultBase::Ok );
7120 }
7121
7122 using ResultValueBase<T>::ResultValueBase;
7123 using ResultBase::m_type;
7124 };
7125
7126 enum class ParseResultType {
7127 Matched, NoMatch, ShortCircuitAll, ShortCircuitSame
7128 };
7129
7130 class ParseState {
7131 public:
7132
ParseState(ParseResultType type,TokenStream const & remainingTokens)7133 ParseState( ParseResultType type, TokenStream const &remainingTokens )
7134 : m_type(type),
7135 m_remainingTokens( remainingTokens )
7136 {}
7137
type() const7138 auto type() const -> ParseResultType { return m_type; }
remainingTokens() const7139 auto remainingTokens() const -> TokenStream { return m_remainingTokens; }
7140
7141 private:
7142 ParseResultType m_type;
7143 TokenStream m_remainingTokens;
7144 };
7145
7146 using Result = BasicResult<void>;
7147 using ParserResult = BasicResult<ParseResultType>;
7148 using InternalParseResult = BasicResult<ParseState>;
7149
7150 struct HelpColumns {
7151 std::string left;
7152 std::string right;
7153 };
7154
7155 template<typename T>
convertInto(std::string const & source,T & target)7156 inline auto convertInto( std::string const &source, T& target ) -> ParserResult {
7157 std::stringstream ss;
7158 ss << source;
7159 ss >> target;
7160 if( ss.fail() )
7161 return ParserResult::runtimeError( "Unable to convert '" + source + "' to destination type" );
7162 else
7163 return ParserResult::ok( ParseResultType::Matched );
7164 }
convertInto(std::string const & source,std::string & target)7165 inline auto convertInto( std::string const &source, std::string& target ) -> ParserResult {
7166 target = source;
7167 return ParserResult::ok( ParseResultType::Matched );
7168 }
convertInto(std::string const & source,bool & target)7169 inline auto convertInto( std::string const &source, bool &target ) -> ParserResult {
7170 std::string srcLC = source;
7171 std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast<char>( std::tolower(c) ); } );
7172 if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on")
7173 target = true;
7174 else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off")
7175 target = false;
7176 else
7177 return ParserResult::runtimeError( "Expected a boolean value but did not recognise: '" + source + "'" );
7178 return ParserResult::ok( ParseResultType::Matched );
7179 }
7180 #ifdef CLARA_CONFIG_OPTIONAL_TYPE
7181 template<typename T>
convertInto(std::string const & source,CLARA_CONFIG_OPTIONAL_TYPE<T> & target)7182 inline auto convertInto( std::string const &source, CLARA_CONFIG_OPTIONAL_TYPE<T>& target ) -> ParserResult {
7183 T temp;
7184 auto result = convertInto( source, temp );
7185 if( result )
7186 target = std::move(temp);
7187 return result;
7188 }
7189 #endif // CLARA_CONFIG_OPTIONAL_TYPE
7190
7191 struct NonCopyable {
7192 NonCopyable() = default;
7193 NonCopyable( NonCopyable const & ) = delete;
7194 NonCopyable( NonCopyable && ) = delete;
7195 NonCopyable &operator=( NonCopyable const & ) = delete;
7196 NonCopyable &operator=( NonCopyable && ) = delete;
7197 };
7198
7199 struct BoundRef : NonCopyable {
7200 virtual ~BoundRef() = default;
isContainerCatch::clara::detail::BoundRef7201 virtual auto isContainer() const -> bool { return false; }
isFlagCatch::clara::detail::BoundRef7202 virtual auto isFlag() const -> bool { return false; }
7203 };
7204 struct BoundValueRefBase : BoundRef {
7205 virtual auto setValue( std::string const &arg ) -> ParserResult = 0;
7206 };
7207 struct BoundFlagRefBase : BoundRef {
7208 virtual auto setFlag( bool flag ) -> ParserResult = 0;
isFlagCatch::clara::detail::BoundFlagRefBase7209 virtual auto isFlag() const -> bool { return true; }
7210 };
7211
7212 template<typename T>
7213 struct BoundValueRef : BoundValueRefBase {
7214 T &m_ref;
7215
BoundValueRefCatch::clara::detail::BoundValueRef7216 explicit BoundValueRef( T &ref ) : m_ref( ref ) {}
7217
setValueCatch::clara::detail::BoundValueRef7218 auto setValue( std::string const &arg ) -> ParserResult override {
7219 return convertInto( arg, m_ref );
7220 }
7221 };
7222
7223 template<typename T>
7224 struct BoundValueRef<std::vector<T>> : BoundValueRefBase {
7225 std::vector<T> &m_ref;
7226
BoundValueRefCatch::clara::detail::BoundValueRef7227 explicit BoundValueRef( std::vector<T> &ref ) : m_ref( ref ) {}
7228
isContainerCatch::clara::detail::BoundValueRef7229 auto isContainer() const -> bool override { return true; }
7230
setValueCatch::clara::detail::BoundValueRef7231 auto setValue( std::string const &arg ) -> ParserResult override {
7232 T temp;
7233 auto result = convertInto( arg, temp );
7234 if( result )
7235 m_ref.push_back( temp );
7236 return result;
7237 }
7238 };
7239
7240 struct BoundFlagRef : BoundFlagRefBase {
7241 bool &m_ref;
7242
BoundFlagRefCatch::clara::detail::BoundFlagRef7243 explicit BoundFlagRef( bool &ref ) : m_ref( ref ) {}
7244
setFlagCatch::clara::detail::BoundFlagRef7245 auto setFlag( bool flag ) -> ParserResult override {
7246 m_ref = flag;
7247 return ParserResult::ok( ParseResultType::Matched );
7248 }
7249 };
7250
7251 template<typename ReturnType>
7252 struct LambdaInvoker {
7253 static_assert( std::is_same<ReturnType, ParserResult>::value, "Lambda must return void or clara::ParserResult" );
7254
7255 template<typename L, typename ArgType>
invokeCatch::clara::detail::LambdaInvoker7256 static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult {
7257 return lambda( arg );
7258 }
7259 };
7260
7261 template<>
7262 struct LambdaInvoker<void> {
7263 template<typename L, typename ArgType>
invokeCatch::clara::detail::LambdaInvoker7264 static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult {
7265 lambda( arg );
7266 return ParserResult::ok( ParseResultType::Matched );
7267 }
7268 };
7269
7270 template<typename ArgType, typename L>
invokeLambda(L const & lambda,std::string const & arg)7271 inline auto invokeLambda( L const &lambda, std::string const &arg ) -> ParserResult {
7272 ArgType temp{};
7273 auto result = convertInto( arg, temp );
7274 return !result
7275 ? result
7276 : LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( lambda, temp );
7277 }
7278
7279 template<typename L>
7280 struct BoundLambda : BoundValueRefBase {
7281 L m_lambda;
7282
7283 static_assert( UnaryLambdaTraits<L>::isValid, "Supplied lambda must take exactly one argument" );
BoundLambdaCatch::clara::detail::BoundLambda7284 explicit BoundLambda( L const &lambda ) : m_lambda( lambda ) {}
7285
setValueCatch::clara::detail::BoundLambda7286 auto setValue( std::string const &arg ) -> ParserResult override {
7287 return invokeLambda<typename UnaryLambdaTraits<L>::ArgType>( m_lambda, arg );
7288 }
7289 };
7290
7291 template<typename L>
7292 struct BoundFlagLambda : BoundFlagRefBase {
7293 L m_lambda;
7294
7295 static_assert( UnaryLambdaTraits<L>::isValid, "Supplied lambda must take exactly one argument" );
7296 static_assert( std::is_same<typename UnaryLambdaTraits<L>::ArgType, bool>::value, "flags must be boolean" );
7297
BoundFlagLambdaCatch::clara::detail::BoundFlagLambda7298 explicit BoundFlagLambda( L const &lambda ) : m_lambda( lambda ) {}
7299
setFlagCatch::clara::detail::BoundFlagLambda7300 auto setFlag( bool flag ) -> ParserResult override {
7301 return LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( m_lambda, flag );
7302 }
7303 };
7304
7305 enum class Optionality { Optional, Required };
7306
7307 struct Parser;
7308
7309 class ParserBase {
7310 public:
7311 virtual ~ParserBase() = default;
validate() const7312 virtual auto validate() const -> Result { return Result::ok(); }
7313 virtual auto parse( std::string const& exeName, TokenStream const &tokens) const -> InternalParseResult = 0;
cardinality() const7314 virtual auto cardinality() const -> size_t { return 1; }
7315
parse(Args const & args) const7316 auto parse( Args const &args ) const -> InternalParseResult {
7317 return parse( args.exeName(), TokenStream( args ) );
7318 }
7319 };
7320
7321 template<typename DerivedT>
7322 class ComposableParserImpl : public ParserBase {
7323 public:
7324 template<typename T>
7325 auto operator|( T const &other ) const -> Parser;
7326
7327 template<typename T>
7328 auto operator+( T const &other ) const -> Parser;
7329 };
7330
7331 // Common code and state for Args and Opts
7332 template<typename DerivedT>
7333 class ParserRefImpl : public ComposableParserImpl<DerivedT> {
7334 protected:
7335 Optionality m_optionality = Optionality::Optional;
7336 std::shared_ptr<BoundRef> m_ref;
7337 std::string m_hint;
7338 std::string m_description;
7339
ParserRefImpl(std::shared_ptr<BoundRef> const & ref)7340 explicit ParserRefImpl( std::shared_ptr<BoundRef> const &ref ) : m_ref( ref ) {}
7341
7342 public:
7343 template<typename T>
ParserRefImpl(T & ref,std::string const & hint)7344 ParserRefImpl( T &ref, std::string const &hint )
7345 : m_ref( std::make_shared<BoundValueRef<T>>( ref ) ),
7346 m_hint( hint )
7347 {}
7348
7349 template<typename LambdaT>
ParserRefImpl(LambdaT const & ref,std::string const & hint)7350 ParserRefImpl( LambdaT const &ref, std::string const &hint )
7351 : m_ref( std::make_shared<BoundLambda<LambdaT>>( ref ) ),
7352 m_hint(hint)
7353 {}
7354
operator ()(std::string const & description)7355 auto operator()( std::string const &description ) -> DerivedT & {
7356 m_description = description;
7357 return static_cast<DerivedT &>( *this );
7358 }
7359
optional()7360 auto optional() -> DerivedT & {
7361 m_optionality = Optionality::Optional;
7362 return static_cast<DerivedT &>( *this );
7363 };
7364
required()7365 auto required() -> DerivedT & {
7366 m_optionality = Optionality::Required;
7367 return static_cast<DerivedT &>( *this );
7368 };
7369
isOptional() const7370 auto isOptional() const -> bool {
7371 return m_optionality == Optionality::Optional;
7372 }
7373
cardinality() const7374 auto cardinality() const -> size_t override {
7375 if( m_ref->isContainer() )
7376 return 0;
7377 else
7378 return 1;
7379 }
7380
hint() const7381 auto hint() const -> std::string { return m_hint; }
7382 };
7383
7384 class ExeName : public ComposableParserImpl<ExeName> {
7385 std::shared_ptr<std::string> m_name;
7386 std::shared_ptr<BoundValueRefBase> m_ref;
7387
7388 template<typename LambdaT>
makeRef(LambdaT const & lambda)7389 static auto makeRef(LambdaT const &lambda) -> std::shared_ptr<BoundValueRefBase> {
7390 return std::make_shared<BoundLambda<LambdaT>>( lambda) ;
7391 }
7392
7393 public:
ExeName()7394 ExeName() : m_name( std::make_shared<std::string>( "<executable>" ) ) {}
7395
ExeName(std::string & ref)7396 explicit ExeName( std::string &ref ) : ExeName() {
7397 m_ref = std::make_shared<BoundValueRef<std::string>>( ref );
7398 }
7399
7400 template<typename LambdaT>
ExeName(LambdaT const & lambda)7401 explicit ExeName( LambdaT const& lambda ) : ExeName() {
7402 m_ref = std::make_shared<BoundLambda<LambdaT>>( lambda );
7403 }
7404
7405 // The exe name is not parsed out of the normal tokens, but is handled specially
parse(std::string const &,TokenStream const & tokens) const7406 auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override {
7407 return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) );
7408 }
7409
name() const7410 auto name() const -> std::string { return *m_name; }
set(std::string const & newName)7411 auto set( std::string const& newName ) -> ParserResult {
7412
7413 auto lastSlash = newName.find_last_of( "\\/" );
7414 auto filename = ( lastSlash == std::string::npos )
7415 ? newName
7416 : newName.substr( lastSlash+1 );
7417
7418 *m_name = filename;
7419 if( m_ref )
7420 return m_ref->setValue( filename );
7421 else
7422 return ParserResult::ok( ParseResultType::Matched );
7423 }
7424 };
7425
7426 class Arg : public ParserRefImpl<Arg> {
7427 public:
7428 using ParserRefImpl::ParserRefImpl;
7429
parse(std::string const &,TokenStream const & tokens) const7430 auto parse( std::string const &, TokenStream const &tokens ) const -> InternalParseResult override {
7431 auto validationResult = validate();
7432 if( !validationResult )
7433 return InternalParseResult( validationResult );
7434
7435 auto remainingTokens = tokens;
7436 auto const &token = *remainingTokens;
7437 if( token.type != TokenType::Argument )
7438 return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) );
7439
7440 assert( !m_ref->isFlag() );
7441 auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() );
7442
7443 auto result = valueRef->setValue( remainingTokens->token );
7444 if( !result )
7445 return InternalParseResult( result );
7446 else
7447 return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) );
7448 }
7449 };
7450
normaliseOpt(std::string const & optName)7451 inline auto normaliseOpt( std::string const &optName ) -> std::string {
7452 #ifdef CATCH_PLATFORM_WINDOWS
7453 if( optName[0] == '/' )
7454 return "-" + optName.substr( 1 );
7455 else
7456 #endif
7457 return optName;
7458 }
7459
7460 class Opt : public ParserRefImpl<Opt> {
7461 protected:
7462 std::vector<std::string> m_optNames;
7463
7464 public:
7465 template<typename LambdaT>
Opt(LambdaT const & ref)7466 explicit Opt( LambdaT const &ref ) : ParserRefImpl( std::make_shared<BoundFlagLambda<LambdaT>>( ref ) ) {}
7467
Opt(bool & ref)7468 explicit Opt( bool &ref ) : ParserRefImpl( std::make_shared<BoundFlagRef>( ref ) ) {}
7469
7470 template<typename LambdaT>
Opt(LambdaT const & ref,std::string const & hint)7471 Opt( LambdaT const &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {}
7472
7473 template<typename T>
Opt(T & ref,std::string const & hint)7474 Opt( T &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {}
7475
operator [](std::string const & optName)7476 auto operator[]( std::string const &optName ) -> Opt & {
7477 m_optNames.push_back( optName );
7478 return *this;
7479 }
7480
getHelpColumns() const7481 auto getHelpColumns() const -> std::vector<HelpColumns> {
7482 std::ostringstream oss;
7483 bool first = true;
7484 for( auto const &opt : m_optNames ) {
7485 if (first)
7486 first = false;
7487 else
7488 oss << ", ";
7489 oss << opt;
7490 }
7491 if( !m_hint.empty() )
7492 oss << " <" << m_hint << ">";
7493 return { { oss.str(), m_description } };
7494 }
7495
isMatch(std::string const & optToken) const7496 auto isMatch( std::string const &optToken ) const -> bool {
7497 auto normalisedToken = normaliseOpt( optToken );
7498 for( auto const &name : m_optNames ) {
7499 if( normaliseOpt( name ) == normalisedToken )
7500 return true;
7501 }
7502 return false;
7503 }
7504
7505 using ParserBase::parse;
7506
parse(std::string const &,TokenStream const & tokens) const7507 auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override {
7508 auto validationResult = validate();
7509 if( !validationResult )
7510 return InternalParseResult( validationResult );
7511
7512 auto remainingTokens = tokens;
7513 if( remainingTokens && remainingTokens->type == TokenType::Option ) {
7514 auto const &token = *remainingTokens;
7515 if( isMatch(token.token ) ) {
7516 if( m_ref->isFlag() ) {
7517 auto flagRef = static_cast<detail::BoundFlagRefBase*>( m_ref.get() );
7518 auto result = flagRef->setFlag( true );
7519 if( !result )
7520 return InternalParseResult( result );
7521 if( result.value() == ParseResultType::ShortCircuitAll )
7522 return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) );
7523 } else {
7524 auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() );
7525 ++remainingTokens;
7526 if( !remainingTokens )
7527 return InternalParseResult::runtimeError( "Expected argument following " + token.token );
7528 auto const &argToken = *remainingTokens;
7529 if( argToken.type != TokenType::Argument )
7530 return InternalParseResult::runtimeError( "Expected argument following " + token.token );
7531 auto result = valueRef->setValue( argToken.token );
7532 if( !result )
7533 return InternalParseResult( result );
7534 if( result.value() == ParseResultType::ShortCircuitAll )
7535 return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) );
7536 }
7537 return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) );
7538 }
7539 }
7540 return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) );
7541 }
7542
validate() const7543 auto validate() const -> Result override {
7544 if( m_optNames.empty() )
7545 return Result::logicError( "No options supplied to Opt" );
7546 for( auto const &name : m_optNames ) {
7547 if( name.empty() )
7548 return Result::logicError( "Option name cannot be empty" );
7549 #ifdef CATCH_PLATFORM_WINDOWS
7550 if( name[0] != '-' && name[0] != '/' )
7551 return Result::logicError( "Option name must begin with '-' or '/'" );
7552 #else
7553 if( name[0] != '-' )
7554 return Result::logicError( "Option name must begin with '-'" );
7555 #endif
7556 }
7557 return ParserRefImpl::validate();
7558 }
7559 };
7560
7561 struct Help : Opt {
HelpCatch::clara::detail::Help7562 Help( bool &showHelpFlag )
7563 : Opt([&]( bool flag ) {
7564 showHelpFlag = flag;
7565 return ParserResult::ok( ParseResultType::ShortCircuitAll );
7566 })
7567 {
7568 static_cast<Opt &>( *this )
7569 ("display usage information")
7570 ["-?"]["-h"]["--help"]
7571 .optional();
7572 }
7573 };
7574
7575 struct Parser : ParserBase {
7576
7577 mutable ExeName m_exeName;
7578 std::vector<Opt> m_options;
7579 std::vector<Arg> m_args;
7580
operator |=Catch::clara::detail::Parser7581 auto operator|=( ExeName const &exeName ) -> Parser & {
7582 m_exeName = exeName;
7583 return *this;
7584 }
7585
operator |=Catch::clara::detail::Parser7586 auto operator|=( Arg const &arg ) -> Parser & {
7587 m_args.push_back(arg);
7588 return *this;
7589 }
7590
operator |=Catch::clara::detail::Parser7591 auto operator|=( Opt const &opt ) -> Parser & {
7592 m_options.push_back(opt);
7593 return *this;
7594 }
7595
operator |=Catch::clara::detail::Parser7596 auto operator|=( Parser const &other ) -> Parser & {
7597 m_options.insert(m_options.end(), other.m_options.begin(), other.m_options.end());
7598 m_args.insert(m_args.end(), other.m_args.begin(), other.m_args.end());
7599 return *this;
7600 }
7601
7602 template<typename T>
operator |Catch::clara::detail::Parser7603 auto operator|( T const &other ) const -> Parser {
7604 return Parser( *this ) |= other;
7605 }
7606
7607 // Forward deprecated interface with '+' instead of '|'
7608 template<typename T>
operator +=Catch::clara::detail::Parser7609 auto operator+=( T const &other ) -> Parser & { return operator|=( other ); }
7610 template<typename T>
operator +Catch::clara::detail::Parser7611 auto operator+( T const &other ) const -> Parser { return operator|( other ); }
7612
getHelpColumnsCatch::clara::detail::Parser7613 auto getHelpColumns() const -> std::vector<HelpColumns> {
7614 std::vector<HelpColumns> cols;
7615 for (auto const &o : m_options) {
7616 auto childCols = o.getHelpColumns();
7617 cols.insert( cols.end(), childCols.begin(), childCols.end() );
7618 }
7619 return cols;
7620 }
7621
writeToStreamCatch::clara::detail::Parser7622 void writeToStream( std::ostream &os ) const {
7623 if (!m_exeName.name().empty()) {
7624 os << "usage:\n" << " " << m_exeName.name() << " ";
7625 bool required = true, first = true;
7626 for( auto const &arg : m_args ) {
7627 if (first)
7628 first = false;
7629 else
7630 os << " ";
7631 if( arg.isOptional() && required ) {
7632 os << "[";
7633 required = false;
7634 }
7635 os << "<" << arg.hint() << ">";
7636 if( arg.cardinality() == 0 )
7637 os << " ... ";
7638 }
7639 if( !required )
7640 os << "]";
7641 if( !m_options.empty() )
7642 os << " options";
7643 os << "\n\nwhere options are:" << std::endl;
7644 }
7645
7646 auto rows = getHelpColumns();
7647 size_t consoleWidth = CATCH_CLARA_CONFIG_CONSOLE_WIDTH;
7648 size_t optWidth = 0;
7649 for( auto const &cols : rows )
7650 optWidth = (std::max)(optWidth, cols.left.size() + 2);
7651
7652 optWidth = (std::min)(optWidth, consoleWidth/2);
7653
7654 for( auto const &cols : rows ) {
7655 auto row =
7656 TextFlow::Column( cols.left ).width( optWidth ).indent( 2 ) +
7657 TextFlow::Spacer(4) +
7658 TextFlow::Column( cols.right ).width( consoleWidth - 7 - optWidth );
7659 os << row << std::endl;
7660 }
7661 }
7662
operator <<(std::ostream & os,Parser const & parser)7663 friend auto operator<<( std::ostream &os, Parser const &parser ) -> std::ostream& {
7664 parser.writeToStream( os );
7665 return os;
7666 }
7667
validateCatch::clara::detail::Parser7668 auto validate() const -> Result override {
7669 for( auto const &opt : m_options ) {
7670 auto result = opt.validate();
7671 if( !result )
7672 return result;
7673 }
7674 for( auto const &arg : m_args ) {
7675 auto result = arg.validate();
7676 if( !result )
7677 return result;
7678 }
7679 return Result::ok();
7680 }
7681
7682 using ParserBase::parse;
7683
parseCatch::clara::detail::Parser7684 auto parse( std::string const& exeName, TokenStream const &tokens ) const -> InternalParseResult override {
7685
7686 struct ParserInfo {
7687 ParserBase const* parser = nullptr;
7688 size_t count = 0;
7689 };
7690 const size_t totalParsers = m_options.size() + m_args.size();
7691 assert( totalParsers < 512 );
7692 // ParserInfo parseInfos[totalParsers]; // <-- this is what we really want to do
7693 ParserInfo parseInfos[512];
7694
7695 {
7696 size_t i = 0;
7697 for (auto const &opt : m_options) parseInfos[i++].parser = &opt;
7698 for (auto const &arg : m_args) parseInfos[i++].parser = &arg;
7699 }
7700
7701 m_exeName.set( exeName );
7702
7703 auto result = InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) );
7704 while( result.value().remainingTokens() ) {
7705 bool tokenParsed = false;
7706
7707 for( size_t i = 0; i < totalParsers; ++i ) {
7708 auto& parseInfo = parseInfos[i];
7709 if( parseInfo.parser->cardinality() == 0 || parseInfo.count < parseInfo.parser->cardinality() ) {
7710 result = parseInfo.parser->parse(exeName, result.value().remainingTokens());
7711 if (!result)
7712 return result;
7713 if (result.value().type() != ParseResultType::NoMatch) {
7714 tokenParsed = true;
7715 ++parseInfo.count;
7716 break;
7717 }
7718 }
7719 }
7720
7721 if( result.value().type() == ParseResultType::ShortCircuitAll )
7722 return result;
7723 if( !tokenParsed )
7724 return InternalParseResult::runtimeError( "Unrecognised token: " + result.value().remainingTokens()->token );
7725 }
7726 // !TBD Check missing required options
7727 return result;
7728 }
7729 };
7730
7731 template<typename DerivedT>
7732 template<typename T>
operator |(T const & other) const7733 auto ComposableParserImpl<DerivedT>::operator|( T const &other ) const -> Parser {
7734 return Parser() | static_cast<DerivedT const &>( *this ) | other;
7735 }
7736 } // namespace detail
7737
7738 // A Combined parser
7739 using detail::Parser;
7740
7741 // A parser for options
7742 using detail::Opt;
7743
7744 // A parser for arguments
7745 using detail::Arg;
7746
7747 // Wrapper for argc, argv from main()
7748 using detail::Args;
7749
7750 // Specifies the name of the executable
7751 using detail::ExeName;
7752
7753 // Convenience wrapper for option parser that specifies the help option
7754 using detail::Help;
7755
7756 // enum of result types from a parse
7757 using detail::ParseResultType;
7758
7759 // Result type for parser operation
7760 using detail::ParserResult;
7761
7762 }} // namespace Catch::clara
7763
7764 // end clara.hpp
7765 #ifdef __clang__
7766 #pragma clang diagnostic pop
7767 #endif
7768
7769 // Restore Clara's value for console width, if present
7770 #ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
7771 #define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
7772 #undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
7773 #endif
7774
7775 // end catch_clara.h
7776 namespace Catch {
7777
7778 clara::Parser makeCommandLineParser( ConfigData& config );
7779
7780 } // end namespace Catch
7781
7782 // end catch_commandline.h
7783 #include <fstream>
7784 #include <ctime>
7785
7786 namespace Catch {
7787
makeCommandLineParser(ConfigData & config)7788 clara::Parser makeCommandLineParser( ConfigData& config ) {
7789
7790 using namespace clara;
7791
7792 auto const setWarning = [&]( std::string const& warning ) {
7793 auto warningSet = [&]() {
7794 if( warning == "NoAssertions" )
7795 return WarnAbout::NoAssertions;
7796
7797 if ( warning == "NoTests" )
7798 return WarnAbout::NoTests;
7799
7800 return WarnAbout::Nothing;
7801 }();
7802
7803 if (warningSet == WarnAbout::Nothing)
7804 return ParserResult::runtimeError( "Unrecognised warning: '" + warning + "'" );
7805 config.warnings = static_cast<WarnAbout::What>( config.warnings | warningSet );
7806 return ParserResult::ok( ParseResultType::Matched );
7807 };
7808 auto const loadTestNamesFromFile = [&]( std::string const& filename ) {
7809 std::ifstream f( filename.c_str() );
7810 if( !f.is_open() )
7811 return ParserResult::runtimeError( "Unable to load input file: '" + filename + "'" );
7812
7813 std::string line;
7814 while( std::getline( f, line ) ) {
7815 line = trim(line);
7816 if( !line.empty() && !startsWith( line, '#' ) ) {
7817 if( !startsWith( line, '"' ) )
7818 line = '"' + line + '"';
7819 config.testsOrTags.push_back( line + ',' );
7820 }
7821 }
7822 return ParserResult::ok( ParseResultType::Matched );
7823 };
7824 auto const setTestOrder = [&]( std::string const& order ) {
7825 if( startsWith( "declared", order ) )
7826 config.runOrder = RunTests::InDeclarationOrder;
7827 else if( startsWith( "lexical", order ) )
7828 config.runOrder = RunTests::InLexicographicalOrder;
7829 else if( startsWith( "random", order ) )
7830 config.runOrder = RunTests::InRandomOrder;
7831 else
7832 return clara::ParserResult::runtimeError( "Unrecognised ordering: '" + order + "'" );
7833 return ParserResult::ok( ParseResultType::Matched );
7834 };
7835 auto const setRngSeed = [&]( std::string const& seed ) {
7836 if( seed != "time" )
7837 return clara::detail::convertInto( seed, config.rngSeed );
7838 config.rngSeed = static_cast<unsigned int>( std::time(nullptr) );
7839 return ParserResult::ok( ParseResultType::Matched );
7840 };
7841 auto const setColourUsage = [&]( std::string const& useColour ) {
7842 auto mode = toLower( useColour );
7843
7844 if( mode == "yes" )
7845 config.useColour = UseColour::Yes;
7846 else if( mode == "no" )
7847 config.useColour = UseColour::No;
7848 else if( mode == "auto" )
7849 config.useColour = UseColour::Auto;
7850 else
7851 return ParserResult::runtimeError( "colour mode must be one of: auto, yes or no. '" + useColour + "' not recognised" );
7852 return ParserResult::ok( ParseResultType::Matched );
7853 };
7854 auto const setWaitForKeypress = [&]( std::string const& keypress ) {
7855 auto keypressLc = toLower( keypress );
7856 if( keypressLc == "start" )
7857 config.waitForKeypress = WaitForKeypress::BeforeStart;
7858 else if( keypressLc == "exit" )
7859 config.waitForKeypress = WaitForKeypress::BeforeExit;
7860 else if( keypressLc == "both" )
7861 config.waitForKeypress = WaitForKeypress::BeforeStartAndExit;
7862 else
7863 return ParserResult::runtimeError( "keypress argument must be one of: start, exit or both. '" + keypress + "' not recognised" );
7864 return ParserResult::ok( ParseResultType::Matched );
7865 };
7866 auto const setVerbosity = [&]( std::string const& verbosity ) {
7867 auto lcVerbosity = toLower( verbosity );
7868 if( lcVerbosity == "quiet" )
7869 config.verbosity = Verbosity::Quiet;
7870 else if( lcVerbosity == "normal" )
7871 config.verbosity = Verbosity::Normal;
7872 else if( lcVerbosity == "high" )
7873 config.verbosity = Verbosity::High;
7874 else
7875 return ParserResult::runtimeError( "Unrecognised verbosity, '" + verbosity + "'" );
7876 return ParserResult::ok( ParseResultType::Matched );
7877 };
7878 auto const setReporter = [&]( std::string const& reporter ) {
7879 IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories();
7880
7881 auto lcReporter = toLower( reporter );
7882 auto result = factories.find( lcReporter );
7883
7884 if( factories.end() != result )
7885 config.reporterName = lcReporter;
7886 else
7887 return ParserResult::runtimeError( "Unrecognized reporter, '" + reporter + "'. Check available with --list-reporters" );
7888 return ParserResult::ok( ParseResultType::Matched );
7889 };
7890
7891 auto cli
7892 = ExeName( config.processName )
7893 | Help( config.showHelp )
7894 | Opt( config.listTests )
7895 ["-l"]["--list-tests"]
7896 ( "list all/matching test cases" )
7897 | Opt( config.listTags )
7898 ["-t"]["--list-tags"]
7899 ( "list all/matching tags" )
7900 | Opt( config.showSuccessfulTests )
7901 ["-s"]["--success"]
7902 ( "include successful tests in output" )
7903 | Opt( config.shouldDebugBreak )
7904 ["-b"]["--break"]
7905 ( "break into debugger on failure" )
7906 | Opt( config.noThrow )
7907 ["-e"]["--nothrow"]
7908 ( "skip exception tests" )
7909 | Opt( config.showInvisibles )
7910 ["-i"]["--invisibles"]
7911 ( "show invisibles (tabs, newlines)" )
7912 | Opt( config.outputFilename, "filename" )
7913 ["-o"]["--out"]
7914 ( "output filename" )
7915 | Opt( setReporter, "name" )
7916 ["-r"]["--reporter"]
7917 ( "reporter to use (defaults to console)" )
7918 | Opt( config.name, "name" )
7919 ["-n"]["--name"]
7920 ( "suite name" )
7921 | Opt( [&]( bool ){ config.abortAfter = 1; } )
7922 ["-a"]["--abort"]
7923 ( "abort at first failure" )
7924 | Opt( [&]( int x ){ config.abortAfter = x; }, "no. failures" )
7925 ["-x"]["--abortx"]
7926 ( "abort after x failures" )
7927 | Opt( setWarning, "warning name" )
7928 ["-w"]["--warn"]
7929 ( "enable warnings" )
7930 | Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" )
7931 ["-d"]["--durations"]
7932 ( "show test durations" )
7933 | Opt( loadTestNamesFromFile, "filename" )
7934 ["-f"]["--input-file"]
7935 ( "load test names to run from a file" )
7936 | Opt( config.filenamesAsTags )
7937 ["-#"]["--filenames-as-tags"]
7938 ( "adds a tag for the filename" )
7939 | Opt( config.sectionsToRun, "section name" )
7940 ["-c"]["--section"]
7941 ( "specify section to run" )
7942 | Opt( setVerbosity, "quiet|normal|high" )
7943 ["-v"]["--verbosity"]
7944 ( "set output verbosity" )
7945 | Opt( config.listTestNamesOnly )
7946 ["--list-test-names-only"]
7947 ( "list all/matching test cases names only" )
7948 | Opt( config.listReporters )
7949 ["--list-reporters"]
7950 ( "list all reporters" )
7951 | Opt( setTestOrder, "decl|lex|rand" )
7952 ["--order"]
7953 ( "test case order (defaults to decl)" )
7954 | Opt( setRngSeed, "'time'|number" )
7955 ["--rng-seed"]
7956 ( "set a specific seed for random numbers" )
7957 | Opt( setColourUsage, "yes|no" )
7958 ["--use-colour"]
7959 ( "should output be colourised" )
7960 | Opt( config.libIdentify )
7961 ["--libidentify"]
7962 ( "report name and version according to libidentify standard" )
7963 | Opt( setWaitForKeypress, "start|exit|both" )
7964 ["--wait-for-keypress"]
7965 ( "waits for a keypress before exiting" )
7966 | Opt( config.benchmarkResolutionMultiple, "multiplier" )
7967 ["--benchmark-resolution-multiple"]
7968 ( "multiple of clock resolution to run benchmarks" )
7969
7970 | Arg( config.testsOrTags, "test name|pattern|tags" )
7971 ( "which test or tests to use" );
7972
7973 return cli;
7974 }
7975
7976 } // end namespace Catch
7977 // end catch_commandline.cpp
7978 // start catch_common.cpp
7979
7980 #include <cstring>
7981 #include <ostream>
7982
7983 namespace Catch {
7984
empty() const7985 bool SourceLineInfo::empty() const noexcept {
7986 return file[0] == '\0';
7987 }
operator ==(SourceLineInfo const & other) const7988 bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const noexcept {
7989 return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0);
7990 }
operator <(SourceLineInfo const & other) const7991 bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const noexcept {
7992 // We can assume that the same file will usually have the same pointer.
7993 // Thus, if the pointers are the same, there is no point in calling the strcmp
7994 return line < other.line || ( line == other.line && file != other.file && (std::strcmp(file, other.file) < 0));
7995 }
7996
operator <<(std::ostream & os,SourceLineInfo const & info)7997 std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) {
7998 #ifndef __GNUG__
7999 os << info.file << '(' << info.line << ')';
8000 #else
8001 os << info.file << ':' << info.line;
8002 #endif
8003 return os;
8004 }
8005
operator +() const8006 std::string StreamEndStop::operator+() const {
8007 return std::string();
8008 }
8009
8010 NonCopyable::NonCopyable() = default;
8011 NonCopyable::~NonCopyable() = default;
8012
8013 }
8014 // end catch_common.cpp
8015 // start catch_config.cpp
8016
8017 namespace Catch {
8018
Config(ConfigData const & data)8019 Config::Config( ConfigData const& data )
8020 : m_data( data ),
8021 m_stream( openStream() )
8022 {
8023 TestSpecParser parser(ITagAliasRegistry::get());
8024 if (data.testsOrTags.empty()) {
8025 parser.parse("~[.]"); // All not hidden tests
8026 }
8027 else {
8028 m_hasTestFilters = true;
8029 for( auto const& testOrTags : data.testsOrTags )
8030 parser.parse( testOrTags );
8031 }
8032 m_testSpec = parser.testSpec();
8033 }
8034
getFilename() const8035 std::string const& Config::getFilename() const {
8036 return m_data.outputFilename ;
8037 }
8038
listTests() const8039 bool Config::listTests() const { return m_data.listTests; }
listTestNamesOnly() const8040 bool Config::listTestNamesOnly() const { return m_data.listTestNamesOnly; }
listTags() const8041 bool Config::listTags() const { return m_data.listTags; }
listReporters() const8042 bool Config::listReporters() const { return m_data.listReporters; }
8043
getProcessName() const8044 std::string Config::getProcessName() const { return m_data.processName; }
getReporterName() const8045 std::string const& Config::getReporterName() const { return m_data.reporterName; }
8046
getTestsOrTags() const8047 std::vector<std::string> const& Config::getTestsOrTags() const { return m_data.testsOrTags; }
getSectionsToRun() const8048 std::vector<std::string> const& Config::getSectionsToRun() const { return m_data.sectionsToRun; }
8049
testSpec() const8050 TestSpec const& Config::testSpec() const { return m_testSpec; }
hasTestFilters() const8051 bool Config::hasTestFilters() const { return m_hasTestFilters; }
8052
showHelp() const8053 bool Config::showHelp() const { return m_data.showHelp; }
8054
8055 // IConfig interface
allowThrows() const8056 bool Config::allowThrows() const { return !m_data.noThrow; }
stream() const8057 std::ostream& Config::stream() const { return m_stream->stream(); }
name() const8058 std::string Config::name() const { return m_data.name.empty() ? m_data.processName : m_data.name; }
includeSuccessfulResults() const8059 bool Config::includeSuccessfulResults() const { return m_data.showSuccessfulTests; }
warnAboutMissingAssertions() const8060 bool Config::warnAboutMissingAssertions() const { return !!(m_data.warnings & WarnAbout::NoAssertions); }
warnAboutNoTests() const8061 bool Config::warnAboutNoTests() const { return !!(m_data.warnings & WarnAbout::NoTests); }
showDurations() const8062 ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; }
runOrder() const8063 RunTests::InWhatOrder Config::runOrder() const { return m_data.runOrder; }
rngSeed() const8064 unsigned int Config::rngSeed() const { return m_data.rngSeed; }
benchmarkResolutionMultiple() const8065 int Config::benchmarkResolutionMultiple() const { return m_data.benchmarkResolutionMultiple; }
useColour() const8066 UseColour::YesOrNo Config::useColour() const { return m_data.useColour; }
shouldDebugBreak() const8067 bool Config::shouldDebugBreak() const { return m_data.shouldDebugBreak; }
abortAfter() const8068 int Config::abortAfter() const { return m_data.abortAfter; }
showInvisibles() const8069 bool Config::showInvisibles() const { return m_data.showInvisibles; }
verbosity() const8070 Verbosity Config::verbosity() const { return m_data.verbosity; }
8071
openStream()8072 IStream const* Config::openStream() {
8073 return Catch::makeStream(m_data.outputFilename);
8074 }
8075
8076 } // end namespace Catch
8077 // end catch_config.cpp
8078 // start catch_console_colour.cpp
8079
8080 #if defined(__clang__)
8081 # pragma clang diagnostic push
8082 # pragma clang diagnostic ignored "-Wexit-time-destructors"
8083 #endif
8084
8085 // start catch_errno_guard.h
8086
8087 namespace Catch {
8088
8089 class ErrnoGuard {
8090 public:
8091 ErrnoGuard();
8092 ~ErrnoGuard();
8093 private:
8094 int m_oldErrno;
8095 };
8096
8097 }
8098
8099 // end catch_errno_guard.h
8100 #include <sstream>
8101
8102 namespace Catch {
8103 namespace {
8104
8105 struct IColourImpl {
8106 virtual ~IColourImpl() = default;
8107 virtual void use( Colour::Code _colourCode ) = 0;
8108 };
8109
8110 struct NoColourImpl : IColourImpl {
useCatch::__anon2c2dcc261311::NoColourImpl8111 void use( Colour::Code ) {}
8112
instanceCatch::__anon2c2dcc261311::NoColourImpl8113 static IColourImpl* instance() {
8114 static NoColourImpl s_instance;
8115 return &s_instance;
8116 }
8117 };
8118
8119 } // anon namespace
8120 } // namespace Catch
8121
8122 #if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI )
8123 # ifdef CATCH_PLATFORM_WINDOWS
8124 # define CATCH_CONFIG_COLOUR_WINDOWS
8125 # else
8126 # define CATCH_CONFIG_COLOUR_ANSI
8127 # endif
8128 #endif
8129
8130 #if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) /////////////////////////////////////////
8131
8132 namespace Catch {
8133 namespace {
8134
8135 class Win32ColourImpl : public IColourImpl {
8136 public:
Win32ColourImpl()8137 Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) )
8138 {
8139 CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
8140 GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo );
8141 originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY );
8142 originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY );
8143 }
8144
use(Colour::Code _colourCode)8145 virtual void use( Colour::Code _colourCode ) override {
8146 switch( _colourCode ) {
8147 case Colour::None: return setTextAttribute( originalForegroundAttributes );
8148 case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
8149 case Colour::Red: return setTextAttribute( FOREGROUND_RED );
8150 case Colour::Green: return setTextAttribute( FOREGROUND_GREEN );
8151 case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE );
8152 case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN );
8153 case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN );
8154 case Colour::Grey: return setTextAttribute( 0 );
8155
8156 case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY );
8157 case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED );
8158 case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN );
8159 case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
8160 case Colour::BrightYellow: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN );
8161
8162 case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" );
8163
8164 default:
8165 CATCH_ERROR( "Unknown colour requested" );
8166 }
8167 }
8168
8169 private:
setTextAttribute(WORD _textAttribute)8170 void setTextAttribute( WORD _textAttribute ) {
8171 SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes );
8172 }
8173 HANDLE stdoutHandle;
8174 WORD originalForegroundAttributes;
8175 WORD originalBackgroundAttributes;
8176 };
8177
platformColourInstance()8178 IColourImpl* platformColourInstance() {
8179 static Win32ColourImpl s_instance;
8180
8181 IConfigPtr config = getCurrentContext().getConfig();
8182 UseColour::YesOrNo colourMode = config
8183 ? config->useColour()
8184 : UseColour::Auto;
8185 if( colourMode == UseColour::Auto )
8186 colourMode = UseColour::Yes;
8187 return colourMode == UseColour::Yes
8188 ? &s_instance
8189 : NoColourImpl::instance();
8190 }
8191
8192 } // end anon namespace
8193 } // end namespace Catch
8194
8195 #elif defined( CATCH_CONFIG_COLOUR_ANSI ) //////////////////////////////////////
8196
8197 #include <unistd.h>
8198
8199 namespace Catch {
8200 namespace {
8201
8202 // use POSIX/ ANSI console terminal codes
8203 // Thanks to Adam Strzelecki for original contribution
8204 // (http://github.com/nanoant)
8205 // https://github.com/philsquared/Catch/pull/131
8206 class PosixColourImpl : public IColourImpl {
8207 public:
use(Colour::Code _colourCode)8208 virtual void use( Colour::Code _colourCode ) override {
8209 switch( _colourCode ) {
8210 case Colour::None:
8211 case Colour::White: return setColour( "[0m" );
8212 case Colour::Red: return setColour( "[0;31m" );
8213 case Colour::Green: return setColour( "[0;32m" );
8214 case Colour::Blue: return setColour( "[0;34m" );
8215 case Colour::Cyan: return setColour( "[0;36m" );
8216 case Colour::Yellow: return setColour( "[0;33m" );
8217 case Colour::Grey: return setColour( "[1;30m" );
8218
8219 case Colour::LightGrey: return setColour( "[0;37m" );
8220 case Colour::BrightRed: return setColour( "[1;31m" );
8221 case Colour::BrightGreen: return setColour( "[1;32m" );
8222 case Colour::BrightWhite: return setColour( "[1;37m" );
8223 case Colour::BrightYellow: return setColour( "[1;33m" );
8224
8225 case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" );
8226 default: CATCH_INTERNAL_ERROR( "Unknown colour requested" );
8227 }
8228 }
instance()8229 static IColourImpl* instance() {
8230 static PosixColourImpl s_instance;
8231 return &s_instance;
8232 }
8233
8234 private:
setColour(const char * _escapeCode)8235 void setColour( const char* _escapeCode ) {
8236 getCurrentContext().getConfig()->stream()
8237 << '\033' << _escapeCode;
8238 }
8239 };
8240
useColourOnPlatform()8241 bool useColourOnPlatform() {
8242 return
8243 #ifdef CATCH_PLATFORM_MAC
8244 !isDebuggerActive() &&
8245 #endif
8246 #if !(defined(__DJGPP__) && defined(__STRICT_ANSI__))
8247 isatty(STDOUT_FILENO)
8248 #else
8249 false
8250 #endif
8251 ;
8252 }
platformColourInstance()8253 IColourImpl* platformColourInstance() {
8254 ErrnoGuard guard;
8255 IConfigPtr config = getCurrentContext().getConfig();
8256 UseColour::YesOrNo colourMode = config
8257 ? config->useColour()
8258 : UseColour::Auto;
8259 if( colourMode == UseColour::Auto )
8260 colourMode = useColourOnPlatform()
8261 ? UseColour::Yes
8262 : UseColour::No;
8263 return colourMode == UseColour::Yes
8264 ? PosixColourImpl::instance()
8265 : NoColourImpl::instance();
8266 }
8267
8268 } // end anon namespace
8269 } // end namespace Catch
8270
8271 #else // not Windows or ANSI ///////////////////////////////////////////////
8272
8273 namespace Catch {
8274
platformColourInstance()8275 static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); }
8276
8277 } // end namespace Catch
8278
8279 #endif // Windows/ ANSI/ None
8280
8281 namespace Catch {
8282
Colour(Code _colourCode)8283 Colour::Colour( Code _colourCode ) { use( _colourCode ); }
Colour(Colour && rhs)8284 Colour::Colour( Colour&& rhs ) noexcept {
8285 m_moved = rhs.m_moved;
8286 rhs.m_moved = true;
8287 }
operator =(Colour && rhs)8288 Colour& Colour::operator=( Colour&& rhs ) noexcept {
8289 m_moved = rhs.m_moved;
8290 rhs.m_moved = true;
8291 return *this;
8292 }
8293
~Colour()8294 Colour::~Colour(){ if( !m_moved ) use( None ); }
8295
use(Code _colourCode)8296 void Colour::use( Code _colourCode ) {
8297 static IColourImpl* impl = platformColourInstance();
8298 impl->use( _colourCode );
8299 }
8300
operator <<(std::ostream & os,Colour const &)8301 std::ostream& operator << ( std::ostream& os, Colour const& ) {
8302 return os;
8303 }
8304
8305 } // end namespace Catch
8306
8307 #if defined(__clang__)
8308 # pragma clang diagnostic pop
8309 #endif
8310
8311 // end catch_console_colour.cpp
8312 // start catch_context.cpp
8313
8314 namespace Catch {
8315
8316 class Context : public IMutableContext, NonCopyable {
8317
8318 public: // IContext
getResultCapture()8319 virtual IResultCapture* getResultCapture() override {
8320 return m_resultCapture;
8321 }
getRunner()8322 virtual IRunner* getRunner() override {
8323 return m_runner;
8324 }
8325
getConfig() const8326 virtual IConfigPtr const& getConfig() const override {
8327 return m_config;
8328 }
8329
8330 virtual ~Context() override;
8331
8332 public: // IMutableContext
setResultCapture(IResultCapture * resultCapture)8333 virtual void setResultCapture( IResultCapture* resultCapture ) override {
8334 m_resultCapture = resultCapture;
8335 }
setRunner(IRunner * runner)8336 virtual void setRunner( IRunner* runner ) override {
8337 m_runner = runner;
8338 }
setConfig(IConfigPtr const & config)8339 virtual void setConfig( IConfigPtr const& config ) override {
8340 m_config = config;
8341 }
8342
8343 friend IMutableContext& getCurrentMutableContext();
8344
8345 private:
8346 IConfigPtr m_config;
8347 IRunner* m_runner = nullptr;
8348 IResultCapture* m_resultCapture = nullptr;
8349 };
8350
8351 IMutableContext *IMutableContext::currentContext = nullptr;
8352
createContext()8353 void IMutableContext::createContext()
8354 {
8355 currentContext = new Context();
8356 }
8357
cleanUpContext()8358 void cleanUpContext() {
8359 delete IMutableContext::currentContext;
8360 IMutableContext::currentContext = nullptr;
8361 }
8362 IContext::~IContext() = default;
8363 IMutableContext::~IMutableContext() = default;
8364 Context::~Context() = default;
8365 }
8366 // end catch_context.cpp
8367 // start catch_debug_console.cpp
8368
8369 // start catch_debug_console.h
8370
8371 #include <string>
8372
8373 namespace Catch {
8374 void writeToDebugConsole( std::string const& text );
8375 }
8376
8377 // end catch_debug_console.h
8378 #ifdef CATCH_PLATFORM_WINDOWS
8379
8380 namespace Catch {
writeToDebugConsole(std::string const & text)8381 void writeToDebugConsole( std::string const& text ) {
8382 ::OutputDebugStringA( text.c_str() );
8383 }
8384 }
8385
8386 #else
8387
8388 namespace Catch {
writeToDebugConsole(std::string const & text)8389 void writeToDebugConsole( std::string const& text ) {
8390 // !TBD: Need a version for Mac/ XCode and other IDEs
8391 Catch::cout() << text;
8392 }
8393 }
8394
8395 #endif // Platform
8396 // end catch_debug_console.cpp
8397 // start catch_debugger.cpp
8398
8399 #ifdef CATCH_PLATFORM_MAC
8400
8401 # include <assert.h>
8402 # include <stdbool.h>
8403 # include <sys/types.h>
8404 # include <unistd.h>
8405 # include <sys/sysctl.h>
8406 # include <cstddef>
8407 # include <ostream>
8408
8409 namespace Catch {
8410
8411 // The following function is taken directly from the following technical note:
8412 // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html
8413
8414 // Returns true if the current process is being debugged (either
8415 // running under the debugger or has a debugger attached post facto).
isDebuggerActive()8416 bool isDebuggerActive(){
8417
8418 int mib[4];
8419 struct kinfo_proc info;
8420 std::size_t size;
8421
8422 // Initialize the flags so that, if sysctl fails for some bizarre
8423 // reason, we get a predictable result.
8424
8425 info.kp_proc.p_flag = 0;
8426
8427 // Initialize mib, which tells sysctl the info we want, in this case
8428 // we're looking for information about a specific process ID.
8429
8430 mib[0] = CTL_KERN;
8431 mib[1] = KERN_PROC;
8432 mib[2] = KERN_PROC_PID;
8433 mib[3] = getpid();
8434
8435 // Call sysctl.
8436
8437 size = sizeof(info);
8438 if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, nullptr, 0) != 0 ) {
8439 Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl;
8440 return false;
8441 }
8442
8443 // We're being debugged if the P_TRACED flag is set.
8444
8445 return ( (info.kp_proc.p_flag & P_TRACED) != 0 );
8446 }
8447 } // namespace Catch
8448
8449 #elif defined(CATCH_PLATFORM_LINUX)
8450 #include <fstream>
8451 #include <string>
8452
8453 namespace Catch{
8454 // The standard POSIX way of detecting a debugger is to attempt to
8455 // ptrace() the process, but this needs to be done from a child and not
8456 // this process itself to still allow attaching to this process later
8457 // if wanted, so is rather heavy. Under Linux we have the PID of the
8458 // "debugger" (which doesn't need to be gdb, of course, it could also
8459 // be strace, for example) in /proc/$PID/status, so just get it from
8460 // there instead.
isDebuggerActive()8461 bool isDebuggerActive(){
8462 // Libstdc++ has a bug, where std::ifstream sets errno to 0
8463 // This way our users can properly assert over errno values
8464 ErrnoGuard guard;
8465 std::ifstream in("/proc/self/status");
8466 for( std::string line; std::getline(in, line); ) {
8467 static const int PREFIX_LEN = 11;
8468 if( line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0 ) {
8469 // We're traced if the PID is not 0 and no other PID starts
8470 // with 0 digit, so it's enough to check for just a single
8471 // character.
8472 return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0';
8473 }
8474 }
8475
8476 return false;
8477 }
8478 } // namespace Catch
8479 #elif defined(_MSC_VER)
8480 extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
8481 namespace Catch {
isDebuggerActive()8482 bool isDebuggerActive() {
8483 return IsDebuggerPresent() != 0;
8484 }
8485 }
8486 #elif defined(__MINGW32__)
8487 extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
8488 namespace Catch {
isDebuggerActive()8489 bool isDebuggerActive() {
8490 return IsDebuggerPresent() != 0;
8491 }
8492 }
8493 #else
8494 namespace Catch {
isDebuggerActive()8495 bool isDebuggerActive() { return false; }
8496 }
8497 #endif // Platform
8498 // end catch_debugger.cpp
8499 // start catch_decomposer.cpp
8500
8501 namespace Catch {
8502
8503 ITransientExpression::~ITransientExpression() = default;
8504
formatReconstructedExpression(std::ostream & os,std::string const & lhs,StringRef op,std::string const & rhs)8505 void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ) {
8506 if( lhs.size() + rhs.size() < 40 &&
8507 lhs.find('\n') == std::string::npos &&
8508 rhs.find('\n') == std::string::npos )
8509 os << lhs << " " << op << " " << rhs;
8510 else
8511 os << lhs << "\n" << op << "\n" << rhs;
8512 }
8513 }
8514 // end catch_decomposer.cpp
8515 // start catch_enforce.cpp
8516
8517 namespace Catch {
8518 #if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER)
8519 [[noreturn]]
throw_exception(std::exception const & e)8520 void throw_exception(std::exception const& e) {
8521 Catch::cerr() << "Catch will terminate because it needed to throw an exception.\n"
8522 << "The message was: " << e.what() << '\n';
8523 std::terminate();
8524 }
8525 #endif
8526 } // namespace Catch;
8527 // end catch_enforce.cpp
8528 // start catch_errno_guard.cpp
8529
8530 #include <cerrno>
8531
8532 namespace Catch {
ErrnoGuard()8533 ErrnoGuard::ErrnoGuard():m_oldErrno(errno){}
~ErrnoGuard()8534 ErrnoGuard::~ErrnoGuard() { errno = m_oldErrno; }
8535 }
8536 // end catch_errno_guard.cpp
8537 // start catch_exception_translator_registry.cpp
8538
8539 // start catch_exception_translator_registry.h
8540
8541 #include <vector>
8542 #include <string>
8543 #include <memory>
8544
8545 namespace Catch {
8546
8547 class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry {
8548 public:
8549 ~ExceptionTranslatorRegistry();
8550 virtual void registerTranslator( const IExceptionTranslator* translator );
8551 virtual std::string translateActiveException() const override;
8552 std::string tryTranslators() const;
8553
8554 private:
8555 std::vector<std::unique_ptr<IExceptionTranslator const>> m_translators;
8556 };
8557 }
8558
8559 // end catch_exception_translator_registry.h
8560 #ifdef __OBJC__
8561 #import "Foundation/Foundation.h"
8562 #endif
8563
8564 namespace Catch {
8565
~ExceptionTranslatorRegistry()8566 ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() {
8567 }
8568
registerTranslator(const IExceptionTranslator * translator)8569 void ExceptionTranslatorRegistry::registerTranslator( const IExceptionTranslator* translator ) {
8570 m_translators.push_back( std::unique_ptr<const IExceptionTranslator>( translator ) );
8571 }
8572
8573 #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
translateActiveException() const8574 std::string ExceptionTranslatorRegistry::translateActiveException() const {
8575 try {
8576 #ifdef __OBJC__
8577 // In Objective-C try objective-c exceptions first
8578 @try {
8579 return tryTranslators();
8580 }
8581 @catch (NSException *exception) {
8582 return Catch::Detail::stringify( [exception description] );
8583 }
8584 #else
8585 // Compiling a mixed mode project with MSVC means that CLR
8586 // exceptions will be caught in (...) as well. However, these
8587 // do not fill-in std::current_exception and thus lead to crash
8588 // when attempting rethrow.
8589 // /EHa switch also causes structured exceptions to be caught
8590 // here, but they fill-in current_exception properly, so
8591 // at worst the output should be a little weird, instead of
8592 // causing a crash.
8593 if (std::current_exception() == nullptr) {
8594 return "Non C++ exception. Possibly a CLR exception.";
8595 }
8596 return tryTranslators();
8597 #endif
8598 }
8599 catch( TestFailureException& ) {
8600 std::rethrow_exception(std::current_exception());
8601 }
8602 catch( std::exception& ex ) {
8603 return ex.what();
8604 }
8605 catch( std::string& msg ) {
8606 return msg;
8607 }
8608 catch( const char* msg ) {
8609 return msg;
8610 }
8611 catch(...) {
8612 return "Unknown exception";
8613 }
8614 }
8615
tryTranslators() const8616 std::string ExceptionTranslatorRegistry::tryTranslators() const {
8617 if (m_translators.empty()) {
8618 std::rethrow_exception(std::current_exception());
8619 } else {
8620 return m_translators[0]->translate(m_translators.begin() + 1, m_translators.end());
8621 }
8622 }
8623
8624 #else // ^^ Exceptions are enabled // Exceptions are disabled vv
translateActiveException() const8625 std::string ExceptionTranslatorRegistry::translateActiveException() const {
8626 CATCH_INTERNAL_ERROR("Attempted to translate active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
8627 }
8628
tryTranslators() const8629 std::string ExceptionTranslatorRegistry::tryTranslators() const {
8630 CATCH_INTERNAL_ERROR("Attempted to use exception translators under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
8631 }
8632 #endif
8633
8634 }
8635 // end catch_exception_translator_registry.cpp
8636 // start catch_fatal_condition.cpp
8637
8638 #if defined(__GNUC__)
8639 # pragma GCC diagnostic push
8640 # pragma GCC diagnostic ignored "-Wmissing-field-initializers"
8641 #endif
8642
8643 #if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS )
8644
8645 namespace {
8646 // Report the error condition
reportFatal(char const * const message)8647 void reportFatal( char const * const message ) {
8648 Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message );
8649 }
8650 }
8651
8652 #endif // signals/SEH handling
8653
8654 #if defined( CATCH_CONFIG_WINDOWS_SEH )
8655
8656 namespace Catch {
8657 struct SignalDefs { DWORD id; const char* name; };
8658
8659 // There is no 1-1 mapping between signals and windows exceptions.
8660 // Windows can easily distinguish between SO and SigSegV,
8661 // but SigInt, SigTerm, etc are handled differently.
8662 static SignalDefs signalDefs[] = {
8663 { EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal" },
8664 { EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" },
8665 { EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" },
8666 { EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" },
8667 };
8668
handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo)8669 LONG CALLBACK FatalConditionHandler::handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) {
8670 for (auto const& def : signalDefs) {
8671 if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) {
8672 reportFatal(def.name);
8673 }
8674 }
8675 // If its not an exception we care about, pass it along.
8676 // This stops us from eating debugger breaks etc.
8677 return EXCEPTION_CONTINUE_SEARCH;
8678 }
8679
FatalConditionHandler()8680 FatalConditionHandler::FatalConditionHandler() {
8681 isSet = true;
8682 // 32k seems enough for Catch to handle stack overflow,
8683 // but the value was found experimentally, so there is no strong guarantee
8684 guaranteeSize = 32 * 1024;
8685 exceptionHandlerHandle = nullptr;
8686 // Register as first handler in current chain
8687 exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException);
8688 // Pass in guarantee size to be filled
8689 SetThreadStackGuarantee(&guaranteeSize);
8690 }
8691
reset()8692 void FatalConditionHandler::reset() {
8693 if (isSet) {
8694 RemoveVectoredExceptionHandler(exceptionHandlerHandle);
8695 SetThreadStackGuarantee(&guaranteeSize);
8696 exceptionHandlerHandle = nullptr;
8697 isSet = false;
8698 }
8699 }
8700
~FatalConditionHandler()8701 FatalConditionHandler::~FatalConditionHandler() {
8702 reset();
8703 }
8704
8705 bool FatalConditionHandler::isSet = false;
8706 ULONG FatalConditionHandler::guaranteeSize = 0;
8707 PVOID FatalConditionHandler::exceptionHandlerHandle = nullptr;
8708
8709 } // namespace Catch
8710
8711 #elif defined( CATCH_CONFIG_POSIX_SIGNALS )
8712
8713 namespace Catch {
8714
8715 struct SignalDefs {
8716 int id;
8717 const char* name;
8718 };
8719
8720 // 32kb for the alternate stack seems to be sufficient. However, this value
8721 // is experimentally determined, so that's not guaranteed.
8722 constexpr static std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ;
8723
8724 static SignalDefs signalDefs[] = {
8725 { SIGINT, "SIGINT - Terminal interrupt signal" },
8726 { SIGILL, "SIGILL - Illegal instruction signal" },
8727 { SIGFPE, "SIGFPE - Floating point error signal" },
8728 { SIGSEGV, "SIGSEGV - Segmentation violation signal" },
8729 { SIGTERM, "SIGTERM - Termination request signal" },
8730 { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" }
8731 };
8732
handleSignal(int sig)8733 void FatalConditionHandler::handleSignal( int sig ) {
8734 char const * name = "<unknown signal>";
8735 for (auto const& def : signalDefs) {
8736 if (sig == def.id) {
8737 name = def.name;
8738 break;
8739 }
8740 }
8741 reset();
8742 reportFatal(name);
8743 raise( sig );
8744 }
8745
FatalConditionHandler()8746 FatalConditionHandler::FatalConditionHandler() {
8747 isSet = true;
8748 stack_t sigStack;
8749 sigStack.ss_sp = altStackMem;
8750 sigStack.ss_size = sigStackSize;
8751 sigStack.ss_flags = 0;
8752 sigaltstack(&sigStack, &oldSigStack);
8753 struct sigaction sa = { };
8754
8755 sa.sa_handler = handleSignal;
8756 sa.sa_flags = SA_ONSTACK;
8757 for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) {
8758 sigaction(signalDefs[i].id, &sa, &oldSigActions[i]);
8759 }
8760 }
8761
~FatalConditionHandler()8762 FatalConditionHandler::~FatalConditionHandler() {
8763 reset();
8764 }
8765
reset()8766 void FatalConditionHandler::reset() {
8767 if( isSet ) {
8768 // Set signals back to previous values -- hopefully nobody overwrote them in the meantime
8769 for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) {
8770 sigaction(signalDefs[i].id, &oldSigActions[i], nullptr);
8771 }
8772 // Return the old stack
8773 sigaltstack(&oldSigStack, nullptr);
8774 isSet = false;
8775 }
8776 }
8777
8778 bool FatalConditionHandler::isSet = false;
8779 struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {};
8780 stack_t FatalConditionHandler::oldSigStack = {};
8781 char FatalConditionHandler::altStackMem[sigStackSize] = {};
8782
8783 } // namespace Catch
8784
8785 #else
8786
8787 namespace Catch {
reset()8788 void FatalConditionHandler::reset() {}
8789 }
8790
8791 #endif // signals/SEH handling
8792
8793 #if defined(__GNUC__)
8794 # pragma GCC diagnostic pop
8795 #endif
8796 // end catch_fatal_condition.cpp
8797 // start catch_generators.cpp
8798
8799 // start catch_random_number_generator.h
8800
8801 #include <algorithm>
8802 #include <random>
8803
8804 namespace Catch {
8805
8806 struct IConfig;
8807
8808 std::mt19937& rng();
8809 void seedRng( IConfig const& config );
8810 unsigned int rngSeed();
8811
8812 }
8813
8814 // end catch_random_number_generator.h
8815 #include <limits>
8816 #include <set>
8817
8818 namespace Catch {
8819
~IGeneratorTracker()8820 IGeneratorTracker::~IGeneratorTracker() {}
8821
what() const8822 const char* GeneratorException::what() const noexcept {
8823 return m_msg;
8824 }
8825
8826 namespace Generators {
8827
~GeneratorUntypedBase()8828 GeneratorUntypedBase::~GeneratorUntypedBase() {}
8829
acquireGeneratorTracker(SourceLineInfo const & lineInfo)8830 auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {
8831 return getResultCapture().acquireGeneratorTracker( lineInfo );
8832 }
8833
8834 } // namespace Generators
8835 } // namespace Catch
8836 // end catch_generators.cpp
8837 // start catch_interfaces_capture.cpp
8838
8839 namespace Catch {
8840 IResultCapture::~IResultCapture() = default;
8841 }
8842 // end catch_interfaces_capture.cpp
8843 // start catch_interfaces_config.cpp
8844
8845 namespace Catch {
8846 IConfig::~IConfig() = default;
8847 }
8848 // end catch_interfaces_config.cpp
8849 // start catch_interfaces_exception.cpp
8850
8851 namespace Catch {
8852 IExceptionTranslator::~IExceptionTranslator() = default;
8853 IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() = default;
8854 }
8855 // end catch_interfaces_exception.cpp
8856 // start catch_interfaces_registry_hub.cpp
8857
8858 namespace Catch {
8859 IRegistryHub::~IRegistryHub() = default;
8860 IMutableRegistryHub::~IMutableRegistryHub() = default;
8861 }
8862 // end catch_interfaces_registry_hub.cpp
8863 // start catch_interfaces_reporter.cpp
8864
8865 // start catch_reporter_listening.h
8866
8867 namespace Catch {
8868
8869 class ListeningReporter : public IStreamingReporter {
8870 using Reporters = std::vector<IStreamingReporterPtr>;
8871 Reporters m_listeners;
8872 IStreamingReporterPtr m_reporter = nullptr;
8873 ReporterPreferences m_preferences;
8874
8875 public:
8876 ListeningReporter();
8877
8878 void addListener( IStreamingReporterPtr&& listener );
8879 void addReporter( IStreamingReporterPtr&& reporter );
8880
8881 public: // IStreamingReporter
8882
8883 ReporterPreferences getPreferences() const override;
8884
8885 void noMatchingTestCases( std::string const& spec ) override;
8886
8887 static std::set<Verbosity> getSupportedVerbosities();
8888
8889 void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) override;
8890 void benchmarkEnded( BenchmarkStats const& benchmarkStats ) override;
8891
8892 void testRunStarting( TestRunInfo const& testRunInfo ) override;
8893 void testGroupStarting( GroupInfo const& groupInfo ) override;
8894 void testCaseStarting( TestCaseInfo const& testInfo ) override;
8895 void sectionStarting( SectionInfo const& sectionInfo ) override;
8896 void assertionStarting( AssertionInfo const& assertionInfo ) override;
8897
8898 // The return value indicates if the messages buffer should be cleared:
8899 bool assertionEnded( AssertionStats const& assertionStats ) override;
8900 void sectionEnded( SectionStats const& sectionStats ) override;
8901 void testCaseEnded( TestCaseStats const& testCaseStats ) override;
8902 void testGroupEnded( TestGroupStats const& testGroupStats ) override;
8903 void testRunEnded( TestRunStats const& testRunStats ) override;
8904
8905 void skipTest( TestCaseInfo const& testInfo ) override;
8906 bool isMulti() const override;
8907
8908 };
8909
8910 } // end namespace Catch
8911
8912 // end catch_reporter_listening.h
8913 namespace Catch {
8914
ReporterConfig(IConfigPtr const & _fullConfig)8915 ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig )
8916 : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {}
8917
ReporterConfig(IConfigPtr const & _fullConfig,std::ostream & _stream)8918 ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream )
8919 : m_stream( &_stream ), m_fullConfig( _fullConfig ) {}
8920
stream() const8921 std::ostream& ReporterConfig::stream() const { return *m_stream; }
fullConfig() const8922 IConfigPtr ReporterConfig::fullConfig() const { return m_fullConfig; }
8923
TestRunInfo(std::string const & _name)8924 TestRunInfo::TestRunInfo( std::string const& _name ) : name( _name ) {}
8925
GroupInfo(std::string const & _name,std::size_t _groupIndex,std::size_t _groupsCount)8926 GroupInfo::GroupInfo( std::string const& _name,
8927 std::size_t _groupIndex,
8928 std::size_t _groupsCount )
8929 : name( _name ),
8930 groupIndex( _groupIndex ),
8931 groupsCounts( _groupsCount )
8932 {}
8933
AssertionStats(AssertionResult const & _assertionResult,std::vector<MessageInfo> const & _infoMessages,Totals const & _totals)8934 AssertionStats::AssertionStats( AssertionResult const& _assertionResult,
8935 std::vector<MessageInfo> const& _infoMessages,
8936 Totals const& _totals )
8937 : assertionResult( _assertionResult ),
8938 infoMessages( _infoMessages ),
8939 totals( _totals )
8940 {
8941 assertionResult.m_resultData.lazyExpression.m_transientExpression = _assertionResult.m_resultData.lazyExpression.m_transientExpression;
8942
8943 if( assertionResult.hasMessage() ) {
8944 // Copy message into messages list.
8945 // !TBD This should have been done earlier, somewhere
8946 MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() );
8947 builder << assertionResult.getMessage();
8948 builder.m_info.message = builder.m_stream.str();
8949
8950 infoMessages.push_back( builder.m_info );
8951 }
8952 }
8953
8954 AssertionStats::~AssertionStats() = default;
8955
SectionStats(SectionInfo const & _sectionInfo,Counts const & _assertions,double _durationInSeconds,bool _missingAssertions)8956 SectionStats::SectionStats( SectionInfo const& _sectionInfo,
8957 Counts const& _assertions,
8958 double _durationInSeconds,
8959 bool _missingAssertions )
8960 : sectionInfo( _sectionInfo ),
8961 assertions( _assertions ),
8962 durationInSeconds( _durationInSeconds ),
8963 missingAssertions( _missingAssertions )
8964 {}
8965
8966 SectionStats::~SectionStats() = default;
8967
TestCaseStats(TestCaseInfo const & _testInfo,Totals const & _totals,std::string const & _stdOut,std::string const & _stdErr,bool _aborting)8968 TestCaseStats::TestCaseStats( TestCaseInfo const& _testInfo,
8969 Totals const& _totals,
8970 std::string const& _stdOut,
8971 std::string const& _stdErr,
8972 bool _aborting )
8973 : testInfo( _testInfo ),
8974 totals( _totals ),
8975 stdOut( _stdOut ),
8976 stdErr( _stdErr ),
8977 aborting( _aborting )
8978 {}
8979
8980 TestCaseStats::~TestCaseStats() = default;
8981
TestGroupStats(GroupInfo const & _groupInfo,Totals const & _totals,bool _aborting)8982 TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo,
8983 Totals const& _totals,
8984 bool _aborting )
8985 : groupInfo( _groupInfo ),
8986 totals( _totals ),
8987 aborting( _aborting )
8988 {}
8989
TestGroupStats(GroupInfo const & _groupInfo)8990 TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo )
8991 : groupInfo( _groupInfo ),
8992 aborting( false )
8993 {}
8994
8995 TestGroupStats::~TestGroupStats() = default;
8996
TestRunStats(TestRunInfo const & _runInfo,Totals const & _totals,bool _aborting)8997 TestRunStats::TestRunStats( TestRunInfo const& _runInfo,
8998 Totals const& _totals,
8999 bool _aborting )
9000 : runInfo( _runInfo ),
9001 totals( _totals ),
9002 aborting( _aborting )
9003 {}
9004
9005 TestRunStats::~TestRunStats() = default;
9006
fatalErrorEncountered(StringRef)9007 void IStreamingReporter::fatalErrorEncountered( StringRef ) {}
isMulti() const9008 bool IStreamingReporter::isMulti() const { return false; }
9009
9010 IReporterFactory::~IReporterFactory() = default;
9011 IReporterRegistry::~IReporterRegistry() = default;
9012
9013 } // end namespace Catch
9014 // end catch_interfaces_reporter.cpp
9015 // start catch_interfaces_runner.cpp
9016
9017 namespace Catch {
9018 IRunner::~IRunner() = default;
9019 }
9020 // end catch_interfaces_runner.cpp
9021 // start catch_interfaces_testcase.cpp
9022
9023 namespace Catch {
9024 ITestInvoker::~ITestInvoker() = default;
9025 ITestCaseRegistry::~ITestCaseRegistry() = default;
9026 }
9027 // end catch_interfaces_testcase.cpp
9028 // start catch_leak_detector.cpp
9029
9030 #ifdef CATCH_CONFIG_WINDOWS_CRTDBG
9031 #include <crtdbg.h>
9032
9033 namespace Catch {
9034
LeakDetector()9035 LeakDetector::LeakDetector() {
9036 int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
9037 flag |= _CRTDBG_LEAK_CHECK_DF;
9038 flag |= _CRTDBG_ALLOC_MEM_DF;
9039 _CrtSetDbgFlag(flag);
9040 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
9041 _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
9042 // Change this to leaking allocation's number to break there
9043 _CrtSetBreakAlloc(-1);
9044 }
9045 }
9046
9047 #else
9048
LeakDetector()9049 Catch::LeakDetector::LeakDetector() {}
9050
9051 #endif
9052
~LeakDetector()9053 Catch::LeakDetector::~LeakDetector() {
9054 Catch::cleanUp();
9055 }
9056 // end catch_leak_detector.cpp
9057 // start catch_list.cpp
9058
9059 // start catch_list.h
9060
9061 #include <set>
9062
9063 namespace Catch {
9064
9065 std::size_t listTests( Config const& config );
9066
9067 std::size_t listTestsNamesOnly( Config const& config );
9068
9069 struct TagInfo {
9070 void add( std::string const& spelling );
9071 std::string all() const;
9072
9073 std::set<std::string> spellings;
9074 std::size_t count = 0;
9075 };
9076
9077 std::size_t listTags( Config const& config );
9078
9079 std::size_t listReporters();
9080
9081 Option<std::size_t> list( std::shared_ptr<Config> const& config );
9082
9083 } // end namespace Catch
9084
9085 // end catch_list.h
9086 // start catch_text.h
9087
9088 namespace Catch {
9089 using namespace clara::TextFlow;
9090 }
9091
9092 // end catch_text.h
9093 #include <limits>
9094 #include <algorithm>
9095 #include <iomanip>
9096
9097 namespace Catch {
9098
listTests(Config const & config)9099 std::size_t listTests( Config const& config ) {
9100 TestSpec testSpec = config.testSpec();
9101 if( config.hasTestFilters() )
9102 Catch::cout() << "Matching test cases:\n";
9103 else {
9104 Catch::cout() << "All available test cases:\n";
9105 }
9106
9107 auto matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
9108 for( auto const& testCaseInfo : matchedTestCases ) {
9109 Colour::Code colour = testCaseInfo.isHidden()
9110 ? Colour::SecondaryText
9111 : Colour::None;
9112 Colour colourGuard( colour );
9113
9114 Catch::cout() << Column( testCaseInfo.name ).initialIndent( 2 ).indent( 4 ) << "\n";
9115 if( config.verbosity() >= Verbosity::High ) {
9116 Catch::cout() << Column( Catch::Detail::stringify( testCaseInfo.lineInfo ) ).indent(4) << std::endl;
9117 std::string description = testCaseInfo.description;
9118 if( description.empty() )
9119 description = "(NO DESCRIPTION)";
9120 Catch::cout() << Column( description ).indent(4) << std::endl;
9121 }
9122 if( !testCaseInfo.tags.empty() )
9123 Catch::cout() << Column( testCaseInfo.tagsAsString() ).indent( 6 ) << "\n";
9124 }
9125
9126 if( !config.hasTestFilters() )
9127 Catch::cout() << pluralise( matchedTestCases.size(), "test case" ) << '\n' << std::endl;
9128 else
9129 Catch::cout() << pluralise( matchedTestCases.size(), "matching test case" ) << '\n' << std::endl;
9130 return matchedTestCases.size();
9131 }
9132
listTestsNamesOnly(Config const & config)9133 std::size_t listTestsNamesOnly( Config const& config ) {
9134 TestSpec testSpec = config.testSpec();
9135 std::size_t matchedTests = 0;
9136 std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
9137 for( auto const& testCaseInfo : matchedTestCases ) {
9138 matchedTests++;
9139 if( startsWith( testCaseInfo.name, '#' ) )
9140 Catch::cout() << '"' << testCaseInfo.name << '"';
9141 else
9142 Catch::cout() << testCaseInfo.name;
9143 if ( config.verbosity() >= Verbosity::High )
9144 Catch::cout() << "\t@" << testCaseInfo.lineInfo;
9145 Catch::cout() << std::endl;
9146 }
9147 return matchedTests;
9148 }
9149
add(std::string const & spelling)9150 void TagInfo::add( std::string const& spelling ) {
9151 ++count;
9152 spellings.insert( spelling );
9153 }
9154
all() const9155 std::string TagInfo::all() const {
9156 std::string out;
9157 for( auto const& spelling : spellings )
9158 out += "[" + spelling + "]";
9159 return out;
9160 }
9161
listTags(Config const & config)9162 std::size_t listTags( Config const& config ) {
9163 TestSpec testSpec = config.testSpec();
9164 if( config.hasTestFilters() )
9165 Catch::cout() << "Tags for matching test cases:\n";
9166 else {
9167 Catch::cout() << "All available tags:\n";
9168 }
9169
9170 std::map<std::string, TagInfo> tagCounts;
9171
9172 std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
9173 for( auto const& testCase : matchedTestCases ) {
9174 for( auto const& tagName : testCase.getTestCaseInfo().tags ) {
9175 std::string lcaseTagName = toLower( tagName );
9176 auto countIt = tagCounts.find( lcaseTagName );
9177 if( countIt == tagCounts.end() )
9178 countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first;
9179 countIt->second.add( tagName );
9180 }
9181 }
9182
9183 for( auto const& tagCount : tagCounts ) {
9184 ReusableStringStream rss;
9185 rss << " " << std::setw(2) << tagCount.second.count << " ";
9186 auto str = rss.str();
9187 auto wrapper = Column( tagCount.second.all() )
9188 .initialIndent( 0 )
9189 .indent( str.size() )
9190 .width( CATCH_CONFIG_CONSOLE_WIDTH-10 );
9191 Catch::cout() << str << wrapper << '\n';
9192 }
9193 Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl;
9194 return tagCounts.size();
9195 }
9196
listReporters()9197 std::size_t listReporters() {
9198 Catch::cout() << "Available reporters:\n";
9199 IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories();
9200 std::size_t maxNameLen = 0;
9201 for( auto const& factoryKvp : factories )
9202 maxNameLen = (std::max)( maxNameLen, factoryKvp.first.size() );
9203
9204 for( auto const& factoryKvp : factories ) {
9205 Catch::cout()
9206 << Column( factoryKvp.first + ":" )
9207 .indent(2)
9208 .width( 5+maxNameLen )
9209 + Column( factoryKvp.second->getDescription() )
9210 .initialIndent(0)
9211 .indent(2)
9212 .width( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 )
9213 << "\n";
9214 }
9215 Catch::cout() << std::endl;
9216 return factories.size();
9217 }
9218
list(std::shared_ptr<Config> const & config)9219 Option<std::size_t> list( std::shared_ptr<Config> const& config ) {
9220 Option<std::size_t> listedCount;
9221 getCurrentMutableContext().setConfig( config );
9222 if( config->listTests() )
9223 listedCount = listedCount.valueOr(0) + listTests( *config );
9224 if( config->listTestNamesOnly() )
9225 listedCount = listedCount.valueOr(0) + listTestsNamesOnly( *config );
9226 if( config->listTags() )
9227 listedCount = listedCount.valueOr(0) + listTags( *config );
9228 if( config->listReporters() )
9229 listedCount = listedCount.valueOr(0) + listReporters();
9230 return listedCount;
9231 }
9232
9233 } // end namespace Catch
9234 // end catch_list.cpp
9235 // start catch_matchers.cpp
9236
9237 namespace Catch {
9238 namespace Matchers {
9239 namespace Impl {
9240
toString() const9241 std::string MatcherUntypedBase::toString() const {
9242 if( m_cachedToString.empty() )
9243 m_cachedToString = describe();
9244 return m_cachedToString;
9245 }
9246
9247 MatcherUntypedBase::~MatcherUntypedBase() = default;
9248
9249 } // namespace Impl
9250 } // namespace Matchers
9251
9252 using namespace Matchers;
9253 using Matchers::Impl::MatcherBase;
9254
9255 } // namespace Catch
9256 // end catch_matchers.cpp
9257 // start catch_matchers_floating.cpp
9258
9259 // start catch_polyfills.hpp
9260
9261 namespace Catch {
9262 bool isnan(float f);
9263 bool isnan(double d);
9264 }
9265
9266 // end catch_polyfills.hpp
9267 // start catch_to_string.hpp
9268
9269 #include <string>
9270
9271 namespace Catch {
9272 template <typename T>
to_string(T const & t)9273 std::string to_string(T const& t) {
9274 #if defined(CATCH_CONFIG_CPP11_TO_STRING)
9275 return std::to_string(t);
9276 #else
9277 ReusableStringStream rss;
9278 rss << t;
9279 return rss.str();
9280 #endif
9281 }
9282 } // end namespace Catch
9283
9284 // end catch_to_string.hpp
9285 #include <cstdlib>
9286 #include <cstdint>
9287 #include <cstring>
9288
9289 namespace Catch {
9290 namespace Matchers {
9291 namespace Floating {
9292 enum class FloatingPointKind : uint8_t {
9293 Float,
9294 Double
9295 };
9296 }
9297 }
9298 }
9299
9300 namespace {
9301
9302 template <typename T>
9303 struct Converter;
9304
9305 template <>
9306 struct Converter<float> {
9307 static_assert(sizeof(float) == sizeof(int32_t), "Important ULP matcher assumption violated");
Converter__anon2c2dcc261711::Converter9308 Converter(float f) {
9309 std::memcpy(&i, &f, sizeof(f));
9310 }
9311 int32_t i;
9312 };
9313
9314 template <>
9315 struct Converter<double> {
9316 static_assert(sizeof(double) == sizeof(int64_t), "Important ULP matcher assumption violated");
Converter__anon2c2dcc261711::Converter9317 Converter(double d) {
9318 std::memcpy(&i, &d, sizeof(d));
9319 }
9320 int64_t i;
9321 };
9322
9323 template <typename T>
convert(T t)9324 auto convert(T t) -> Converter<T> {
9325 return Converter<T>(t);
9326 }
9327
9328 template <typename FP>
almostEqualUlps(FP lhs,FP rhs,int maxUlpDiff)9329 bool almostEqualUlps(FP lhs, FP rhs, int maxUlpDiff) {
9330 // Comparison with NaN should always be false.
9331 // This way we can rule it out before getting into the ugly details
9332 if (Catch::isnan(lhs) || Catch::isnan(rhs)) {
9333 return false;
9334 }
9335
9336 auto lc = convert(lhs);
9337 auto rc = convert(rhs);
9338
9339 if ((lc.i < 0) != (rc.i < 0)) {
9340 // Potentially we can have +0 and -0
9341 return lhs == rhs;
9342 }
9343
9344 auto ulpDiff = std::abs(lc.i - rc.i);
9345 return ulpDiff <= maxUlpDiff;
9346 }
9347
9348 }
9349
9350 namespace Catch {
9351 namespace Matchers {
9352 namespace Floating {
WithinAbsMatcher(double target,double margin)9353 WithinAbsMatcher::WithinAbsMatcher(double target, double margin)
9354 :m_target{ target }, m_margin{ margin } {
9355 CATCH_ENFORCE(margin >= 0, "Invalid margin: " << margin << '.'
9356 << " Margin has to be non-negative.");
9357 }
9358
9359 // Performs equivalent check of std::fabs(lhs - rhs) <= margin
9360 // But without the subtraction to allow for INFINITY in comparison
match(double const & matchee) const9361 bool WithinAbsMatcher::match(double const& matchee) const {
9362 return (matchee + m_margin >= m_target) && (m_target + m_margin >= matchee);
9363 }
9364
describe() const9365 std::string WithinAbsMatcher::describe() const {
9366 return "is within " + ::Catch::Detail::stringify(m_margin) + " of " + ::Catch::Detail::stringify(m_target);
9367 }
9368
WithinUlpsMatcher(double target,int ulps,FloatingPointKind baseType)9369 WithinUlpsMatcher::WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType)
9370 :m_target{ target }, m_ulps{ ulps }, m_type{ baseType } {
9371 CATCH_ENFORCE(ulps >= 0, "Invalid ULP setting: " << ulps << '.'
9372 << " ULPs have to be non-negative.");
9373 }
9374
9375 #if defined(__clang__)
9376 #pragma clang diagnostic push
9377 // Clang <3.5 reports on the default branch in the switch below
9378 #pragma clang diagnostic ignored "-Wunreachable-code"
9379 #endif
9380
match(double const & matchee) const9381 bool WithinUlpsMatcher::match(double const& matchee) const {
9382 switch (m_type) {
9383 case FloatingPointKind::Float:
9384 return almostEqualUlps<float>(static_cast<float>(matchee), static_cast<float>(m_target), m_ulps);
9385 case FloatingPointKind::Double:
9386 return almostEqualUlps<double>(matchee, m_target, m_ulps);
9387 default:
9388 CATCH_INTERNAL_ERROR( "Unknown FloatingPointKind value" );
9389 }
9390 }
9391
9392 #if defined(__clang__)
9393 #pragma clang diagnostic pop
9394 #endif
9395
describe() const9396 std::string WithinUlpsMatcher::describe() const {
9397 return "is within " + Catch::to_string(m_ulps) + " ULPs of " + ::Catch::Detail::stringify(m_target) + ((m_type == FloatingPointKind::Float)? "f" : "");
9398 }
9399
9400 }// namespace Floating
9401
WithinULP(double target,int maxUlpDiff)9402 Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff) {
9403 return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Double);
9404 }
9405
WithinULP(float target,int maxUlpDiff)9406 Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff) {
9407 return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Float);
9408 }
9409
WithinAbs(double target,double margin)9410 Floating::WithinAbsMatcher WithinAbs(double target, double margin) {
9411 return Floating::WithinAbsMatcher(target, margin);
9412 }
9413
9414 } // namespace Matchers
9415 } // namespace Catch
9416
9417 // end catch_matchers_floating.cpp
9418 // start catch_matchers_generic.cpp
9419
finalizeDescription(const std::string & desc)9420 std::string Catch::Matchers::Generic::Detail::finalizeDescription(const std::string& desc) {
9421 if (desc.empty()) {
9422 return "matches undescribed predicate";
9423 } else {
9424 return "matches predicate: \"" + desc + '"';
9425 }
9426 }
9427 // end catch_matchers_generic.cpp
9428 // start catch_matchers_string.cpp
9429
9430 #include <regex>
9431
9432 namespace Catch {
9433 namespace Matchers {
9434
9435 namespace StdString {
9436
CasedString(std::string const & str,CaseSensitive::Choice caseSensitivity)9437 CasedString::CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity )
9438 : m_caseSensitivity( caseSensitivity ),
9439 m_str( adjustString( str ) )
9440 {}
adjustString(std::string const & str) const9441 std::string CasedString::adjustString( std::string const& str ) const {
9442 return m_caseSensitivity == CaseSensitive::No
9443 ? toLower( str )
9444 : str;
9445 }
caseSensitivitySuffix() const9446 std::string CasedString::caseSensitivitySuffix() const {
9447 return m_caseSensitivity == CaseSensitive::No
9448 ? " (case insensitive)"
9449 : std::string();
9450 }
9451
StringMatcherBase(std::string const & operation,CasedString const & comparator)9452 StringMatcherBase::StringMatcherBase( std::string const& operation, CasedString const& comparator )
9453 : m_comparator( comparator ),
9454 m_operation( operation ) {
9455 }
9456
describe() const9457 std::string StringMatcherBase::describe() const {
9458 std::string description;
9459 description.reserve(5 + m_operation.size() + m_comparator.m_str.size() +
9460 m_comparator.caseSensitivitySuffix().size());
9461 description += m_operation;
9462 description += ": \"";
9463 description += m_comparator.m_str;
9464 description += "\"";
9465 description += m_comparator.caseSensitivitySuffix();
9466 return description;
9467 }
9468
EqualsMatcher(CasedString const & comparator)9469 EqualsMatcher::EqualsMatcher( CasedString const& comparator ) : StringMatcherBase( "equals", comparator ) {}
9470
match(std::string const & source) const9471 bool EqualsMatcher::match( std::string const& source ) const {
9472 return m_comparator.adjustString( source ) == m_comparator.m_str;
9473 }
9474
ContainsMatcher(CasedString const & comparator)9475 ContainsMatcher::ContainsMatcher( CasedString const& comparator ) : StringMatcherBase( "contains", comparator ) {}
9476
match(std::string const & source) const9477 bool ContainsMatcher::match( std::string const& source ) const {
9478 return contains( m_comparator.adjustString( source ), m_comparator.m_str );
9479 }
9480
StartsWithMatcher(CasedString const & comparator)9481 StartsWithMatcher::StartsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "starts with", comparator ) {}
9482
match(std::string const & source) const9483 bool StartsWithMatcher::match( std::string const& source ) const {
9484 return startsWith( m_comparator.adjustString( source ), m_comparator.m_str );
9485 }
9486
EndsWithMatcher(CasedString const & comparator)9487 EndsWithMatcher::EndsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "ends with", comparator ) {}
9488
match(std::string const & source) const9489 bool EndsWithMatcher::match( std::string const& source ) const {
9490 return endsWith( m_comparator.adjustString( source ), m_comparator.m_str );
9491 }
9492
RegexMatcher(std::string regex,CaseSensitive::Choice caseSensitivity)9493 RegexMatcher::RegexMatcher(std::string regex, CaseSensitive::Choice caseSensitivity): m_regex(std::move(regex)), m_caseSensitivity(caseSensitivity) {}
9494
match(std::string const & matchee) const9495 bool RegexMatcher::match(std::string const& matchee) const {
9496 auto flags = std::regex::ECMAScript; // ECMAScript is the default syntax option anyway
9497 if (m_caseSensitivity == CaseSensitive::Choice::No) {
9498 flags |= std::regex::icase;
9499 }
9500 auto reg = std::regex(m_regex, flags);
9501 return std::regex_match(matchee, reg);
9502 }
9503
describe() const9504 std::string RegexMatcher::describe() const {
9505 return "matches " + ::Catch::Detail::stringify(m_regex) + ((m_caseSensitivity == CaseSensitive::Choice::Yes)? " case sensitively" : " case insensitively");
9506 }
9507
9508 } // namespace StdString
9509
Equals(std::string const & str,CaseSensitive::Choice caseSensitivity)9510 StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity ) {
9511 return StdString::EqualsMatcher( StdString::CasedString( str, caseSensitivity) );
9512 }
Contains(std::string const & str,CaseSensitive::Choice caseSensitivity)9513 StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity ) {
9514 return StdString::ContainsMatcher( StdString::CasedString( str, caseSensitivity) );
9515 }
EndsWith(std::string const & str,CaseSensitive::Choice caseSensitivity)9516 StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) {
9517 return StdString::EndsWithMatcher( StdString::CasedString( str, caseSensitivity) );
9518 }
StartsWith(std::string const & str,CaseSensitive::Choice caseSensitivity)9519 StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) {
9520 return StdString::StartsWithMatcher( StdString::CasedString( str, caseSensitivity) );
9521 }
9522
Matches(std::string const & regex,CaseSensitive::Choice caseSensitivity)9523 StdString::RegexMatcher Matches(std::string const& regex, CaseSensitive::Choice caseSensitivity) {
9524 return StdString::RegexMatcher(regex, caseSensitivity);
9525 }
9526
9527 } // namespace Matchers
9528 } // namespace Catch
9529 // end catch_matchers_string.cpp
9530 // start catch_message.cpp
9531
9532 // start catch_uncaught_exceptions.h
9533
9534 namespace Catch {
9535 bool uncaught_exceptions();
9536 } // end namespace Catch
9537
9538 // end catch_uncaught_exceptions.h
9539 #include <cassert>
9540 #include <stack>
9541
9542 namespace Catch {
9543
MessageInfo(StringRef const & _macroName,SourceLineInfo const & _lineInfo,ResultWas::OfType _type)9544 MessageInfo::MessageInfo( StringRef const& _macroName,
9545 SourceLineInfo const& _lineInfo,
9546 ResultWas::OfType _type )
9547 : macroName( _macroName ),
9548 lineInfo( _lineInfo ),
9549 type( _type ),
9550 sequence( ++globalCount )
9551 {}
9552
operator ==(MessageInfo const & other) const9553 bool MessageInfo::operator==( MessageInfo const& other ) const {
9554 return sequence == other.sequence;
9555 }
9556
operator <(MessageInfo const & other) const9557 bool MessageInfo::operator<( MessageInfo const& other ) const {
9558 return sequence < other.sequence;
9559 }
9560
9561 // This may need protecting if threading support is added
9562 unsigned int MessageInfo::globalCount = 0;
9563
9564 ////////////////////////////////////////////////////////////////////////////
9565
MessageBuilder(StringRef const & macroName,SourceLineInfo const & lineInfo,ResultWas::OfType type)9566 Catch::MessageBuilder::MessageBuilder( StringRef const& macroName,
9567 SourceLineInfo const& lineInfo,
9568 ResultWas::OfType type )
9569 :m_info(macroName, lineInfo, type) {}
9570
9571 ////////////////////////////////////////////////////////////////////////////
9572
ScopedMessage(MessageBuilder const & builder)9573 ScopedMessage::ScopedMessage( MessageBuilder const& builder )
9574 : m_info( builder.m_info ), m_moved()
9575 {
9576 m_info.message = builder.m_stream.str();
9577 getResultCapture().pushScopedMessage( m_info );
9578 }
9579
ScopedMessage(ScopedMessage && old)9580 ScopedMessage::ScopedMessage( ScopedMessage&& old )
9581 : m_info( old.m_info ), m_moved()
9582 {
9583 old.m_moved = true;
9584 }
9585
~ScopedMessage()9586 ScopedMessage::~ScopedMessage() {
9587 if ( !uncaught_exceptions() && !m_moved ){
9588 getResultCapture().popScopedMessage(m_info);
9589 }
9590 }
9591
Capturer(StringRef macroName,SourceLineInfo const & lineInfo,ResultWas::OfType resultType,StringRef names)9592 Capturer::Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ) {
9593 auto trimmed = [&] (size_t start, size_t end) {
9594 while (names[start] == ',' || isspace(names[start])) {
9595 ++start;
9596 }
9597 while (names[end] == ',' || isspace(names[end])) {
9598 --end;
9599 }
9600 return names.substr(start, end - start + 1);
9601 };
9602
9603 size_t start = 0;
9604 std::stack<char> openings;
9605 for (size_t pos = 0; pos < names.size(); ++pos) {
9606 char c = names[pos];
9607 switch (c) {
9608 case '[':
9609 case '{':
9610 case '(':
9611 // It is basically impossible to disambiguate between
9612 // comparison and start of template args in this context
9613 // case '<':
9614 openings.push(c);
9615 break;
9616 case ']':
9617 case '}':
9618 case ')':
9619 // case '>':
9620 openings.pop();
9621 break;
9622 case ',':
9623 if (start != pos && openings.size() == 0) {
9624 m_messages.emplace_back(macroName, lineInfo, resultType);
9625 m_messages.back().message = trimmed(start, pos);
9626 m_messages.back().message += " := ";
9627 start = pos;
9628 }
9629 }
9630 }
9631 assert(openings.size() == 0 && "Mismatched openings");
9632 m_messages.emplace_back(macroName, lineInfo, resultType);
9633 m_messages.back().message = trimmed(start, names.size() - 1);
9634 m_messages.back().message += " := ";
9635 }
~Capturer()9636 Capturer::~Capturer() {
9637 if ( !uncaught_exceptions() ){
9638 assert( m_captured == m_messages.size() );
9639 for( size_t i = 0; i < m_captured; ++i )
9640 m_resultCapture.popScopedMessage( m_messages[i] );
9641 }
9642 }
9643
captureValue(size_t index,std::string const & value)9644 void Capturer::captureValue( size_t index, std::string const& value ) {
9645 assert( index < m_messages.size() );
9646 m_messages[index].message += value;
9647 m_resultCapture.pushScopedMessage( m_messages[index] );
9648 m_captured++;
9649 }
9650
9651 } // end namespace Catch
9652 // end catch_message.cpp
9653 // start catch_output_redirect.cpp
9654
9655 // start catch_output_redirect.h
9656 #ifndef TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H
9657 #define TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H
9658
9659 #include <cstdio>
9660 #include <iosfwd>
9661 #include <string>
9662
9663 namespace Catch {
9664
9665 class RedirectedStream {
9666 std::ostream& m_originalStream;
9667 std::ostream& m_redirectionStream;
9668 std::streambuf* m_prevBuf;
9669
9670 public:
9671 RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream );
9672 ~RedirectedStream();
9673 };
9674
9675 class RedirectedStdOut {
9676 ReusableStringStream m_rss;
9677 RedirectedStream m_cout;
9678 public:
9679 RedirectedStdOut();
9680 auto str() const -> std::string;
9681 };
9682
9683 // StdErr has two constituent streams in C++, std::cerr and std::clog
9684 // This means that we need to redirect 2 streams into 1 to keep proper
9685 // order of writes
9686 class RedirectedStdErr {
9687 ReusableStringStream m_rss;
9688 RedirectedStream m_cerr;
9689 RedirectedStream m_clog;
9690 public:
9691 RedirectedStdErr();
9692 auto str() const -> std::string;
9693 };
9694
9695 class RedirectedStreams {
9696 public:
9697 RedirectedStreams(RedirectedStreams const&) = delete;
9698 RedirectedStreams& operator=(RedirectedStreams const&) = delete;
9699 RedirectedStreams(RedirectedStreams&&) = delete;
9700 RedirectedStreams& operator=(RedirectedStreams&&) = delete;
9701
9702 RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr);
9703 ~RedirectedStreams();
9704 private:
9705 std::string& m_redirectedCout;
9706 std::string& m_redirectedCerr;
9707 RedirectedStdOut m_redirectedStdOut;
9708 RedirectedStdErr m_redirectedStdErr;
9709 };
9710
9711 #if defined(CATCH_CONFIG_NEW_CAPTURE)
9712
9713 // Windows's implementation of std::tmpfile is terrible (it tries
9714 // to create a file inside system folder, thus requiring elevated
9715 // privileges for the binary), so we have to use tmpnam(_s) and
9716 // create the file ourselves there.
9717 class TempFile {
9718 public:
9719 TempFile(TempFile const&) = delete;
9720 TempFile& operator=(TempFile const&) = delete;
9721 TempFile(TempFile&&) = delete;
9722 TempFile& operator=(TempFile&&) = delete;
9723
9724 TempFile();
9725 ~TempFile();
9726
9727 std::FILE* getFile();
9728 std::string getContents();
9729
9730 private:
9731 std::FILE* m_file = nullptr;
9732 #if defined(_MSC_VER)
9733 char m_buffer[L_tmpnam] = { 0 };
9734 #endif
9735 };
9736
9737 class OutputRedirect {
9738 public:
9739 OutputRedirect(OutputRedirect const&) = delete;
9740 OutputRedirect& operator=(OutputRedirect const&) = delete;
9741 OutputRedirect(OutputRedirect&&) = delete;
9742 OutputRedirect& operator=(OutputRedirect&&) = delete;
9743
9744 OutputRedirect(std::string& stdout_dest, std::string& stderr_dest);
9745 ~OutputRedirect();
9746
9747 private:
9748 int m_originalStdout = -1;
9749 int m_originalStderr = -1;
9750 TempFile m_stdoutFile;
9751 TempFile m_stderrFile;
9752 std::string& m_stdoutDest;
9753 std::string& m_stderrDest;
9754 };
9755
9756 #endif
9757
9758 } // end namespace Catch
9759
9760 #endif // TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H
9761 // end catch_output_redirect.h
9762 #include <cstdio>
9763 #include <cstring>
9764 #include <fstream>
9765 #include <sstream>
9766 #include <stdexcept>
9767
9768 #if defined(CATCH_CONFIG_NEW_CAPTURE)
9769 #if defined(_MSC_VER)
9770 #include <io.h> //_dup and _dup2
9771 #define dup _dup
9772 #define dup2 _dup2
9773 #define fileno _fileno
9774 #else
9775 #include <unistd.h> // dup and dup2
9776 #endif
9777 #endif
9778
9779 namespace Catch {
9780
RedirectedStream(std::ostream & originalStream,std::ostream & redirectionStream)9781 RedirectedStream::RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream )
9782 : m_originalStream( originalStream ),
9783 m_redirectionStream( redirectionStream ),
9784 m_prevBuf( m_originalStream.rdbuf() )
9785 {
9786 m_originalStream.rdbuf( m_redirectionStream.rdbuf() );
9787 }
9788
~RedirectedStream()9789 RedirectedStream::~RedirectedStream() {
9790 m_originalStream.rdbuf( m_prevBuf );
9791 }
9792
RedirectedStdOut()9793 RedirectedStdOut::RedirectedStdOut() : m_cout( Catch::cout(), m_rss.get() ) {}
str() const9794 auto RedirectedStdOut::str() const -> std::string { return m_rss.str(); }
9795
RedirectedStdErr()9796 RedirectedStdErr::RedirectedStdErr()
9797 : m_cerr( Catch::cerr(), m_rss.get() ),
9798 m_clog( Catch::clog(), m_rss.get() )
9799 {}
str() const9800 auto RedirectedStdErr::str() const -> std::string { return m_rss.str(); }
9801
RedirectedStreams(std::string & redirectedCout,std::string & redirectedCerr)9802 RedirectedStreams::RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr)
9803 : m_redirectedCout(redirectedCout),
9804 m_redirectedCerr(redirectedCerr)
9805 {}
9806
~RedirectedStreams()9807 RedirectedStreams::~RedirectedStreams() {
9808 m_redirectedCout += m_redirectedStdOut.str();
9809 m_redirectedCerr += m_redirectedStdErr.str();
9810 }
9811
9812 #if defined(CATCH_CONFIG_NEW_CAPTURE)
9813
9814 #if defined(_MSC_VER)
TempFile()9815 TempFile::TempFile() {
9816 if (tmpnam_s(m_buffer)) {
9817 CATCH_RUNTIME_ERROR("Could not get a temp filename");
9818 }
9819 if (fopen_s(&m_file, m_buffer, "w")) {
9820 char buffer[100];
9821 if (strerror_s(buffer, errno)) {
9822 CATCH_RUNTIME_ERROR("Could not translate errno to a string");
9823 }
9824 CATCH_RUNTIME_ERROR("Coul dnot open the temp file: '" << m_buffer << "' because: " << buffer);
9825 }
9826 }
9827 #else
TempFile()9828 TempFile::TempFile() {
9829 m_file = std::tmpfile();
9830 if (!m_file) {
9831 CATCH_RUNTIME_ERROR("Could not create a temp file.");
9832 }
9833 }
9834
9835 #endif
9836
~TempFile()9837 TempFile::~TempFile() {
9838 // TBD: What to do about errors here?
9839 std::fclose(m_file);
9840 // We manually create the file on Windows only, on Linux
9841 // it will be autodeleted
9842 #if defined(_MSC_VER)
9843 std::remove(m_buffer);
9844 #endif
9845 }
9846
getFile()9847 FILE* TempFile::getFile() {
9848 return m_file;
9849 }
9850
getContents()9851 std::string TempFile::getContents() {
9852 std::stringstream sstr;
9853 char buffer[100] = {};
9854 std::rewind(m_file);
9855 while (std::fgets(buffer, sizeof(buffer), m_file)) {
9856 sstr << buffer;
9857 }
9858 return sstr.str();
9859 }
9860
OutputRedirect(std::string & stdout_dest,std::string & stderr_dest)9861 OutputRedirect::OutputRedirect(std::string& stdout_dest, std::string& stderr_dest) :
9862 m_originalStdout(dup(1)),
9863 m_originalStderr(dup(2)),
9864 m_stdoutDest(stdout_dest),
9865 m_stderrDest(stderr_dest) {
9866 dup2(fileno(m_stdoutFile.getFile()), 1);
9867 dup2(fileno(m_stderrFile.getFile()), 2);
9868 }
9869
~OutputRedirect()9870 OutputRedirect::~OutputRedirect() {
9871 Catch::cout() << std::flush;
9872 fflush(stdout);
9873 // Since we support overriding these streams, we flush cerr
9874 // even though std::cerr is unbuffered
9875 Catch::cerr() << std::flush;
9876 Catch::clog() << std::flush;
9877 fflush(stderr);
9878
9879 dup2(m_originalStdout, 1);
9880 dup2(m_originalStderr, 2);
9881
9882 m_stdoutDest += m_stdoutFile.getContents();
9883 m_stderrDest += m_stderrFile.getContents();
9884 }
9885
9886 #endif // CATCH_CONFIG_NEW_CAPTURE
9887
9888 } // namespace Catch
9889
9890 #if defined(CATCH_CONFIG_NEW_CAPTURE)
9891 #if defined(_MSC_VER)
9892 #undef dup
9893 #undef dup2
9894 #undef fileno
9895 #endif
9896 #endif
9897 // end catch_output_redirect.cpp
9898 // start catch_polyfills.cpp
9899
9900 #include <cmath>
9901
9902 namespace Catch {
9903
9904 #if !defined(CATCH_CONFIG_POLYFILL_ISNAN)
isnan(float f)9905 bool isnan(float f) {
9906 return std::isnan(f);
9907 }
isnan(double d)9908 bool isnan(double d) {
9909 return std::isnan(d);
9910 }
9911 #else
9912 // For now we only use this for embarcadero
9913 bool isnan(float f) {
9914 return std::_isnan(f);
9915 }
9916 bool isnan(double d) {
9917 return std::_isnan(d);
9918 }
9919 #endif
9920
9921 } // end namespace Catch
9922 // end catch_polyfills.cpp
9923 // start catch_random_number_generator.cpp
9924
9925 namespace Catch {
9926
rng()9927 std::mt19937& rng() {
9928 static std::mt19937 s_rng;
9929 return s_rng;
9930 }
9931
seedRng(IConfig const & config)9932 void seedRng( IConfig const& config ) {
9933 if( config.rngSeed() != 0 ) {
9934 std::srand( config.rngSeed() );
9935 rng().seed( config.rngSeed() );
9936 }
9937 }
9938
rngSeed()9939 unsigned int rngSeed() {
9940 return getCurrentContext().getConfig()->rngSeed();
9941 }
9942 }
9943 // end catch_random_number_generator.cpp
9944 // start catch_registry_hub.cpp
9945
9946 // start catch_test_case_registry_impl.h
9947
9948 #include <vector>
9949 #include <set>
9950 #include <algorithm>
9951 #include <ios>
9952
9953 namespace Catch {
9954
9955 class TestCase;
9956 struct IConfig;
9957
9958 std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases );
9959 bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config );
9960
9961 void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions );
9962
9963 std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config );
9964 std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config );
9965
9966 class TestRegistry : public ITestCaseRegistry {
9967 public:
9968 virtual ~TestRegistry() = default;
9969
9970 virtual void registerTest( TestCase const& testCase );
9971
9972 std::vector<TestCase> const& getAllTests() const override;
9973 std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const override;
9974
9975 private:
9976 std::vector<TestCase> m_functions;
9977 mutable RunTests::InWhatOrder m_currentSortOrder = RunTests::InDeclarationOrder;
9978 mutable std::vector<TestCase> m_sortedFunctions;
9979 std::size_t m_unnamedCount = 0;
9980 std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised
9981 };
9982
9983 ///////////////////////////////////////////////////////////////////////////
9984
9985 class TestInvokerAsFunction : public ITestInvoker {
9986 void(*m_testAsFunction)();
9987 public:
9988 TestInvokerAsFunction( void(*testAsFunction)() ) noexcept;
9989
9990 void invoke() const override;
9991 };
9992
9993 std::string extractClassName( StringRef const& classOrQualifiedMethodName );
9994
9995 ///////////////////////////////////////////////////////////////////////////
9996
9997 } // end namespace Catch
9998
9999 // end catch_test_case_registry_impl.h
10000 // start catch_reporter_registry.h
10001
10002 #include <map>
10003
10004 namespace Catch {
10005
10006 class ReporterRegistry : public IReporterRegistry {
10007
10008 public:
10009
10010 ~ReporterRegistry() override;
10011
10012 IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const override;
10013
10014 void registerReporter( std::string const& name, IReporterFactoryPtr const& factory );
10015 void registerListener( IReporterFactoryPtr const& factory );
10016
10017 FactoryMap const& getFactories() const override;
10018 Listeners const& getListeners() const override;
10019
10020 private:
10021 FactoryMap m_factories;
10022 Listeners m_listeners;
10023 };
10024 }
10025
10026 // end catch_reporter_registry.h
10027 // start catch_tag_alias_registry.h
10028
10029 // start catch_tag_alias.h
10030
10031 #include <string>
10032
10033 namespace Catch {
10034
10035 struct TagAlias {
10036 TagAlias(std::string const& _tag, SourceLineInfo _lineInfo);
10037
10038 std::string tag;
10039 SourceLineInfo lineInfo;
10040 };
10041
10042 } // end namespace Catch
10043
10044 // end catch_tag_alias.h
10045 #include <map>
10046
10047 namespace Catch {
10048
10049 class TagAliasRegistry : public ITagAliasRegistry {
10050 public:
10051 ~TagAliasRegistry() override;
10052 TagAlias const* find( std::string const& alias ) const override;
10053 std::string expandAliases( std::string const& unexpandedTestSpec ) const override;
10054 void add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo );
10055
10056 private:
10057 std::map<std::string, TagAlias> m_registry;
10058 };
10059
10060 } // end namespace Catch
10061
10062 // end catch_tag_alias_registry.h
10063 // start catch_startup_exception_registry.h
10064
10065 #include <vector>
10066 #include <exception>
10067
10068 namespace Catch {
10069
10070 class StartupExceptionRegistry {
10071 public:
10072 void add(std::exception_ptr const& exception) noexcept;
10073 std::vector<std::exception_ptr> const& getExceptions() const noexcept;
10074 private:
10075 std::vector<std::exception_ptr> m_exceptions;
10076 };
10077
10078 } // end namespace Catch
10079
10080 // end catch_startup_exception_registry.h
10081 // start catch_singletons.hpp
10082
10083 namespace Catch {
10084
10085 struct ISingleton {
10086 virtual ~ISingleton();
10087 };
10088
10089 void addSingleton( ISingleton* singleton );
10090 void cleanupSingletons();
10091
10092 template<typename SingletonImplT, typename InterfaceT = SingletonImplT, typename MutableInterfaceT = InterfaceT>
10093 class Singleton : SingletonImplT, public ISingleton {
10094
getInternal()10095 static auto getInternal() -> Singleton* {
10096 static Singleton* s_instance = nullptr;
10097 if( !s_instance ) {
10098 s_instance = new Singleton;
10099 addSingleton( s_instance );
10100 }
10101 return s_instance;
10102 }
10103
10104 public:
get()10105 static auto get() -> InterfaceT const& {
10106 return *getInternal();
10107 }
getMutable()10108 static auto getMutable() -> MutableInterfaceT& {
10109 return *getInternal();
10110 }
10111 };
10112
10113 } // namespace Catch
10114
10115 // end catch_singletons.hpp
10116 namespace Catch {
10117
10118 namespace {
10119
10120 class RegistryHub : public IRegistryHub, public IMutableRegistryHub,
10121 private NonCopyable {
10122
10123 public: // IRegistryHub
10124 RegistryHub() = default;
getReporterRegistry() const10125 IReporterRegistry const& getReporterRegistry() const override {
10126 return m_reporterRegistry;
10127 }
getTestCaseRegistry() const10128 ITestCaseRegistry const& getTestCaseRegistry() const override {
10129 return m_testCaseRegistry;
10130 }
getExceptionTranslatorRegistry() const10131 IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const override {
10132 return m_exceptionTranslatorRegistry;
10133 }
getTagAliasRegistry() const10134 ITagAliasRegistry const& getTagAliasRegistry() const override {
10135 return m_tagAliasRegistry;
10136 }
getStartupExceptionRegistry() const10137 StartupExceptionRegistry const& getStartupExceptionRegistry() const override {
10138 return m_exceptionRegistry;
10139 }
10140
10141 public: // IMutableRegistryHub
registerReporter(std::string const & name,IReporterFactoryPtr const & factory)10142 void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) override {
10143 m_reporterRegistry.registerReporter( name, factory );
10144 }
registerListener(IReporterFactoryPtr const & factory)10145 void registerListener( IReporterFactoryPtr const& factory ) override {
10146 m_reporterRegistry.registerListener( factory );
10147 }
registerTest(TestCase const & testInfo)10148 void registerTest( TestCase const& testInfo ) override {
10149 m_testCaseRegistry.registerTest( testInfo );
10150 }
registerTranslator(const IExceptionTranslator * translator)10151 void registerTranslator( const IExceptionTranslator* translator ) override {
10152 m_exceptionTranslatorRegistry.registerTranslator( translator );
10153 }
registerTagAlias(std::string const & alias,std::string const & tag,SourceLineInfo const & lineInfo)10154 void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) override {
10155 m_tagAliasRegistry.add( alias, tag, lineInfo );
10156 }
registerStartupException()10157 void registerStartupException() noexcept override {
10158 m_exceptionRegistry.add(std::current_exception());
10159 }
10160
10161 private:
10162 TestRegistry m_testCaseRegistry;
10163 ReporterRegistry m_reporterRegistry;
10164 ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;
10165 TagAliasRegistry m_tagAliasRegistry;
10166 StartupExceptionRegistry m_exceptionRegistry;
10167 };
10168 }
10169
10170 using RegistryHubSingleton = Singleton<RegistryHub, IRegistryHub, IMutableRegistryHub>;
10171
getRegistryHub()10172 IRegistryHub const& getRegistryHub() {
10173 return RegistryHubSingleton::get();
10174 }
getMutableRegistryHub()10175 IMutableRegistryHub& getMutableRegistryHub() {
10176 return RegistryHubSingleton::getMutable();
10177 }
cleanUp()10178 void cleanUp() {
10179 cleanupSingletons();
10180 cleanUpContext();
10181 }
translateActiveException()10182 std::string translateActiveException() {
10183 return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException();
10184 }
10185
10186 } // end namespace Catch
10187 // end catch_registry_hub.cpp
10188 // start catch_reporter_registry.cpp
10189
10190 namespace Catch {
10191
10192 ReporterRegistry::~ReporterRegistry() = default;
10193
create(std::string const & name,IConfigPtr const & config) const10194 IStreamingReporterPtr ReporterRegistry::create( std::string const& name, IConfigPtr const& config ) const {
10195 auto it = m_factories.find( name );
10196 if( it == m_factories.end() )
10197 return nullptr;
10198 return it->second->create( ReporterConfig( config ) );
10199 }
10200
registerReporter(std::string const & name,IReporterFactoryPtr const & factory)10201 void ReporterRegistry::registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) {
10202 m_factories.emplace(name, factory);
10203 }
registerListener(IReporterFactoryPtr const & factory)10204 void ReporterRegistry::registerListener( IReporterFactoryPtr const& factory ) {
10205 m_listeners.push_back( factory );
10206 }
10207
getFactories() const10208 IReporterRegistry::FactoryMap const& ReporterRegistry::getFactories() const {
10209 return m_factories;
10210 }
getListeners() const10211 IReporterRegistry::Listeners const& ReporterRegistry::getListeners() const {
10212 return m_listeners;
10213 }
10214
10215 }
10216 // end catch_reporter_registry.cpp
10217 // start catch_result_type.cpp
10218
10219 namespace Catch {
10220
isOk(ResultWas::OfType resultType)10221 bool isOk( ResultWas::OfType resultType ) {
10222 return ( resultType & ResultWas::FailureBit ) == 0;
10223 }
isJustInfo(int flags)10224 bool isJustInfo( int flags ) {
10225 return flags == ResultWas::Info;
10226 }
10227
operator |(ResultDisposition::Flags lhs,ResultDisposition::Flags rhs)10228 ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) {
10229 return static_cast<ResultDisposition::Flags>( static_cast<int>( lhs ) | static_cast<int>( rhs ) );
10230 }
10231
shouldContinueOnFailure(int flags)10232 bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; }
shouldSuppressFailure(int flags)10233 bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; }
10234
10235 } // end namespace Catch
10236 // end catch_result_type.cpp
10237 // start catch_run_context.cpp
10238
10239 #include <cassert>
10240 #include <algorithm>
10241 #include <sstream>
10242
10243 namespace Catch {
10244
10245 namespace Generators {
10246 struct GeneratorTracker : TestCaseTracking::TrackerBase, IGeneratorTracker {
10247 GeneratorBasePtr m_generator;
10248
GeneratorTrackerCatch::Generators::GeneratorTracker10249 GeneratorTracker( TestCaseTracking::NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
10250 : TrackerBase( nameAndLocation, ctx, parent )
10251 {}
10252 ~GeneratorTracker();
10253
acquireCatch::Generators::GeneratorTracker10254 static GeneratorTracker& acquire( TrackerContext& ctx, TestCaseTracking::NameAndLocation const& nameAndLocation ) {
10255 std::shared_ptr<GeneratorTracker> tracker;
10256
10257 ITracker& currentTracker = ctx.currentTracker();
10258 if( TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) {
10259 assert( childTracker );
10260 assert( childTracker->isGeneratorTracker() );
10261 tracker = std::static_pointer_cast<GeneratorTracker>( childTracker );
10262 }
10263 else {
10264 tracker = std::make_shared<GeneratorTracker>( nameAndLocation, ctx, ¤tTracker );
10265 currentTracker.addChild( tracker );
10266 }
10267
10268 if( !ctx.completedCycle() && !tracker->isComplete() ) {
10269 tracker->open();
10270 }
10271
10272 return *tracker;
10273 }
10274
10275 // TrackerBase interface
isGeneratorTrackerCatch::Generators::GeneratorTracker10276 bool isGeneratorTracker() const override { return true; }
hasGeneratorCatch::Generators::GeneratorTracker10277 auto hasGenerator() const -> bool override {
10278 return !!m_generator;
10279 }
closeCatch::Generators::GeneratorTracker10280 void close() override {
10281 TrackerBase::close();
10282 // Generator interface only finds out if it has another item on atual move
10283 if (m_runState == CompletedSuccessfully && m_generator->next()) {
10284 m_children.clear();
10285 m_runState = Executing;
10286 }
10287 }
10288
10289 // IGeneratorTracker interface
getGeneratorCatch::Generators::GeneratorTracker10290 auto getGenerator() const -> GeneratorBasePtr const& override {
10291 return m_generator;
10292 }
setGeneratorCatch::Generators::GeneratorTracker10293 void setGenerator( GeneratorBasePtr&& generator ) override {
10294 m_generator = std::move( generator );
10295 }
10296 };
~GeneratorTracker()10297 GeneratorTracker::~GeneratorTracker() {}
10298 }
10299
RunContext(IConfigPtr const & _config,IStreamingReporterPtr && reporter)10300 RunContext::RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter)
10301 : m_runInfo(_config->name()),
10302 m_context(getCurrentMutableContext()),
10303 m_config(_config),
10304 m_reporter(std::move(reporter)),
10305 m_lastAssertionInfo{ StringRef(), SourceLineInfo("",0), StringRef(), ResultDisposition::Normal },
10306 m_includeSuccessfulResults( m_config->includeSuccessfulResults() || m_reporter->getPreferences().shouldReportAllAssertions )
10307 {
10308 m_context.setRunner(this);
10309 m_context.setConfig(m_config);
10310 m_context.setResultCapture(this);
10311 m_reporter->testRunStarting(m_runInfo);
10312 }
10313
~RunContext()10314 RunContext::~RunContext() {
10315 m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, aborting()));
10316 }
10317
testGroupStarting(std::string const & testSpec,std::size_t groupIndex,std::size_t groupsCount)10318 void RunContext::testGroupStarting(std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount) {
10319 m_reporter->testGroupStarting(GroupInfo(testSpec, groupIndex, groupsCount));
10320 }
10321
testGroupEnded(std::string const & testSpec,Totals const & totals,std::size_t groupIndex,std::size_t groupsCount)10322 void RunContext::testGroupEnded(std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount) {
10323 m_reporter->testGroupEnded(TestGroupStats(GroupInfo(testSpec, groupIndex, groupsCount), totals, aborting()));
10324 }
10325
runTest(TestCase const & testCase)10326 Totals RunContext::runTest(TestCase const& testCase) {
10327 Totals prevTotals = m_totals;
10328
10329 std::string redirectedCout;
10330 std::string redirectedCerr;
10331
10332 auto const& testInfo = testCase.getTestCaseInfo();
10333
10334 m_reporter->testCaseStarting(testInfo);
10335
10336 m_activeTestCase = &testCase;
10337
10338 ITracker& rootTracker = m_trackerContext.startRun();
10339 assert(rootTracker.isSectionTracker());
10340 static_cast<SectionTracker&>(rootTracker).addInitialFilters(m_config->getSectionsToRun());
10341 do {
10342 m_trackerContext.startCycle();
10343 m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(testInfo.name, testInfo.lineInfo));
10344 runCurrentTest(redirectedCout, redirectedCerr);
10345 } while (!m_testCaseTracker->isSuccessfullyCompleted() && !aborting());
10346
10347 Totals deltaTotals = m_totals.delta(prevTotals);
10348 if (testInfo.expectedToFail() && deltaTotals.testCases.passed > 0) {
10349 deltaTotals.assertions.failed++;
10350 deltaTotals.testCases.passed--;
10351 deltaTotals.testCases.failed++;
10352 }
10353 m_totals.testCases += deltaTotals.testCases;
10354 m_reporter->testCaseEnded(TestCaseStats(testInfo,
10355 deltaTotals,
10356 redirectedCout,
10357 redirectedCerr,
10358 aborting()));
10359
10360 m_activeTestCase = nullptr;
10361 m_testCaseTracker = nullptr;
10362
10363 return deltaTotals;
10364 }
10365
config() const10366 IConfigPtr RunContext::config() const {
10367 return m_config;
10368 }
10369
reporter() const10370 IStreamingReporter& RunContext::reporter() const {
10371 return *m_reporter;
10372 }
10373
assertionEnded(AssertionResult const & result)10374 void RunContext::assertionEnded(AssertionResult const & result) {
10375 if (result.getResultType() == ResultWas::Ok) {
10376 m_totals.assertions.passed++;
10377 m_lastAssertionPassed = true;
10378 } else if (!result.isOk()) {
10379 m_lastAssertionPassed = false;
10380 if( m_activeTestCase->getTestCaseInfo().okToFail() )
10381 m_totals.assertions.failedButOk++;
10382 else
10383 m_totals.assertions.failed++;
10384 }
10385 else {
10386 m_lastAssertionPassed = true;
10387 }
10388
10389 // We have no use for the return value (whether messages should be cleared), because messages were made scoped
10390 // and should be let to clear themselves out.
10391 static_cast<void>(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals)));
10392
10393 if (result.getResultType() != ResultWas::Warning)
10394 m_messageScopes.clear();
10395
10396 // Reset working state
10397 resetAssertionInfo();
10398 m_lastResult = result;
10399 }
resetAssertionInfo()10400 void RunContext::resetAssertionInfo() {
10401 m_lastAssertionInfo.macroName = StringRef();
10402 m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"_sr;
10403 }
10404
sectionStarted(SectionInfo const & sectionInfo,Counts & assertions)10405 bool RunContext::sectionStarted(SectionInfo const & sectionInfo, Counts & assertions) {
10406 ITracker& sectionTracker = SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(sectionInfo.name, sectionInfo.lineInfo));
10407 if (!sectionTracker.isOpen())
10408 return false;
10409 m_activeSections.push_back(§ionTracker);
10410
10411 m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo;
10412
10413 m_reporter->sectionStarting(sectionInfo);
10414
10415 assertions = m_totals.assertions;
10416
10417 return true;
10418 }
acquireGeneratorTracker(SourceLineInfo const & lineInfo)10419 auto RunContext::acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {
10420 using namespace Generators;
10421 GeneratorTracker& tracker = GeneratorTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( "generator", lineInfo ) );
10422 assert( tracker.isOpen() );
10423 m_lastAssertionInfo.lineInfo = lineInfo;
10424 return tracker;
10425 }
10426
testForMissingAssertions(Counts & assertions)10427 bool RunContext::testForMissingAssertions(Counts& assertions) {
10428 if (assertions.total() != 0)
10429 return false;
10430 if (!m_config->warnAboutMissingAssertions())
10431 return false;
10432 if (m_trackerContext.currentTracker().hasChildren())
10433 return false;
10434 m_totals.assertions.failed++;
10435 assertions.failed++;
10436 return true;
10437 }
10438
sectionEnded(SectionEndInfo const & endInfo)10439 void RunContext::sectionEnded(SectionEndInfo const & endInfo) {
10440 Counts assertions = m_totals.assertions - endInfo.prevAssertions;
10441 bool missingAssertions = testForMissingAssertions(assertions);
10442
10443 if (!m_activeSections.empty()) {
10444 m_activeSections.back()->close();
10445 m_activeSections.pop_back();
10446 }
10447
10448 m_reporter->sectionEnded(SectionStats(endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions));
10449 m_messages.clear();
10450 m_messageScopes.clear();
10451 }
10452
sectionEndedEarly(SectionEndInfo const & endInfo)10453 void RunContext::sectionEndedEarly(SectionEndInfo const & endInfo) {
10454 if (m_unfinishedSections.empty())
10455 m_activeSections.back()->fail();
10456 else
10457 m_activeSections.back()->close();
10458 m_activeSections.pop_back();
10459
10460 m_unfinishedSections.push_back(endInfo);
10461 }
benchmarkStarting(BenchmarkInfo const & info)10462 void RunContext::benchmarkStarting( BenchmarkInfo const& info ) {
10463 m_reporter->benchmarkStarting( info );
10464 }
benchmarkEnded(BenchmarkStats const & stats)10465 void RunContext::benchmarkEnded( BenchmarkStats const& stats ) {
10466 m_reporter->benchmarkEnded( stats );
10467 }
10468
pushScopedMessage(MessageInfo const & message)10469 void RunContext::pushScopedMessage(MessageInfo const & message) {
10470 m_messages.push_back(message);
10471 }
10472
popScopedMessage(MessageInfo const & message)10473 void RunContext::popScopedMessage(MessageInfo const & message) {
10474 m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end());
10475 }
10476
emplaceUnscopedMessage(MessageBuilder const & builder)10477 void RunContext::emplaceUnscopedMessage( MessageBuilder const& builder ) {
10478 m_messageScopes.emplace_back( builder );
10479 }
10480
getCurrentTestName() const10481 std::string RunContext::getCurrentTestName() const {
10482 return m_activeTestCase
10483 ? m_activeTestCase->getTestCaseInfo().name
10484 : std::string();
10485 }
10486
getLastResult() const10487 const AssertionResult * RunContext::getLastResult() const {
10488 return &(*m_lastResult);
10489 }
10490
exceptionEarlyReported()10491 void RunContext::exceptionEarlyReported() {
10492 m_shouldReportUnexpected = false;
10493 }
10494
handleFatalErrorCondition(StringRef message)10495 void RunContext::handleFatalErrorCondition( StringRef message ) {
10496 // First notify reporter that bad things happened
10497 m_reporter->fatalErrorEncountered(message);
10498
10499 // Don't rebuild the result -- the stringification itself can cause more fatal errors
10500 // Instead, fake a result data.
10501 AssertionResultData tempResult( ResultWas::FatalErrorCondition, { false } );
10502 tempResult.message = message;
10503 AssertionResult result(m_lastAssertionInfo, tempResult);
10504
10505 assertionEnded(result);
10506
10507 handleUnfinishedSections();
10508
10509 // Recreate section for test case (as we will lose the one that was in scope)
10510 auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
10511 SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name);
10512
10513 Counts assertions;
10514 assertions.failed = 1;
10515 SectionStats testCaseSectionStats(testCaseSection, assertions, 0, false);
10516 m_reporter->sectionEnded(testCaseSectionStats);
10517
10518 auto const& testInfo = m_activeTestCase->getTestCaseInfo();
10519
10520 Totals deltaTotals;
10521 deltaTotals.testCases.failed = 1;
10522 deltaTotals.assertions.failed = 1;
10523 m_reporter->testCaseEnded(TestCaseStats(testInfo,
10524 deltaTotals,
10525 std::string(),
10526 std::string(),
10527 false));
10528 m_totals.testCases.failed++;
10529 testGroupEnded(std::string(), m_totals, 1, 1);
10530 m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, false));
10531 }
10532
lastAssertionPassed()10533 bool RunContext::lastAssertionPassed() {
10534 return m_lastAssertionPassed;
10535 }
10536
assertionPassed()10537 void RunContext::assertionPassed() {
10538 m_lastAssertionPassed = true;
10539 ++m_totals.assertions.passed;
10540 resetAssertionInfo();
10541 m_messageScopes.clear();
10542 }
10543
aborting() const10544 bool RunContext::aborting() const {
10545 return m_totals.assertions.failed >= static_cast<std::size_t>(m_config->abortAfter());
10546 }
10547
runCurrentTest(std::string & redirectedCout,std::string & redirectedCerr)10548 void RunContext::runCurrentTest(std::string & redirectedCout, std::string & redirectedCerr) {
10549 auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
10550 SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name);
10551 m_reporter->sectionStarting(testCaseSection);
10552 Counts prevAssertions = m_totals.assertions;
10553 double duration = 0;
10554 m_shouldReportUnexpected = true;
10555 m_lastAssertionInfo = { "TEST_CASE"_sr, testCaseInfo.lineInfo, StringRef(), ResultDisposition::Normal };
10556
10557 seedRng(*m_config);
10558
10559 Timer timer;
10560 CATCH_TRY {
10561 if (m_reporter->getPreferences().shouldRedirectStdOut) {
10562 #if !defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT)
10563 RedirectedStreams redirectedStreams(redirectedCout, redirectedCerr);
10564
10565 timer.start();
10566 invokeActiveTestCase();
10567 #else
10568 OutputRedirect r(redirectedCout, redirectedCerr);
10569 timer.start();
10570 invokeActiveTestCase();
10571 #endif
10572 } else {
10573 timer.start();
10574 invokeActiveTestCase();
10575 }
10576 duration = timer.getElapsedSeconds();
10577 } CATCH_CATCH_ANON (TestFailureException&) {
10578 // This just means the test was aborted due to failure
10579 } CATCH_CATCH_ALL {
10580 // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions
10581 // are reported without translation at the point of origin.
10582 if( m_shouldReportUnexpected ) {
10583 AssertionReaction dummyReaction;
10584 handleUnexpectedInflightException( m_lastAssertionInfo, translateActiveException(), dummyReaction );
10585 }
10586 }
10587 Counts assertions = m_totals.assertions - prevAssertions;
10588 bool missingAssertions = testForMissingAssertions(assertions);
10589
10590 m_testCaseTracker->close();
10591 handleUnfinishedSections();
10592 m_messages.clear();
10593 m_messageScopes.clear();
10594
10595 SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions);
10596 m_reporter->sectionEnded(testCaseSectionStats);
10597 }
10598
invokeActiveTestCase()10599 void RunContext::invokeActiveTestCase() {
10600 FatalConditionHandler fatalConditionHandler; // Handle signals
10601 m_activeTestCase->invoke();
10602 fatalConditionHandler.reset();
10603 }
10604
handleUnfinishedSections()10605 void RunContext::handleUnfinishedSections() {
10606 // If sections ended prematurely due to an exception we stored their
10607 // infos here so we can tear them down outside the unwind process.
10608 for (auto it = m_unfinishedSections.rbegin(),
10609 itEnd = m_unfinishedSections.rend();
10610 it != itEnd;
10611 ++it)
10612 sectionEnded(*it);
10613 m_unfinishedSections.clear();
10614 }
10615
handleExpr(AssertionInfo const & info,ITransientExpression const & expr,AssertionReaction & reaction)10616 void RunContext::handleExpr(
10617 AssertionInfo const& info,
10618 ITransientExpression const& expr,
10619 AssertionReaction& reaction
10620 ) {
10621 m_reporter->assertionStarting( info );
10622
10623 bool negated = isFalseTest( info.resultDisposition );
10624 bool result = expr.getResult() != negated;
10625
10626 if( result ) {
10627 if (!m_includeSuccessfulResults) {
10628 assertionPassed();
10629 }
10630 else {
10631 reportExpr(info, ResultWas::Ok, &expr, negated);
10632 }
10633 }
10634 else {
10635 reportExpr(info, ResultWas::ExpressionFailed, &expr, negated );
10636 populateReaction( reaction );
10637 }
10638 }
reportExpr(AssertionInfo const & info,ResultWas::OfType resultType,ITransientExpression const * expr,bool negated)10639 void RunContext::reportExpr(
10640 AssertionInfo const &info,
10641 ResultWas::OfType resultType,
10642 ITransientExpression const *expr,
10643 bool negated ) {
10644
10645 m_lastAssertionInfo = info;
10646 AssertionResultData data( resultType, LazyExpression( negated ) );
10647
10648 AssertionResult assertionResult{ info, data };
10649 assertionResult.m_resultData.lazyExpression.m_transientExpression = expr;
10650
10651 assertionEnded( assertionResult );
10652 }
10653
handleMessage(AssertionInfo const & info,ResultWas::OfType resultType,StringRef const & message,AssertionReaction & reaction)10654 void RunContext::handleMessage(
10655 AssertionInfo const& info,
10656 ResultWas::OfType resultType,
10657 StringRef const& message,
10658 AssertionReaction& reaction
10659 ) {
10660 m_reporter->assertionStarting( info );
10661
10662 m_lastAssertionInfo = info;
10663
10664 AssertionResultData data( resultType, LazyExpression( false ) );
10665 data.message = message;
10666 AssertionResult assertionResult{ m_lastAssertionInfo, data };
10667 assertionEnded( assertionResult );
10668 if( !assertionResult.isOk() )
10669 populateReaction( reaction );
10670 }
handleUnexpectedExceptionNotThrown(AssertionInfo const & info,AssertionReaction & reaction)10671 void RunContext::handleUnexpectedExceptionNotThrown(
10672 AssertionInfo const& info,
10673 AssertionReaction& reaction
10674 ) {
10675 handleNonExpr(info, Catch::ResultWas::DidntThrowException, reaction);
10676 }
10677
handleUnexpectedInflightException(AssertionInfo const & info,std::string const & message,AssertionReaction & reaction)10678 void RunContext::handleUnexpectedInflightException(
10679 AssertionInfo const& info,
10680 std::string const& message,
10681 AssertionReaction& reaction
10682 ) {
10683 m_lastAssertionInfo = info;
10684
10685 AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) );
10686 data.message = message;
10687 AssertionResult assertionResult{ info, data };
10688 assertionEnded( assertionResult );
10689 populateReaction( reaction );
10690 }
10691
populateReaction(AssertionReaction & reaction)10692 void RunContext::populateReaction( AssertionReaction& reaction ) {
10693 reaction.shouldDebugBreak = m_config->shouldDebugBreak();
10694 reaction.shouldThrow = aborting() || (m_lastAssertionInfo.resultDisposition & ResultDisposition::Normal);
10695 }
10696
handleIncomplete(AssertionInfo const & info)10697 void RunContext::handleIncomplete(
10698 AssertionInfo const& info
10699 ) {
10700 m_lastAssertionInfo = info;
10701
10702 AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) );
10703 data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE";
10704 AssertionResult assertionResult{ info, data };
10705 assertionEnded( assertionResult );
10706 }
handleNonExpr(AssertionInfo const & info,ResultWas::OfType resultType,AssertionReaction & reaction)10707 void RunContext::handleNonExpr(
10708 AssertionInfo const &info,
10709 ResultWas::OfType resultType,
10710 AssertionReaction &reaction
10711 ) {
10712 m_lastAssertionInfo = info;
10713
10714 AssertionResultData data( resultType, LazyExpression( false ) );
10715 AssertionResult assertionResult{ info, data };
10716 assertionEnded( assertionResult );
10717
10718 if( !assertionResult.isOk() )
10719 populateReaction( reaction );
10720 }
10721
getResultCapture()10722 IResultCapture& getResultCapture() {
10723 if (auto* capture = getCurrentContext().getResultCapture())
10724 return *capture;
10725 else
10726 CATCH_INTERNAL_ERROR("No result capture instance");
10727 }
10728 }
10729 // end catch_run_context.cpp
10730 // start catch_section.cpp
10731
10732 namespace Catch {
10733
Section(SectionInfo const & info)10734 Section::Section( SectionInfo const& info )
10735 : m_info( info ),
10736 m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) )
10737 {
10738 m_timer.start();
10739 }
10740
~Section()10741 Section::~Section() {
10742 if( m_sectionIncluded ) {
10743 SectionEndInfo endInfo{ m_info, m_assertions, m_timer.getElapsedSeconds() };
10744 if( uncaught_exceptions() )
10745 getResultCapture().sectionEndedEarly( endInfo );
10746 else
10747 getResultCapture().sectionEnded( endInfo );
10748 }
10749 }
10750
10751 // This indicates whether the section should be executed or not
operator bool() const10752 Section::operator bool() const {
10753 return m_sectionIncluded;
10754 }
10755
10756 } // end namespace Catch
10757 // end catch_section.cpp
10758 // start catch_section_info.cpp
10759
10760 namespace Catch {
10761
SectionInfo(SourceLineInfo const & _lineInfo,std::string const & _name)10762 SectionInfo::SectionInfo
10763 ( SourceLineInfo const& _lineInfo,
10764 std::string const& _name )
10765 : name( _name ),
10766 lineInfo( _lineInfo )
10767 {}
10768
10769 } // end namespace Catch
10770 // end catch_section_info.cpp
10771 // start catch_session.cpp
10772
10773 // start catch_session.h
10774
10775 #include <memory>
10776
10777 namespace Catch {
10778
10779 class Session : NonCopyable {
10780 public:
10781
10782 Session();
10783 ~Session() override;
10784
10785 void showHelp() const;
10786 void libIdentify();
10787
10788 int applyCommandLine( int argc, char const * const * argv );
10789 #if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE)
10790 int applyCommandLine( int argc, wchar_t const * const * argv );
10791 #endif
10792
10793 void useConfigData( ConfigData const& configData );
10794
10795 template<typename CharT>
run(int argc,CharT const * const argv[])10796 int run(int argc, CharT const * const argv[]) {
10797 if (m_startupExceptions)
10798 return 1;
10799 int returnCode = applyCommandLine(argc, argv);
10800 if (returnCode == 0)
10801 returnCode = run();
10802 return returnCode;
10803 }
10804
10805 int run();
10806
10807 clara::Parser const& cli() const;
10808 void cli( clara::Parser const& newParser );
10809 ConfigData& configData();
10810 Config& config();
10811 private:
10812 int runInternal();
10813
10814 clara::Parser m_cli;
10815 ConfigData m_configData;
10816 std::shared_ptr<Config> m_config;
10817 bool m_startupExceptions = false;
10818 };
10819
10820 } // end namespace Catch
10821
10822 // end catch_session.h
10823 // start catch_version.h
10824
10825 #include <iosfwd>
10826
10827 namespace Catch {
10828
10829 // Versioning information
10830 struct Version {
10831 Version( Version const& ) = delete;
10832 Version& operator=( Version const& ) = delete;
10833 Version( unsigned int _majorVersion,
10834 unsigned int _minorVersion,
10835 unsigned int _patchNumber,
10836 char const * const _branchName,
10837 unsigned int _buildNumber );
10838
10839 unsigned int const majorVersion;
10840 unsigned int const minorVersion;
10841 unsigned int const patchNumber;
10842
10843 // buildNumber is only used if branchName is not null
10844 char const * const branchName;
10845 unsigned int const buildNumber;
10846
10847 friend std::ostream& operator << ( std::ostream& os, Version const& version );
10848 };
10849
10850 Version const& libraryVersion();
10851 }
10852
10853 // end catch_version.h
10854 #include <cstdlib>
10855 #include <iomanip>
10856
10857 namespace Catch {
10858
10859 namespace {
10860 const int MaxExitCode = 255;
10861
createReporter(std::string const & reporterName,IConfigPtr const & config)10862 IStreamingReporterPtr createReporter(std::string const& reporterName, IConfigPtr const& config) {
10863 auto reporter = Catch::getRegistryHub().getReporterRegistry().create(reporterName, config);
10864 CATCH_ENFORCE(reporter, "No reporter registered with name: '" << reporterName << "'");
10865
10866 return reporter;
10867 }
10868
makeReporter(std::shared_ptr<Config> const & config)10869 IStreamingReporterPtr makeReporter(std::shared_ptr<Config> const& config) {
10870 if (Catch::getRegistryHub().getReporterRegistry().getListeners().empty()) {
10871 return createReporter(config->getReporterName(), config);
10872 }
10873
10874 // On older platforms, returning std::unique_ptr<ListeningReporter>
10875 // when the return type is std::unique_ptr<IStreamingReporter>
10876 // doesn't compile without a std::move call. However, this causes
10877 // a warning on newer platforms. Thus, we have to work around
10878 // it a bit and downcast the pointer manually.
10879 auto ret = std::unique_ptr<IStreamingReporter>(new ListeningReporter);
10880 auto& multi = static_cast<ListeningReporter&>(*ret);
10881 auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners();
10882 for (auto const& listener : listeners) {
10883 multi.addListener(listener->create(Catch::ReporterConfig(config)));
10884 }
10885 multi.addReporter(createReporter(config->getReporterName(), config));
10886 return ret;
10887 }
10888
runTests(std::shared_ptr<Config> const & config)10889 Catch::Totals runTests(std::shared_ptr<Config> const& config) {
10890 auto reporter = makeReporter(config);
10891
10892 RunContext context(config, std::move(reporter));
10893
10894 Totals totals;
10895
10896 context.testGroupStarting(config->name(), 1, 1);
10897
10898 TestSpec testSpec = config->testSpec();
10899
10900 auto const& allTestCases = getAllTestCasesSorted(*config);
10901 for (auto const& testCase : allTestCases) {
10902 if (!context.aborting() && matchTest(testCase, testSpec, *config))
10903 totals += context.runTest(testCase);
10904 else
10905 context.reporter().skipTest(testCase);
10906 }
10907
10908 if (config->warnAboutNoTests() && totals.testCases.total() == 0) {
10909 ReusableStringStream testConfig;
10910
10911 bool first = true;
10912 for (const auto& input : config->getTestsOrTags()) {
10913 if (!first) { testConfig << ' '; }
10914 first = false;
10915 testConfig << input;
10916 }
10917
10918 context.reporter().noMatchingTestCases(testConfig.str());
10919 totals.error = -1;
10920 }
10921
10922 context.testGroupEnded(config->name(), totals, 1, 1);
10923 return totals;
10924 }
10925
applyFilenamesAsTags(Catch::IConfig const & config)10926 void applyFilenamesAsTags(Catch::IConfig const& config) {
10927 auto& tests = const_cast<std::vector<TestCase>&>(getAllTestCasesSorted(config));
10928 for (auto& testCase : tests) {
10929 auto tags = testCase.tags;
10930
10931 std::string filename = testCase.lineInfo.file;
10932 auto lastSlash = filename.find_last_of("\\/");
10933 if (lastSlash != std::string::npos) {
10934 filename.erase(0, lastSlash);
10935 filename[0] = '#';
10936 }
10937
10938 auto lastDot = filename.find_last_of('.');
10939 if (lastDot != std::string::npos) {
10940 filename.erase(lastDot);
10941 }
10942
10943 tags.push_back(std::move(filename));
10944 setTags(testCase, tags);
10945 }
10946 }
10947
10948 } // anon namespace
10949
Session()10950 Session::Session() {
10951 static bool alreadyInstantiated = false;
10952 if( alreadyInstantiated ) {
10953 CATCH_TRY { CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); }
10954 CATCH_CATCH_ALL { getMutableRegistryHub().registerStartupException(); }
10955 }
10956
10957 // There cannot be exceptions at startup in no-exception mode.
10958 #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
10959 const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions();
10960 if ( !exceptions.empty() ) {
10961 m_startupExceptions = true;
10962 Colour colourGuard( Colour::Red );
10963 Catch::cerr() << "Errors occurred during startup!" << '\n';
10964 // iterate over all exceptions and notify user
10965 for ( const auto& ex_ptr : exceptions ) {
10966 try {
10967 std::rethrow_exception(ex_ptr);
10968 } catch ( std::exception const& ex ) {
10969 Catch::cerr() << Column( ex.what() ).indent(2) << '\n';
10970 }
10971 }
10972 }
10973 #endif
10974
10975 alreadyInstantiated = true;
10976 m_cli = makeCommandLineParser( m_configData );
10977 }
~Session()10978 Session::~Session() {
10979 Catch::cleanUp();
10980 }
10981
showHelp() const10982 void Session::showHelp() const {
10983 Catch::cout()
10984 << "\nCatch v" << libraryVersion() << "\n"
10985 << m_cli << std::endl
10986 << "For more detailed usage please see the project docs\n" << std::endl;
10987 }
libIdentify()10988 void Session::libIdentify() {
10989 Catch::cout()
10990 << std::left << std::setw(16) << "description: " << "A Catch test executable\n"
10991 << std::left << std::setw(16) << "category: " << "testframework\n"
10992 << std::left << std::setw(16) << "framework: " << "Catch Test\n"
10993 << std::left << std::setw(16) << "version: " << libraryVersion() << std::endl;
10994 }
10995
applyCommandLine(int argc,char const * const * argv)10996 int Session::applyCommandLine( int argc, char const * const * argv ) {
10997 if( m_startupExceptions )
10998 return 1;
10999
11000 auto result = m_cli.parse( clara::Args( argc, argv ) );
11001 if( !result ) {
11002 config();
11003 getCurrentMutableContext().setConfig(m_config);
11004 Catch::cerr()
11005 << Colour( Colour::Red )
11006 << "\nError(s) in input:\n"
11007 << Column( result.errorMessage() ).indent( 2 )
11008 << "\n\n";
11009 Catch::cerr() << "Run with -? for usage\n" << std::endl;
11010 return MaxExitCode;
11011 }
11012
11013 if( m_configData.showHelp )
11014 showHelp();
11015 if( m_configData.libIdentify )
11016 libIdentify();
11017 m_config.reset();
11018 return 0;
11019 }
11020
11021 #if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE)
applyCommandLine(int argc,wchar_t const * const * argv)11022 int Session::applyCommandLine( int argc, wchar_t const * const * argv ) {
11023
11024 char **utf8Argv = new char *[ argc ];
11025
11026 for ( int i = 0; i < argc; ++i ) {
11027 int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL );
11028
11029 utf8Argv[ i ] = new char[ bufSize ];
11030
11031 WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL );
11032 }
11033
11034 int returnCode = applyCommandLine( argc, utf8Argv );
11035
11036 for ( int i = 0; i < argc; ++i )
11037 delete [] utf8Argv[ i ];
11038
11039 delete [] utf8Argv;
11040
11041 return returnCode;
11042 }
11043 #endif
11044
useConfigData(ConfigData const & configData)11045 void Session::useConfigData( ConfigData const& configData ) {
11046 m_configData = configData;
11047 m_config.reset();
11048 }
11049
run()11050 int Session::run() {
11051 if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) {
11052 Catch::cout() << "...waiting for enter/ return before starting" << std::endl;
11053 static_cast<void>(std::getchar());
11054 }
11055 int exitCode = runInternal();
11056 if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) {
11057 Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << std::endl;
11058 static_cast<void>(std::getchar());
11059 }
11060 return exitCode;
11061 }
11062
cli() const11063 clara::Parser const& Session::cli() const {
11064 return m_cli;
11065 }
cli(clara::Parser const & newParser)11066 void Session::cli( clara::Parser const& newParser ) {
11067 m_cli = newParser;
11068 }
configData()11069 ConfigData& Session::configData() {
11070 return m_configData;
11071 }
config()11072 Config& Session::config() {
11073 if( !m_config )
11074 m_config = std::make_shared<Config>( m_configData );
11075 return *m_config;
11076 }
11077
runInternal()11078 int Session::runInternal() {
11079 if( m_startupExceptions )
11080 return 1;
11081
11082 if (m_configData.showHelp || m_configData.libIdentify) {
11083 return 0;
11084 }
11085
11086 CATCH_TRY {
11087 config(); // Force config to be constructed
11088
11089 seedRng( *m_config );
11090
11091 if( m_configData.filenamesAsTags )
11092 applyFilenamesAsTags( *m_config );
11093
11094 // Handle list request
11095 if( Option<std::size_t> listed = list( m_config ) )
11096 return static_cast<int>( *listed );
11097
11098 auto totals = runTests( m_config );
11099 // Note that on unices only the lower 8 bits are usually used, clamping
11100 // the return value to 255 prevents false negative when some multiple
11101 // of 256 tests has failed
11102 return (std::min) (MaxExitCode, (std::max) (totals.error, static_cast<int>(totals.assertions.failed)));
11103 }
11104 #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
11105 catch( std::exception& ex ) {
11106 Catch::cerr() << ex.what() << std::endl;
11107 return MaxExitCode;
11108 }
11109 #endif
11110 }
11111
11112 } // end namespace Catch
11113 // end catch_session.cpp
11114 // start catch_singletons.cpp
11115
11116 #include <vector>
11117
11118 namespace Catch {
11119
11120 namespace {
getSingletons()11121 static auto getSingletons() -> std::vector<ISingleton*>*& {
11122 static std::vector<ISingleton*>* g_singletons = nullptr;
11123 if( !g_singletons )
11124 g_singletons = new std::vector<ISingleton*>();
11125 return g_singletons;
11126 }
11127 }
11128
~ISingleton()11129 ISingleton::~ISingleton() {}
11130
addSingleton(ISingleton * singleton)11131 void addSingleton(ISingleton* singleton ) {
11132 getSingletons()->push_back( singleton );
11133 }
cleanupSingletons()11134 void cleanupSingletons() {
11135 auto& singletons = getSingletons();
11136 for( auto singleton : *singletons )
11137 delete singleton;
11138 delete singletons;
11139 singletons = nullptr;
11140 }
11141
11142 } // namespace Catch
11143 // end catch_singletons.cpp
11144 // start catch_startup_exception_registry.cpp
11145
11146 namespace Catch {
add(std::exception_ptr const & exception)11147 void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept {
11148 CATCH_TRY {
11149 m_exceptions.push_back(exception);
11150 } CATCH_CATCH_ALL {
11151 // If we run out of memory during start-up there's really not a lot more we can do about it
11152 std::terminate();
11153 }
11154 }
11155
getExceptions() const11156 std::vector<std::exception_ptr> const& StartupExceptionRegistry::getExceptions() const noexcept {
11157 return m_exceptions;
11158 }
11159
11160 } // end namespace Catch
11161 // end catch_startup_exception_registry.cpp
11162 // start catch_stream.cpp
11163
11164 #include <cstdio>
11165 #include <iostream>
11166 #include <fstream>
11167 #include <sstream>
11168 #include <vector>
11169 #include <memory>
11170
11171 namespace Catch {
11172
11173 Catch::IStream::~IStream() = default;
11174
11175 namespace detail { namespace {
11176 template<typename WriterF, std::size_t bufferSize=256>
11177 class StreamBufImpl : public std::streambuf {
11178 char data[bufferSize];
11179 WriterF m_writer;
11180
11181 public:
StreamBufImpl()11182 StreamBufImpl() {
11183 setp( data, data + sizeof(data) );
11184 }
11185
~StreamBufImpl()11186 ~StreamBufImpl() noexcept {
11187 StreamBufImpl::sync();
11188 }
11189
11190 private:
overflow(int c)11191 int overflow( int c ) override {
11192 sync();
11193
11194 if( c != EOF ) {
11195 if( pbase() == epptr() )
11196 m_writer( std::string( 1, static_cast<char>( c ) ) );
11197 else
11198 sputc( static_cast<char>( c ) );
11199 }
11200 return 0;
11201 }
11202
sync()11203 int sync() override {
11204 if( pbase() != pptr() ) {
11205 m_writer( std::string( pbase(), static_cast<std::string::size_type>( pptr() - pbase() ) ) );
11206 setp( pbase(), epptr() );
11207 }
11208 return 0;
11209 }
11210 };
11211
11212 ///////////////////////////////////////////////////////////////////////////
11213
11214 struct OutputDebugWriter {
11215
operator ()Catch::detail::__anon2c2dcc261c11::OutputDebugWriter11216 void operator()( std::string const&str ) {
11217 writeToDebugConsole( str );
11218 }
11219 };
11220
11221 ///////////////////////////////////////////////////////////////////////////
11222
11223 class FileStream : public IStream {
11224 mutable std::ofstream m_ofs;
11225 public:
FileStream(StringRef filename)11226 FileStream( StringRef filename ) {
11227 m_ofs.open( filename.c_str() );
11228 CATCH_ENFORCE( !m_ofs.fail(), "Unable to open file: '" << filename << "'" );
11229 }
11230 ~FileStream() override = default;
11231 public: // IStream
stream() const11232 std::ostream& stream() const override {
11233 return m_ofs;
11234 }
11235 };
11236
11237 ///////////////////////////////////////////////////////////////////////////
11238
11239 class CoutStream : public IStream {
11240 mutable std::ostream m_os;
11241 public:
11242 // Store the streambuf from cout up-front because
11243 // cout may get redirected when running tests
CoutStream()11244 CoutStream() : m_os( Catch::cout().rdbuf() ) {}
11245 ~CoutStream() override = default;
11246
11247 public: // IStream
stream() const11248 std::ostream& stream() const override { return m_os; }
11249 };
11250
11251 ///////////////////////////////////////////////////////////////////////////
11252
11253 class DebugOutStream : public IStream {
11254 std::unique_ptr<StreamBufImpl<OutputDebugWriter>> m_streamBuf;
11255 mutable std::ostream m_os;
11256 public:
DebugOutStream()11257 DebugOutStream()
11258 : m_streamBuf( new StreamBufImpl<OutputDebugWriter>() ),
11259 m_os( m_streamBuf.get() )
11260 {}
11261
11262 ~DebugOutStream() override = default;
11263
11264 public: // IStream
stream() const11265 std::ostream& stream() const override { return m_os; }
11266 };
11267
11268 }} // namespace anon::detail
11269
11270 ///////////////////////////////////////////////////////////////////////////
11271
makeStream(StringRef const & filename)11272 auto makeStream( StringRef const &filename ) -> IStream const* {
11273 if( filename.empty() )
11274 return new detail::CoutStream();
11275 else if( filename[0] == '%' ) {
11276 if( filename == "%debug" )
11277 return new detail::DebugOutStream();
11278 else
11279 CATCH_ERROR( "Unrecognised stream: '" << filename << "'" );
11280 }
11281 else
11282 return new detail::FileStream( filename );
11283 }
11284
11285 // This class encapsulates the idea of a pool of ostringstreams that can be reused.
11286 struct StringStreams {
11287 std::vector<std::unique_ptr<std::ostringstream>> m_streams;
11288 std::vector<std::size_t> m_unused;
11289 std::ostringstream m_referenceStream; // Used for copy state/ flags from
11290
addCatch::StringStreams11291 auto add() -> std::size_t {
11292 if( m_unused.empty() ) {
11293 m_streams.push_back( std::unique_ptr<std::ostringstream>( new std::ostringstream ) );
11294 return m_streams.size()-1;
11295 }
11296 else {
11297 auto index = m_unused.back();
11298 m_unused.pop_back();
11299 return index;
11300 }
11301 }
11302
releaseCatch::StringStreams11303 void release( std::size_t index ) {
11304 m_streams[index]->copyfmt( m_referenceStream ); // Restore initial flags and other state
11305 m_unused.push_back(index);
11306 }
11307 };
11308
ReusableStringStream()11309 ReusableStringStream::ReusableStringStream()
11310 : m_index( Singleton<StringStreams>::getMutable().add() ),
11311 m_oss( Singleton<StringStreams>::getMutable().m_streams[m_index].get() )
11312 {}
11313
~ReusableStringStream()11314 ReusableStringStream::~ReusableStringStream() {
11315 static_cast<std::ostringstream*>( m_oss )->str("");
11316 m_oss->clear();
11317 Singleton<StringStreams>::getMutable().release( m_index );
11318 }
11319
str() const11320 auto ReusableStringStream::str() const -> std::string {
11321 return static_cast<std::ostringstream*>( m_oss )->str();
11322 }
11323
11324 ///////////////////////////////////////////////////////////////////////////
11325
11326 #ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions
cout()11327 std::ostream& cout() { return std::cout; }
cerr()11328 std::ostream& cerr() { return std::cerr; }
clog()11329 std::ostream& clog() { return std::clog; }
11330 #endif
11331 }
11332 // end catch_stream.cpp
11333 // start catch_string_manip.cpp
11334
11335 #include <algorithm>
11336 #include <ostream>
11337 #include <cstring>
11338 #include <cctype>
11339
11340 namespace Catch {
11341
11342 namespace {
toLowerCh(char c)11343 char toLowerCh(char c) {
11344 return static_cast<char>( std::tolower( c ) );
11345 }
11346 }
11347
startsWith(std::string const & s,std::string const & prefix)11348 bool startsWith( std::string const& s, std::string const& prefix ) {
11349 return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin());
11350 }
startsWith(std::string const & s,char prefix)11351 bool startsWith( std::string const& s, char prefix ) {
11352 return !s.empty() && s[0] == prefix;
11353 }
endsWith(std::string const & s,std::string const & suffix)11354 bool endsWith( std::string const& s, std::string const& suffix ) {
11355 return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin());
11356 }
endsWith(std::string const & s,char suffix)11357 bool endsWith( std::string const& s, char suffix ) {
11358 return !s.empty() && s[s.size()-1] == suffix;
11359 }
contains(std::string const & s,std::string const & infix)11360 bool contains( std::string const& s, std::string const& infix ) {
11361 return s.find( infix ) != std::string::npos;
11362 }
toLowerInPlace(std::string & s)11363 void toLowerInPlace( std::string& s ) {
11364 std::transform( s.begin(), s.end(), s.begin(), toLowerCh );
11365 }
toLower(std::string const & s)11366 std::string toLower( std::string const& s ) {
11367 std::string lc = s;
11368 toLowerInPlace( lc );
11369 return lc;
11370 }
trim(std::string const & str)11371 std::string trim( std::string const& str ) {
11372 static char const* whitespaceChars = "\n\r\t ";
11373 std::string::size_type start = str.find_first_not_of( whitespaceChars );
11374 std::string::size_type end = str.find_last_not_of( whitespaceChars );
11375
11376 return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string();
11377 }
11378
replaceInPlace(std::string & str,std::string const & replaceThis,std::string const & withThis)11379 bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) {
11380 bool replaced = false;
11381 std::size_t i = str.find( replaceThis );
11382 while( i != std::string::npos ) {
11383 replaced = true;
11384 str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() );
11385 if( i < str.size()-withThis.size() )
11386 i = str.find( replaceThis, i+withThis.size() );
11387 else
11388 i = std::string::npos;
11389 }
11390 return replaced;
11391 }
11392
pluralise(std::size_t count,std::string const & label)11393 pluralise::pluralise( std::size_t count, std::string const& label )
11394 : m_count( count ),
11395 m_label( label )
11396 {}
11397
operator <<(std::ostream & os,pluralise const & pluraliser)11398 std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) {
11399 os << pluraliser.m_count << ' ' << pluraliser.m_label;
11400 if( pluraliser.m_count != 1 )
11401 os << 's';
11402 return os;
11403 }
11404
11405 }
11406 // end catch_string_manip.cpp
11407 // start catch_stringref.cpp
11408
11409 #if defined(__clang__)
11410 # pragma clang diagnostic push
11411 # pragma clang diagnostic ignored "-Wexit-time-destructors"
11412 #endif
11413
11414 #include <ostream>
11415 #include <cstring>
11416 #include <cstdint>
11417
11418 namespace {
11419 const uint32_t byte_2_lead = 0xC0;
11420 const uint32_t byte_3_lead = 0xE0;
11421 const uint32_t byte_4_lead = 0xF0;
11422 }
11423
11424 namespace Catch {
StringRef(char const * rawChars)11425 StringRef::StringRef( char const* rawChars ) noexcept
11426 : StringRef( rawChars, static_cast<StringRef::size_type>(std::strlen(rawChars) ) )
11427 {}
11428
operator std::string() const11429 StringRef::operator std::string() const {
11430 return std::string( m_start, m_size );
11431 }
11432
swap(StringRef & other)11433 void StringRef::swap( StringRef& other ) noexcept {
11434 std::swap( m_start, other.m_start );
11435 std::swap( m_size, other.m_size );
11436 std::swap( m_data, other.m_data );
11437 }
11438
c_str() const11439 auto StringRef::c_str() const -> char const* {
11440 if( isSubstring() )
11441 const_cast<StringRef*>( this )->takeOwnership();
11442 return m_start;
11443 }
currentData() const11444 auto StringRef::currentData() const noexcept -> char const* {
11445 return m_start;
11446 }
11447
isOwned() const11448 auto StringRef::isOwned() const noexcept -> bool {
11449 return m_data != nullptr;
11450 }
isSubstring() const11451 auto StringRef::isSubstring() const noexcept -> bool {
11452 return m_start[m_size] != '\0';
11453 }
11454
takeOwnership()11455 void StringRef::takeOwnership() {
11456 if( !isOwned() ) {
11457 m_data = new char[m_size+1];
11458 memcpy( m_data, m_start, m_size );
11459 m_data[m_size] = '\0';
11460 m_start = m_data;
11461 }
11462 }
substr(size_type start,size_type size) const11463 auto StringRef::substr( size_type start, size_type size ) const noexcept -> StringRef {
11464 if( start < m_size )
11465 return StringRef( m_start+start, size );
11466 else
11467 return StringRef();
11468 }
operator ==(StringRef const & other) const11469 auto StringRef::operator == ( StringRef const& other ) const noexcept -> bool {
11470 return
11471 size() == other.size() &&
11472 (std::strncmp( m_start, other.m_start, size() ) == 0);
11473 }
operator !=(StringRef const & other) const11474 auto StringRef::operator != ( StringRef const& other ) const noexcept -> bool {
11475 return !operator==( other );
11476 }
11477
operator [](size_type index) const11478 auto StringRef::operator[](size_type index) const noexcept -> char {
11479 return m_start[index];
11480 }
11481
numberOfCharacters() const11482 auto StringRef::numberOfCharacters() const noexcept -> size_type {
11483 size_type noChars = m_size;
11484 // Make adjustments for uft encodings
11485 for( size_type i=0; i < m_size; ++i ) {
11486 char c = m_start[i];
11487 if( ( c & byte_2_lead ) == byte_2_lead ) {
11488 noChars--;
11489 if (( c & byte_3_lead ) == byte_3_lead )
11490 noChars--;
11491 if( ( c & byte_4_lead ) == byte_4_lead )
11492 noChars--;
11493 }
11494 }
11495 return noChars;
11496 }
11497
operator +(StringRef const & lhs,StringRef const & rhs)11498 auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string {
11499 std::string str;
11500 str.reserve( lhs.size() + rhs.size() );
11501 str += lhs;
11502 str += rhs;
11503 return str;
11504 }
operator +(StringRef const & lhs,const char * rhs)11505 auto operator + ( StringRef const& lhs, const char* rhs ) -> std::string {
11506 return std::string( lhs ) + std::string( rhs );
11507 }
operator +(char const * lhs,StringRef const & rhs)11508 auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string {
11509 return std::string( lhs ) + std::string( rhs );
11510 }
11511
operator <<(std::ostream & os,StringRef const & str)11512 auto operator << ( std::ostream& os, StringRef const& str ) -> std::ostream& {
11513 return os.write(str.currentData(), str.size());
11514 }
11515
operator +=(std::string & lhs,StringRef const & rhs)11516 auto operator+=( std::string& lhs, StringRef const& rhs ) -> std::string& {
11517 lhs.append(rhs.currentData(), rhs.size());
11518 return lhs;
11519 }
11520
11521 } // namespace Catch
11522
11523 #if defined(__clang__)
11524 # pragma clang diagnostic pop
11525 #endif
11526 // end catch_stringref.cpp
11527 // start catch_tag_alias.cpp
11528
11529 namespace Catch {
TagAlias(std::string const & _tag,SourceLineInfo _lineInfo)11530 TagAlias::TagAlias(std::string const & _tag, SourceLineInfo _lineInfo): tag(_tag), lineInfo(_lineInfo) {}
11531 }
11532 // end catch_tag_alias.cpp
11533 // start catch_tag_alias_autoregistrar.cpp
11534
11535 namespace Catch {
11536
RegistrarForTagAliases(char const * alias,char const * tag,SourceLineInfo const & lineInfo)11537 RegistrarForTagAliases::RegistrarForTagAliases(char const* alias, char const* tag, SourceLineInfo const& lineInfo) {
11538 CATCH_TRY {
11539 getMutableRegistryHub().registerTagAlias(alias, tag, lineInfo);
11540 } CATCH_CATCH_ALL {
11541 // Do not throw when constructing global objects, instead register the exception to be processed later
11542 getMutableRegistryHub().registerStartupException();
11543 }
11544 }
11545
11546 }
11547 // end catch_tag_alias_autoregistrar.cpp
11548 // start catch_tag_alias_registry.cpp
11549
11550 #include <sstream>
11551
11552 namespace Catch {
11553
~TagAliasRegistry()11554 TagAliasRegistry::~TagAliasRegistry() {}
11555
find(std::string const & alias) const11556 TagAlias const* TagAliasRegistry::find( std::string const& alias ) const {
11557 auto it = m_registry.find( alias );
11558 if( it != m_registry.end() )
11559 return &(it->second);
11560 else
11561 return nullptr;
11562 }
11563
expandAliases(std::string const & unexpandedTestSpec) const11564 std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const {
11565 std::string expandedTestSpec = unexpandedTestSpec;
11566 for( auto const& registryKvp : m_registry ) {
11567 std::size_t pos = expandedTestSpec.find( registryKvp.first );
11568 if( pos != std::string::npos ) {
11569 expandedTestSpec = expandedTestSpec.substr( 0, pos ) +
11570 registryKvp.second.tag +
11571 expandedTestSpec.substr( pos + registryKvp.first.size() );
11572 }
11573 }
11574 return expandedTestSpec;
11575 }
11576
add(std::string const & alias,std::string const & tag,SourceLineInfo const & lineInfo)11577 void TagAliasRegistry::add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) {
11578 CATCH_ENFORCE( startsWith(alias, "[@") && endsWith(alias, ']'),
11579 "error: tag alias, '" << alias << "' is not of the form [@alias name].\n" << lineInfo );
11580
11581 CATCH_ENFORCE( m_registry.insert(std::make_pair(alias, TagAlias(tag, lineInfo))).second,
11582 "error: tag alias, '" << alias << "' already registered.\n"
11583 << "\tFirst seen at: " << find(alias)->lineInfo << "\n"
11584 << "\tRedefined at: " << lineInfo );
11585 }
11586
~ITagAliasRegistry()11587 ITagAliasRegistry::~ITagAliasRegistry() {}
11588
get()11589 ITagAliasRegistry const& ITagAliasRegistry::get() {
11590 return getRegistryHub().getTagAliasRegistry();
11591 }
11592
11593 } // end namespace Catch
11594 // end catch_tag_alias_registry.cpp
11595 // start catch_test_case_info.cpp
11596
11597 #include <cctype>
11598 #include <exception>
11599 #include <algorithm>
11600 #include <sstream>
11601
11602 namespace Catch {
11603
11604 namespace {
parseSpecialTag(std::string const & tag)11605 TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) {
11606 if( startsWith( tag, '.' ) ||
11607 tag == "!hide" )
11608 return TestCaseInfo::IsHidden;
11609 else if( tag == "!throws" )
11610 return TestCaseInfo::Throws;
11611 else if( tag == "!shouldfail" )
11612 return TestCaseInfo::ShouldFail;
11613 else if( tag == "!mayfail" )
11614 return TestCaseInfo::MayFail;
11615 else if( tag == "!nonportable" )
11616 return TestCaseInfo::NonPortable;
11617 else if( tag == "!benchmark" )
11618 return static_cast<TestCaseInfo::SpecialProperties>( TestCaseInfo::Benchmark | TestCaseInfo::IsHidden );
11619 else
11620 return TestCaseInfo::None;
11621 }
isReservedTag(std::string const & tag)11622 bool isReservedTag( std::string const& tag ) {
11623 return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( static_cast<unsigned char>(tag[0]) );
11624 }
enforceNotReservedTag(std::string const & tag,SourceLineInfo const & _lineInfo)11625 void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) {
11626 CATCH_ENFORCE( !isReservedTag(tag),
11627 "Tag name: [" << tag << "] is not allowed.\n"
11628 << "Tag names starting with non alpha-numeric characters are reserved\n"
11629 << _lineInfo );
11630 }
11631 }
11632
makeTestCase(ITestInvoker * _testCase,std::string const & _className,NameAndTags const & nameAndTags,SourceLineInfo const & _lineInfo)11633 TestCase makeTestCase( ITestInvoker* _testCase,
11634 std::string const& _className,
11635 NameAndTags const& nameAndTags,
11636 SourceLineInfo const& _lineInfo )
11637 {
11638 bool isHidden = false;
11639
11640 // Parse out tags
11641 std::vector<std::string> tags;
11642 std::string desc, tag;
11643 bool inTag = false;
11644 std::string _descOrTags = nameAndTags.tags;
11645 for (char c : _descOrTags) {
11646 if( !inTag ) {
11647 if( c == '[' )
11648 inTag = true;
11649 else
11650 desc += c;
11651 }
11652 else {
11653 if( c == ']' ) {
11654 TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag );
11655 if( ( prop & TestCaseInfo::IsHidden ) != 0 )
11656 isHidden = true;
11657 else if( prop == TestCaseInfo::None )
11658 enforceNotReservedTag( tag, _lineInfo );
11659
11660 tags.push_back( tag );
11661 tag.clear();
11662 inTag = false;
11663 }
11664 else
11665 tag += c;
11666 }
11667 }
11668 if( isHidden ) {
11669 tags.push_back( "." );
11670 }
11671
11672 TestCaseInfo info( nameAndTags.name, _className, desc, tags, _lineInfo );
11673 return TestCase( _testCase, std::move(info) );
11674 }
11675
setTags(TestCaseInfo & testCaseInfo,std::vector<std::string> tags)11676 void setTags( TestCaseInfo& testCaseInfo, std::vector<std::string> tags ) {
11677 std::sort(begin(tags), end(tags));
11678 tags.erase(std::unique(begin(tags), end(tags)), end(tags));
11679 testCaseInfo.lcaseTags.clear();
11680
11681 for( auto const& tag : tags ) {
11682 std::string lcaseTag = toLower( tag );
11683 testCaseInfo.properties = static_cast<TestCaseInfo::SpecialProperties>( testCaseInfo.properties | parseSpecialTag( lcaseTag ) );
11684 testCaseInfo.lcaseTags.push_back( lcaseTag );
11685 }
11686 testCaseInfo.tags = std::move(tags);
11687 }
11688
TestCaseInfo(std::string const & _name,std::string const & _className,std::string const & _description,std::vector<std::string> const & _tags,SourceLineInfo const & _lineInfo)11689 TestCaseInfo::TestCaseInfo( std::string const& _name,
11690 std::string const& _className,
11691 std::string const& _description,
11692 std::vector<std::string> const& _tags,
11693 SourceLineInfo const& _lineInfo )
11694 : name( _name ),
11695 className( _className ),
11696 description( _description ),
11697 lineInfo( _lineInfo ),
11698 properties( None )
11699 {
11700 setTags( *this, _tags );
11701 }
11702
isHidden() const11703 bool TestCaseInfo::isHidden() const {
11704 return ( properties & IsHidden ) != 0;
11705 }
throws() const11706 bool TestCaseInfo::throws() const {
11707 return ( properties & Throws ) != 0;
11708 }
okToFail() const11709 bool TestCaseInfo::okToFail() const {
11710 return ( properties & (ShouldFail | MayFail ) ) != 0;
11711 }
expectedToFail() const11712 bool TestCaseInfo::expectedToFail() const {
11713 return ( properties & (ShouldFail ) ) != 0;
11714 }
11715
tagsAsString() const11716 std::string TestCaseInfo::tagsAsString() const {
11717 std::string ret;
11718 // '[' and ']' per tag
11719 std::size_t full_size = 2 * tags.size();
11720 for (const auto& tag : tags) {
11721 full_size += tag.size();
11722 }
11723 ret.reserve(full_size);
11724 for (const auto& tag : tags) {
11725 ret.push_back('[');
11726 ret.append(tag);
11727 ret.push_back(']');
11728 }
11729
11730 return ret;
11731 }
11732
TestCase(ITestInvoker * testCase,TestCaseInfo && info)11733 TestCase::TestCase( ITestInvoker* testCase, TestCaseInfo&& info ) : TestCaseInfo( std::move(info) ), test( testCase ) {}
11734
withName(std::string const & _newName) const11735 TestCase TestCase::withName( std::string const& _newName ) const {
11736 TestCase other( *this );
11737 other.name = _newName;
11738 return other;
11739 }
11740
invoke() const11741 void TestCase::invoke() const {
11742 test->invoke();
11743 }
11744
operator ==(TestCase const & other) const11745 bool TestCase::operator == ( TestCase const& other ) const {
11746 return test.get() == other.test.get() &&
11747 name == other.name &&
11748 className == other.className;
11749 }
11750
operator <(TestCase const & other) const11751 bool TestCase::operator < ( TestCase const& other ) const {
11752 return name < other.name;
11753 }
11754
getTestCaseInfo() const11755 TestCaseInfo const& TestCase::getTestCaseInfo() const
11756 {
11757 return *this;
11758 }
11759
11760 } // end namespace Catch
11761 // end catch_test_case_info.cpp
11762 // start catch_test_case_registry_impl.cpp
11763
11764 #include <sstream>
11765
11766 namespace Catch {
11767
sortTests(IConfig const & config,std::vector<TestCase> const & unsortedTestCases)11768 std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) {
11769
11770 std::vector<TestCase> sorted = unsortedTestCases;
11771
11772 switch( config.runOrder() ) {
11773 case RunTests::InLexicographicalOrder:
11774 std::sort( sorted.begin(), sorted.end() );
11775 break;
11776 case RunTests::InRandomOrder:
11777 seedRng( config );
11778 std::shuffle( sorted.begin(), sorted.end(), rng() );
11779 break;
11780 case RunTests::InDeclarationOrder:
11781 // already in declaration order
11782 break;
11783 }
11784 return sorted;
11785 }
matchTest(TestCase const & testCase,TestSpec const & testSpec,IConfig const & config)11786 bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) {
11787 return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() );
11788 }
11789
enforceNoDuplicateTestCases(std::vector<TestCase> const & functions)11790 void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions ) {
11791 std::set<TestCase> seenFunctions;
11792 for( auto const& function : functions ) {
11793 auto prev = seenFunctions.insert( function );
11794 CATCH_ENFORCE( prev.second,
11795 "error: TEST_CASE( \"" << function.name << "\" ) already defined.\n"
11796 << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n"
11797 << "\tRedefined at " << function.getTestCaseInfo().lineInfo );
11798 }
11799 }
11800
filterTests(std::vector<TestCase> const & testCases,TestSpec const & testSpec,IConfig const & config)11801 std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ) {
11802 std::vector<TestCase> filtered;
11803 filtered.reserve( testCases.size() );
11804 for( auto const& testCase : testCases )
11805 if( matchTest( testCase, testSpec, config ) )
11806 filtered.push_back( testCase );
11807 return filtered;
11808 }
getAllTestCasesSorted(IConfig const & config)11809 std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ) {
11810 return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config );
11811 }
11812
registerTest(TestCase const & testCase)11813 void TestRegistry::registerTest( TestCase const& testCase ) {
11814 std::string name = testCase.getTestCaseInfo().name;
11815 if( name.empty() ) {
11816 ReusableStringStream rss;
11817 rss << "Anonymous test case " << ++m_unnamedCount;
11818 return registerTest( testCase.withName( rss.str() ) );
11819 }
11820 m_functions.push_back( testCase );
11821 }
11822
getAllTests() const11823 std::vector<TestCase> const& TestRegistry::getAllTests() const {
11824 return m_functions;
11825 }
getAllTestsSorted(IConfig const & config) const11826 std::vector<TestCase> const& TestRegistry::getAllTestsSorted( IConfig const& config ) const {
11827 if( m_sortedFunctions.empty() )
11828 enforceNoDuplicateTestCases( m_functions );
11829
11830 if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) {
11831 m_sortedFunctions = sortTests( config, m_functions );
11832 m_currentSortOrder = config.runOrder();
11833 }
11834 return m_sortedFunctions;
11835 }
11836
11837 ///////////////////////////////////////////////////////////////////////////
TestInvokerAsFunction(void (* testAsFunction)())11838 TestInvokerAsFunction::TestInvokerAsFunction( void(*testAsFunction)() ) noexcept : m_testAsFunction( testAsFunction ) {}
11839
invoke() const11840 void TestInvokerAsFunction::invoke() const {
11841 m_testAsFunction();
11842 }
11843
extractClassName(StringRef const & classOrQualifiedMethodName)11844 std::string extractClassName( StringRef const& classOrQualifiedMethodName ) {
11845 std::string className = classOrQualifiedMethodName;
11846 if( startsWith( className, '&' ) )
11847 {
11848 std::size_t lastColons = className.rfind( "::" );
11849 std::size_t penultimateColons = className.rfind( "::", lastColons-1 );
11850 if( penultimateColons == std::string::npos )
11851 penultimateColons = 1;
11852 className = className.substr( penultimateColons, lastColons-penultimateColons );
11853 }
11854 return className;
11855 }
11856
11857 } // end namespace Catch
11858 // end catch_test_case_registry_impl.cpp
11859 // start catch_test_case_tracker.cpp
11860
11861 #include <algorithm>
11862 #include <cassert>
11863 #include <stdexcept>
11864 #include <memory>
11865 #include <sstream>
11866
11867 #if defined(__clang__)
11868 # pragma clang diagnostic push
11869 # pragma clang diagnostic ignored "-Wexit-time-destructors"
11870 #endif
11871
11872 namespace Catch {
11873 namespace TestCaseTracking {
11874
NameAndLocation(std::string const & _name,SourceLineInfo const & _location)11875 NameAndLocation::NameAndLocation( std::string const& _name, SourceLineInfo const& _location )
11876 : name( _name ),
11877 location( _location )
11878 {}
11879
11880 ITracker::~ITracker() = default;
11881
instance()11882 TrackerContext& TrackerContext::instance() {
11883 static TrackerContext s_instance;
11884 return s_instance;
11885 }
11886
startRun()11887 ITracker& TrackerContext::startRun() {
11888 m_rootTracker = std::make_shared<SectionTracker>( NameAndLocation( "{root}", CATCH_INTERNAL_LINEINFO ), *this, nullptr );
11889 m_currentTracker = nullptr;
11890 m_runState = Executing;
11891 return *m_rootTracker;
11892 }
11893
endRun()11894 void TrackerContext::endRun() {
11895 m_rootTracker.reset();
11896 m_currentTracker = nullptr;
11897 m_runState = NotStarted;
11898 }
11899
startCycle()11900 void TrackerContext::startCycle() {
11901 m_currentTracker = m_rootTracker.get();
11902 m_runState = Executing;
11903 }
completeCycle()11904 void TrackerContext::completeCycle() {
11905 m_runState = CompletedCycle;
11906 }
11907
completedCycle() const11908 bool TrackerContext::completedCycle() const {
11909 return m_runState == CompletedCycle;
11910 }
currentTracker()11911 ITracker& TrackerContext::currentTracker() {
11912 return *m_currentTracker;
11913 }
setCurrentTracker(ITracker * tracker)11914 void TrackerContext::setCurrentTracker( ITracker* tracker ) {
11915 m_currentTracker = tracker;
11916 }
11917
TrackerBase(NameAndLocation const & nameAndLocation,TrackerContext & ctx,ITracker * parent)11918 TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
11919 : m_nameAndLocation( nameAndLocation ),
11920 m_ctx( ctx ),
11921 m_parent( parent )
11922 {}
11923
nameAndLocation() const11924 NameAndLocation const& TrackerBase::nameAndLocation() const {
11925 return m_nameAndLocation;
11926 }
isComplete() const11927 bool TrackerBase::isComplete() const {
11928 return m_runState == CompletedSuccessfully || m_runState == Failed;
11929 }
isSuccessfullyCompleted() const11930 bool TrackerBase::isSuccessfullyCompleted() const {
11931 return m_runState == CompletedSuccessfully;
11932 }
isOpen() const11933 bool TrackerBase::isOpen() const {
11934 return m_runState != NotStarted && !isComplete();
11935 }
hasChildren() const11936 bool TrackerBase::hasChildren() const {
11937 return !m_children.empty();
11938 }
11939
addChild(ITrackerPtr const & child)11940 void TrackerBase::addChild( ITrackerPtr const& child ) {
11941 m_children.push_back( child );
11942 }
11943
findChild(NameAndLocation const & nameAndLocation)11944 ITrackerPtr TrackerBase::findChild( NameAndLocation const& nameAndLocation ) {
11945 auto it = std::find_if( m_children.begin(), m_children.end(),
11946 [&nameAndLocation]( ITrackerPtr const& tracker ){
11947 return
11948 tracker->nameAndLocation().location == nameAndLocation.location &&
11949 tracker->nameAndLocation().name == nameAndLocation.name;
11950 } );
11951 return( it != m_children.end() )
11952 ? *it
11953 : nullptr;
11954 }
parent()11955 ITracker& TrackerBase::parent() {
11956 assert( m_parent ); // Should always be non-null except for root
11957 return *m_parent;
11958 }
11959
openChild()11960 void TrackerBase::openChild() {
11961 if( m_runState != ExecutingChildren ) {
11962 m_runState = ExecutingChildren;
11963 if( m_parent )
11964 m_parent->openChild();
11965 }
11966 }
11967
isSectionTracker() const11968 bool TrackerBase::isSectionTracker() const { return false; }
isGeneratorTracker() const11969 bool TrackerBase::isGeneratorTracker() const { return false; }
11970
open()11971 void TrackerBase::open() {
11972 m_runState = Executing;
11973 moveToThis();
11974 if( m_parent )
11975 m_parent->openChild();
11976 }
11977
close()11978 void TrackerBase::close() {
11979
11980 // Close any still open children (e.g. generators)
11981 while( &m_ctx.currentTracker() != this )
11982 m_ctx.currentTracker().close();
11983
11984 switch( m_runState ) {
11985 case NeedsAnotherRun:
11986 break;
11987
11988 case Executing:
11989 m_runState = CompletedSuccessfully;
11990 break;
11991 case ExecutingChildren:
11992 if( m_children.empty() || m_children.back()->isComplete() )
11993 m_runState = CompletedSuccessfully;
11994 break;
11995
11996 case NotStarted:
11997 case CompletedSuccessfully:
11998 case Failed:
11999 CATCH_INTERNAL_ERROR( "Illogical state: " << m_runState );
12000
12001 default:
12002 CATCH_INTERNAL_ERROR( "Unknown state: " << m_runState );
12003 }
12004 moveToParent();
12005 m_ctx.completeCycle();
12006 }
fail()12007 void TrackerBase::fail() {
12008 m_runState = Failed;
12009 if( m_parent )
12010 m_parent->markAsNeedingAnotherRun();
12011 moveToParent();
12012 m_ctx.completeCycle();
12013 }
markAsNeedingAnotherRun()12014 void TrackerBase::markAsNeedingAnotherRun() {
12015 m_runState = NeedsAnotherRun;
12016 }
12017
moveToParent()12018 void TrackerBase::moveToParent() {
12019 assert( m_parent );
12020 m_ctx.setCurrentTracker( m_parent );
12021 }
moveToThis()12022 void TrackerBase::moveToThis() {
12023 m_ctx.setCurrentTracker( this );
12024 }
12025
SectionTracker(NameAndLocation const & nameAndLocation,TrackerContext & ctx,ITracker * parent)12026 SectionTracker::SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
12027 : TrackerBase( nameAndLocation, ctx, parent )
12028 {
12029 if( parent ) {
12030 while( !parent->isSectionTracker() )
12031 parent = &parent->parent();
12032
12033 SectionTracker& parentSection = static_cast<SectionTracker&>( *parent );
12034 addNextFilters( parentSection.m_filters );
12035 }
12036 }
12037
isComplete() const12038 bool SectionTracker::isComplete() const {
12039 bool complete = true;
12040
12041 if ((m_filters.empty() || m_filters[0] == "") ||
12042 std::find(m_filters.begin(), m_filters.end(),
12043 m_nameAndLocation.name) != m_filters.end())
12044 complete = TrackerBase::isComplete();
12045 return complete;
12046
12047 }
12048
isSectionTracker() const12049 bool SectionTracker::isSectionTracker() const { return true; }
12050
acquire(TrackerContext & ctx,NameAndLocation const & nameAndLocation)12051 SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) {
12052 std::shared_ptr<SectionTracker> section;
12053
12054 ITracker& currentTracker = ctx.currentTracker();
12055 if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) {
12056 assert( childTracker );
12057 assert( childTracker->isSectionTracker() );
12058 section = std::static_pointer_cast<SectionTracker>( childTracker );
12059 }
12060 else {
12061 section = std::make_shared<SectionTracker>( nameAndLocation, ctx, ¤tTracker );
12062 currentTracker.addChild( section );
12063 }
12064 if( !ctx.completedCycle() )
12065 section->tryOpen();
12066 return *section;
12067 }
12068
tryOpen()12069 void SectionTracker::tryOpen() {
12070 if( !isComplete() && (m_filters.empty() || m_filters[0].empty() || m_filters[0] == m_nameAndLocation.name ) )
12071 open();
12072 }
12073
addInitialFilters(std::vector<std::string> const & filters)12074 void SectionTracker::addInitialFilters( std::vector<std::string> const& filters ) {
12075 if( !filters.empty() ) {
12076 m_filters.push_back(""); // Root - should never be consulted
12077 m_filters.push_back(""); // Test Case - not a section filter
12078 m_filters.insert( m_filters.end(), filters.begin(), filters.end() );
12079 }
12080 }
addNextFilters(std::vector<std::string> const & filters)12081 void SectionTracker::addNextFilters( std::vector<std::string> const& filters ) {
12082 if( filters.size() > 1 )
12083 m_filters.insert( m_filters.end(), ++filters.begin(), filters.end() );
12084 }
12085
12086 } // namespace TestCaseTracking
12087
12088 using TestCaseTracking::ITracker;
12089 using TestCaseTracking::TrackerContext;
12090 using TestCaseTracking::SectionTracker;
12091
12092 } // namespace Catch
12093
12094 #if defined(__clang__)
12095 # pragma clang diagnostic pop
12096 #endif
12097 // end catch_test_case_tracker.cpp
12098 // start catch_test_registry.cpp
12099
12100 namespace Catch {
12101
makeTestInvoker(void (* testAsFunction)())12102 auto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker* {
12103 return new(std::nothrow) TestInvokerAsFunction( testAsFunction );
12104 }
12105
NameAndTags(StringRef const & name_,StringRef const & tags_)12106 NameAndTags::NameAndTags( StringRef const& name_ , StringRef const& tags_ ) noexcept : name( name_ ), tags( tags_ ) {}
12107
AutoReg(ITestInvoker * invoker,SourceLineInfo const & lineInfo,StringRef const & classOrMethod,NameAndTags const & nameAndTags)12108 AutoReg::AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept {
12109 CATCH_TRY {
12110 getMutableRegistryHub()
12111 .registerTest(
12112 makeTestCase(
12113 invoker,
12114 extractClassName( classOrMethod ),
12115 nameAndTags,
12116 lineInfo));
12117 } CATCH_CATCH_ALL {
12118 // Do not throw when constructing global objects, instead register the exception to be processed later
12119 getMutableRegistryHub().registerStartupException();
12120 }
12121 }
12122
12123 AutoReg::~AutoReg() = default;
12124 }
12125 // end catch_test_registry.cpp
12126 // start catch_test_spec.cpp
12127
12128 #include <algorithm>
12129 #include <string>
12130 #include <vector>
12131 #include <memory>
12132
12133 namespace Catch {
12134
12135 TestSpec::Pattern::~Pattern() = default;
12136 TestSpec::NamePattern::~NamePattern() = default;
12137 TestSpec::TagPattern::~TagPattern() = default;
12138 TestSpec::ExcludedPattern::~ExcludedPattern() = default;
12139
NamePattern(std::string const & name)12140 TestSpec::NamePattern::NamePattern( std::string const& name )
12141 : m_wildcardPattern( toLower( name ), CaseSensitive::No )
12142 {}
matches(TestCaseInfo const & testCase) const12143 bool TestSpec::NamePattern::matches( TestCaseInfo const& testCase ) const {
12144 return m_wildcardPattern.matches( toLower( testCase.name ) );
12145 }
12146
TagPattern(std::string const & tag)12147 TestSpec::TagPattern::TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {}
matches(TestCaseInfo const & testCase) const12148 bool TestSpec::TagPattern::matches( TestCaseInfo const& testCase ) const {
12149 return std::find(begin(testCase.lcaseTags),
12150 end(testCase.lcaseTags),
12151 m_tag) != end(testCase.lcaseTags);
12152 }
12153
ExcludedPattern(PatternPtr const & underlyingPattern)12154 TestSpec::ExcludedPattern::ExcludedPattern( PatternPtr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {}
matches(TestCaseInfo const & testCase) const12155 bool TestSpec::ExcludedPattern::matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); }
12156
matches(TestCaseInfo const & testCase) const12157 bool TestSpec::Filter::matches( TestCaseInfo const& testCase ) const {
12158 // All patterns in a filter must match for the filter to be a match
12159 for( auto const& pattern : m_patterns ) {
12160 if( !pattern->matches( testCase ) )
12161 return false;
12162 }
12163 return true;
12164 }
12165
hasFilters() const12166 bool TestSpec::hasFilters() const {
12167 return !m_filters.empty();
12168 }
matches(TestCaseInfo const & testCase) const12169 bool TestSpec::matches( TestCaseInfo const& testCase ) const {
12170 // A TestSpec matches if any filter matches
12171 for( auto const& filter : m_filters )
12172 if( filter.matches( testCase ) )
12173 return true;
12174 return false;
12175 }
12176 }
12177 // end catch_test_spec.cpp
12178 // start catch_test_spec_parser.cpp
12179
12180 namespace Catch {
12181
TestSpecParser(ITagAliasRegistry const & tagAliases)12182 TestSpecParser::TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {}
12183
parse(std::string const & arg)12184 TestSpecParser& TestSpecParser::parse( std::string const& arg ) {
12185 m_mode = None;
12186 m_exclusion = false;
12187 m_start = std::string::npos;
12188 m_arg = m_tagAliases->expandAliases( arg );
12189 m_escapeChars.clear();
12190 for( m_pos = 0; m_pos < m_arg.size(); ++m_pos )
12191 visitChar( m_arg[m_pos] );
12192 if( m_mode == Name )
12193 addPattern<TestSpec::NamePattern>();
12194 return *this;
12195 }
testSpec()12196 TestSpec TestSpecParser::testSpec() {
12197 addFilter();
12198 return m_testSpec;
12199 }
12200
visitChar(char c)12201 void TestSpecParser::visitChar( char c ) {
12202 if( m_mode == None ) {
12203 switch( c ) {
12204 case ' ': return;
12205 case '~': m_exclusion = true; return;
12206 case '[': return startNewMode( Tag, ++m_pos );
12207 case '"': return startNewMode( QuotedName, ++m_pos );
12208 case '\\': return escape();
12209 default: startNewMode( Name, m_pos ); break;
12210 }
12211 }
12212 if( m_mode == Name ) {
12213 if( c == ',' ) {
12214 addPattern<TestSpec::NamePattern>();
12215 addFilter();
12216 }
12217 else if( c == '[' ) {
12218 if( subString() == "exclude:" )
12219 m_exclusion = true;
12220 else
12221 addPattern<TestSpec::NamePattern>();
12222 startNewMode( Tag, ++m_pos );
12223 }
12224 else if( c == '\\' )
12225 escape();
12226 }
12227 else if( m_mode == EscapedName )
12228 m_mode = Name;
12229 else if( m_mode == QuotedName && c == '"' )
12230 addPattern<TestSpec::NamePattern>();
12231 else if( m_mode == Tag && c == ']' )
12232 addPattern<TestSpec::TagPattern>();
12233 }
startNewMode(Mode mode,std::size_t start)12234 void TestSpecParser::startNewMode( Mode mode, std::size_t start ) {
12235 m_mode = mode;
12236 m_start = start;
12237 }
escape()12238 void TestSpecParser::escape() {
12239 if( m_mode == None )
12240 m_start = m_pos;
12241 m_mode = EscapedName;
12242 m_escapeChars.push_back( m_pos );
12243 }
subString() const12244 std::string TestSpecParser::subString() const { return m_arg.substr( m_start, m_pos - m_start ); }
12245
addFilter()12246 void TestSpecParser::addFilter() {
12247 if( !m_currentFilter.m_patterns.empty() ) {
12248 m_testSpec.m_filters.push_back( m_currentFilter );
12249 m_currentFilter = TestSpec::Filter();
12250 }
12251 }
12252
parseTestSpec(std::string const & arg)12253 TestSpec parseTestSpec( std::string const& arg ) {
12254 return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec();
12255 }
12256
12257 } // namespace Catch
12258 // end catch_test_spec_parser.cpp
12259 // start catch_timer.cpp
12260
12261 #include <chrono>
12262
12263 static const uint64_t nanosecondsInSecond = 1000000000;
12264
12265 namespace Catch {
12266
getCurrentNanosecondsSinceEpoch()12267 auto getCurrentNanosecondsSinceEpoch() -> uint64_t {
12268 return std::chrono::duration_cast<std::chrono::nanoseconds>( std::chrono::high_resolution_clock::now().time_since_epoch() ).count();
12269 }
12270
12271 namespace {
estimateClockResolution()12272 auto estimateClockResolution() -> uint64_t {
12273 uint64_t sum = 0;
12274 static const uint64_t iterations = 1000000;
12275
12276 auto startTime = getCurrentNanosecondsSinceEpoch();
12277
12278 for( std::size_t i = 0; i < iterations; ++i ) {
12279
12280 uint64_t ticks;
12281 uint64_t baseTicks = getCurrentNanosecondsSinceEpoch();
12282 do {
12283 ticks = getCurrentNanosecondsSinceEpoch();
12284 } while( ticks == baseTicks );
12285
12286 auto delta = ticks - baseTicks;
12287 sum += delta;
12288
12289 // If we have been calibrating for over 3 seconds -- the clock
12290 // is terrible and we should move on.
12291 // TBD: How to signal that the measured resolution is probably wrong?
12292 if (ticks > startTime + 3 * nanosecondsInSecond) {
12293 return sum / ( i + 1u );
12294 }
12295 }
12296
12297 // We're just taking the mean, here. To do better we could take the std. dev and exclude outliers
12298 // - and potentially do more iterations if there's a high variance.
12299 return sum/iterations;
12300 }
12301 }
getEstimatedClockResolution()12302 auto getEstimatedClockResolution() -> uint64_t {
12303 static auto s_resolution = estimateClockResolution();
12304 return s_resolution;
12305 }
12306
start()12307 void Timer::start() {
12308 m_nanoseconds = getCurrentNanosecondsSinceEpoch();
12309 }
getElapsedNanoseconds() const12310 auto Timer::getElapsedNanoseconds() const -> uint64_t {
12311 return getCurrentNanosecondsSinceEpoch() - m_nanoseconds;
12312 }
getElapsedMicroseconds() const12313 auto Timer::getElapsedMicroseconds() const -> uint64_t {
12314 return getElapsedNanoseconds()/1000;
12315 }
getElapsedMilliseconds() const12316 auto Timer::getElapsedMilliseconds() const -> unsigned int {
12317 return static_cast<unsigned int>(getElapsedMicroseconds()/1000);
12318 }
getElapsedSeconds() const12319 auto Timer::getElapsedSeconds() const -> double {
12320 return getElapsedMicroseconds()/1000000.0;
12321 }
12322
12323 } // namespace Catch
12324 // end catch_timer.cpp
12325 // start catch_tostring.cpp
12326
12327 #if defined(__clang__)
12328 # pragma clang diagnostic push
12329 # pragma clang diagnostic ignored "-Wexit-time-destructors"
12330 # pragma clang diagnostic ignored "-Wglobal-constructors"
12331 #endif
12332
12333 // Enable specific decls locally
12334 #if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER)
12335 #define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER
12336 #endif
12337
12338 #include <cmath>
12339 #include <iomanip>
12340
12341 namespace Catch {
12342
12343 namespace Detail {
12344
12345 const std::string unprintableString = "{?}";
12346
12347 namespace {
12348 const int hexThreshold = 255;
12349
12350 struct Endianness {
12351 enum Arch { Big, Little };
12352
whichCatch::Detail::__anon2c2dcc262211::Endianness12353 static Arch which() {
12354 union _{
12355 int asInt;
12356 char asChar[sizeof (int)];
12357 } u;
12358
12359 u.asInt = 1;
12360 return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little;
12361 }
12362 };
12363 }
12364
rawMemoryToString(const void * object,std::size_t size)12365 std::string rawMemoryToString( const void *object, std::size_t size ) {
12366 // Reverse order for little endian architectures
12367 int i = 0, end = static_cast<int>( size ), inc = 1;
12368 if( Endianness::which() == Endianness::Little ) {
12369 i = end-1;
12370 end = inc = -1;
12371 }
12372
12373 unsigned char const *bytes = static_cast<unsigned char const *>(object);
12374 ReusableStringStream rss;
12375 rss << "0x" << std::setfill('0') << std::hex;
12376 for( ; i != end; i += inc )
12377 rss << std::setw(2) << static_cast<unsigned>(bytes[i]);
12378 return rss.str();
12379 }
12380 }
12381
12382 template<typename T>
fpToString(T value,int precision)12383 std::string fpToString( T value, int precision ) {
12384 if (Catch::isnan(value)) {
12385 return "nan";
12386 }
12387
12388 ReusableStringStream rss;
12389 rss << std::setprecision( precision )
12390 << std::fixed
12391 << value;
12392 std::string d = rss.str();
12393 std::size_t i = d.find_last_not_of( '0' );
12394 if( i != std::string::npos && i != d.size()-1 ) {
12395 if( d[i] == '.' )
12396 i++;
12397 d = d.substr( 0, i+1 );
12398 }
12399 return d;
12400 }
12401
12402 //// ======================================================= ////
12403 //
12404 // Out-of-line defs for full specialization of StringMaker
12405 //
12406 //// ======================================================= ////
12407
convert(const std::string & str)12408 std::string StringMaker<std::string>::convert(const std::string& str) {
12409 if (!getCurrentContext().getConfig()->showInvisibles()) {
12410 return '"' + str + '"';
12411 }
12412
12413 std::string s("\"");
12414 for (char c : str) {
12415 switch (c) {
12416 case '\n':
12417 s.append("\\n");
12418 break;
12419 case '\t':
12420 s.append("\\t");
12421 break;
12422 default:
12423 s.push_back(c);
12424 break;
12425 }
12426 }
12427 s.append("\"");
12428 return s;
12429 }
12430
12431 #ifdef CATCH_CONFIG_CPP17_STRING_VIEW
convert(std::string_view str)12432 std::string StringMaker<std::string_view>::convert(std::string_view str) {
12433 return ::Catch::Detail::stringify(std::string{ str });
12434 }
12435 #endif
12436
convert(char const * str)12437 std::string StringMaker<char const*>::convert(char const* str) {
12438 if (str) {
12439 return ::Catch::Detail::stringify(std::string{ str });
12440 } else {
12441 return{ "{null string}" };
12442 }
12443 }
convert(char * str)12444 std::string StringMaker<char*>::convert(char* str) {
12445 if (str) {
12446 return ::Catch::Detail::stringify(std::string{ str });
12447 } else {
12448 return{ "{null string}" };
12449 }
12450 }
12451
12452 #ifdef CATCH_CONFIG_WCHAR
convert(const std::wstring & wstr)12453 std::string StringMaker<std::wstring>::convert(const std::wstring& wstr) {
12454 std::string s;
12455 s.reserve(wstr.size());
12456 for (auto c : wstr) {
12457 s += (c <= 0xff) ? static_cast<char>(c) : '?';
12458 }
12459 return ::Catch::Detail::stringify(s);
12460 }
12461
12462 # ifdef CATCH_CONFIG_CPP17_STRING_VIEW
convert(std::wstring_view str)12463 std::string StringMaker<std::wstring_view>::convert(std::wstring_view str) {
12464 return StringMaker<std::wstring>::convert(std::wstring(str));
12465 }
12466 # endif
12467
convert(wchar_t const * str)12468 std::string StringMaker<wchar_t const*>::convert(wchar_t const * str) {
12469 if (str) {
12470 return ::Catch::Detail::stringify(std::wstring{ str });
12471 } else {
12472 return{ "{null string}" };
12473 }
12474 }
convert(wchar_t * str)12475 std::string StringMaker<wchar_t *>::convert(wchar_t * str) {
12476 if (str) {
12477 return ::Catch::Detail::stringify(std::wstring{ str });
12478 } else {
12479 return{ "{null string}" };
12480 }
12481 }
12482 #endif
12483
convert(int value)12484 std::string StringMaker<int>::convert(int value) {
12485 return ::Catch::Detail::stringify(static_cast<long long>(value));
12486 }
convert(long value)12487 std::string StringMaker<long>::convert(long value) {
12488 return ::Catch::Detail::stringify(static_cast<long long>(value));
12489 }
convert(long long value)12490 std::string StringMaker<long long>::convert(long long value) {
12491 ReusableStringStream rss;
12492 rss << value;
12493 if (value > Detail::hexThreshold) {
12494 rss << " (0x" << std::hex << value << ')';
12495 }
12496 return rss.str();
12497 }
12498
convert(unsigned int value)12499 std::string StringMaker<unsigned int>::convert(unsigned int value) {
12500 return ::Catch::Detail::stringify(static_cast<unsigned long long>(value));
12501 }
convert(unsigned long value)12502 std::string StringMaker<unsigned long>::convert(unsigned long value) {
12503 return ::Catch::Detail::stringify(static_cast<unsigned long long>(value));
12504 }
convert(unsigned long long value)12505 std::string StringMaker<unsigned long long>::convert(unsigned long long value) {
12506 ReusableStringStream rss;
12507 rss << value;
12508 if (value > Detail::hexThreshold) {
12509 rss << " (0x" << std::hex << value << ')';
12510 }
12511 return rss.str();
12512 }
12513
convert(bool b)12514 std::string StringMaker<bool>::convert(bool b) {
12515 return b ? "true" : "false";
12516 }
12517
convert(signed char value)12518 std::string StringMaker<signed char>::convert(signed char value) {
12519 if (value == '\r') {
12520 return "'\\r'";
12521 } else if (value == '\f') {
12522 return "'\\f'";
12523 } else if (value == '\n') {
12524 return "'\\n'";
12525 } else if (value == '\t') {
12526 return "'\\t'";
12527 } else if ('\0' <= value && value < ' ') {
12528 return ::Catch::Detail::stringify(static_cast<unsigned int>(value));
12529 } else {
12530 char chstr[] = "' '";
12531 chstr[1] = value;
12532 return chstr;
12533 }
12534 }
convert(char c)12535 std::string StringMaker<char>::convert(char c) {
12536 return ::Catch::Detail::stringify(static_cast<signed char>(c));
12537 }
convert(unsigned char c)12538 std::string StringMaker<unsigned char>::convert(unsigned char c) {
12539 return ::Catch::Detail::stringify(static_cast<char>(c));
12540 }
12541
convert(std::nullptr_t)12542 std::string StringMaker<std::nullptr_t>::convert(std::nullptr_t) {
12543 return "nullptr";
12544 }
12545
convert(float value)12546 std::string StringMaker<float>::convert(float value) {
12547 return fpToString(value, 5) + 'f';
12548 }
convert(double value)12549 std::string StringMaker<double>::convert(double value) {
12550 return fpToString(value, 10);
12551 }
12552
symbol()12553 std::string ratio_string<std::atto>::symbol() { return "a"; }
symbol()12554 std::string ratio_string<std::femto>::symbol() { return "f"; }
symbol()12555 std::string ratio_string<std::pico>::symbol() { return "p"; }
symbol()12556 std::string ratio_string<std::nano>::symbol() { return "n"; }
symbol()12557 std::string ratio_string<std::micro>::symbol() { return "u"; }
symbol()12558 std::string ratio_string<std::milli>::symbol() { return "m"; }
12559
12560 } // end namespace Catch
12561
12562 #if defined(__clang__)
12563 # pragma clang diagnostic pop
12564 #endif
12565
12566 // end catch_tostring.cpp
12567 // start catch_totals.cpp
12568
12569 namespace Catch {
12570
operator -(Counts const & other) const12571 Counts Counts::operator - ( Counts const& other ) const {
12572 Counts diff;
12573 diff.passed = passed - other.passed;
12574 diff.failed = failed - other.failed;
12575 diff.failedButOk = failedButOk - other.failedButOk;
12576 return diff;
12577 }
12578
operator +=(Counts const & other)12579 Counts& Counts::operator += ( Counts const& other ) {
12580 passed += other.passed;
12581 failed += other.failed;
12582 failedButOk += other.failedButOk;
12583 return *this;
12584 }
12585
total() const12586 std::size_t Counts::total() const {
12587 return passed + failed + failedButOk;
12588 }
allPassed() const12589 bool Counts::allPassed() const {
12590 return failed == 0 && failedButOk == 0;
12591 }
allOk() const12592 bool Counts::allOk() const {
12593 return failed == 0;
12594 }
12595
operator -(Totals const & other) const12596 Totals Totals::operator - ( Totals const& other ) const {
12597 Totals diff;
12598 diff.assertions = assertions - other.assertions;
12599 diff.testCases = testCases - other.testCases;
12600 return diff;
12601 }
12602
operator +=(Totals const & other)12603 Totals& Totals::operator += ( Totals const& other ) {
12604 assertions += other.assertions;
12605 testCases += other.testCases;
12606 return *this;
12607 }
12608
delta(Totals const & prevTotals) const12609 Totals Totals::delta( Totals const& prevTotals ) const {
12610 Totals diff = *this - prevTotals;
12611 if( diff.assertions.failed > 0 )
12612 ++diff.testCases.failed;
12613 else if( diff.assertions.failedButOk > 0 )
12614 ++diff.testCases.failedButOk;
12615 else
12616 ++diff.testCases.passed;
12617 return diff;
12618 }
12619
12620 }
12621 // end catch_totals.cpp
12622 // start catch_uncaught_exceptions.cpp
12623
12624 #include <exception>
12625
12626 namespace Catch {
uncaught_exceptions()12627 bool uncaught_exceptions() {
12628 #if defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
12629 return std::uncaught_exceptions() > 0;
12630 #else
12631 return std::uncaught_exception();
12632 #endif
12633 }
12634 } // end namespace Catch
12635 // end catch_uncaught_exceptions.cpp
12636 // start catch_version.cpp
12637
12638 #include <ostream>
12639
12640 namespace Catch {
12641
Version(unsigned int _majorVersion,unsigned int _minorVersion,unsigned int _patchNumber,char const * const _branchName,unsigned int _buildNumber)12642 Version::Version
12643 ( unsigned int _majorVersion,
12644 unsigned int _minorVersion,
12645 unsigned int _patchNumber,
12646 char const * const _branchName,
12647 unsigned int _buildNumber )
12648 : majorVersion( _majorVersion ),
12649 minorVersion( _minorVersion ),
12650 patchNumber( _patchNumber ),
12651 branchName( _branchName ),
12652 buildNumber( _buildNumber )
12653 {}
12654
operator <<(std::ostream & os,Version const & version)12655 std::ostream& operator << ( std::ostream& os, Version const& version ) {
12656 os << version.majorVersion << '.'
12657 << version.minorVersion << '.'
12658 << version.patchNumber;
12659 // branchName is never null -> 0th char is \0 if it is empty
12660 if (version.branchName[0]) {
12661 os << '-' << version.branchName
12662 << '.' << version.buildNumber;
12663 }
12664 return os;
12665 }
12666
libraryVersion()12667 Version const& libraryVersion() {
12668 static Version version( 2, 7, 0, "", 0 );
12669 return version;
12670 }
12671
12672 }
12673 // end catch_version.cpp
12674 // start catch_wildcard_pattern.cpp
12675
12676 #include <sstream>
12677
12678 namespace Catch {
12679
WildcardPattern(std::string const & pattern,CaseSensitive::Choice caseSensitivity)12680 WildcardPattern::WildcardPattern( std::string const& pattern,
12681 CaseSensitive::Choice caseSensitivity )
12682 : m_caseSensitivity( caseSensitivity ),
12683 m_pattern( adjustCase( pattern ) )
12684 {
12685 if( startsWith( m_pattern, '*' ) ) {
12686 m_pattern = m_pattern.substr( 1 );
12687 m_wildcard = WildcardAtStart;
12688 }
12689 if( endsWith( m_pattern, '*' ) ) {
12690 m_pattern = m_pattern.substr( 0, m_pattern.size()-1 );
12691 m_wildcard = static_cast<WildcardPosition>( m_wildcard | WildcardAtEnd );
12692 }
12693 }
12694
matches(std::string const & str) const12695 bool WildcardPattern::matches( std::string const& str ) const {
12696 switch( m_wildcard ) {
12697 case NoWildcard:
12698 return m_pattern == adjustCase( str );
12699 case WildcardAtStart:
12700 return endsWith( adjustCase( str ), m_pattern );
12701 case WildcardAtEnd:
12702 return startsWith( adjustCase( str ), m_pattern );
12703 case WildcardAtBothEnds:
12704 return contains( adjustCase( str ), m_pattern );
12705 default:
12706 CATCH_INTERNAL_ERROR( "Unknown enum" );
12707 }
12708 }
12709
adjustCase(std::string const & str) const12710 std::string WildcardPattern::adjustCase( std::string const& str ) const {
12711 return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str;
12712 }
12713 }
12714 // end catch_wildcard_pattern.cpp
12715 // start catch_xmlwriter.cpp
12716
12717 #include <iomanip>
12718
12719 using uchar = unsigned char;
12720
12721 namespace Catch {
12722
12723 namespace {
12724
trailingBytes(unsigned char c)12725 size_t trailingBytes(unsigned char c) {
12726 if ((c & 0xE0) == 0xC0) {
12727 return 2;
12728 }
12729 if ((c & 0xF0) == 0xE0) {
12730 return 3;
12731 }
12732 if ((c & 0xF8) == 0xF0) {
12733 return 4;
12734 }
12735 CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered");
12736 }
12737
headerValue(unsigned char c)12738 uint32_t headerValue(unsigned char c) {
12739 if ((c & 0xE0) == 0xC0) {
12740 return c & 0x1F;
12741 }
12742 if ((c & 0xF0) == 0xE0) {
12743 return c & 0x0F;
12744 }
12745 if ((c & 0xF8) == 0xF0) {
12746 return c & 0x07;
12747 }
12748 CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered");
12749 }
12750
hexEscapeChar(std::ostream & os,unsigned char c)12751 void hexEscapeChar(std::ostream& os, unsigned char c) {
12752 std::ios_base::fmtflags f(os.flags());
12753 os << "\\x"
12754 << std::uppercase << std::hex << std::setfill('0') << std::setw(2)
12755 << static_cast<int>(c);
12756 os.flags(f);
12757 }
12758
12759 } // anonymous namespace
12760
XmlEncode(std::string const & str,ForWhat forWhat)12761 XmlEncode::XmlEncode( std::string const& str, ForWhat forWhat )
12762 : m_str( str ),
12763 m_forWhat( forWhat )
12764 {}
12765
encodeTo(std::ostream & os) const12766 void XmlEncode::encodeTo( std::ostream& os ) const {
12767 // Apostrophe escaping not necessary if we always use " to write attributes
12768 // (see: http://www.w3.org/TR/xml/#syntax)
12769
12770 for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) {
12771 uchar c = m_str[idx];
12772 switch (c) {
12773 case '<': os << "<"; break;
12774 case '&': os << "&"; break;
12775
12776 case '>':
12777 // See: http://www.w3.org/TR/xml/#syntax
12778 if (idx > 2 && m_str[idx - 1] == ']' && m_str[idx - 2] == ']')
12779 os << ">";
12780 else
12781 os << c;
12782 break;
12783
12784 case '\"':
12785 if (m_forWhat == ForAttributes)
12786 os << """;
12787 else
12788 os << c;
12789 break;
12790
12791 default:
12792 // Check for control characters and invalid utf-8
12793
12794 // Escape control characters in standard ascii
12795 // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0
12796 if (c < 0x09 || (c > 0x0D && c < 0x20) || c == 0x7F) {
12797 hexEscapeChar(os, c);
12798 break;
12799 }
12800
12801 // Plain ASCII: Write it to stream
12802 if (c < 0x7F) {
12803 os << c;
12804 break;
12805 }
12806
12807 // UTF-8 territory
12808 // Check if the encoding is valid and if it is not, hex escape bytes.
12809 // Important: We do not check the exact decoded values for validity, only the encoding format
12810 // First check that this bytes is a valid lead byte:
12811 // This means that it is not encoded as 1111 1XXX
12812 // Or as 10XX XXXX
12813 if (c < 0xC0 ||
12814 c >= 0xF8) {
12815 hexEscapeChar(os, c);
12816 break;
12817 }
12818
12819 auto encBytes = trailingBytes(c);
12820 // Are there enough bytes left to avoid accessing out-of-bounds memory?
12821 if (idx + encBytes - 1 >= m_str.size()) {
12822 hexEscapeChar(os, c);
12823 break;
12824 }
12825 // The header is valid, check data
12826 // The next encBytes bytes must together be a valid utf-8
12827 // This means: bitpattern 10XX XXXX and the extracted value is sane (ish)
12828 bool valid = true;
12829 uint32_t value = headerValue(c);
12830 for (std::size_t n = 1; n < encBytes; ++n) {
12831 uchar nc = m_str[idx + n];
12832 valid &= ((nc & 0xC0) == 0x80);
12833 value = (value << 6) | (nc & 0x3F);
12834 }
12835
12836 if (
12837 // Wrong bit pattern of following bytes
12838 (!valid) ||
12839 // Overlong encodings
12840 (value < 0x80) ||
12841 (0x80 <= value && value < 0x800 && encBytes > 2) ||
12842 (0x800 < value && value < 0x10000 && encBytes > 3) ||
12843 // Encoded value out of range
12844 (value >= 0x110000)
12845 ) {
12846 hexEscapeChar(os, c);
12847 break;
12848 }
12849
12850 // If we got here, this is in fact a valid(ish) utf-8 sequence
12851 for (std::size_t n = 0; n < encBytes; ++n) {
12852 os << m_str[idx + n];
12853 }
12854 idx += encBytes - 1;
12855 break;
12856 }
12857 }
12858 }
12859
operator <<(std::ostream & os,XmlEncode const & xmlEncode)12860 std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) {
12861 xmlEncode.encodeTo( os );
12862 return os;
12863 }
12864
ScopedElement(XmlWriter * writer)12865 XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer )
12866 : m_writer( writer )
12867 {}
12868
ScopedElement(ScopedElement && other)12869 XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) noexcept
12870 : m_writer( other.m_writer ){
12871 other.m_writer = nullptr;
12872 }
operator =(ScopedElement && other)12873 XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) noexcept {
12874 if ( m_writer ) {
12875 m_writer->endElement();
12876 }
12877 m_writer = other.m_writer;
12878 other.m_writer = nullptr;
12879 return *this;
12880 }
12881
~ScopedElement()12882 XmlWriter::ScopedElement::~ScopedElement() {
12883 if( m_writer )
12884 m_writer->endElement();
12885 }
12886
writeText(std::string const & text,bool indent)12887 XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, bool indent ) {
12888 m_writer->writeText( text, indent );
12889 return *this;
12890 }
12891
XmlWriter(std::ostream & os)12892 XmlWriter::XmlWriter( std::ostream& os ) : m_os( os )
12893 {
12894 writeDeclaration();
12895 }
12896
~XmlWriter()12897 XmlWriter::~XmlWriter() {
12898 while( !m_tags.empty() )
12899 endElement();
12900 }
12901
startElement(std::string const & name)12902 XmlWriter& XmlWriter::startElement( std::string const& name ) {
12903 ensureTagClosed();
12904 newlineIfNecessary();
12905 m_os << m_indent << '<' << name;
12906 m_tags.push_back( name );
12907 m_indent += " ";
12908 m_tagIsOpen = true;
12909 return *this;
12910 }
12911
scopedElement(std::string const & name)12912 XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name ) {
12913 ScopedElement scoped( this );
12914 startElement( name );
12915 return scoped;
12916 }
12917
endElement()12918 XmlWriter& XmlWriter::endElement() {
12919 newlineIfNecessary();
12920 m_indent = m_indent.substr( 0, m_indent.size()-2 );
12921 if( m_tagIsOpen ) {
12922 m_os << "/>";
12923 m_tagIsOpen = false;
12924 }
12925 else {
12926 m_os << m_indent << "</" << m_tags.back() << ">";
12927 }
12928 m_os << std::endl;
12929 m_tags.pop_back();
12930 return *this;
12931 }
12932
writeAttribute(std::string const & name,std::string const & attribute)12933 XmlWriter& XmlWriter::writeAttribute( std::string const& name, std::string const& attribute ) {
12934 if( !name.empty() && !attribute.empty() )
12935 m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"';
12936 return *this;
12937 }
12938
writeAttribute(std::string const & name,bool attribute)12939 XmlWriter& XmlWriter::writeAttribute( std::string const& name, bool attribute ) {
12940 m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"';
12941 return *this;
12942 }
12943
writeText(std::string const & text,bool indent)12944 XmlWriter& XmlWriter::writeText( std::string const& text, bool indent ) {
12945 if( !text.empty() ){
12946 bool tagWasOpen = m_tagIsOpen;
12947 ensureTagClosed();
12948 if( tagWasOpen && indent )
12949 m_os << m_indent;
12950 m_os << XmlEncode( text );
12951 m_needsNewline = true;
12952 }
12953 return *this;
12954 }
12955
writeComment(std::string const & text)12956 XmlWriter& XmlWriter::writeComment( std::string const& text ) {
12957 ensureTagClosed();
12958 m_os << m_indent << "<!--" << text << "-->";
12959 m_needsNewline = true;
12960 return *this;
12961 }
12962
writeStylesheetRef(std::string const & url)12963 void XmlWriter::writeStylesheetRef( std::string const& url ) {
12964 m_os << "<?xml-stylesheet type=\"text/xsl\" href=\"" << url << "\"?>\n";
12965 }
12966
writeBlankLine()12967 XmlWriter& XmlWriter::writeBlankLine() {
12968 ensureTagClosed();
12969 m_os << '\n';
12970 return *this;
12971 }
12972
ensureTagClosed()12973 void XmlWriter::ensureTagClosed() {
12974 if( m_tagIsOpen ) {
12975 m_os << ">" << std::endl;
12976 m_tagIsOpen = false;
12977 }
12978 }
12979
writeDeclaration()12980 void XmlWriter::writeDeclaration() {
12981 m_os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
12982 }
12983
newlineIfNecessary()12984 void XmlWriter::newlineIfNecessary() {
12985 if( m_needsNewline ) {
12986 m_os << std::endl;
12987 m_needsNewline = false;
12988 }
12989 }
12990 }
12991 // end catch_xmlwriter.cpp
12992 // start catch_reporter_bases.cpp
12993
12994 #include <cstring>
12995 #include <cfloat>
12996 #include <cstdio>
12997 #include <cassert>
12998 #include <memory>
12999
13000 namespace Catch {
prepareExpandedExpression(AssertionResult & result)13001 void prepareExpandedExpression(AssertionResult& result) {
13002 result.getExpandedExpression();
13003 }
13004
13005 // Because formatting using c++ streams is stateful, drop down to C is required
13006 // Alternatively we could use stringstream, but its performance is... not good.
getFormattedDuration(double duration)13007 std::string getFormattedDuration( double duration ) {
13008 // Max exponent + 1 is required to represent the whole part
13009 // + 1 for decimal point
13010 // + 3 for the 3 decimal places
13011 // + 1 for null terminator
13012 const std::size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1;
13013 char buffer[maxDoubleSize];
13014
13015 // Save previous errno, to prevent sprintf from overwriting it
13016 ErrnoGuard guard;
13017 #ifdef _MSC_VER
13018 sprintf_s(buffer, "%.3f", duration);
13019 #else
13020 std::sprintf(buffer, "%.3f", duration);
13021 #endif
13022 return std::string(buffer);
13023 }
13024
TestEventListenerBase(ReporterConfig const & _config)13025 TestEventListenerBase::TestEventListenerBase(ReporterConfig const & _config)
13026 :StreamingReporterBase(_config) {}
13027
getSupportedVerbosities()13028 std::set<Verbosity> TestEventListenerBase::getSupportedVerbosities() {
13029 return { Verbosity::Quiet, Verbosity::Normal, Verbosity::High };
13030 }
13031
assertionStarting(AssertionInfo const &)13032 void TestEventListenerBase::assertionStarting(AssertionInfo const &) {}
13033
assertionEnded(AssertionStats const &)13034 bool TestEventListenerBase::assertionEnded(AssertionStats const &) {
13035 return false;
13036 }
13037
13038 } // end namespace Catch
13039 // end catch_reporter_bases.cpp
13040 // start catch_reporter_compact.cpp
13041
13042 namespace {
13043
13044 #ifdef CATCH_PLATFORM_MAC
failedString()13045 const char* failedString() { return "FAILED"; }
passedString()13046 const char* passedString() { return "PASSED"; }
13047 #else
13048 const char* failedString() { return "failed"; }
13049 const char* passedString() { return "passed"; }
13050 #endif
13051
13052 // Colour::LightGrey
dimColour()13053 Catch::Colour::Code dimColour() { return Catch::Colour::FileName; }
13054
bothOrAll(std::size_t count)13055 std::string bothOrAll( std::size_t count ) {
13056 return count == 1 ? std::string() :
13057 count == 2 ? "both " : "all " ;
13058 }
13059
13060 } // anon namespace
13061
13062 namespace Catch {
13063 namespace {
13064 // Colour, message variants:
13065 // - white: No tests ran.
13066 // - red: Failed [both/all] N test cases, failed [both/all] M assertions.
13067 // - white: Passed [both/all] N test cases (no assertions).
13068 // - red: Failed N tests cases, failed M assertions.
13069 // - green: Passed [both/all] N tests cases with M assertions.
printTotals(std::ostream & out,const Totals & totals)13070 void printTotals(std::ostream& out, const Totals& totals) {
13071 if (totals.testCases.total() == 0) {
13072 out << "No tests ran.";
13073 } else if (totals.testCases.failed == totals.testCases.total()) {
13074 Colour colour(Colour::ResultError);
13075 const std::string qualify_assertions_failed =
13076 totals.assertions.failed == totals.assertions.total() ?
13077 bothOrAll(totals.assertions.failed) : std::string();
13078 out <<
13079 "Failed " << bothOrAll(totals.testCases.failed)
13080 << pluralise(totals.testCases.failed, "test case") << ", "
13081 "failed " << qualify_assertions_failed <<
13082 pluralise(totals.assertions.failed, "assertion") << '.';
13083 } else if (totals.assertions.total() == 0) {
13084 out <<
13085 "Passed " << bothOrAll(totals.testCases.total())
13086 << pluralise(totals.testCases.total(), "test case")
13087 << " (no assertions).";
13088 } else if (totals.assertions.failed) {
13089 Colour colour(Colour::ResultError);
13090 out <<
13091 "Failed " << pluralise(totals.testCases.failed, "test case") << ", "
13092 "failed " << pluralise(totals.assertions.failed, "assertion") << '.';
13093 } else {
13094 Colour colour(Colour::ResultSuccess);
13095 out <<
13096 "Passed " << bothOrAll(totals.testCases.passed)
13097 << pluralise(totals.testCases.passed, "test case") <<
13098 " with " << pluralise(totals.assertions.passed, "assertion") << '.';
13099 }
13100 }
13101
13102 // Implementation of CompactReporter formatting
13103 class AssertionPrinter {
13104 public:
13105 AssertionPrinter& operator= (AssertionPrinter const&) = delete;
13106 AssertionPrinter(AssertionPrinter const&) = delete;
AssertionPrinter(std::ostream & _stream,AssertionStats const & _stats,bool _printInfoMessages)13107 AssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages)
13108 : stream(_stream)
13109 , result(_stats.assertionResult)
13110 , messages(_stats.infoMessages)
13111 , itMessage(_stats.infoMessages.begin())
13112 , printInfoMessages(_printInfoMessages) {}
13113
print()13114 void print() {
13115 printSourceInfo();
13116
13117 itMessage = messages.begin();
13118
13119 switch (result.getResultType()) {
13120 case ResultWas::Ok:
13121 printResultType(Colour::ResultSuccess, passedString());
13122 printOriginalExpression();
13123 printReconstructedExpression();
13124 if (!result.hasExpression())
13125 printRemainingMessages(Colour::None);
13126 else
13127 printRemainingMessages();
13128 break;
13129 case ResultWas::ExpressionFailed:
13130 if (result.isOk())
13131 printResultType(Colour::ResultSuccess, failedString() + std::string(" - but was ok"));
13132 else
13133 printResultType(Colour::Error, failedString());
13134 printOriginalExpression();
13135 printReconstructedExpression();
13136 printRemainingMessages();
13137 break;
13138 case ResultWas::ThrewException:
13139 printResultType(Colour::Error, failedString());
13140 printIssue("unexpected exception with message:");
13141 printMessage();
13142 printExpressionWas();
13143 printRemainingMessages();
13144 break;
13145 case ResultWas::FatalErrorCondition:
13146 printResultType(Colour::Error, failedString());
13147 printIssue("fatal error condition with message:");
13148 printMessage();
13149 printExpressionWas();
13150 printRemainingMessages();
13151 break;
13152 case ResultWas::DidntThrowException:
13153 printResultType(Colour::Error, failedString());
13154 printIssue("expected exception, got none");
13155 printExpressionWas();
13156 printRemainingMessages();
13157 break;
13158 case ResultWas::Info:
13159 printResultType(Colour::None, "info");
13160 printMessage();
13161 printRemainingMessages();
13162 break;
13163 case ResultWas::Warning:
13164 printResultType(Colour::None, "warning");
13165 printMessage();
13166 printRemainingMessages();
13167 break;
13168 case ResultWas::ExplicitFailure:
13169 printResultType(Colour::Error, failedString());
13170 printIssue("explicitly");
13171 printRemainingMessages(Colour::None);
13172 break;
13173 // These cases are here to prevent compiler warnings
13174 case ResultWas::Unknown:
13175 case ResultWas::FailureBit:
13176 case ResultWas::Exception:
13177 printResultType(Colour::Error, "** internal error **");
13178 break;
13179 }
13180 }
13181
13182 private:
printSourceInfo() const13183 void printSourceInfo() const {
13184 Colour colourGuard(Colour::FileName);
13185 stream << result.getSourceInfo() << ':';
13186 }
13187
printResultType(Colour::Code colour,std::string const & passOrFail) const13188 void printResultType(Colour::Code colour, std::string const& passOrFail) const {
13189 if (!passOrFail.empty()) {
13190 {
13191 Colour colourGuard(colour);
13192 stream << ' ' << passOrFail;
13193 }
13194 stream << ':';
13195 }
13196 }
13197
printIssue(std::string const & issue) const13198 void printIssue(std::string const& issue) const {
13199 stream << ' ' << issue;
13200 }
13201
printExpressionWas()13202 void printExpressionWas() {
13203 if (result.hasExpression()) {
13204 stream << ';';
13205 {
13206 Colour colour(dimColour());
13207 stream << " expression was:";
13208 }
13209 printOriginalExpression();
13210 }
13211 }
13212
printOriginalExpression() const13213 void printOriginalExpression() const {
13214 if (result.hasExpression()) {
13215 stream << ' ' << result.getExpression();
13216 }
13217 }
13218
printReconstructedExpression() const13219 void printReconstructedExpression() const {
13220 if (result.hasExpandedExpression()) {
13221 {
13222 Colour colour(dimColour());
13223 stream << " for: ";
13224 }
13225 stream << result.getExpandedExpression();
13226 }
13227 }
13228
printMessage()13229 void printMessage() {
13230 if (itMessage != messages.end()) {
13231 stream << " '" << itMessage->message << '\'';
13232 ++itMessage;
13233 }
13234 }
13235
printRemainingMessages(Colour::Code colour=dimColour ())13236 void printRemainingMessages(Colour::Code colour = dimColour()) {
13237 if (itMessage == messages.end())
13238 return;
13239
13240 // using messages.end() directly yields (or auto) compilation error:
13241 std::vector<MessageInfo>::const_iterator itEnd = messages.end();
13242 const std::size_t N = static_cast<std::size_t>(std::distance(itMessage, itEnd));
13243
13244 {
13245 Colour colourGuard(colour);
13246 stream << " with " << pluralise(N, "message") << ':';
13247 }
13248
13249 for (; itMessage != itEnd; ) {
13250 // If this assertion is a warning ignore any INFO messages
13251 if (printInfoMessages || itMessage->type != ResultWas::Info) {
13252 stream << " '" << itMessage->message << '\'';
13253 if (++itMessage != itEnd) {
13254 Colour colourGuard(dimColour());
13255 stream << " and";
13256 }
13257 }
13258 }
13259 }
13260
13261 private:
13262 std::ostream& stream;
13263 AssertionResult const& result;
13264 std::vector<MessageInfo> messages;
13265 std::vector<MessageInfo>::const_iterator itMessage;
13266 bool printInfoMessages;
13267 };
13268
13269 } // anon namespace
13270
getDescription()13271 std::string CompactReporter::getDescription() {
13272 return "Reports test results on a single line, suitable for IDEs";
13273 }
13274
getPreferences() const13275 ReporterPreferences CompactReporter::getPreferences() const {
13276 return m_reporterPrefs;
13277 }
13278
noMatchingTestCases(std::string const & spec)13279 void CompactReporter::noMatchingTestCases( std::string const& spec ) {
13280 stream << "No test cases matched '" << spec << '\'' << std::endl;
13281 }
13282
assertionStarting(AssertionInfo const &)13283 void CompactReporter::assertionStarting( AssertionInfo const& ) {}
13284
assertionEnded(AssertionStats const & _assertionStats)13285 bool CompactReporter::assertionEnded( AssertionStats const& _assertionStats ) {
13286 AssertionResult const& result = _assertionStats.assertionResult;
13287
13288 bool printInfoMessages = true;
13289
13290 // Drop out if result was successful and we're not printing those
13291 if( !m_config->includeSuccessfulResults() && result.isOk() ) {
13292 if( result.getResultType() != ResultWas::Warning )
13293 return false;
13294 printInfoMessages = false;
13295 }
13296
13297 AssertionPrinter printer( stream, _assertionStats, printInfoMessages );
13298 printer.print();
13299
13300 stream << std::endl;
13301 return true;
13302 }
13303
sectionEnded(SectionStats const & _sectionStats)13304 void CompactReporter::sectionEnded(SectionStats const& _sectionStats) {
13305 if (m_config->showDurations() == ShowDurations::Always) {
13306 stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl;
13307 }
13308 }
13309
testRunEnded(TestRunStats const & _testRunStats)13310 void CompactReporter::testRunEnded( TestRunStats const& _testRunStats ) {
13311 printTotals( stream, _testRunStats.totals );
13312 stream << '\n' << std::endl;
13313 StreamingReporterBase::testRunEnded( _testRunStats );
13314 }
13315
~CompactReporter()13316 CompactReporter::~CompactReporter() {}
13317
13318 CATCH_REGISTER_REPORTER( "compact", CompactReporter )
13319
13320 } // end namespace Catch
13321 // end catch_reporter_compact.cpp
13322 // start catch_reporter_console.cpp
13323
13324 #include <cfloat>
13325 #include <cstdio>
13326
13327 #if defined(_MSC_VER)
13328 #pragma warning(push)
13329 #pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch
13330 // Note that 4062 (not all labels are handled
13331 // and default is missing) is enabled
13332 #endif
13333
13334 namespace Catch {
13335
13336 namespace {
13337
13338 // Formatter impl for ConsoleReporter
13339 class ConsoleAssertionPrinter {
13340 public:
13341 ConsoleAssertionPrinter& operator= (ConsoleAssertionPrinter const&) = delete;
13342 ConsoleAssertionPrinter(ConsoleAssertionPrinter const&) = delete;
ConsoleAssertionPrinter(std::ostream & _stream,AssertionStats const & _stats,bool _printInfoMessages)13343 ConsoleAssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages)
13344 : stream(_stream),
13345 stats(_stats),
13346 result(_stats.assertionResult),
13347 colour(Colour::None),
13348 message(result.getMessage()),
13349 messages(_stats.infoMessages),
13350 printInfoMessages(_printInfoMessages) {
13351 switch (result.getResultType()) {
13352 case ResultWas::Ok:
13353 colour = Colour::Success;
13354 passOrFail = "PASSED";
13355 //if( result.hasMessage() )
13356 if (_stats.infoMessages.size() == 1)
13357 messageLabel = "with message";
13358 if (_stats.infoMessages.size() > 1)
13359 messageLabel = "with messages";
13360 break;
13361 case ResultWas::ExpressionFailed:
13362 if (result.isOk()) {
13363 colour = Colour::Success;
13364 passOrFail = "FAILED - but was ok";
13365 } else {
13366 colour = Colour::Error;
13367 passOrFail = "FAILED";
13368 }
13369 if (_stats.infoMessages.size() == 1)
13370 messageLabel = "with message";
13371 if (_stats.infoMessages.size() > 1)
13372 messageLabel = "with messages";
13373 break;
13374 case ResultWas::ThrewException:
13375 colour = Colour::Error;
13376 passOrFail = "FAILED";
13377 messageLabel = "due to unexpected exception with ";
13378 if (_stats.infoMessages.size() == 1)
13379 messageLabel += "message";
13380 if (_stats.infoMessages.size() > 1)
13381 messageLabel += "messages";
13382 break;
13383 case ResultWas::FatalErrorCondition:
13384 colour = Colour::Error;
13385 passOrFail = "FAILED";
13386 messageLabel = "due to a fatal error condition";
13387 break;
13388 case ResultWas::DidntThrowException:
13389 colour = Colour::Error;
13390 passOrFail = "FAILED";
13391 messageLabel = "because no exception was thrown where one was expected";
13392 break;
13393 case ResultWas::Info:
13394 messageLabel = "info";
13395 break;
13396 case ResultWas::Warning:
13397 messageLabel = "warning";
13398 break;
13399 case ResultWas::ExplicitFailure:
13400 passOrFail = "FAILED";
13401 colour = Colour::Error;
13402 if (_stats.infoMessages.size() == 1)
13403 messageLabel = "explicitly with message";
13404 if (_stats.infoMessages.size() > 1)
13405 messageLabel = "explicitly with messages";
13406 break;
13407 // These cases are here to prevent compiler warnings
13408 case ResultWas::Unknown:
13409 case ResultWas::FailureBit:
13410 case ResultWas::Exception:
13411 passOrFail = "** internal error **";
13412 colour = Colour::Error;
13413 break;
13414 }
13415 }
13416
print() const13417 void print() const {
13418 printSourceInfo();
13419 if (stats.totals.assertions.total() > 0) {
13420 printResultType();
13421 printOriginalExpression();
13422 printReconstructedExpression();
13423 } else {
13424 stream << '\n';
13425 }
13426 printMessage();
13427 }
13428
13429 private:
printResultType() const13430 void printResultType() const {
13431 if (!passOrFail.empty()) {
13432 Colour colourGuard(colour);
13433 stream << passOrFail << ":\n";
13434 }
13435 }
printOriginalExpression() const13436 void printOriginalExpression() const {
13437 if (result.hasExpression()) {
13438 Colour colourGuard(Colour::OriginalExpression);
13439 stream << " ";
13440 stream << result.getExpressionInMacro();
13441 stream << '\n';
13442 }
13443 }
printReconstructedExpression() const13444 void printReconstructedExpression() const {
13445 if (result.hasExpandedExpression()) {
13446 stream << "with expansion:\n";
13447 Colour colourGuard(Colour::ReconstructedExpression);
13448 stream << Column(result.getExpandedExpression()).indent(2) << '\n';
13449 }
13450 }
printMessage() const13451 void printMessage() const {
13452 if (!messageLabel.empty())
13453 stream << messageLabel << ':' << '\n';
13454 for (auto const& msg : messages) {
13455 // If this assertion is a warning ignore any INFO messages
13456 if (printInfoMessages || msg.type != ResultWas::Info)
13457 stream << Column(msg.message).indent(2) << '\n';
13458 }
13459 }
printSourceInfo() const13460 void printSourceInfo() const {
13461 Colour colourGuard(Colour::FileName);
13462 stream << result.getSourceInfo() << ": ";
13463 }
13464
13465 std::ostream& stream;
13466 AssertionStats const& stats;
13467 AssertionResult const& result;
13468 Colour::Code colour;
13469 std::string passOrFail;
13470 std::string messageLabel;
13471 std::string message;
13472 std::vector<MessageInfo> messages;
13473 bool printInfoMessages;
13474 };
13475
makeRatio(std::size_t number,std::size_t total)13476 std::size_t makeRatio(std::size_t number, std::size_t total) {
13477 std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number / total : 0;
13478 return (ratio == 0 && number > 0) ? 1 : ratio;
13479 }
13480
findMax(std::size_t & i,std::size_t & j,std::size_t & k)13481 std::size_t& findMax(std::size_t& i, std::size_t& j, std::size_t& k) {
13482 if (i > j && i > k)
13483 return i;
13484 else if (j > k)
13485 return j;
13486 else
13487 return k;
13488 }
13489
13490 struct ColumnInfo {
13491 enum Justification { Left, Right };
13492 std::string name;
13493 int width;
13494 Justification justification;
13495 };
13496 struct ColumnBreak {};
13497 struct RowBreak {};
13498
13499 class Duration {
13500 enum class Unit {
13501 Auto,
13502 Nanoseconds,
13503 Microseconds,
13504 Milliseconds,
13505 Seconds,
13506 Minutes
13507 };
13508 static const uint64_t s_nanosecondsInAMicrosecond = 1000;
13509 static const uint64_t s_nanosecondsInAMillisecond = 1000 * s_nanosecondsInAMicrosecond;
13510 static const uint64_t s_nanosecondsInASecond = 1000 * s_nanosecondsInAMillisecond;
13511 static const uint64_t s_nanosecondsInAMinute = 60 * s_nanosecondsInASecond;
13512
13513 uint64_t m_inNanoseconds;
13514 Unit m_units;
13515
13516 public:
Duration(uint64_t inNanoseconds,Unit units=Unit::Auto)13517 explicit Duration(uint64_t inNanoseconds, Unit units = Unit::Auto)
13518 : m_inNanoseconds(inNanoseconds),
13519 m_units(units) {
13520 if (m_units == Unit::Auto) {
13521 if (m_inNanoseconds < s_nanosecondsInAMicrosecond)
13522 m_units = Unit::Nanoseconds;
13523 else if (m_inNanoseconds < s_nanosecondsInAMillisecond)
13524 m_units = Unit::Microseconds;
13525 else if (m_inNanoseconds < s_nanosecondsInASecond)
13526 m_units = Unit::Milliseconds;
13527 else if (m_inNanoseconds < s_nanosecondsInAMinute)
13528 m_units = Unit::Seconds;
13529 else
13530 m_units = Unit::Minutes;
13531 }
13532
13533 }
13534
value() const13535 auto value() const -> double {
13536 switch (m_units) {
13537 case Unit::Microseconds:
13538 return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMicrosecond);
13539 case Unit::Milliseconds:
13540 return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMillisecond);
13541 case Unit::Seconds:
13542 return m_inNanoseconds / static_cast<double>(s_nanosecondsInASecond);
13543 case Unit::Minutes:
13544 return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMinute);
13545 default:
13546 return static_cast<double>(m_inNanoseconds);
13547 }
13548 }
unitsAsString() const13549 auto unitsAsString() const -> std::string {
13550 switch (m_units) {
13551 case Unit::Nanoseconds:
13552 return "ns";
13553 case Unit::Microseconds:
13554 return "us";
13555 case Unit::Milliseconds:
13556 return "ms";
13557 case Unit::Seconds:
13558 return "s";
13559 case Unit::Minutes:
13560 return "m";
13561 default:
13562 return "** internal error **";
13563 }
13564
13565 }
operator <<(std::ostream & os,Duration const & duration)13566 friend auto operator << (std::ostream& os, Duration const& duration) -> std::ostream& {
13567 return os << duration.value() << " " << duration.unitsAsString();
13568 }
13569 };
13570 } // end anon namespace
13571
13572 class TablePrinter {
13573 std::ostream& m_os;
13574 std::vector<ColumnInfo> m_columnInfos;
13575 std::ostringstream m_oss;
13576 int m_currentColumn = -1;
13577 bool m_isOpen = false;
13578
13579 public:
TablePrinter(std::ostream & os,std::vector<ColumnInfo> columnInfos)13580 TablePrinter( std::ostream& os, std::vector<ColumnInfo> columnInfos )
13581 : m_os( os ),
13582 m_columnInfos( std::move( columnInfos ) ) {}
13583
columnInfos() const13584 auto columnInfos() const -> std::vector<ColumnInfo> const& {
13585 return m_columnInfos;
13586 }
13587
open()13588 void open() {
13589 if (!m_isOpen) {
13590 m_isOpen = true;
13591 *this << RowBreak();
13592 for (auto const& info : m_columnInfos)
13593 *this << info.name << ColumnBreak();
13594 *this << RowBreak();
13595 m_os << Catch::getLineOfChars<'-'>() << "\n";
13596 }
13597 }
close()13598 void close() {
13599 if (m_isOpen) {
13600 *this << RowBreak();
13601 m_os << std::endl;
13602 m_isOpen = false;
13603 }
13604 }
13605
13606 template<typename T>
operator <<(TablePrinter & tp,T const & value)13607 friend TablePrinter& operator << (TablePrinter& tp, T const& value) {
13608 tp.m_oss << value;
13609 return tp;
13610 }
13611
operator <<(TablePrinter & tp,ColumnBreak)13612 friend TablePrinter& operator << (TablePrinter& tp, ColumnBreak) {
13613 auto colStr = tp.m_oss.str();
13614 // This takes account of utf8 encodings
13615 auto strSize = Catch::StringRef(colStr).numberOfCharacters();
13616 tp.m_oss.str("");
13617 tp.open();
13618 if (tp.m_currentColumn == static_cast<int>(tp.m_columnInfos.size() - 1)) {
13619 tp.m_currentColumn = -1;
13620 tp.m_os << "\n";
13621 }
13622 tp.m_currentColumn++;
13623
13624 auto colInfo = tp.m_columnInfos[tp.m_currentColumn];
13625 auto padding = (strSize + 2 < static_cast<std::size_t>(colInfo.width))
13626 ? std::string(colInfo.width - (strSize + 2), ' ')
13627 : std::string();
13628 if (colInfo.justification == ColumnInfo::Left)
13629 tp.m_os << colStr << padding << " ";
13630 else
13631 tp.m_os << padding << colStr << " ";
13632 return tp;
13633 }
13634
operator <<(TablePrinter & tp,RowBreak)13635 friend TablePrinter& operator << (TablePrinter& tp, RowBreak) {
13636 if (tp.m_currentColumn > 0) {
13637 tp.m_os << "\n";
13638 tp.m_currentColumn = -1;
13639 }
13640 return tp;
13641 }
13642 };
13643
ConsoleReporter(ReporterConfig const & config)13644 ConsoleReporter::ConsoleReporter(ReporterConfig const& config)
13645 : StreamingReporterBase(config),
13646 m_tablePrinter(new TablePrinter(config.stream(),
13647 {
13648 { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 32, ColumnInfo::Left },
13649 { "iters", 8, ColumnInfo::Right },
13650 { "elapsed ns", 14, ColumnInfo::Right },
13651 { "average", 14, ColumnInfo::Right }
13652 })) {}
13653 ConsoleReporter::~ConsoleReporter() = default;
13654
getDescription()13655 std::string ConsoleReporter::getDescription() {
13656 return "Reports test results as plain lines of text";
13657 }
13658
noMatchingTestCases(std::string const & spec)13659 void ConsoleReporter::noMatchingTestCases(std::string const& spec) {
13660 stream << "No test cases matched '" << spec << '\'' << std::endl;
13661 }
13662
assertionStarting(AssertionInfo const &)13663 void ConsoleReporter::assertionStarting(AssertionInfo const&) {}
13664
assertionEnded(AssertionStats const & _assertionStats)13665 bool ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) {
13666 AssertionResult const& result = _assertionStats.assertionResult;
13667
13668 bool includeResults = m_config->includeSuccessfulResults() || !result.isOk();
13669
13670 // Drop out if result was successful but we're not printing them.
13671 if (!includeResults && result.getResultType() != ResultWas::Warning)
13672 return false;
13673
13674 lazyPrint();
13675
13676 ConsoleAssertionPrinter printer(stream, _assertionStats, includeResults);
13677 printer.print();
13678 stream << std::endl;
13679 return true;
13680 }
13681
sectionStarting(SectionInfo const & _sectionInfo)13682 void ConsoleReporter::sectionStarting(SectionInfo const& _sectionInfo) {
13683 m_headerPrinted = false;
13684 StreamingReporterBase::sectionStarting(_sectionInfo);
13685 }
sectionEnded(SectionStats const & _sectionStats)13686 void ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) {
13687 m_tablePrinter->close();
13688 if (_sectionStats.missingAssertions) {
13689 lazyPrint();
13690 Colour colour(Colour::ResultError);
13691 if (m_sectionStack.size() > 1)
13692 stream << "\nNo assertions in section";
13693 else
13694 stream << "\nNo assertions in test case";
13695 stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl;
13696 }
13697 if (m_config->showDurations() == ShowDurations::Always) {
13698 stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl;
13699 }
13700 if (m_headerPrinted) {
13701 m_headerPrinted = false;
13702 }
13703 StreamingReporterBase::sectionEnded(_sectionStats);
13704 }
13705
benchmarkStarting(BenchmarkInfo const & info)13706 void ConsoleReporter::benchmarkStarting(BenchmarkInfo const& info) {
13707 lazyPrintWithoutClosingBenchmarkTable();
13708
13709 auto nameCol = Column( info.name ).width( static_cast<std::size_t>( m_tablePrinter->columnInfos()[0].width - 2 ) );
13710
13711 bool firstLine = true;
13712 for (auto line : nameCol) {
13713 if (!firstLine)
13714 (*m_tablePrinter) << ColumnBreak() << ColumnBreak() << ColumnBreak();
13715 else
13716 firstLine = false;
13717
13718 (*m_tablePrinter) << line << ColumnBreak();
13719 }
13720 }
benchmarkEnded(BenchmarkStats const & stats)13721 void ConsoleReporter::benchmarkEnded(BenchmarkStats const& stats) {
13722 Duration average(stats.elapsedTimeInNanoseconds / stats.iterations);
13723 (*m_tablePrinter)
13724 << stats.iterations << ColumnBreak()
13725 << stats.elapsedTimeInNanoseconds << ColumnBreak()
13726 << average << ColumnBreak();
13727 }
13728
testCaseEnded(TestCaseStats const & _testCaseStats)13729 void ConsoleReporter::testCaseEnded(TestCaseStats const& _testCaseStats) {
13730 m_tablePrinter->close();
13731 StreamingReporterBase::testCaseEnded(_testCaseStats);
13732 m_headerPrinted = false;
13733 }
testGroupEnded(TestGroupStats const & _testGroupStats)13734 void ConsoleReporter::testGroupEnded(TestGroupStats const& _testGroupStats) {
13735 if (currentGroupInfo.used) {
13736 printSummaryDivider();
13737 stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n";
13738 printTotals(_testGroupStats.totals);
13739 stream << '\n' << std::endl;
13740 }
13741 StreamingReporterBase::testGroupEnded(_testGroupStats);
13742 }
testRunEnded(TestRunStats const & _testRunStats)13743 void ConsoleReporter::testRunEnded(TestRunStats const& _testRunStats) {
13744 printTotalsDivider(_testRunStats.totals);
13745 printTotals(_testRunStats.totals);
13746 stream << std::endl;
13747 StreamingReporterBase::testRunEnded(_testRunStats);
13748 }
13749
lazyPrint()13750 void ConsoleReporter::lazyPrint() {
13751
13752 m_tablePrinter->close();
13753 lazyPrintWithoutClosingBenchmarkTable();
13754 }
13755
lazyPrintWithoutClosingBenchmarkTable()13756 void ConsoleReporter::lazyPrintWithoutClosingBenchmarkTable() {
13757
13758 if (!currentTestRunInfo.used)
13759 lazyPrintRunInfo();
13760 if (!currentGroupInfo.used)
13761 lazyPrintGroupInfo();
13762
13763 if (!m_headerPrinted) {
13764 printTestCaseAndSectionHeader();
13765 m_headerPrinted = true;
13766 }
13767 }
lazyPrintRunInfo()13768 void ConsoleReporter::lazyPrintRunInfo() {
13769 stream << '\n' << getLineOfChars<'~'>() << '\n';
13770 Colour colour(Colour::SecondaryText);
13771 stream << currentTestRunInfo->name
13772 << " is a Catch v" << libraryVersion() << " host application.\n"
13773 << "Run with -? for options\n\n";
13774
13775 if (m_config->rngSeed() != 0)
13776 stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n";
13777
13778 currentTestRunInfo.used = true;
13779 }
lazyPrintGroupInfo()13780 void ConsoleReporter::lazyPrintGroupInfo() {
13781 if (!currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1) {
13782 printClosedHeader("Group: " + currentGroupInfo->name);
13783 currentGroupInfo.used = true;
13784 }
13785 }
printTestCaseAndSectionHeader()13786 void ConsoleReporter::printTestCaseAndSectionHeader() {
13787 assert(!m_sectionStack.empty());
13788 printOpenHeader(currentTestCaseInfo->name);
13789
13790 if (m_sectionStack.size() > 1) {
13791 Colour colourGuard(Colour::Headers);
13792
13793 auto
13794 it = m_sectionStack.begin() + 1, // Skip first section (test case)
13795 itEnd = m_sectionStack.end();
13796 for (; it != itEnd; ++it)
13797 printHeaderString(it->name, 2);
13798 }
13799
13800 SourceLineInfo lineInfo = m_sectionStack.back().lineInfo;
13801
13802 if (!lineInfo.empty()) {
13803 stream << getLineOfChars<'-'>() << '\n';
13804 Colour colourGuard(Colour::FileName);
13805 stream << lineInfo << '\n';
13806 }
13807 stream << getLineOfChars<'.'>() << '\n' << std::endl;
13808 }
13809
printClosedHeader(std::string const & _name)13810 void ConsoleReporter::printClosedHeader(std::string const& _name) {
13811 printOpenHeader(_name);
13812 stream << getLineOfChars<'.'>() << '\n';
13813 }
printOpenHeader(std::string const & _name)13814 void ConsoleReporter::printOpenHeader(std::string const& _name) {
13815 stream << getLineOfChars<'-'>() << '\n';
13816 {
13817 Colour colourGuard(Colour::Headers);
13818 printHeaderString(_name);
13819 }
13820 }
13821
13822 // if string has a : in first line will set indent to follow it on
13823 // subsequent lines
printHeaderString(std::string const & _string,std::size_t indent)13824 void ConsoleReporter::printHeaderString(std::string const& _string, std::size_t indent) {
13825 std::size_t i = _string.find(": ");
13826 if (i != std::string::npos)
13827 i += 2;
13828 else
13829 i = 0;
13830 stream << Column(_string).indent(indent + i).initialIndent(indent) << '\n';
13831 }
13832
13833 struct SummaryColumn {
13834
SummaryColumnCatch::SummaryColumn13835 SummaryColumn( std::string _label, Colour::Code _colour )
13836 : label( std::move( _label ) ),
13837 colour( _colour ) {}
addRowCatch::SummaryColumn13838 SummaryColumn addRow( std::size_t count ) {
13839 ReusableStringStream rss;
13840 rss << count;
13841 std::string row = rss.str();
13842 for (auto& oldRow : rows) {
13843 while (oldRow.size() < row.size())
13844 oldRow = ' ' + oldRow;
13845 while (oldRow.size() > row.size())
13846 row = ' ' + row;
13847 }
13848 rows.push_back(row);
13849 return *this;
13850 }
13851
13852 std::string label;
13853 Colour::Code colour;
13854 std::vector<std::string> rows;
13855
13856 };
13857
printTotals(Totals const & totals)13858 void ConsoleReporter::printTotals( Totals const& totals ) {
13859 if (totals.testCases.total() == 0) {
13860 stream << Colour(Colour::Warning) << "No tests ran\n";
13861 } else if (totals.assertions.total() > 0 && totals.testCases.allPassed()) {
13862 stream << Colour(Colour::ResultSuccess) << "All tests passed";
13863 stream << " ("
13864 << pluralise(totals.assertions.passed, "assertion") << " in "
13865 << pluralise(totals.testCases.passed, "test case") << ')'
13866 << '\n';
13867 } else {
13868
13869 std::vector<SummaryColumn> columns;
13870 columns.push_back(SummaryColumn("", Colour::None)
13871 .addRow(totals.testCases.total())
13872 .addRow(totals.assertions.total()));
13873 columns.push_back(SummaryColumn("passed", Colour::Success)
13874 .addRow(totals.testCases.passed)
13875 .addRow(totals.assertions.passed));
13876 columns.push_back(SummaryColumn("failed", Colour::ResultError)
13877 .addRow(totals.testCases.failed)
13878 .addRow(totals.assertions.failed));
13879 columns.push_back(SummaryColumn("failed as expected", Colour::ResultExpectedFailure)
13880 .addRow(totals.testCases.failedButOk)
13881 .addRow(totals.assertions.failedButOk));
13882
13883 printSummaryRow("test cases", columns, 0);
13884 printSummaryRow("assertions", columns, 1);
13885 }
13886 }
printSummaryRow(std::string const & label,std::vector<SummaryColumn> const & cols,std::size_t row)13887 void ConsoleReporter::printSummaryRow(std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row) {
13888 for (auto col : cols) {
13889 std::string value = col.rows[row];
13890 if (col.label.empty()) {
13891 stream << label << ": ";
13892 if (value != "0")
13893 stream << value;
13894 else
13895 stream << Colour(Colour::Warning) << "- none -";
13896 } else if (value != "0") {
13897 stream << Colour(Colour::LightGrey) << " | ";
13898 stream << Colour(col.colour)
13899 << value << ' ' << col.label;
13900 }
13901 }
13902 stream << '\n';
13903 }
13904
printTotalsDivider(Totals const & totals)13905 void ConsoleReporter::printTotalsDivider(Totals const& totals) {
13906 if (totals.testCases.total() > 0) {
13907 std::size_t failedRatio = makeRatio(totals.testCases.failed, totals.testCases.total());
13908 std::size_t failedButOkRatio = makeRatio(totals.testCases.failedButOk, totals.testCases.total());
13909 std::size_t passedRatio = makeRatio(totals.testCases.passed, totals.testCases.total());
13910 while (failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH - 1)
13911 findMax(failedRatio, failedButOkRatio, passedRatio)++;
13912 while (failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH - 1)
13913 findMax(failedRatio, failedButOkRatio, passedRatio)--;
13914
13915 stream << Colour(Colour::Error) << std::string(failedRatio, '=');
13916 stream << Colour(Colour::ResultExpectedFailure) << std::string(failedButOkRatio, '=');
13917 if (totals.testCases.allPassed())
13918 stream << Colour(Colour::ResultSuccess) << std::string(passedRatio, '=');
13919 else
13920 stream << Colour(Colour::Success) << std::string(passedRatio, '=');
13921 } else {
13922 stream << Colour(Colour::Warning) << std::string(CATCH_CONFIG_CONSOLE_WIDTH - 1, '=');
13923 }
13924 stream << '\n';
13925 }
printSummaryDivider()13926 void ConsoleReporter::printSummaryDivider() {
13927 stream << getLineOfChars<'-'>() << '\n';
13928 }
13929
13930 CATCH_REGISTER_REPORTER("console", ConsoleReporter)
13931
13932 } // end namespace Catch
13933
13934 #if defined(_MSC_VER)
13935 #pragma warning(pop)
13936 #endif
13937 // end catch_reporter_console.cpp
13938 // start catch_reporter_junit.cpp
13939
13940 #include <cassert>
13941 #include <sstream>
13942 #include <ctime>
13943 #include <algorithm>
13944
13945 namespace Catch {
13946
13947 namespace {
getCurrentTimestamp()13948 std::string getCurrentTimestamp() {
13949 // Beware, this is not reentrant because of backward compatibility issues
13950 // Also, UTC only, again because of backward compatibility (%z is C++11)
13951 time_t rawtime;
13952 std::time(&rawtime);
13953 auto const timeStampSize = sizeof("2017-01-16T17:06:45Z");
13954
13955 #ifdef _MSC_VER
13956 std::tm timeInfo = {};
13957 gmtime_s(&timeInfo, &rawtime);
13958 #else
13959 std::tm* timeInfo;
13960 timeInfo = std::gmtime(&rawtime);
13961 #endif
13962
13963 char timeStamp[timeStampSize];
13964 const char * const fmt = "%Y-%m-%dT%H:%M:%SZ";
13965
13966 #ifdef _MSC_VER
13967 std::strftime(timeStamp, timeStampSize, fmt, &timeInfo);
13968 #else
13969 std::strftime(timeStamp, timeStampSize, fmt, timeInfo);
13970 #endif
13971 return std::string(timeStamp);
13972 }
13973
fileNameTag(const std::vector<std::string> & tags)13974 std::string fileNameTag(const std::vector<std::string> &tags) {
13975 auto it = std::find_if(begin(tags),
13976 end(tags),
13977 [] (std::string const& tag) {return tag.front() == '#'; });
13978 if (it != tags.end())
13979 return it->substr(1);
13980 return std::string();
13981 }
13982 } // anonymous namespace
13983
JunitReporter(ReporterConfig const & _config)13984 JunitReporter::JunitReporter( ReporterConfig const& _config )
13985 : CumulativeReporterBase( _config ),
13986 xml( _config.stream() )
13987 {
13988 m_reporterPrefs.shouldRedirectStdOut = true;
13989 m_reporterPrefs.shouldReportAllAssertions = true;
13990 }
13991
~JunitReporter()13992 JunitReporter::~JunitReporter() {}
13993
getDescription()13994 std::string JunitReporter::getDescription() {
13995 return "Reports test results in an XML format that looks like Ant's junitreport target";
13996 }
13997
noMatchingTestCases(std::string const &)13998 void JunitReporter::noMatchingTestCases( std::string const& /*spec*/ ) {}
13999
testRunStarting(TestRunInfo const & runInfo)14000 void JunitReporter::testRunStarting( TestRunInfo const& runInfo ) {
14001 CumulativeReporterBase::testRunStarting( runInfo );
14002 xml.startElement( "testsuites" );
14003 if( m_config->rngSeed() != 0 ) {
14004 xml.startElement( "properties" );
14005 xml.scopedElement( "property" )
14006 .writeAttribute( "name", "random-seed" )
14007 .writeAttribute( "value", m_config->rngSeed() );
14008 xml.endElement();
14009 }
14010 }
14011
testGroupStarting(GroupInfo const & groupInfo)14012 void JunitReporter::testGroupStarting( GroupInfo const& groupInfo ) {
14013 suiteTimer.start();
14014 stdOutForSuite.clear();
14015 stdErrForSuite.clear();
14016 unexpectedExceptions = 0;
14017 CumulativeReporterBase::testGroupStarting( groupInfo );
14018 }
14019
testCaseStarting(TestCaseInfo const & testCaseInfo)14020 void JunitReporter::testCaseStarting( TestCaseInfo const& testCaseInfo ) {
14021 m_okToFail = testCaseInfo.okToFail();
14022 }
14023
assertionEnded(AssertionStats const & assertionStats)14024 bool JunitReporter::assertionEnded( AssertionStats const& assertionStats ) {
14025 if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail )
14026 unexpectedExceptions++;
14027 return CumulativeReporterBase::assertionEnded( assertionStats );
14028 }
14029
testCaseEnded(TestCaseStats const & testCaseStats)14030 void JunitReporter::testCaseEnded( TestCaseStats const& testCaseStats ) {
14031 stdOutForSuite += testCaseStats.stdOut;
14032 stdErrForSuite += testCaseStats.stdErr;
14033 CumulativeReporterBase::testCaseEnded( testCaseStats );
14034 }
14035
testGroupEnded(TestGroupStats const & testGroupStats)14036 void JunitReporter::testGroupEnded( TestGroupStats const& testGroupStats ) {
14037 double suiteTime = suiteTimer.getElapsedSeconds();
14038 CumulativeReporterBase::testGroupEnded( testGroupStats );
14039 writeGroup( *m_testGroups.back(), suiteTime );
14040 }
14041
testRunEndedCumulative()14042 void JunitReporter::testRunEndedCumulative() {
14043 xml.endElement();
14044 }
14045
writeGroup(TestGroupNode const & groupNode,double suiteTime)14046 void JunitReporter::writeGroup( TestGroupNode const& groupNode, double suiteTime ) {
14047 XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" );
14048 TestGroupStats const& stats = groupNode.value;
14049 xml.writeAttribute( "name", stats.groupInfo.name );
14050 xml.writeAttribute( "errors", unexpectedExceptions );
14051 xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions );
14052 xml.writeAttribute( "tests", stats.totals.assertions.total() );
14053 xml.writeAttribute( "hostname", "tbd" ); // !TBD
14054 if( m_config->showDurations() == ShowDurations::Never )
14055 xml.writeAttribute( "time", "" );
14056 else
14057 xml.writeAttribute( "time", suiteTime );
14058 xml.writeAttribute( "timestamp", getCurrentTimestamp() );
14059
14060 // Write test cases
14061 for( auto const& child : groupNode.children )
14062 writeTestCase( *child );
14063
14064 xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite ), false );
14065 xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite ), false );
14066 }
14067
writeTestCase(TestCaseNode const & testCaseNode)14068 void JunitReporter::writeTestCase( TestCaseNode const& testCaseNode ) {
14069 TestCaseStats const& stats = testCaseNode.value;
14070
14071 // All test cases have exactly one section - which represents the
14072 // test case itself. That section may have 0-n nested sections
14073 assert( testCaseNode.children.size() == 1 );
14074 SectionNode const& rootSection = *testCaseNode.children.front();
14075
14076 std::string className = stats.testInfo.className;
14077
14078 if( className.empty() ) {
14079 className = fileNameTag(stats.testInfo.tags);
14080 if ( className.empty() )
14081 className = "global";
14082 }
14083
14084 if ( !m_config->name().empty() )
14085 className = m_config->name() + "." + className;
14086
14087 writeSection( className, "", rootSection );
14088 }
14089
writeSection(std::string const & className,std::string const & rootName,SectionNode const & sectionNode)14090 void JunitReporter::writeSection( std::string const& className,
14091 std::string const& rootName,
14092 SectionNode const& sectionNode ) {
14093 std::string name = trim( sectionNode.stats.sectionInfo.name );
14094 if( !rootName.empty() )
14095 name = rootName + '/' + name;
14096
14097 if( !sectionNode.assertions.empty() ||
14098 !sectionNode.stdOut.empty() ||
14099 !sectionNode.stdErr.empty() ) {
14100 XmlWriter::ScopedElement e = xml.scopedElement( "testcase" );
14101 if( className.empty() ) {
14102 xml.writeAttribute( "classname", name );
14103 xml.writeAttribute( "name", "root" );
14104 }
14105 else {
14106 xml.writeAttribute( "classname", className );
14107 xml.writeAttribute( "name", name );
14108 }
14109 xml.writeAttribute( "time", ::Catch::Detail::stringify( sectionNode.stats.durationInSeconds ) );
14110
14111 writeAssertions( sectionNode );
14112
14113 if( !sectionNode.stdOut.empty() )
14114 xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false );
14115 if( !sectionNode.stdErr.empty() )
14116 xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false );
14117 }
14118 for( auto const& childNode : sectionNode.childSections )
14119 if( className.empty() )
14120 writeSection( name, "", *childNode );
14121 else
14122 writeSection( className, name, *childNode );
14123 }
14124
writeAssertions(SectionNode const & sectionNode)14125 void JunitReporter::writeAssertions( SectionNode const& sectionNode ) {
14126 for( auto const& assertion : sectionNode.assertions )
14127 writeAssertion( assertion );
14128 }
14129
writeAssertion(AssertionStats const & stats)14130 void JunitReporter::writeAssertion( AssertionStats const& stats ) {
14131 AssertionResult const& result = stats.assertionResult;
14132 if( !result.isOk() ) {
14133 std::string elementName;
14134 switch( result.getResultType() ) {
14135 case ResultWas::ThrewException:
14136 case ResultWas::FatalErrorCondition:
14137 elementName = "error";
14138 break;
14139 case ResultWas::ExplicitFailure:
14140 elementName = "failure";
14141 break;
14142 case ResultWas::ExpressionFailed:
14143 elementName = "failure";
14144 break;
14145 case ResultWas::DidntThrowException:
14146 elementName = "failure";
14147 break;
14148
14149 // We should never see these here:
14150 case ResultWas::Info:
14151 case ResultWas::Warning:
14152 case ResultWas::Ok:
14153 case ResultWas::Unknown:
14154 case ResultWas::FailureBit:
14155 case ResultWas::Exception:
14156 elementName = "internalError";
14157 break;
14158 }
14159
14160 XmlWriter::ScopedElement e = xml.scopedElement( elementName );
14161
14162 xml.writeAttribute( "message", result.getExpandedExpression() );
14163 xml.writeAttribute( "type", result.getTestMacroName() );
14164
14165 ReusableStringStream rss;
14166 if( !result.getMessage().empty() )
14167 rss << result.getMessage() << '\n';
14168 for( auto const& msg : stats.infoMessages )
14169 if( msg.type == ResultWas::Info )
14170 rss << msg.message << '\n';
14171
14172 rss << "at " << result.getSourceInfo();
14173 xml.writeText( rss.str(), false );
14174 }
14175 }
14176
14177 CATCH_REGISTER_REPORTER( "junit", JunitReporter )
14178
14179 } // end namespace Catch
14180 // end catch_reporter_junit.cpp
14181 // start catch_reporter_listening.cpp
14182
14183 #include <cassert>
14184
14185 namespace Catch {
14186
ListeningReporter()14187 ListeningReporter::ListeningReporter() {
14188 // We will assume that listeners will always want all assertions
14189 m_preferences.shouldReportAllAssertions = true;
14190 }
14191
addListener(IStreamingReporterPtr && listener)14192 void ListeningReporter::addListener( IStreamingReporterPtr&& listener ) {
14193 m_listeners.push_back( std::move( listener ) );
14194 }
14195
addReporter(IStreamingReporterPtr && reporter)14196 void ListeningReporter::addReporter(IStreamingReporterPtr&& reporter) {
14197 assert(!m_reporter && "Listening reporter can wrap only 1 real reporter");
14198 m_reporter = std::move( reporter );
14199 m_preferences.shouldRedirectStdOut = m_reporter->getPreferences().shouldRedirectStdOut;
14200 }
14201
getPreferences() const14202 ReporterPreferences ListeningReporter::getPreferences() const {
14203 return m_preferences;
14204 }
14205
getSupportedVerbosities()14206 std::set<Verbosity> ListeningReporter::getSupportedVerbosities() {
14207 return std::set<Verbosity>{ };
14208 }
14209
noMatchingTestCases(std::string const & spec)14210 void ListeningReporter::noMatchingTestCases( std::string const& spec ) {
14211 for ( auto const& listener : m_listeners ) {
14212 listener->noMatchingTestCases( spec );
14213 }
14214 m_reporter->noMatchingTestCases( spec );
14215 }
14216
benchmarkStarting(BenchmarkInfo const & benchmarkInfo)14217 void ListeningReporter::benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) {
14218 for ( auto const& listener : m_listeners ) {
14219 listener->benchmarkStarting( benchmarkInfo );
14220 }
14221 m_reporter->benchmarkStarting( benchmarkInfo );
14222 }
benchmarkEnded(BenchmarkStats const & benchmarkStats)14223 void ListeningReporter::benchmarkEnded( BenchmarkStats const& benchmarkStats ) {
14224 for ( auto const& listener : m_listeners ) {
14225 listener->benchmarkEnded( benchmarkStats );
14226 }
14227 m_reporter->benchmarkEnded( benchmarkStats );
14228 }
14229
testRunStarting(TestRunInfo const & testRunInfo)14230 void ListeningReporter::testRunStarting( TestRunInfo const& testRunInfo ) {
14231 for ( auto const& listener : m_listeners ) {
14232 listener->testRunStarting( testRunInfo );
14233 }
14234 m_reporter->testRunStarting( testRunInfo );
14235 }
14236
testGroupStarting(GroupInfo const & groupInfo)14237 void ListeningReporter::testGroupStarting( GroupInfo const& groupInfo ) {
14238 for ( auto const& listener : m_listeners ) {
14239 listener->testGroupStarting( groupInfo );
14240 }
14241 m_reporter->testGroupStarting( groupInfo );
14242 }
14243
testCaseStarting(TestCaseInfo const & testInfo)14244 void ListeningReporter::testCaseStarting( TestCaseInfo const& testInfo ) {
14245 for ( auto const& listener : m_listeners ) {
14246 listener->testCaseStarting( testInfo );
14247 }
14248 m_reporter->testCaseStarting( testInfo );
14249 }
14250
sectionStarting(SectionInfo const & sectionInfo)14251 void ListeningReporter::sectionStarting( SectionInfo const& sectionInfo ) {
14252 for ( auto const& listener : m_listeners ) {
14253 listener->sectionStarting( sectionInfo );
14254 }
14255 m_reporter->sectionStarting( sectionInfo );
14256 }
14257
assertionStarting(AssertionInfo const & assertionInfo)14258 void ListeningReporter::assertionStarting( AssertionInfo const& assertionInfo ) {
14259 for ( auto const& listener : m_listeners ) {
14260 listener->assertionStarting( assertionInfo );
14261 }
14262 m_reporter->assertionStarting( assertionInfo );
14263 }
14264
14265 // The return value indicates if the messages buffer should be cleared:
assertionEnded(AssertionStats const & assertionStats)14266 bool ListeningReporter::assertionEnded( AssertionStats const& assertionStats ) {
14267 for( auto const& listener : m_listeners ) {
14268 static_cast<void>( listener->assertionEnded( assertionStats ) );
14269 }
14270 return m_reporter->assertionEnded( assertionStats );
14271 }
14272
sectionEnded(SectionStats const & sectionStats)14273 void ListeningReporter::sectionEnded( SectionStats const& sectionStats ) {
14274 for ( auto const& listener : m_listeners ) {
14275 listener->sectionEnded( sectionStats );
14276 }
14277 m_reporter->sectionEnded( sectionStats );
14278 }
14279
testCaseEnded(TestCaseStats const & testCaseStats)14280 void ListeningReporter::testCaseEnded( TestCaseStats const& testCaseStats ) {
14281 for ( auto const& listener : m_listeners ) {
14282 listener->testCaseEnded( testCaseStats );
14283 }
14284 m_reporter->testCaseEnded( testCaseStats );
14285 }
14286
testGroupEnded(TestGroupStats const & testGroupStats)14287 void ListeningReporter::testGroupEnded( TestGroupStats const& testGroupStats ) {
14288 for ( auto const& listener : m_listeners ) {
14289 listener->testGroupEnded( testGroupStats );
14290 }
14291 m_reporter->testGroupEnded( testGroupStats );
14292 }
14293
testRunEnded(TestRunStats const & testRunStats)14294 void ListeningReporter::testRunEnded( TestRunStats const& testRunStats ) {
14295 for ( auto const& listener : m_listeners ) {
14296 listener->testRunEnded( testRunStats );
14297 }
14298 m_reporter->testRunEnded( testRunStats );
14299 }
14300
skipTest(TestCaseInfo const & testInfo)14301 void ListeningReporter::skipTest( TestCaseInfo const& testInfo ) {
14302 for ( auto const& listener : m_listeners ) {
14303 listener->skipTest( testInfo );
14304 }
14305 m_reporter->skipTest( testInfo );
14306 }
14307
isMulti() const14308 bool ListeningReporter::isMulti() const {
14309 return true;
14310 }
14311
14312 } // end namespace Catch
14313 // end catch_reporter_listening.cpp
14314 // start catch_reporter_xml.cpp
14315
14316 #if defined(_MSC_VER)
14317 #pragma warning(push)
14318 #pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch
14319 // Note that 4062 (not all labels are handled
14320 // and default is missing) is enabled
14321 #endif
14322
14323 namespace Catch {
XmlReporter(ReporterConfig const & _config)14324 XmlReporter::XmlReporter( ReporterConfig const& _config )
14325 : StreamingReporterBase( _config ),
14326 m_xml(_config.stream())
14327 {
14328 m_reporterPrefs.shouldRedirectStdOut = true;
14329 m_reporterPrefs.shouldReportAllAssertions = true;
14330 }
14331
14332 XmlReporter::~XmlReporter() = default;
14333
getDescription()14334 std::string XmlReporter::getDescription() {
14335 return "Reports test results as an XML document";
14336 }
14337
getStylesheetRef() const14338 std::string XmlReporter::getStylesheetRef() const {
14339 return std::string();
14340 }
14341
writeSourceInfo(SourceLineInfo const & sourceInfo)14342 void XmlReporter::writeSourceInfo( SourceLineInfo const& sourceInfo ) {
14343 m_xml
14344 .writeAttribute( "filename", sourceInfo.file )
14345 .writeAttribute( "line", sourceInfo.line );
14346 }
14347
noMatchingTestCases(std::string const & s)14348 void XmlReporter::noMatchingTestCases( std::string const& s ) {
14349 StreamingReporterBase::noMatchingTestCases( s );
14350 }
14351
testRunStarting(TestRunInfo const & testInfo)14352 void XmlReporter::testRunStarting( TestRunInfo const& testInfo ) {
14353 StreamingReporterBase::testRunStarting( testInfo );
14354 std::string stylesheetRef = getStylesheetRef();
14355 if( !stylesheetRef.empty() )
14356 m_xml.writeStylesheetRef( stylesheetRef );
14357 m_xml.startElement( "Catch" );
14358 if( !m_config->name().empty() )
14359 m_xml.writeAttribute( "name", m_config->name() );
14360 if( m_config->rngSeed() != 0 )
14361 m_xml.scopedElement( "Randomness" )
14362 .writeAttribute( "seed", m_config->rngSeed() );
14363 }
14364
testGroupStarting(GroupInfo const & groupInfo)14365 void XmlReporter::testGroupStarting( GroupInfo const& groupInfo ) {
14366 StreamingReporterBase::testGroupStarting( groupInfo );
14367 m_xml.startElement( "Group" )
14368 .writeAttribute( "name", groupInfo.name );
14369 }
14370
testCaseStarting(TestCaseInfo const & testInfo)14371 void XmlReporter::testCaseStarting( TestCaseInfo const& testInfo ) {
14372 StreamingReporterBase::testCaseStarting(testInfo);
14373 m_xml.startElement( "TestCase" )
14374 .writeAttribute( "name", trim( testInfo.name ) )
14375 .writeAttribute( "description", testInfo.description )
14376 .writeAttribute( "tags", testInfo.tagsAsString() );
14377
14378 writeSourceInfo( testInfo.lineInfo );
14379
14380 if ( m_config->showDurations() == ShowDurations::Always )
14381 m_testCaseTimer.start();
14382 m_xml.ensureTagClosed();
14383 }
14384
sectionStarting(SectionInfo const & sectionInfo)14385 void XmlReporter::sectionStarting( SectionInfo const& sectionInfo ) {
14386 StreamingReporterBase::sectionStarting( sectionInfo );
14387 if( m_sectionDepth++ > 0 ) {
14388 m_xml.startElement( "Section" )
14389 .writeAttribute( "name", trim( sectionInfo.name ) );
14390 writeSourceInfo( sectionInfo.lineInfo );
14391 m_xml.ensureTagClosed();
14392 }
14393 }
14394
assertionStarting(AssertionInfo const &)14395 void XmlReporter::assertionStarting( AssertionInfo const& ) { }
14396
assertionEnded(AssertionStats const & assertionStats)14397 bool XmlReporter::assertionEnded( AssertionStats const& assertionStats ) {
14398
14399 AssertionResult const& result = assertionStats.assertionResult;
14400
14401 bool includeResults = m_config->includeSuccessfulResults() || !result.isOk();
14402
14403 if( includeResults || result.getResultType() == ResultWas::Warning ) {
14404 // Print any info messages in <Info> tags.
14405 for( auto const& msg : assertionStats.infoMessages ) {
14406 if( msg.type == ResultWas::Info && includeResults ) {
14407 m_xml.scopedElement( "Info" )
14408 .writeText( msg.message );
14409 } else if ( msg.type == ResultWas::Warning ) {
14410 m_xml.scopedElement( "Warning" )
14411 .writeText( msg.message );
14412 }
14413 }
14414 }
14415
14416 // Drop out if result was successful but we're not printing them.
14417 if( !includeResults && result.getResultType() != ResultWas::Warning )
14418 return true;
14419
14420 // Print the expression if there is one.
14421 if( result.hasExpression() ) {
14422 m_xml.startElement( "Expression" )
14423 .writeAttribute( "success", result.succeeded() )
14424 .writeAttribute( "type", result.getTestMacroName() );
14425
14426 writeSourceInfo( result.getSourceInfo() );
14427
14428 m_xml.scopedElement( "Original" )
14429 .writeText( result.getExpression() );
14430 m_xml.scopedElement( "Expanded" )
14431 .writeText( result.getExpandedExpression() );
14432 }
14433
14434 // And... Print a result applicable to each result type.
14435 switch( result.getResultType() ) {
14436 case ResultWas::ThrewException:
14437 m_xml.startElement( "Exception" );
14438 writeSourceInfo( result.getSourceInfo() );
14439 m_xml.writeText( result.getMessage() );
14440 m_xml.endElement();
14441 break;
14442 case ResultWas::FatalErrorCondition:
14443 m_xml.startElement( "FatalErrorCondition" );
14444 writeSourceInfo( result.getSourceInfo() );
14445 m_xml.writeText( result.getMessage() );
14446 m_xml.endElement();
14447 break;
14448 case ResultWas::Info:
14449 m_xml.scopedElement( "Info" )
14450 .writeText( result.getMessage() );
14451 break;
14452 case ResultWas::Warning:
14453 // Warning will already have been written
14454 break;
14455 case ResultWas::ExplicitFailure:
14456 m_xml.startElement( "Failure" );
14457 writeSourceInfo( result.getSourceInfo() );
14458 m_xml.writeText( result.getMessage() );
14459 m_xml.endElement();
14460 break;
14461 default:
14462 break;
14463 }
14464
14465 if( result.hasExpression() )
14466 m_xml.endElement();
14467
14468 return true;
14469 }
14470
sectionEnded(SectionStats const & sectionStats)14471 void XmlReporter::sectionEnded( SectionStats const& sectionStats ) {
14472 StreamingReporterBase::sectionEnded( sectionStats );
14473 if( --m_sectionDepth > 0 ) {
14474 XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" );
14475 e.writeAttribute( "successes", sectionStats.assertions.passed );
14476 e.writeAttribute( "failures", sectionStats.assertions.failed );
14477 e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk );
14478
14479 if ( m_config->showDurations() == ShowDurations::Always )
14480 e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds );
14481
14482 m_xml.endElement();
14483 }
14484 }
14485
testCaseEnded(TestCaseStats const & testCaseStats)14486 void XmlReporter::testCaseEnded( TestCaseStats const& testCaseStats ) {
14487 StreamingReporterBase::testCaseEnded( testCaseStats );
14488 XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" );
14489 e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() );
14490
14491 if ( m_config->showDurations() == ShowDurations::Always )
14492 e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() );
14493
14494 if( !testCaseStats.stdOut.empty() )
14495 m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), false );
14496 if( !testCaseStats.stdErr.empty() )
14497 m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), false );
14498
14499 m_xml.endElement();
14500 }
14501
testGroupEnded(TestGroupStats const & testGroupStats)14502 void XmlReporter::testGroupEnded( TestGroupStats const& testGroupStats ) {
14503 StreamingReporterBase::testGroupEnded( testGroupStats );
14504 // TODO: Check testGroupStats.aborting and act accordingly.
14505 m_xml.scopedElement( "OverallResults" )
14506 .writeAttribute( "successes", testGroupStats.totals.assertions.passed )
14507 .writeAttribute( "failures", testGroupStats.totals.assertions.failed )
14508 .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk );
14509 m_xml.endElement();
14510 }
14511
testRunEnded(TestRunStats const & testRunStats)14512 void XmlReporter::testRunEnded( TestRunStats const& testRunStats ) {
14513 StreamingReporterBase::testRunEnded( testRunStats );
14514 m_xml.scopedElement( "OverallResults" )
14515 .writeAttribute( "successes", testRunStats.totals.assertions.passed )
14516 .writeAttribute( "failures", testRunStats.totals.assertions.failed )
14517 .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk );
14518 m_xml.endElement();
14519 }
14520
14521 CATCH_REGISTER_REPORTER( "xml", XmlReporter )
14522
14523 } // end namespace Catch
14524
14525 #if defined(_MSC_VER)
14526 #pragma warning(pop)
14527 #endif
14528 // end catch_reporter_xml.cpp
14529
14530 namespace Catch {
14531 LeakDetector leakDetector;
14532 }
14533
14534 #ifdef __clang__
14535 #pragma clang diagnostic pop
14536 #endif
14537
14538 // end catch_impl.hpp
14539 #endif
14540
14541 #ifdef CATCH_CONFIG_MAIN
14542 // start catch_default_main.hpp
14543
14544 #ifndef __OBJC__
14545
14546 #if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN)
14547 // Standard C/C++ Win32 Unicode wmain entry point
wmain(int argc,wchar_t * argv[],wchar_t * [])14548 extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) {
14549 #else
14550 // Standard C/C++ main entry point
14551 int main (int argc, char * argv[]) {
14552 #endif
14553
14554 return Catch::Session().run( argc, argv );
14555 }
14556
14557 #else // __OBJC__
14558
14559 // Objective-C entry point
14560 int main (int argc, char * const argv[]) {
14561 #if !CATCH_ARC_ENABLED
14562 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
14563 #endif
14564
14565 Catch::registerTestMethods();
14566 int result = Catch::Session().run( argc, (char**)argv );
14567
14568 #if !CATCH_ARC_ENABLED
14569 [pool drain];
14570 #endif
14571
14572 return result;
14573 }
14574
14575 #endif // __OBJC__
14576
14577 // end catch_default_main.hpp
14578 #endif
14579
14580 #if !defined(CATCH_CONFIG_IMPL_ONLY)
14581
14582 #ifdef CLARA_CONFIG_MAIN_NOT_DEFINED
14583 # undef CLARA_CONFIG_MAIN
14584 #endif
14585
14586 #if !defined(CATCH_CONFIG_DISABLE)
14587 //////
14588 // If this config identifier is defined then all CATCH macros are prefixed with CATCH_
14589 #ifdef CATCH_CONFIG_PREFIX_ALL
14590
14591 #define CATCH_REQUIRE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ )
14592 #define CATCH_REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
14593
14594 #define CATCH_REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ )
14595 #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr )
14596 #define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr )
14597 #if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
14598 #define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr )
14599 #endif// CATCH_CONFIG_DISABLE_MATCHERS
14600 #define CATCH_REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ )
14601
14602 #define CATCH_CHECK( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
14603 #define CATCH_CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
14604 #define CATCH_CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CATCH_CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
14605 #define CATCH_CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
14606 #define CATCH_CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
14607
14608 #define CATCH_CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
14609 #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr )
14610 #define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
14611 #if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
14612 #define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
14613 #endif // CATCH_CONFIG_DISABLE_MATCHERS
14614 #define CATCH_CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
14615
14616 #if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
14617 #define CATCH_CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg )
14618
14619 #define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )
14620 #endif // CATCH_CONFIG_DISABLE_MATCHERS
14621
14622 #define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg )
14623 #define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
14624 #define CATCH_CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CATCH_CAPTURE",__VA_ARGS__ )
14625
14626 #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
14627 #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
14628 #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
14629 #define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
14630 #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
14631 #define CATCH_DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ )
14632 #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )
14633 #define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
14634 #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
14635
14636 #define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE()
14637
14638 #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
14639 #define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
14640 #define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
14641 #define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ )
14642 #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ )
14643 #else
14644 #define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) )
14645 #define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
14646 #define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) )
14647 #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
14648 #endif
14649
14650 #if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE)
14651 #define CATCH_STATIC_REQUIRE( ... ) static_assert( __VA_ARGS__ , #__VA_ARGS__ ); CATCH_SUCCEED( #__VA_ARGS__ )
14652 #define CATCH_STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); CATCH_SUCCEED( #__VA_ARGS__ )
14653 #else
14654 #define CATCH_STATIC_REQUIRE( ... ) CATCH_REQUIRE( __VA_ARGS__ )
14655 #define CATCH_STATIC_REQUIRE_FALSE( ... ) CATCH_REQUIRE_FALSE( __VA_ARGS__ )
14656 #endif
14657
14658 // "BDD-style" convenience wrappers
14659 #define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ )
14660 #define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
14661 #define CATCH_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc )
14662 #define CATCH_AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc )
14663 #define CATCH_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc )
14664 #define CATCH_AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc )
14665 #define CATCH_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc )
14666 #define CATCH_AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc )
14667
14668 // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required
14669 #else
14670
14671 #define REQUIRE( ... ) INTERNAL_CATCH_TEST( "REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ )
14672 #define REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
14673
14674 #define REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ )
14675 #define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr )
14676 #define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr )
14677 #if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
14678 #define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr )
14679 #endif // CATCH_CONFIG_DISABLE_MATCHERS
14680 #define REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ )
14681
14682 #define CHECK( ... ) INTERNAL_CATCH_TEST( "CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
14683 #define CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
14684 #define CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
14685 #define CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
14686 #define CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
14687
14688 #define CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
14689 #define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr )
14690 #define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
14691 #if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
14692 #define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
14693 #endif // CATCH_CONFIG_DISABLE_MATCHERS
14694 #define CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
14695
14696 #if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
14697 #define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg )
14698
14699 #define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )
14700 #endif // CATCH_CONFIG_DISABLE_MATCHERS
14701
14702 #define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg )
14703 #define UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "UNSCOPED_INFO", msg )
14704 #define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
14705 #define CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CAPTURE",__VA_ARGS__ )
14706
14707 #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
14708 #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
14709 #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
14710 #define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
14711 #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
14712 #define DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ )
14713 #define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )
14714 #define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
14715 #define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
14716 #define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE()
14717
14718 #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
14719 #define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
14720 #define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
14721 #define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ )
14722 #define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ )
14723 #else
14724 #define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) )
14725 #define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
14726 #define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) )
14727 #define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
14728 #endif
14729
14730 #if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE)
14731 #define STATIC_REQUIRE( ... ) static_assert( __VA_ARGS__, #__VA_ARGS__ ); SUCCEED( #__VA_ARGS__ )
14732 #define STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); SUCCEED( "!(" #__VA_ARGS__ ")" )
14733 #else
14734 #define STATIC_REQUIRE( ... ) REQUIRE( __VA_ARGS__ )
14735 #define STATIC_REQUIRE_FALSE( ... ) REQUIRE_FALSE( __VA_ARGS__ )
14736 #endif
14737
14738 #endif
14739
14740 #define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature )
14741
14742 // "BDD-style" convenience wrappers
14743 #define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ )
14744 #define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
14745
14746 #define GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc )
14747 #define AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc )
14748 #define WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc )
14749 #define AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc )
14750 #define THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc )
14751 #define AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc )
14752
14753 using Catch::Detail::Approx;
14754
14755 #else // CATCH_CONFIG_DISABLE
14756
14757 //////
14758 // If this config identifier is defined then all CATCH macros are prefixed with CATCH_
14759 #ifdef CATCH_CONFIG_PREFIX_ALL
14760
14761 #define CATCH_REQUIRE( ... ) (void)(0)
14762 #define CATCH_REQUIRE_FALSE( ... ) (void)(0)
14763
14764 #define CATCH_REQUIRE_THROWS( ... ) (void)(0)
14765 #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0)
14766 #define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) (void)(0)
14767 #if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
14768 #define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0)
14769 #endif// CATCH_CONFIG_DISABLE_MATCHERS
14770 #define CATCH_REQUIRE_NOTHROW( ... ) (void)(0)
14771
14772 #define CATCH_CHECK( ... ) (void)(0)
14773 #define CATCH_CHECK_FALSE( ... ) (void)(0)
14774 #define CATCH_CHECKED_IF( ... ) if (__VA_ARGS__)
14775 #define CATCH_CHECKED_ELSE( ... ) if (!(__VA_ARGS__))
14776 #define CATCH_CHECK_NOFAIL( ... ) (void)(0)
14777
14778 #define CATCH_CHECK_THROWS( ... ) (void)(0)
14779 #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) (void)(0)
14780 #define CATCH_CHECK_THROWS_WITH( expr, matcher ) (void)(0)
14781 #if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
14782 #define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0)
14783 #endif // CATCH_CONFIG_DISABLE_MATCHERS
14784 #define CATCH_CHECK_NOTHROW( ... ) (void)(0)
14785
14786 #if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
14787 #define CATCH_CHECK_THAT( arg, matcher ) (void)(0)
14788
14789 #define CATCH_REQUIRE_THAT( arg, matcher ) (void)(0)
14790 #endif // CATCH_CONFIG_DISABLE_MATCHERS
14791
14792 #define CATCH_INFO( msg ) (void)(0)
14793 #define CATCH_WARN( msg ) (void)(0)
14794 #define CATCH_CAPTURE( msg ) (void)(0)
14795
14796 #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
14797 #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
14798 #define CATCH_METHOD_AS_TEST_CASE( method, ... )
14799 #define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0)
14800 #define CATCH_SECTION( ... )
14801 #define CATCH_DYNAMIC_SECTION( ... )
14802 #define CATCH_FAIL( ... ) (void)(0)
14803 #define CATCH_FAIL_CHECK( ... ) (void)(0)
14804 #define CATCH_SUCCEED( ... ) (void)(0)
14805
14806 #define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
14807
14808 #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
14809 #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____ ) )
14810 #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 )
14811 #define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
14812 #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
14813 #else
14814 #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____ ) ) )
14815 #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 ) )
14816 #define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
14817 #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
14818 #endif
14819
14820 // "BDD-style" convenience wrappers
14821 #define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
14822 #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 )
14823 #define CATCH_GIVEN( desc )
14824 #define CATCH_AND_GIVEN( desc )
14825 #define CATCH_WHEN( desc )
14826 #define CATCH_AND_WHEN( desc )
14827 #define CATCH_THEN( desc )
14828 #define CATCH_AND_THEN( desc )
14829
14830 #define CATCH_STATIC_REQUIRE( ... ) (void)(0)
14831 #define CATCH_STATIC_REQUIRE_FALSE( ... ) (void)(0)
14832
14833 // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required
14834 #else
14835
14836 #define REQUIRE( ... ) (void)(0)
14837 #define REQUIRE_FALSE( ... ) (void)(0)
14838
14839 #define REQUIRE_THROWS( ... ) (void)(0)
14840 #define REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0)
14841 #define REQUIRE_THROWS_WITH( expr, matcher ) (void)(0)
14842 #if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
14843 #define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0)
14844 #endif // CATCH_CONFIG_DISABLE_MATCHERS
14845 #define REQUIRE_NOTHROW( ... ) (void)(0)
14846
14847 #define CHECK( ... ) (void)(0)
14848 #define CHECK_FALSE( ... ) (void)(0)
14849 #define CHECKED_IF( ... ) if (__VA_ARGS__)
14850 #define CHECKED_ELSE( ... ) if (!(__VA_ARGS__))
14851 #define CHECK_NOFAIL( ... ) (void)(0)
14852
14853 #define CHECK_THROWS( ... ) (void)(0)
14854 #define CHECK_THROWS_AS( expr, exceptionType ) (void)(0)
14855 #define CHECK_THROWS_WITH( expr, matcher ) (void)(0)
14856 #if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
14857 #define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0)
14858 #endif // CATCH_CONFIG_DISABLE_MATCHERS
14859 #define CHECK_NOTHROW( ... ) (void)(0)
14860
14861 #if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
14862 #define CHECK_THAT( arg, matcher ) (void)(0)
14863
14864 #define REQUIRE_THAT( arg, matcher ) (void)(0)
14865 #endif // CATCH_CONFIG_DISABLE_MATCHERS
14866
14867 #define INFO( msg ) (void)(0)
14868 #define WARN( msg ) (void)(0)
14869 #define CAPTURE( msg ) (void)(0)
14870
14871 #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
14872 #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
14873 #define METHOD_AS_TEST_CASE( method, ... )
14874 #define REGISTER_TEST_CASE( Function, ... ) (void)(0)
14875 #define SECTION( ... )
14876 #define DYNAMIC_SECTION( ... )
14877 #define FAIL( ... ) (void)(0)
14878 #define FAIL_CHECK( ... ) (void)(0)
14879 #define SUCCEED( ... ) (void)(0)
14880 #define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
14881
14882 #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
14883 #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____ ) )
14884 #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 )
14885 #define TEMPLATE_PRODUCT_TEST_CASE( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )
14886 #define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
14887 #else
14888 #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____ ) ) )
14889 #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 ) )
14890 #define TEMPLATE_PRODUCT_TEST_CASE( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )
14891 #define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
14892 #endif
14893
14894 #define STATIC_REQUIRE( ... ) (void)(0)
14895 #define STATIC_REQUIRE_FALSE( ... ) (void)(0)
14896
14897 #endif
14898
14899 #define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )
14900
14901 // "BDD-style" convenience wrappers
14902 #define SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) )
14903 #define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className )
14904
14905 #define GIVEN( desc )
14906 #define AND_GIVEN( desc )
14907 #define WHEN( desc )
14908 #define AND_WHEN( desc )
14909 #define THEN( desc )
14910 #define AND_THEN( desc )
14911
14912 using Catch::Detail::Approx;
14913
14914 #endif
14915
14916 #endif // ! CATCH_CONFIG_IMPL_ONLY
14917
14918 // start catch_reenable_warnings.h
14919
14920
14921 #ifdef __clang__
14922 # ifdef __ICC // icpc defines the __clang__ macro
14923 # pragma warning(pop)
14924 # else
14925 # pragma clang diagnostic pop
14926 # endif
14927 #elif defined __GNUC__
14928 # pragma GCC diagnostic pop
14929 #endif
14930
14931 // end catch_reenable_warnings.h
14932 // end catch.hpp
14933 #endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
14934
14935