1 | /* |
2 | * Catch v2.4.0 |
3 | * Generated: 2018-09-04 11:55:01.682061 |
4 | * ---------------------------------------------------------- |
5 | * This file has been merged from multiple headers. Please don't edit it directly |
6 | * Copyright (c) 2018 Two Blue Cubes Ltd. All rights reserved. |
7 | * |
8 | * Distributed under the Boost Software License, Version 1.0. (See accompanying |
9 | * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
10 | */ |
11 | #ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED |
12 | #define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED |
13 | // start catch.hpp |
14 | |
15 | |
16 | #define CATCH_VERSION_MAJOR 2 |
17 | #define CATCH_VERSION_MINOR 4 |
18 | #define CATCH_VERSION_PATCH 0 |
19 | |
20 | #ifdef __clang__ |
21 | # pragma clang system_header |
22 | #elif defined __GNUC__ |
23 | # pragma GCC system_header |
24 | #endif |
25 | |
26 | // start catch_suppress_warnings.h |
27 | |
28 | #ifdef __clang__ |
29 | # ifdef __ICC // icpc defines the __clang__ macro |
30 | # pragma warning(push) |
31 | # pragma warning(disable: 161 1682) |
32 | # else // __ICC |
33 | # pragma clang diagnostic push |
34 | # pragma clang diagnostic ignored "-Wpadded" |
35 | # pragma clang diagnostic ignored "-Wswitch-enum" |
36 | # pragma clang diagnostic ignored "-Wcovered-switch-default" |
37 | # endif |
38 | #elif defined __GNUC__ |
39 | // GCC likes to warn on REQUIREs, and we cannot suppress them |
40 | // locally because g++'s support for _Pragma is lacking in older, |
41 | // still supported, versions |
42 | # pragma GCC diagnostic ignored "-Wparentheses" |
43 | # pragma GCC diagnostic push |
44 | # pragma GCC diagnostic ignored "-Wunused-variable" |
45 | # pragma GCC diagnostic ignored "-Wpadded" |
46 | #endif |
47 | // end catch_suppress_warnings.h |
48 | #if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) |
49 | # define CATCH_IMPL |
50 | # define CATCH_CONFIG_ALL_PARTS |
51 | #endif |
52 | |
53 | // In the impl file, we want to have access to all parts of the headers |
54 | // Can also be used to sanely support PCHs |
55 | #if defined(CATCH_CONFIG_ALL_PARTS) |
56 | # define CATCH_CONFIG_EXTERNAL_INTERFACES |
57 | # if defined(CATCH_CONFIG_DISABLE_MATCHERS) |
58 | # undef CATCH_CONFIG_DISABLE_MATCHERS |
59 | # endif |
60 | # if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) |
61 | # define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER |
62 | # endif |
63 | #endif |
64 | |
65 | #if !defined(CATCH_CONFIG_IMPL_ONLY) |
66 | // start catch_platform.h |
67 | |
68 | #ifdef __APPLE__ |
69 | # include <TargetConditionals.h> |
70 | # if TARGET_OS_OSX == 1 |
71 | # define CATCH_PLATFORM_MAC |
72 | # elif TARGET_OS_IPHONE == 1 |
73 | # define CATCH_PLATFORM_IPHONE |
74 | # endif |
75 | |
76 | #elif defined(linux) || defined(__linux) || defined(__linux__) |
77 | # define CATCH_PLATFORM_LINUX |
78 | |
79 | #elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__) |
80 | # define CATCH_PLATFORM_WINDOWS |
81 | #endif |
82 | |
83 | // end catch_platform.h |
84 | |
85 | #ifdef CATCH_IMPL |
86 | # ifndef CLARA_CONFIG_MAIN |
87 | # define CLARA_CONFIG_MAIN_NOT_DEFINED |
88 | # define CLARA_CONFIG_MAIN |
89 | # endif |
90 | #endif |
91 | |
92 | // start catch_user_interfaces.h |
93 | |
94 | namespace Catch { |
95 | unsigned int rngSeed(); |
96 | } |
97 | |
98 | // end catch_user_interfaces.h |
99 | // start catch_tag_alias_autoregistrar.h |
100 | |
101 | // start catch_common.h |
102 | |
103 | // start catch_compiler_capabilities.h |
104 | |
105 | // Detect a number of compiler features - by compiler |
106 | // The following features are defined: |
107 | // |
108 | // CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported? |
109 | // CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? |
110 | // CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? |
111 | // CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled? |
112 | // **************** |
113 | // Note to maintainers: if new toggles are added please document them |
114 | // in configuration.md, too |
115 | // **************** |
116 | |
117 | // In general each macro has a _NO_<feature name> form |
118 | // (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature. |
119 | // Many features, at point of detection, define an _INTERNAL_ macro, so they |
120 | // can be combined, en-mass, with the _NO_ forms later. |
121 | |
122 | #ifdef __cplusplus |
123 | |
124 | # if __cplusplus >= 201402L |
125 | # define CATCH_CPP14_OR_GREATER |
126 | # endif |
127 | |
128 | # if __cplusplus >= 201703L |
129 | # define CATCH_CPP17_OR_GREATER |
130 | # endif |
131 | |
132 | #endif |
133 | |
134 | #if defined(CATCH_CPP17_OR_GREATER) |
135 | # define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS |
136 | #endif |
137 | |
138 | #ifdef __clang__ |
139 | |
140 | # define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ |
141 | _Pragma( "clang diagnostic push" ) \ |
142 | _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ |
143 | _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") |
144 | # define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ |
145 | _Pragma( "clang diagnostic pop" ) |
146 | |
147 | # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ |
148 | _Pragma( "clang diagnostic push" ) \ |
149 | _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) |
150 | # define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ |
151 | _Pragma( "clang diagnostic pop" ) |
152 | |
153 | # define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ |
154 | _Pragma( "clang diagnostic push" ) \ |
155 | _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" ) |
156 | # define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS \ |
157 | _Pragma( "clang diagnostic pop" ) |
158 | |
159 | #endif // __clang__ |
160 | |
161 | //////////////////////////////////////////////////////////////////////////////// |
162 | // Assume that non-Windows platforms support posix signals by default |
163 | #if !defined(CATCH_PLATFORM_WINDOWS) |
164 | #define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS |
165 | #endif |
166 | |
167 | //////////////////////////////////////////////////////////////////////////////// |
168 | // We know some environments not to support full POSIX signals |
169 | #if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__) |
170 | #define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS |
171 | #endif |
172 | |
173 | #ifdef __OS400__ |
174 | # define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS |
175 | # define CATCH_CONFIG_COLOUR_NONE |
176 | #endif |
177 | |
178 | //////////////////////////////////////////////////////////////////////////////// |
179 | // Android somehow still does not support std::to_string |
180 | #if defined(__ANDROID__) |
181 | # define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING |
182 | #endif |
183 | |
184 | //////////////////////////////////////////////////////////////////////////////// |
185 | // Not all Windows environments support SEH properly |
186 | #if defined(__MINGW32__) |
187 | # define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH |
188 | #endif |
189 | |
190 | //////////////////////////////////////////////////////////////////////////////// |
191 | // PS4 |
192 | #if defined(__ORBIS__) |
193 | # define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE |
194 | #endif |
195 | |
196 | //////////////////////////////////////////////////////////////////////////////// |
197 | // Cygwin |
198 | #ifdef __CYGWIN__ |
199 | |
200 | // Required for some versions of Cygwin to declare gettimeofday |
201 | // see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin |
202 | # define _BSD_SOURCE |
203 | |
204 | #endif // __CYGWIN__ |
205 | |
206 | //////////////////////////////////////////////////////////////////////////////// |
207 | // Visual C++ |
208 | #ifdef _MSC_VER |
209 | |
210 | # if _MSC_VER >= 1900 // Visual Studio 2015 or newer |
211 | # define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS |
212 | # endif |
213 | |
214 | // Universal Windows platform does not support SEH |
215 | // Or console colours (or console at all...) |
216 | # if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) |
217 | # define CATCH_CONFIG_COLOUR_NONE |
218 | # else |
219 | # define CATCH_INTERNAL_CONFIG_WINDOWS_SEH |
220 | # endif |
221 | |
222 | #endif // _MSC_VER |
223 | |
224 | //////////////////////////////////////////////////////////////////////////////// |
225 | // Check if we are compiled with -fno-exceptions or equivalent |
226 | #if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND) |
227 | # define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED |
228 | #endif |
229 | |
230 | //////////////////////////////////////////////////////////////////////////////// |
231 | // DJGPP |
232 | #ifdef __DJGPP__ |
233 | # define CATCH_INTERNAL_CONFIG_NO_WCHAR |
234 | #endif // __DJGPP__ |
235 | |
236 | //////////////////////////////////////////////////////////////////////////////// |
237 | |
238 | // Use of __COUNTER__ is suppressed during code analysis in |
239 | // CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly |
240 | // handled by it. |
241 | // Otherwise all supported compilers support COUNTER macro, |
242 | // but user still might want to turn it off |
243 | #if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) |
244 | #define CATCH_INTERNAL_CONFIG_COUNTER |
245 | #endif |
246 | |
247 | #if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) |
248 | # define CATCH_CONFIG_COUNTER |
249 | #endif |
250 | #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) |
251 | # define CATCH_CONFIG_WINDOWS_SEH |
252 | #endif |
253 | // This is set by default, because we assume that unix compilers are posix-signal-compatible by default. |
254 | #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) |
255 | # define CATCH_CONFIG_POSIX_SIGNALS |
256 | #endif |
257 | // This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions. |
258 | #if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR) |
259 | # define CATCH_CONFIG_WCHAR |
260 | #endif |
261 | |
262 | #if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING) |
263 | # define CATCH_CONFIG_CPP11_TO_STRING |
264 | #endif |
265 | |
266 | #if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) |
267 | # define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS |
268 | #endif |
269 | |
270 | #if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) |
271 | # define CATCH_INTERNAL_CONFIG_NEW_CAPTURE |
272 | #endif |
273 | |
274 | #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) |
275 | # define CATCH_CONFIG_NEW_CAPTURE |
276 | #endif |
277 | |
278 | #if !defined(CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) |
279 | # define CATCH_CONFIG_DISABLE_EXCEPTIONS |
280 | #endif |
281 | |
282 | #if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) |
283 | # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS |
284 | # define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS |
285 | #endif |
286 | #if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) |
287 | # define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS |
288 | # define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS |
289 | #endif |
290 | #if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS) |
291 | # define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS |
292 | # define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS |
293 | #endif |
294 | |
295 | #if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) |
296 | #define CATCH_TRY if ((true)) |
297 | #define CATCH_CATCH_ALL if ((false)) |
298 | #define CATCH_CATCH_ANON(type) if ((false)) |
299 | #else |
300 | #define CATCH_TRY try |
301 | #define CATCH_CATCH_ALL catch (...) |
302 | #define CATCH_CATCH_ANON(type) catch (type) |
303 | #endif |
304 | |
305 | // end catch_compiler_capabilities.h |
306 | #define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line |
307 | #define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) |
308 | #ifdef CATCH_CONFIG_COUNTER |
309 | # define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) |
310 | #else |
311 | # define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) |
312 | #endif |
313 | |
314 | #include <iosfwd> |
315 | #include <string> |
316 | #include <cstdint> |
317 | |
318 | namespace Catch { |
319 | |
320 | struct CaseSensitive { enum Choice { |
321 | Yes, |
322 | No |
323 | }; }; |
324 | |
325 | class NonCopyable { |
326 | NonCopyable( NonCopyable const& ) = delete; |
327 | NonCopyable( NonCopyable && ) = delete; |
328 | NonCopyable& operator = ( NonCopyable const& ) = delete; |
329 | NonCopyable& operator = ( NonCopyable && ) = delete; |
330 | |
331 | protected: |
332 | NonCopyable(); |
333 | virtual ~NonCopyable(); |
334 | }; |
335 | |
336 | struct SourceLineInfo { |
337 | |
338 | SourceLineInfo() = delete; |
339 | SourceLineInfo( char const* _file, std::size_t _line ) noexcept |
340 | : file( _file ), |
341 | line( _line ) |
342 | {} |
343 | |
344 | SourceLineInfo( SourceLineInfo const& other ) = default; |
345 | SourceLineInfo( SourceLineInfo && ) = default; |
346 | SourceLineInfo& operator = ( SourceLineInfo const& ) = default; |
347 | SourceLineInfo& operator = ( SourceLineInfo && ) = default; |
348 | |
349 | bool empty() const noexcept; |
350 | bool operator == ( SourceLineInfo const& other ) const noexcept; |
351 | bool operator < ( SourceLineInfo const& other ) const noexcept; |
352 | |
353 | char const* file; |
354 | std::size_t line; |
355 | }; |
356 | |
357 | std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); |
358 | |
359 | // Use this in variadic streaming macros to allow |
360 | // >> +StreamEndStop |
361 | // as well as |
362 | // >> stuff +StreamEndStop |
363 | struct StreamEndStop { |
364 | std::string operator+() const; |
365 | }; |
366 | template<typename T> |
367 | T const& operator + ( T const& value, StreamEndStop ) { |
368 | return value; |
369 | } |
370 | } |
371 | |
372 | #define CATCH_INTERNAL_LINEINFO \ |
373 | ::Catch::SourceLineInfo( __FILE__, static_cast<std::size_t>( __LINE__ ) ) |
374 | |
375 | // end catch_common.h |
376 | namespace Catch { |
377 | |
378 | struct RegistrarForTagAliases { |
379 | RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); |
380 | }; |
381 | |
382 | } // end namespace Catch |
383 | |
384 | #define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \ |
385 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ |
386 | namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \ |
387 | CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS |
388 | |
389 | // end catch_tag_alias_autoregistrar.h |
390 | // start catch_test_registry.h |
391 | |
392 | // start catch_interfaces_testcase.h |
393 | |
394 | #include <vector> |
395 | #include <memory> |
396 | |
397 | namespace Catch { |
398 | |
399 | class TestSpec; |
400 | |
401 | struct ITestInvoker { |
402 | virtual void invoke () const = 0; |
403 | virtual ~ITestInvoker(); |
404 | }; |
405 | |
406 | using ITestCasePtr = std::shared_ptr<ITestInvoker>; |
407 | |
408 | class TestCase; |
409 | struct IConfig; |
410 | |
411 | struct ITestCaseRegistry { |
412 | virtual ~ITestCaseRegistry(); |
413 | virtual std::vector<TestCase> const& getAllTests() const = 0; |
414 | virtual std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const = 0; |
415 | }; |
416 | |
417 | bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); |
418 | std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ); |
419 | std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ); |
420 | |
421 | } |
422 | |
423 | // end catch_interfaces_testcase.h |
424 | // start catch_stringref.h |
425 | |
426 | #include <cstddef> |
427 | #include <string> |
428 | #include <iosfwd> |
429 | |
430 | namespace Catch { |
431 | |
432 | class StringData; |
433 | |
434 | /// A non-owning string class (similar to the forthcoming std::string_view) |
435 | /// Note that, because a StringRef may be a substring of another string, |
436 | /// it may not be null terminated. c_str() must return a null terminated |
437 | /// string, however, and so the StringRef will internally take ownership |
438 | /// (taking a copy), if necessary. In theory this ownership is not externally |
439 | /// visible - but it does mean (substring) StringRefs should not be shared between |
440 | /// threads. |
441 | class StringRef { |
442 | public: |
443 | using size_type = std::size_t; |
444 | |
445 | private: |
446 | friend struct StringRefTestAccess; |
447 | |
448 | char const* m_start; |
449 | size_type m_size; |
450 | |
451 | char* m_data = nullptr; |
452 | |
453 | void takeOwnership(); |
454 | |
455 | static constexpr char const* const s_empty = "" ; |
456 | |
457 | public: // construction/ assignment |
458 | StringRef() noexcept |
459 | : StringRef( s_empty, 0 ) |
460 | {} |
461 | |
462 | StringRef( StringRef const& other ) noexcept |
463 | : m_start( other.m_start ), |
464 | m_size( other.m_size ) |
465 | {} |
466 | |
467 | StringRef( StringRef&& other ) noexcept |
468 | : m_start( other.m_start ), |
469 | m_size( other.m_size ), |
470 | m_data( other.m_data ) |
471 | { |
472 | other.m_data = nullptr; |
473 | } |
474 | |
475 | StringRef( char const* rawChars ) noexcept; |
476 | |
477 | StringRef( char const* rawChars, size_type size ) noexcept |
478 | : m_start( rawChars ), |
479 | m_size( size ) |
480 | {} |
481 | |
482 | StringRef( std::string const& stdString ) noexcept |
483 | : m_start( stdString.c_str() ), |
484 | m_size( stdString.size() ) |
485 | {} |
486 | |
487 | ~StringRef() noexcept { |
488 | delete[] m_data; |
489 | } |
490 | |
491 | auto operator = ( StringRef const &other ) noexcept -> StringRef& { |
492 | delete[] m_data; |
493 | m_data = nullptr; |
494 | m_start = other.m_start; |
495 | m_size = other.m_size; |
496 | return *this; |
497 | } |
498 | |
499 | operator std::string() const; |
500 | |
501 | void swap( StringRef& other ) noexcept; |
502 | |
503 | public: // operators |
504 | auto operator == ( StringRef const& other ) const noexcept -> bool; |
505 | auto operator != ( StringRef const& other ) const noexcept -> bool; |
506 | |
507 | auto operator[] ( size_type index ) const noexcept -> char; |
508 | |
509 | public: // named queries |
510 | auto empty() const noexcept -> bool { |
511 | return m_size == 0; |
512 | } |
513 | auto size() const noexcept -> size_type { |
514 | return m_size; |
515 | } |
516 | |
517 | auto numberOfCharacters() const noexcept -> size_type; |
518 | auto c_str() const -> char const*; |
519 | |
520 | public: // substrings and searches |
521 | auto substr( size_type start, size_type size ) const noexcept -> StringRef; |
522 | |
523 | // Returns the current start pointer. |
524 | // Note that the pointer can change when if the StringRef is a substring |
525 | auto currentData() const noexcept -> char const*; |
526 | |
527 | private: // ownership queries - may not be consistent between calls |
528 | auto isOwned() const noexcept -> bool; |
529 | auto isSubstring() const noexcept -> bool; |
530 | }; |
531 | |
532 | auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string; |
533 | auto operator + ( StringRef const& lhs, char const* rhs ) -> std::string; |
534 | auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string; |
535 | |
536 | auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&; |
537 | auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; |
538 | |
539 | inline auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { |
540 | return StringRef( rawChars, size ); |
541 | } |
542 | |
543 | } // namespace Catch |
544 | |
545 | inline auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { |
546 | return Catch::StringRef( rawChars, size ); |
547 | } |
548 | |
549 | // end catch_stringref.h |
550 | namespace Catch { |
551 | |
552 | template<typename C> |
553 | class TestInvokerAsMethod : public ITestInvoker { |
554 | void (C::*m_testAsMethod)(); |
555 | public: |
556 | TestInvokerAsMethod( void (C::*testAsMethod)() ) noexcept : m_testAsMethod( testAsMethod ) {} |
557 | |
558 | void invoke() const override { |
559 | C obj; |
560 | (obj.*m_testAsMethod)(); |
561 | } |
562 | }; |
563 | |
564 | auto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker*; |
565 | |
566 | template<typename C> |
567 | auto makeTestInvoker( void (C::*testAsMethod)() ) noexcept -> ITestInvoker* { |
568 | return new(std::nothrow) TestInvokerAsMethod<C>( testAsMethod ); |
569 | } |
570 | |
571 | struct NameAndTags { |
572 | NameAndTags( StringRef const& name_ = StringRef(), StringRef const& tags_ = StringRef() ) noexcept; |
573 | StringRef name; |
574 | StringRef tags; |
575 | }; |
576 | |
577 | struct AutoReg : NonCopyable { |
578 | AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept; |
579 | ~AutoReg(); |
580 | }; |
581 | |
582 | } // end namespace Catch |
583 | |
584 | #define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param) |
585 | #define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__ |
586 | #define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__ |
587 | #define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF |
588 | |
589 | #if defined(CATCH_CONFIG_DISABLE) |
590 | #define INTERNAL_CATCH_TESTCASE_NO_REGISTRATION( TestName, ... ) \ |
591 | static void TestName() |
592 | #define INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... ) \ |
593 | namespace{ \ |
594 | struct TestName : INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF ClassName) { \ |
595 | void test(); \ |
596 | }; \ |
597 | } \ |
598 | void TestName::test() |
599 | |
600 | #endif |
601 | |
602 | /////////////////////////////////////////////////////////////////////////////// |
603 | #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \ |
604 | static void TestName(); \ |
605 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ |
606 | namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ |
607 | CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ |
608 | static void TestName() |
609 | #define INTERNAL_CATCH_TESTCASE( ... ) \ |
610 | INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ ) |
611 | |
612 | /////////////////////////////////////////////////////////////////////////////// |
613 | #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ |
614 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ |
615 | namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &QualifiedMethod ), CATCH_INTERNAL_LINEINFO, "&" #QualifiedMethod, Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ |
616 | CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS |
617 | |
618 | /////////////////////////////////////////////////////////////////////////////// |
619 | #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\ |
620 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ |
621 | namespace{ \ |
622 | struct TestName : INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF ClassName) { \ |
623 | void test(); \ |
624 | }; \ |
625 | Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ |
626 | } \ |
627 | CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ |
628 | void TestName::test() |
629 | #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \ |
630 | INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ ) |
631 | |
632 | /////////////////////////////////////////////////////////////////////////////// |
633 | #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ |
634 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ |
635 | Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ |
636 | CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS |
637 | |
638 | // end catch_test_registry.h |
639 | // start catch_capture.hpp |
640 | |
641 | // start catch_assertionhandler.h |
642 | |
643 | // start catch_assertioninfo.h |
644 | |
645 | // start catch_result_type.h |
646 | |
647 | namespace Catch { |
648 | |
649 | // ResultWas::OfType enum |
650 | struct ResultWas { enum OfType { |
651 | Unknown = -1, |
652 | Ok = 0, |
653 | Info = 1, |
654 | Warning = 2, |
655 | |
656 | FailureBit = 0x10, |
657 | |
658 | ExpressionFailed = FailureBit | 1, |
659 | ExplicitFailure = FailureBit | 2, |
660 | |
661 | Exception = 0x100 | FailureBit, |
662 | |
663 | ThrewException = Exception | 1, |
664 | DidntThrowException = Exception | 2, |
665 | |
666 | FatalErrorCondition = 0x200 | FailureBit |
667 | |
668 | }; }; |
669 | |
670 | bool isOk( ResultWas::OfType resultType ); |
671 | bool isJustInfo( int flags ); |
672 | |
673 | // ResultDisposition::Flags enum |
674 | struct ResultDisposition { enum Flags { |
675 | Normal = 0x01, |
676 | |
677 | ContinueOnFailure = 0x02, // Failures fail test, but execution continues |
678 | FalseTest = 0x04, // Prefix expression with ! |
679 | SuppressFail = 0x08 // Failures are reported but do not fail the test |
680 | }; }; |
681 | |
682 | ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ); |
683 | |
684 | bool shouldContinueOnFailure( int flags ); |
685 | inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } |
686 | bool shouldSuppressFailure( int flags ); |
687 | |
688 | } // end namespace Catch |
689 | |
690 | // end catch_result_type.h |
691 | namespace Catch { |
692 | |
693 | struct AssertionInfo |
694 | { |
695 | StringRef macroName; |
696 | SourceLineInfo lineInfo; |
697 | StringRef capturedExpression; |
698 | ResultDisposition::Flags resultDisposition; |
699 | |
700 | // We want to delete this constructor but a compiler bug in 4.8 means |
701 | // the struct is then treated as non-aggregate |
702 | //AssertionInfo() = delete; |
703 | }; |
704 | |
705 | } // end namespace Catch |
706 | |
707 | // end catch_assertioninfo.h |
708 | // start catch_decomposer.h |
709 | |
710 | // start catch_tostring.h |
711 | |
712 | #include <vector> |
713 | #include <cstddef> |
714 | #include <type_traits> |
715 | #include <string> |
716 | // start catch_stream.h |
717 | |
718 | #include <iosfwd> |
719 | #include <cstddef> |
720 | #include <ostream> |
721 | |
722 | namespace Catch { |
723 | |
724 | std::ostream& cout(); |
725 | std::ostream& cerr(); |
726 | std::ostream& clog(); |
727 | |
728 | class StringRef; |
729 | |
730 | struct IStream { |
731 | virtual ~IStream(); |
732 | virtual std::ostream& stream() const = 0; |
733 | }; |
734 | |
735 | auto makeStream( StringRef const &filename ) -> IStream const*; |
736 | |
737 | class ReusableStringStream { |
738 | std::size_t m_index; |
739 | std::ostream* m_oss; |
740 | public: |
741 | ReusableStringStream(); |
742 | ~ReusableStringStream(); |
743 | |
744 | auto str() const -> std::string; |
745 | |
746 | template<typename T> |
747 | auto operator << ( T const& value ) -> ReusableStringStream& { |
748 | *m_oss << value; |
749 | return *this; |
750 | } |
751 | auto get() -> std::ostream& { return *m_oss; } |
752 | }; |
753 | } |
754 | |
755 | // end catch_stream.h |
756 | |
757 | #ifdef __OBJC__ |
758 | // start catch_objc_arc.hpp |
759 | |
760 | #import <Foundation/Foundation.h> |
761 | |
762 | #ifdef __has_feature |
763 | #define CATCH_ARC_ENABLED __has_feature(objc_arc) |
764 | #else |
765 | #define CATCH_ARC_ENABLED 0 |
766 | #endif |
767 | |
768 | void arcSafeRelease( NSObject* obj ); |
769 | id performOptionalSelector( id obj, SEL sel ); |
770 | |
771 | #if !CATCH_ARC_ENABLED |
772 | inline void arcSafeRelease( NSObject* obj ) { |
773 | [obj release]; |
774 | } |
775 | inline id performOptionalSelector( id obj, SEL sel ) { |
776 | if( [obj respondsToSelector: sel] ) |
777 | return [obj performSelector: sel]; |
778 | return nil; |
779 | } |
780 | #define CATCH_UNSAFE_UNRETAINED |
781 | #define CATCH_ARC_STRONG |
782 | #else |
783 | inline void arcSafeRelease( NSObject* ){} |
784 | inline id performOptionalSelector( id obj, SEL sel ) { |
785 | #ifdef __clang__ |
786 | #pragma clang diagnostic push |
787 | #pragma clang diagnostic ignored "-Warc-performSelector-leaks" |
788 | #endif |
789 | if( [obj respondsToSelector: sel] ) |
790 | return [obj performSelector: sel]; |
791 | #ifdef __clang__ |
792 | #pragma clang diagnostic pop |
793 | #endif |
794 | return nil; |
795 | } |
796 | #define CATCH_UNSAFE_UNRETAINED __unsafe_unretained |
797 | #define CATCH_ARC_STRONG __strong |
798 | #endif |
799 | |
800 | // end catch_objc_arc.hpp |
801 | #endif |
802 | |
803 | #ifdef _MSC_VER |
804 | #pragma warning(push) |
805 | #pragma warning(disable:4180) // We attempt to stream a function (address) by const&, which MSVC complains about but is harmless |
806 | #endif |
807 | |
808 | // We need a dummy global operator<< so we can bring it into Catch namespace later |
809 | struct Catch_global_namespace_dummy {}; |
810 | std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy); |
811 | |
812 | namespace Catch { |
813 | // Bring in operator<< from global namespace into Catch namespace |
814 | using ::operator<<; |
815 | |
816 | namespace Detail { |
817 | |
818 | extern const std::string unprintableString; |
819 | |
820 | std::string rawMemoryToString( const void *object, std::size_t size ); |
821 | |
822 | template<typename T> |
823 | std::string rawMemoryToString( const T& object ) { |
824 | return rawMemoryToString( &object, sizeof(object) ); |
825 | } |
826 | |
827 | template<typename T> |
828 | class IsStreamInsertable { |
829 | template<typename SSX, typename TT> |
830 | static auto test(int) |
831 | -> decltype(std::declval<SSX&>() << std::declval<TT>(), std::true_type()); |
832 | |
833 | template<typename, typename> |
834 | static auto test(...)->std::false_type; |
835 | |
836 | public: |
837 | static const bool value = decltype(test<std::ostream, const T&>(0))::value; |
838 | }; |
839 | |
840 | template<typename E> |
841 | std::string convertUnknownEnumToString( E e ); |
842 | |
843 | template<typename T> |
844 | typename std::enable_if< |
845 | !std::is_enum<T>::value && !std::is_base_of<std::exception, T>::value, |
846 | std::string>::type convertUnstreamable( T const& ) { |
847 | return Detail::unprintableString; |
848 | } |
849 | template<typename T> |
850 | typename std::enable_if< |
851 | !std::is_enum<T>::value && std::is_base_of<std::exception, T>::value, |
852 | std::string>::type convertUnstreamable(T const& ex) { |
853 | return ex.what(); |
854 | } |
855 | |
856 | template<typename T> |
857 | typename std::enable_if< |
858 | std::is_enum<T>::value |
859 | , std::string>::type convertUnstreamable( T const& value ) { |
860 | return convertUnknownEnumToString( value ); |
861 | } |
862 | |
863 | #if defined(_MANAGED) |
864 | //! Convert a CLR string to a utf8 std::string |
865 | template<typename T> |
866 | std::string clrReferenceToString( T^ ref ) { |
867 | if (ref == nullptr) |
868 | return std::string("null" ); |
869 | auto bytes = System::Text::Encoding::UTF8->GetBytes(ref->ToString()); |
870 | cli::pin_ptr<System::Byte> p = &bytes[0]; |
871 | return std::string(reinterpret_cast<char const *>(p), bytes->Length); |
872 | } |
873 | #endif |
874 | |
875 | } // namespace Detail |
876 | |
877 | // If we decide for C++14, change these to enable_if_ts |
878 | template <typename T, typename = void> |
879 | struct StringMaker { |
880 | template <typename Fake = T> |
881 | static |
882 | typename std::enable_if<::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>::type |
883 | convert(const Fake& value) { |
884 | ReusableStringStream ; |
885 | // NB: call using the function-like syntax to avoid ambiguity with |
886 | // user-defined templated operator<< under clang. |
887 | rss.operator<<(value); |
888 | return rss.str(); |
889 | } |
890 | |
891 | template <typename Fake = T> |
892 | static |
893 | typename std::enable_if<!::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>::type |
894 | convert( const Fake& value ) { |
895 | #if !defined(CATCH_CONFIG_FALLBACK_STRINGIFIER) |
896 | return Detail::convertUnstreamable(value); |
897 | #else |
898 | return CATCH_CONFIG_FALLBACK_STRINGIFIER(value); |
899 | #endif |
900 | } |
901 | }; |
902 | |
903 | namespace Detail { |
904 | |
905 | // This function dispatches all stringification requests inside of Catch. |
906 | // Should be preferably called fully qualified, like ::Catch::Detail::stringify |
907 | template <typename T> |
908 | std::string stringify(const T& e) { |
909 | return ::Catch::StringMaker<typename std::remove_cv<typename std::remove_reference<T>::type>::type>::convert(e); |
910 | } |
911 | |
912 | template<typename E> |
913 | std::string convertUnknownEnumToString( E e ) { |
914 | return ::Catch::Detail::stringify(static_cast<typename std::underlying_type<E>::type>(e)); |
915 | } |
916 | |
917 | #if defined(_MANAGED) |
918 | template <typename T> |
919 | std::string stringify( T^ e ) { |
920 | return ::Catch::StringMaker<T^>::convert(e); |
921 | } |
922 | #endif |
923 | |
924 | } // namespace Detail |
925 | |
926 | // Some predefined specializations |
927 | |
928 | template<> |
929 | struct StringMaker<std::string> { |
930 | static std::string convert(const std::string& str); |
931 | }; |
932 | #ifdef CATCH_CONFIG_WCHAR |
933 | template<> |
934 | struct StringMaker<std::wstring> { |
935 | static std::string convert(const std::wstring& wstr); |
936 | }; |
937 | #endif |
938 | |
939 | template<> |
940 | struct StringMaker<char const *> { |
941 | static std::string convert(char const * str); |
942 | }; |
943 | template<> |
944 | struct StringMaker<char *> { |
945 | static std::string convert(char * str); |
946 | }; |
947 | |
948 | #ifdef CATCH_CONFIG_WCHAR |
949 | template<> |
950 | struct StringMaker<wchar_t const *> { |
951 | static std::string convert(wchar_t const * str); |
952 | }; |
953 | template<> |
954 | struct StringMaker<wchar_t *> { |
955 | static std::string convert(wchar_t * str); |
956 | }; |
957 | #endif |
958 | |
959 | // TBD: Should we use `strnlen` to ensure that we don't go out of the buffer, |
960 | // while keeping string semantics? |
961 | template<int SZ> |
962 | struct StringMaker<char[SZ]> { |
963 | static std::string convert(char const* str) { |
964 | return ::Catch::Detail::stringify(std::string{ str }); |
965 | } |
966 | }; |
967 | template<int SZ> |
968 | struct StringMaker<signed char[SZ]> { |
969 | static std::string convert(signed char const* str) { |
970 | return ::Catch::Detail::stringify(std::string{ reinterpret_cast<char const *>(str) }); |
971 | } |
972 | }; |
973 | template<int SZ> |
974 | struct StringMaker<unsigned char[SZ]> { |
975 | static std::string convert(unsigned char const* str) { |
976 | return ::Catch::Detail::stringify(std::string{ reinterpret_cast<char const *>(str) }); |
977 | } |
978 | }; |
979 | |
980 | template<> |
981 | struct StringMaker<int> { |
982 | static std::string convert(int value); |
983 | }; |
984 | template<> |
985 | struct StringMaker<long> { |
986 | static std::string convert(long value); |
987 | }; |
988 | template<> |
989 | struct StringMaker<long long> { |
990 | static std::string convert(long long value); |
991 | }; |
992 | template<> |
993 | struct StringMaker<unsigned int> { |
994 | static std::string convert(unsigned int value); |
995 | }; |
996 | template<> |
997 | struct StringMaker<unsigned long> { |
998 | static std::string convert(unsigned long value); |
999 | }; |
1000 | template<> |
1001 | struct StringMaker<unsigned long long> { |
1002 | static std::string convert(unsigned long long value); |
1003 | }; |
1004 | |
1005 | template<> |
1006 | struct StringMaker<bool> { |
1007 | static std::string convert(bool b); |
1008 | }; |
1009 | |
1010 | template<> |
1011 | struct StringMaker<char> { |
1012 | static std::string convert(char c); |
1013 | }; |
1014 | template<> |
1015 | struct StringMaker<signed char> { |
1016 | static std::string convert(signed char c); |
1017 | }; |
1018 | template<> |
1019 | struct StringMaker<unsigned char> { |
1020 | static std::string convert(unsigned char c); |
1021 | }; |
1022 | |
1023 | template<> |
1024 | struct StringMaker<std::nullptr_t> { |
1025 | static std::string convert(std::nullptr_t); |
1026 | }; |
1027 | |
1028 | template<> |
1029 | struct StringMaker<float> { |
1030 | static std::string convert(float value); |
1031 | }; |
1032 | template<> |
1033 | struct StringMaker<double> { |
1034 | static std::string convert(double value); |
1035 | }; |
1036 | |
1037 | template <typename T> |
1038 | struct StringMaker<T*> { |
1039 | template <typename U> |
1040 | static std::string convert(U* p) { |
1041 | if (p) { |
1042 | return ::Catch::Detail::rawMemoryToString(p); |
1043 | } else { |
1044 | return "nullptr" ; |
1045 | } |
1046 | } |
1047 | }; |
1048 | |
1049 | template <typename R, typename C> |
1050 | struct StringMaker<R C::*> { |
1051 | static std::string convert(R C::* p) { |
1052 | if (p) { |
1053 | return ::Catch::Detail::rawMemoryToString(p); |
1054 | } else { |
1055 | return "nullptr" ; |
1056 | } |
1057 | } |
1058 | }; |
1059 | |
1060 | #if defined(_MANAGED) |
1061 | template <typename T> |
1062 | struct StringMaker<T^> { |
1063 | static std::string convert( T^ ref ) { |
1064 | return ::Catch::Detail::clrReferenceToString(ref); |
1065 | } |
1066 | }; |
1067 | #endif |
1068 | |
1069 | namespace Detail { |
1070 | template<typename InputIterator> |
1071 | std::string rangeToString(InputIterator first, InputIterator last) { |
1072 | ReusableStringStream ; |
1073 | rss << "{ " ; |
1074 | if (first != last) { |
1075 | rss << ::Catch::Detail::stringify(*first); |
1076 | for (++first; first != last; ++first) |
1077 | rss << ", " << ::Catch::Detail::stringify(*first); |
1078 | } |
1079 | rss << " }" ; |
1080 | return rss.str(); |
1081 | } |
1082 | } |
1083 | |
1084 | #ifdef __OBJC__ |
1085 | template<> |
1086 | struct StringMaker<NSString*> { |
1087 | static std::string convert(NSString * nsstring) { |
1088 | if (!nsstring) |
1089 | return "nil" ; |
1090 | return std::string("@" ) + [nsstring UTF8String]; |
1091 | } |
1092 | }; |
1093 | template<> |
1094 | struct StringMaker<NSObject*> { |
1095 | static std::string convert(NSObject* nsObject) { |
1096 | return ::Catch::Detail::stringify([nsObject description]); |
1097 | } |
1098 | |
1099 | }; |
1100 | namespace Detail { |
1101 | inline std::string stringify( NSString* nsstring ) { |
1102 | return StringMaker<NSString*>::convert( nsstring ); |
1103 | } |
1104 | |
1105 | } // namespace Detail |
1106 | #endif // __OBJC__ |
1107 | |
1108 | } // namespace Catch |
1109 | |
1110 | ////////////////////////////////////////////////////// |
1111 | // Separate std-lib types stringification, so it can be selectively enabled |
1112 | // This means that we do not bring in |
1113 | |
1114 | #if defined(CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS) |
1115 | # define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER |
1116 | # define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER |
1117 | # define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER |
1118 | #endif |
1119 | |
1120 | // Separate std::pair specialization |
1121 | #if defined(CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER) |
1122 | #include <utility> |
1123 | namespace Catch { |
1124 | template<typename T1, typename T2> |
1125 | struct StringMaker<std::pair<T1, T2> > { |
1126 | static std::string convert(const std::pair<T1, T2>& pair) { |
1127 | ReusableStringStream rss; |
1128 | rss << "{ " |
1129 | << ::Catch::Detail::stringify(pair.first) |
1130 | << ", " |
1131 | << ::Catch::Detail::stringify(pair.second) |
1132 | << " }" ; |
1133 | return rss.str(); |
1134 | } |
1135 | }; |
1136 | } |
1137 | #endif // CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER |
1138 | |
1139 | // Separate std::tuple specialization |
1140 | #if defined(CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER) |
1141 | #include <tuple> |
1142 | namespace Catch { |
1143 | namespace Detail { |
1144 | template< |
1145 | typename Tuple, |
1146 | std::size_t N = 0, |
1147 | bool = (N < std::tuple_size<Tuple>::value) |
1148 | > |
1149 | struct TupleElementPrinter { |
1150 | static void print(const Tuple& tuple, std::ostream& os) { |
1151 | os << (N ? ", " : " " ) |
1152 | << ::Catch::Detail::stringify(std::get<N>(tuple)); |
1153 | TupleElementPrinter<Tuple, N + 1>::print(tuple, os); |
1154 | } |
1155 | }; |
1156 | |
1157 | template< |
1158 | typename Tuple, |
1159 | std::size_t N |
1160 | > |
1161 | struct TupleElementPrinter<Tuple, N, false> { |
1162 | static void print(const Tuple&, std::ostream&) {} |
1163 | }; |
1164 | |
1165 | } |
1166 | |
1167 | template<typename ...Types> |
1168 | struct StringMaker<std::tuple<Types...>> { |
1169 | static std::string convert(const std::tuple<Types...>& tuple) { |
1170 | ReusableStringStream rss; |
1171 | rss << '{'; |
1172 | Detail::TupleElementPrinter<std::tuple<Types...>>::print(tuple, rss.get()); |
1173 | rss << " }" ; |
1174 | return rss.str(); |
1175 | } |
1176 | }; |
1177 | } |
1178 | #endif // CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER |
1179 | |
1180 | namespace Catch { |
1181 | struct not_this_one {}; // Tag type for detecting which begin/ end are being selected |
1182 | |
1183 | // Import begin/ end from std here so they are considered alongside the fallback (...) overloads in this namespace |
1184 | using std::begin; |
1185 | using std::end; |
1186 | |
1187 | not_this_one begin( ... ); |
1188 | not_this_one end( ... ); |
1189 | |
1190 | template <typename T> |
1191 | struct is_range { |
1192 | static const bool value = |
1193 | !std::is_same<decltype(begin(std::declval<T>())), not_this_one>::value && |
1194 | !std::is_same<decltype(end(std::declval<T>())), not_this_one>::value; |
1195 | }; |
1196 | |
1197 | #if defined(_MANAGED) // Managed types are never ranges |
1198 | template <typename T> |
1199 | struct is_range<T^> { |
1200 | static const bool value = false; |
1201 | }; |
1202 | #endif |
1203 | |
1204 | template<typename Range> |
1205 | std::string rangeToString( Range const& range ) { |
1206 | return ::Catch::Detail::rangeToString( begin( range ), end( range ) ); |
1207 | } |
1208 | |
1209 | // Handle vector<bool> specially |
1210 | template<typename Allocator> |
1211 | std::string rangeToString( std::vector<bool, Allocator> const& v ) { |
1212 | ReusableStringStream ; |
1213 | rss << "{ " ; |
1214 | bool first = true; |
1215 | for( bool b : v ) { |
1216 | if( first ) |
1217 | first = false; |
1218 | else |
1219 | rss << ", " ; |
1220 | rss << ::Catch::Detail::stringify( b ); |
1221 | } |
1222 | rss << " }" ; |
1223 | return rss.str(); |
1224 | } |
1225 | |
1226 | template<typename R> |
1227 | struct StringMaker<R, typename std::enable_if<is_range<R>::value && !::Catch::Detail::IsStreamInsertable<R>::value>::type> { |
1228 | static std::string convert( R const& range ) { |
1229 | return rangeToString( range ); |
1230 | } |
1231 | }; |
1232 | |
1233 | template <typename T, int SZ> |
1234 | struct StringMaker<T[SZ]> { |
1235 | static std::string convert(T const(&arr)[SZ]) { |
1236 | return rangeToString(arr); |
1237 | } |
1238 | }; |
1239 | |
1240 | } // namespace Catch |
1241 | |
1242 | // Separate std::chrono::duration specialization |
1243 | #if defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) |
1244 | #include <ctime> |
1245 | #include <ratio> |
1246 | #include <chrono> |
1247 | |
1248 | namespace Catch { |
1249 | |
1250 | template <class Ratio> |
1251 | struct ratio_string { |
1252 | static std::string symbol(); |
1253 | }; |
1254 | |
1255 | template <class Ratio> |
1256 | std::string ratio_string<Ratio>::symbol() { |
1257 | Catch::ReusableStringStream ; |
1258 | rss << '[' << Ratio::num << '/' |
1259 | << Ratio::den << ']'; |
1260 | return rss.str(); |
1261 | } |
1262 | template <> |
1263 | struct ratio_string<std::atto> { |
1264 | static std::string symbol(); |
1265 | }; |
1266 | template <> |
1267 | struct ratio_string<std::femto> { |
1268 | static std::string symbol(); |
1269 | }; |
1270 | template <> |
1271 | struct ratio_string<std::pico> { |
1272 | static std::string symbol(); |
1273 | }; |
1274 | template <> |
1275 | struct ratio_string<std::nano> { |
1276 | static std::string symbol(); |
1277 | }; |
1278 | template <> |
1279 | struct ratio_string<std::micro> { |
1280 | static std::string symbol(); |
1281 | }; |
1282 | template <> |
1283 | struct ratio_string<std::milli> { |
1284 | static std::string symbol(); |
1285 | }; |
1286 | |
1287 | //////////// |
1288 | // std::chrono::duration specializations |
1289 | template<typename Value, typename Ratio> |
1290 | struct StringMaker<std::chrono::duration<Value, Ratio>> { |
1291 | static std::string convert(std::chrono::duration<Value, Ratio> const& duration) { |
1292 | ReusableStringStream ; |
1293 | rss << duration.count() << ' ' << ratio_string<Ratio>::symbol() << 's'; |
1294 | return rss.str(); |
1295 | } |
1296 | }; |
1297 | template<typename Value> |
1298 | struct StringMaker<std::chrono::duration<Value, std::ratio<1>>> { |
1299 | static std::string convert(std::chrono::duration<Value, std::ratio<1>> const& duration) { |
1300 | ReusableStringStream ; |
1301 | rss << duration.count() << " s" ; |
1302 | return rss.str(); |
1303 | } |
1304 | }; |
1305 | template<typename Value> |
1306 | struct StringMaker<std::chrono::duration<Value, std::ratio<60>>> { |
1307 | static std::string convert(std::chrono::duration<Value, std::ratio<60>> const& duration) { |
1308 | ReusableStringStream ; |
1309 | rss << duration.count() << " m" ; |
1310 | return rss.str(); |
1311 | } |
1312 | }; |
1313 | template<typename Value> |
1314 | struct StringMaker<std::chrono::duration<Value, std::ratio<3600>>> { |
1315 | static std::string convert(std::chrono::duration<Value, std::ratio<3600>> const& duration) { |
1316 | ReusableStringStream ; |
1317 | rss << duration.count() << " h" ; |
1318 | return rss.str(); |
1319 | } |
1320 | }; |
1321 | |
1322 | //////////// |
1323 | // std::chrono::time_point specialization |
1324 | // Generic time_point cannot be specialized, only std::chrono::time_point<system_clock> |
1325 | template<typename Clock, typename Duration> |
1326 | struct StringMaker<std::chrono::time_point<Clock, Duration>> { |
1327 | static std::string convert(std::chrono::time_point<Clock, Duration> const& time_point) { |
1328 | return ::Catch::Detail::stringify(time_point.time_since_epoch()) + " since epoch" ; |
1329 | } |
1330 | }; |
1331 | // std::chrono::time_point<system_clock> specialization |
1332 | template<typename Duration> |
1333 | struct StringMaker<std::chrono::time_point<std::chrono::system_clock, Duration>> { |
1334 | static std::string convert(std::chrono::time_point<std::chrono::system_clock, Duration> const& time_point) { |
1335 | auto converted = std::chrono::system_clock::to_time_t(time_point); |
1336 | |
1337 | #ifdef _MSC_VER |
1338 | std::tm timeInfo = {}; |
1339 | gmtime_s(&timeInfo, &converted); |
1340 | #else |
1341 | std::tm* timeInfo = std::gmtime(&converted); |
1342 | #endif |
1343 | |
1344 | auto const timeStampSize = sizeof("2017-01-16T17:06:45Z" ); |
1345 | char timeStamp[timeStampSize]; |
1346 | const char * const fmt = "%Y-%m-%dT%H:%M:%SZ" ; |
1347 | |
1348 | #ifdef _MSC_VER |
1349 | std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); |
1350 | #else |
1351 | std::strftime(timeStamp, timeStampSize, fmt, timeInfo); |
1352 | #endif |
1353 | return std::string(timeStamp); |
1354 | } |
1355 | }; |
1356 | } |
1357 | #endif // CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER |
1358 | |
1359 | #ifdef _MSC_VER |
1360 | #pragma warning(pop) |
1361 | #endif |
1362 | |
1363 | // end catch_tostring.h |
1364 | #include <iosfwd> |
1365 | |
1366 | #ifdef _MSC_VER |
1367 | #pragma warning(push) |
1368 | #pragma warning(disable:4389) // '==' : signed/unsigned mismatch |
1369 | #pragma warning(disable:4018) // more "signed/unsigned mismatch" |
1370 | #pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform) |
1371 | #pragma warning(disable:4180) // qualifier applied to function type has no meaning |
1372 | #endif |
1373 | |
1374 | namespace Catch { |
1375 | |
1376 | struct ITransientExpression { |
1377 | auto isBinaryExpression() const -> bool { return m_isBinaryExpression; } |
1378 | auto getResult() const -> bool { return m_result; } |
1379 | virtual void streamReconstructedExpression( std::ostream &os ) const = 0; |
1380 | |
1381 | ITransientExpression( bool isBinaryExpression, bool result ) |
1382 | : m_isBinaryExpression( isBinaryExpression ), |
1383 | m_result( result ) |
1384 | {} |
1385 | |
1386 | // We don't actually need a virtual destructor, but many static analysers |
1387 | // complain if it's not here :-( |
1388 | virtual ~ITransientExpression(); |
1389 | |
1390 | bool m_isBinaryExpression; |
1391 | bool m_result; |
1392 | |
1393 | }; |
1394 | |
1395 | void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ); |
1396 | |
1397 | template<typename LhsT, typename RhsT> |
1398 | class BinaryExpr : public ITransientExpression { |
1399 | LhsT m_lhs; |
1400 | StringRef m_op; |
1401 | RhsT m_rhs; |
1402 | |
1403 | void streamReconstructedExpression( std::ostream &os ) const override { |
1404 | formatReconstructedExpression |
1405 | ( os, Catch::Detail::stringify( m_lhs ), m_op, Catch::Detail::stringify( m_rhs ) ); |
1406 | } |
1407 | |
1408 | public: |
1409 | BinaryExpr( bool comparisonResult, LhsT lhs, StringRef op, RhsT rhs ) |
1410 | : ITransientExpression{ true, comparisonResult }, |
1411 | m_lhs( lhs ), |
1412 | m_op( op ), |
1413 | m_rhs( rhs ) |
1414 | {} |
1415 | }; |
1416 | |
1417 | template<typename LhsT> |
1418 | class UnaryExpr : public ITransientExpression { |
1419 | LhsT m_lhs; |
1420 | |
1421 | void streamReconstructedExpression( std::ostream &os ) const override { |
1422 | os << Catch::Detail::stringify( m_lhs ); |
1423 | } |
1424 | |
1425 | public: |
1426 | explicit UnaryExpr( LhsT lhs ) |
1427 | : ITransientExpression{ false, lhs ? true : false }, |
1428 | m_lhs( lhs ) |
1429 | {} |
1430 | }; |
1431 | |
1432 | // Specialised comparison functions to handle equality comparisons between ints and pointers (NULL deduces as an int) |
1433 | template<typename LhsT, typename RhsT> |
1434 | auto compareEqual( LhsT const& lhs, RhsT const& rhs ) -> bool { return static_cast<bool>(lhs == rhs); } |
1435 | template<typename T> |
1436 | auto compareEqual( T* const& lhs, int rhs ) -> bool { return lhs == reinterpret_cast<void const*>( rhs ); } |
1437 | template<typename T> |
1438 | auto compareEqual( T* const& lhs, long rhs ) -> bool { return lhs == reinterpret_cast<void const*>( rhs ); } |
1439 | template<typename T> |
1440 | auto compareEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) == rhs; } |
1441 | template<typename T> |
1442 | auto compareEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) == rhs; } |
1443 | |
1444 | template<typename LhsT, typename RhsT> |
1445 | auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return static_cast<bool>(lhs != rhs); } |
1446 | template<typename T> |
1447 | auto compareNotEqual( T* const& lhs, int rhs ) -> bool { return lhs != reinterpret_cast<void const*>( rhs ); } |
1448 | template<typename T> |
1449 | auto compareNotEqual( T* const& lhs, long rhs ) -> bool { return lhs != reinterpret_cast<void const*>( rhs ); } |
1450 | template<typename T> |
1451 | auto compareNotEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) != rhs; } |
1452 | template<typename T> |
1453 | auto compareNotEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) != rhs; } |
1454 | |
1455 | template<typename LhsT> |
1456 | class ExprLhs { |
1457 | LhsT m_lhs; |
1458 | public: |
1459 | explicit ExprLhs( LhsT lhs ) : m_lhs( lhs ) {} |
1460 | |
1461 | template<typename RhsT> |
1462 | auto operator == ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { |
1463 | return { compareEqual( m_lhs, rhs ), m_lhs, "==" , rhs }; |
1464 | } |
1465 | auto operator == ( bool rhs ) -> BinaryExpr<LhsT, bool> const { |
1466 | return { m_lhs == rhs, m_lhs, "==" , rhs }; |
1467 | } |
1468 | |
1469 | template<typename RhsT> |
1470 | auto operator != ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { |
1471 | return { compareNotEqual( m_lhs, rhs ), m_lhs, "!=" , rhs }; |
1472 | } |
1473 | auto operator != ( bool rhs ) -> BinaryExpr<LhsT, bool> const { |
1474 | return { m_lhs != rhs, m_lhs, "!=" , rhs }; |
1475 | } |
1476 | |
1477 | template<typename RhsT> |
1478 | auto operator > ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { |
1479 | return { static_cast<bool>(m_lhs > rhs), m_lhs, ">" , rhs }; |
1480 | } |
1481 | template<typename RhsT> |
1482 | auto operator < ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { |
1483 | return { static_cast<bool>(m_lhs < rhs), m_lhs, "<" , rhs }; |
1484 | } |
1485 | template<typename RhsT> |
1486 | auto operator >= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { |
1487 | return { static_cast<bool>(m_lhs >= rhs), m_lhs, ">=" , rhs }; |
1488 | } |
1489 | template<typename RhsT> |
1490 | auto operator <= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { |
1491 | return { static_cast<bool>(m_lhs <= rhs), m_lhs, "<=" , rhs }; |
1492 | } |
1493 | |
1494 | auto makeUnaryExpr() const -> UnaryExpr<LhsT> { |
1495 | return UnaryExpr<LhsT>{ m_lhs }; |
1496 | } |
1497 | }; |
1498 | |
1499 | void handleExpression( ITransientExpression const& expr ); |
1500 | |
1501 | template<typename T> |
1502 | void handleExpression( ExprLhs<T> const& expr ) { |
1503 | handleExpression( expr.makeUnaryExpr() ); |
1504 | } |
1505 | |
1506 | struct Decomposer { |
1507 | template<typename T> |
1508 | auto operator <= ( T const& lhs ) -> ExprLhs<T const&> { |
1509 | return ExprLhs<T const&>{ lhs }; |
1510 | } |
1511 | |
1512 | auto operator <=( bool value ) -> ExprLhs<bool> { |
1513 | return ExprLhs<bool>{ value }; |
1514 | } |
1515 | }; |
1516 | |
1517 | } // end namespace Catch |
1518 | |
1519 | #ifdef _MSC_VER |
1520 | #pragma warning(pop) |
1521 | #endif |
1522 | |
1523 | // end catch_decomposer.h |
1524 | // start catch_interfaces_capture.h |
1525 | |
1526 | #include <string> |
1527 | |
1528 | namespace Catch { |
1529 | |
1530 | class AssertionResult; |
1531 | struct AssertionInfo; |
1532 | struct SectionInfo; |
1533 | struct SectionEndInfo; |
1534 | struct MessageInfo; |
1535 | struct Counts; |
1536 | struct BenchmarkInfo; |
1537 | struct BenchmarkStats; |
1538 | struct AssertionReaction; |
1539 | struct SourceLineInfo; |
1540 | |
1541 | struct ITransientExpression; |
1542 | struct IGeneratorTracker; |
1543 | |
1544 | struct IResultCapture { |
1545 | |
1546 | virtual ~IResultCapture(); |
1547 | |
1548 | virtual bool sectionStarted( SectionInfo const& sectionInfo, |
1549 | Counts& assertions ) = 0; |
1550 | virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; |
1551 | virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; |
1552 | |
1553 | virtual auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0; |
1554 | |
1555 | virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0; |
1556 | virtual void benchmarkEnded( BenchmarkStats const& stats ) = 0; |
1557 | |
1558 | virtual void pushScopedMessage( MessageInfo const& message ) = 0; |
1559 | virtual void popScopedMessage( MessageInfo const& message ) = 0; |
1560 | |
1561 | virtual void handleFatalErrorCondition( StringRef message ) = 0; |
1562 | |
1563 | virtual void handleExpr |
1564 | ( AssertionInfo const& info, |
1565 | ITransientExpression const& expr, |
1566 | AssertionReaction& reaction ) = 0; |
1567 | virtual void handleMessage |
1568 | ( AssertionInfo const& info, |
1569 | ResultWas::OfType resultType, |
1570 | StringRef const& message, |
1571 | AssertionReaction& reaction ) = 0; |
1572 | virtual void handleUnexpectedExceptionNotThrown |
1573 | ( AssertionInfo const& info, |
1574 | AssertionReaction& reaction ) = 0; |
1575 | virtual void handleUnexpectedInflightException |
1576 | ( AssertionInfo const& info, |
1577 | std::string const& message, |
1578 | AssertionReaction& reaction ) = 0; |
1579 | virtual void handleIncomplete |
1580 | ( AssertionInfo const& info ) = 0; |
1581 | virtual void handleNonExpr |
1582 | ( AssertionInfo const &info, |
1583 | ResultWas::OfType resultType, |
1584 | AssertionReaction &reaction ) = 0; |
1585 | |
1586 | virtual bool lastAssertionPassed() = 0; |
1587 | virtual void assertionPassed() = 0; |
1588 | |
1589 | // Deprecated, do not use: |
1590 | virtual std::string getCurrentTestName() const = 0; |
1591 | virtual const AssertionResult* getLastResult() const = 0; |
1592 | virtual void exceptionEarlyReported() = 0; |
1593 | }; |
1594 | |
1595 | IResultCapture& getResultCapture(); |
1596 | } |
1597 | |
1598 | // end catch_interfaces_capture.h |
1599 | namespace Catch { |
1600 | |
1601 | struct TestFailureException{}; |
1602 | struct AssertionResultData; |
1603 | struct IResultCapture; |
1604 | class RunContext; |
1605 | |
1606 | class LazyExpression { |
1607 | friend class AssertionHandler; |
1608 | friend struct AssertionStats; |
1609 | friend class RunContext; |
1610 | |
1611 | ITransientExpression const* m_transientExpression = nullptr; |
1612 | bool m_isNegated; |
1613 | public: |
1614 | LazyExpression( bool isNegated ); |
1615 | LazyExpression( LazyExpression const& other ); |
1616 | LazyExpression& operator = ( LazyExpression const& ) = delete; |
1617 | |
1618 | explicit operator bool() const; |
1619 | |
1620 | friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&; |
1621 | }; |
1622 | |
1623 | struct AssertionReaction { |
1624 | bool shouldDebugBreak = false; |
1625 | bool shouldThrow = false; |
1626 | }; |
1627 | |
1628 | class AssertionHandler { |
1629 | AssertionInfo m_assertionInfo; |
1630 | AssertionReaction m_reaction; |
1631 | bool m_completed = false; |
1632 | IResultCapture& m_resultCapture; |
1633 | |
1634 | public: |
1635 | AssertionHandler |
1636 | ( StringRef const& macroName, |
1637 | SourceLineInfo const& lineInfo, |
1638 | StringRef capturedExpression, |
1639 | ResultDisposition::Flags resultDisposition ); |
1640 | ~AssertionHandler() { |
1641 | if ( !m_completed ) { |
1642 | m_resultCapture.handleIncomplete( m_assertionInfo ); |
1643 | } |
1644 | } |
1645 | |
1646 | template<typename T> |
1647 | void handleExpr( ExprLhs<T> const& expr ) { |
1648 | handleExpr( expr.makeUnaryExpr() ); |
1649 | } |
1650 | void handleExpr( ITransientExpression const& expr ); |
1651 | |
1652 | void handleMessage(ResultWas::OfType resultType, StringRef const& message); |
1653 | |
1654 | void handleExceptionThrownAsExpected(); |
1655 | void handleUnexpectedExceptionNotThrown(); |
1656 | void handleExceptionNotThrownAsExpected(); |
1657 | void handleThrowingCallSkipped(); |
1658 | void handleUnexpectedInflightException(); |
1659 | |
1660 | void complete(); |
1661 | void setCompleted(); |
1662 | |
1663 | // query |
1664 | auto allowThrows() const -> bool; |
1665 | }; |
1666 | |
1667 | void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef const& matcherString ); |
1668 | |
1669 | } // namespace Catch |
1670 | |
1671 | // end catch_assertionhandler.h |
1672 | // start catch_message.h |
1673 | |
1674 | #include <string> |
1675 | #include <vector> |
1676 | |
1677 | namespace Catch { |
1678 | |
1679 | struct MessageInfo { |
1680 | MessageInfo( StringRef const& _macroName, |
1681 | SourceLineInfo const& _lineInfo, |
1682 | ResultWas::OfType _type ); |
1683 | |
1684 | StringRef macroName; |
1685 | std::string message; |
1686 | SourceLineInfo lineInfo; |
1687 | ResultWas::OfType type; |
1688 | unsigned int sequence; |
1689 | |
1690 | bool operator == ( MessageInfo const& other ) const; |
1691 | bool operator < ( MessageInfo const& other ) const; |
1692 | private: |
1693 | static unsigned int globalCount; |
1694 | }; |
1695 | |
1696 | struct MessageStream { |
1697 | |
1698 | template<typename T> |
1699 | MessageStream& operator << ( T const& value ) { |
1700 | m_stream << value; |
1701 | return *this; |
1702 | } |
1703 | |
1704 | ReusableStringStream m_stream; |
1705 | }; |
1706 | |
1707 | struct MessageBuilder : MessageStream { |
1708 | MessageBuilder( StringRef const& macroName, |
1709 | SourceLineInfo const& lineInfo, |
1710 | ResultWas::OfType type ); |
1711 | |
1712 | template<typename T> |
1713 | MessageBuilder& operator << ( T const& value ) { |
1714 | m_stream << value; |
1715 | return *this; |
1716 | } |
1717 | |
1718 | MessageInfo m_info; |
1719 | }; |
1720 | |
1721 | class ScopedMessage { |
1722 | public: |
1723 | explicit ScopedMessage( MessageBuilder const& builder ); |
1724 | ~ScopedMessage(); |
1725 | |
1726 | MessageInfo m_info; |
1727 | }; |
1728 | |
1729 | class Capturer { |
1730 | std::vector<MessageInfo> m_messages; |
1731 | IResultCapture& m_resultCapture = getResultCapture(); |
1732 | size_t m_captured = 0; |
1733 | public: |
1734 | Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ); |
1735 | ~Capturer(); |
1736 | |
1737 | void captureValue( size_t index, StringRef value ); |
1738 | |
1739 | template<typename T> |
1740 | void captureValues( size_t index, T&& value ) { |
1741 | captureValue( index, Catch::Detail::stringify( value ) ); |
1742 | } |
1743 | |
1744 | template<typename T, typename... Ts> |
1745 | void captureValues( size_t index, T&& value, Ts&&... values ) { |
1746 | captureValues( index, value ); |
1747 | captureValues( index+1, values... ); |
1748 | } |
1749 | }; |
1750 | |
1751 | } // end namespace Catch |
1752 | |
1753 | // end catch_message.h |
1754 | #if !defined(CATCH_CONFIG_DISABLE) |
1755 | |
1756 | #if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION) |
1757 | #define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__ |
1758 | #else |
1759 | #define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION" |
1760 | #endif |
1761 | |
1762 | #if defined(CATCH_CONFIG_FAST_COMPILE) || defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) |
1763 | |
1764 | /////////////////////////////////////////////////////////////////////////////// |
1765 | // Another way to speed-up compilation is to omit local try-catch for REQUIRE* |
1766 | // macros. |
1767 | #define INTERNAL_CATCH_TRY |
1768 | #define INTERNAL_CATCH_CATCH( capturer ) |
1769 | |
1770 | #else // CATCH_CONFIG_FAST_COMPILE |
1771 | |
1772 | #define INTERNAL_CATCH_TRY try |
1773 | #define INTERNAL_CATCH_CATCH( handler ) catch(...) { handler.handleUnexpectedInflightException(); } |
1774 | |
1775 | #endif |
1776 | |
1777 | #define INTERNAL_CATCH_REACT( handler ) handler.complete(); |
1778 | |
1779 | /////////////////////////////////////////////////////////////////////////////// |
1780 | #define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \ |
1781 | do { \ |
1782 | Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ |
1783 | INTERNAL_CATCH_TRY { \ |
1784 | CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ |
1785 | catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); \ |
1786 | CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \ |
1787 | } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ |
1788 | INTERNAL_CATCH_REACT( catchAssertionHandler ) \ |
1789 | } 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 |
1790 | // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&. |
1791 | |
1792 | /////////////////////////////////////////////////////////////////////////////// |
1793 | #define INTERNAL_CATCH_IF( macroName, resultDisposition, ... ) \ |
1794 | INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \ |
1795 | if( Catch::getResultCapture().lastAssertionPassed() ) |
1796 | |
1797 | /////////////////////////////////////////////////////////////////////////////// |
1798 | #define INTERNAL_CATCH_ELSE( macroName, resultDisposition, ... ) \ |
1799 | INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \ |
1800 | if( !Catch::getResultCapture().lastAssertionPassed() ) |
1801 | |
1802 | /////////////////////////////////////////////////////////////////////////////// |
1803 | #define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \ |
1804 | do { \ |
1805 | Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ |
1806 | try { \ |
1807 | static_cast<void>(__VA_ARGS__); \ |
1808 | catchAssertionHandler.handleExceptionNotThrownAsExpected(); \ |
1809 | } \ |
1810 | catch( ... ) { \ |
1811 | catchAssertionHandler.handleUnexpectedInflightException(); \ |
1812 | } \ |
1813 | INTERNAL_CATCH_REACT( catchAssertionHandler ) \ |
1814 | } while( false ) |
1815 | |
1816 | /////////////////////////////////////////////////////////////////////////////// |
1817 | #define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \ |
1818 | do { \ |
1819 | Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition); \ |
1820 | if( catchAssertionHandler.allowThrows() ) \ |
1821 | try { \ |
1822 | static_cast<void>(__VA_ARGS__); \ |
1823 | catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ |
1824 | } \ |
1825 | catch( ... ) { \ |
1826 | catchAssertionHandler.handleExceptionThrownAsExpected(); \ |
1827 | } \ |
1828 | else \ |
1829 | catchAssertionHandler.handleThrowingCallSkipped(); \ |
1830 | INTERNAL_CATCH_REACT( catchAssertionHandler ) \ |
1831 | } while( false ) |
1832 | |
1833 | /////////////////////////////////////////////////////////////////////////////// |
1834 | #define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \ |
1835 | do { \ |
1836 | Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \ |
1837 | if( catchAssertionHandler.allowThrows() ) \ |
1838 | try { \ |
1839 | static_cast<void>(expr); \ |
1840 | catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ |
1841 | } \ |
1842 | catch( exceptionType const& ) { \ |
1843 | catchAssertionHandler.handleExceptionThrownAsExpected(); \ |
1844 | } \ |
1845 | catch( ... ) { \ |
1846 | catchAssertionHandler.handleUnexpectedInflightException(); \ |
1847 | } \ |
1848 | else \ |
1849 | catchAssertionHandler.handleThrowingCallSkipped(); \ |
1850 | INTERNAL_CATCH_REACT( catchAssertionHandler ) \ |
1851 | } while( false ) |
1852 | |
1853 | /////////////////////////////////////////////////////////////////////////////// |
1854 | #define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \ |
1855 | do { \ |
1856 | Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::StringRef(), resultDisposition ); \ |
1857 | catchAssertionHandler.handleMessage( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \ |
1858 | INTERNAL_CATCH_REACT( catchAssertionHandler ) \ |
1859 | } while( false ) |
1860 | |
1861 | /////////////////////////////////////////////////////////////////////////////// |
1862 | #define INTERNAL_CATCH_CAPTURE( varName, macroName, ... ) \ |
1863 | auto varName = Catch::Capturer( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info, #__VA_ARGS__ ); \ |
1864 | varName.captureValues( 0, __VA_ARGS__ ) |
1865 | |
1866 | /////////////////////////////////////////////////////////////////////////////// |
1867 | #define INTERNAL_CATCH_INFO( macroName, log ) \ |
1868 | Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log ); |
1869 | |
1870 | /////////////////////////////////////////////////////////////////////////////// |
1871 | // Although this is matcher-based, it can be used with just a string |
1872 | #define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \ |
1873 | do { \ |
1874 | Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ |
1875 | if( catchAssertionHandler.allowThrows() ) \ |
1876 | try { \ |
1877 | static_cast<void>(__VA_ARGS__); \ |
1878 | catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ |
1879 | } \ |
1880 | catch( ... ) { \ |
1881 | Catch::handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher##_catch_sr ); \ |
1882 | } \ |
1883 | else \ |
1884 | catchAssertionHandler.handleThrowingCallSkipped(); \ |
1885 | INTERNAL_CATCH_REACT( catchAssertionHandler ) \ |
1886 | } while( false ) |
1887 | |
1888 | #endif // CATCH_CONFIG_DISABLE |
1889 | |
1890 | // end catch_capture.hpp |
1891 | // start catch_section.h |
1892 | |
1893 | // start catch_section_info.h |
1894 | |
1895 | // start catch_totals.h |
1896 | |
1897 | #include <cstddef> |
1898 | |
1899 | namespace Catch { |
1900 | |
1901 | struct Counts { |
1902 | Counts operator - ( Counts const& other ) const; |
1903 | Counts& operator += ( Counts const& other ); |
1904 | |
1905 | std::size_t total() const; |
1906 | bool allPassed() const; |
1907 | bool allOk() const; |
1908 | |
1909 | std::size_t passed = 0; |
1910 | std::size_t failed = 0; |
1911 | std::size_t failedButOk = 0; |
1912 | }; |
1913 | |
1914 | struct Totals { |
1915 | |
1916 | Totals operator - ( Totals const& other ) const; |
1917 | Totals& operator += ( Totals const& other ); |
1918 | |
1919 | Totals delta( Totals const& prevTotals ) const; |
1920 | |
1921 | int error = 0; |
1922 | Counts assertions; |
1923 | Counts testCases; |
1924 | }; |
1925 | } |
1926 | |
1927 | // end catch_totals.h |
1928 | #include <string> |
1929 | |
1930 | namespace Catch { |
1931 | |
1932 | struct SectionInfo { |
1933 | SectionInfo |
1934 | ( SourceLineInfo const& _lineInfo, |
1935 | std::string const& _name ); |
1936 | |
1937 | // Deprecated |
1938 | SectionInfo |
1939 | ( SourceLineInfo const& _lineInfo, |
1940 | std::string const& _name, |
1941 | std::string const& ) : SectionInfo( _lineInfo, _name ) {} |
1942 | |
1943 | std::string name; |
1944 | std::string description; // !Deprecated: this will always be empty |
1945 | SourceLineInfo lineInfo; |
1946 | }; |
1947 | |
1948 | struct SectionEndInfo { |
1949 | SectionInfo sectionInfo; |
1950 | Counts prevAssertions; |
1951 | double durationInSeconds; |
1952 | }; |
1953 | |
1954 | } // end namespace Catch |
1955 | |
1956 | // end catch_section_info.h |
1957 | // start catch_timer.h |
1958 | |
1959 | #include <cstdint> |
1960 | |
1961 | namespace Catch { |
1962 | |
1963 | auto getCurrentNanosecondsSinceEpoch() -> uint64_t; |
1964 | auto getEstimatedClockResolution() -> uint64_t; |
1965 | |
1966 | class Timer { |
1967 | uint64_t m_nanoseconds = 0; |
1968 | public: |
1969 | void start(); |
1970 | auto getElapsedNanoseconds() const -> uint64_t; |
1971 | auto getElapsedMicroseconds() const -> uint64_t; |
1972 | auto getElapsedMilliseconds() const -> unsigned int; |
1973 | auto getElapsedSeconds() const -> double; |
1974 | }; |
1975 | |
1976 | } // namespace Catch |
1977 | |
1978 | // end catch_timer.h |
1979 | #include <string> |
1980 | |
1981 | namespace Catch { |
1982 | |
1983 | class Section : NonCopyable { |
1984 | public: |
1985 | Section( SectionInfo const& info ); |
1986 | ~Section(); |
1987 | |
1988 | // This indicates whether the section should be executed or not |
1989 | explicit operator bool() const; |
1990 | |
1991 | private: |
1992 | SectionInfo m_info; |
1993 | |
1994 | std::string m_name; |
1995 | Counts m_assertions; |
1996 | bool m_sectionIncluded; |
1997 | Timer m_timer; |
1998 | }; |
1999 | |
2000 | } // end namespace Catch |
2001 | |
2002 | #define INTERNAL_CATCH_SECTION( ... ) \ |
2003 | CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ |
2004 | if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \ |
2005 | CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS |
2006 | |
2007 | #define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \ |
2008 | CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ |
2009 | if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, (Catch::ReusableStringStream() << __VA_ARGS__).str() ) ) \ |
2010 | CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS |
2011 | |
2012 | // end catch_section.h |
2013 | // start catch_benchmark.h |
2014 | |
2015 | #include <cstdint> |
2016 | #include <string> |
2017 | |
2018 | namespace Catch { |
2019 | |
2020 | class BenchmarkLooper { |
2021 | |
2022 | std::string m_name; |
2023 | std::size_t m_count = 0; |
2024 | std::size_t m_iterationsToRun = 1; |
2025 | uint64_t m_resolution; |
2026 | Timer m_timer; |
2027 | |
2028 | static auto getResolution() -> uint64_t; |
2029 | public: |
2030 | // Keep most of this inline as it's on the code path that is being timed |
2031 | BenchmarkLooper( StringRef name ) |
2032 | : m_name( name ), |
2033 | m_resolution( getResolution() ) |
2034 | { |
2035 | reportStart(); |
2036 | m_timer.start(); |
2037 | } |
2038 | |
2039 | explicit operator bool() { |
2040 | if( m_count < m_iterationsToRun ) |
2041 | return true; |
2042 | return needsMoreIterations(); |
2043 | } |
2044 | |
2045 | void increment() { |
2046 | ++m_count; |
2047 | } |
2048 | |
2049 | void reportStart(); |
2050 | auto needsMoreIterations() -> bool; |
2051 | }; |
2052 | |
2053 | } // end namespace Catch |
2054 | |
2055 | #define BENCHMARK( name ) \ |
2056 | for( Catch::BenchmarkLooper looper( name ); looper; looper.increment() ) |
2057 | |
2058 | // end catch_benchmark.h |
2059 | // start catch_interfaces_exception.h |
2060 | |
2061 | // start catch_interfaces_registry_hub.h |
2062 | |
2063 | #include <string> |
2064 | #include <memory> |
2065 | |
2066 | namespace Catch { |
2067 | |
2068 | class TestCase; |
2069 | struct ITestCaseRegistry; |
2070 | struct IExceptionTranslatorRegistry; |
2071 | struct IExceptionTranslator; |
2072 | struct IReporterRegistry; |
2073 | struct IReporterFactory; |
2074 | struct ITagAliasRegistry; |
2075 | class StartupExceptionRegistry; |
2076 | |
2077 | using IReporterFactoryPtr = std::shared_ptr<IReporterFactory>; |
2078 | |
2079 | struct IRegistryHub { |
2080 | virtual ~IRegistryHub(); |
2081 | |
2082 | virtual IReporterRegistry const& getReporterRegistry() const = 0; |
2083 | virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; |
2084 | virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0; |
2085 | |
2086 | virtual IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const = 0; |
2087 | |
2088 | virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0; |
2089 | }; |
2090 | |
2091 | struct IMutableRegistryHub { |
2092 | virtual ~IMutableRegistryHub(); |
2093 | virtual void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) = 0; |
2094 | virtual void registerListener( IReporterFactoryPtr const& factory ) = 0; |
2095 | virtual void registerTest( TestCase const& testInfo ) = 0; |
2096 | virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; |
2097 | virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0; |
2098 | virtual void registerStartupException() noexcept = 0; |
2099 | }; |
2100 | |
2101 | IRegistryHub const& getRegistryHub(); |
2102 | IMutableRegistryHub& getMutableRegistryHub(); |
2103 | void cleanUp(); |
2104 | std::string translateActiveException(); |
2105 | |
2106 | } |
2107 | |
2108 | // end catch_interfaces_registry_hub.h |
2109 | #if defined(CATCH_CONFIG_DISABLE) |
2110 | #define INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( translatorName, signature) \ |
2111 | static std::string translatorName( signature ) |
2112 | #endif |
2113 | |
2114 | #include <exception> |
2115 | #include <string> |
2116 | #include <vector> |
2117 | |
2118 | namespace Catch { |
2119 | using exceptionTranslateFunction = std::string(*)(); |
2120 | |
2121 | struct IExceptionTranslator; |
2122 | using ExceptionTranslators = std::vector<std::unique_ptr<IExceptionTranslator const>>; |
2123 | |
2124 | struct IExceptionTranslator { |
2125 | virtual ~IExceptionTranslator(); |
2126 | virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0; |
2127 | }; |
2128 | |
2129 | struct IExceptionTranslatorRegistry { |
2130 | virtual ~IExceptionTranslatorRegistry(); |
2131 | |
2132 | virtual std::string translateActiveException() const = 0; |
2133 | }; |
2134 | |
2135 | class ExceptionTranslatorRegistrar { |
2136 | template<typename T> |
2137 | class ExceptionTranslator : public IExceptionTranslator { |
2138 | public: |
2139 | |
2140 | ExceptionTranslator( std::string(*translateFunction)( T& ) ) |
2141 | : m_translateFunction( translateFunction ) |
2142 | {} |
2143 | |
2144 | std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const override { |
2145 | try { |
2146 | if( it == itEnd ) |
2147 | std::rethrow_exception(std::current_exception()); |
2148 | else |
2149 | return (*it)->translate( it+1, itEnd ); |
2150 | } |
2151 | catch( T& ex ) { |
2152 | return m_translateFunction( ex ); |
2153 | } |
2154 | } |
2155 | |
2156 | protected: |
2157 | std::string(*m_translateFunction)( T& ); |
2158 | }; |
2159 | |
2160 | public: |
2161 | template<typename T> |
2162 | ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) { |
2163 | getMutableRegistryHub().registerTranslator |
2164 | ( new ExceptionTranslator<T>( translateFunction ) ); |
2165 | } |
2166 | }; |
2167 | } |
2168 | |
2169 | /////////////////////////////////////////////////////////////////////////////// |
2170 | #define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \ |
2171 | static std::string translatorName( signature ); \ |
2172 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ |
2173 | namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); } \ |
2174 | CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \ |
2175 | static std::string translatorName( signature ) |
2176 | |
2177 | #define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) |
2178 | |
2179 | // end catch_interfaces_exception.h |
2180 | // start catch_approx.h |
2181 | |
2182 | #include <type_traits> |
2183 | |
2184 | namespace Catch { |
2185 | namespace Detail { |
2186 | |
2187 | class Approx { |
2188 | private: |
2189 | bool equalityComparisonImpl(double other) const; |
2190 | // Validates the new margin (margin >= 0) |
2191 | // out-of-line to avoid including stdexcept in the header |
2192 | void setMargin(double margin); |
2193 | // Validates the new epsilon (0 < epsilon < 1) |
2194 | // out-of-line to avoid including stdexcept in the header |
2195 | void setEpsilon(double epsilon); |
2196 | |
2197 | public: |
2198 | explicit Approx ( double value ); |
2199 | |
2200 | static Approx custom(); |
2201 | |
2202 | Approx operator-() const; |
2203 | |
2204 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
2205 | Approx operator()( T const& value ) { |
2206 | Approx approx( static_cast<double>(value) ); |
2207 | approx.m_epsilon = m_epsilon; |
2208 | approx.m_margin = m_margin; |
2209 | approx.m_scale = m_scale; |
2210 | return approx; |
2211 | } |
2212 | |
2213 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
2214 | explicit Approx( T const& value ): Approx(static_cast<double>(value)) |
2215 | {} |
2216 | |
2217 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
2218 | friend bool operator == ( const T& lhs, Approx const& rhs ) { |
2219 | auto lhs_v = static_cast<double>(lhs); |
2220 | return rhs.equalityComparisonImpl(lhs_v); |
2221 | } |
2222 | |
2223 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
2224 | friend bool operator == ( Approx const& lhs, const T& rhs ) { |
2225 | return operator==( rhs, lhs ); |
2226 | } |
2227 | |
2228 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
2229 | friend bool operator != ( T const& lhs, Approx const& rhs ) { |
2230 | return !operator==( lhs, rhs ); |
2231 | } |
2232 | |
2233 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
2234 | friend bool operator != ( Approx const& lhs, T const& rhs ) { |
2235 | return !operator==( rhs, lhs ); |
2236 | } |
2237 | |
2238 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
2239 | friend bool operator <= ( T const& lhs, Approx const& rhs ) { |
2240 | return static_cast<double>(lhs) < rhs.m_value || lhs == rhs; |
2241 | } |
2242 | |
2243 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
2244 | friend bool operator <= ( Approx const& lhs, T const& rhs ) { |
2245 | return lhs.m_value < static_cast<double>(rhs) || lhs == rhs; |
2246 | } |
2247 | |
2248 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
2249 | friend bool operator >= ( T const& lhs, Approx const& rhs ) { |
2250 | return static_cast<double>(lhs) > rhs.m_value || lhs == rhs; |
2251 | } |
2252 | |
2253 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
2254 | friend bool operator >= ( Approx const& lhs, T const& rhs ) { |
2255 | return lhs.m_value > static_cast<double>(rhs) || lhs == rhs; |
2256 | } |
2257 | |
2258 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
2259 | Approx& epsilon( T const& newEpsilon ) { |
2260 | double epsilonAsDouble = static_cast<double>(newEpsilon); |
2261 | setEpsilon(epsilonAsDouble); |
2262 | return *this; |
2263 | } |
2264 | |
2265 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
2266 | Approx& margin( T const& newMargin ) { |
2267 | double marginAsDouble = static_cast<double>(newMargin); |
2268 | setMargin(marginAsDouble); |
2269 | return *this; |
2270 | } |
2271 | |
2272 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
2273 | Approx& scale( T const& newScale ) { |
2274 | m_scale = static_cast<double>(newScale); |
2275 | return *this; |
2276 | } |
2277 | |
2278 | std::string toString() const; |
2279 | |
2280 | private: |
2281 | double m_epsilon; |
2282 | double m_margin; |
2283 | double m_scale; |
2284 | double m_value; |
2285 | }; |
2286 | } // end namespace Detail |
2287 | |
2288 | namespace literals { |
2289 | Detail::Approx operator "" _a(long double val); |
2290 | Detail::Approx operator "" _a(unsigned long long val); |
2291 | } // end namespace literals |
2292 | |
2293 | template<> |
2294 | struct StringMaker<Catch::Detail::Approx> { |
2295 | static std::string convert(Catch::Detail::Approx const& value); |
2296 | }; |
2297 | |
2298 | } // end namespace Catch |
2299 | |
2300 | // end catch_approx.h |
2301 | // start catch_string_manip.h |
2302 | |
2303 | #include <string> |
2304 | #include <iosfwd> |
2305 | |
2306 | namespace Catch { |
2307 | |
2308 | bool startsWith( std::string const& s, std::string const& prefix ); |
2309 | bool startsWith( std::string const& s, char prefix ); |
2310 | bool endsWith( std::string const& s, std::string const& suffix ); |
2311 | bool endsWith( std::string const& s, char suffix ); |
2312 | bool contains( std::string const& s, std::string const& infix ); |
2313 | void toLowerInPlace( std::string& s ); |
2314 | std::string toLower( std::string const& s ); |
2315 | std::string trim( std::string const& str ); |
2316 | bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); |
2317 | |
2318 | struct pluralise { |
2319 | pluralise( std::size_t count, std::string const& label ); |
2320 | |
2321 | friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ); |
2322 | |
2323 | std::size_t m_count; |
2324 | std::string m_label; |
2325 | }; |
2326 | } |
2327 | |
2328 | // end catch_string_manip.h |
2329 | #ifndef CATCH_CONFIG_DISABLE_MATCHERS |
2330 | // start catch_capture_matchers.h |
2331 | |
2332 | // start catch_matchers.h |
2333 | |
2334 | #include <string> |
2335 | #include <vector> |
2336 | |
2337 | namespace Catch { |
2338 | namespace Matchers { |
2339 | namespace Impl { |
2340 | |
2341 | template<typename ArgT> struct MatchAllOf; |
2342 | template<typename ArgT> struct MatchAnyOf; |
2343 | template<typename ArgT> struct MatchNotOf; |
2344 | |
2345 | class MatcherUntypedBase { |
2346 | public: |
2347 | MatcherUntypedBase() = default; |
2348 | MatcherUntypedBase ( MatcherUntypedBase const& ) = default; |
2349 | MatcherUntypedBase& operator = ( MatcherUntypedBase const& ) = delete; |
2350 | std::string toString() const; |
2351 | |
2352 | protected: |
2353 | virtual ~MatcherUntypedBase(); |
2354 | virtual std::string describe() const = 0; |
2355 | mutable std::string m_cachedToString; |
2356 | }; |
2357 | |
2358 | #ifdef __clang__ |
2359 | # pragma clang diagnostic push |
2360 | # pragma clang diagnostic ignored "-Wnon-virtual-dtor" |
2361 | #endif |
2362 | |
2363 | template<typename ObjectT> |
2364 | struct MatcherMethod { |
2365 | virtual bool match( ObjectT const& arg ) const = 0; |
2366 | }; |
2367 | template<typename PtrT> |
2368 | struct MatcherMethod<PtrT*> { |
2369 | virtual bool match( PtrT* arg ) const = 0; |
2370 | }; |
2371 | |
2372 | #ifdef __clang__ |
2373 | # pragma clang diagnostic pop |
2374 | #endif |
2375 | |
2376 | template<typename T> |
2377 | struct MatcherBase : MatcherUntypedBase, MatcherMethod<T> { |
2378 | |
2379 | MatchAllOf<T> operator && ( MatcherBase const& other ) const; |
2380 | MatchAnyOf<T> operator || ( MatcherBase const& other ) const; |
2381 | MatchNotOf<T> operator ! () const; |
2382 | }; |
2383 | |
2384 | template<typename ArgT> |
2385 | struct MatchAllOf : MatcherBase<ArgT> { |
2386 | bool match( ArgT const& arg ) const override { |
2387 | for( auto matcher : m_matchers ) { |
2388 | if (!matcher->match(arg)) |
2389 | return false; |
2390 | } |
2391 | return true; |
2392 | } |
2393 | std::string describe() const override { |
2394 | std::string description; |
2395 | description.reserve( 4 + m_matchers.size()*32 ); |
2396 | description += "( " ; |
2397 | bool first = true; |
2398 | for( auto matcher : m_matchers ) { |
2399 | if( first ) |
2400 | first = false; |
2401 | else |
2402 | description += " and " ; |
2403 | description += matcher->toString(); |
2404 | } |
2405 | description += " )" ; |
2406 | return description; |
2407 | } |
2408 | |
2409 | MatchAllOf<ArgT>& operator && ( MatcherBase<ArgT> const& other ) { |
2410 | m_matchers.push_back( &other ); |
2411 | return *this; |
2412 | } |
2413 | |
2414 | std::vector<MatcherBase<ArgT> const*> m_matchers; |
2415 | }; |
2416 | template<typename ArgT> |
2417 | struct MatchAnyOf : MatcherBase<ArgT> { |
2418 | |
2419 | bool match( ArgT const& arg ) const override { |
2420 | for( auto matcher : m_matchers ) { |
2421 | if (matcher->match(arg)) |
2422 | return true; |
2423 | } |
2424 | return false; |
2425 | } |
2426 | std::string describe() const override { |
2427 | std::string description; |
2428 | description.reserve( 4 + m_matchers.size()*32 ); |
2429 | description += "( " ; |
2430 | bool first = true; |
2431 | for( auto matcher : m_matchers ) { |
2432 | if( first ) |
2433 | first = false; |
2434 | else |
2435 | description += " or " ; |
2436 | description += matcher->toString(); |
2437 | } |
2438 | description += " )" ; |
2439 | return description; |
2440 | } |
2441 | |
2442 | MatchAnyOf<ArgT>& operator || ( MatcherBase<ArgT> const& other ) { |
2443 | m_matchers.push_back( &other ); |
2444 | return *this; |
2445 | } |
2446 | |
2447 | std::vector<MatcherBase<ArgT> const*> m_matchers; |
2448 | }; |
2449 | |
2450 | template<typename ArgT> |
2451 | struct MatchNotOf : MatcherBase<ArgT> { |
2452 | |
2453 | MatchNotOf( MatcherBase<ArgT> const& underlyingMatcher ) : m_underlyingMatcher( underlyingMatcher ) {} |
2454 | |
2455 | bool match( ArgT const& arg ) const override { |
2456 | return !m_underlyingMatcher.match( arg ); |
2457 | } |
2458 | |
2459 | std::string describe() const override { |
2460 | return "not " + m_underlyingMatcher.toString(); |
2461 | } |
2462 | MatcherBase<ArgT> const& m_underlyingMatcher; |
2463 | }; |
2464 | |
2465 | template<typename T> |
2466 | MatchAllOf<T> MatcherBase<T>::operator && ( MatcherBase const& other ) const { |
2467 | return MatchAllOf<T>() && *this && other; |
2468 | } |
2469 | template<typename T> |
2470 | MatchAnyOf<T> MatcherBase<T>::operator || ( MatcherBase const& other ) const { |
2471 | return MatchAnyOf<T>() || *this || other; |
2472 | } |
2473 | template<typename T> |
2474 | MatchNotOf<T> MatcherBase<T>::operator ! () const { |
2475 | return MatchNotOf<T>( *this ); |
2476 | } |
2477 | |
2478 | } // namespace Impl |
2479 | |
2480 | } // namespace Matchers |
2481 | |
2482 | using namespace Matchers; |
2483 | using Matchers::Impl::MatcherBase; |
2484 | |
2485 | } // namespace Catch |
2486 | |
2487 | // end catch_matchers.h |
2488 | // start catch_matchers_floating.h |
2489 | |
2490 | #include <type_traits> |
2491 | #include <cmath> |
2492 | |
2493 | namespace Catch { |
2494 | namespace Matchers { |
2495 | |
2496 | namespace Floating { |
2497 | |
2498 | enum class FloatingPointKind : uint8_t; |
2499 | |
2500 | struct WithinAbsMatcher : MatcherBase<double> { |
2501 | WithinAbsMatcher(double target, double margin); |
2502 | bool match(double const& matchee) const override; |
2503 | std::string describe() const override; |
2504 | private: |
2505 | double m_target; |
2506 | double m_margin; |
2507 | }; |
2508 | |
2509 | struct WithinUlpsMatcher : MatcherBase<double> { |
2510 | WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType); |
2511 | bool match(double const& matchee) const override; |
2512 | std::string describe() const override; |
2513 | private: |
2514 | double m_target; |
2515 | int m_ulps; |
2516 | FloatingPointKind m_type; |
2517 | }; |
2518 | |
2519 | } // namespace Floating |
2520 | |
2521 | // The following functions create the actual matcher objects. |
2522 | // This allows the types to be inferred |
2523 | Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff); |
2524 | Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff); |
2525 | Floating::WithinAbsMatcher WithinAbs(double target, double margin); |
2526 | |
2527 | } // namespace Matchers |
2528 | } // namespace Catch |
2529 | |
2530 | // end catch_matchers_floating.h |
2531 | // start catch_matchers_generic.hpp |
2532 | |
2533 | #include <functional> |
2534 | #include <string> |
2535 | |
2536 | namespace Catch { |
2537 | namespace Matchers { |
2538 | namespace Generic { |
2539 | |
2540 | namespace Detail { |
2541 | std::string finalizeDescription(const std::string& desc); |
2542 | } |
2543 | |
2544 | template <typename T> |
2545 | class PredicateMatcher : public MatcherBase<T> { |
2546 | std::function<bool(T const&)> m_predicate; |
2547 | std::string m_description; |
2548 | public: |
2549 | |
2550 | PredicateMatcher(std::function<bool(T const&)> const& elem, std::string const& descr) |
2551 | :m_predicate(std::move(elem)), |
2552 | m_description(Detail::finalizeDescription(descr)) |
2553 | {} |
2554 | |
2555 | bool match( T const& item ) const override { |
2556 | return m_predicate(item); |
2557 | } |
2558 | |
2559 | std::string describe() const override { |
2560 | return m_description; |
2561 | } |
2562 | }; |
2563 | |
2564 | } // namespace Generic |
2565 | |
2566 | // The following functions create the actual matcher objects. |
2567 | // The user has to explicitly specify type to the function, because |
2568 | // infering std::function<bool(T const&)> is hard (but possible) and |
2569 | // requires a lot of TMP. |
2570 | template<typename T> |
2571 | Generic::PredicateMatcher<T> Predicate(std::function<bool(T const&)> const& predicate, std::string const& description = "" ) { |
2572 | return Generic::PredicateMatcher<T>(predicate, description); |
2573 | } |
2574 | |
2575 | } // namespace Matchers |
2576 | } // namespace Catch |
2577 | |
2578 | // end catch_matchers_generic.hpp |
2579 | // start catch_matchers_string.h |
2580 | |
2581 | #include <string> |
2582 | |
2583 | namespace Catch { |
2584 | namespace Matchers { |
2585 | |
2586 | namespace StdString { |
2587 | |
2588 | struct CasedString |
2589 | { |
2590 | CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ); |
2591 | std::string adjustString( std::string const& str ) const; |
2592 | std::string caseSensitivitySuffix() const; |
2593 | |
2594 | CaseSensitive::Choice m_caseSensitivity; |
2595 | std::string m_str; |
2596 | }; |
2597 | |
2598 | struct StringMatcherBase : MatcherBase<std::string> { |
2599 | StringMatcherBase( std::string const& operation, CasedString const& comparator ); |
2600 | std::string describe() const override; |
2601 | |
2602 | CasedString m_comparator; |
2603 | std::string m_operation; |
2604 | }; |
2605 | |
2606 | struct EqualsMatcher : StringMatcherBase { |
2607 | EqualsMatcher( CasedString const& comparator ); |
2608 | bool match( std::string const& source ) const override; |
2609 | }; |
2610 | struct ContainsMatcher : StringMatcherBase { |
2611 | ContainsMatcher( CasedString const& comparator ); |
2612 | bool match( std::string const& source ) const override; |
2613 | }; |
2614 | struct StartsWithMatcher : StringMatcherBase { |
2615 | StartsWithMatcher( CasedString const& comparator ); |
2616 | bool match( std::string const& source ) const override; |
2617 | }; |
2618 | struct EndsWithMatcher : StringMatcherBase { |
2619 | EndsWithMatcher( CasedString const& comparator ); |
2620 | bool match( std::string const& source ) const override; |
2621 | }; |
2622 | |
2623 | struct RegexMatcher : MatcherBase<std::string> { |
2624 | RegexMatcher( std::string regex, CaseSensitive::Choice caseSensitivity ); |
2625 | bool match( std::string const& matchee ) const override; |
2626 | std::string describe() const override; |
2627 | |
2628 | private: |
2629 | std::string m_regex; |
2630 | CaseSensitive::Choice m_caseSensitivity; |
2631 | }; |
2632 | |
2633 | } // namespace StdString |
2634 | |
2635 | // The following functions create the actual matcher objects. |
2636 | // This allows the types to be inferred |
2637 | |
2638 | StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); |
2639 | StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); |
2640 | StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); |
2641 | StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); |
2642 | StdString::RegexMatcher Matches( std::string const& regex, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); |
2643 | |
2644 | } // namespace Matchers |
2645 | } // namespace Catch |
2646 | |
2647 | // end catch_matchers_string.h |
2648 | // start catch_matchers_vector.h |
2649 | |
2650 | #include <algorithm> |
2651 | |
2652 | namespace Catch { |
2653 | namespace Matchers { |
2654 | |
2655 | namespace Vector { |
2656 | namespace Detail { |
2657 | template <typename InputIterator, typename T> |
2658 | size_t count(InputIterator first, InputIterator last, T const& item) { |
2659 | size_t cnt = 0; |
2660 | for (; first != last; ++first) { |
2661 | if (*first == item) { |
2662 | ++cnt; |
2663 | } |
2664 | } |
2665 | return cnt; |
2666 | } |
2667 | template <typename InputIterator, typename T> |
2668 | bool contains(InputIterator first, InputIterator last, T const& item) { |
2669 | for (; first != last; ++first) { |
2670 | if (*first == item) { |
2671 | return true; |
2672 | } |
2673 | } |
2674 | return false; |
2675 | } |
2676 | } |
2677 | |
2678 | template<typename T> |
2679 | struct ContainsElementMatcher : MatcherBase<std::vector<T>> { |
2680 | |
2681 | ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {} |
2682 | |
2683 | bool match(std::vector<T> const &v) const override { |
2684 | for (auto const& el : v) { |
2685 | if (el == m_comparator) { |
2686 | return true; |
2687 | } |
2688 | } |
2689 | return false; |
2690 | } |
2691 | |
2692 | std::string describe() const override { |
2693 | return "Contains: " + ::Catch::Detail::stringify( m_comparator ); |
2694 | } |
2695 | |
2696 | T const& m_comparator; |
2697 | }; |
2698 | |
2699 | template<typename T> |
2700 | struct ContainsMatcher : MatcherBase<std::vector<T>> { |
2701 | |
2702 | ContainsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {} |
2703 | |
2704 | bool match(std::vector<T> const &v) const override { |
2705 | // !TBD: see note in EqualsMatcher |
2706 | if (m_comparator.size() > v.size()) |
2707 | return false; |
2708 | for (auto const& comparator : m_comparator) { |
2709 | auto present = false; |
2710 | for (const auto& el : v) { |
2711 | if (el == comparator) { |
2712 | present = true; |
2713 | break; |
2714 | } |
2715 | } |
2716 | if (!present) { |
2717 | return false; |
2718 | } |
2719 | } |
2720 | return true; |
2721 | } |
2722 | std::string describe() const override { |
2723 | return "Contains: " + ::Catch::Detail::stringify( m_comparator ); |
2724 | } |
2725 | |
2726 | std::vector<T> const& m_comparator; |
2727 | }; |
2728 | |
2729 | template<typename T> |
2730 | struct EqualsMatcher : MatcherBase<std::vector<T>> { |
2731 | |
2732 | EqualsMatcher(std::vector<T> const &comparator) : m_comparator( comparator ) {} |
2733 | |
2734 | bool match(std::vector<T> const &v) const override { |
2735 | // !TBD: This currently works if all elements can be compared using != |
2736 | // - a more general approach would be via a compare template that defaults |
2737 | // to using !=. but could be specialised for, e.g. std::vector<T> etc |
2738 | // - then just call that directly |
2739 | if (m_comparator.size() != v.size()) |
2740 | return false; |
2741 | for (std::size_t i = 0; i < v.size(); ++i) |
2742 | if (m_comparator[i] != v[i]) |
2743 | return false; |
2744 | return true; |
2745 | } |
2746 | std::string describe() const override { |
2747 | return "Equals: " + ::Catch::Detail::stringify( m_comparator ); |
2748 | } |
2749 | std::vector<T> const& m_comparator; |
2750 | }; |
2751 | |
2752 | template<typename T> |
2753 | struct UnorderedEqualsMatcher : MatcherBase<std::vector<T>> { |
2754 | UnorderedEqualsMatcher(std::vector<T> const& target) : m_target(target) {} |
2755 | bool match(std::vector<T> const& vec) const override { |
2756 | // Note: This is a reimplementation of std::is_permutation, |
2757 | // because I don't want to include <algorithm> inside the common path |
2758 | if (m_target.size() != vec.size()) { |
2759 | return false; |
2760 | } |
2761 | auto lfirst = m_target.begin(), llast = m_target.end(); |
2762 | auto rfirst = vec.begin(), rlast = vec.end(); |
2763 | // Cut common prefix to optimize checking of permuted parts |
2764 | while (lfirst != llast && *lfirst != *rfirst) { |
2765 | ++lfirst; ++rfirst; |
2766 | } |
2767 | if (lfirst == llast) { |
2768 | return true; |
2769 | } |
2770 | |
2771 | for (auto mid = lfirst; mid != llast; ++mid) { |
2772 | // Skip already counted items |
2773 | if (Detail::contains(lfirst, mid, *mid)) { |
2774 | continue; |
2775 | } |
2776 | size_t num_vec = Detail::count(rfirst, rlast, *mid); |
2777 | if (num_vec == 0 || Detail::count(lfirst, llast, *mid) != num_vec) { |
2778 | return false; |
2779 | } |
2780 | } |
2781 | |
2782 | return true; |
2783 | } |
2784 | |
2785 | std::string describe() const override { |
2786 | return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target); |
2787 | } |
2788 | private: |
2789 | std::vector<T> const& m_target; |
2790 | }; |
2791 | |
2792 | } // namespace Vector |
2793 | |
2794 | // The following functions create the actual matcher objects. |
2795 | // This allows the types to be inferred |
2796 | |
2797 | template<typename T> |
2798 | Vector::ContainsMatcher<T> Contains( std::vector<T> const& comparator ) { |
2799 | return Vector::ContainsMatcher<T>( comparator ); |
2800 | } |
2801 | |
2802 | template<typename T> |
2803 | Vector::ContainsElementMatcher<T> VectorContains( T const& comparator ) { |
2804 | return Vector::ContainsElementMatcher<T>( comparator ); |
2805 | } |
2806 | |
2807 | template<typename T> |
2808 | Vector::EqualsMatcher<T> Equals( std::vector<T> const& comparator ) { |
2809 | return Vector::EqualsMatcher<T>( comparator ); |
2810 | } |
2811 | |
2812 | template<typename T> |
2813 | Vector::UnorderedEqualsMatcher<T> UnorderedEquals(std::vector<T> const& target) { |
2814 | return Vector::UnorderedEqualsMatcher<T>(target); |
2815 | } |
2816 | |
2817 | } // namespace Matchers |
2818 | } // namespace Catch |
2819 | |
2820 | // end catch_matchers_vector.h |
2821 | namespace Catch { |
2822 | |
2823 | template<typename ArgT, typename MatcherT> |
2824 | class MatchExpr : public ITransientExpression { |
2825 | ArgT const& m_arg; |
2826 | MatcherT m_matcher; |
2827 | StringRef m_matcherString; |
2828 | public: |
2829 | MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef const& matcherString ) |
2830 | : ITransientExpression{ true, matcher.match( arg ) }, |
2831 | m_arg( arg ), |
2832 | m_matcher( matcher ), |
2833 | m_matcherString( matcherString ) |
2834 | {} |
2835 | |
2836 | void streamReconstructedExpression( std::ostream &os ) const override { |
2837 | auto matcherAsString = m_matcher.toString(); |
2838 | os << Catch::Detail::stringify( m_arg ) << ' '; |
2839 | if( matcherAsString == Detail::unprintableString ) |
2840 | os << m_matcherString; |
2841 | else |
2842 | os << matcherAsString; |
2843 | } |
2844 | }; |
2845 | |
2846 | using StringMatcher = Matchers::Impl::MatcherBase<std::string>; |
2847 | |
2848 | void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString ); |
2849 | |
2850 | template<typename ArgT, typename MatcherT> |
2851 | auto makeMatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef const& matcherString ) -> MatchExpr<ArgT, MatcherT> { |
2852 | return MatchExpr<ArgT, MatcherT>( arg, matcher, matcherString ); |
2853 | } |
2854 | |
2855 | } // namespace Catch |
2856 | |
2857 | /////////////////////////////////////////////////////////////////////////////// |
2858 | #define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \ |
2859 | do { \ |
2860 | Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ |
2861 | INTERNAL_CATCH_TRY { \ |
2862 | catchAssertionHandler.handleExpr( Catch::makeMatchExpr( arg, matcher, #matcher##_catch_sr ) ); \ |
2863 | } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ |
2864 | INTERNAL_CATCH_REACT( catchAssertionHandler ) \ |
2865 | } while( false ) |
2866 | |
2867 | /////////////////////////////////////////////////////////////////////////////// |
2868 | #define INTERNAL_CATCH_THROWS_MATCHES( macroName, exceptionType, resultDisposition, matcher, ... ) \ |
2869 | do { \ |
2870 | Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(exceptionType) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ |
2871 | if( catchAssertionHandler.allowThrows() ) \ |
2872 | try { \ |
2873 | static_cast<void>(__VA_ARGS__ ); \ |
2874 | catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ |
2875 | } \ |
2876 | catch( exceptionType const& ex ) { \ |
2877 | catchAssertionHandler.handleExpr( Catch::makeMatchExpr( ex, matcher, #matcher##_catch_sr ) ); \ |
2878 | } \ |
2879 | catch( ... ) { \ |
2880 | catchAssertionHandler.handleUnexpectedInflightException(); \ |
2881 | } \ |
2882 | else \ |
2883 | catchAssertionHandler.handleThrowingCallSkipped(); \ |
2884 | INTERNAL_CATCH_REACT( catchAssertionHandler ) \ |
2885 | } while( false ) |
2886 | |
2887 | // end catch_capture_matchers.h |
2888 | #endif |
2889 | // start catch_generators.hpp |
2890 | |
2891 | // start catch_interfaces_generatortracker.h |
2892 | |
2893 | |
2894 | #include <memory> |
2895 | |
2896 | namespace Catch { |
2897 | |
2898 | namespace Generators { |
2899 | class GeneratorBase { |
2900 | protected: |
2901 | size_t m_size = 0; |
2902 | |
2903 | public: |
2904 | GeneratorBase( size_t size ) : m_size( size ) {} |
2905 | virtual ~GeneratorBase(); |
2906 | auto size() const -> size_t { return m_size; } |
2907 | }; |
2908 | using GeneratorBasePtr = std::unique_ptr<GeneratorBase>; |
2909 | |
2910 | } // namespace Generators |
2911 | |
2912 | struct IGeneratorTracker { |
2913 | virtual ~IGeneratorTracker(); |
2914 | virtual auto hasGenerator() const -> bool = 0; |
2915 | virtual auto getGenerator() const -> Generators::GeneratorBasePtr const& = 0; |
2916 | virtual void setGenerator( Generators::GeneratorBasePtr&& generator ) = 0; |
2917 | virtual auto getIndex() const -> std::size_t = 0; |
2918 | }; |
2919 | |
2920 | } // namespace Catch |
2921 | |
2922 | // end catch_interfaces_generatortracker.h |
2923 | // start catch_enforce.h |
2924 | |
2925 | #include <stdexcept> |
2926 | |
2927 | namespace Catch { |
2928 | #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) |
2929 | template <typename Ex> |
2930 | [[noreturn]] |
2931 | void throw_exception(Ex const& e) { |
2932 | throw e; |
2933 | } |
2934 | #else // ^^ Exceptions are enabled // Exceptions are disabled vv |
2935 | [[noreturn]] |
2936 | void throw_exception(std::exception const& e); |
2937 | #endif |
2938 | } // namespace Catch; |
2939 | |
2940 | #define CATCH_PREPARE_EXCEPTION( type, msg ) \ |
2941 | type( ( Catch::ReusableStringStream() << msg ).str() ) |
2942 | #define CATCH_INTERNAL_ERROR( msg ) \ |
2943 | Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::logic_error, CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg)) |
2944 | #define CATCH_ERROR( msg ) \ |
2945 | Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::domain_error, msg )) |
2946 | #define CATCH_RUNTIME_ERROR( msg ) \ |
2947 | Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::runtime_error, msg )) |
2948 | #define CATCH_ENFORCE( condition, msg ) \ |
2949 | do{ if( !(condition) ) CATCH_ERROR( msg ); } while(false) |
2950 | |
2951 | // end catch_enforce.h |
2952 | #include <memory> |
2953 | #include <vector> |
2954 | #include <cassert> |
2955 | |
2956 | #include <utility> |
2957 | |
2958 | namespace Catch { |
2959 | namespace Generators { |
2960 | |
2961 | // !TBD move this into its own location? |
2962 | namespace pf{ |
2963 | template<typename T, typename... Args> |
2964 | std::unique_ptr<T> make_unique( Args&&... args ) { |
2965 | return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); |
2966 | } |
2967 | } |
2968 | |
2969 | template<typename T> |
2970 | struct IGenerator { |
2971 | virtual ~IGenerator() {} |
2972 | virtual auto get( size_t index ) const -> T = 0; |
2973 | }; |
2974 | |
2975 | template<typename T> |
2976 | class SingleValueGenerator : public IGenerator<T> { |
2977 | T m_value; |
2978 | public: |
2979 | SingleValueGenerator( T const& value ) : m_value( value ) {} |
2980 | |
2981 | auto get( size_t ) const -> T override { |
2982 | return m_value; |
2983 | } |
2984 | }; |
2985 | |
2986 | template<typename T> |
2987 | class FixedValuesGenerator : public IGenerator<T> { |
2988 | std::vector<T> m_values; |
2989 | |
2990 | public: |
2991 | FixedValuesGenerator( std::initializer_list<T> values ) : m_values( values ) {} |
2992 | |
2993 | auto get( size_t index ) const -> T override { |
2994 | return m_values[index]; |
2995 | } |
2996 | }; |
2997 | |
2998 | template<typename T> |
2999 | class RangeGenerator : public IGenerator<T> { |
3000 | T const m_first; |
3001 | T const m_last; |
3002 | |
3003 | public: |
3004 | RangeGenerator( T const& first, T const& last ) : m_first( first ), m_last( last ) { |
3005 | assert( m_last > m_first ); |
3006 | } |
3007 | |
3008 | auto get( size_t index ) const -> T override { |
3009 | // ToDo:: introduce a safe cast to catch potential overflows |
3010 | return static_cast<T>(m_first+index); |
3011 | } |
3012 | }; |
3013 | |
3014 | template<typename T> |
3015 | struct NullGenerator : IGenerator<T> { |
3016 | auto get( size_t ) const -> T override { |
3017 | CATCH_INTERNAL_ERROR("A Null Generator is always empty" ); |
3018 | } |
3019 | }; |
3020 | |
3021 | template<typename T> |
3022 | class Generator { |
3023 | std::unique_ptr<IGenerator<T>> m_generator; |
3024 | size_t m_size; |
3025 | |
3026 | public: |
3027 | Generator( size_t size, std::unique_ptr<IGenerator<T>> generator ) |
3028 | : m_generator( std::move( generator ) ), |
3029 | m_size( size ) |
3030 | {} |
3031 | |
3032 | auto size() const -> size_t { return m_size; } |
3033 | auto operator[]( size_t index ) const -> T { |
3034 | assert( index < m_size ); |
3035 | return m_generator->get( index ); |
3036 | } |
3037 | }; |
3038 | |
3039 | std::vector<size_t> randomiseIndices( size_t selectionSize, size_t sourceSize ); |
3040 | |
3041 | template<typename T> |
3042 | class GeneratorRandomiser : public IGenerator<T> { |
3043 | Generator<T> m_baseGenerator; |
3044 | |
3045 | std::vector<size_t> m_indices; |
3046 | public: |
3047 | GeneratorRandomiser( Generator<T>&& baseGenerator, size_t numberOfItems ) |
3048 | : m_baseGenerator( std::move( baseGenerator ) ), |
3049 | m_indices( randomiseIndices( numberOfItems, m_baseGenerator.size() ) ) |
3050 | {} |
3051 | |
3052 | auto get( size_t index ) const -> T override { |
3053 | return m_baseGenerator[m_indices[index]]; |
3054 | } |
3055 | }; |
3056 | |
3057 | template<typename T> |
3058 | struct RequiresASpecialisationFor; |
3059 | |
3060 | template<typename T> |
3061 | auto all() -> Generator<T> { return RequiresASpecialisationFor<T>(); } |
3062 | |
3063 | template<> |
3064 | auto all<int>() -> Generator<int>; |
3065 | |
3066 | template<typename T> |
3067 | auto range( T const& first, T const& last ) -> Generator<T> { |
3068 | return Generator<T>( (last-first), pf::make_unique<RangeGenerator<T>>( first, last ) ); |
3069 | } |
3070 | |
3071 | template<typename T> |
3072 | auto random( T const& first, T const& last ) -> Generator<T> { |
3073 | auto gen = range( first, last ); |
3074 | auto size = gen.size(); |
3075 | |
3076 | return Generator<T>( size, pf::make_unique<GeneratorRandomiser<T>>( std::move( gen ), size ) ); |
3077 | } |
3078 | template<typename T> |
3079 | auto random( size_t size ) -> Generator<T> { |
3080 | return Generator<T>( size, pf::make_unique<GeneratorRandomiser<T>>( all<T>(), size ) ); |
3081 | } |
3082 | |
3083 | template<typename T> |
3084 | auto values( std::initializer_list<T> values ) -> Generator<T> { |
3085 | return Generator<T>( values.size(), pf::make_unique<FixedValuesGenerator<T>>( values ) ); |
3086 | } |
3087 | template<typename T> |
3088 | auto value( T const& val ) -> Generator<T> { |
3089 | return Generator<T>( 1, pf::make_unique<SingleValueGenerator<T>>( val ) ); |
3090 | } |
3091 | |
3092 | template<typename T> |
3093 | auto as() -> Generator<T> { |
3094 | return Generator<T>( 0, pf::make_unique<NullGenerator<T>>() ); |
3095 | } |
3096 | |
3097 | template<typename... Ts> |
3098 | auto table( std::initializer_list<std::tuple<Ts...>>&& tuples ) -> Generator<std::tuple<Ts...>> { |
3099 | return values<std::tuple<Ts...>>( std::forward<std::initializer_list<std::tuple<Ts...>>>( tuples ) ); |
3100 | } |
3101 | |
3102 | template<typename T> |
3103 | struct Generators : GeneratorBase { |
3104 | std::vector<Generator<T>> m_generators; |
3105 | |
3106 | using type = T; |
3107 | |
3108 | Generators() : GeneratorBase( 0 ) {} |
3109 | |
3110 | void populate( T&& val ) { |
3111 | m_size += 1; |
3112 | m_generators.emplace_back( value( std::move( val ) ) ); |
3113 | } |
3114 | template<typename U> |
3115 | void populate( U&& val ) { |
3116 | populate( T( std::move( val ) ) ); |
3117 | } |
3118 | void populate( Generator<T>&& generator ) { |
3119 | m_size += generator.size(); |
3120 | m_generators.emplace_back( std::move( generator ) ); |
3121 | } |
3122 | |
3123 | template<typename U, typename... Gs> |
3124 | void populate( U&& valueOrGenerator, Gs... moreGenerators ) { |
3125 | populate( std::forward<U>( valueOrGenerator ) ); |
3126 | populate( std::forward<Gs>( moreGenerators )... ); |
3127 | } |
3128 | |
3129 | auto operator[]( size_t index ) const -> T { |
3130 | size_t sizes = 0; |
3131 | for( auto const& gen : m_generators ) { |
3132 | auto localIndex = index-sizes; |
3133 | sizes += gen.size(); |
3134 | if( index < sizes ) |
3135 | return gen[localIndex]; |
3136 | } |
3137 | CATCH_INTERNAL_ERROR("Index '" << index << "' is out of range (" << sizes << ')'); |
3138 | } |
3139 | }; |
3140 | |
3141 | template<typename T, typename... Gs> |
3142 | auto makeGenerators( Generator<T>&& generator, Gs... moreGenerators ) -> Generators<T> { |
3143 | Generators<T> generators; |
3144 | generators.m_generators.reserve( 1+sizeof...(Gs) ); |
3145 | generators.populate( std::move( generator ), std::forward<Gs>( moreGenerators )... ); |
3146 | return generators; |
3147 | } |
3148 | template<typename T> |
3149 | auto makeGenerators( Generator<T>&& generator ) -> Generators<T> { |
3150 | Generators<T> generators; |
3151 | generators.populate( std::move( generator ) ); |
3152 | return generators; |
3153 | } |
3154 | template<typename T, typename... Gs> |
3155 | auto makeGenerators( T&& val, Gs... moreGenerators ) -> Generators<T> { |
3156 | return makeGenerators( value( std::forward<T>( val ) ), std::forward<Gs>( moreGenerators )... ); |
3157 | } |
3158 | template<typename T, typename U, typename... Gs> |
3159 | auto makeGenerators( U&& val, Gs... moreGenerators ) -> Generators<T> { |
3160 | return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... ); |
3161 | } |
3162 | |
3163 | auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker&; |
3164 | |
3165 | template<typename L> |
3166 | // Note: The type after -> is weird, because VS2015 cannot parse |
3167 | // the expression used in the typedef inside, when it is in |
3168 | // return type. Yeah, ¯\_(ツ)_/¯ |
3169 | auto generate( SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>()[0]) { |
3170 | using UnderlyingType = typename decltype(generatorExpression())::type; |
3171 | |
3172 | IGeneratorTracker& tracker = acquireGeneratorTracker( lineInfo ); |
3173 | if( !tracker.hasGenerator() ) |
3174 | tracker.setGenerator( pf::make_unique<Generators<UnderlyingType>>( generatorExpression() ) ); |
3175 | |
3176 | auto const& generator = static_cast<Generators<UnderlyingType> const&>( *tracker.getGenerator() ); |
3177 | return generator[tracker.getIndex()]; |
3178 | } |
3179 | |
3180 | } // namespace Generators |
3181 | } // namespace Catch |
3182 | |
3183 | #define GENERATE( ... ) \ |
3184 | Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, []{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) |
3185 | |
3186 | // end catch_generators.hpp |
3187 | |
3188 | // These files are included here so the single_include script doesn't put them |
3189 | // in the conditionally compiled sections |
3190 | // start catch_test_case_info.h |
3191 | |
3192 | #include <string> |
3193 | #include <vector> |
3194 | #include <memory> |
3195 | |
3196 | #ifdef __clang__ |
3197 | #pragma clang diagnostic push |
3198 | #pragma clang diagnostic ignored "-Wpadded" |
3199 | #endif |
3200 | |
3201 | namespace Catch { |
3202 | |
3203 | struct ITestInvoker; |
3204 | |
3205 | struct TestCaseInfo { |
3206 | enum SpecialProperties{ |
3207 | None = 0, |
3208 | IsHidden = 1 << 1, |
3209 | ShouldFail = 1 << 2, |
3210 | MayFail = 1 << 3, |
3211 | Throws = 1 << 4, |
3212 | NonPortable = 1 << 5, |
3213 | Benchmark = 1 << 6 |
3214 | }; |
3215 | |
3216 | TestCaseInfo( std::string const& _name, |
3217 | std::string const& _className, |
3218 | std::string const& _description, |
3219 | std::vector<std::string> const& _tags, |
3220 | SourceLineInfo const& _lineInfo ); |
3221 | |
3222 | friend void setTags( TestCaseInfo& testCaseInfo, std::vector<std::string> tags ); |
3223 | |
3224 | bool isHidden() const; |
3225 | bool throws() const; |
3226 | bool okToFail() const; |
3227 | bool expectedToFail() const; |
3228 | |
3229 | std::string tagsAsString() const; |
3230 | |
3231 | std::string name; |
3232 | std::string className; |
3233 | std::string description; |
3234 | std::vector<std::string> tags; |
3235 | std::vector<std::string> lcaseTags; |
3236 | SourceLineInfo lineInfo; |
3237 | SpecialProperties properties; |
3238 | }; |
3239 | |
3240 | class TestCase : public TestCaseInfo { |
3241 | public: |
3242 | |
3243 | TestCase( ITestInvoker* testCase, TestCaseInfo&& info ); |
3244 | |
3245 | TestCase withName( std::string const& _newName ) const; |
3246 | |
3247 | void invoke() const; |
3248 | |
3249 | TestCaseInfo const& getTestCaseInfo() const; |
3250 | |
3251 | bool operator == ( TestCase const& other ) const; |
3252 | bool operator < ( TestCase const& other ) const; |
3253 | |
3254 | private: |
3255 | std::shared_ptr<ITestInvoker> test; |
3256 | }; |
3257 | |
3258 | TestCase makeTestCase( ITestInvoker* testCase, |
3259 | std::string const& className, |
3260 | NameAndTags const& nameAndTags, |
3261 | SourceLineInfo const& lineInfo ); |
3262 | } |
3263 | |
3264 | #ifdef __clang__ |
3265 | #pragma clang diagnostic pop |
3266 | #endif |
3267 | |
3268 | // end catch_test_case_info.h |
3269 | // start catch_interfaces_runner.h |
3270 | |
3271 | namespace Catch { |
3272 | |
3273 | struct IRunner { |
3274 | virtual ~IRunner(); |
3275 | virtual bool aborting() const = 0; |
3276 | }; |
3277 | } |
3278 | |
3279 | // end catch_interfaces_runner.h |
3280 | |
3281 | #ifdef __OBJC__ |
3282 | // start catch_objc.hpp |
3283 | |
3284 | #import <objc/runtime.h> |
3285 | |
3286 | #include <string> |
3287 | |
3288 | // NB. Any general catch headers included here must be included |
3289 | // in catch.hpp first to make sure they are included by the single |
3290 | // header for non obj-usage |
3291 | |
3292 | /////////////////////////////////////////////////////////////////////////////// |
3293 | // This protocol is really only here for (self) documenting purposes, since |
3294 | // all its methods are optional. |
3295 | @protocol OcFixture |
3296 | |
3297 | @optional |
3298 | |
3299 | -(void) setUp; |
3300 | -(void) tearDown; |
3301 | |
3302 | @end |
3303 | |
3304 | namespace Catch { |
3305 | |
3306 | class OcMethod : public ITestInvoker { |
3307 | |
3308 | public: |
3309 | OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {} |
3310 | |
3311 | virtual void invoke() const { |
3312 | id obj = [[m_cls alloc] init]; |
3313 | |
3314 | performOptionalSelector( obj, @selector(setUp) ); |
3315 | performOptionalSelector( obj, m_sel ); |
3316 | performOptionalSelector( obj, @selector(tearDown) ); |
3317 | |
3318 | arcSafeRelease( obj ); |
3319 | } |
3320 | private: |
3321 | virtual ~OcMethod() {} |
3322 | |
3323 | Class m_cls; |
3324 | SEL m_sel; |
3325 | }; |
3326 | |
3327 | namespace Detail{ |
3328 | |
3329 | inline std::string getAnnotation( Class cls, |
3330 | std::string const& annotationName, |
3331 | std::string const& testCaseName ) { |
3332 | NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s" , annotationName.c_str(), testCaseName.c_str()]; |
3333 | SEL sel = NSSelectorFromString( selStr ); |
3334 | arcSafeRelease( selStr ); |
3335 | id value = performOptionalSelector( cls, sel ); |
3336 | if( value ) |
3337 | return [(NSString*)value UTF8String]; |
3338 | return "" ; |
3339 | } |
3340 | } |
3341 | |
3342 | inline std::size_t registerTestMethods() { |
3343 | std::size_t noTestMethods = 0; |
3344 | int noClasses = objc_getClassList( nullptr, 0 ); |
3345 | |
3346 | Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); |
3347 | objc_getClassList( classes, noClasses ); |
3348 | |
3349 | for( int c = 0; c < noClasses; c++ ) { |
3350 | Class cls = classes[c]; |
3351 | { |
3352 | u_int count; |
3353 | Method* methods = class_copyMethodList( cls, &count ); |
3354 | for( u_int m = 0; m < count ; m++ ) { |
3355 | SEL selector = method_getName(methods[m]); |
3356 | std::string methodName = sel_getName(selector); |
3357 | if( startsWith( methodName, "Catch_TestCase_" ) ) { |
3358 | std::string testCaseName = methodName.substr( 15 ); |
3359 | std::string name = Detail::getAnnotation( cls, "Name" , testCaseName ); |
3360 | std::string desc = Detail::getAnnotation( cls, "Description" , testCaseName ); |
3361 | const char* className = class_getName( cls ); |
3362 | |
3363 | getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, NameAndTags( name.c_str(), desc.c_str() ), SourceLineInfo("" ,0) ) ); |
3364 | noTestMethods++; |
3365 | } |
3366 | } |
3367 | free(methods); |
3368 | } |
3369 | } |
3370 | return noTestMethods; |
3371 | } |
3372 | |
3373 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) |
3374 | |
3375 | namespace Matchers { |
3376 | namespace Impl { |
3377 | namespace NSStringMatchers { |
3378 | |
3379 | struct StringHolder : MatcherBase<NSString*>{ |
3380 | StringHolder( NSString* substr ) : m_substr( [substr copy] ){} |
3381 | StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){} |
3382 | StringHolder() { |
3383 | arcSafeRelease( m_substr ); |
3384 | } |
3385 | |
3386 | bool match( NSString* arg ) const override { |
3387 | return false; |
3388 | } |
3389 | |
3390 | NSString* CATCH_ARC_STRONG m_substr; |
3391 | }; |
3392 | |
3393 | struct Equals : StringHolder { |
3394 | Equals( NSString* substr ) : StringHolder( substr ){} |
3395 | |
3396 | bool match( NSString* str ) const override { |
3397 | return (str != nil || m_substr == nil ) && |
3398 | [str isEqualToString:m_substr]; |
3399 | } |
3400 | |
3401 | std::string describe() const override { |
3402 | return "equals string: " + Catch::Detail::stringify( m_substr ); |
3403 | } |
3404 | }; |
3405 | |
3406 | struct Contains : StringHolder { |
3407 | Contains( NSString* substr ) : StringHolder( substr ){} |
3408 | |
3409 | bool match( NSString* str ) const { |
3410 | return (str != nil || m_substr == nil ) && |
3411 | [str rangeOfString:m_substr].location != NSNotFound; |
3412 | } |
3413 | |
3414 | std::string describe() const override { |
3415 | return "contains string: " + Catch::Detail::stringify( m_substr ); |
3416 | } |
3417 | }; |
3418 | |
3419 | struct StartsWith : StringHolder { |
3420 | StartsWith( NSString* substr ) : StringHolder( substr ){} |
3421 | |
3422 | bool match( NSString* str ) const override { |
3423 | return (str != nil || m_substr == nil ) && |
3424 | [str rangeOfString:m_substr].location == 0; |
3425 | } |
3426 | |
3427 | std::string describe() const override { |
3428 | return "starts with: " + Catch::Detail::stringify( m_substr ); |
3429 | } |
3430 | }; |
3431 | struct EndsWith : StringHolder { |
3432 | EndsWith( NSString* substr ) : StringHolder( substr ){} |
3433 | |
3434 | bool match( NSString* str ) const override { |
3435 | return (str != nil || m_substr == nil ) && |
3436 | [str rangeOfString:m_substr].location == [str length] - [m_substr length]; |
3437 | } |
3438 | |
3439 | std::string describe() const override { |
3440 | return "ends with: " + Catch::Detail::stringify( m_substr ); |
3441 | } |
3442 | }; |
3443 | |
3444 | } // namespace NSStringMatchers |
3445 | } // namespace Impl |
3446 | |
3447 | inline Impl::NSStringMatchers::Equals |
3448 | Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); } |
3449 | |
3450 | inline Impl::NSStringMatchers::Contains |
3451 | Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); } |
3452 | |
3453 | inline Impl::NSStringMatchers::StartsWith |
3454 | StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); } |
3455 | |
3456 | inline Impl::NSStringMatchers::EndsWith |
3457 | EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); } |
3458 | |
3459 | } // namespace Matchers |
3460 | |
3461 | using namespace Matchers; |
3462 | |
3463 | #endif // CATCH_CONFIG_DISABLE_MATCHERS |
3464 | |
3465 | } // namespace Catch |
3466 | |
3467 | /////////////////////////////////////////////////////////////////////////////// |
3468 | #define OC_MAKE_UNIQUE_NAME( root, uniqueSuffix ) root##uniqueSuffix |
3469 | #define OC_TEST_CASE2( name, desc, uniqueSuffix ) \ |
3470 | +(NSString*) OC_MAKE_UNIQUE_NAME( Catch_Name_test_, uniqueSuffix ) \ |
3471 | { \ |
3472 | return @ name; \ |
3473 | } \ |
3474 | +(NSString*) OC_MAKE_UNIQUE_NAME( Catch_Description_test_, uniqueSuffix ) \ |
3475 | { \ |
3476 | return @ desc; \ |
3477 | } \ |
3478 | -(void) OC_MAKE_UNIQUE_NAME( Catch_TestCase_test_, uniqueSuffix ) |
3479 | |
3480 | #define OC_TEST_CASE( name, desc ) OC_TEST_CASE2( name, desc, __LINE__ ) |
3481 | |
3482 | // end catch_objc.hpp |
3483 | #endif |
3484 | |
3485 | #ifdef CATCH_CONFIG_EXTERNAL_INTERFACES |
3486 | // start catch_external_interfaces.h |
3487 | |
3488 | // start catch_reporter_bases.hpp |
3489 | |
3490 | // start catch_interfaces_reporter.h |
3491 | |
3492 | // start catch_config.hpp |
3493 | |
3494 | // start catch_test_spec_parser.h |
3495 | |
3496 | #ifdef __clang__ |
3497 | #pragma clang diagnostic push |
3498 | #pragma clang diagnostic ignored "-Wpadded" |
3499 | #endif |
3500 | |
3501 | // start catch_test_spec.h |
3502 | |
3503 | #ifdef __clang__ |
3504 | #pragma clang diagnostic push |
3505 | #pragma clang diagnostic ignored "-Wpadded" |
3506 | #endif |
3507 | |
3508 | // start catch_wildcard_pattern.h |
3509 | |
3510 | namespace Catch |
3511 | { |
3512 | class WildcardPattern { |
3513 | enum WildcardPosition { |
3514 | NoWildcard = 0, |
3515 | WildcardAtStart = 1, |
3516 | WildcardAtEnd = 2, |
3517 | WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd |
3518 | }; |
3519 | |
3520 | public: |
3521 | |
3522 | WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity ); |
3523 | virtual ~WildcardPattern() = default; |
3524 | virtual bool matches( std::string const& str ) const; |
3525 | |
3526 | private: |
3527 | std::string adjustCase( std::string const& str ) const; |
3528 | CaseSensitive::Choice m_caseSensitivity; |
3529 | WildcardPosition m_wildcard = NoWildcard; |
3530 | std::string m_pattern; |
3531 | }; |
3532 | } |
3533 | |
3534 | // end catch_wildcard_pattern.h |
3535 | #include <string> |
3536 | #include <vector> |
3537 | #include <memory> |
3538 | |
3539 | namespace Catch { |
3540 | |
3541 | class TestSpec { |
3542 | struct Pattern { |
3543 | virtual ~Pattern(); |
3544 | virtual bool matches( TestCaseInfo const& testCase ) const = 0; |
3545 | }; |
3546 | using PatternPtr = std::shared_ptr<Pattern>; |
3547 | |
3548 | class NamePattern : public Pattern { |
3549 | public: |
3550 | NamePattern( std::string const& name ); |
3551 | virtual ~NamePattern(); |
3552 | virtual bool matches( TestCaseInfo const& testCase ) const override; |
3553 | private: |
3554 | WildcardPattern m_wildcardPattern; |
3555 | }; |
3556 | |
3557 | class TagPattern : public Pattern { |
3558 | public: |
3559 | TagPattern( std::string const& tag ); |
3560 | virtual ~TagPattern(); |
3561 | virtual bool matches( TestCaseInfo const& testCase ) const override; |
3562 | private: |
3563 | std::string m_tag; |
3564 | }; |
3565 | |
3566 | class ExcludedPattern : public Pattern { |
3567 | public: |
3568 | ExcludedPattern( PatternPtr const& underlyingPattern ); |
3569 | virtual ~ExcludedPattern(); |
3570 | virtual bool matches( TestCaseInfo const& testCase ) const override; |
3571 | private: |
3572 | PatternPtr m_underlyingPattern; |
3573 | }; |
3574 | |
3575 | struct Filter { |
3576 | std::vector<PatternPtr> m_patterns; |
3577 | |
3578 | bool matches( TestCaseInfo const& testCase ) const; |
3579 | }; |
3580 | |
3581 | public: |
3582 | bool hasFilters() const; |
3583 | bool matches( TestCaseInfo const& testCase ) const; |
3584 | |
3585 | private: |
3586 | std::vector<Filter> m_filters; |
3587 | |
3588 | friend class TestSpecParser; |
3589 | }; |
3590 | } |
3591 | |
3592 | #ifdef __clang__ |
3593 | #pragma clang diagnostic pop |
3594 | #endif |
3595 | |
3596 | // end catch_test_spec.h |
3597 | // start catch_interfaces_tag_alias_registry.h |
3598 | |
3599 | #include <string> |
3600 | |
3601 | namespace Catch { |
3602 | |
3603 | struct TagAlias; |
3604 | |
3605 | struct ITagAliasRegistry { |
3606 | virtual ~ITagAliasRegistry(); |
3607 | // Nullptr if not present |
3608 | virtual TagAlias const* find( std::string const& alias ) const = 0; |
3609 | virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0; |
3610 | |
3611 | static ITagAliasRegistry const& get(); |
3612 | }; |
3613 | |
3614 | } // end namespace Catch |
3615 | |
3616 | // end catch_interfaces_tag_alias_registry.h |
3617 | namespace Catch { |
3618 | |
3619 | class TestSpecParser { |
3620 | enum Mode{ None, Name, QuotedName, Tag, EscapedName }; |
3621 | Mode m_mode = None; |
3622 | bool m_exclusion = false; |
3623 | std::size_t m_start = std::string::npos, m_pos = 0; |
3624 | std::string m_arg; |
3625 | std::vector<std::size_t> m_escapeChars; |
3626 | TestSpec::Filter m_currentFilter; |
3627 | TestSpec m_testSpec; |
3628 | ITagAliasRegistry const* m_tagAliases = nullptr; |
3629 | |
3630 | public: |
3631 | TestSpecParser( ITagAliasRegistry const& tagAliases ); |
3632 | |
3633 | TestSpecParser& parse( std::string const& arg ); |
3634 | TestSpec testSpec(); |
3635 | |
3636 | private: |
3637 | void visitChar( char c ); |
3638 | void startNewMode( Mode mode, std::size_t start ); |
3639 | void escape(); |
3640 | std::string subString() const; |
3641 | |
3642 | template<typename T> |
3643 | void addPattern() { |
3644 | std::string token = subString(); |
3645 | for( std::size_t i = 0; i < m_escapeChars.size(); ++i ) |
3646 | token = token.substr( 0, m_escapeChars[i]-m_start-i ) + token.substr( m_escapeChars[i]-m_start-i+1 ); |
3647 | m_escapeChars.clear(); |
3648 | if( startsWith( token, "exclude:" ) ) { |
3649 | m_exclusion = true; |
3650 | token = token.substr( 8 ); |
3651 | } |
3652 | if( !token.empty() ) { |
3653 | TestSpec::PatternPtr pattern = std::make_shared<T>( token ); |
3654 | if( m_exclusion ) |
3655 | pattern = std::make_shared<TestSpec::ExcludedPattern>( pattern ); |
3656 | m_currentFilter.m_patterns.push_back( pattern ); |
3657 | } |
3658 | m_exclusion = false; |
3659 | m_mode = None; |
3660 | } |
3661 | |
3662 | void addFilter(); |
3663 | }; |
3664 | TestSpec parseTestSpec( std::string const& arg ); |
3665 | |
3666 | } // namespace Catch |
3667 | |
3668 | #ifdef __clang__ |
3669 | #pragma clang diagnostic pop |
3670 | #endif |
3671 | |
3672 | // end catch_test_spec_parser.h |
3673 | // start catch_interfaces_config.h |
3674 | |
3675 | #include <iosfwd> |
3676 | #include <string> |
3677 | #include <vector> |
3678 | #include <memory> |
3679 | |
3680 | namespace Catch { |
3681 | |
3682 | enum class Verbosity { |
3683 | Quiet = 0, |
3684 | Normal, |
3685 | High |
3686 | }; |
3687 | |
3688 | struct WarnAbout { enum What { |
3689 | Nothing = 0x00, |
3690 | NoAssertions = 0x01, |
3691 | NoTests = 0x02 |
3692 | }; }; |
3693 | |
3694 | struct ShowDurations { enum OrNot { |
3695 | DefaultForReporter, |
3696 | Always, |
3697 | Never |
3698 | }; }; |
3699 | struct RunTests { enum InWhatOrder { |
3700 | InDeclarationOrder, |
3701 | InLexicographicalOrder, |
3702 | InRandomOrder |
3703 | }; }; |
3704 | struct UseColour { enum YesOrNo { |
3705 | Auto, |
3706 | Yes, |
3707 | No |
3708 | }; }; |
3709 | struct WaitForKeypress { enum When { |
3710 | Never, |
3711 | BeforeStart = 1, |
3712 | BeforeExit = 2, |
3713 | BeforeStartAndExit = BeforeStart | BeforeExit |
3714 | }; }; |
3715 | |
3716 | class TestSpec; |
3717 | |
3718 | struct IConfig : NonCopyable { |
3719 | |
3720 | virtual ~IConfig(); |
3721 | |
3722 | virtual bool allowThrows() const = 0; |
3723 | virtual std::ostream& stream() const = 0; |
3724 | virtual std::string name() const = 0; |
3725 | virtual bool includeSuccessfulResults() const = 0; |
3726 | virtual bool shouldDebugBreak() const = 0; |
3727 | virtual bool warnAboutMissingAssertions() const = 0; |
3728 | virtual bool warnAboutNoTests() const = 0; |
3729 | virtual int abortAfter() const = 0; |
3730 | virtual bool showInvisibles() const = 0; |
3731 | virtual ShowDurations::OrNot showDurations() const = 0; |
3732 | virtual TestSpec const& testSpec() const = 0; |
3733 | virtual bool hasTestFilters() const = 0; |
3734 | virtual RunTests::InWhatOrder runOrder() const = 0; |
3735 | virtual unsigned int rngSeed() const = 0; |
3736 | virtual int benchmarkResolutionMultiple() const = 0; |
3737 | virtual UseColour::YesOrNo useColour() const = 0; |
3738 | virtual std::vector<std::string> const& getSectionsToRun() const = 0; |
3739 | virtual Verbosity verbosity() const = 0; |
3740 | }; |
3741 | |
3742 | using IConfigPtr = std::shared_ptr<IConfig const>; |
3743 | } |
3744 | |
3745 | // end catch_interfaces_config.h |
3746 | // Libstdc++ doesn't like incomplete classes for unique_ptr |
3747 | |
3748 | #include <memory> |
3749 | #include <vector> |
3750 | #include <string> |
3751 | |
3752 | #ifndef CATCH_CONFIG_CONSOLE_WIDTH |
3753 | #define CATCH_CONFIG_CONSOLE_WIDTH 80 |
3754 | #endif |
3755 | |
3756 | namespace Catch { |
3757 | |
3758 | struct IStream; |
3759 | |
3760 | struct ConfigData { |
3761 | bool listTests = false; |
3762 | bool listTags = false; |
3763 | bool listReporters = false; |
3764 | bool listTestNamesOnly = false; |
3765 | |
3766 | bool showSuccessfulTests = false; |
3767 | bool shouldDebugBreak = false; |
3768 | bool noThrow = false; |
3769 | bool showHelp = false; |
3770 | bool showInvisibles = false; |
3771 | bool filenamesAsTags = false; |
3772 | bool libIdentify = false; |
3773 | |
3774 | int abortAfter = -1; |
3775 | unsigned int rngSeed = 0; |
3776 | int benchmarkResolutionMultiple = 100; |
3777 | |
3778 | Verbosity verbosity = Verbosity::Normal; |
3779 | WarnAbout::What warnings = WarnAbout::Nothing; |
3780 | ShowDurations::OrNot showDurations = ShowDurations::DefaultForReporter; |
3781 | RunTests::InWhatOrder runOrder = RunTests::InDeclarationOrder; |
3782 | UseColour::YesOrNo useColour = UseColour::Auto; |
3783 | WaitForKeypress::When waitForKeypress = WaitForKeypress::Never; |
3784 | |
3785 | std::string outputFilename; |
3786 | std::string name; |
3787 | std::string processName; |
3788 | #ifndef CATCH_CONFIG_DEFAULT_REPORTER |
3789 | #define CATCH_CONFIG_DEFAULT_REPORTER "console" |
3790 | #endif |
3791 | std::string reporterName = CATCH_CONFIG_DEFAULT_REPORTER; |
3792 | #undef CATCH_CONFIG_DEFAULT_REPORTER |
3793 | |
3794 | std::vector<std::string> testsOrTags; |
3795 | std::vector<std::string> sectionsToRun; |
3796 | }; |
3797 | |
3798 | class Config : public IConfig { |
3799 | public: |
3800 | |
3801 | Config() = default; |
3802 | Config( ConfigData const& data ); |
3803 | virtual ~Config() = default; |
3804 | |
3805 | std::string const& getFilename() const; |
3806 | |
3807 | bool listTests() const; |
3808 | bool listTestNamesOnly() const; |
3809 | bool listTags() const; |
3810 | bool listReporters() const; |
3811 | |
3812 | std::string getProcessName() const; |
3813 | std::string const& getReporterName() const; |
3814 | |
3815 | std::vector<std::string> const& getTestsOrTags() const; |
3816 | std::vector<std::string> const& getSectionsToRun() const override; |
3817 | |
3818 | virtual TestSpec const& testSpec() const override; |
3819 | bool hasTestFilters() const override; |
3820 | |
3821 | bool showHelp() const; |
3822 | |
3823 | // IConfig interface |
3824 | bool allowThrows() const override; |
3825 | std::ostream& stream() const override; |
3826 | std::string name() const override; |
3827 | bool includeSuccessfulResults() const override; |
3828 | bool warnAboutMissingAssertions() const override; |
3829 | bool warnAboutNoTests() const override; |
3830 | ShowDurations::OrNot showDurations() const override; |
3831 | RunTests::InWhatOrder runOrder() const override; |
3832 | unsigned int rngSeed() const override; |
3833 | int benchmarkResolutionMultiple() const override; |
3834 | UseColour::YesOrNo useColour() const override; |
3835 | bool shouldDebugBreak() const override; |
3836 | int abortAfter() const override; |
3837 | bool showInvisibles() const override; |
3838 | Verbosity verbosity() const override; |
3839 | |
3840 | private: |
3841 | |
3842 | IStream const* openStream(); |
3843 | ConfigData m_data; |
3844 | |
3845 | std::unique_ptr<IStream const> m_stream; |
3846 | TestSpec m_testSpec; |
3847 | bool m_hasTestFilters = false; |
3848 | }; |
3849 | |
3850 | } // end namespace Catch |
3851 | |
3852 | // end catch_config.hpp |
3853 | // start catch_assertionresult.h |
3854 | |
3855 | #include <string> |
3856 | |
3857 | namespace Catch { |
3858 | |
3859 | struct AssertionResultData |
3860 | { |
3861 | AssertionResultData() = delete; |
3862 | |
3863 | AssertionResultData( ResultWas::OfType _resultType, LazyExpression const& _lazyExpression ); |
3864 | |
3865 | std::string message; |
3866 | mutable std::string reconstructedExpression; |
3867 | LazyExpression lazyExpression; |
3868 | ResultWas::OfType resultType; |
3869 | |
3870 | std::string reconstructExpression() const; |
3871 | }; |
3872 | |
3873 | class AssertionResult { |
3874 | public: |
3875 | AssertionResult() = delete; |
3876 | AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); |
3877 | |
3878 | bool isOk() const; |
3879 | bool succeeded() const; |
3880 | ResultWas::OfType getResultType() const; |
3881 | bool hasExpression() const; |
3882 | bool hasMessage() const; |
3883 | std::string getExpression() const; |
3884 | std::string getExpressionInMacro() const; |
3885 | bool hasExpandedExpression() const; |
3886 | std::string getExpandedExpression() const; |
3887 | std::string getMessage() const; |
3888 | SourceLineInfo getSourceInfo() const; |
3889 | StringRef getTestMacroName() const; |
3890 | |
3891 | //protected: |
3892 | AssertionInfo m_info; |
3893 | AssertionResultData m_resultData; |
3894 | }; |
3895 | |
3896 | } // end namespace Catch |
3897 | |
3898 | // end catch_assertionresult.h |
3899 | // start catch_option.hpp |
3900 | |
3901 | namespace Catch { |
3902 | |
3903 | // An optional type |
3904 | template<typename T> |
3905 | class Option { |
3906 | public: |
3907 | Option() : nullableValue( nullptr ) {} |
3908 | Option( T const& _value ) |
3909 | : nullableValue( new( storage ) T( _value ) ) |
3910 | {} |
3911 | Option( Option const& _other ) |
3912 | : nullableValue( _other ? new( storage ) T( *_other ) : nullptr ) |
3913 | {} |
3914 | |
3915 | ~Option() { |
3916 | reset(); |
3917 | } |
3918 | |
3919 | Option& operator= ( Option const& _other ) { |
3920 | if( &_other != this ) { |
3921 | reset(); |
3922 | if( _other ) |
3923 | nullableValue = new( storage ) T( *_other ); |
3924 | } |
3925 | return *this; |
3926 | } |
3927 | Option& operator = ( T const& _value ) { |
3928 | reset(); |
3929 | nullableValue = new( storage ) T( _value ); |
3930 | return *this; |
3931 | } |
3932 | |
3933 | void reset() { |
3934 | if( nullableValue ) |
3935 | nullableValue->~T(); |
3936 | nullableValue = nullptr; |
3937 | } |
3938 | |
3939 | T& operator*() { return *nullableValue; } |
3940 | T const& operator*() const { return *nullableValue; } |
3941 | T* operator->() { return nullableValue; } |
3942 | const T* operator->() const { return nullableValue; } |
3943 | |
3944 | T valueOr( T const& defaultValue ) const { |
3945 | return nullableValue ? *nullableValue : defaultValue; |
3946 | } |
3947 | |
3948 | bool some() const { return nullableValue != nullptr; } |
3949 | bool none() const { return nullableValue == nullptr; } |
3950 | |
3951 | bool operator !() const { return nullableValue == nullptr; } |
3952 | explicit operator bool() const { |
3953 | return some(); |
3954 | } |
3955 | |
3956 | private: |
3957 | T *nullableValue; |
3958 | alignas(alignof(T)) char storage[sizeof(T)]; |
3959 | }; |
3960 | |
3961 | } // end namespace Catch |
3962 | |
3963 | // end catch_option.hpp |
3964 | #include <string> |
3965 | #include <iosfwd> |
3966 | #include <map> |
3967 | #include <set> |
3968 | #include <memory> |
3969 | |
3970 | namespace Catch { |
3971 | |
3972 | struct ReporterConfig { |
3973 | explicit ReporterConfig( IConfigPtr const& _fullConfig ); |
3974 | |
3975 | ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream ); |
3976 | |
3977 | std::ostream& stream() const; |
3978 | IConfigPtr fullConfig() const; |
3979 | |
3980 | private: |
3981 | std::ostream* m_stream; |
3982 | IConfigPtr m_fullConfig; |
3983 | }; |
3984 | |
3985 | struct ReporterPreferences { |
3986 | bool shouldRedirectStdOut = false; |
3987 | bool shouldReportAllAssertions = false; |
3988 | }; |
3989 | |
3990 | template<typename T> |
3991 | struct LazyStat : Option<T> { |
3992 | LazyStat& operator=( T const& _value ) { |
3993 | Option<T>::operator=( _value ); |
3994 | used = false; |
3995 | return *this; |
3996 | } |
3997 | void reset() { |
3998 | Option<T>::reset(); |
3999 | used = false; |
4000 | } |
4001 | bool used = false; |
4002 | }; |
4003 | |
4004 | struct TestRunInfo { |
4005 | TestRunInfo( std::string const& _name ); |
4006 | std::string name; |
4007 | }; |
4008 | struct GroupInfo { |
4009 | GroupInfo( std::string const& _name, |
4010 | std::size_t _groupIndex, |
4011 | std::size_t _groupsCount ); |
4012 | |
4013 | std::string name; |
4014 | std::size_t groupIndex; |
4015 | std::size_t groupsCounts; |
4016 | }; |
4017 | |
4018 | struct AssertionStats { |
4019 | AssertionStats( AssertionResult const& _assertionResult, |
4020 | std::vector<MessageInfo> const& _infoMessages, |
4021 | Totals const& _totals ); |
4022 | |
4023 | AssertionStats( AssertionStats const& ) = default; |
4024 | AssertionStats( AssertionStats && ) = default; |
4025 | AssertionStats& operator = ( AssertionStats const& ) = default; |
4026 | AssertionStats& operator = ( AssertionStats && ) = default; |
4027 | virtual ~AssertionStats(); |
4028 | |
4029 | AssertionResult assertionResult; |
4030 | std::vector<MessageInfo> infoMessages; |
4031 | Totals totals; |
4032 | }; |
4033 | |
4034 | struct SectionStats { |
4035 | SectionStats( SectionInfo const& _sectionInfo, |
4036 | Counts const& _assertions, |
4037 | double _durationInSeconds, |
4038 | bool _missingAssertions ); |
4039 | SectionStats( SectionStats const& ) = default; |
4040 | SectionStats( SectionStats && ) = default; |
4041 | SectionStats& operator = ( SectionStats const& ) = default; |
4042 | SectionStats& operator = ( SectionStats && ) = default; |
4043 | virtual ~SectionStats(); |
4044 | |
4045 | SectionInfo sectionInfo; |
4046 | Counts assertions; |
4047 | double durationInSeconds; |
4048 | bool missingAssertions; |
4049 | }; |
4050 | |
4051 | struct TestCaseStats { |
4052 | TestCaseStats( TestCaseInfo const& _testInfo, |
4053 | Totals const& _totals, |
4054 | std::string const& _stdOut, |
4055 | std::string const& _stdErr, |
4056 | bool _aborting ); |
4057 | |
4058 | TestCaseStats( TestCaseStats const& ) = default; |
4059 | TestCaseStats( TestCaseStats && ) = default; |
4060 | TestCaseStats& operator = ( TestCaseStats const& ) = default; |
4061 | TestCaseStats& operator = ( TestCaseStats && ) = default; |
4062 | virtual ~TestCaseStats(); |
4063 | |
4064 | TestCaseInfo testInfo; |
4065 | Totals totals; |
4066 | std::string stdOut; |
4067 | std::string stdErr; |
4068 | bool aborting; |
4069 | }; |
4070 | |
4071 | struct TestGroupStats { |
4072 | TestGroupStats( GroupInfo const& _groupInfo, |
4073 | Totals const& _totals, |
4074 | bool _aborting ); |
4075 | TestGroupStats( GroupInfo const& _groupInfo ); |
4076 | |
4077 | TestGroupStats( TestGroupStats const& ) = default; |
4078 | TestGroupStats( TestGroupStats && ) = default; |
4079 | TestGroupStats& operator = ( TestGroupStats const& ) = default; |
4080 | TestGroupStats& operator = ( TestGroupStats && ) = default; |
4081 | virtual ~TestGroupStats(); |
4082 | |
4083 | GroupInfo groupInfo; |
4084 | Totals totals; |
4085 | bool aborting; |
4086 | }; |
4087 | |
4088 | struct TestRunStats { |
4089 | TestRunStats( TestRunInfo const& _runInfo, |
4090 | Totals const& _totals, |
4091 | bool _aborting ); |
4092 | |
4093 | TestRunStats( TestRunStats const& ) = default; |
4094 | TestRunStats( TestRunStats && ) = default; |
4095 | TestRunStats& operator = ( TestRunStats const& ) = default; |
4096 | TestRunStats& operator = ( TestRunStats && ) = default; |
4097 | virtual ~TestRunStats(); |
4098 | |
4099 | TestRunInfo runInfo; |
4100 | Totals totals; |
4101 | bool aborting; |
4102 | }; |
4103 | |
4104 | struct BenchmarkInfo { |
4105 | std::string name; |
4106 | }; |
4107 | struct BenchmarkStats { |
4108 | BenchmarkInfo info; |
4109 | std::size_t iterations; |
4110 | uint64_t elapsedTimeInNanoseconds; |
4111 | }; |
4112 | |
4113 | struct IStreamingReporter { |
4114 | virtual ~IStreamingReporter() = default; |
4115 | |
4116 | // Implementing class must also provide the following static methods: |
4117 | // static std::string getDescription(); |
4118 | // static std::set<Verbosity> getSupportedVerbosities() |
4119 | |
4120 | virtual ReporterPreferences getPreferences() const = 0; |
4121 | |
4122 | virtual void noMatchingTestCases( std::string const& spec ) = 0; |
4123 | |
4124 | virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; |
4125 | virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0; |
4126 | |
4127 | virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; |
4128 | virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; |
4129 | |
4130 | // *** experimental *** |
4131 | virtual void benchmarkStarting( BenchmarkInfo const& ) {} |
4132 | |
4133 | virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; |
4134 | |
4135 | // The return value indicates if the messages buffer should be cleared: |
4136 | virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; |
4137 | |
4138 | // *** experimental *** |
4139 | virtual void benchmarkEnded( BenchmarkStats const& ) {} |
4140 | |
4141 | virtual void sectionEnded( SectionStats const& sectionStats ) = 0; |
4142 | virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; |
4143 | virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; |
4144 | virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; |
4145 | |
4146 | virtual void skipTest( TestCaseInfo const& testInfo ) = 0; |
4147 | |
4148 | // Default empty implementation provided |
4149 | virtual void fatalErrorEncountered( StringRef name ); |
4150 | |
4151 | virtual bool isMulti() const; |
4152 | }; |
4153 | using IStreamingReporterPtr = std::unique_ptr<IStreamingReporter>; |
4154 | |
4155 | struct IReporterFactory { |
4156 | virtual ~IReporterFactory(); |
4157 | virtual IStreamingReporterPtr create( ReporterConfig const& config ) const = 0; |
4158 | virtual std::string getDescription() const = 0; |
4159 | }; |
4160 | using IReporterFactoryPtr = std::shared_ptr<IReporterFactory>; |
4161 | |
4162 | struct IReporterRegistry { |
4163 | using FactoryMap = std::map<std::string, IReporterFactoryPtr>; |
4164 | using Listeners = std::vector<IReporterFactoryPtr>; |
4165 | |
4166 | virtual ~IReporterRegistry(); |
4167 | virtual IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const = 0; |
4168 | virtual FactoryMap const& getFactories() const = 0; |
4169 | virtual Listeners const& getListeners() const = 0; |
4170 | }; |
4171 | |
4172 | } // end namespace Catch |
4173 | |
4174 | // end catch_interfaces_reporter.h |
4175 | #include <algorithm> |
4176 | #include <cstring> |
4177 | #include <cfloat> |
4178 | #include <cstdio> |
4179 | #include <cassert> |
4180 | #include <memory> |
4181 | #include <ostream> |
4182 | |
4183 | namespace Catch { |
4184 | void prepareExpandedExpression(AssertionResult& result); |
4185 | |
4186 | // Returns double formatted as %.3f (format expected on output) |
4187 | std::string getFormattedDuration( double duration ); |
4188 | |
4189 | template<typename DerivedT> |
4190 | struct StreamingReporterBase : IStreamingReporter { |
4191 | |
4192 | StreamingReporterBase( ReporterConfig const& _config ) |
4193 | : m_config( _config.fullConfig() ), |
4194 | stream( _config.stream() ) |
4195 | { |
4196 | m_reporterPrefs.shouldRedirectStdOut = false; |
4197 | if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) ) |
4198 | CATCH_ERROR( "Verbosity level not supported by this reporter" ); |
4199 | } |
4200 | |
4201 | ReporterPreferences getPreferences() const override { |
4202 | return m_reporterPrefs; |
4203 | } |
4204 | |
4205 | static std::set<Verbosity> getSupportedVerbosities() { |
4206 | return { Verbosity::Normal }; |
4207 | } |
4208 | |
4209 | ~StreamingReporterBase() override = default; |
4210 | |
4211 | void noMatchingTestCases(std::string const&) override {} |
4212 | |
4213 | void testRunStarting(TestRunInfo const& _testRunInfo) override { |
4214 | currentTestRunInfo = _testRunInfo; |
4215 | } |
4216 | void testGroupStarting(GroupInfo const& _groupInfo) override { |
4217 | currentGroupInfo = _groupInfo; |
4218 | } |
4219 | |
4220 | void testCaseStarting(TestCaseInfo const& _testInfo) override { |
4221 | currentTestCaseInfo = _testInfo; |
4222 | } |
4223 | void sectionStarting(SectionInfo const& _sectionInfo) override { |
4224 | m_sectionStack.push_back(_sectionInfo); |
4225 | } |
4226 | |
4227 | void sectionEnded(SectionStats const& /* _sectionStats */) override { |
4228 | m_sectionStack.pop_back(); |
4229 | } |
4230 | void testCaseEnded(TestCaseStats const& /* _testCaseStats */) override { |
4231 | currentTestCaseInfo.reset(); |
4232 | } |
4233 | void testGroupEnded(TestGroupStats const& /* _testGroupStats */) override { |
4234 | currentGroupInfo.reset(); |
4235 | } |
4236 | void testRunEnded(TestRunStats const& /* _testRunStats */) override { |
4237 | currentTestCaseInfo.reset(); |
4238 | currentGroupInfo.reset(); |
4239 | currentTestRunInfo.reset(); |
4240 | } |
4241 | |
4242 | void skipTest(TestCaseInfo const&) override { |
4243 | // Don't do anything with this by default. |
4244 | // It can optionally be overridden in the derived class. |
4245 | } |
4246 | |
4247 | IConfigPtr m_config; |
4248 | std::ostream& stream; |
4249 | |
4250 | LazyStat<TestRunInfo> currentTestRunInfo; |
4251 | LazyStat<GroupInfo> currentGroupInfo; |
4252 | LazyStat<TestCaseInfo> currentTestCaseInfo; |
4253 | |
4254 | std::vector<SectionInfo> m_sectionStack; |
4255 | ReporterPreferences m_reporterPrefs; |
4256 | }; |
4257 | |
4258 | template<typename DerivedT> |
4259 | struct CumulativeReporterBase : IStreamingReporter { |
4260 | template<typename T, typename ChildNodeT> |
4261 | struct Node { |
4262 | explicit Node( T const& _value ) : value( _value ) {} |
4263 | virtual ~Node() {} |
4264 | |
4265 | using ChildNodes = std::vector<std::shared_ptr<ChildNodeT>>; |
4266 | T value; |
4267 | ChildNodes children; |
4268 | }; |
4269 | struct SectionNode { |
4270 | explicit SectionNode(SectionStats const& _stats) : stats(_stats) {} |
4271 | virtual ~SectionNode() = default; |
4272 | |
4273 | bool operator == (SectionNode const& other) const { |
4274 | return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo; |
4275 | } |
4276 | bool operator == (std::shared_ptr<SectionNode> const& other) const { |
4277 | return operator==(*other); |
4278 | } |
4279 | |
4280 | SectionStats stats; |
4281 | using ChildSections = std::vector<std::shared_ptr<SectionNode>>; |
4282 | using Assertions = std::vector<AssertionStats>; |
4283 | ChildSections childSections; |
4284 | Assertions assertions; |
4285 | std::string stdOut; |
4286 | std::string stdErr; |
4287 | }; |
4288 | |
4289 | struct BySectionInfo { |
4290 | BySectionInfo( SectionInfo const& other ) : m_other( other ) {} |
4291 | BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} |
4292 | bool operator() (std::shared_ptr<SectionNode> const& node) const { |
4293 | return ((node->stats.sectionInfo.name == m_other.name) && |
4294 | (node->stats.sectionInfo.lineInfo == m_other.lineInfo)); |
4295 | } |
4296 | void operator=(BySectionInfo const&) = delete; |
4297 | |
4298 | private: |
4299 | SectionInfo const& m_other; |
4300 | }; |
4301 | |
4302 | using TestCaseNode = Node<TestCaseStats, SectionNode>; |
4303 | using TestGroupNode = Node<TestGroupStats, TestCaseNode>; |
4304 | using TestRunNode = Node<TestRunStats, TestGroupNode>; |
4305 | |
4306 | CumulativeReporterBase( ReporterConfig const& _config ) |
4307 | : m_config( _config.fullConfig() ), |
4308 | stream( _config.stream() ) |
4309 | { |
4310 | m_reporterPrefs.shouldRedirectStdOut = false; |
4311 | if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) ) |
4312 | CATCH_ERROR( "Verbosity level not supported by this reporter" ); |
4313 | } |
4314 | ~CumulativeReporterBase() override = default; |
4315 | |
4316 | ReporterPreferences getPreferences() const override { |
4317 | return m_reporterPrefs; |
4318 | } |
4319 | |
4320 | static std::set<Verbosity> getSupportedVerbosities() { |
4321 | return { Verbosity::Normal }; |
4322 | } |
4323 | |
4324 | void testRunStarting( TestRunInfo const& ) override {} |
4325 | void testGroupStarting( GroupInfo const& ) override {} |
4326 | |
4327 | void testCaseStarting( TestCaseInfo const& ) override {} |
4328 | |
4329 | void sectionStarting( SectionInfo const& sectionInfo ) override { |
4330 | SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); |
4331 | std::shared_ptr<SectionNode> node; |
4332 | if( m_sectionStack.empty() ) { |
4333 | if( !m_rootSection ) |
4334 | m_rootSection = std::make_shared<SectionNode>( incompleteStats ); |
4335 | node = m_rootSection; |
4336 | } |
4337 | else { |
4338 | SectionNode& parentNode = *m_sectionStack.back(); |
4339 | auto it = |
4340 | std::find_if( parentNode.childSections.begin(), |
4341 | parentNode.childSections.end(), |
4342 | BySectionInfo( sectionInfo ) ); |
4343 | if( it == parentNode.childSections.end() ) { |
4344 | node = std::make_shared<SectionNode>( incompleteStats ); |
4345 | parentNode.childSections.push_back( node ); |
4346 | } |
4347 | else |
4348 | node = *it; |
4349 | } |
4350 | m_sectionStack.push_back( node ); |
4351 | m_deepestSection = std::move(node); |
4352 | } |
4353 | |
4354 | void assertionStarting(AssertionInfo const&) override {} |
4355 | |
4356 | bool assertionEnded(AssertionStats const& assertionStats) override { |
4357 | assert(!m_sectionStack.empty()); |
4358 | // AssertionResult holds a pointer to a temporary DecomposedExpression, |
4359 | // which getExpandedExpression() calls to build the expression string. |
4360 | // Our section stack copy of the assertionResult will likely outlive the |
4361 | // temporary, so it must be expanded or discarded now to avoid calling |
4362 | // a destroyed object later. |
4363 | prepareExpandedExpression(const_cast<AssertionResult&>( assertionStats.assertionResult ) ); |
4364 | SectionNode& sectionNode = *m_sectionStack.back(); |
4365 | sectionNode.assertions.push_back(assertionStats); |
4366 | return true; |
4367 | } |
4368 | void sectionEnded(SectionStats const& sectionStats) override { |
4369 | assert(!m_sectionStack.empty()); |
4370 | SectionNode& node = *m_sectionStack.back(); |
4371 | node.stats = sectionStats; |
4372 | m_sectionStack.pop_back(); |
4373 | } |
4374 | void testCaseEnded(TestCaseStats const& testCaseStats) override { |
4375 | auto node = std::make_shared<TestCaseNode>(testCaseStats); |
4376 | assert(m_sectionStack.size() == 0); |
4377 | node->children.push_back(m_rootSection); |
4378 | m_testCases.push_back(node); |
4379 | m_rootSection.reset(); |
4380 | |
4381 | assert(m_deepestSection); |
4382 | m_deepestSection->stdOut = testCaseStats.stdOut; |
4383 | m_deepestSection->stdErr = testCaseStats.stdErr; |
4384 | } |
4385 | void testGroupEnded(TestGroupStats const& testGroupStats) override { |
4386 | auto node = std::make_shared<TestGroupNode>(testGroupStats); |
4387 | node->children.swap(m_testCases); |
4388 | m_testGroups.push_back(node); |
4389 | } |
4390 | void testRunEnded(TestRunStats const& testRunStats) override { |
4391 | auto node = std::make_shared<TestRunNode>(testRunStats); |
4392 | node->children.swap(m_testGroups); |
4393 | m_testRuns.push_back(node); |
4394 | testRunEndedCumulative(); |
4395 | } |
4396 | virtual void testRunEndedCumulative() = 0; |
4397 | |
4398 | void skipTest(TestCaseInfo const&) override {} |
4399 | |
4400 | IConfigPtr m_config; |
4401 | std::ostream& stream; |
4402 | std::vector<AssertionStats> m_assertions; |
4403 | std::vector<std::vector<std::shared_ptr<SectionNode>>> m_sections; |
4404 | std::vector<std::shared_ptr<TestCaseNode>> m_testCases; |
4405 | std::vector<std::shared_ptr<TestGroupNode>> m_testGroups; |
4406 | |
4407 | std::vector<std::shared_ptr<TestRunNode>> m_testRuns; |
4408 | |
4409 | std::shared_ptr<SectionNode> m_rootSection; |
4410 | std::shared_ptr<SectionNode> m_deepestSection; |
4411 | std::vector<std::shared_ptr<SectionNode>> m_sectionStack; |
4412 | ReporterPreferences m_reporterPrefs; |
4413 | }; |
4414 | |
4415 | template<char C> |
4416 | char const* getLineOfChars() { |
4417 | static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; |
4418 | if( !*line ) { |
4419 | std::memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); |
4420 | line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; |
4421 | } |
4422 | return line; |
4423 | } |
4424 | |
4425 | struct TestEventListenerBase : StreamingReporterBase<TestEventListenerBase> { |
4426 | TestEventListenerBase( ReporterConfig const& _config ); |
4427 | |
4428 | void assertionStarting(AssertionInfo const&) override; |
4429 | bool assertionEnded(AssertionStats const&) override; |
4430 | }; |
4431 | |
4432 | } // end namespace Catch |
4433 | |
4434 | // end catch_reporter_bases.hpp |
4435 | // start catch_console_colour.h |
4436 | |
4437 | namespace Catch { |
4438 | |
4439 | struct Colour { |
4440 | enum Code { |
4441 | None = 0, |
4442 | |
4443 | White, |
4444 | Red, |
4445 | Green, |
4446 | Blue, |
4447 | Cyan, |
4448 | Yellow, |
4449 | Grey, |
4450 | |
4451 | Bright = 0x10, |
4452 | |
4453 | BrightRed = Bright | Red, |
4454 | BrightGreen = Bright | Green, |
4455 | LightGrey = Bright | Grey, |
4456 | BrightWhite = Bright | White, |
4457 | BrightYellow = Bright | Yellow, |
4458 | |
4459 | // By intention |
4460 | FileName = LightGrey, |
4461 | Warning = BrightYellow, |
4462 | ResultError = BrightRed, |
4463 | ResultSuccess = BrightGreen, |
4464 | ResultExpectedFailure = Warning, |
4465 | |
4466 | Error = BrightRed, |
4467 | Success = Green, |
4468 | |
4469 | OriginalExpression = Cyan, |
4470 | ReconstructedExpression = BrightYellow, |
4471 | |
4472 | SecondaryText = LightGrey, |
4473 | = White |
4474 | }; |
4475 | |
4476 | // Use constructed object for RAII guard |
4477 | Colour( Code _colourCode ); |
4478 | Colour( Colour&& other ) noexcept; |
4479 | Colour& operator=( Colour&& other ) noexcept; |
4480 | ~Colour(); |
4481 | |
4482 | // Use static method for one-shot changes |
4483 | static void use( Code _colourCode ); |
4484 | |
4485 | private: |
4486 | bool m_moved = false; |
4487 | }; |
4488 | |
4489 | std::ostream& operator << ( std::ostream& os, Colour const& ); |
4490 | |
4491 | } // end namespace Catch |
4492 | |
4493 | // end catch_console_colour.h |
4494 | // start catch_reporter_registrars.hpp |
4495 | |
4496 | |
4497 | namespace Catch { |
4498 | |
4499 | template<typename T> |
4500 | class ReporterRegistrar { |
4501 | |
4502 | class ReporterFactory : public IReporterFactory { |
4503 | |
4504 | virtual IStreamingReporterPtr create( ReporterConfig const& config ) const override { |
4505 | return std::unique_ptr<T>( new T( config ) ); |
4506 | } |
4507 | |
4508 | virtual std::string getDescription() const override { |
4509 | return T::getDescription(); |
4510 | } |
4511 | }; |
4512 | |
4513 | public: |
4514 | |
4515 | explicit ReporterRegistrar( std::string const& name ) { |
4516 | getMutableRegistryHub().registerReporter( name, std::make_shared<ReporterFactory>() ); |
4517 | } |
4518 | }; |
4519 | |
4520 | template<typename T> |
4521 | class ListenerRegistrar { |
4522 | |
4523 | class ListenerFactory : public IReporterFactory { |
4524 | |
4525 | virtual IStreamingReporterPtr create( ReporterConfig const& config ) const override { |
4526 | return std::unique_ptr<T>( new T( config ) ); |
4527 | } |
4528 | virtual std::string getDescription() const override { |
4529 | return std::string(); |
4530 | } |
4531 | }; |
4532 | |
4533 | public: |
4534 | |
4535 | ListenerRegistrar() { |
4536 | getMutableRegistryHub().registerListener( std::make_shared<ListenerFactory>() ); |
4537 | } |
4538 | }; |
4539 | } |
4540 | |
4541 | #if !defined(CATCH_CONFIG_DISABLE) |
4542 | |
4543 | #define CATCH_REGISTER_REPORTER( name, reporterType ) \ |
4544 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ |
4545 | namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); } \ |
4546 | CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS |
4547 | |
4548 | #define CATCH_REGISTER_LISTENER( listenerType ) \ |
4549 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ |
4550 | namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; } \ |
4551 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS |
4552 | #else // CATCH_CONFIG_DISABLE |
4553 | |
4554 | #define CATCH_REGISTER_REPORTER(name, reporterType) |
4555 | #define CATCH_REGISTER_LISTENER(listenerType) |
4556 | |
4557 | #endif // CATCH_CONFIG_DISABLE |
4558 | |
4559 | // end catch_reporter_registrars.hpp |
4560 | // Allow users to base their work off existing reporters |
4561 | // start catch_reporter_compact.h |
4562 | |
4563 | namespace Catch { |
4564 | |
4565 | struct CompactReporter : StreamingReporterBase<CompactReporter> { |
4566 | |
4567 | using StreamingReporterBase::StreamingReporterBase; |
4568 | |
4569 | ~CompactReporter() override; |
4570 | |
4571 | static std::string getDescription(); |
4572 | |
4573 | ReporterPreferences getPreferences() const override; |
4574 | |
4575 | void noMatchingTestCases(std::string const& spec) override; |
4576 | |
4577 | void assertionStarting(AssertionInfo const&) override; |
4578 | |
4579 | bool assertionEnded(AssertionStats const& _assertionStats) override; |
4580 | |
4581 | void sectionEnded(SectionStats const& _sectionStats) override; |
4582 | |
4583 | void testRunEnded(TestRunStats const& _testRunStats) override; |
4584 | |
4585 | }; |
4586 | |
4587 | } // end namespace Catch |
4588 | |
4589 | // end catch_reporter_compact.h |
4590 | // start catch_reporter_console.h |
4591 | |
4592 | #if defined(_MSC_VER) |
4593 | #pragma warning(push) |
4594 | #pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch |
4595 | // Note that 4062 (not all labels are handled |
4596 | // and default is missing) is enabled |
4597 | #endif |
4598 | |
4599 | namespace Catch { |
4600 | // Fwd decls |
4601 | struct SummaryColumn; |
4602 | class TablePrinter; |
4603 | |
4604 | struct ConsoleReporter : StreamingReporterBase<ConsoleReporter> { |
4605 | std::unique_ptr<TablePrinter> m_tablePrinter; |
4606 | |
4607 | ConsoleReporter(ReporterConfig const& config); |
4608 | ~ConsoleReporter() override; |
4609 | static std::string getDescription(); |
4610 | |
4611 | void noMatchingTestCases(std::string const& spec) override; |
4612 | |
4613 | void assertionStarting(AssertionInfo const&) override; |
4614 | |
4615 | bool assertionEnded(AssertionStats const& _assertionStats) override; |
4616 | |
4617 | void sectionStarting(SectionInfo const& _sectionInfo) override; |
4618 | void sectionEnded(SectionStats const& _sectionStats) override; |
4619 | |
4620 | void benchmarkStarting(BenchmarkInfo const& info) override; |
4621 | void benchmarkEnded(BenchmarkStats const& stats) override; |
4622 | |
4623 | void testCaseEnded(TestCaseStats const& _testCaseStats) override; |
4624 | void testGroupEnded(TestGroupStats const& _testGroupStats) override; |
4625 | void testRunEnded(TestRunStats const& _testRunStats) override; |
4626 | |
4627 | private: |
4628 | |
4629 | void lazyPrint(); |
4630 | |
4631 | void lazyPrintWithoutClosingBenchmarkTable(); |
4632 | void lazyPrintRunInfo(); |
4633 | void lazyPrintGroupInfo(); |
4634 | void printTestCaseAndSectionHeader(); |
4635 | |
4636 | void printClosedHeader(std::string const& _name); |
4637 | void printOpenHeader(std::string const& _name); |
4638 | |
4639 | // if string has a : in first line will set indent to follow it on |
4640 | // subsequent lines |
4641 | void printHeaderString(std::string const& _string, std::size_t indent = 0); |
4642 | |
4643 | void printTotals(Totals const& totals); |
4644 | void printSummaryRow(std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row); |
4645 | |
4646 | void printTotalsDivider(Totals const& totals); |
4647 | void printSummaryDivider(); |
4648 | |
4649 | private: |
4650 | bool = false; |
4651 | }; |
4652 | |
4653 | } // end namespace Catch |
4654 | |
4655 | #if defined(_MSC_VER) |
4656 | #pragma warning(pop) |
4657 | #endif |
4658 | |
4659 | // end catch_reporter_console.h |
4660 | // start catch_reporter_junit.h |
4661 | |
4662 | // start catch_xmlwriter.h |
4663 | |
4664 | #include <vector> |
4665 | |
4666 | namespace Catch { |
4667 | |
4668 | class XmlEncode { |
4669 | public: |
4670 | enum ForWhat { ForTextNodes, ForAttributes }; |
4671 | |
4672 | XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ); |
4673 | |
4674 | void encodeTo( std::ostream& os ) const; |
4675 | |
4676 | friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ); |
4677 | |
4678 | private: |
4679 | std::string m_str; |
4680 | ForWhat m_forWhat; |
4681 | }; |
4682 | |
4683 | class XmlWriter { |
4684 | public: |
4685 | |
4686 | class ScopedElement { |
4687 | public: |
4688 | ScopedElement( XmlWriter* writer ); |
4689 | |
4690 | ScopedElement( ScopedElement&& other ) noexcept; |
4691 | ScopedElement& operator=( ScopedElement&& other ) noexcept; |
4692 | |
4693 | ~ScopedElement(); |
4694 | |
4695 | ScopedElement& writeText( std::string const& text, bool indent = true ); |
4696 | |
4697 | template<typename T> |
4698 | ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { |
4699 | m_writer->writeAttribute( name, attribute ); |
4700 | return *this; |
4701 | } |
4702 | |
4703 | private: |
4704 | mutable XmlWriter* m_writer = nullptr; |
4705 | }; |
4706 | |
4707 | XmlWriter( std::ostream& os = Catch::cout() ); |
4708 | ~XmlWriter(); |
4709 | |
4710 | XmlWriter( XmlWriter const& ) = delete; |
4711 | XmlWriter& operator=( XmlWriter const& ) = delete; |
4712 | |
4713 | XmlWriter& startElement( std::string const& name ); |
4714 | |
4715 | ScopedElement scopedElement( std::string const& name ); |
4716 | |
4717 | XmlWriter& endElement(); |
4718 | |
4719 | XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ); |
4720 | |
4721 | XmlWriter& writeAttribute( std::string const& name, bool attribute ); |
4722 | |
4723 | template<typename T> |
4724 | XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { |
4725 | ReusableStringStream ; |
4726 | rss << attribute; |
4727 | return writeAttribute( name, rss.str() ); |
4728 | } |
4729 | |
4730 | XmlWriter& writeText( std::string const& text, bool indent = true ); |
4731 | |
4732 | XmlWriter& writeComment( std::string const& text ); |
4733 | |
4734 | void writeStylesheetRef( std::string const& url ); |
4735 | |
4736 | XmlWriter& writeBlankLine(); |
4737 | |
4738 | void ensureTagClosed(); |
4739 | |
4740 | private: |
4741 | |
4742 | void writeDeclaration(); |
4743 | |
4744 | void newlineIfNecessary(); |
4745 | |
4746 | bool m_tagIsOpen = false; |
4747 | bool m_needsNewline = false; |
4748 | std::vector<std::string> m_tags; |
4749 | std::string m_indent; |
4750 | std::ostream& m_os; |
4751 | }; |
4752 | |
4753 | } |
4754 | |
4755 | // end catch_xmlwriter.h |
4756 | namespace Catch { |
4757 | |
4758 | class JunitReporter : public CumulativeReporterBase<JunitReporter> { |
4759 | public: |
4760 | JunitReporter(ReporterConfig const& _config); |
4761 | |
4762 | ~JunitReporter() override; |
4763 | |
4764 | static std::string getDescription(); |
4765 | |
4766 | void noMatchingTestCases(std::string const& /*spec*/) override; |
4767 | |
4768 | void testRunStarting(TestRunInfo const& runInfo) override; |
4769 | |
4770 | void testGroupStarting(GroupInfo const& groupInfo) override; |
4771 | |
4772 | void testCaseStarting(TestCaseInfo const& testCaseInfo) override; |
4773 | bool assertionEnded(AssertionStats const& assertionStats) override; |
4774 | |
4775 | void testCaseEnded(TestCaseStats const& testCaseStats) override; |
4776 | |
4777 | void testGroupEnded(TestGroupStats const& testGroupStats) override; |
4778 | |
4779 | void testRunEndedCumulative() override; |
4780 | |
4781 | void writeGroup(TestGroupNode const& groupNode, double suiteTime); |
4782 | |
4783 | void writeTestCase(TestCaseNode const& testCaseNode); |
4784 | |
4785 | void writeSection(std::string const& className, |
4786 | std::string const& rootName, |
4787 | SectionNode const& sectionNode); |
4788 | |
4789 | void writeAssertions(SectionNode const& sectionNode); |
4790 | void writeAssertion(AssertionStats const& stats); |
4791 | |
4792 | XmlWriter xml; |
4793 | Timer suiteTimer; |
4794 | std::string stdOutForSuite; |
4795 | std::string stdErrForSuite; |
4796 | unsigned int unexpectedExceptions = 0; |
4797 | bool m_okToFail = false; |
4798 | }; |
4799 | |
4800 | } // end namespace Catch |
4801 | |
4802 | // end catch_reporter_junit.h |
4803 | // start catch_reporter_xml.h |
4804 | |
4805 | namespace Catch { |
4806 | class XmlReporter : public StreamingReporterBase<XmlReporter> { |
4807 | public: |
4808 | XmlReporter(ReporterConfig const& _config); |
4809 | |
4810 | ~XmlReporter() override; |
4811 | |
4812 | static std::string getDescription(); |
4813 | |
4814 | virtual std::string getStylesheetRef() const; |
4815 | |
4816 | void writeSourceInfo(SourceLineInfo const& sourceInfo); |
4817 | |
4818 | public: // StreamingReporterBase |
4819 | |
4820 | void noMatchingTestCases(std::string const& s) override; |
4821 | |
4822 | void testRunStarting(TestRunInfo const& testInfo) override; |
4823 | |
4824 | void testGroupStarting(GroupInfo const& groupInfo) override; |
4825 | |
4826 | void testCaseStarting(TestCaseInfo const& testInfo) override; |
4827 | |
4828 | void sectionStarting(SectionInfo const& sectionInfo) override; |
4829 | |
4830 | void assertionStarting(AssertionInfo const&) override; |
4831 | |
4832 | bool assertionEnded(AssertionStats const& assertionStats) override; |
4833 | |
4834 | void sectionEnded(SectionStats const& sectionStats) override; |
4835 | |
4836 | void testCaseEnded(TestCaseStats const& testCaseStats) override; |
4837 | |
4838 | void testGroupEnded(TestGroupStats const& testGroupStats) override; |
4839 | |
4840 | void testRunEnded(TestRunStats const& testRunStats) override; |
4841 | |
4842 | private: |
4843 | Timer m_testCaseTimer; |
4844 | XmlWriter m_xml; |
4845 | int m_sectionDepth = 0; |
4846 | }; |
4847 | |
4848 | } // end namespace Catch |
4849 | |
4850 | // end catch_reporter_xml.h |
4851 | |
4852 | // end catch_external_interfaces.h |
4853 | #endif |
4854 | |
4855 | #endif // ! CATCH_CONFIG_IMPL_ONLY |
4856 | |
4857 | #ifdef CATCH_IMPL |
4858 | // start catch_impl.hpp |
4859 | |
4860 | #ifdef __clang__ |
4861 | #pragma clang diagnostic push |
4862 | #pragma clang diagnostic ignored "-Wweak-vtables" |
4863 | #endif |
4864 | |
4865 | // Keep these here for external reporters |
4866 | // start catch_test_case_tracker.h |
4867 | |
4868 | #include <string> |
4869 | #include <vector> |
4870 | #include <memory> |
4871 | |
4872 | namespace Catch { |
4873 | namespace TestCaseTracking { |
4874 | |
4875 | struct NameAndLocation { |
4876 | std::string name; |
4877 | SourceLineInfo location; |
4878 | |
4879 | NameAndLocation( std::string const& _name, SourceLineInfo const& _location ); |
4880 | }; |
4881 | |
4882 | struct ITracker; |
4883 | |
4884 | using ITrackerPtr = std::shared_ptr<ITracker>; |
4885 | |
4886 | struct ITracker { |
4887 | virtual ~ITracker(); |
4888 | |
4889 | // static queries |
4890 | virtual NameAndLocation const& nameAndLocation() const = 0; |
4891 | |
4892 | // dynamic queries |
4893 | virtual bool isComplete() const = 0; // Successfully completed or failed |
4894 | virtual bool isSuccessfullyCompleted() const = 0; |
4895 | virtual bool isOpen() const = 0; // Started but not complete |
4896 | virtual bool hasChildren() const = 0; |
4897 | |
4898 | virtual ITracker& parent() = 0; |
4899 | |
4900 | // actions |
4901 | virtual void close() = 0; // Successfully complete |
4902 | virtual void fail() = 0; |
4903 | virtual void markAsNeedingAnotherRun() = 0; |
4904 | |
4905 | virtual void addChild( ITrackerPtr const& child ) = 0; |
4906 | virtual ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) = 0; |
4907 | virtual void openChild() = 0; |
4908 | |
4909 | // Debug/ checking |
4910 | virtual bool isSectionTracker() const = 0; |
4911 | virtual bool () const = 0; |
4912 | }; |
4913 | |
4914 | class TrackerContext { |
4915 | |
4916 | enum RunState { |
4917 | NotStarted, |
4918 | Executing, |
4919 | CompletedCycle |
4920 | }; |
4921 | |
4922 | ITrackerPtr m_rootTracker; |
4923 | ITracker* m_currentTracker = nullptr; |
4924 | RunState m_runState = NotStarted; |
4925 | |
4926 | public: |
4927 | |
4928 | static TrackerContext& instance(); |
4929 | |
4930 | ITracker& startRun(); |
4931 | void endRun(); |
4932 | |
4933 | void startCycle(); |
4934 | void completeCycle(); |
4935 | |
4936 | bool completedCycle() const; |
4937 | ITracker& currentTracker(); |
4938 | void setCurrentTracker( ITracker* tracker ); |
4939 | }; |
4940 | |
4941 | class TrackerBase : public ITracker { |
4942 | protected: |
4943 | enum CycleState { |
4944 | NotStarted, |
4945 | Executing, |
4946 | ExecutingChildren, |
4947 | NeedsAnotherRun, |
4948 | CompletedSuccessfully, |
4949 | Failed |
4950 | }; |
4951 | |
4952 | using Children = std::vector<ITrackerPtr>; |
4953 | NameAndLocation m_nameAndLocation; |
4954 | TrackerContext& m_ctx; |
4955 | ITracker* m_parent; |
4956 | Children m_children; |
4957 | CycleState m_runState = NotStarted; |
4958 | |
4959 | public: |
4960 | TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); |
4961 | |
4962 | NameAndLocation const& nameAndLocation() const override; |
4963 | bool isComplete() const override; |
4964 | bool isSuccessfullyCompleted() const override; |
4965 | bool isOpen() const override; |
4966 | bool hasChildren() const override; |
4967 | |
4968 | void addChild( ITrackerPtr const& child ) override; |
4969 | |
4970 | ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) override; |
4971 | ITracker& parent() override; |
4972 | |
4973 | void openChild() override; |
4974 | |
4975 | bool isSectionTracker() const override; |
4976 | bool isIndexTracker() const override; |
4977 | |
4978 | void open(); |
4979 | |
4980 | void close() override; |
4981 | void fail() override; |
4982 | void markAsNeedingAnotherRun() override; |
4983 | |
4984 | private: |
4985 | void moveToParent(); |
4986 | void moveToThis(); |
4987 | }; |
4988 | |
4989 | class SectionTracker : public TrackerBase { |
4990 | std::vector<std::string> m_filters; |
4991 | public: |
4992 | SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); |
4993 | |
4994 | bool isSectionTracker() const override; |
4995 | |
4996 | static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ); |
4997 | |
4998 | void tryOpen(); |
4999 | |
5000 | void addInitialFilters( std::vector<std::string> const& filters ); |
5001 | void addNextFilters( std::vector<std::string> const& filters ); |
5002 | }; |
5003 | |
5004 | class : public TrackerBase { |
5005 | int ; |
5006 | int = -1; |
5007 | public: |
5008 | IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size ); |
5009 | |
5010 | bool isIndexTracker() const override; |
5011 | void close() override; |
5012 | |
5013 | static IndexTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ); |
5014 | |
5015 | int index() const; |
5016 | |
5017 | void moveNext(); |
5018 | }; |
5019 | |
5020 | } // namespace TestCaseTracking |
5021 | |
5022 | using TestCaseTracking::ITracker; |
5023 | using TestCaseTracking::TrackerContext; |
5024 | using TestCaseTracking::SectionTracker; |
5025 | using TestCaseTracking::IndexTracker; |
5026 | |
5027 | } // namespace Catch |
5028 | |
5029 | // end catch_test_case_tracker.h |
5030 | |
5031 | // start catch_leak_detector.h |
5032 | |
5033 | namespace Catch { |
5034 | |
5035 | struct LeakDetector { |
5036 | LeakDetector(); |
5037 | }; |
5038 | |
5039 | } |
5040 | // end catch_leak_detector.h |
5041 | // Cpp files will be included in the single-header file here |
5042 | // start catch_approx.cpp |
5043 | |
5044 | #include <cmath> |
5045 | #include <limits> |
5046 | |
5047 | namespace { |
5048 | |
5049 | // Performs equivalent check of std::fabs(lhs - rhs) <= margin |
5050 | // But without the subtraction to allow for INFINITY in comparison |
5051 | bool marginComparison(double lhs, double rhs, double margin) { |
5052 | return (lhs + margin >= rhs) && (rhs + margin >= lhs); |
5053 | } |
5054 | |
5055 | } |
5056 | |
5057 | namespace Catch { |
5058 | namespace Detail { |
5059 | |
5060 | Approx::Approx ( double value ) |
5061 | : m_epsilon( std::numeric_limits<float>::epsilon()*100 ), |
5062 | m_margin( 0.0 ), |
5063 | m_scale( 0.0 ), |
5064 | m_value( value ) |
5065 | {} |
5066 | |
5067 | Approx Approx::custom() { |
5068 | return Approx( 0 ); |
5069 | } |
5070 | |
5071 | Approx Approx::operator-() const { |
5072 | auto temp(*this); |
5073 | temp.m_value = -temp.m_value; |
5074 | return temp; |
5075 | } |
5076 | |
5077 | std::string Approx::toString() const { |
5078 | ReusableStringStream ; |
5079 | rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )" ; |
5080 | return rss.str(); |
5081 | } |
5082 | |
5083 | bool Approx::equalityComparisonImpl(const double other) const { |
5084 | // First try with fixed margin, then compute margin based on epsilon, scale and Approx's value |
5085 | // Thanks to Richard Harris for his help refining the scaled margin value |
5086 | return marginComparison(m_value, other, m_margin) || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(m_value))); |
5087 | } |
5088 | |
5089 | void Approx::setMargin(double margin) { |
5090 | CATCH_ENFORCE(margin >= 0, |
5091 | "Invalid Approx::margin: " << margin << '.' |
5092 | << " Approx::Margin has to be non-negative." ); |
5093 | m_margin = margin; |
5094 | } |
5095 | |
5096 | void Approx::setEpsilon(double epsilon) { |
5097 | CATCH_ENFORCE(epsilon >= 0 && epsilon <= 1.0, |
5098 | "Invalid Approx::epsilon: " << epsilon << '.' |
5099 | << " Approx::epsilon has to be in [0, 1]" ); |
5100 | m_epsilon = epsilon; |
5101 | } |
5102 | |
5103 | } // end namespace Detail |
5104 | |
5105 | namespace literals { |
5106 | Detail::Approx operator "" _a(long double val) { |
5107 | return Detail::Approx(val); |
5108 | } |
5109 | Detail::Approx operator "" _a(unsigned long long val) { |
5110 | return Detail::Approx(val); |
5111 | } |
5112 | } // end namespace literals |
5113 | |
5114 | std::string StringMaker<Catch::Detail::Approx>::convert(Catch::Detail::Approx const& value) { |
5115 | return value.toString(); |
5116 | } |
5117 | |
5118 | } // end namespace Catch |
5119 | // end catch_approx.cpp |
5120 | // start catch_assertionhandler.cpp |
5121 | |
5122 | // start catch_context.h |
5123 | |
5124 | #include <memory> |
5125 | |
5126 | namespace Catch { |
5127 | |
5128 | struct IResultCapture; |
5129 | struct IRunner; |
5130 | struct IConfig; |
5131 | struct IMutableContext; |
5132 | |
5133 | using IConfigPtr = std::shared_ptr<IConfig const>; |
5134 | |
5135 | struct IContext |
5136 | { |
5137 | virtual ~IContext(); |
5138 | |
5139 | virtual IResultCapture* getResultCapture() = 0; |
5140 | virtual IRunner* getRunner() = 0; |
5141 | virtual IConfigPtr const& getConfig() const = 0; |
5142 | }; |
5143 | |
5144 | struct IMutableContext : IContext |
5145 | { |
5146 | virtual ~IMutableContext(); |
5147 | virtual void setResultCapture( IResultCapture* resultCapture ) = 0; |
5148 | virtual void setRunner( IRunner* runner ) = 0; |
5149 | virtual void setConfig( IConfigPtr const& config ) = 0; |
5150 | |
5151 | private: |
5152 | static IMutableContext *currentContext; |
5153 | friend IMutableContext& getCurrentMutableContext(); |
5154 | friend void cleanUpContext(); |
5155 | static void createContext(); |
5156 | }; |
5157 | |
5158 | inline IMutableContext& getCurrentMutableContext() |
5159 | { |
5160 | if( !IMutableContext::currentContext ) |
5161 | IMutableContext::createContext(); |
5162 | return *IMutableContext::currentContext; |
5163 | } |
5164 | |
5165 | inline IContext& getCurrentContext() |
5166 | { |
5167 | return getCurrentMutableContext(); |
5168 | } |
5169 | |
5170 | void cleanUpContext(); |
5171 | } |
5172 | |
5173 | // end catch_context.h |
5174 | // start catch_debugger.h |
5175 | |
5176 | namespace Catch { |
5177 | bool isDebuggerActive(); |
5178 | } |
5179 | |
5180 | #ifdef CATCH_PLATFORM_MAC |
5181 | |
5182 | #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */ |
5183 | |
5184 | #elif defined(CATCH_PLATFORM_LINUX) |
5185 | // If we can use inline assembler, do it because this allows us to break |
5186 | // directly at the location of the failing check instead of breaking inside |
5187 | // raise() called from it, i.e. one stack frame below. |
5188 | #if defined(__GNUC__) && (defined(__i386) || defined(__x86_64)) |
5189 | #define CATCH_TRAP() asm volatile ("int $3") /* NOLINT */ |
5190 | #else // Fall back to the generic way. |
5191 | #include <signal.h> |
5192 | |
5193 | #define CATCH_TRAP() raise(SIGTRAP) |
5194 | #endif |
5195 | #elif defined(_MSC_VER) |
5196 | #define CATCH_TRAP() __debugbreak() |
5197 | #elif defined(__MINGW32__) |
5198 | extern "C" __declspec(dllimport) void __stdcall DebugBreak(); |
5199 | #define CATCH_TRAP() DebugBreak() |
5200 | #endif |
5201 | |
5202 | #ifdef CATCH_TRAP |
5203 | #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } |
5204 | #else |
5205 | namespace Catch { |
5206 | inline void doNothing() {} |
5207 | } |
5208 | #define CATCH_BREAK_INTO_DEBUGGER() Catch::doNothing() |
5209 | #endif |
5210 | |
5211 | // end catch_debugger.h |
5212 | // start catch_run_context.h |
5213 | |
5214 | // start catch_fatal_condition.h |
5215 | |
5216 | // start catch_windows_h_proxy.h |
5217 | |
5218 | |
5219 | #if defined(CATCH_PLATFORM_WINDOWS) |
5220 | |
5221 | #if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX) |
5222 | # define CATCH_DEFINED_NOMINMAX |
5223 | # define NOMINMAX |
5224 | #endif |
5225 | #if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN) |
5226 | # define CATCH_DEFINED_WIN32_LEAN_AND_MEAN |
5227 | # define WIN32_LEAN_AND_MEAN |
5228 | #endif |
5229 | |
5230 | #ifdef __AFXDLL |
5231 | #include <AfxWin.h> |
5232 | #else |
5233 | #include <windows.h> |
5234 | #endif |
5235 | |
5236 | #ifdef CATCH_DEFINED_NOMINMAX |
5237 | # undef NOMINMAX |
5238 | #endif |
5239 | #ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN |
5240 | # undef WIN32_LEAN_AND_MEAN |
5241 | #endif |
5242 | |
5243 | #endif // defined(CATCH_PLATFORM_WINDOWS) |
5244 | |
5245 | // end catch_windows_h_proxy.h |
5246 | #if defined( CATCH_CONFIG_WINDOWS_SEH ) |
5247 | |
5248 | namespace Catch { |
5249 | |
5250 | struct FatalConditionHandler { |
5251 | |
5252 | static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo); |
5253 | FatalConditionHandler(); |
5254 | static void reset(); |
5255 | ~FatalConditionHandler(); |
5256 | |
5257 | private: |
5258 | static bool isSet; |
5259 | static ULONG guaranteeSize; |
5260 | static PVOID exceptionHandlerHandle; |
5261 | }; |
5262 | |
5263 | } // namespace Catch |
5264 | |
5265 | #elif defined ( CATCH_CONFIG_POSIX_SIGNALS ) |
5266 | |
5267 | #include <signal.h> |
5268 | |
5269 | namespace Catch { |
5270 | |
5271 | struct FatalConditionHandler { |
5272 | |
5273 | static bool isSet; |
5274 | static struct sigaction oldSigActions[]; |
5275 | static stack_t oldSigStack; |
5276 | static char altStackMem[]; |
5277 | |
5278 | static void handleSignal( int sig ); |
5279 | |
5280 | FatalConditionHandler(); |
5281 | ~FatalConditionHandler(); |
5282 | static void reset(); |
5283 | }; |
5284 | |
5285 | } // namespace Catch |
5286 | |
5287 | #else |
5288 | |
5289 | namespace Catch { |
5290 | struct FatalConditionHandler { |
5291 | void reset(); |
5292 | }; |
5293 | } |
5294 | |
5295 | #endif |
5296 | |
5297 | // end catch_fatal_condition.h |
5298 | #include <string> |
5299 | |
5300 | namespace Catch { |
5301 | |
5302 | struct IMutableContext; |
5303 | |
5304 | /////////////////////////////////////////////////////////////////////////// |
5305 | |
5306 | class RunContext : public IResultCapture, public IRunner { |
5307 | |
5308 | public: |
5309 | RunContext( RunContext const& ) = delete; |
5310 | RunContext& operator =( RunContext const& ) = delete; |
5311 | |
5312 | explicit RunContext( IConfigPtr const& _config, IStreamingReporterPtr&& reporter ); |
5313 | |
5314 | ~RunContext() override; |
5315 | |
5316 | void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ); |
5317 | void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ); |
5318 | |
5319 | Totals runTest(TestCase const& testCase); |
5320 | |
5321 | IConfigPtr config() const; |
5322 | IStreamingReporter& reporter() const; |
5323 | |
5324 | public: // IResultCapture |
5325 | |
5326 | // Assertion handlers |
5327 | void handleExpr |
5328 | ( AssertionInfo const& info, |
5329 | ITransientExpression const& expr, |
5330 | AssertionReaction& reaction ) override; |
5331 | void handleMessage |
5332 | ( AssertionInfo const& info, |
5333 | ResultWas::OfType resultType, |
5334 | StringRef const& message, |
5335 | AssertionReaction& reaction ) override; |
5336 | void handleUnexpectedExceptionNotThrown |
5337 | ( AssertionInfo const& info, |
5338 | AssertionReaction& reaction ) override; |
5339 | void handleUnexpectedInflightException |
5340 | ( AssertionInfo const& info, |
5341 | std::string const& message, |
5342 | AssertionReaction& reaction ) override; |
5343 | void handleIncomplete |
5344 | ( AssertionInfo const& info ) override; |
5345 | void handleNonExpr |
5346 | ( AssertionInfo const &info, |
5347 | ResultWas::OfType resultType, |
5348 | AssertionReaction &reaction ) override; |
5349 | |
5350 | bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) override; |
5351 | |
5352 | void sectionEnded( SectionEndInfo const& endInfo ) override; |
5353 | void sectionEndedEarly( SectionEndInfo const& endInfo ) override; |
5354 | |
5355 | auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override; |
5356 | |
5357 | void benchmarkStarting( BenchmarkInfo const& info ) override; |
5358 | void benchmarkEnded( BenchmarkStats const& stats ) override; |
5359 | |
5360 | void pushScopedMessage( MessageInfo const& message ) override; |
5361 | void popScopedMessage( MessageInfo const& message ) override; |
5362 | |
5363 | std::string getCurrentTestName() const override; |
5364 | |
5365 | const AssertionResult* getLastResult() const override; |
5366 | |
5367 | void exceptionEarlyReported() override; |
5368 | |
5369 | void handleFatalErrorCondition( StringRef message ) override; |
5370 | |
5371 | bool lastAssertionPassed() override; |
5372 | |
5373 | void assertionPassed() override; |
5374 | |
5375 | public: |
5376 | // !TBD We need to do this another way! |
5377 | bool aborting() const final; |
5378 | |
5379 | private: |
5380 | |
5381 | void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ); |
5382 | void invokeActiveTestCase(); |
5383 | |
5384 | void resetAssertionInfo(); |
5385 | bool testForMissingAssertions( Counts& assertions ); |
5386 | |
5387 | void assertionEnded( AssertionResult const& result ); |
5388 | void reportExpr |
5389 | ( AssertionInfo const &info, |
5390 | ResultWas::OfType resultType, |
5391 | ITransientExpression const *expr, |
5392 | bool negated ); |
5393 | |
5394 | void populateReaction( AssertionReaction& reaction ); |
5395 | |
5396 | private: |
5397 | |
5398 | void handleUnfinishedSections(); |
5399 | |
5400 | TestRunInfo m_runInfo; |
5401 | IMutableContext& m_context; |
5402 | TestCase const* m_activeTestCase = nullptr; |
5403 | ITracker* m_testCaseTracker; |
5404 | Option<AssertionResult> m_lastResult; |
5405 | |
5406 | IConfigPtr m_config; |
5407 | Totals m_totals; |
5408 | IStreamingReporterPtr m_reporter; |
5409 | std::vector<MessageInfo> m_messages; |
5410 | AssertionInfo m_lastAssertionInfo; |
5411 | std::vector<SectionEndInfo> m_unfinishedSections; |
5412 | std::vector<ITracker*> m_activeSections; |
5413 | TrackerContext m_trackerContext; |
5414 | bool m_lastAssertionPassed = false; |
5415 | bool m_shouldReportUnexpected = true; |
5416 | bool m_includeSuccessfulResults; |
5417 | }; |
5418 | |
5419 | } // end namespace Catch |
5420 | |
5421 | // end catch_run_context.h |
5422 | namespace Catch { |
5423 | |
5424 | namespace { |
5425 | auto operator <<( std::ostream& os, ITransientExpression const& expr ) -> std::ostream& { |
5426 | expr.streamReconstructedExpression( os ); |
5427 | return os; |
5428 | } |
5429 | } |
5430 | |
5431 | LazyExpression::LazyExpression( bool isNegated ) |
5432 | : m_isNegated( isNegated ) |
5433 | {} |
5434 | |
5435 | LazyExpression::LazyExpression( LazyExpression const& other ) : m_isNegated( other.m_isNegated ) {} |
5436 | |
5437 | LazyExpression::operator bool() const { |
5438 | return m_transientExpression != nullptr; |
5439 | } |
5440 | |
5441 | auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream& { |
5442 | if( lazyExpr.m_isNegated ) |
5443 | os << "!" ; |
5444 | |
5445 | if( lazyExpr ) { |
5446 | if( lazyExpr.m_isNegated && lazyExpr.m_transientExpression->isBinaryExpression() ) |
5447 | os << "(" << *lazyExpr.m_transientExpression << ")" ; |
5448 | else |
5449 | os << *lazyExpr.m_transientExpression; |
5450 | } |
5451 | else { |
5452 | os << "{** error - unchecked empty expression requested **}" ; |
5453 | } |
5454 | return os; |
5455 | } |
5456 | |
5457 | AssertionHandler::AssertionHandler |
5458 | ( StringRef const& macroName, |
5459 | SourceLineInfo const& lineInfo, |
5460 | StringRef capturedExpression, |
5461 | ResultDisposition::Flags resultDisposition ) |
5462 | : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition }, |
5463 | m_resultCapture( getResultCapture() ) |
5464 | {} |
5465 | |
5466 | void AssertionHandler::handleExpr( ITransientExpression const& expr ) { |
5467 | m_resultCapture.handleExpr( m_assertionInfo, expr, m_reaction ); |
5468 | } |
5469 | void AssertionHandler::handleMessage(ResultWas::OfType resultType, StringRef const& message) { |
5470 | m_resultCapture.handleMessage( m_assertionInfo, resultType, message, m_reaction ); |
5471 | } |
5472 | |
5473 | auto AssertionHandler::allowThrows() const -> bool { |
5474 | return getCurrentContext().getConfig()->allowThrows(); |
5475 | } |
5476 | |
5477 | void AssertionHandler::complete() { |
5478 | setCompleted(); |
5479 | if( m_reaction.shouldDebugBreak ) { |
5480 | |
5481 | // If you find your debugger stopping you here then go one level up on the |
5482 | // call-stack for the code that caused it (typically a failed assertion) |
5483 | |
5484 | // (To go back to the test and change execution, jump over the throw, next) |
5485 | CATCH_BREAK_INTO_DEBUGGER(); |
5486 | } |
5487 | if (m_reaction.shouldThrow) { |
5488 | #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) |
5489 | throw Catch::TestFailureException(); |
5490 | #else |
5491 | CATCH_ERROR( "Test failure requires aborting test!" ); |
5492 | #endif |
5493 | } |
5494 | } |
5495 | void AssertionHandler::setCompleted() { |
5496 | m_completed = true; |
5497 | } |
5498 | |
5499 | void AssertionHandler::handleUnexpectedInflightException() { |
5500 | m_resultCapture.handleUnexpectedInflightException( m_assertionInfo, Catch::translateActiveException(), m_reaction ); |
5501 | } |
5502 | |
5503 | void AssertionHandler::handleExceptionThrownAsExpected() { |
5504 | m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); |
5505 | } |
5506 | void AssertionHandler::handleExceptionNotThrownAsExpected() { |
5507 | m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); |
5508 | } |
5509 | |
5510 | void AssertionHandler::handleUnexpectedExceptionNotThrown() { |
5511 | m_resultCapture.handleUnexpectedExceptionNotThrown( m_assertionInfo, m_reaction ); |
5512 | } |
5513 | |
5514 | void AssertionHandler::handleThrowingCallSkipped() { |
5515 | m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); |
5516 | } |
5517 | |
5518 | // This is the overload that takes a string and infers the Equals matcher from it |
5519 | // The more general overload, that takes any string matcher, is in catch_capture_matchers.cpp |
5520 | void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef const& matcherString ) { |
5521 | handleExceptionMatchExpr( handler, Matchers::Equals( str ), matcherString ); |
5522 | } |
5523 | |
5524 | } // namespace Catch |
5525 | // end catch_assertionhandler.cpp |
5526 | // start catch_assertionresult.cpp |
5527 | |
5528 | namespace Catch { |
5529 | AssertionResultData::AssertionResultData(ResultWas::OfType _resultType, LazyExpression const & _lazyExpression): |
5530 | lazyExpression(_lazyExpression), |
5531 | resultType(_resultType) {} |
5532 | |
5533 | std::string AssertionResultData::reconstructExpression() const { |
5534 | |
5535 | if( reconstructedExpression.empty() ) { |
5536 | if( lazyExpression ) { |
5537 | ReusableStringStream ; |
5538 | rss << lazyExpression; |
5539 | reconstructedExpression = rss.str(); |
5540 | } |
5541 | } |
5542 | return reconstructedExpression; |
5543 | } |
5544 | |
5545 | AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) |
5546 | : m_info( info ), |
5547 | m_resultData( data ) |
5548 | {} |
5549 | |
5550 | // Result was a success |
5551 | bool AssertionResult::succeeded() const { |
5552 | return Catch::isOk( m_resultData.resultType ); |
5553 | } |
5554 | |
5555 | // Result was a success, or failure is suppressed |
5556 | bool AssertionResult::isOk() const { |
5557 | return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition ); |
5558 | } |
5559 | |
5560 | ResultWas::OfType AssertionResult::getResultType() const { |
5561 | return m_resultData.resultType; |
5562 | } |
5563 | |
5564 | bool AssertionResult::hasExpression() const { |
5565 | return m_info.capturedExpression[0] != 0; |
5566 | } |
5567 | |
5568 | bool AssertionResult::hasMessage() const { |
5569 | return !m_resultData.message.empty(); |
5570 | } |
5571 | |
5572 | std::string AssertionResult::getExpression() const { |
5573 | if( isFalseTest( m_info.resultDisposition ) ) |
5574 | return "!(" + m_info.capturedExpression + ")" ; |
5575 | else |
5576 | return m_info.capturedExpression; |
5577 | } |
5578 | |
5579 | std::string AssertionResult::getExpressionInMacro() const { |
5580 | std::string expr; |
5581 | if( m_info.macroName[0] == 0 ) |
5582 | expr = m_info.capturedExpression; |
5583 | else { |
5584 | expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 ); |
5585 | expr += m_info.macroName; |
5586 | expr += "( " ; |
5587 | expr += m_info.capturedExpression; |
5588 | expr += " )" ; |
5589 | } |
5590 | return expr; |
5591 | } |
5592 | |
5593 | bool AssertionResult::hasExpandedExpression() const { |
5594 | return hasExpression() && getExpandedExpression() != getExpression(); |
5595 | } |
5596 | |
5597 | std::string AssertionResult::getExpandedExpression() const { |
5598 | std::string expr = m_resultData.reconstructExpression(); |
5599 | return expr.empty() |
5600 | ? getExpression() |
5601 | : expr; |
5602 | } |
5603 | |
5604 | std::string AssertionResult::getMessage() const { |
5605 | return m_resultData.message; |
5606 | } |
5607 | SourceLineInfo AssertionResult::getSourceInfo() const { |
5608 | return m_info.lineInfo; |
5609 | } |
5610 | |
5611 | StringRef AssertionResult::getTestMacroName() const { |
5612 | return m_info.macroName; |
5613 | } |
5614 | |
5615 | } // end namespace Catch |
5616 | // end catch_assertionresult.cpp |
5617 | // start catch_benchmark.cpp |
5618 | |
5619 | namespace Catch { |
5620 | |
5621 | auto BenchmarkLooper::getResolution() -> uint64_t { |
5622 | return getEstimatedClockResolution() * getCurrentContext().getConfig()->benchmarkResolutionMultiple(); |
5623 | } |
5624 | |
5625 | void BenchmarkLooper::reportStart() { |
5626 | getResultCapture().benchmarkStarting( { m_name } ); |
5627 | } |
5628 | auto BenchmarkLooper::needsMoreIterations() -> bool { |
5629 | auto elapsed = m_timer.getElapsedNanoseconds(); |
5630 | |
5631 | // Exponentially increasing iterations until we're confident in our timer resolution |
5632 | if( elapsed < m_resolution ) { |
5633 | m_iterationsToRun *= 10; |
5634 | return true; |
5635 | } |
5636 | |
5637 | getResultCapture().benchmarkEnded( { { m_name }, m_count, elapsed } ); |
5638 | return false; |
5639 | } |
5640 | |
5641 | } // end namespace Catch |
5642 | // end catch_benchmark.cpp |
5643 | // start catch_capture_matchers.cpp |
5644 | |
5645 | namespace Catch { |
5646 | |
5647 | using StringMatcher = Matchers::Impl::MatcherBase<std::string>; |
5648 | |
5649 | // This is the general overload that takes a any string matcher |
5650 | // There is another overload, in catch_assertionhandler.h/.cpp, that only takes a string and infers |
5651 | // the Equals matcher (so the header does not mention matchers) |
5652 | void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString ) { |
5653 | std::string exceptionMessage = Catch::translateActiveException(); |
5654 | MatchExpr<std::string, StringMatcher const&> expr( exceptionMessage, matcher, matcherString ); |
5655 | handler.handleExpr( expr ); |
5656 | } |
5657 | |
5658 | } // namespace Catch |
5659 | // end catch_capture_matchers.cpp |
5660 | // start catch_commandline.cpp |
5661 | |
5662 | // start catch_commandline.h |
5663 | |
5664 | // start catch_clara.h |
5665 | |
5666 | // Use Catch's value for console width (store Clara's off to the side, if present) |
5667 | #ifdef CLARA_CONFIG_CONSOLE_WIDTH |
5668 | #define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH |
5669 | #undef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH |
5670 | #endif |
5671 | #define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH-1 |
5672 | |
5673 | #ifdef __clang__ |
5674 | #pragma clang diagnostic push |
5675 | #pragma clang diagnostic ignored "-Wweak-vtables" |
5676 | #pragma clang diagnostic ignored "-Wexit-time-destructors" |
5677 | #pragma clang diagnostic ignored "-Wshadow" |
5678 | #endif |
5679 | |
5680 | // start clara.hpp |
5681 | // Copyright 2017 Two Blue Cubes Ltd. All rights reserved. |
5682 | // |
5683 | // Distributed under the Boost Software License, Version 1.0. (See accompanying |
5684 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
5685 | // |
5686 | // See https://github.com/philsquared/Clara for more details |
5687 | |
5688 | // Clara v1.1.4 |
5689 | |
5690 | |
5691 | #ifndef CATCH_CLARA_CONFIG_CONSOLE_WIDTH |
5692 | #define CATCH_CLARA_CONFIG_CONSOLE_WIDTH 80 |
5693 | #endif |
5694 | |
5695 | #ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH |
5696 | #define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CLARA_CONFIG_CONSOLE_WIDTH |
5697 | #endif |
5698 | |
5699 | #ifndef CLARA_CONFIG_OPTIONAL_TYPE |
5700 | #ifdef __has_include |
5701 | #if __has_include(<optional>) && __cplusplus >= 201703L |
5702 | #include <optional> |
5703 | #define CLARA_CONFIG_OPTIONAL_TYPE std::optional |
5704 | #endif |
5705 | #endif |
5706 | #endif |
5707 | |
5708 | // ----------- #included from clara_textflow.hpp ----------- |
5709 | |
5710 | // TextFlowCpp |
5711 | // |
5712 | // A single-header library for wrapping and laying out basic text, by Phil Nash |
5713 | // |
5714 | // This work is licensed under the BSD 2-Clause license. |
5715 | // See the accompanying LICENSE file, or the one at https://opensource.org/licenses/BSD-2-Clause |
5716 | // |
5717 | // This project is hosted at https://github.com/philsquared/textflowcpp |
5718 | |
5719 | |
5720 | #include <cassert> |
5721 | #include <ostream> |
5722 | #include <sstream> |
5723 | #include <vector> |
5724 | |
5725 | #ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH |
5726 | #define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH 80 |
5727 | #endif |
5728 | |
5729 | namespace Catch { namespace clara { namespace TextFlow { |
5730 | |
5731 | inline auto isWhitespace( char c ) -> bool { |
5732 | static std::string chars = " \t\n\r" ; |
5733 | return chars.find( c ) != std::string::npos; |
5734 | } |
5735 | inline auto isBreakableBefore( char c ) -> bool { |
5736 | static std::string chars = "[({<|" ; |
5737 | return chars.find( c ) != std::string::npos; |
5738 | } |
5739 | inline auto isBreakableAfter( char c ) -> bool { |
5740 | static std::string chars = "])}>.,:;*+-=&/\\" ; |
5741 | return chars.find( c ) != std::string::npos; |
5742 | } |
5743 | |
5744 | class Columns; |
5745 | |
5746 | class Column { |
5747 | std::vector<std::string> m_strings; |
5748 | size_t m_width = CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH; |
5749 | size_t m_indent = 0; |
5750 | size_t m_initialIndent = std::string::npos; |
5751 | |
5752 | public: |
5753 | class iterator { |
5754 | friend Column; |
5755 | |
5756 | Column const& m_column; |
5757 | size_t m_stringIndex = 0; |
5758 | size_t m_pos = 0; |
5759 | |
5760 | size_t m_len = 0; |
5761 | size_t m_end = 0; |
5762 | bool m_suffix = false; |
5763 | |
5764 | iterator( Column const& column, size_t stringIndex ) |
5765 | : m_column( column ), |
5766 | m_stringIndex( stringIndex ) |
5767 | {} |
5768 | |
5769 | auto line() const -> std::string const& { return m_column.m_strings[m_stringIndex]; } |
5770 | |
5771 | auto isBoundary( size_t at ) const -> bool { |
5772 | assert( at > 0 ); |
5773 | assert( at <= line().size() ); |
5774 | |
5775 | return at == line().size() || |
5776 | ( isWhitespace( line()[at] ) && !isWhitespace( line()[at-1] ) ) || |
5777 | isBreakableBefore( line()[at] ) || |
5778 | isBreakableAfter( line()[at-1] ); |
5779 | } |
5780 | |
5781 | void calcLength() { |
5782 | assert( m_stringIndex < m_column.m_strings.size() ); |
5783 | |
5784 | m_suffix = false; |
5785 | auto width = m_column.m_width-indent(); |
5786 | m_end = m_pos; |
5787 | while( m_end < line().size() && line()[m_end] != '\n' ) |
5788 | ++m_end; |
5789 | |
5790 | if( m_end < m_pos + width ) { |
5791 | m_len = m_end - m_pos; |
5792 | } |
5793 | else { |
5794 | size_t len = width; |
5795 | while (len > 0 && !isBoundary(m_pos + len)) |
5796 | --len; |
5797 | while (len > 0 && isWhitespace( line()[m_pos + len - 1] )) |
5798 | --len; |
5799 | |
5800 | if (len > 0) { |
5801 | m_len = len; |
5802 | } else { |
5803 | m_suffix = true; |
5804 | m_len = width - 1; |
5805 | } |
5806 | } |
5807 | } |
5808 | |
5809 | auto indent() const -> size_t { |
5810 | auto initial = m_pos == 0 && m_stringIndex == 0 ? m_column.m_initialIndent : std::string::npos; |
5811 | return initial == std::string::npos ? m_column.m_indent : initial; |
5812 | } |
5813 | |
5814 | auto addIndentAndSuffix(std::string const &plain) const -> std::string { |
5815 | return std::string( indent(), ' ' ) + (m_suffix ? plain + "-" : plain); |
5816 | } |
5817 | |
5818 | public: |
5819 | explicit iterator( Column const& column ) : m_column( column ) { |
5820 | assert( m_column.m_width > m_column.m_indent ); |
5821 | assert( m_column.m_initialIndent == std::string::npos || m_column.m_width > m_column.m_initialIndent ); |
5822 | calcLength(); |
5823 | if( m_len == 0 ) |
5824 | m_stringIndex++; // Empty string |
5825 | } |
5826 | |
5827 | auto operator *() const -> std::string { |
5828 | assert( m_stringIndex < m_column.m_strings.size() ); |
5829 | assert( m_pos <= m_end ); |
5830 | if( m_pos + m_column.m_width < m_end ) |
5831 | return addIndentAndSuffix(line().substr(m_pos, m_len)); |
5832 | else |
5833 | return addIndentAndSuffix(line().substr(m_pos, m_end - m_pos)); |
5834 | } |
5835 | |
5836 | auto operator ++() -> iterator& { |
5837 | m_pos += m_len; |
5838 | if( m_pos < line().size() && line()[m_pos] == '\n' ) |
5839 | m_pos += 1; |
5840 | else |
5841 | while( m_pos < line().size() && isWhitespace( line()[m_pos] ) ) |
5842 | ++m_pos; |
5843 | |
5844 | if( m_pos == line().size() ) { |
5845 | m_pos = 0; |
5846 | ++m_stringIndex; |
5847 | } |
5848 | if( m_stringIndex < m_column.m_strings.size() ) |
5849 | calcLength(); |
5850 | return *this; |
5851 | } |
5852 | auto operator ++(int) -> iterator { |
5853 | iterator prev( *this ); |
5854 | operator++(); |
5855 | return prev; |
5856 | } |
5857 | |
5858 | auto operator ==( iterator const& other ) const -> bool { |
5859 | return |
5860 | m_pos == other.m_pos && |
5861 | m_stringIndex == other.m_stringIndex && |
5862 | &m_column == &other.m_column; |
5863 | } |
5864 | auto operator !=( iterator const& other ) const -> bool { |
5865 | return !operator==( other ); |
5866 | } |
5867 | }; |
5868 | using const_iterator = iterator; |
5869 | |
5870 | explicit Column( std::string const& text ) { m_strings.push_back( text ); } |
5871 | |
5872 | auto width( size_t newWidth ) -> Column& { |
5873 | assert( newWidth > 0 ); |
5874 | m_width = newWidth; |
5875 | return *this; |
5876 | } |
5877 | auto indent( size_t newIndent ) -> Column& { |
5878 | m_indent = newIndent; |
5879 | return *this; |
5880 | } |
5881 | auto initialIndent( size_t newIndent ) -> Column& { |
5882 | m_initialIndent = newIndent; |
5883 | return *this; |
5884 | } |
5885 | |
5886 | auto width() const -> size_t { return m_width; } |
5887 | auto begin() const -> iterator { return iterator( *this ); } |
5888 | auto end() const -> iterator { return { *this, m_strings.size() }; } |
5889 | |
5890 | inline friend std::ostream& operator << ( std::ostream& os, Column const& col ) { |
5891 | bool first = true; |
5892 | for( auto line : col ) { |
5893 | if( first ) |
5894 | first = false; |
5895 | else |
5896 | os << "\n" ; |
5897 | os << line; |
5898 | } |
5899 | return os; |
5900 | } |
5901 | |
5902 | auto operator + ( Column const& other ) -> Columns; |
5903 | |
5904 | auto toString() const -> std::string { |
5905 | std::ostringstream oss; |
5906 | oss << *this; |
5907 | return oss.str(); |
5908 | } |
5909 | }; |
5910 | |
5911 | class Spacer : public Column { |
5912 | |
5913 | public: |
5914 | explicit Spacer( size_t spaceWidth ) : Column( "" ) { |
5915 | width( spaceWidth ); |
5916 | } |
5917 | }; |
5918 | |
5919 | class Columns { |
5920 | std::vector<Column> m_columns; |
5921 | |
5922 | public: |
5923 | |
5924 | class iterator { |
5925 | friend Columns; |
5926 | struct EndTag {}; |
5927 | |
5928 | std::vector<Column> const& m_columns; |
5929 | std::vector<Column::iterator> m_iterators; |
5930 | size_t m_activeIterators; |
5931 | |
5932 | iterator( Columns const& columns, EndTag ) |
5933 | : m_columns( columns.m_columns ), |
5934 | m_activeIterators( 0 ) |
5935 | { |
5936 | m_iterators.reserve( m_columns.size() ); |
5937 | |
5938 | for( auto const& col : m_columns ) |
5939 | m_iterators.push_back( col.end() ); |
5940 | } |
5941 | |
5942 | public: |
5943 | explicit iterator( Columns const& columns ) |
5944 | : m_columns( columns.m_columns ), |
5945 | m_activeIterators( m_columns.size() ) |
5946 | { |
5947 | m_iterators.reserve( m_columns.size() ); |
5948 | |
5949 | for( auto const& col : m_columns ) |
5950 | m_iterators.push_back( col.begin() ); |
5951 | } |
5952 | |
5953 | auto operator ==( iterator const& other ) const -> bool { |
5954 | return m_iterators == other.m_iterators; |
5955 | } |
5956 | auto operator !=( iterator const& other ) const -> bool { |
5957 | return m_iterators != other.m_iterators; |
5958 | } |
5959 | auto operator *() const -> std::string { |
5960 | std::string row, padding; |
5961 | |
5962 | for( size_t i = 0; i < m_columns.size(); ++i ) { |
5963 | auto width = m_columns[i].width(); |
5964 | if( m_iterators[i] != m_columns[i].end() ) { |
5965 | std::string col = *m_iterators[i]; |
5966 | row += padding + col; |
5967 | if( col.size() < width ) |
5968 | padding = std::string( width - col.size(), ' ' ); |
5969 | else |
5970 | padding = "" ; |
5971 | } |
5972 | else { |
5973 | padding += std::string( width, ' ' ); |
5974 | } |
5975 | } |
5976 | return row; |
5977 | } |
5978 | auto operator ++() -> iterator& { |
5979 | for( size_t i = 0; i < m_columns.size(); ++i ) { |
5980 | if (m_iterators[i] != m_columns[i].end()) |
5981 | ++m_iterators[i]; |
5982 | } |
5983 | return *this; |
5984 | } |
5985 | auto operator ++(int) -> iterator { |
5986 | iterator prev( *this ); |
5987 | operator++(); |
5988 | return prev; |
5989 | } |
5990 | }; |
5991 | using const_iterator = iterator; |
5992 | |
5993 | auto begin() const -> iterator { return iterator( *this ); } |
5994 | auto end() const -> iterator { return { *this, iterator::EndTag() }; } |
5995 | |
5996 | auto operator += ( Column const& col ) -> Columns& { |
5997 | m_columns.push_back( col ); |
5998 | return *this; |
5999 | } |
6000 | auto operator + ( Column const& col ) -> Columns { |
6001 | Columns combined = *this; |
6002 | combined += col; |
6003 | return combined; |
6004 | } |
6005 | |
6006 | inline friend std::ostream& operator << ( std::ostream& os, Columns const& cols ) { |
6007 | |
6008 | bool first = true; |
6009 | for( auto line : cols ) { |
6010 | if( first ) |
6011 | first = false; |
6012 | else |
6013 | os << "\n" ; |
6014 | os << line; |
6015 | } |
6016 | return os; |
6017 | } |
6018 | |
6019 | auto toString() const -> std::string { |
6020 | std::ostringstream oss; |
6021 | oss << *this; |
6022 | return oss.str(); |
6023 | } |
6024 | }; |
6025 | |
6026 | inline auto Column::operator + ( Column const& other ) -> Columns { |
6027 | Columns cols; |
6028 | cols += *this; |
6029 | cols += other; |
6030 | return cols; |
6031 | } |
6032 | }}} // namespace Catch::clara::TextFlow |
6033 | |
6034 | // ----------- end of #include from clara_textflow.hpp ----------- |
6035 | // ........... back in clara.hpp |
6036 | |
6037 | #include <memory> |
6038 | #include <set> |
6039 | #include <algorithm> |
6040 | |
6041 | #if !defined(CATCH_PLATFORM_WINDOWS) && ( defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) ) |
6042 | #define CATCH_PLATFORM_WINDOWS |
6043 | #endif |
6044 | |
6045 | namespace Catch { namespace clara { |
6046 | namespace detail { |
6047 | |
6048 | // Traits for extracting arg and return type of lambdas (for single argument lambdas) |
6049 | template<typename L> |
6050 | struct UnaryLambdaTraits : UnaryLambdaTraits<decltype( &L::operator() )> {}; |
6051 | |
6052 | template<typename ClassT, typename ReturnT, typename... Args> |
6053 | struct UnaryLambdaTraits<ReturnT( ClassT::* )( Args... ) const> { |
6054 | static const bool isValid = false; |
6055 | }; |
6056 | |
6057 | template<typename ClassT, typename ReturnT, typename ArgT> |
6058 | struct UnaryLambdaTraits<ReturnT( ClassT::* )( ArgT ) const> { |
6059 | static const bool isValid = true; |
6060 | using ArgType = typename std::remove_const<typename std::remove_reference<ArgT>::type>::type; |
6061 | using ReturnType = ReturnT; |
6062 | }; |
6063 | |
6064 | class TokenStream; |
6065 | |
6066 | // Transport for raw args (copied from main args, or supplied via init list for testing) |
6067 | class Args { |
6068 | friend TokenStream; |
6069 | std::string m_exeName; |
6070 | std::vector<std::string> m_args; |
6071 | |
6072 | public: |
6073 | Args( int argc, char const* const* argv ) |
6074 | : m_exeName(argv[0]), |
6075 | m_args(argv + 1, argv + argc) {} |
6076 | |
6077 | Args( std::initializer_list<std::string> args ) |
6078 | : m_exeName( *args.begin() ), |
6079 | m_args( args.begin()+1, args.end() ) |
6080 | {} |
6081 | |
6082 | auto exeName() const -> std::string { |
6083 | return m_exeName; |
6084 | } |
6085 | }; |
6086 | |
6087 | // Wraps a token coming from a token stream. These may not directly correspond to strings as a single string |
6088 | // may encode an option + its argument if the : or = form is used |
6089 | enum class TokenType { |
6090 | Option, Argument |
6091 | }; |
6092 | struct Token { |
6093 | TokenType type; |
6094 | std::string token; |
6095 | }; |
6096 | |
6097 | inline auto isOptPrefix( char c ) -> bool { |
6098 | return c == '-' |
6099 | #ifdef CATCH_PLATFORM_WINDOWS |
6100 | || c == '/' |
6101 | #endif |
6102 | ; |
6103 | } |
6104 | |
6105 | // Abstracts iterators into args as a stream of tokens, with option arguments uniformly handled |
6106 | class TokenStream { |
6107 | using Iterator = std::vector<std::string>::const_iterator; |
6108 | Iterator it; |
6109 | Iterator itEnd; |
6110 | std::vector<Token> m_tokenBuffer; |
6111 | |
6112 | void loadBuffer() { |
6113 | m_tokenBuffer.resize( 0 ); |
6114 | |
6115 | // Skip any empty strings |
6116 | while( it != itEnd && it->empty() ) |
6117 | ++it; |
6118 | |
6119 | if( it != itEnd ) { |
6120 | auto const &next = *it; |
6121 | if( isOptPrefix( next[0] ) ) { |
6122 | auto delimiterPos = next.find_first_of( " :=" ); |
6123 | if( delimiterPos != std::string::npos ) { |
6124 | m_tokenBuffer.push_back( { TokenType::Option, next.substr( 0, delimiterPos ) } ); |
6125 | m_tokenBuffer.push_back( { TokenType::Argument, next.substr( delimiterPos + 1 ) } ); |
6126 | } else { |
6127 | if( next[1] != '-' && next.size() > 2 ) { |
6128 | std::string opt = "- " ; |
6129 | for( size_t i = 1; i < next.size(); ++i ) { |
6130 | opt[1] = next[i]; |
6131 | m_tokenBuffer.push_back( { TokenType::Option, opt } ); |
6132 | } |
6133 | } else { |
6134 | m_tokenBuffer.push_back( { TokenType::Option, next } ); |
6135 | } |
6136 | } |
6137 | } else { |
6138 | m_tokenBuffer.push_back( { TokenType::Argument, next } ); |
6139 | } |
6140 | } |
6141 | } |
6142 | |
6143 | public: |
6144 | explicit TokenStream( Args const &args ) : TokenStream( args.m_args.begin(), args.m_args.end() ) {} |
6145 | |
6146 | TokenStream( Iterator it, Iterator itEnd ) : it( it ), itEnd( itEnd ) { |
6147 | loadBuffer(); |
6148 | } |
6149 | |
6150 | explicit operator bool() const { |
6151 | return !m_tokenBuffer.empty() || it != itEnd; |
6152 | } |
6153 | |
6154 | auto count() const -> size_t { return m_tokenBuffer.size() + (itEnd - it); } |
6155 | |
6156 | auto operator*() const -> Token { |
6157 | assert( !m_tokenBuffer.empty() ); |
6158 | return m_tokenBuffer.front(); |
6159 | } |
6160 | |
6161 | auto operator->() const -> Token const * { |
6162 | assert( !m_tokenBuffer.empty() ); |
6163 | return &m_tokenBuffer.front(); |
6164 | } |
6165 | |
6166 | auto operator++() -> TokenStream & { |
6167 | if( m_tokenBuffer.size() >= 2 ) { |
6168 | m_tokenBuffer.erase( m_tokenBuffer.begin() ); |
6169 | } else { |
6170 | if( it != itEnd ) |
6171 | ++it; |
6172 | loadBuffer(); |
6173 | } |
6174 | return *this; |
6175 | } |
6176 | }; |
6177 | |
6178 | class ResultBase { |
6179 | public: |
6180 | enum Type { |
6181 | Ok, LogicError, RuntimeError |
6182 | }; |
6183 | |
6184 | protected: |
6185 | ResultBase( Type type ) : m_type( type ) {} |
6186 | virtual ~ResultBase() = default; |
6187 | |
6188 | virtual void enforceOk() const = 0; |
6189 | |
6190 | Type m_type; |
6191 | }; |
6192 | |
6193 | template<typename T> |
6194 | class ResultValueBase : public ResultBase { |
6195 | public: |
6196 | auto value() const -> T const & { |
6197 | enforceOk(); |
6198 | return m_value; |
6199 | } |
6200 | |
6201 | protected: |
6202 | ResultValueBase( Type type ) : ResultBase( type ) {} |
6203 | |
6204 | ResultValueBase( ResultValueBase const &other ) : ResultBase( other ) { |
6205 | if( m_type == ResultBase::Ok ) |
6206 | new( &m_value ) T( other.m_value ); |
6207 | } |
6208 | |
6209 | ResultValueBase( Type, T const &value ) : ResultBase( Ok ) { |
6210 | new( &m_value ) T( value ); |
6211 | } |
6212 | |
6213 | auto operator=( ResultValueBase const &other ) -> ResultValueBase & { |
6214 | if( m_type == ResultBase::Ok ) |
6215 | m_value.~T(); |
6216 | ResultBase::operator=(other); |
6217 | if( m_type == ResultBase::Ok ) |
6218 | new( &m_value ) T( other.m_value ); |
6219 | return *this; |
6220 | } |
6221 | |
6222 | ~ResultValueBase() override { |
6223 | if( m_type == Ok ) |
6224 | m_value.~T(); |
6225 | } |
6226 | |
6227 | union { |
6228 | T m_value; |
6229 | }; |
6230 | }; |
6231 | |
6232 | template<> |
6233 | class ResultValueBase<void> : public ResultBase { |
6234 | protected: |
6235 | using ResultBase::ResultBase; |
6236 | }; |
6237 | |
6238 | template<typename T = void> |
6239 | class BasicResult : public ResultValueBase<T> { |
6240 | public: |
6241 | template<typename U> |
6242 | explicit BasicResult( BasicResult<U> const &other ) |
6243 | : ResultValueBase<T>( other.type() ), |
6244 | m_errorMessage( other.errorMessage() ) |
6245 | { |
6246 | assert( type() != ResultBase::Ok ); |
6247 | } |
6248 | |
6249 | template<typename U> |
6250 | static auto ok( U const &value ) -> BasicResult { return { ResultBase::Ok, value }; } |
6251 | static auto ok() -> BasicResult { return { ResultBase::Ok }; } |
6252 | static auto logicError( std::string const &message ) -> BasicResult { return { ResultBase::LogicError, message }; } |
6253 | static auto runtimeError( std::string const &message ) -> BasicResult { return { ResultBase::RuntimeError, message }; } |
6254 | |
6255 | explicit operator bool() const { return m_type == ResultBase::Ok; } |
6256 | auto type() const -> ResultBase::Type { return m_type; } |
6257 | auto errorMessage() const -> std::string { return m_errorMessage; } |
6258 | |
6259 | protected: |
6260 | void enforceOk() const override { |
6261 | |
6262 | // Errors shouldn't reach this point, but if they do |
6263 | // the actual error message will be in m_errorMessage |
6264 | assert( m_type != ResultBase::LogicError ); |
6265 | assert( m_type != ResultBase::RuntimeError ); |
6266 | if( m_type != ResultBase::Ok ) |
6267 | std::abort(); |
6268 | } |
6269 | |
6270 | std::string m_errorMessage; // Only populated if resultType is an error |
6271 | |
6272 | BasicResult( ResultBase::Type type, std::string const &message ) |
6273 | : ResultValueBase<T>(type), |
6274 | m_errorMessage(message) |
6275 | { |
6276 | assert( m_type != ResultBase::Ok ); |
6277 | } |
6278 | |
6279 | using ResultValueBase<T>::ResultValueBase; |
6280 | using ResultBase::m_type; |
6281 | }; |
6282 | |
6283 | enum class ParseResultType { |
6284 | Matched, NoMatch, ShortCircuitAll, ShortCircuitSame |
6285 | }; |
6286 | |
6287 | class ParseState { |
6288 | public: |
6289 | |
6290 | ParseState( ParseResultType type, TokenStream const &remainingTokens ) |
6291 | : m_type(type), |
6292 | m_remainingTokens( remainingTokens ) |
6293 | {} |
6294 | |
6295 | auto type() const -> ParseResultType { return m_type; } |
6296 | auto remainingTokens() const -> TokenStream { return m_remainingTokens; } |
6297 | |
6298 | private: |
6299 | ParseResultType m_type; |
6300 | TokenStream m_remainingTokens; |
6301 | }; |
6302 | |
6303 | using Result = BasicResult<void>; |
6304 | using ParserResult = BasicResult<ParseResultType>; |
6305 | using InternalParseResult = BasicResult<ParseState>; |
6306 | |
6307 | struct HelpColumns { |
6308 | std::string left; |
6309 | std::string right; |
6310 | }; |
6311 | |
6312 | template<typename T> |
6313 | inline auto convertInto( std::string const &source, T& target ) -> ParserResult { |
6314 | std::stringstream ss; |
6315 | ss << source; |
6316 | ss >> target; |
6317 | if( ss.fail() ) |
6318 | return ParserResult::runtimeError( "Unable to convert '" + source + "' to destination type" ); |
6319 | else |
6320 | return ParserResult::ok( ParseResultType::Matched ); |
6321 | } |
6322 | inline auto convertInto( std::string const &source, std::string& target ) -> ParserResult { |
6323 | target = source; |
6324 | return ParserResult::ok( ParseResultType::Matched ); |
6325 | } |
6326 | inline auto convertInto( std::string const &source, bool &target ) -> ParserResult { |
6327 | std::string srcLC = source; |
6328 | std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast<char>( ::tolower(c) ); } ); |
6329 | if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on" ) |
6330 | target = true; |
6331 | else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off" ) |
6332 | target = false; |
6333 | else |
6334 | return ParserResult::runtimeError( "Expected a boolean value but did not recognise: '" + source + "'" ); |
6335 | return ParserResult::ok( ParseResultType::Matched ); |
6336 | } |
6337 | #ifdef CLARA_CONFIG_OPTIONAL_TYPE |
6338 | template<typename T> |
6339 | inline auto convertInto( std::string const &source, CLARA_CONFIG_OPTIONAL_TYPE<T>& target ) -> ParserResult { |
6340 | T temp; |
6341 | auto result = convertInto( source, temp ); |
6342 | if( result ) |
6343 | target = std::move(temp); |
6344 | return result; |
6345 | } |
6346 | #endif // CLARA_CONFIG_OPTIONAL_TYPE |
6347 | |
6348 | struct NonCopyable { |
6349 | NonCopyable() = default; |
6350 | NonCopyable( NonCopyable const & ) = delete; |
6351 | NonCopyable( NonCopyable && ) = delete; |
6352 | NonCopyable &operator=( NonCopyable const & ) = delete; |
6353 | NonCopyable &operator=( NonCopyable && ) = delete; |
6354 | }; |
6355 | |
6356 | struct BoundRef : NonCopyable { |
6357 | virtual ~BoundRef() = default; |
6358 | virtual auto isContainer() const -> bool { return false; } |
6359 | virtual auto isFlag() const -> bool { return false; } |
6360 | }; |
6361 | struct BoundValueRefBase : BoundRef { |
6362 | virtual auto setValue( std::string const &arg ) -> ParserResult = 0; |
6363 | }; |
6364 | struct BoundFlagRefBase : BoundRef { |
6365 | virtual auto setFlag( bool flag ) -> ParserResult = 0; |
6366 | virtual auto isFlag() const -> bool { return true; } |
6367 | }; |
6368 | |
6369 | template<typename T> |
6370 | struct BoundValueRef : BoundValueRefBase { |
6371 | T &m_ref; |
6372 | |
6373 | explicit BoundValueRef( T &ref ) : m_ref( ref ) {} |
6374 | |
6375 | auto setValue( std::string const &arg ) -> ParserResult override { |
6376 | return convertInto( arg, m_ref ); |
6377 | } |
6378 | }; |
6379 | |
6380 | template<typename T> |
6381 | struct BoundValueRef<std::vector<T>> : BoundValueRefBase { |
6382 | std::vector<T> &m_ref; |
6383 | |
6384 | explicit BoundValueRef( std::vector<T> &ref ) : m_ref( ref ) {} |
6385 | |
6386 | auto isContainer() const -> bool override { return true; } |
6387 | |
6388 | auto setValue( std::string const &arg ) -> ParserResult override { |
6389 | T temp; |
6390 | auto result = convertInto( arg, temp ); |
6391 | if( result ) |
6392 | m_ref.push_back( temp ); |
6393 | return result; |
6394 | } |
6395 | }; |
6396 | |
6397 | struct BoundFlagRef : BoundFlagRefBase { |
6398 | bool &m_ref; |
6399 | |
6400 | explicit BoundFlagRef( bool &ref ) : m_ref( ref ) {} |
6401 | |
6402 | auto setFlag( bool flag ) -> ParserResult override { |
6403 | m_ref = flag; |
6404 | return ParserResult::ok( ParseResultType::Matched ); |
6405 | } |
6406 | }; |
6407 | |
6408 | template<typename ReturnType> |
6409 | struct LambdaInvoker { |
6410 | static_assert( std::is_same<ReturnType, ParserResult>::value, "Lambda must return void or clara::ParserResult" ); |
6411 | |
6412 | template<typename L, typename ArgType> |
6413 | static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult { |
6414 | return lambda( arg ); |
6415 | } |
6416 | }; |
6417 | |
6418 | template<> |
6419 | struct LambdaInvoker<void> { |
6420 | template<typename L, typename ArgType> |
6421 | static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult { |
6422 | lambda( arg ); |
6423 | return ParserResult::ok( ParseResultType::Matched ); |
6424 | } |
6425 | }; |
6426 | |
6427 | template<typename ArgType, typename L> |
6428 | inline auto invokeLambda( L const &lambda, std::string const &arg ) -> ParserResult { |
6429 | ArgType temp{}; |
6430 | auto result = convertInto( arg, temp ); |
6431 | return !result |
6432 | ? result |
6433 | : LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( lambda, temp ); |
6434 | } |
6435 | |
6436 | template<typename L> |
6437 | struct BoundLambda : BoundValueRefBase { |
6438 | L m_lambda; |
6439 | |
6440 | static_assert( UnaryLambdaTraits<L>::isValid, "Supplied lambda must take exactly one argument" ); |
6441 | explicit BoundLambda( L const &lambda ) : m_lambda( lambda ) {} |
6442 | |
6443 | auto setValue( std::string const &arg ) -> ParserResult override { |
6444 | return invokeLambda<typename UnaryLambdaTraits<L>::ArgType>( m_lambda, arg ); |
6445 | } |
6446 | }; |
6447 | |
6448 | template<typename L> |
6449 | struct BoundFlagLambda : BoundFlagRefBase { |
6450 | L m_lambda; |
6451 | |
6452 | static_assert( UnaryLambdaTraits<L>::isValid, "Supplied lambda must take exactly one argument" ); |
6453 | static_assert( std::is_same<typename UnaryLambdaTraits<L>::ArgType, bool>::value, "flags must be boolean" ); |
6454 | |
6455 | explicit BoundFlagLambda( L const &lambda ) : m_lambda( lambda ) {} |
6456 | |
6457 | auto setFlag( bool flag ) -> ParserResult override { |
6458 | return LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( m_lambda, flag ); |
6459 | } |
6460 | }; |
6461 | |
6462 | enum class Optionality { Optional, Required }; |
6463 | |
6464 | struct Parser; |
6465 | |
6466 | class ParserBase { |
6467 | public: |
6468 | virtual ~ParserBase() = default; |
6469 | virtual auto validate() const -> Result { return Result::ok(); } |
6470 | virtual auto parse( std::string const& exeName, TokenStream const &tokens) const -> InternalParseResult = 0; |
6471 | virtual auto cardinality() const -> size_t { return 1; } |
6472 | |
6473 | auto parse( Args const &args ) const -> InternalParseResult { |
6474 | return parse( args.exeName(), TokenStream( args ) ); |
6475 | } |
6476 | }; |
6477 | |
6478 | template<typename DerivedT> |
6479 | class ComposableParserImpl : public ParserBase { |
6480 | public: |
6481 | template<typename T> |
6482 | auto operator|( T const &other ) const -> Parser; |
6483 | |
6484 | template<typename T> |
6485 | auto operator+( T const &other ) const -> Parser; |
6486 | }; |
6487 | |
6488 | // Common code and state for Args and Opts |
6489 | template<typename DerivedT> |
6490 | class ParserRefImpl : public ComposableParserImpl<DerivedT> { |
6491 | protected: |
6492 | Optionality m_optionality = Optionality::Optional; |
6493 | std::shared_ptr<BoundRef> m_ref; |
6494 | std::string m_hint; |
6495 | std::string m_description; |
6496 | |
6497 | explicit ParserRefImpl( std::shared_ptr<BoundRef> const &ref ) : m_ref( ref ) {} |
6498 | |
6499 | public: |
6500 | template<typename T> |
6501 | ParserRefImpl( T &ref, std::string const &hint ) |
6502 | : m_ref( std::make_shared<BoundValueRef<T>>( ref ) ), |
6503 | m_hint( hint ) |
6504 | {} |
6505 | |
6506 | template<typename LambdaT> |
6507 | ParserRefImpl( LambdaT const &ref, std::string const &hint ) |
6508 | : m_ref( std::make_shared<BoundLambda<LambdaT>>( ref ) ), |
6509 | m_hint(hint) |
6510 | {} |
6511 | |
6512 | auto operator()( std::string const &description ) -> DerivedT & { |
6513 | m_description = description; |
6514 | return static_cast<DerivedT &>( *this ); |
6515 | } |
6516 | |
6517 | auto optional() -> DerivedT & { |
6518 | m_optionality = Optionality::Optional; |
6519 | return static_cast<DerivedT &>( *this ); |
6520 | }; |
6521 | |
6522 | auto required() -> DerivedT & { |
6523 | m_optionality = Optionality::Required; |
6524 | return static_cast<DerivedT &>( *this ); |
6525 | }; |
6526 | |
6527 | auto isOptional() const -> bool { |
6528 | return m_optionality == Optionality::Optional; |
6529 | } |
6530 | |
6531 | auto cardinality() const -> size_t override { |
6532 | if( m_ref->isContainer() ) |
6533 | return 0; |
6534 | else |
6535 | return 1; |
6536 | } |
6537 | |
6538 | auto hint() const -> std::string { return m_hint; } |
6539 | }; |
6540 | |
6541 | class ExeName : public ComposableParserImpl<ExeName> { |
6542 | std::shared_ptr<std::string> m_name; |
6543 | std::shared_ptr<BoundValueRefBase> m_ref; |
6544 | |
6545 | template<typename LambdaT> |
6546 | static auto makeRef(LambdaT const &lambda) -> std::shared_ptr<BoundValueRefBase> { |
6547 | return std::make_shared<BoundLambda<LambdaT>>( lambda) ; |
6548 | } |
6549 | |
6550 | public: |
6551 | ExeName() : m_name( std::make_shared<std::string>( "<executable>" ) ) {} |
6552 | |
6553 | explicit ExeName( std::string &ref ) : ExeName() { |
6554 | m_ref = std::make_shared<BoundValueRef<std::string>>( ref ); |
6555 | } |
6556 | |
6557 | template<typename LambdaT> |
6558 | explicit ExeName( LambdaT const& lambda ) : ExeName() { |
6559 | m_ref = std::make_shared<BoundLambda<LambdaT>>( lambda ); |
6560 | } |
6561 | |
6562 | // The exe name is not parsed out of the normal tokens, but is handled specially |
6563 | auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override { |
6564 | return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) ); |
6565 | } |
6566 | |
6567 | auto name() const -> std::string { return *m_name; } |
6568 | auto set( std::string const& newName ) -> ParserResult { |
6569 | |
6570 | auto lastSlash = newName.find_last_of( "\\/" ); |
6571 | auto filename = ( lastSlash == std::string::npos ) |
6572 | ? newName |
6573 | : newName.substr( lastSlash+1 ); |
6574 | |
6575 | *m_name = filename; |
6576 | if( m_ref ) |
6577 | return m_ref->setValue( filename ); |
6578 | else |
6579 | return ParserResult::ok( ParseResultType::Matched ); |
6580 | } |
6581 | }; |
6582 | |
6583 | class Arg : public ParserRefImpl<Arg> { |
6584 | public: |
6585 | using ParserRefImpl::ParserRefImpl; |
6586 | |
6587 | auto parse( std::string const &, TokenStream const &tokens ) const -> InternalParseResult override { |
6588 | auto validationResult = validate(); |
6589 | if( !validationResult ) |
6590 | return InternalParseResult( validationResult ); |
6591 | |
6592 | auto remainingTokens = tokens; |
6593 | auto const &token = *remainingTokens; |
6594 | if( token.type != TokenType::Argument ) |
6595 | return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) ); |
6596 | |
6597 | assert( !m_ref->isFlag() ); |
6598 | auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() ); |
6599 | |
6600 | auto result = valueRef->setValue( remainingTokens->token ); |
6601 | if( !result ) |
6602 | return InternalParseResult( result ); |
6603 | else |
6604 | return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) ); |
6605 | } |
6606 | }; |
6607 | |
6608 | inline auto normaliseOpt( std::string const &optName ) -> std::string { |
6609 | #ifdef CATCH_PLATFORM_WINDOWS |
6610 | if( optName[0] == '/' ) |
6611 | return "-" + optName.substr( 1 ); |
6612 | else |
6613 | #endif |
6614 | return optName; |
6615 | } |
6616 | |
6617 | class Opt : public ParserRefImpl<Opt> { |
6618 | protected: |
6619 | std::vector<std::string> m_optNames; |
6620 | |
6621 | public: |
6622 | template<typename LambdaT> |
6623 | explicit Opt( LambdaT const &ref ) : ParserRefImpl( std::make_shared<BoundFlagLambda<LambdaT>>( ref ) ) {} |
6624 | |
6625 | explicit Opt( bool &ref ) : ParserRefImpl( std::make_shared<BoundFlagRef>( ref ) ) {} |
6626 | |
6627 | template<typename LambdaT> |
6628 | Opt( LambdaT const &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {} |
6629 | |
6630 | template<typename T> |
6631 | Opt( T &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {} |
6632 | |
6633 | auto operator[]( std::string const &optName ) -> Opt & { |
6634 | m_optNames.push_back( optName ); |
6635 | return *this; |
6636 | } |
6637 | |
6638 | auto getHelpColumns() const -> std::vector<HelpColumns> { |
6639 | std::ostringstream oss; |
6640 | bool first = true; |
6641 | for( auto const &opt : m_optNames ) { |
6642 | if (first) |
6643 | first = false; |
6644 | else |
6645 | oss << ", " ; |
6646 | oss << opt; |
6647 | } |
6648 | if( !m_hint.empty() ) |
6649 | oss << " <" << m_hint << ">" ; |
6650 | return { { oss.str(), m_description } }; |
6651 | } |
6652 | |
6653 | auto isMatch( std::string const &optToken ) const -> bool { |
6654 | auto normalisedToken = normaliseOpt( optToken ); |
6655 | for( auto const &name : m_optNames ) { |
6656 | if( normaliseOpt( name ) == normalisedToken ) |
6657 | return true; |
6658 | } |
6659 | return false; |
6660 | } |
6661 | |
6662 | using ParserBase::parse; |
6663 | |
6664 | auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override { |
6665 | auto validationResult = validate(); |
6666 | if( !validationResult ) |
6667 | return InternalParseResult( validationResult ); |
6668 | |
6669 | auto remainingTokens = tokens; |
6670 | if( remainingTokens && remainingTokens->type == TokenType::Option ) { |
6671 | auto const &token = *remainingTokens; |
6672 | if( isMatch(token.token ) ) { |
6673 | if( m_ref->isFlag() ) { |
6674 | auto flagRef = static_cast<detail::BoundFlagRefBase*>( m_ref.get() ); |
6675 | auto result = flagRef->setFlag( true ); |
6676 | if( !result ) |
6677 | return InternalParseResult( result ); |
6678 | if( result.value() == ParseResultType::ShortCircuitAll ) |
6679 | return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) ); |
6680 | } else { |
6681 | auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() ); |
6682 | ++remainingTokens; |
6683 | if( !remainingTokens ) |
6684 | return InternalParseResult::runtimeError( "Expected argument following " + token.token ); |
6685 | auto const &argToken = *remainingTokens; |
6686 | if( argToken.type != TokenType::Argument ) |
6687 | return InternalParseResult::runtimeError( "Expected argument following " + token.token ); |
6688 | auto result = valueRef->setValue( argToken.token ); |
6689 | if( !result ) |
6690 | return InternalParseResult( result ); |
6691 | if( result.value() == ParseResultType::ShortCircuitAll ) |
6692 | return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) ); |
6693 | } |
6694 | return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) ); |
6695 | } |
6696 | } |
6697 | return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) ); |
6698 | } |
6699 | |
6700 | auto validate() const -> Result override { |
6701 | if( m_optNames.empty() ) |
6702 | return Result::logicError( "No options supplied to Opt" ); |
6703 | for( auto const &name : m_optNames ) { |
6704 | if( name.empty() ) |
6705 | return Result::logicError( "Option name cannot be empty" ); |
6706 | #ifdef CATCH_PLATFORM_WINDOWS |
6707 | if( name[0] != '-' && name[0] != '/' ) |
6708 | return Result::logicError( "Option name must begin with '-' or '/'" ); |
6709 | #else |
6710 | if( name[0] != '-' ) |
6711 | return Result::logicError( "Option name must begin with '-'" ); |
6712 | #endif |
6713 | } |
6714 | return ParserRefImpl::validate(); |
6715 | } |
6716 | }; |
6717 | |
6718 | struct Help : Opt { |
6719 | Help( bool &showHelpFlag ) |
6720 | : Opt([&]( bool flag ) { |
6721 | showHelpFlag = flag; |
6722 | return ParserResult::ok( ParseResultType::ShortCircuitAll ); |
6723 | }) |
6724 | { |
6725 | static_cast<Opt &>( *this ) |
6726 | ("display usage information" ) |
6727 | ["-?" ]["-h" ]["--help" ] |
6728 | .optional(); |
6729 | } |
6730 | }; |
6731 | |
6732 | struct Parser : ParserBase { |
6733 | |
6734 | mutable ExeName m_exeName; |
6735 | std::vector<Opt> m_options; |
6736 | std::vector<Arg> m_args; |
6737 | |
6738 | auto operator|=( ExeName const &exeName ) -> Parser & { |
6739 | m_exeName = exeName; |
6740 | return *this; |
6741 | } |
6742 | |
6743 | auto operator|=( Arg const &arg ) -> Parser & { |
6744 | m_args.push_back(arg); |
6745 | return *this; |
6746 | } |
6747 | |
6748 | auto operator|=( Opt const &opt ) -> Parser & { |
6749 | m_options.push_back(opt); |
6750 | return *this; |
6751 | } |
6752 | |
6753 | auto operator|=( Parser const &other ) -> Parser & { |
6754 | m_options.insert(m_options.end(), other.m_options.begin(), other.m_options.end()); |
6755 | m_args.insert(m_args.end(), other.m_args.begin(), other.m_args.end()); |
6756 | return *this; |
6757 | } |
6758 | |
6759 | template<typename T> |
6760 | auto operator|( T const &other ) const -> Parser { |
6761 | return Parser( *this ) |= other; |
6762 | } |
6763 | |
6764 | // Forward deprecated interface with '+' instead of '|' |
6765 | template<typename T> |
6766 | auto operator+=( T const &other ) -> Parser & { return operator|=( other ); } |
6767 | template<typename T> |
6768 | auto operator+( T const &other ) const -> Parser { return operator|( other ); } |
6769 | |
6770 | auto getHelpColumns() const -> std::vector<HelpColumns> { |
6771 | std::vector<HelpColumns> cols; |
6772 | for (auto const &o : m_options) { |
6773 | auto childCols = o.getHelpColumns(); |
6774 | cols.insert( cols.end(), childCols.begin(), childCols.end() ); |
6775 | } |
6776 | return cols; |
6777 | } |
6778 | |
6779 | void writeToStream( std::ostream &os ) const { |
6780 | if (!m_exeName.name().empty()) { |
6781 | os << "usage:\n" << " " << m_exeName.name() << " " ; |
6782 | bool required = true, first = true; |
6783 | for( auto const &arg : m_args ) { |
6784 | if (first) |
6785 | first = false; |
6786 | else |
6787 | os << " " ; |
6788 | if( arg.isOptional() && required ) { |
6789 | os << "[" ; |
6790 | required = false; |
6791 | } |
6792 | os << "<" << arg.hint() << ">" ; |
6793 | if( arg.cardinality() == 0 ) |
6794 | os << " ... " ; |
6795 | } |
6796 | if( !required ) |
6797 | os << "]" ; |
6798 | if( !m_options.empty() ) |
6799 | os << " options" ; |
6800 | os << "\n\nwhere options are:" << std::endl; |
6801 | } |
6802 | |
6803 | auto rows = getHelpColumns(); |
6804 | size_t consoleWidth = CATCH_CLARA_CONFIG_CONSOLE_WIDTH; |
6805 | size_t optWidth = 0; |
6806 | for( auto const &cols : rows ) |
6807 | optWidth = (std::max)(optWidth, cols.left.size() + 2); |
6808 | |
6809 | optWidth = (std::min)(optWidth, consoleWidth/2); |
6810 | |
6811 | for( auto const &cols : rows ) { |
6812 | auto row = |
6813 | TextFlow::Column( cols.left ).width( optWidth ).indent( 2 ) + |
6814 | TextFlow::Spacer(4) + |
6815 | TextFlow::Column( cols.right ).width( consoleWidth - 7 - optWidth ); |
6816 | os << row << std::endl; |
6817 | } |
6818 | } |
6819 | |
6820 | friend auto operator<<( std::ostream &os, Parser const &parser ) -> std::ostream& { |
6821 | parser.writeToStream( os ); |
6822 | return os; |
6823 | } |
6824 | |
6825 | auto validate() const -> Result override { |
6826 | for( auto const &opt : m_options ) { |
6827 | auto result = opt.validate(); |
6828 | if( !result ) |
6829 | return result; |
6830 | } |
6831 | for( auto const &arg : m_args ) { |
6832 | auto result = arg.validate(); |
6833 | if( !result ) |
6834 | return result; |
6835 | } |
6836 | return Result::ok(); |
6837 | } |
6838 | |
6839 | using ParserBase::parse; |
6840 | |
6841 | auto parse( std::string const& exeName, TokenStream const &tokens ) const -> InternalParseResult override { |
6842 | |
6843 | struct ParserInfo { |
6844 | ParserBase const* parser = nullptr; |
6845 | size_t count = 0; |
6846 | }; |
6847 | const size_t totalParsers = m_options.size() + m_args.size(); |
6848 | assert( totalParsers < 512 ); |
6849 | // ParserInfo parseInfos[totalParsers]; // <-- this is what we really want to do |
6850 | ParserInfo parseInfos[512]; |
6851 | |
6852 | { |
6853 | size_t i = 0; |
6854 | for (auto const &opt : m_options) parseInfos[i++].parser = &opt; |
6855 | for (auto const &arg : m_args) parseInfos[i++].parser = &arg; |
6856 | } |
6857 | |
6858 | m_exeName.set( exeName ); |
6859 | |
6860 | auto result = InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) ); |
6861 | while( result.value().remainingTokens() ) { |
6862 | bool tokenParsed = false; |
6863 | |
6864 | for( size_t i = 0; i < totalParsers; ++i ) { |
6865 | auto& parseInfo = parseInfos[i]; |
6866 | if( parseInfo.parser->cardinality() == 0 || parseInfo.count < parseInfo.parser->cardinality() ) { |
6867 | result = parseInfo.parser->parse(exeName, result.value().remainingTokens()); |
6868 | if (!result) |
6869 | return result; |
6870 | if (result.value().type() != ParseResultType::NoMatch) { |
6871 | tokenParsed = true; |
6872 | ++parseInfo.count; |
6873 | break; |
6874 | } |
6875 | } |
6876 | } |
6877 | |
6878 | if( result.value().type() == ParseResultType::ShortCircuitAll ) |
6879 | return result; |
6880 | if( !tokenParsed ) |
6881 | return InternalParseResult::runtimeError( "Unrecognised token: " + result.value().remainingTokens()->token ); |
6882 | } |
6883 | // !TBD Check missing required options |
6884 | return result; |
6885 | } |
6886 | }; |
6887 | |
6888 | template<typename DerivedT> |
6889 | template<typename T> |
6890 | auto ComposableParserImpl<DerivedT>::operator|( T const &other ) const -> Parser { |
6891 | return Parser() | static_cast<DerivedT const &>( *this ) | other; |
6892 | } |
6893 | } // namespace detail |
6894 | |
6895 | // A Combined parser |
6896 | using detail::Parser; |
6897 | |
6898 | // A parser for options |
6899 | using detail::Opt; |
6900 | |
6901 | // A parser for arguments |
6902 | using detail::Arg; |
6903 | |
6904 | // Wrapper for argc, argv from main() |
6905 | using detail::Args; |
6906 | |
6907 | // Specifies the name of the executable |
6908 | using detail::ExeName; |
6909 | |
6910 | // Convenience wrapper for option parser that specifies the help option |
6911 | using detail::Help; |
6912 | |
6913 | // enum of result types from a parse |
6914 | using detail::ParseResultType; |
6915 | |
6916 | // Result type for parser operation |
6917 | using detail::ParserResult; |
6918 | |
6919 | }} // namespace Catch::clara |
6920 | |
6921 | // end clara.hpp |
6922 | #ifdef __clang__ |
6923 | #pragma clang diagnostic pop |
6924 | #endif |
6925 | |
6926 | // Restore Clara's value for console width, if present |
6927 | #ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH |
6928 | #define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH |
6929 | #undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH |
6930 | #endif |
6931 | |
6932 | // end catch_clara.h |
6933 | namespace Catch { |
6934 | |
6935 | clara::Parser makeCommandLineParser( ConfigData& config ); |
6936 | |
6937 | } // end namespace Catch |
6938 | |
6939 | // end catch_commandline.h |
6940 | #include <fstream> |
6941 | #include <ctime> |
6942 | |
6943 | namespace Catch { |
6944 | |
6945 | clara::Parser makeCommandLineParser( ConfigData& config ) { |
6946 | |
6947 | using namespace clara; |
6948 | |
6949 | auto const setWarning = [&]( std::string const& warning ) { |
6950 | auto warningSet = [&]() { |
6951 | if( warning == "NoAssertions" ) |
6952 | return WarnAbout::NoAssertions; |
6953 | |
6954 | if ( warning == "NoTests" ) |
6955 | return WarnAbout::NoTests; |
6956 | |
6957 | return WarnAbout::Nothing; |
6958 | }(); |
6959 | |
6960 | if (warningSet == WarnAbout::Nothing) |
6961 | return ParserResult::runtimeError( "Unrecognised warning: '" + warning + "'" ); |
6962 | config.warnings = static_cast<WarnAbout::What>( config.warnings | warningSet ); |
6963 | return ParserResult::ok( ParseResultType::Matched ); |
6964 | }; |
6965 | auto const loadTestNamesFromFile = [&]( std::string const& filename ) { |
6966 | std::ifstream f( filename.c_str() ); |
6967 | if( !f.is_open() ) |
6968 | return ParserResult::runtimeError( "Unable to load input file: '" + filename + "'" ); |
6969 | |
6970 | std::string line; |
6971 | while( std::getline( f, line ) ) { |
6972 | line = trim(line); |
6973 | if( !line.empty() && !startsWith( line, '#' ) ) { |
6974 | if( !startsWith( line, '"' ) ) |
6975 | line = '"' + line + '"'; |
6976 | config.testsOrTags.push_back( line + ',' ); |
6977 | } |
6978 | } |
6979 | return ParserResult::ok( ParseResultType::Matched ); |
6980 | }; |
6981 | auto const setTestOrder = [&]( std::string const& order ) { |
6982 | if( startsWith( "declared" , order ) ) |
6983 | config.runOrder = RunTests::InDeclarationOrder; |
6984 | else if( startsWith( "lexical" , order ) ) |
6985 | config.runOrder = RunTests::InLexicographicalOrder; |
6986 | else if( startsWith( "random" , order ) ) |
6987 | config.runOrder = RunTests::InRandomOrder; |
6988 | else |
6989 | return clara::ParserResult::runtimeError( "Unrecognised ordering: '" + order + "'" ); |
6990 | return ParserResult::ok( ParseResultType::Matched ); |
6991 | }; |
6992 | auto const setRngSeed = [&]( std::string const& seed ) { |
6993 | if( seed != "time" ) |
6994 | return clara::detail::convertInto( seed, config.rngSeed ); |
6995 | config.rngSeed = static_cast<unsigned int>( std::time(nullptr) ); |
6996 | return ParserResult::ok( ParseResultType::Matched ); |
6997 | }; |
6998 | auto const setColourUsage = [&]( std::string const& useColour ) { |
6999 | auto mode = toLower( useColour ); |
7000 | |
7001 | if( mode == "yes" ) |
7002 | config.useColour = UseColour::Yes; |
7003 | else if( mode == "no" ) |
7004 | config.useColour = UseColour::No; |
7005 | else if( mode == "auto" ) |
7006 | config.useColour = UseColour::Auto; |
7007 | else |
7008 | return ParserResult::runtimeError( "colour mode must be one of: auto, yes or no. '" + useColour + "' not recognised" ); |
7009 | return ParserResult::ok( ParseResultType::Matched ); |
7010 | }; |
7011 | auto const setWaitForKeypress = [&]( std::string const& keypress ) { |
7012 | auto keypressLc = toLower( keypress ); |
7013 | if( keypressLc == "start" ) |
7014 | config.waitForKeypress = WaitForKeypress::BeforeStart; |
7015 | else if( keypressLc == "exit" ) |
7016 | config.waitForKeypress = WaitForKeypress::BeforeExit; |
7017 | else if( keypressLc == "both" ) |
7018 | config.waitForKeypress = WaitForKeypress::BeforeStartAndExit; |
7019 | else |
7020 | return ParserResult::runtimeError( "keypress argument must be one of: start, exit or both. '" + keypress + "' not recognised" ); |
7021 | return ParserResult::ok( ParseResultType::Matched ); |
7022 | }; |
7023 | auto const setVerbosity = [&]( std::string const& verbosity ) { |
7024 | auto lcVerbosity = toLower( verbosity ); |
7025 | if( lcVerbosity == "quiet" ) |
7026 | config.verbosity = Verbosity::Quiet; |
7027 | else if( lcVerbosity == "normal" ) |
7028 | config.verbosity = Verbosity::Normal; |
7029 | else if( lcVerbosity == "high" ) |
7030 | config.verbosity = Verbosity::High; |
7031 | else |
7032 | return ParserResult::runtimeError( "Unrecognised verbosity, '" + verbosity + "'" ); |
7033 | return ParserResult::ok( ParseResultType::Matched ); |
7034 | }; |
7035 | |
7036 | auto cli |
7037 | = ExeName( config.processName ) |
7038 | | Help( config.showHelp ) |
7039 | | Opt( config.listTests ) |
7040 | ["-l" ]["--list-tests" ] |
7041 | ( "list all/matching test cases" ) |
7042 | | Opt( config.listTags ) |
7043 | ["-t" ]["--list-tags" ] |
7044 | ( "list all/matching tags" ) |
7045 | | Opt( config.showSuccessfulTests ) |
7046 | ["-s" ]["--success" ] |
7047 | ( "include successful tests in output" ) |
7048 | | Opt( config.shouldDebugBreak ) |
7049 | ["-b" ]["--break" ] |
7050 | ( "break into debugger on failure" ) |
7051 | | Opt( config.noThrow ) |
7052 | ["-e" ]["--nothrow" ] |
7053 | ( "skip exception tests" ) |
7054 | | Opt( config.showInvisibles ) |
7055 | ["-i" ]["--invisibles" ] |
7056 | ( "show invisibles (tabs, newlines)" ) |
7057 | | Opt( config.outputFilename, "filename" ) |
7058 | ["-o" ]["--out" ] |
7059 | ( "output filename" ) |
7060 | | Opt( config.reporterName, "name" ) |
7061 | ["-r" ]["--reporter" ] |
7062 | ( "reporter to use (defaults to console)" ) |
7063 | | Opt( config.name, "name" ) |
7064 | ["-n" ]["--name" ] |
7065 | ( "suite name" ) |
7066 | | Opt( [&]( bool ){ config.abortAfter = 1; } ) |
7067 | ["-a" ]["--abort" ] |
7068 | ( "abort at first failure" ) |
7069 | | Opt( [&]( int x ){ config.abortAfter = x; }, "no. failures" ) |
7070 | ["-x" ]["--abortx" ] |
7071 | ( "abort after x failures" ) |
7072 | | Opt( setWarning, "warning name" ) |
7073 | ["-w" ]["--warn" ] |
7074 | ( "enable warnings" ) |
7075 | | Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" ) |
7076 | ["-d" ]["--durations" ] |
7077 | ( "show test durations" ) |
7078 | | Opt( loadTestNamesFromFile, "filename" ) |
7079 | ["-f" ]["--input-file" ] |
7080 | ( "load test names to run from a file" ) |
7081 | | Opt( config.filenamesAsTags ) |
7082 | ["-#" ]["--filenames-as-tags" ] |
7083 | ( "adds a tag for the filename" ) |
7084 | | Opt( config.sectionsToRun, "section name" ) |
7085 | ["-c" ]["--section" ] |
7086 | ( "specify section to run" ) |
7087 | | Opt( setVerbosity, "quiet|normal|high" ) |
7088 | ["-v" ]["--verbosity" ] |
7089 | ( "set output verbosity" ) |
7090 | | Opt( config.listTestNamesOnly ) |
7091 | ["--list-test-names-only" ] |
7092 | ( "list all/matching test cases names only" ) |
7093 | | Opt( config.listReporters ) |
7094 | ["--list-reporters" ] |
7095 | ( "list all reporters" ) |
7096 | | Opt( setTestOrder, "decl|lex|rand" ) |
7097 | ["--order" ] |
7098 | ( "test case order (defaults to decl)" ) |
7099 | | Opt( setRngSeed, "'time'|number" ) |
7100 | ["--rng-seed" ] |
7101 | ( "set a specific seed for random numbers" ) |
7102 | | Opt( setColourUsage, "yes|no" ) |
7103 | ["--use-colour" ] |
7104 | ( "should output be colourised" ) |
7105 | | Opt( config.libIdentify ) |
7106 | ["--libidentify" ] |
7107 | ( "report name and version according to libidentify standard" ) |
7108 | | Opt( setWaitForKeypress, "start|exit|both" ) |
7109 | ["--wait-for-keypress" ] |
7110 | ( "waits for a keypress before exiting" ) |
7111 | | Opt( config.benchmarkResolutionMultiple, "multiplier" ) |
7112 | ["--benchmark-resolution-multiple" ] |
7113 | ( "multiple of clock resolution to run benchmarks" ) |
7114 | |
7115 | | Arg( config.testsOrTags, "test name|pattern|tags" ) |
7116 | ( "which test or tests to use" ); |
7117 | |
7118 | return cli; |
7119 | } |
7120 | |
7121 | } // end namespace Catch |
7122 | // end catch_commandline.cpp |
7123 | // start catch_common.cpp |
7124 | |
7125 | #include <cstring> |
7126 | #include <ostream> |
7127 | |
7128 | namespace Catch { |
7129 | |
7130 | bool SourceLineInfo::empty() const noexcept { |
7131 | return file[0] == '\0'; |
7132 | } |
7133 | bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const noexcept { |
7134 | return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0); |
7135 | } |
7136 | bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const noexcept { |
7137 | // We can assume that the same file will usually have the same pointer. |
7138 | // Thus, if the pointers are the same, there is no point in calling the strcmp |
7139 | return line < other.line || ( line == other.line && file != other.file && (std::strcmp(file, other.file) < 0)); |
7140 | } |
7141 | |
7142 | std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { |
7143 | #ifndef __GNUG__ |
7144 | os << info.file << '(' << info.line << ')'; |
7145 | #else |
7146 | os << info.file << ':' << info.line; |
7147 | #endif |
7148 | return os; |
7149 | } |
7150 | |
7151 | std::string StreamEndStop::operator+() const { |
7152 | return std::string(); |
7153 | } |
7154 | |
7155 | NonCopyable::NonCopyable() = default; |
7156 | NonCopyable::~NonCopyable() = default; |
7157 | |
7158 | } |
7159 | // end catch_common.cpp |
7160 | // start catch_config.cpp |
7161 | |
7162 | namespace Catch { |
7163 | |
7164 | Config::Config( ConfigData const& data ) |
7165 | : m_data( data ), |
7166 | m_stream( openStream() ) |
7167 | { |
7168 | TestSpecParser parser(ITagAliasRegistry::get()); |
7169 | if (data.testsOrTags.empty()) { |
7170 | parser.parse("~[.]" ); // All not hidden tests |
7171 | } |
7172 | else { |
7173 | m_hasTestFilters = true; |
7174 | for( auto const& testOrTags : data.testsOrTags ) |
7175 | parser.parse( testOrTags ); |
7176 | } |
7177 | m_testSpec = parser.testSpec(); |
7178 | } |
7179 | |
7180 | std::string const& Config::getFilename() const { |
7181 | return m_data.outputFilename ; |
7182 | } |
7183 | |
7184 | bool Config::listTests() const { return m_data.listTests; } |
7185 | bool Config::listTestNamesOnly() const { return m_data.listTestNamesOnly; } |
7186 | bool Config::listTags() const { return m_data.listTags; } |
7187 | bool Config::listReporters() const { return m_data.listReporters; } |
7188 | |
7189 | std::string Config::getProcessName() const { return m_data.processName; } |
7190 | std::string const& Config::getReporterName() const { return m_data.reporterName; } |
7191 | |
7192 | std::vector<std::string> const& Config::getTestsOrTags() const { return m_data.testsOrTags; } |
7193 | std::vector<std::string> const& Config::getSectionsToRun() const { return m_data.sectionsToRun; } |
7194 | |
7195 | TestSpec const& Config::testSpec() const { return m_testSpec; } |
7196 | bool Config::hasTestFilters() const { return m_hasTestFilters; } |
7197 | |
7198 | bool Config::showHelp() const { return m_data.showHelp; } |
7199 | |
7200 | // IConfig interface |
7201 | bool Config::allowThrows() const { return !m_data.noThrow; } |
7202 | std::ostream& Config::stream() const { return m_stream->stream(); } |
7203 | std::string Config::name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } |
7204 | bool Config::includeSuccessfulResults() const { return m_data.showSuccessfulTests; } |
7205 | bool Config::warnAboutMissingAssertions() const { return !!(m_data.warnings & WarnAbout::NoAssertions); } |
7206 | bool Config::warnAboutNoTests() const { return !!(m_data.warnings & WarnAbout::NoTests); } |
7207 | ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; } |
7208 | RunTests::InWhatOrder Config::runOrder() const { return m_data.runOrder; } |
7209 | unsigned int Config::rngSeed() const { return m_data.rngSeed; } |
7210 | int Config::benchmarkResolutionMultiple() const { return m_data.benchmarkResolutionMultiple; } |
7211 | UseColour::YesOrNo Config::useColour() const { return m_data.useColour; } |
7212 | bool Config::shouldDebugBreak() const { return m_data.shouldDebugBreak; } |
7213 | int Config::abortAfter() const { return m_data.abortAfter; } |
7214 | bool Config::showInvisibles() const { return m_data.showInvisibles; } |
7215 | Verbosity Config::verbosity() const { return m_data.verbosity; } |
7216 | |
7217 | IStream const* Config::openStream() { |
7218 | return Catch::makeStream(m_data.outputFilename); |
7219 | } |
7220 | |
7221 | } // end namespace Catch |
7222 | // end catch_config.cpp |
7223 | // start catch_console_colour.cpp |
7224 | |
7225 | #if defined(__clang__) |
7226 | # pragma clang diagnostic push |
7227 | # pragma clang diagnostic ignored "-Wexit-time-destructors" |
7228 | #endif |
7229 | |
7230 | // start catch_errno_guard.h |
7231 | |
7232 | namespace Catch { |
7233 | |
7234 | class ErrnoGuard { |
7235 | public: |
7236 | ErrnoGuard(); |
7237 | ~ErrnoGuard(); |
7238 | private: |
7239 | int m_oldErrno; |
7240 | }; |
7241 | |
7242 | } |
7243 | |
7244 | // end catch_errno_guard.h |
7245 | #include <sstream> |
7246 | |
7247 | namespace Catch { |
7248 | namespace { |
7249 | |
7250 | struct IColourImpl { |
7251 | virtual ~IColourImpl() = default; |
7252 | virtual void use( Colour::Code _colourCode ) = 0; |
7253 | }; |
7254 | |
7255 | struct NoColourImpl : IColourImpl { |
7256 | void use( Colour::Code ) {} |
7257 | |
7258 | static IColourImpl* instance() { |
7259 | static NoColourImpl s_instance; |
7260 | return &s_instance; |
7261 | } |
7262 | }; |
7263 | |
7264 | } // anon namespace |
7265 | } // namespace Catch |
7266 | |
7267 | #if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI ) |
7268 | # ifdef CATCH_PLATFORM_WINDOWS |
7269 | # define CATCH_CONFIG_COLOUR_WINDOWS |
7270 | # else |
7271 | # define CATCH_CONFIG_COLOUR_ANSI |
7272 | # endif |
7273 | #endif |
7274 | |
7275 | #if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) ///////////////////////////////////////// |
7276 | |
7277 | namespace Catch { |
7278 | namespace { |
7279 | |
7280 | class Win32ColourImpl : public IColourImpl { |
7281 | public: |
7282 | Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) |
7283 | { |
7284 | CONSOLE_SCREEN_BUFFER_INFO csbiInfo; |
7285 | GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); |
7286 | originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY ); |
7287 | originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY ); |
7288 | } |
7289 | |
7290 | virtual void use( Colour::Code _colourCode ) override { |
7291 | switch( _colourCode ) { |
7292 | case Colour::None: return setTextAttribute( originalForegroundAttributes ); |
7293 | case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); |
7294 | case Colour::Red: return setTextAttribute( FOREGROUND_RED ); |
7295 | case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); |
7296 | case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE ); |
7297 | case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN ); |
7298 | case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN ); |
7299 | case Colour::Grey: return setTextAttribute( 0 ); |
7300 | |
7301 | case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY ); |
7302 | case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED ); |
7303 | case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); |
7304 | case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); |
7305 | case Colour::BrightYellow: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN ); |
7306 | |
7307 | case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" ); |
7308 | |
7309 | default: |
7310 | CATCH_ERROR( "Unknown colour requested" ); |
7311 | } |
7312 | } |
7313 | |
7314 | private: |
7315 | void setTextAttribute( WORD _textAttribute ) { |
7316 | SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes ); |
7317 | } |
7318 | HANDLE stdoutHandle; |
7319 | WORD originalForegroundAttributes; |
7320 | WORD originalBackgroundAttributes; |
7321 | }; |
7322 | |
7323 | IColourImpl* platformColourInstance() { |
7324 | static Win32ColourImpl s_instance; |
7325 | |
7326 | IConfigPtr config = getCurrentContext().getConfig(); |
7327 | UseColour::YesOrNo colourMode = config |
7328 | ? config->useColour() |
7329 | : UseColour::Auto; |
7330 | if( colourMode == UseColour::Auto ) |
7331 | colourMode = UseColour::Yes; |
7332 | return colourMode == UseColour::Yes |
7333 | ? &s_instance |
7334 | : NoColourImpl::instance(); |
7335 | } |
7336 | |
7337 | } // end anon namespace |
7338 | } // end namespace Catch |
7339 | |
7340 | #elif defined( CATCH_CONFIG_COLOUR_ANSI ) ////////////////////////////////////// |
7341 | |
7342 | #include <unistd.h> |
7343 | |
7344 | namespace Catch { |
7345 | namespace { |
7346 | |
7347 | // use POSIX/ ANSI console terminal codes |
7348 | // Thanks to Adam Strzelecki for original contribution |
7349 | // (http://github.com/nanoant) |
7350 | // https://github.com/philsquared/Catch/pull/131 |
7351 | class PosixColourImpl : public IColourImpl { |
7352 | public: |
7353 | virtual void use( Colour::Code _colourCode ) override { |
7354 | switch( _colourCode ) { |
7355 | case Colour::None: |
7356 | case Colour::White: return setColour( "[0m" ); |
7357 | case Colour::Red: return setColour( "[0;31m" ); |
7358 | case Colour::Green: return setColour( "[0;32m" ); |
7359 | case Colour::Blue: return setColour( "[0;34m" ); |
7360 | case Colour::Cyan: return setColour( "[0;36m" ); |
7361 | case Colour::Yellow: return setColour( "[0;33m" ); |
7362 | case Colour::Grey: return setColour( "[1;30m" ); |
7363 | |
7364 | case Colour::LightGrey: return setColour( "[0;37m" ); |
7365 | case Colour::BrightRed: return setColour( "[1;31m" ); |
7366 | case Colour::BrightGreen: return setColour( "[1;32m" ); |
7367 | case Colour::BrightWhite: return setColour( "[1;37m" ); |
7368 | case Colour::BrightYellow: return setColour( "[1;33m" ); |
7369 | |
7370 | case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" ); |
7371 | default: CATCH_INTERNAL_ERROR( "Unknown colour requested" ); |
7372 | } |
7373 | } |
7374 | static IColourImpl* instance() { |
7375 | static PosixColourImpl s_instance; |
7376 | return &s_instance; |
7377 | } |
7378 | |
7379 | private: |
7380 | void setColour( const char* _escapeCode ) { |
7381 | Catch::cout() << '\033' << _escapeCode; |
7382 | } |
7383 | }; |
7384 | |
7385 | bool useColourOnPlatform() { |
7386 | return |
7387 | #ifdef CATCH_PLATFORM_MAC |
7388 | !isDebuggerActive() && |
7389 | #endif |
7390 | #if !(defined(__DJGPP__) && defined(__STRICT_ANSI__)) |
7391 | isatty(STDOUT_FILENO) |
7392 | #else |
7393 | false |
7394 | #endif |
7395 | ; |
7396 | } |
7397 | IColourImpl* platformColourInstance() { |
7398 | ErrnoGuard guard; |
7399 | IConfigPtr config = getCurrentContext().getConfig(); |
7400 | UseColour::YesOrNo colourMode = config |
7401 | ? config->useColour() |
7402 | : UseColour::Auto; |
7403 | if( colourMode == UseColour::Auto ) |
7404 | colourMode = useColourOnPlatform() |
7405 | ? UseColour::Yes |
7406 | : UseColour::No; |
7407 | return colourMode == UseColour::Yes |
7408 | ? PosixColourImpl::instance() |
7409 | : NoColourImpl::instance(); |
7410 | } |
7411 | |
7412 | } // end anon namespace |
7413 | } // end namespace Catch |
7414 | |
7415 | #else // not Windows or ANSI /////////////////////////////////////////////// |
7416 | |
7417 | namespace Catch { |
7418 | |
7419 | static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); } |
7420 | |
7421 | } // end namespace Catch |
7422 | |
7423 | #endif // Windows/ ANSI/ None |
7424 | |
7425 | namespace Catch { |
7426 | |
7427 | Colour::Colour( Code _colourCode ) { use( _colourCode ); } |
7428 | Colour::Colour( Colour&& rhs ) noexcept { |
7429 | m_moved = rhs.m_moved; |
7430 | rhs.m_moved = true; |
7431 | } |
7432 | Colour& Colour::operator=( Colour&& rhs ) noexcept { |
7433 | m_moved = rhs.m_moved; |
7434 | rhs.m_moved = true; |
7435 | return *this; |
7436 | } |
7437 | |
7438 | Colour::~Colour(){ if( !m_moved ) use( None ); } |
7439 | |
7440 | void Colour::use( Code _colourCode ) { |
7441 | static IColourImpl* impl = platformColourInstance(); |
7442 | impl->use( _colourCode ); |
7443 | } |
7444 | |
7445 | std::ostream& operator << ( std::ostream& os, Colour const& ) { |
7446 | return os; |
7447 | } |
7448 | |
7449 | } // end namespace Catch |
7450 | |
7451 | #if defined(__clang__) |
7452 | # pragma clang diagnostic pop |
7453 | #endif |
7454 | |
7455 | // end catch_console_colour.cpp |
7456 | // start catch_context.cpp |
7457 | |
7458 | namespace Catch { |
7459 | |
7460 | class Context : public IMutableContext, NonCopyable { |
7461 | |
7462 | public: // IContext |
7463 | virtual IResultCapture* getResultCapture() override { |
7464 | return m_resultCapture; |
7465 | } |
7466 | virtual IRunner* getRunner() override { |
7467 | return m_runner; |
7468 | } |
7469 | |
7470 | virtual IConfigPtr const& getConfig() const override { |
7471 | return m_config; |
7472 | } |
7473 | |
7474 | virtual ~Context() override; |
7475 | |
7476 | public: // IMutableContext |
7477 | virtual void setResultCapture( IResultCapture* resultCapture ) override { |
7478 | m_resultCapture = resultCapture; |
7479 | } |
7480 | virtual void setRunner( IRunner* runner ) override { |
7481 | m_runner = runner; |
7482 | } |
7483 | virtual void setConfig( IConfigPtr const& config ) override { |
7484 | m_config = config; |
7485 | } |
7486 | |
7487 | friend IMutableContext& getCurrentMutableContext(); |
7488 | |
7489 | private: |
7490 | IConfigPtr m_config; |
7491 | IRunner* m_runner = nullptr; |
7492 | IResultCapture* m_resultCapture = nullptr; |
7493 | }; |
7494 | |
7495 | IMutableContext *IMutableContext::currentContext = nullptr; |
7496 | |
7497 | void IMutableContext::createContext() |
7498 | { |
7499 | currentContext = new Context(); |
7500 | } |
7501 | |
7502 | void cleanUpContext() { |
7503 | delete IMutableContext::currentContext; |
7504 | IMutableContext::currentContext = nullptr; |
7505 | } |
7506 | IContext::~IContext() = default; |
7507 | IMutableContext::~IMutableContext() = default; |
7508 | Context::~Context() = default; |
7509 | } |
7510 | // end catch_context.cpp |
7511 | // start catch_debug_console.cpp |
7512 | |
7513 | // start catch_debug_console.h |
7514 | |
7515 | #include <string> |
7516 | |
7517 | namespace Catch { |
7518 | void writeToDebugConsole( std::string const& text ); |
7519 | } |
7520 | |
7521 | // end catch_debug_console.h |
7522 | #ifdef CATCH_PLATFORM_WINDOWS |
7523 | |
7524 | namespace Catch { |
7525 | void writeToDebugConsole( std::string const& text ) { |
7526 | ::OutputDebugStringA( text.c_str() ); |
7527 | } |
7528 | } |
7529 | |
7530 | #else |
7531 | |
7532 | namespace Catch { |
7533 | void writeToDebugConsole( std::string const& text ) { |
7534 | // !TBD: Need a version for Mac/ XCode and other IDEs |
7535 | Catch::cout() << text; |
7536 | } |
7537 | } |
7538 | |
7539 | #endif // Platform |
7540 | // end catch_debug_console.cpp |
7541 | // start catch_debugger.cpp |
7542 | |
7543 | #ifdef CATCH_PLATFORM_MAC |
7544 | |
7545 | # include <assert.h> |
7546 | # include <stdbool.h> |
7547 | # include <sys/types.h> |
7548 | # include <unistd.h> |
7549 | # include <sys/sysctl.h> |
7550 | # include <cstddef> |
7551 | # include <ostream> |
7552 | |
7553 | namespace Catch { |
7554 | |
7555 | // The following function is taken directly from the following technical note: |
7556 | // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html |
7557 | |
7558 | // Returns true if the current process is being debugged (either |
7559 | // running under the debugger or has a debugger attached post facto). |
7560 | bool isDebuggerActive(){ |
7561 | |
7562 | int mib[4]; |
7563 | struct kinfo_proc info; |
7564 | std::size_t size; |
7565 | |
7566 | // Initialize the flags so that, if sysctl fails for some bizarre |
7567 | // reason, we get a predictable result. |
7568 | |
7569 | info.kp_proc.p_flag = 0; |
7570 | |
7571 | // Initialize mib, which tells sysctl the info we want, in this case |
7572 | // we're looking for information about a specific process ID. |
7573 | |
7574 | mib[0] = CTL_KERN; |
7575 | mib[1] = KERN_PROC; |
7576 | mib[2] = KERN_PROC_PID; |
7577 | mib[3] = getpid(); |
7578 | |
7579 | // Call sysctl. |
7580 | |
7581 | size = sizeof(info); |
7582 | if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, nullptr, 0) != 0 ) { |
7583 | Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; |
7584 | return false; |
7585 | } |
7586 | |
7587 | // We're being debugged if the P_TRACED flag is set. |
7588 | |
7589 | return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); |
7590 | } |
7591 | } // namespace Catch |
7592 | |
7593 | #elif defined(CATCH_PLATFORM_LINUX) |
7594 | #include <fstream> |
7595 | #include <string> |
7596 | |
7597 | namespace Catch{ |
7598 | // The standard POSIX way of detecting a debugger is to attempt to |
7599 | // ptrace() the process, but this needs to be done from a child and not |
7600 | // this process itself to still allow attaching to this process later |
7601 | // if wanted, so is rather heavy. Under Linux we have the PID of the |
7602 | // "debugger" (which doesn't need to be gdb, of course, it could also |
7603 | // be strace, for example) in /proc/$PID/status, so just get it from |
7604 | // there instead. |
7605 | bool isDebuggerActive(){ |
7606 | // Libstdc++ has a bug, where std::ifstream sets errno to 0 |
7607 | // This way our users can properly assert over errno values |
7608 | ErrnoGuard guard; |
7609 | std::ifstream in("/proc/self/status" ); |
7610 | for( std::string line; std::getline(in, line); ) { |
7611 | static const int PREFIX_LEN = 11; |
7612 | if( line.compare(0, PREFIX_LEN, "TracerPid:\t" ) == 0 ) { |
7613 | // We're traced if the PID is not 0 and no other PID starts |
7614 | // with 0 digit, so it's enough to check for just a single |
7615 | // character. |
7616 | return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0'; |
7617 | } |
7618 | } |
7619 | |
7620 | return false; |
7621 | } |
7622 | } // namespace Catch |
7623 | #elif defined(_MSC_VER) |
7624 | extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); |
7625 | namespace Catch { |
7626 | bool isDebuggerActive() { |
7627 | return IsDebuggerPresent() != 0; |
7628 | } |
7629 | } |
7630 | #elif defined(__MINGW32__) |
7631 | extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); |
7632 | namespace Catch { |
7633 | bool isDebuggerActive() { |
7634 | return IsDebuggerPresent() != 0; |
7635 | } |
7636 | } |
7637 | #else |
7638 | namespace Catch { |
7639 | bool isDebuggerActive() { return false; } |
7640 | } |
7641 | #endif // Platform |
7642 | // end catch_debugger.cpp |
7643 | // start catch_decomposer.cpp |
7644 | |
7645 | namespace Catch { |
7646 | |
7647 | ITransientExpression::~ITransientExpression() = default; |
7648 | |
7649 | void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ) { |
7650 | if( lhs.size() + rhs.size() < 40 && |
7651 | lhs.find('\n') == std::string::npos && |
7652 | rhs.find('\n') == std::string::npos ) |
7653 | os << lhs << " " << op << " " << rhs; |
7654 | else |
7655 | os << lhs << "\n" << op << "\n" << rhs; |
7656 | } |
7657 | } |
7658 | // end catch_decomposer.cpp |
7659 | // start catch_enforce.cpp |
7660 | |
7661 | namespace Catch { |
7662 | #if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER) |
7663 | [[noreturn]] |
7664 | void throw_exception(std::exception const& e) { |
7665 | Catch::cerr() << "Catch will terminate because it needed to throw an exception.\n" |
7666 | << "The message was: " << e.what() << '\n'; |
7667 | std::terminate(); |
7668 | } |
7669 | #endif |
7670 | } // namespace Catch; |
7671 | // end catch_enforce.cpp |
7672 | // start catch_errno_guard.cpp |
7673 | |
7674 | #include <cerrno> |
7675 | |
7676 | namespace Catch { |
7677 | ErrnoGuard::ErrnoGuard():m_oldErrno(errno){} |
7678 | ErrnoGuard::~ErrnoGuard() { errno = m_oldErrno; } |
7679 | } |
7680 | // end catch_errno_guard.cpp |
7681 | // start catch_exception_translator_registry.cpp |
7682 | |
7683 | // start catch_exception_translator_registry.h |
7684 | |
7685 | #include <vector> |
7686 | #include <string> |
7687 | #include <memory> |
7688 | |
7689 | namespace Catch { |
7690 | |
7691 | class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { |
7692 | public: |
7693 | ~ExceptionTranslatorRegistry(); |
7694 | virtual void registerTranslator( const IExceptionTranslator* translator ); |
7695 | virtual std::string translateActiveException() const override; |
7696 | std::string tryTranslators() const; |
7697 | |
7698 | private: |
7699 | std::vector<std::unique_ptr<IExceptionTranslator const>> m_translators; |
7700 | }; |
7701 | } |
7702 | |
7703 | // end catch_exception_translator_registry.h |
7704 | #ifdef __OBJC__ |
7705 | #import "Foundation/Foundation.h" |
7706 | #endif |
7707 | |
7708 | namespace Catch { |
7709 | |
7710 | ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() { |
7711 | } |
7712 | |
7713 | void ExceptionTranslatorRegistry::registerTranslator( const IExceptionTranslator* translator ) { |
7714 | m_translators.push_back( std::unique_ptr<const IExceptionTranslator>( translator ) ); |
7715 | } |
7716 | |
7717 | #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) |
7718 | std::string ExceptionTranslatorRegistry::translateActiveException() const { |
7719 | try { |
7720 | #ifdef __OBJC__ |
7721 | // In Objective-C try objective-c exceptions first |
7722 | @try { |
7723 | return tryTranslators(); |
7724 | } |
7725 | @catch (NSException *exception) { |
7726 | return Catch::Detail::stringify( [exception description] ); |
7727 | } |
7728 | #else |
7729 | // Compiling a mixed mode project with MSVC means that CLR |
7730 | // exceptions will be caught in (...) as well. However, these |
7731 | // do not fill-in std::current_exception and thus lead to crash |
7732 | // when attempting rethrow. |
7733 | // /EHa switch also causes structured exceptions to be caught |
7734 | // here, but they fill-in current_exception properly, so |
7735 | // at worst the output should be a little weird, instead of |
7736 | // causing a crash. |
7737 | if (std::current_exception() == nullptr) { |
7738 | return "Non C++ exception. Possibly a CLR exception." ; |
7739 | } |
7740 | return tryTranslators(); |
7741 | #endif |
7742 | } |
7743 | catch( TestFailureException& ) { |
7744 | std::rethrow_exception(std::current_exception()); |
7745 | } |
7746 | catch( std::exception& ex ) { |
7747 | return ex.what(); |
7748 | } |
7749 | catch( std::string& msg ) { |
7750 | return msg; |
7751 | } |
7752 | catch( const char* msg ) { |
7753 | return msg; |
7754 | } |
7755 | catch(...) { |
7756 | return "Unknown exception" ; |
7757 | } |
7758 | } |
7759 | |
7760 | #else // ^^ Exceptions are enabled // Exceptions are disabled vv |
7761 | std::string ExceptionTranslatorRegistry::translateActiveException() const { |
7762 | CATCH_INTERNAL_ERROR("Attempted to translate active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!" ); |
7763 | } |
7764 | #endif |
7765 | |
7766 | std::string ExceptionTranslatorRegistry::tryTranslators() const { |
7767 | if( m_translators.empty() ) |
7768 | std::rethrow_exception(std::current_exception()); |
7769 | else |
7770 | return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() ); |
7771 | } |
7772 | } |
7773 | // end catch_exception_translator_registry.cpp |
7774 | // start catch_fatal_condition.cpp |
7775 | |
7776 | #if defined(__GNUC__) |
7777 | # pragma GCC diagnostic push |
7778 | # pragma GCC diagnostic ignored "-Wmissing-field-initializers" |
7779 | #endif |
7780 | |
7781 | #if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS ) |
7782 | |
7783 | namespace { |
7784 | // Report the error condition |
7785 | void reportFatal( char const * const message ) { |
7786 | Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message ); |
7787 | } |
7788 | } |
7789 | |
7790 | #endif // signals/SEH handling |
7791 | |
7792 | #if defined( CATCH_CONFIG_WINDOWS_SEH ) |
7793 | |
7794 | namespace Catch { |
7795 | struct SignalDefs { DWORD id; const char* name; }; |
7796 | |
7797 | // There is no 1-1 mapping between signals and windows exceptions. |
7798 | // Windows can easily distinguish between SO and SigSegV, |
7799 | // but SigInt, SigTerm, etc are handled differently. |
7800 | static SignalDefs signalDefs[] = { |
7801 | { EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal" }, |
7802 | { EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" }, |
7803 | { EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" }, |
7804 | { EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" }, |
7805 | }; |
7806 | |
7807 | LONG CALLBACK FatalConditionHandler::handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) { |
7808 | for (auto const& def : signalDefs) { |
7809 | if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) { |
7810 | reportFatal(def.name); |
7811 | } |
7812 | } |
7813 | // If its not an exception we care about, pass it along. |
7814 | // This stops us from eating debugger breaks etc. |
7815 | return EXCEPTION_CONTINUE_SEARCH; |
7816 | } |
7817 | |
7818 | FatalConditionHandler::FatalConditionHandler() { |
7819 | isSet = true; |
7820 | // 32k seems enough for Catch to handle stack overflow, |
7821 | // but the value was found experimentally, so there is no strong guarantee |
7822 | guaranteeSize = 32 * 1024; |
7823 | exceptionHandlerHandle = nullptr; |
7824 | // Register as first handler in current chain |
7825 | exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException); |
7826 | // Pass in guarantee size to be filled |
7827 | SetThreadStackGuarantee(&guaranteeSize); |
7828 | } |
7829 | |
7830 | void FatalConditionHandler::reset() { |
7831 | if (isSet) { |
7832 | RemoveVectoredExceptionHandler(exceptionHandlerHandle); |
7833 | SetThreadStackGuarantee(&guaranteeSize); |
7834 | exceptionHandlerHandle = nullptr; |
7835 | isSet = false; |
7836 | } |
7837 | } |
7838 | |
7839 | FatalConditionHandler::~FatalConditionHandler() { |
7840 | reset(); |
7841 | } |
7842 | |
7843 | bool FatalConditionHandler::isSet = false; |
7844 | ULONG FatalConditionHandler::guaranteeSize = 0; |
7845 | PVOID FatalConditionHandler::exceptionHandlerHandle = nullptr; |
7846 | |
7847 | } // namespace Catch |
7848 | |
7849 | #elif defined( CATCH_CONFIG_POSIX_SIGNALS ) |
7850 | |
7851 | namespace Catch { |
7852 | |
7853 | struct SignalDefs { |
7854 | int id; |
7855 | const char* name; |
7856 | }; |
7857 | |
7858 | // 32kb for the alternate stack seems to be sufficient. However, this value |
7859 | // is experimentally determined, so that's not guaranteed. |
7860 | constexpr static std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ; |
7861 | |
7862 | static SignalDefs signalDefs[] = { |
7863 | { SIGINT, "SIGINT - Terminal interrupt signal" }, |
7864 | { SIGILL, "SIGILL - Illegal instruction signal" }, |
7865 | { SIGFPE, "SIGFPE - Floating point error signal" }, |
7866 | { SIGSEGV, "SIGSEGV - Segmentation violation signal" }, |
7867 | { SIGTERM, "SIGTERM - Termination request signal" }, |
7868 | { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } |
7869 | }; |
7870 | |
7871 | void FatalConditionHandler::handleSignal( int sig ) { |
7872 | char const * name = "<unknown signal>" ; |
7873 | for (auto const& def : signalDefs) { |
7874 | if (sig == def.id) { |
7875 | name = def.name; |
7876 | break; |
7877 | } |
7878 | } |
7879 | reset(); |
7880 | reportFatal(name); |
7881 | raise( sig ); |
7882 | } |
7883 | |
7884 | FatalConditionHandler::FatalConditionHandler() { |
7885 | isSet = true; |
7886 | stack_t sigStack; |
7887 | sigStack.ss_sp = altStackMem; |
7888 | sigStack.ss_size = sigStackSize; |
7889 | sigStack.ss_flags = 0; |
7890 | sigaltstack(&sigStack, &oldSigStack); |
7891 | struct sigaction sa = { }; |
7892 | |
7893 | sa.sa_handler = handleSignal; |
7894 | sa.sa_flags = SA_ONSTACK; |
7895 | for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) { |
7896 | sigaction(signalDefs[i].id, &sa, &oldSigActions[i]); |
7897 | } |
7898 | } |
7899 | |
7900 | FatalConditionHandler::~FatalConditionHandler() { |
7901 | reset(); |
7902 | } |
7903 | |
7904 | void FatalConditionHandler::reset() { |
7905 | if( isSet ) { |
7906 | // Set signals back to previous values -- hopefully nobody overwrote them in the meantime |
7907 | for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) { |
7908 | sigaction(signalDefs[i].id, &oldSigActions[i], nullptr); |
7909 | } |
7910 | // Return the old stack |
7911 | sigaltstack(&oldSigStack, nullptr); |
7912 | isSet = false; |
7913 | } |
7914 | } |
7915 | |
7916 | bool FatalConditionHandler::isSet = false; |
7917 | struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {}; |
7918 | stack_t FatalConditionHandler::oldSigStack = {}; |
7919 | char FatalConditionHandler::altStackMem[sigStackSize] = {}; |
7920 | |
7921 | } // namespace Catch |
7922 | |
7923 | #else |
7924 | |
7925 | namespace Catch { |
7926 | void FatalConditionHandler::reset() {} |
7927 | } |
7928 | |
7929 | #endif // signals/SEH handling |
7930 | |
7931 | #if defined(__GNUC__) |
7932 | # pragma GCC diagnostic pop |
7933 | #endif |
7934 | // end catch_fatal_condition.cpp |
7935 | // start catch_generators.cpp |
7936 | |
7937 | // start catch_random_number_generator.h |
7938 | |
7939 | #include <algorithm> |
7940 | #include <random> |
7941 | |
7942 | namespace Catch { |
7943 | |
7944 | struct IConfig; |
7945 | |
7946 | std::mt19937& rng(); |
7947 | void seedRng( IConfig const& config ); |
7948 | unsigned int rngSeed(); |
7949 | |
7950 | } |
7951 | |
7952 | // end catch_random_number_generator.h |
7953 | #include <limits> |
7954 | #include <set> |
7955 | |
7956 | namespace Catch { |
7957 | |
7958 | IGeneratorTracker::~IGeneratorTracker() {} |
7959 | |
7960 | namespace Generators { |
7961 | |
7962 | GeneratorBase::~GeneratorBase() {} |
7963 | |
7964 | std::vector<size_t> randomiseIndices( size_t selectionSize, size_t sourceSize ) { |
7965 | |
7966 | assert( selectionSize <= sourceSize ); |
7967 | std::vector<size_t> indices; |
7968 | indices.reserve( selectionSize ); |
7969 | std::uniform_int_distribution<size_t> uid( 0, sourceSize-1 ); |
7970 | |
7971 | std::set<size_t> seen; |
7972 | // !TBD: improve this algorithm |
7973 | while( indices.size() < selectionSize ) { |
7974 | auto index = uid( rng() ); |
7975 | if( seen.insert( index ).second ) |
7976 | indices.push_back( index ); |
7977 | } |
7978 | return indices; |
7979 | } |
7980 | |
7981 | auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { |
7982 | return getResultCapture().acquireGeneratorTracker( lineInfo ); |
7983 | } |
7984 | |
7985 | template<> |
7986 | auto all<int>() -> Generator<int> { |
7987 | return range( std::numeric_limits<int>::min(), std::numeric_limits<int>::max() ); |
7988 | } |
7989 | |
7990 | } // namespace Generators |
7991 | } // namespace Catch |
7992 | // end catch_generators.cpp |
7993 | // start catch_interfaces_capture.cpp |
7994 | |
7995 | namespace Catch { |
7996 | IResultCapture::~IResultCapture() = default; |
7997 | } |
7998 | // end catch_interfaces_capture.cpp |
7999 | // start catch_interfaces_config.cpp |
8000 | |
8001 | namespace Catch { |
8002 | IConfig::~IConfig() = default; |
8003 | } |
8004 | // end catch_interfaces_config.cpp |
8005 | // start catch_interfaces_exception.cpp |
8006 | |
8007 | namespace Catch { |
8008 | IExceptionTranslator::~IExceptionTranslator() = default; |
8009 | IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() = default; |
8010 | } |
8011 | // end catch_interfaces_exception.cpp |
8012 | // start catch_interfaces_registry_hub.cpp |
8013 | |
8014 | namespace Catch { |
8015 | IRegistryHub::~IRegistryHub() = default; |
8016 | IMutableRegistryHub::~IMutableRegistryHub() = default; |
8017 | } |
8018 | // end catch_interfaces_registry_hub.cpp |
8019 | // start catch_interfaces_reporter.cpp |
8020 | |
8021 | // start catch_reporter_listening.h |
8022 | |
8023 | namespace Catch { |
8024 | |
8025 | class ListeningReporter : public IStreamingReporter { |
8026 | using Reporters = std::vector<IStreamingReporterPtr>; |
8027 | Reporters m_listeners; |
8028 | IStreamingReporterPtr m_reporter = nullptr; |
8029 | ReporterPreferences m_preferences; |
8030 | |
8031 | public: |
8032 | ListeningReporter(); |
8033 | |
8034 | void addListener( IStreamingReporterPtr&& listener ); |
8035 | void addReporter( IStreamingReporterPtr&& reporter ); |
8036 | |
8037 | public: // IStreamingReporter |
8038 | |
8039 | ReporterPreferences getPreferences() const override; |
8040 | |
8041 | void noMatchingTestCases( std::string const& spec ) override; |
8042 | |
8043 | static std::set<Verbosity> getSupportedVerbosities(); |
8044 | |
8045 | void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) override; |
8046 | void benchmarkEnded( BenchmarkStats const& benchmarkStats ) override; |
8047 | |
8048 | void testRunStarting( TestRunInfo const& testRunInfo ) override; |
8049 | void testGroupStarting( GroupInfo const& groupInfo ) override; |
8050 | void testCaseStarting( TestCaseInfo const& testInfo ) override; |
8051 | void sectionStarting( SectionInfo const& sectionInfo ) override; |
8052 | void assertionStarting( AssertionInfo const& assertionInfo ) override; |
8053 | |
8054 | // The return value indicates if the messages buffer should be cleared: |
8055 | bool assertionEnded( AssertionStats const& assertionStats ) override; |
8056 | void sectionEnded( SectionStats const& sectionStats ) override; |
8057 | void testCaseEnded( TestCaseStats const& testCaseStats ) override; |
8058 | void testGroupEnded( TestGroupStats const& testGroupStats ) override; |
8059 | void testRunEnded( TestRunStats const& testRunStats ) override; |
8060 | |
8061 | void skipTest( TestCaseInfo const& testInfo ) override; |
8062 | bool isMulti() const override; |
8063 | |
8064 | }; |
8065 | |
8066 | } // end namespace Catch |
8067 | |
8068 | // end catch_reporter_listening.h |
8069 | namespace Catch { |
8070 | |
8071 | ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig ) |
8072 | : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} |
8073 | |
8074 | ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream ) |
8075 | : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} |
8076 | |
8077 | std::ostream& ReporterConfig::stream() const { return *m_stream; } |
8078 | IConfigPtr ReporterConfig::fullConfig() const { return m_fullConfig; } |
8079 | |
8080 | TestRunInfo::TestRunInfo( std::string const& _name ) : name( _name ) {} |
8081 | |
8082 | GroupInfo::GroupInfo( std::string const& _name, |
8083 | std::size_t _groupIndex, |
8084 | std::size_t _groupsCount ) |
8085 | : name( _name ), |
8086 | groupIndex( _groupIndex ), |
8087 | groupsCounts( _groupsCount ) |
8088 | {} |
8089 | |
8090 | AssertionStats::AssertionStats( AssertionResult const& _assertionResult, |
8091 | std::vector<MessageInfo> const& _infoMessages, |
8092 | Totals const& _totals ) |
8093 | : assertionResult( _assertionResult ), |
8094 | infoMessages( _infoMessages ), |
8095 | totals( _totals ) |
8096 | { |
8097 | assertionResult.m_resultData.lazyExpression.m_transientExpression = _assertionResult.m_resultData.lazyExpression.m_transientExpression; |
8098 | |
8099 | if( assertionResult.hasMessage() ) { |
8100 | // Copy message into messages list. |
8101 | // !TBD This should have been done earlier, somewhere |
8102 | MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); |
8103 | builder << assertionResult.getMessage(); |
8104 | builder.m_info.message = builder.m_stream.str(); |
8105 | |
8106 | infoMessages.push_back( builder.m_info ); |
8107 | } |
8108 | } |
8109 | |
8110 | AssertionStats::~AssertionStats() = default; |
8111 | |
8112 | SectionStats::SectionStats( SectionInfo const& _sectionInfo, |
8113 | Counts const& _assertions, |
8114 | double _durationInSeconds, |
8115 | bool _missingAssertions ) |
8116 | : sectionInfo( _sectionInfo ), |
8117 | assertions( _assertions ), |
8118 | durationInSeconds( _durationInSeconds ), |
8119 | missingAssertions( _missingAssertions ) |
8120 | {} |
8121 | |
8122 | SectionStats::~SectionStats() = default; |
8123 | |
8124 | TestCaseStats::TestCaseStats( TestCaseInfo const& _testInfo, |
8125 | Totals const& _totals, |
8126 | std::string const& _stdOut, |
8127 | std::string const& _stdErr, |
8128 | bool _aborting ) |
8129 | : testInfo( _testInfo ), |
8130 | totals( _totals ), |
8131 | stdOut( _stdOut ), |
8132 | stdErr( _stdErr ), |
8133 | aborting( _aborting ) |
8134 | {} |
8135 | |
8136 | TestCaseStats::~TestCaseStats() = default; |
8137 | |
8138 | TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo, |
8139 | Totals const& _totals, |
8140 | bool _aborting ) |
8141 | : groupInfo( _groupInfo ), |
8142 | totals( _totals ), |
8143 | aborting( _aborting ) |
8144 | {} |
8145 | |
8146 | TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo ) |
8147 | : groupInfo( _groupInfo ), |
8148 | aborting( false ) |
8149 | {} |
8150 | |
8151 | TestGroupStats::~TestGroupStats() = default; |
8152 | |
8153 | TestRunStats::TestRunStats( TestRunInfo const& _runInfo, |
8154 | Totals const& _totals, |
8155 | bool _aborting ) |
8156 | : runInfo( _runInfo ), |
8157 | totals( _totals ), |
8158 | aborting( _aborting ) |
8159 | {} |
8160 | |
8161 | TestRunStats::~TestRunStats() = default; |
8162 | |
8163 | void IStreamingReporter::fatalErrorEncountered( StringRef ) {} |
8164 | bool IStreamingReporter::isMulti() const { return false; } |
8165 | |
8166 | IReporterFactory::~IReporterFactory() = default; |
8167 | IReporterRegistry::~IReporterRegistry() = default; |
8168 | |
8169 | } // end namespace Catch |
8170 | // end catch_interfaces_reporter.cpp |
8171 | // start catch_interfaces_runner.cpp |
8172 | |
8173 | namespace Catch { |
8174 | IRunner::~IRunner() = default; |
8175 | } |
8176 | // end catch_interfaces_runner.cpp |
8177 | // start catch_interfaces_testcase.cpp |
8178 | |
8179 | namespace Catch { |
8180 | ITestInvoker::~ITestInvoker() = default; |
8181 | ITestCaseRegistry::~ITestCaseRegistry() = default; |
8182 | } |
8183 | // end catch_interfaces_testcase.cpp |
8184 | // start catch_leak_detector.cpp |
8185 | |
8186 | #ifdef CATCH_CONFIG_WINDOWS_CRTDBG |
8187 | #include <crtdbg.h> |
8188 | |
8189 | namespace Catch { |
8190 | |
8191 | LeakDetector::LeakDetector() { |
8192 | int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); |
8193 | flag |= _CRTDBG_LEAK_CHECK_DF; |
8194 | flag |= _CRTDBG_ALLOC_MEM_DF; |
8195 | _CrtSetDbgFlag(flag); |
8196 | _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); |
8197 | _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); |
8198 | // Change this to leaking allocation's number to break there |
8199 | _CrtSetBreakAlloc(-1); |
8200 | } |
8201 | } |
8202 | |
8203 | #else |
8204 | |
8205 | Catch::LeakDetector::LeakDetector() {} |
8206 | |
8207 | #endif |
8208 | // end catch_leak_detector.cpp |
8209 | // start catch_list.cpp |
8210 | |
8211 | // start catch_list.h |
8212 | |
8213 | #include <set> |
8214 | |
8215 | namespace Catch { |
8216 | |
8217 | std::size_t listTests( Config const& config ); |
8218 | |
8219 | std::size_t listTestsNamesOnly( Config const& config ); |
8220 | |
8221 | struct TagInfo { |
8222 | void add( std::string const& spelling ); |
8223 | std::string all() const; |
8224 | |
8225 | std::set<std::string> spellings; |
8226 | std::size_t count = 0; |
8227 | }; |
8228 | |
8229 | std::size_t listTags( Config const& config ); |
8230 | |
8231 | std::size_t listReporters( Config const& /*config*/ ); |
8232 | |
8233 | Option<std::size_t> list( Config const& config ); |
8234 | |
8235 | } // end namespace Catch |
8236 | |
8237 | // end catch_list.h |
8238 | // start catch_text.h |
8239 | |
8240 | namespace Catch { |
8241 | using namespace clara::TextFlow; |
8242 | } |
8243 | |
8244 | // end catch_text.h |
8245 | #include <limits> |
8246 | #include <algorithm> |
8247 | #include <iomanip> |
8248 | |
8249 | namespace Catch { |
8250 | |
8251 | std::size_t listTests( Config const& config ) { |
8252 | TestSpec testSpec = config.testSpec(); |
8253 | if( config.hasTestFilters() ) |
8254 | Catch::cout() << "Matching test cases:\n" ; |
8255 | else { |
8256 | Catch::cout() << "All available test cases:\n" ; |
8257 | } |
8258 | |
8259 | auto matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); |
8260 | for( auto const& testCaseInfo : matchedTestCases ) { |
8261 | Colour::Code colour = testCaseInfo.isHidden() |
8262 | ? Colour::SecondaryText |
8263 | : Colour::None; |
8264 | Colour colourGuard( colour ); |
8265 | |
8266 | Catch::cout() << Column( testCaseInfo.name ).initialIndent( 2 ).indent( 4 ) << "\n" ; |
8267 | if( config.verbosity() >= Verbosity::High ) { |
8268 | Catch::cout() << Column( Catch::Detail::stringify( testCaseInfo.lineInfo ) ).indent(4) << std::endl; |
8269 | std::string description = testCaseInfo.description; |
8270 | if( description.empty() ) |
8271 | description = "(NO DESCRIPTION)" ; |
8272 | Catch::cout() << Column( description ).indent(4) << std::endl; |
8273 | } |
8274 | if( !testCaseInfo.tags.empty() ) |
8275 | Catch::cout() << Column( testCaseInfo.tagsAsString() ).indent( 6 ) << "\n" ; |
8276 | } |
8277 | |
8278 | if( !config.hasTestFilters() ) |
8279 | Catch::cout() << pluralise( matchedTestCases.size(), "test case" ) << '\n' << std::endl; |
8280 | else |
8281 | Catch::cout() << pluralise( matchedTestCases.size(), "matching test case" ) << '\n' << std::endl; |
8282 | return matchedTestCases.size(); |
8283 | } |
8284 | |
8285 | std::size_t listTestsNamesOnly( Config const& config ) { |
8286 | TestSpec testSpec = config.testSpec(); |
8287 | std::size_t matchedTests = 0; |
8288 | std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); |
8289 | for( auto const& testCaseInfo : matchedTestCases ) { |
8290 | matchedTests++; |
8291 | if( startsWith( testCaseInfo.name, '#' ) ) |
8292 | Catch::cout() << '"' << testCaseInfo.name << '"'; |
8293 | else |
8294 | Catch::cout() << testCaseInfo.name; |
8295 | if ( config.verbosity() >= Verbosity::High ) |
8296 | Catch::cout() << "\t@" << testCaseInfo.lineInfo; |
8297 | Catch::cout() << std::endl; |
8298 | } |
8299 | return matchedTests; |
8300 | } |
8301 | |
8302 | void TagInfo::add( std::string const& spelling ) { |
8303 | ++count; |
8304 | spellings.insert( spelling ); |
8305 | } |
8306 | |
8307 | std::string TagInfo::all() const { |
8308 | std::string out; |
8309 | for( auto const& spelling : spellings ) |
8310 | out += "[" + spelling + "]" ; |
8311 | return out; |
8312 | } |
8313 | |
8314 | std::size_t listTags( Config const& config ) { |
8315 | TestSpec testSpec = config.testSpec(); |
8316 | if( config.hasTestFilters() ) |
8317 | Catch::cout() << "Tags for matching test cases:\n" ; |
8318 | else { |
8319 | Catch::cout() << "All available tags:\n" ; |
8320 | } |
8321 | |
8322 | std::map<std::string, TagInfo> tagCounts; |
8323 | |
8324 | std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); |
8325 | for( auto const& testCase : matchedTestCases ) { |
8326 | for( auto const& tagName : testCase.getTestCaseInfo().tags ) { |
8327 | std::string lcaseTagName = toLower( tagName ); |
8328 | auto countIt = tagCounts.find( lcaseTagName ); |
8329 | if( countIt == tagCounts.end() ) |
8330 | countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; |
8331 | countIt->second.add( tagName ); |
8332 | } |
8333 | } |
8334 | |
8335 | for( auto const& tagCount : tagCounts ) { |
8336 | ReusableStringStream ; |
8337 | rss << " " << std::setw(2) << tagCount.second.count << " " ; |
8338 | auto str = rss.str(); |
8339 | auto wrapper = Column( tagCount.second.all() ) |
8340 | .initialIndent( 0 ) |
8341 | .indent( str.size() ) |
8342 | .width( CATCH_CONFIG_CONSOLE_WIDTH-10 ); |
8343 | Catch::cout() << str << wrapper << '\n'; |
8344 | } |
8345 | Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl; |
8346 | return tagCounts.size(); |
8347 | } |
8348 | |
8349 | std::size_t listReporters( Config const& /*config*/ ) { |
8350 | Catch::cout() << "Available reporters:\n" ; |
8351 | IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); |
8352 | std::size_t maxNameLen = 0; |
8353 | for( auto const& factoryKvp : factories ) |
8354 | maxNameLen = (std::max)( maxNameLen, factoryKvp.first.size() ); |
8355 | |
8356 | for( auto const& factoryKvp : factories ) { |
8357 | Catch::cout() |
8358 | << Column( factoryKvp.first + ":" ) |
8359 | .indent(2) |
8360 | .width( 5+maxNameLen ) |
8361 | + Column( factoryKvp.second->getDescription() ) |
8362 | .initialIndent(0) |
8363 | .indent(2) |
8364 | .width( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) |
8365 | << "\n" ; |
8366 | } |
8367 | Catch::cout() << std::endl; |
8368 | return factories.size(); |
8369 | } |
8370 | |
8371 | Option<std::size_t> list( Config const& config ) { |
8372 | Option<std::size_t> listedCount; |
8373 | if( config.listTests() ) |
8374 | listedCount = listedCount.valueOr(0) + listTests( config ); |
8375 | if( config.listTestNamesOnly() ) |
8376 | listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config ); |
8377 | if( config.listTags() ) |
8378 | listedCount = listedCount.valueOr(0) + listTags( config ); |
8379 | if( config.listReporters() ) |
8380 | listedCount = listedCount.valueOr(0) + listReporters( config ); |
8381 | return listedCount; |
8382 | } |
8383 | |
8384 | } // end namespace Catch |
8385 | // end catch_list.cpp |
8386 | // start catch_matchers.cpp |
8387 | |
8388 | namespace Catch { |
8389 | namespace Matchers { |
8390 | namespace Impl { |
8391 | |
8392 | std::string MatcherUntypedBase::toString() const { |
8393 | if( m_cachedToString.empty() ) |
8394 | m_cachedToString = describe(); |
8395 | return m_cachedToString; |
8396 | } |
8397 | |
8398 | MatcherUntypedBase::~MatcherUntypedBase() = default; |
8399 | |
8400 | } // namespace Impl |
8401 | } // namespace Matchers |
8402 | |
8403 | using namespace Matchers; |
8404 | using Matchers::Impl::MatcherBase; |
8405 | |
8406 | } // namespace Catch |
8407 | // end catch_matchers.cpp |
8408 | // start catch_matchers_floating.cpp |
8409 | |
8410 | // start catch_to_string.hpp |
8411 | |
8412 | #include <string> |
8413 | |
8414 | namespace Catch { |
8415 | template <typename T> |
8416 | std::string to_string(T const& t) { |
8417 | #if defined(CATCH_CONFIG_CPP11_TO_STRING) |
8418 | return std::to_string(t); |
8419 | #else |
8420 | ReusableStringStream rss; |
8421 | rss << t; |
8422 | return rss.str(); |
8423 | #endif |
8424 | } |
8425 | } // end namespace Catch |
8426 | |
8427 | // end catch_to_string.hpp |
8428 | #include <cstdlib> |
8429 | #include <cstdint> |
8430 | #include <cstring> |
8431 | |
8432 | namespace Catch { |
8433 | namespace Matchers { |
8434 | namespace Floating { |
8435 | enum class FloatingPointKind : uint8_t { |
8436 | Float, |
8437 | Double |
8438 | }; |
8439 | } |
8440 | } |
8441 | } |
8442 | |
8443 | namespace { |
8444 | |
8445 | template <typename T> |
8446 | struct Converter; |
8447 | |
8448 | template <> |
8449 | struct Converter<float> { |
8450 | static_assert(sizeof(float) == sizeof(int32_t), "Important ULP matcher assumption violated" ); |
8451 | Converter(float f) { |
8452 | std::memcpy(&i, &f, sizeof(f)); |
8453 | } |
8454 | int32_t i; |
8455 | }; |
8456 | |
8457 | template <> |
8458 | struct Converter<double> { |
8459 | static_assert(sizeof(double) == sizeof(int64_t), "Important ULP matcher assumption violated" ); |
8460 | Converter(double d) { |
8461 | std::memcpy(&i, &d, sizeof(d)); |
8462 | } |
8463 | int64_t i; |
8464 | }; |
8465 | |
8466 | template <typename T> |
8467 | auto convert(T t) -> Converter<T> { |
8468 | return Converter<T>(t); |
8469 | } |
8470 | |
8471 | template <typename FP> |
8472 | bool almostEqualUlps(FP lhs, FP rhs, int maxUlpDiff) { |
8473 | // Comparison with NaN should always be false. |
8474 | // This way we can rule it out before getting into the ugly details |
8475 | if (std::isnan(lhs) || std::isnan(rhs)) { |
8476 | return false; |
8477 | } |
8478 | |
8479 | auto lc = convert(lhs); |
8480 | auto rc = convert(rhs); |
8481 | |
8482 | if ((lc.i < 0) != (rc.i < 0)) { |
8483 | // Potentially we can have +0 and -0 |
8484 | return lhs == rhs; |
8485 | } |
8486 | |
8487 | auto ulpDiff = std::abs(lc.i - rc.i); |
8488 | return ulpDiff <= maxUlpDiff; |
8489 | } |
8490 | |
8491 | } |
8492 | |
8493 | namespace Catch { |
8494 | namespace Matchers { |
8495 | namespace Floating { |
8496 | WithinAbsMatcher::WithinAbsMatcher(double target, double margin) |
8497 | :m_target{ target }, m_margin{ margin } { |
8498 | CATCH_ENFORCE(margin >= 0, "Invalid margin: " << margin << '.' |
8499 | << " Margin has to be non-negative." ); |
8500 | } |
8501 | |
8502 | // Performs equivalent check of std::fabs(lhs - rhs) <= margin |
8503 | // But without the subtraction to allow for INFINITY in comparison |
8504 | bool WithinAbsMatcher::match(double const& matchee) const { |
8505 | return (matchee + m_margin >= m_target) && (m_target + m_margin >= matchee); |
8506 | } |
8507 | |
8508 | std::string WithinAbsMatcher::describe() const { |
8509 | return "is within " + ::Catch::Detail::stringify(m_margin) + " of " + ::Catch::Detail::stringify(m_target); |
8510 | } |
8511 | |
8512 | WithinUlpsMatcher::WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType) |
8513 | :m_target{ target }, m_ulps{ ulps }, m_type{ baseType } { |
8514 | CATCH_ENFORCE(ulps >= 0, "Invalid ULP setting: " << ulps << '.' |
8515 | << " ULPs have to be non-negative." ); |
8516 | } |
8517 | |
8518 | #if defined(__clang__) |
8519 | #pragma clang diagnostic push |
8520 | // Clang <3.5 reports on the default branch in the switch below |
8521 | #pragma clang diagnostic ignored "-Wunreachable-code" |
8522 | #endif |
8523 | |
8524 | bool WithinUlpsMatcher::match(double const& matchee) const { |
8525 | switch (m_type) { |
8526 | case FloatingPointKind::Float: |
8527 | return almostEqualUlps<float>(static_cast<float>(matchee), static_cast<float>(m_target), m_ulps); |
8528 | case FloatingPointKind::Double: |
8529 | return almostEqualUlps<double>(matchee, m_target, m_ulps); |
8530 | default: |
8531 | CATCH_INTERNAL_ERROR( "Unknown FloatingPointKind value" ); |
8532 | } |
8533 | } |
8534 | |
8535 | #if defined(__clang__) |
8536 | #pragma clang diagnostic pop |
8537 | #endif |
8538 | |
8539 | std::string WithinUlpsMatcher::describe() const { |
8540 | return "is within " + Catch::to_string(m_ulps) + " ULPs of " + ::Catch::Detail::stringify(m_target) + ((m_type == FloatingPointKind::Float)? "f" : "" ); |
8541 | } |
8542 | |
8543 | }// namespace Floating |
8544 | |
8545 | Floating::WithinUlpsMatcher WithinULP(double target, int maxUlpDiff) { |
8546 | return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Double); |
8547 | } |
8548 | |
8549 | Floating::WithinUlpsMatcher WithinULP(float target, int maxUlpDiff) { |
8550 | return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Float); |
8551 | } |
8552 | |
8553 | Floating::WithinAbsMatcher WithinAbs(double target, double margin) { |
8554 | return Floating::WithinAbsMatcher(target, margin); |
8555 | } |
8556 | |
8557 | } // namespace Matchers |
8558 | } // namespace Catch |
8559 | |
8560 | // end catch_matchers_floating.cpp |
8561 | // start catch_matchers_generic.cpp |
8562 | |
8563 | std::string Catch::Matchers::Generic::Detail::finalizeDescription(const std::string& desc) { |
8564 | if (desc.empty()) { |
8565 | return "matches undescribed predicate" ; |
8566 | } else { |
8567 | return "matches predicate: \"" + desc + '"'; |
8568 | } |
8569 | } |
8570 | // end catch_matchers_generic.cpp |
8571 | // start catch_matchers_string.cpp |
8572 | |
8573 | #include <regex> |
8574 | |
8575 | namespace Catch { |
8576 | namespace Matchers { |
8577 | |
8578 | namespace StdString { |
8579 | |
8580 | CasedString::CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ) |
8581 | : m_caseSensitivity( caseSensitivity ), |
8582 | m_str( adjustString( str ) ) |
8583 | {} |
8584 | std::string CasedString::adjustString( std::string const& str ) const { |
8585 | return m_caseSensitivity == CaseSensitive::No |
8586 | ? toLower( str ) |
8587 | : str; |
8588 | } |
8589 | std::string CasedString::caseSensitivitySuffix() const { |
8590 | return m_caseSensitivity == CaseSensitive::No |
8591 | ? " (case insensitive)" |
8592 | : std::string(); |
8593 | } |
8594 | |
8595 | StringMatcherBase::StringMatcherBase( std::string const& operation, CasedString const& comparator ) |
8596 | : m_comparator( comparator ), |
8597 | m_operation( operation ) { |
8598 | } |
8599 | |
8600 | std::string StringMatcherBase::describe() const { |
8601 | std::string description; |
8602 | description.reserve(5 + m_operation.size() + m_comparator.m_str.size() + |
8603 | m_comparator.caseSensitivitySuffix().size()); |
8604 | description += m_operation; |
8605 | description += ": \"" ; |
8606 | description += m_comparator.m_str; |
8607 | description += "\"" ; |
8608 | description += m_comparator.caseSensitivitySuffix(); |
8609 | return description; |
8610 | } |
8611 | |
8612 | EqualsMatcher::EqualsMatcher( CasedString const& comparator ) : StringMatcherBase( "equals" , comparator ) {} |
8613 | |
8614 | bool EqualsMatcher::match( std::string const& source ) const { |
8615 | return m_comparator.adjustString( source ) == m_comparator.m_str; |
8616 | } |
8617 | |
8618 | ContainsMatcher::ContainsMatcher( CasedString const& comparator ) : StringMatcherBase( "contains" , comparator ) {} |
8619 | |
8620 | bool ContainsMatcher::match( std::string const& source ) const { |
8621 | return contains( m_comparator.adjustString( source ), m_comparator.m_str ); |
8622 | } |
8623 | |
8624 | StartsWithMatcher::StartsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "starts with" , comparator ) {} |
8625 | |
8626 | bool StartsWithMatcher::match( std::string const& source ) const { |
8627 | return startsWith( m_comparator.adjustString( source ), m_comparator.m_str ); |
8628 | } |
8629 | |
8630 | EndsWithMatcher::EndsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "ends with" , comparator ) {} |
8631 | |
8632 | bool EndsWithMatcher::match( std::string const& source ) const { |
8633 | return endsWith( m_comparator.adjustString( source ), m_comparator.m_str ); |
8634 | } |
8635 | |
8636 | RegexMatcher::RegexMatcher(std::string regex, CaseSensitive::Choice caseSensitivity): m_regex(std::move(regex)), m_caseSensitivity(caseSensitivity) {} |
8637 | |
8638 | bool RegexMatcher::match(std::string const& matchee) const { |
8639 | auto flags = std::regex::ECMAScript; // ECMAScript is the default syntax option anyway |
8640 | if (m_caseSensitivity == CaseSensitive::Choice::No) { |
8641 | flags |= std::regex::icase; |
8642 | } |
8643 | auto reg = std::regex(m_regex, flags); |
8644 | return std::regex_match(matchee, reg); |
8645 | } |
8646 | |
8647 | std::string RegexMatcher::describe() const { |
8648 | return "matches " + ::Catch::Detail::stringify(m_regex) + ((m_caseSensitivity == CaseSensitive::Choice::Yes)? " case sensitively" : " case insensitively" ); |
8649 | } |
8650 | |
8651 | } // namespace StdString |
8652 | |
8653 | StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity ) { |
8654 | return StdString::EqualsMatcher( StdString::CasedString( str, caseSensitivity) ); |
8655 | } |
8656 | StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity ) { |
8657 | return StdString::ContainsMatcher( StdString::CasedString( str, caseSensitivity) ); |
8658 | } |
8659 | StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) { |
8660 | return StdString::EndsWithMatcher( StdString::CasedString( str, caseSensitivity) ); |
8661 | } |
8662 | StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) { |
8663 | return StdString::StartsWithMatcher( StdString::CasedString( str, caseSensitivity) ); |
8664 | } |
8665 | |
8666 | StdString::RegexMatcher Matches(std::string const& regex, CaseSensitive::Choice caseSensitivity) { |
8667 | return StdString::RegexMatcher(regex, caseSensitivity); |
8668 | } |
8669 | |
8670 | } // namespace Matchers |
8671 | } // namespace Catch |
8672 | // end catch_matchers_string.cpp |
8673 | // start catch_message.cpp |
8674 | |
8675 | // start catch_uncaught_exceptions.h |
8676 | |
8677 | namespace Catch { |
8678 | bool uncaught_exceptions(); |
8679 | } // end namespace Catch |
8680 | |
8681 | // end catch_uncaught_exceptions.h |
8682 | #include <cassert> |
8683 | |
8684 | namespace Catch { |
8685 | |
8686 | MessageInfo::MessageInfo( StringRef const& _macroName, |
8687 | SourceLineInfo const& _lineInfo, |
8688 | ResultWas::OfType _type ) |
8689 | : macroName( _macroName ), |
8690 | lineInfo( _lineInfo ), |
8691 | type( _type ), |
8692 | sequence( ++globalCount ) |
8693 | {} |
8694 | |
8695 | bool MessageInfo::operator==( MessageInfo const& other ) const { |
8696 | return sequence == other.sequence; |
8697 | } |
8698 | |
8699 | bool MessageInfo::operator<( MessageInfo const& other ) const { |
8700 | return sequence < other.sequence; |
8701 | } |
8702 | |
8703 | // This may need protecting if threading support is added |
8704 | unsigned int MessageInfo::globalCount = 0; |
8705 | |
8706 | //////////////////////////////////////////////////////////////////////////// |
8707 | |
8708 | Catch::MessageBuilder::MessageBuilder( StringRef const& macroName, |
8709 | SourceLineInfo const& lineInfo, |
8710 | ResultWas::OfType type ) |
8711 | :m_info(macroName, lineInfo, type) {} |
8712 | |
8713 | //////////////////////////////////////////////////////////////////////////// |
8714 | |
8715 | ScopedMessage::ScopedMessage( MessageBuilder const& builder ) |
8716 | : m_info( builder.m_info ) |
8717 | { |
8718 | m_info.message = builder.m_stream.str(); |
8719 | getResultCapture().pushScopedMessage( m_info ); |
8720 | } |
8721 | |
8722 | ScopedMessage::~ScopedMessage() { |
8723 | if ( !uncaught_exceptions() ){ |
8724 | getResultCapture().popScopedMessage(m_info); |
8725 | } |
8726 | } |
8727 | |
8728 | Capturer::Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ) { |
8729 | auto start = std::string::npos; |
8730 | for( size_t pos = 0; pos <= names.size(); ++pos ) { |
8731 | char c = names[pos]; |
8732 | if( pos == names.size() || c == ' ' || c == '\t' || c == ',' || c == ']' ) { |
8733 | if( start != std::string::npos ) { |
8734 | m_messages.push_back( MessageInfo( macroName, lineInfo, resultType ) ); |
8735 | m_messages.back().message = names.substr( start, pos-start) + " := " ; |
8736 | start = std::string::npos; |
8737 | } |
8738 | } |
8739 | else if( c != '[' && c != ']' && start == std::string::npos ) |
8740 | start = pos; |
8741 | } |
8742 | } |
8743 | Capturer::~Capturer() { |
8744 | if ( !uncaught_exceptions() ){ |
8745 | assert( m_captured == m_messages.size() ); |
8746 | for( size_t i = 0; i < m_captured; ++i ) |
8747 | m_resultCapture.popScopedMessage( m_messages[i] ); |
8748 | } |
8749 | } |
8750 | |
8751 | void Capturer::captureValue( size_t index, StringRef value ) { |
8752 | assert( index < m_messages.size() ); |
8753 | m_messages[index].message += value; |
8754 | m_resultCapture.pushScopedMessage( m_messages[index] ); |
8755 | m_captured++; |
8756 | } |
8757 | |
8758 | } // end namespace Catch |
8759 | // end catch_message.cpp |
8760 | // start catch_output_redirect.cpp |
8761 | |
8762 | // start catch_output_redirect.h |
8763 | #ifndef TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H |
8764 | #define TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H |
8765 | |
8766 | #include <cstdio> |
8767 | #include <iosfwd> |
8768 | #include <string> |
8769 | |
8770 | namespace Catch { |
8771 | |
8772 | class RedirectedStream { |
8773 | std::ostream& m_originalStream; |
8774 | std::ostream& m_redirectionStream; |
8775 | std::streambuf* m_prevBuf; |
8776 | |
8777 | public: |
8778 | RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream ); |
8779 | ~RedirectedStream(); |
8780 | }; |
8781 | |
8782 | class RedirectedStdOut { |
8783 | ReusableStringStream ; |
8784 | RedirectedStream m_cout; |
8785 | public: |
8786 | RedirectedStdOut(); |
8787 | auto str() const -> std::string; |
8788 | }; |
8789 | |
8790 | // StdErr has two constituent streams in C++, std::cerr and std::clog |
8791 | // This means that we need to redirect 2 streams into 1 to keep proper |
8792 | // order of writes |
8793 | class RedirectedStdErr { |
8794 | ReusableStringStream ; |
8795 | RedirectedStream m_cerr; |
8796 | RedirectedStream m_clog; |
8797 | public: |
8798 | RedirectedStdErr(); |
8799 | auto str() const -> std::string; |
8800 | }; |
8801 | |
8802 | #if defined(CATCH_CONFIG_NEW_CAPTURE) |
8803 | |
8804 | // Windows's implementation of std::tmpfile is terrible (it tries |
8805 | // to create a file inside system folder, thus requiring elevated |
8806 | // privileges for the binary), so we have to use tmpnam(_s) and |
8807 | // create the file ourselves there. |
8808 | class TempFile { |
8809 | public: |
8810 | TempFile(TempFile const&) = delete; |
8811 | TempFile& operator=(TempFile const&) = delete; |
8812 | TempFile(TempFile&&) = delete; |
8813 | TempFile& operator=(TempFile&&) = delete; |
8814 | |
8815 | TempFile(); |
8816 | ~TempFile(); |
8817 | |
8818 | std::FILE* getFile(); |
8819 | std::string getContents(); |
8820 | |
8821 | private: |
8822 | std::FILE* m_file = nullptr; |
8823 | #if defined(_MSC_VER) |
8824 | char m_buffer[L_tmpnam] = { 0 }; |
8825 | #endif |
8826 | }; |
8827 | |
8828 | class OutputRedirect { |
8829 | public: |
8830 | OutputRedirect(OutputRedirect const&) = delete; |
8831 | OutputRedirect& operator=(OutputRedirect const&) = delete; |
8832 | OutputRedirect(OutputRedirect&&) = delete; |
8833 | OutputRedirect& operator=(OutputRedirect&&) = delete; |
8834 | |
8835 | OutputRedirect(std::string& stdout_dest, std::string& stderr_dest); |
8836 | ~OutputRedirect(); |
8837 | |
8838 | private: |
8839 | int m_originalStdout = -1; |
8840 | int m_originalStderr = -1; |
8841 | TempFile m_stdoutFile; |
8842 | TempFile m_stderrFile; |
8843 | std::string& m_stdoutDest; |
8844 | std::string& m_stderrDest; |
8845 | }; |
8846 | |
8847 | #endif |
8848 | |
8849 | } // end namespace Catch |
8850 | |
8851 | #endif // TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H |
8852 | // end catch_output_redirect.h |
8853 | #include <cstdio> |
8854 | #include <cstring> |
8855 | #include <fstream> |
8856 | #include <sstream> |
8857 | #include <stdexcept> |
8858 | |
8859 | #if defined(CATCH_CONFIG_NEW_CAPTURE) |
8860 | #if defined(_MSC_VER) |
8861 | #include <io.h> //_dup and _dup2 |
8862 | #define dup _dup |
8863 | #define dup2 _dup2 |
8864 | #define fileno _fileno |
8865 | #else |
8866 | #include <unistd.h> // dup and dup2 |
8867 | #endif |
8868 | #endif |
8869 | |
8870 | namespace Catch { |
8871 | |
8872 | RedirectedStream::RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream ) |
8873 | : m_originalStream( originalStream ), |
8874 | m_redirectionStream( redirectionStream ), |
8875 | m_prevBuf( m_originalStream.rdbuf() ) |
8876 | { |
8877 | m_originalStream.rdbuf( m_redirectionStream.rdbuf() ); |
8878 | } |
8879 | |
8880 | RedirectedStream::~RedirectedStream() { |
8881 | m_originalStream.rdbuf( m_prevBuf ); |
8882 | } |
8883 | |
8884 | RedirectedStdOut::RedirectedStdOut() : m_cout( Catch::cout(), m_rss.get() ) {} |
8885 | auto RedirectedStdOut::str() const -> std::string { return m_rss.str(); } |
8886 | |
8887 | RedirectedStdErr::RedirectedStdErr() |
8888 | : m_cerr( Catch::cerr(), m_rss.get() ), |
8889 | m_clog( Catch::clog(), m_rss.get() ) |
8890 | {} |
8891 | auto RedirectedStdErr::str() const -> std::string { return m_rss.str(); } |
8892 | |
8893 | #if defined(CATCH_CONFIG_NEW_CAPTURE) |
8894 | |
8895 | #if defined(_MSC_VER) |
8896 | TempFile::TempFile() { |
8897 | if (tmpnam_s(m_buffer)) { |
8898 | CATCH_RUNTIME_ERROR("Could not get a temp filename" ); |
8899 | } |
8900 | if (fopen_s(&m_file, m_buffer, "w" )) { |
8901 | char buffer[100]; |
8902 | if (strerror_s(buffer, errno)) { |
8903 | CATCH_RUNTIME_ERROR("Could not translate errno to a string" ); |
8904 | } |
8905 | CATCH_RUNTIME_ERROR("Coul dnot open the temp file: '" << m_buffer << "' because: " << buffer); |
8906 | } |
8907 | } |
8908 | #else |
8909 | TempFile::TempFile() { |
8910 | m_file = std::tmpfile(); |
8911 | if (!m_file) { |
8912 | CATCH_RUNTIME_ERROR("Could not create a temp file." ); |
8913 | } |
8914 | } |
8915 | |
8916 | #endif |
8917 | |
8918 | TempFile::~TempFile() { |
8919 | // TBD: What to do about errors here? |
8920 | std::fclose(m_file); |
8921 | // We manually create the file on Windows only, on Linux |
8922 | // it will be autodeleted |
8923 | #if defined(_MSC_VER) |
8924 | std::remove(m_buffer); |
8925 | #endif |
8926 | } |
8927 | |
8928 | FILE* TempFile::getFile() { |
8929 | return m_file; |
8930 | } |
8931 | |
8932 | std::string TempFile::getContents() { |
8933 | std::stringstream sstr; |
8934 | char buffer[100] = {}; |
8935 | std::rewind(m_file); |
8936 | while (std::fgets(buffer, sizeof(buffer), m_file)) { |
8937 | sstr << buffer; |
8938 | } |
8939 | return sstr.str(); |
8940 | } |
8941 | |
8942 | OutputRedirect::OutputRedirect(std::string& stdout_dest, std::string& stderr_dest) : |
8943 | m_originalStdout(dup(1)), |
8944 | m_originalStderr(dup(2)), |
8945 | m_stdoutDest(stdout_dest), |
8946 | m_stderrDest(stderr_dest) { |
8947 | dup2(fileno(m_stdoutFile.getFile()), 1); |
8948 | dup2(fileno(m_stderrFile.getFile()), 2); |
8949 | } |
8950 | |
8951 | OutputRedirect::~OutputRedirect() { |
8952 | Catch::cout() << std::flush; |
8953 | fflush(stdout); |
8954 | // Since we support overriding these streams, we flush cerr |
8955 | // even though std::cerr is unbuffered |
8956 | Catch::cerr() << std::flush; |
8957 | Catch::clog() << std::flush; |
8958 | fflush(stderr); |
8959 | |
8960 | dup2(m_originalStdout, 1); |
8961 | dup2(m_originalStderr, 2); |
8962 | |
8963 | m_stdoutDest += m_stdoutFile.getContents(); |
8964 | m_stderrDest += m_stderrFile.getContents(); |
8965 | } |
8966 | |
8967 | #endif // CATCH_CONFIG_NEW_CAPTURE |
8968 | |
8969 | } // namespace Catch |
8970 | |
8971 | #if defined(CATCH_CONFIG_NEW_CAPTURE) |
8972 | #if defined(_MSC_VER) |
8973 | #undef dup |
8974 | #undef dup2 |
8975 | #undef fileno |
8976 | #endif |
8977 | #endif |
8978 | // end catch_output_redirect.cpp |
8979 | // start catch_random_number_generator.cpp |
8980 | |
8981 | namespace Catch { |
8982 | |
8983 | std::mt19937& rng() { |
8984 | static std::mt19937 s_rng; |
8985 | return s_rng; |
8986 | } |
8987 | |
8988 | void seedRng( IConfig const& config ) { |
8989 | if( config.rngSeed() != 0 ) { |
8990 | std::srand( config.rngSeed() ); |
8991 | rng().seed( config.rngSeed() ); |
8992 | } |
8993 | } |
8994 | |
8995 | unsigned int rngSeed() { |
8996 | return getCurrentContext().getConfig()->rngSeed(); |
8997 | } |
8998 | } |
8999 | // end catch_random_number_generator.cpp |
9000 | // start catch_registry_hub.cpp |
9001 | |
9002 | // start catch_test_case_registry_impl.h |
9003 | |
9004 | #include <vector> |
9005 | #include <set> |
9006 | #include <algorithm> |
9007 | #include <ios> |
9008 | |
9009 | namespace Catch { |
9010 | |
9011 | class TestCase; |
9012 | struct IConfig; |
9013 | |
9014 | std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ); |
9015 | bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); |
9016 | |
9017 | void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions ); |
9018 | |
9019 | std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ); |
9020 | std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ); |
9021 | |
9022 | class TestRegistry : public ITestCaseRegistry { |
9023 | public: |
9024 | virtual ~TestRegistry() = default; |
9025 | |
9026 | virtual void registerTest( TestCase const& testCase ); |
9027 | |
9028 | std::vector<TestCase> const& getAllTests() const override; |
9029 | std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const override; |
9030 | |
9031 | private: |
9032 | std::vector<TestCase> m_functions; |
9033 | mutable RunTests::InWhatOrder m_currentSortOrder = RunTests::InDeclarationOrder; |
9034 | mutable std::vector<TestCase> m_sortedFunctions; |
9035 | std::size_t m_unnamedCount = 0; |
9036 | std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised |
9037 | }; |
9038 | |
9039 | /////////////////////////////////////////////////////////////////////////// |
9040 | |
9041 | class TestInvokerAsFunction : public ITestInvoker { |
9042 | void(*m_testAsFunction)(); |
9043 | public: |
9044 | TestInvokerAsFunction( void(*testAsFunction)() ) noexcept; |
9045 | |
9046 | void invoke() const override; |
9047 | }; |
9048 | |
9049 | std::string extractClassName( StringRef const& classOrQualifiedMethodName ); |
9050 | |
9051 | /////////////////////////////////////////////////////////////////////////// |
9052 | |
9053 | } // end namespace Catch |
9054 | |
9055 | // end catch_test_case_registry_impl.h |
9056 | // start catch_reporter_registry.h |
9057 | |
9058 | #include <map> |
9059 | |
9060 | namespace Catch { |
9061 | |
9062 | class ReporterRegistry : public IReporterRegistry { |
9063 | |
9064 | public: |
9065 | |
9066 | ~ReporterRegistry() override; |
9067 | |
9068 | IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const override; |
9069 | |
9070 | void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ); |
9071 | void registerListener( IReporterFactoryPtr const& factory ); |
9072 | |
9073 | FactoryMap const& getFactories() const override; |
9074 | Listeners const& getListeners() const override; |
9075 | |
9076 | private: |
9077 | FactoryMap m_factories; |
9078 | Listeners m_listeners; |
9079 | }; |
9080 | } |
9081 | |
9082 | // end catch_reporter_registry.h |
9083 | // start catch_tag_alias_registry.h |
9084 | |
9085 | // start catch_tag_alias.h |
9086 | |
9087 | #include <string> |
9088 | |
9089 | namespace Catch { |
9090 | |
9091 | struct TagAlias { |
9092 | TagAlias(std::string const& _tag, SourceLineInfo _lineInfo); |
9093 | |
9094 | std::string tag; |
9095 | SourceLineInfo lineInfo; |
9096 | }; |
9097 | |
9098 | } // end namespace Catch |
9099 | |
9100 | // end catch_tag_alias.h |
9101 | #include <map> |
9102 | |
9103 | namespace Catch { |
9104 | |
9105 | class TagAliasRegistry : public ITagAliasRegistry { |
9106 | public: |
9107 | ~TagAliasRegistry() override; |
9108 | TagAlias const* find( std::string const& alias ) const override; |
9109 | std::string expandAliases( std::string const& unexpandedTestSpec ) const override; |
9110 | void add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ); |
9111 | |
9112 | private: |
9113 | std::map<std::string, TagAlias> m_registry; |
9114 | }; |
9115 | |
9116 | } // end namespace Catch |
9117 | |
9118 | // end catch_tag_alias_registry.h |
9119 | // start catch_startup_exception_registry.h |
9120 | |
9121 | #include <vector> |
9122 | #include <exception> |
9123 | |
9124 | namespace Catch { |
9125 | |
9126 | class StartupExceptionRegistry { |
9127 | public: |
9128 | void add(std::exception_ptr const& exception) noexcept; |
9129 | std::vector<std::exception_ptr> const& getExceptions() const noexcept; |
9130 | private: |
9131 | std::vector<std::exception_ptr> m_exceptions; |
9132 | }; |
9133 | |
9134 | } // end namespace Catch |
9135 | |
9136 | // end catch_startup_exception_registry.h |
9137 | // start catch_singletons.hpp |
9138 | |
9139 | namespace Catch { |
9140 | |
9141 | struct ISingleton { |
9142 | virtual ~ISingleton(); |
9143 | }; |
9144 | |
9145 | void addSingleton( ISingleton* singleton ); |
9146 | void cleanupSingletons(); |
9147 | |
9148 | template<typename SingletonImplT, typename InterfaceT = SingletonImplT, typename MutableInterfaceT = InterfaceT> |
9149 | class Singleton : SingletonImplT, public ISingleton { |
9150 | |
9151 | static auto getInternal() -> Singleton* { |
9152 | static Singleton* s_instance = nullptr; |
9153 | if( !s_instance ) { |
9154 | s_instance = new Singleton; |
9155 | addSingleton( s_instance ); |
9156 | } |
9157 | return s_instance; |
9158 | } |
9159 | |
9160 | public: |
9161 | static auto get() -> InterfaceT const& { |
9162 | return *getInternal(); |
9163 | } |
9164 | static auto getMutable() -> MutableInterfaceT& { |
9165 | return *getInternal(); |
9166 | } |
9167 | }; |
9168 | |
9169 | } // namespace Catch |
9170 | |
9171 | // end catch_singletons.hpp |
9172 | namespace Catch { |
9173 | |
9174 | namespace { |
9175 | |
9176 | class RegistryHub : public IRegistryHub, public IMutableRegistryHub, |
9177 | private NonCopyable { |
9178 | |
9179 | public: // IRegistryHub |
9180 | RegistryHub() = default; |
9181 | IReporterRegistry const& getReporterRegistry() const override { |
9182 | return m_reporterRegistry; |
9183 | } |
9184 | ITestCaseRegistry const& getTestCaseRegistry() const override { |
9185 | return m_testCaseRegistry; |
9186 | } |
9187 | IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const override { |
9188 | return m_exceptionTranslatorRegistry; |
9189 | } |
9190 | ITagAliasRegistry const& getTagAliasRegistry() const override { |
9191 | return m_tagAliasRegistry; |
9192 | } |
9193 | StartupExceptionRegistry const& getStartupExceptionRegistry() const override { |
9194 | return m_exceptionRegistry; |
9195 | } |
9196 | |
9197 | public: // IMutableRegistryHub |
9198 | void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) override { |
9199 | m_reporterRegistry.registerReporter( name, factory ); |
9200 | } |
9201 | void registerListener( IReporterFactoryPtr const& factory ) override { |
9202 | m_reporterRegistry.registerListener( factory ); |
9203 | } |
9204 | void registerTest( TestCase const& testInfo ) override { |
9205 | m_testCaseRegistry.registerTest( testInfo ); |
9206 | } |
9207 | void registerTranslator( const IExceptionTranslator* translator ) override { |
9208 | m_exceptionTranslatorRegistry.registerTranslator( translator ); |
9209 | } |
9210 | void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) override { |
9211 | m_tagAliasRegistry.add( alias, tag, lineInfo ); |
9212 | } |
9213 | void registerStartupException() noexcept override { |
9214 | m_exceptionRegistry.add(std::current_exception()); |
9215 | } |
9216 | |
9217 | private: |
9218 | TestRegistry m_testCaseRegistry; |
9219 | ReporterRegistry m_reporterRegistry; |
9220 | ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; |
9221 | TagAliasRegistry m_tagAliasRegistry; |
9222 | StartupExceptionRegistry m_exceptionRegistry; |
9223 | }; |
9224 | } |
9225 | |
9226 | using RegistryHubSingleton = Singleton<RegistryHub, IRegistryHub, IMutableRegistryHub>; |
9227 | |
9228 | IRegistryHub const& getRegistryHub() { |
9229 | return RegistryHubSingleton::get(); |
9230 | } |
9231 | IMutableRegistryHub& getMutableRegistryHub() { |
9232 | return RegistryHubSingleton::getMutable(); |
9233 | } |
9234 | void cleanUp() { |
9235 | cleanupSingletons(); |
9236 | cleanUpContext(); |
9237 | } |
9238 | std::string translateActiveException() { |
9239 | return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); |
9240 | } |
9241 | |
9242 | } // end namespace Catch |
9243 | // end catch_registry_hub.cpp |
9244 | // start catch_reporter_registry.cpp |
9245 | |
9246 | namespace Catch { |
9247 | |
9248 | ReporterRegistry::~ReporterRegistry() = default; |
9249 | |
9250 | IStreamingReporterPtr ReporterRegistry::create( std::string const& name, IConfigPtr const& config ) const { |
9251 | auto it = m_factories.find( name ); |
9252 | if( it == m_factories.end() ) |
9253 | return nullptr; |
9254 | return it->second->create( ReporterConfig( config ) ); |
9255 | } |
9256 | |
9257 | void ReporterRegistry::registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) { |
9258 | m_factories.emplace(name, factory); |
9259 | } |
9260 | void ReporterRegistry::registerListener( IReporterFactoryPtr const& factory ) { |
9261 | m_listeners.push_back( factory ); |
9262 | } |
9263 | |
9264 | IReporterRegistry::FactoryMap const& ReporterRegistry::getFactories() const { |
9265 | return m_factories; |
9266 | } |
9267 | IReporterRegistry::Listeners const& ReporterRegistry::getListeners() const { |
9268 | return m_listeners; |
9269 | } |
9270 | |
9271 | } |
9272 | // end catch_reporter_registry.cpp |
9273 | // start catch_result_type.cpp |
9274 | |
9275 | namespace Catch { |
9276 | |
9277 | bool isOk( ResultWas::OfType resultType ) { |
9278 | return ( resultType & ResultWas::FailureBit ) == 0; |
9279 | } |
9280 | bool isJustInfo( int flags ) { |
9281 | return flags == ResultWas::Info; |
9282 | } |
9283 | |
9284 | ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { |
9285 | return static_cast<ResultDisposition::Flags>( static_cast<int>( lhs ) | static_cast<int>( rhs ) ); |
9286 | } |
9287 | |
9288 | bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } |
9289 | bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } |
9290 | |
9291 | } // end namespace Catch |
9292 | // end catch_result_type.cpp |
9293 | // start catch_run_context.cpp |
9294 | |
9295 | #include <cassert> |
9296 | #include <algorithm> |
9297 | #include <sstream> |
9298 | |
9299 | namespace Catch { |
9300 | |
9301 | namespace Generators { |
9302 | struct GeneratorTracker : TestCaseTracking::TrackerBase, IGeneratorTracker { |
9303 | size_t m_index = static_cast<size_t>( -1 ); |
9304 | GeneratorBasePtr m_generator; |
9305 | |
9306 | GeneratorTracker( TestCaseTracking::NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) |
9307 | : TrackerBase( nameAndLocation, ctx, parent ) |
9308 | {} |
9309 | ~GeneratorTracker(); |
9310 | |
9311 | static GeneratorTracker& acquire( TrackerContext& ctx, TestCaseTracking::NameAndLocation const& nameAndLocation ) { |
9312 | std::shared_ptr<GeneratorTracker> tracker; |
9313 | |
9314 | ITracker& currentTracker = ctx.currentTracker(); |
9315 | if( TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { |
9316 | assert( childTracker ); |
9317 | assert( childTracker->isIndexTracker() ); |
9318 | tracker = std::static_pointer_cast<GeneratorTracker>( childTracker ); |
9319 | } |
9320 | else { |
9321 | tracker = std::make_shared<GeneratorTracker>( nameAndLocation, ctx, ¤tTracker ); |
9322 | currentTracker.addChild( tracker ); |
9323 | } |
9324 | |
9325 | if( !ctx.completedCycle() && !tracker->isComplete() ) { |
9326 | if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun ) |
9327 | tracker->moveNext(); |
9328 | tracker->open(); |
9329 | } |
9330 | |
9331 | return *tracker; |
9332 | } |
9333 | |
9334 | void moveNext() { |
9335 | m_index++; |
9336 | m_children.clear(); |
9337 | } |
9338 | |
9339 | // TrackerBase interface |
9340 | bool () const override { return true; } |
9341 | auto hasGenerator() const -> bool override { |
9342 | return !!m_generator; |
9343 | } |
9344 | void close() override { |
9345 | TrackerBase::close(); |
9346 | if( m_runState == CompletedSuccessfully && m_index < m_generator->size()-1 ) |
9347 | m_runState = Executing; |
9348 | } |
9349 | |
9350 | // IGeneratorTracker interface |
9351 | auto getGenerator() const -> GeneratorBasePtr const& override { |
9352 | return m_generator; |
9353 | } |
9354 | void setGenerator( GeneratorBasePtr&& generator ) override { |
9355 | m_generator = std::move( generator ); |
9356 | } |
9357 | auto getIndex() const -> size_t override { |
9358 | return m_index; |
9359 | } |
9360 | }; |
9361 | GeneratorTracker::~GeneratorTracker() {} |
9362 | } |
9363 | |
9364 | RunContext::RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter) |
9365 | : m_runInfo(_config->name()), |
9366 | m_context(getCurrentMutableContext()), |
9367 | m_config(_config), |
9368 | m_reporter(std::move(reporter)), |
9369 | m_lastAssertionInfo{ StringRef(), SourceLineInfo("" ,0), StringRef(), ResultDisposition::Normal }, |
9370 | m_includeSuccessfulResults( m_config->includeSuccessfulResults() || m_reporter->getPreferences().shouldReportAllAssertions ) |
9371 | { |
9372 | m_context.setRunner(this); |
9373 | m_context.setConfig(m_config); |
9374 | m_context.setResultCapture(this); |
9375 | m_reporter->testRunStarting(m_runInfo); |
9376 | } |
9377 | |
9378 | RunContext::~RunContext() { |
9379 | m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, aborting())); |
9380 | } |
9381 | |
9382 | void RunContext::testGroupStarting(std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount) { |
9383 | m_reporter->testGroupStarting(GroupInfo(testSpec, groupIndex, groupsCount)); |
9384 | } |
9385 | |
9386 | void RunContext::testGroupEnded(std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount) { |
9387 | m_reporter->testGroupEnded(TestGroupStats(GroupInfo(testSpec, groupIndex, groupsCount), totals, aborting())); |
9388 | } |
9389 | |
9390 | Totals RunContext::runTest(TestCase const& testCase) { |
9391 | Totals prevTotals = m_totals; |
9392 | |
9393 | std::string redirectedCout; |
9394 | std::string redirectedCerr; |
9395 | |
9396 | auto const& testInfo = testCase.getTestCaseInfo(); |
9397 | |
9398 | m_reporter->testCaseStarting(testInfo); |
9399 | |
9400 | m_activeTestCase = &testCase; |
9401 | |
9402 | ITracker& rootTracker = m_trackerContext.startRun(); |
9403 | assert(rootTracker.isSectionTracker()); |
9404 | static_cast<SectionTracker&>(rootTracker).addInitialFilters(m_config->getSectionsToRun()); |
9405 | do { |
9406 | m_trackerContext.startCycle(); |
9407 | m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(testInfo.name, testInfo.lineInfo)); |
9408 | runCurrentTest(redirectedCout, redirectedCerr); |
9409 | } while (!m_testCaseTracker->isSuccessfullyCompleted() && !aborting()); |
9410 | |
9411 | Totals deltaTotals = m_totals.delta(prevTotals); |
9412 | if (testInfo.expectedToFail() && deltaTotals.testCases.passed > 0) { |
9413 | deltaTotals.assertions.failed++; |
9414 | deltaTotals.testCases.passed--; |
9415 | deltaTotals.testCases.failed++; |
9416 | } |
9417 | m_totals.testCases += deltaTotals.testCases; |
9418 | m_reporter->testCaseEnded(TestCaseStats(testInfo, |
9419 | deltaTotals, |
9420 | redirectedCout, |
9421 | redirectedCerr, |
9422 | aborting())); |
9423 | |
9424 | m_activeTestCase = nullptr; |
9425 | m_testCaseTracker = nullptr; |
9426 | |
9427 | return deltaTotals; |
9428 | } |
9429 | |
9430 | IConfigPtr RunContext::config() const { |
9431 | return m_config; |
9432 | } |
9433 | |
9434 | IStreamingReporter& RunContext::reporter() const { |
9435 | return *m_reporter; |
9436 | } |
9437 | |
9438 | void RunContext::assertionEnded(AssertionResult const & result) { |
9439 | if (result.getResultType() == ResultWas::Ok) { |
9440 | m_totals.assertions.passed++; |
9441 | m_lastAssertionPassed = true; |
9442 | } else if (!result.isOk()) { |
9443 | m_lastAssertionPassed = false; |
9444 | if( m_activeTestCase->getTestCaseInfo().okToFail() ) |
9445 | m_totals.assertions.failedButOk++; |
9446 | else |
9447 | m_totals.assertions.failed++; |
9448 | } |
9449 | else { |
9450 | m_lastAssertionPassed = true; |
9451 | } |
9452 | |
9453 | // We have no use for the return value (whether messages should be cleared), because messages were made scoped |
9454 | // and should be let to clear themselves out. |
9455 | static_cast<void>(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals))); |
9456 | |
9457 | // Reset working state |
9458 | resetAssertionInfo(); |
9459 | m_lastResult = result; |
9460 | } |
9461 | void RunContext::resetAssertionInfo() { |
9462 | m_lastAssertionInfo.macroName = StringRef(); |
9463 | m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"_sr ; |
9464 | } |
9465 | |
9466 | bool RunContext::sectionStarted(SectionInfo const & sectionInfo, Counts & assertions) { |
9467 | ITracker& sectionTracker = SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(sectionInfo.name, sectionInfo.lineInfo)); |
9468 | if (!sectionTracker.isOpen()) |
9469 | return false; |
9470 | m_activeSections.push_back(§ionTracker); |
9471 | |
9472 | m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; |
9473 | |
9474 | m_reporter->sectionStarting(sectionInfo); |
9475 | |
9476 | assertions = m_totals.assertions; |
9477 | |
9478 | return true; |
9479 | } |
9480 | auto RunContext::acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { |
9481 | using namespace Generators; |
9482 | GeneratorTracker& tracker = GeneratorTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( "generator" , lineInfo ) ); |
9483 | assert( tracker.isOpen() ); |
9484 | m_lastAssertionInfo.lineInfo = lineInfo; |
9485 | return tracker; |
9486 | } |
9487 | |
9488 | bool RunContext::testForMissingAssertions(Counts& assertions) { |
9489 | if (assertions.total() != 0) |
9490 | return false; |
9491 | if (!m_config->warnAboutMissingAssertions()) |
9492 | return false; |
9493 | if (m_trackerContext.currentTracker().hasChildren()) |
9494 | return false; |
9495 | m_totals.assertions.failed++; |
9496 | assertions.failed++; |
9497 | return true; |
9498 | } |
9499 | |
9500 | void RunContext::sectionEnded(SectionEndInfo const & endInfo) { |
9501 | Counts assertions = m_totals.assertions - endInfo.prevAssertions; |
9502 | bool missingAssertions = testForMissingAssertions(assertions); |
9503 | |
9504 | if (!m_activeSections.empty()) { |
9505 | m_activeSections.back()->close(); |
9506 | m_activeSections.pop_back(); |
9507 | } |
9508 | |
9509 | m_reporter->sectionEnded(SectionStats(endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions)); |
9510 | m_messages.clear(); |
9511 | } |
9512 | |
9513 | void RunContext::sectionEndedEarly(SectionEndInfo const & endInfo) { |
9514 | if (m_unfinishedSections.empty()) |
9515 | m_activeSections.back()->fail(); |
9516 | else |
9517 | m_activeSections.back()->close(); |
9518 | m_activeSections.pop_back(); |
9519 | |
9520 | m_unfinishedSections.push_back(endInfo); |
9521 | } |
9522 | void RunContext::benchmarkStarting( BenchmarkInfo const& info ) { |
9523 | m_reporter->benchmarkStarting( info ); |
9524 | } |
9525 | void RunContext::benchmarkEnded( BenchmarkStats const& stats ) { |
9526 | m_reporter->benchmarkEnded( stats ); |
9527 | } |
9528 | |
9529 | void RunContext::pushScopedMessage(MessageInfo const & message) { |
9530 | m_messages.push_back(message); |
9531 | } |
9532 | |
9533 | void RunContext::popScopedMessage(MessageInfo const & message) { |
9534 | m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end()); |
9535 | } |
9536 | |
9537 | std::string RunContext::getCurrentTestName() const { |
9538 | return m_activeTestCase |
9539 | ? m_activeTestCase->getTestCaseInfo().name |
9540 | : std::string(); |
9541 | } |
9542 | |
9543 | const AssertionResult * RunContext::getLastResult() const { |
9544 | return &(*m_lastResult); |
9545 | } |
9546 | |
9547 | void RunContext::exceptionEarlyReported() { |
9548 | m_shouldReportUnexpected = false; |
9549 | } |
9550 | |
9551 | void RunContext::handleFatalErrorCondition( StringRef message ) { |
9552 | // First notify reporter that bad things happened |
9553 | m_reporter->fatalErrorEncountered(message); |
9554 | |
9555 | // Don't rebuild the result -- the stringification itself can cause more fatal errors |
9556 | // Instead, fake a result data. |
9557 | AssertionResultData tempResult( ResultWas::FatalErrorCondition, { false } ); |
9558 | tempResult.message = message; |
9559 | AssertionResult result(m_lastAssertionInfo, tempResult); |
9560 | |
9561 | assertionEnded(result); |
9562 | |
9563 | handleUnfinishedSections(); |
9564 | |
9565 | // Recreate section for test case (as we will lose the one that was in scope) |
9566 | auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); |
9567 | SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name); |
9568 | |
9569 | Counts assertions; |
9570 | assertions.failed = 1; |
9571 | SectionStats testCaseSectionStats(testCaseSection, assertions, 0, false); |
9572 | m_reporter->sectionEnded(testCaseSectionStats); |
9573 | |
9574 | auto const& testInfo = m_activeTestCase->getTestCaseInfo(); |
9575 | |
9576 | Totals deltaTotals; |
9577 | deltaTotals.testCases.failed = 1; |
9578 | deltaTotals.assertions.failed = 1; |
9579 | m_reporter->testCaseEnded(TestCaseStats(testInfo, |
9580 | deltaTotals, |
9581 | std::string(), |
9582 | std::string(), |
9583 | false)); |
9584 | m_totals.testCases.failed++; |
9585 | testGroupEnded(std::string(), m_totals, 1, 1); |
9586 | m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, false)); |
9587 | } |
9588 | |
9589 | bool RunContext::lastAssertionPassed() { |
9590 | return m_lastAssertionPassed; |
9591 | } |
9592 | |
9593 | void RunContext::assertionPassed() { |
9594 | m_lastAssertionPassed = true; |
9595 | ++m_totals.assertions.passed; |
9596 | resetAssertionInfo(); |
9597 | } |
9598 | |
9599 | bool RunContext::aborting() const { |
9600 | return m_totals.assertions.failed == static_cast<std::size_t>(m_config->abortAfter()); |
9601 | } |
9602 | |
9603 | void RunContext::runCurrentTest(std::string & redirectedCout, std::string & redirectedCerr) { |
9604 | auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); |
9605 | SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name); |
9606 | m_reporter->sectionStarting(testCaseSection); |
9607 | Counts prevAssertions = m_totals.assertions; |
9608 | double duration = 0; |
9609 | m_shouldReportUnexpected = true; |
9610 | m_lastAssertionInfo = { "TEST_CASE"_sr , testCaseInfo.lineInfo, StringRef(), ResultDisposition::Normal }; |
9611 | |
9612 | seedRng(*m_config); |
9613 | |
9614 | Timer timer; |
9615 | CATCH_TRY { |
9616 | if (m_reporter->getPreferences().shouldRedirectStdOut) { |
9617 | #if !defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) |
9618 | RedirectedStdOut redirectedStdOut; |
9619 | RedirectedStdErr redirectedStdErr; |
9620 | |
9621 | timer.start(); |
9622 | invokeActiveTestCase(); |
9623 | redirectedCout += redirectedStdOut.str(); |
9624 | redirectedCerr += redirectedStdErr.str(); |
9625 | #else |
9626 | OutputRedirect r(redirectedCout, redirectedCerr); |
9627 | timer.start(); |
9628 | invokeActiveTestCase(); |
9629 | #endif |
9630 | } else { |
9631 | timer.start(); |
9632 | invokeActiveTestCase(); |
9633 | } |
9634 | duration = timer.getElapsedSeconds(); |
9635 | } CATCH_CATCH_ANON (TestFailureException&) { |
9636 | // This just means the test was aborted due to failure |
9637 | } CATCH_CATCH_ALL { |
9638 | // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions |
9639 | // are reported without translation at the point of origin. |
9640 | if( m_shouldReportUnexpected ) { |
9641 | AssertionReaction dummyReaction; |
9642 | handleUnexpectedInflightException( m_lastAssertionInfo, translateActiveException(), dummyReaction ); |
9643 | } |
9644 | } |
9645 | Counts assertions = m_totals.assertions - prevAssertions; |
9646 | bool missingAssertions = testForMissingAssertions(assertions); |
9647 | |
9648 | m_testCaseTracker->close(); |
9649 | handleUnfinishedSections(); |
9650 | m_messages.clear(); |
9651 | |
9652 | SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions); |
9653 | m_reporter->sectionEnded(testCaseSectionStats); |
9654 | } |
9655 | |
9656 | void RunContext::invokeActiveTestCase() { |
9657 | FatalConditionHandler fatalConditionHandler; // Handle signals |
9658 | m_activeTestCase->invoke(); |
9659 | fatalConditionHandler.reset(); |
9660 | } |
9661 | |
9662 | void RunContext::handleUnfinishedSections() { |
9663 | // If sections ended prematurely due to an exception we stored their |
9664 | // infos here so we can tear them down outside the unwind process. |
9665 | for (auto it = m_unfinishedSections.rbegin(), |
9666 | itEnd = m_unfinishedSections.rend(); |
9667 | it != itEnd; |
9668 | ++it) |
9669 | sectionEnded(*it); |
9670 | m_unfinishedSections.clear(); |
9671 | } |
9672 | |
9673 | void RunContext::handleExpr( |
9674 | AssertionInfo const& info, |
9675 | ITransientExpression const& expr, |
9676 | AssertionReaction& reaction |
9677 | ) { |
9678 | m_reporter->assertionStarting( info ); |
9679 | |
9680 | bool negated = isFalseTest( info.resultDisposition ); |
9681 | bool result = expr.getResult() != negated; |
9682 | |
9683 | if( result ) { |
9684 | if (!m_includeSuccessfulResults) { |
9685 | assertionPassed(); |
9686 | } |
9687 | else { |
9688 | reportExpr(info, ResultWas::Ok, &expr, negated); |
9689 | } |
9690 | } |
9691 | else { |
9692 | reportExpr(info, ResultWas::ExpressionFailed, &expr, negated ); |
9693 | populateReaction( reaction ); |
9694 | } |
9695 | } |
9696 | void RunContext::reportExpr( |
9697 | AssertionInfo const &info, |
9698 | ResultWas::OfType resultType, |
9699 | ITransientExpression const *expr, |
9700 | bool negated ) { |
9701 | |
9702 | m_lastAssertionInfo = info; |
9703 | AssertionResultData data( resultType, LazyExpression( negated ) ); |
9704 | |
9705 | AssertionResult assertionResult{ info, data }; |
9706 | assertionResult.m_resultData.lazyExpression.m_transientExpression = expr; |
9707 | |
9708 | assertionEnded( assertionResult ); |
9709 | } |
9710 | |
9711 | void RunContext::handleMessage( |
9712 | AssertionInfo const& info, |
9713 | ResultWas::OfType resultType, |
9714 | StringRef const& message, |
9715 | AssertionReaction& reaction |
9716 | ) { |
9717 | m_reporter->assertionStarting( info ); |
9718 | |
9719 | m_lastAssertionInfo = info; |
9720 | |
9721 | AssertionResultData data( resultType, LazyExpression( false ) ); |
9722 | data.message = message; |
9723 | AssertionResult assertionResult{ m_lastAssertionInfo, data }; |
9724 | assertionEnded( assertionResult ); |
9725 | if( !assertionResult.isOk() ) |
9726 | populateReaction( reaction ); |
9727 | } |
9728 | void RunContext::handleUnexpectedExceptionNotThrown( |
9729 | AssertionInfo const& info, |
9730 | AssertionReaction& reaction |
9731 | ) { |
9732 | handleNonExpr(info, Catch::ResultWas::DidntThrowException, reaction); |
9733 | } |
9734 | |
9735 | void RunContext::handleUnexpectedInflightException( |
9736 | AssertionInfo const& info, |
9737 | std::string const& message, |
9738 | AssertionReaction& reaction |
9739 | ) { |
9740 | m_lastAssertionInfo = info; |
9741 | |
9742 | AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); |
9743 | data.message = message; |
9744 | AssertionResult assertionResult{ info, data }; |
9745 | assertionEnded( assertionResult ); |
9746 | populateReaction( reaction ); |
9747 | } |
9748 | |
9749 | void RunContext::populateReaction( AssertionReaction& reaction ) { |
9750 | reaction.shouldDebugBreak = m_config->shouldDebugBreak(); |
9751 | reaction.shouldThrow = aborting() || (m_lastAssertionInfo.resultDisposition & ResultDisposition::Normal); |
9752 | } |
9753 | |
9754 | void RunContext::handleIncomplete( |
9755 | AssertionInfo const& info |
9756 | ) { |
9757 | m_lastAssertionInfo = info; |
9758 | |
9759 | AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); |
9760 | data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE" ; |
9761 | AssertionResult assertionResult{ info, data }; |
9762 | assertionEnded( assertionResult ); |
9763 | } |
9764 | void RunContext::handleNonExpr( |
9765 | AssertionInfo const &info, |
9766 | ResultWas::OfType resultType, |
9767 | AssertionReaction &reaction |
9768 | ) { |
9769 | m_lastAssertionInfo = info; |
9770 | |
9771 | AssertionResultData data( resultType, LazyExpression( false ) ); |
9772 | AssertionResult assertionResult{ info, data }; |
9773 | assertionEnded( assertionResult ); |
9774 | |
9775 | if( !assertionResult.isOk() ) |
9776 | populateReaction( reaction ); |
9777 | } |
9778 | |
9779 | IResultCapture& getResultCapture() { |
9780 | if (auto* capture = getCurrentContext().getResultCapture()) |
9781 | return *capture; |
9782 | else |
9783 | CATCH_INTERNAL_ERROR("No result capture instance" ); |
9784 | } |
9785 | } |
9786 | // end catch_run_context.cpp |
9787 | // start catch_section.cpp |
9788 | |
9789 | namespace Catch { |
9790 | |
9791 | Section::Section( SectionInfo const& info ) |
9792 | : m_info( info ), |
9793 | m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) ) |
9794 | { |
9795 | m_timer.start(); |
9796 | } |
9797 | |
9798 | Section::~Section() { |
9799 | if( m_sectionIncluded ) { |
9800 | SectionEndInfo endInfo{ m_info, m_assertions, m_timer.getElapsedSeconds() }; |
9801 | if( uncaught_exceptions() ) |
9802 | getResultCapture().sectionEndedEarly( endInfo ); |
9803 | else |
9804 | getResultCapture().sectionEnded( endInfo ); |
9805 | } |
9806 | } |
9807 | |
9808 | // This indicates whether the section should be executed or not |
9809 | Section::operator bool() const { |
9810 | return m_sectionIncluded; |
9811 | } |
9812 | |
9813 | } // end namespace Catch |
9814 | // end catch_section.cpp |
9815 | // start catch_section_info.cpp |
9816 | |
9817 | namespace Catch { |
9818 | |
9819 | SectionInfo::SectionInfo |
9820 | ( SourceLineInfo const& _lineInfo, |
9821 | std::string const& _name ) |
9822 | : name( _name ), |
9823 | lineInfo( _lineInfo ) |
9824 | {} |
9825 | |
9826 | } // end namespace Catch |
9827 | // end catch_section_info.cpp |
9828 | // start catch_session.cpp |
9829 | |
9830 | // start catch_session.h |
9831 | |
9832 | #include <memory> |
9833 | |
9834 | namespace Catch { |
9835 | |
9836 | class Session : NonCopyable { |
9837 | public: |
9838 | |
9839 | Session(); |
9840 | ~Session() override; |
9841 | |
9842 | void showHelp() const; |
9843 | void libIdentify(); |
9844 | |
9845 | int applyCommandLine( int argc, char const * const * argv ); |
9846 | |
9847 | void useConfigData( ConfigData const& configData ); |
9848 | |
9849 | int run( int argc, char* argv[] ); |
9850 | #if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE) |
9851 | int run( int argc, wchar_t* const argv[] ); |
9852 | #endif |
9853 | int run(); |
9854 | |
9855 | clara::Parser const& cli() const; |
9856 | void cli( clara::Parser const& newParser ); |
9857 | ConfigData& configData(); |
9858 | Config& config(); |
9859 | private: |
9860 | int runInternal(); |
9861 | |
9862 | clara::Parser m_cli; |
9863 | ConfigData m_configData; |
9864 | std::shared_ptr<Config> m_config; |
9865 | bool m_startupExceptions = false; |
9866 | }; |
9867 | |
9868 | } // end namespace Catch |
9869 | |
9870 | // end catch_session.h |
9871 | // start catch_version.h |
9872 | |
9873 | #include <iosfwd> |
9874 | |
9875 | namespace Catch { |
9876 | |
9877 | // Versioning information |
9878 | struct Version { |
9879 | Version( Version const& ) = delete; |
9880 | Version& operator=( Version const& ) = delete; |
9881 | Version( unsigned int _majorVersion, |
9882 | unsigned int _minorVersion, |
9883 | unsigned int _patchNumber, |
9884 | char const * const _branchName, |
9885 | unsigned int _buildNumber ); |
9886 | |
9887 | unsigned int const majorVersion; |
9888 | unsigned int const minorVersion; |
9889 | unsigned int const patchNumber; |
9890 | |
9891 | // buildNumber is only used if branchName is not null |
9892 | char const * const branchName; |
9893 | unsigned int const buildNumber; |
9894 | |
9895 | friend std::ostream& operator << ( std::ostream& os, Version const& version ); |
9896 | }; |
9897 | |
9898 | Version const& libraryVersion(); |
9899 | } |
9900 | |
9901 | // end catch_version.h |
9902 | #include <cstdlib> |
9903 | #include <iomanip> |
9904 | #include <iostream> |
9905 | |
9906 | namespace Catch { |
9907 | |
9908 | namespace { |
9909 | const int MaxExitCode = 255; |
9910 | |
9911 | IStreamingReporterPtr createReporter(std::string const& reporterName, IConfigPtr const& config) { |
9912 | auto reporter = Catch::getRegistryHub().getReporterRegistry().create(reporterName, config); |
9913 | CATCH_ENFORCE(reporter, "No reporter registered with name: '" << reporterName << "'" ); |
9914 | |
9915 | return reporter; |
9916 | } |
9917 | |
9918 | IStreamingReporterPtr makeReporter(std::shared_ptr<Config> const& config) { |
9919 | if (Catch::getRegistryHub().getReporterRegistry().getListeners().empty()) { |
9920 | return createReporter(config->getReporterName(), config); |
9921 | } |
9922 | |
9923 | auto multi = std::unique_ptr<ListeningReporter>(new ListeningReporter); |
9924 | |
9925 | auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners(); |
9926 | for (auto const& listener : listeners) { |
9927 | multi->addListener(listener->create(Catch::ReporterConfig(config))); |
9928 | } |
9929 | multi->addReporter(createReporter(config->getReporterName(), config)); |
9930 | return std::move(multi); |
9931 | } |
9932 | |
9933 | void renderTestProgress(int current_test, int total_tests, std::string next_test) { |
9934 | double progress = (double) current_test / (double) total_tests; |
9935 | int render_width = 80; |
9936 | std::string result = "[" + std::to_string(current_test) + "/" + std::to_string(total_tests) + "] (" + std::to_string(int(progress * 100)) + "%): " + next_test; |
9937 | if (result.size() < render_width) { |
9938 | result += std::string(render_width - result.size(), ' '); |
9939 | } else if (result.size() > render_width) { |
9940 | result = result.substr(0, render_width - 3) + "..." ; |
9941 | } |
9942 | std::cout << "\r" << result; |
9943 | std::cout.flush(); |
9944 | } |
9945 | |
9946 | Catch::Totals runTests(std::shared_ptr<Config> const& config) { |
9947 | // FixMe: Add listeners in order first, then add reporters. |
9948 | |
9949 | auto reporter = makeReporter(config); |
9950 | |
9951 | RunContext context(config, std::move(reporter)); |
9952 | |
9953 | Totals totals; |
9954 | |
9955 | context.testGroupStarting(config->name(), 1, 1); |
9956 | |
9957 | TestSpec testSpec = config->testSpec(); |
9958 | |
9959 | auto const& allTestCases = getAllTestCasesSorted(*config); |
9960 | int total_tests_run = 0, current_test = 0; |
9961 | for (auto const& testCase : allTestCases) { |
9962 | if (matchTest(testCase, testSpec, *config)) { |
9963 | total_tests_run++; |
9964 | } |
9965 | } |
9966 | for (auto const& testCase : allTestCases) { |
9967 | if (!context.aborting() && matchTest(testCase, testSpec, *config)) { |
9968 | renderTestProgress(current_test, total_tests_run, testCase.name); |
9969 | totals += context.runTest(testCase); |
9970 | current_test++; |
9971 | if (current_test == total_tests_run) { |
9972 | renderTestProgress(current_test, total_tests_run, testCase.name); |
9973 | std::cout << std::endl; |
9974 | } |
9975 | } else { |
9976 | context.reporter().skipTest(testCase); |
9977 | } |
9978 | } |
9979 | |
9980 | if (config->warnAboutNoTests() && totals.testCases.total() == 0) { |
9981 | ReusableStringStream testConfig; |
9982 | |
9983 | bool first = true; |
9984 | for (const auto& input : config->getTestsOrTags()) { |
9985 | if (!first) { testConfig << ' '; } |
9986 | first = false; |
9987 | testConfig << input; |
9988 | } |
9989 | |
9990 | context.reporter().noMatchingTestCases(testConfig.str()); |
9991 | totals.error = -1; |
9992 | } |
9993 | |
9994 | context.testGroupEnded(config->name(), totals, 1, 1); |
9995 | return totals; |
9996 | } |
9997 | |
9998 | void applyFilenamesAsTags(Catch::IConfig const& config) { |
9999 | auto& tests = const_cast<std::vector<TestCase>&>(getAllTestCasesSorted(config)); |
10000 | for (auto& testCase : tests) { |
10001 | auto tags = testCase.tags; |
10002 | |
10003 | std::string filename = testCase.lineInfo.file; |
10004 | auto lastSlash = filename.find_last_of("\\/" ); |
10005 | if (lastSlash != std::string::npos) { |
10006 | filename.erase(0, lastSlash); |
10007 | filename[0] = '#'; |
10008 | } |
10009 | |
10010 | auto lastDot = filename.find_last_of('.'); |
10011 | if (lastDot != std::string::npos) { |
10012 | filename.erase(lastDot); |
10013 | } |
10014 | |
10015 | tags.push_back(std::move(filename)); |
10016 | setTags(testCase, tags); |
10017 | } |
10018 | } |
10019 | |
10020 | } // anon namespace |
10021 | |
10022 | Session::Session() { |
10023 | static bool alreadyInstantiated = false; |
10024 | if( alreadyInstantiated ) { |
10025 | CATCH_TRY { CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); } |
10026 | CATCH_CATCH_ALL { getMutableRegistryHub().registerStartupException(); } |
10027 | } |
10028 | |
10029 | // There cannot be exceptions at startup in no-exception mode. |
10030 | #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) |
10031 | const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions(); |
10032 | if ( !exceptions.empty() ) { |
10033 | m_startupExceptions = true; |
10034 | Colour colourGuard( Colour::Red ); |
10035 | Catch::cerr() << "Errors occurred during startup!" << '\n'; |
10036 | // iterate over all exceptions and notify user |
10037 | for ( const auto& ex_ptr : exceptions ) { |
10038 | try { |
10039 | std::rethrow_exception(ex_ptr); |
10040 | } catch ( std::exception const& ex ) { |
10041 | Catch::cerr() << Column( ex.what() ).indent(2) << '\n'; |
10042 | } |
10043 | } |
10044 | } |
10045 | #endif |
10046 | |
10047 | alreadyInstantiated = true; |
10048 | m_cli = makeCommandLineParser( m_configData ); |
10049 | } |
10050 | Session::~Session() { |
10051 | Catch::cleanUp(); |
10052 | } |
10053 | |
10054 | void Session::showHelp() const { |
10055 | Catch::cout() |
10056 | << "\nCatch v" << libraryVersion() << "\n" |
10057 | << m_cli << std::endl |
10058 | << "For more detailed usage please see the project docs\n" << std::endl; |
10059 | } |
10060 | void Session::libIdentify() { |
10061 | Catch::cout() |
10062 | << std::left << std::setw(16) << "description: " << "A Catch test executable\n" |
10063 | << std::left << std::setw(16) << "category: " << "testframework\n" |
10064 | << std::left << std::setw(16) << "framework: " << "Catch Test\n" |
10065 | << std::left << std::setw(16) << "version: " << libraryVersion() << std::endl; |
10066 | } |
10067 | |
10068 | int Session::applyCommandLine( int argc, char const * const * argv ) { |
10069 | if( m_startupExceptions ) |
10070 | return 1; |
10071 | |
10072 | auto result = m_cli.parse( clara::Args( argc, argv ) ); |
10073 | if( !result ) { |
10074 | Catch::cerr() |
10075 | << Colour( Colour::Red ) |
10076 | << "\nError(s) in input:\n" |
10077 | << Column( result.errorMessage() ).indent( 2 ) |
10078 | << "\n\n" ; |
10079 | Catch::cerr() << "Run with -? for usage\n" << std::endl; |
10080 | return MaxExitCode; |
10081 | } |
10082 | |
10083 | if( m_configData.showHelp ) |
10084 | showHelp(); |
10085 | if( m_configData.libIdentify ) |
10086 | libIdentify(); |
10087 | m_config.reset(); |
10088 | return 0; |
10089 | } |
10090 | |
10091 | void Session::useConfigData( ConfigData const& configData ) { |
10092 | m_configData = configData; |
10093 | m_config.reset(); |
10094 | } |
10095 | |
10096 | int Session::run( int argc, char* argv[] ) { |
10097 | if( m_startupExceptions ) |
10098 | return 1; |
10099 | int returnCode = applyCommandLine( argc, argv ); |
10100 | if( returnCode == 0 ) |
10101 | returnCode = run(); |
10102 | return returnCode; |
10103 | } |
10104 | |
10105 | #if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE) |
10106 | int Session::run( int argc, wchar_t* const argv[] ) { |
10107 | |
10108 | char **utf8Argv = new char *[ argc ]; |
10109 | |
10110 | for ( int i = 0; i < argc; ++i ) { |
10111 | int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL ); |
10112 | |
10113 | utf8Argv[ i ] = new char[ bufSize ]; |
10114 | |
10115 | WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL ); |
10116 | } |
10117 | |
10118 | int returnCode = run( argc, utf8Argv ); |
10119 | |
10120 | for ( int i = 0; i < argc; ++i ) |
10121 | delete [] utf8Argv[ i ]; |
10122 | |
10123 | delete [] utf8Argv; |
10124 | |
10125 | return returnCode; |
10126 | } |
10127 | #endif |
10128 | int Session::run() { |
10129 | if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) { |
10130 | Catch::cout() << "...waiting for enter/ return before starting" << std::endl; |
10131 | static_cast<void>(std::getchar()); |
10132 | } |
10133 | int exitCode = runInternal(); |
10134 | if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) { |
10135 | Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << std::endl; |
10136 | static_cast<void>(std::getchar()); |
10137 | } |
10138 | return exitCode; |
10139 | } |
10140 | |
10141 | clara::Parser const& Session::cli() const { |
10142 | return m_cli; |
10143 | } |
10144 | void Session::cli( clara::Parser const& newParser ) { |
10145 | m_cli = newParser; |
10146 | } |
10147 | ConfigData& Session::configData() { |
10148 | return m_configData; |
10149 | } |
10150 | Config& Session::config() { |
10151 | if( !m_config ) |
10152 | m_config = std::make_shared<Config>( m_configData ); |
10153 | return *m_config; |
10154 | } |
10155 | |
10156 | int Session::runInternal() { |
10157 | if( m_startupExceptions ) |
10158 | return 1; |
10159 | |
10160 | if (m_configData.showHelp || m_configData.libIdentify) { |
10161 | return 0; |
10162 | } |
10163 | |
10164 | CATCH_TRY { |
10165 | config(); // Force config to be constructed |
10166 | |
10167 | seedRng( *m_config ); |
10168 | |
10169 | if( m_configData.filenamesAsTags ) |
10170 | applyFilenamesAsTags( *m_config ); |
10171 | |
10172 | // Handle list request |
10173 | if( Option<std::size_t> listed = list( config() ) ) |
10174 | return static_cast<int>( *listed ); |
10175 | |
10176 | auto totals = runTests( m_config ); |
10177 | // Note that on unices only the lower 8 bits are usually used, clamping |
10178 | // the return value to 255 prevents false negative when some multiple |
10179 | // of 256 tests has failed |
10180 | return (std::min) (MaxExitCode, (std::max) (totals.error, static_cast<int>(totals.assertions.failed))); |
10181 | } |
10182 | #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) |
10183 | catch( std::exception& ex ) { |
10184 | Catch::cerr() << ex.what() << std::endl; |
10185 | return MaxExitCode; |
10186 | } |
10187 | #endif |
10188 | } |
10189 | |
10190 | } // end namespace Catch |
10191 | // end catch_session.cpp |
10192 | // start catch_singletons.cpp |
10193 | |
10194 | #include <vector> |
10195 | |
10196 | namespace Catch { |
10197 | |
10198 | namespace { |
10199 | static auto getSingletons() -> std::vector<ISingleton*>*& { |
10200 | static std::vector<ISingleton*>* g_singletons = nullptr; |
10201 | if( !g_singletons ) |
10202 | g_singletons = new std::vector<ISingleton*>(); |
10203 | return g_singletons; |
10204 | } |
10205 | } |
10206 | |
10207 | ISingleton::~ISingleton() {} |
10208 | |
10209 | void addSingleton(ISingleton* singleton ) { |
10210 | getSingletons()->push_back( singleton ); |
10211 | } |
10212 | void cleanupSingletons() { |
10213 | auto& singletons = getSingletons(); |
10214 | for( auto singleton : *singletons ) |
10215 | delete singleton; |
10216 | delete singletons; |
10217 | singletons = nullptr; |
10218 | } |
10219 | |
10220 | } // namespace Catch |
10221 | // end catch_singletons.cpp |
10222 | // start catch_startup_exception_registry.cpp |
10223 | |
10224 | namespace Catch { |
10225 | void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept { |
10226 | CATCH_TRY { |
10227 | m_exceptions.push_back(exception); |
10228 | } CATCH_CATCH_ALL { |
10229 | // If we run out of memory during start-up there's really not a lot more we can do about it |
10230 | std::terminate(); |
10231 | } |
10232 | } |
10233 | |
10234 | std::vector<std::exception_ptr> const& StartupExceptionRegistry::getExceptions() const noexcept { |
10235 | return m_exceptions; |
10236 | } |
10237 | |
10238 | } // end namespace Catch |
10239 | // end catch_startup_exception_registry.cpp |
10240 | // start catch_stream.cpp |
10241 | |
10242 | #include <cstdio> |
10243 | #include <iostream> |
10244 | #include <fstream> |
10245 | #include <sstream> |
10246 | #include <vector> |
10247 | #include <memory> |
10248 | |
10249 | namespace Catch { |
10250 | |
10251 | Catch::IStream::~IStream() = default; |
10252 | |
10253 | namespace detail { namespace { |
10254 | template<typename WriterF, std::size_t bufferSize=256> |
10255 | class StreamBufImpl : public std::streambuf { |
10256 | char data[bufferSize]; |
10257 | WriterF m_writer; |
10258 | |
10259 | public: |
10260 | StreamBufImpl() { |
10261 | setp( data, data + sizeof(data) ); |
10262 | } |
10263 | |
10264 | ~StreamBufImpl() noexcept { |
10265 | StreamBufImpl::sync(); |
10266 | } |
10267 | |
10268 | private: |
10269 | int overflow( int c ) override { |
10270 | sync(); |
10271 | |
10272 | if( c != EOF ) { |
10273 | if( pbase() == epptr() ) |
10274 | m_writer( std::string( 1, static_cast<char>( c ) ) ); |
10275 | else |
10276 | sputc( static_cast<char>( c ) ); |
10277 | } |
10278 | return 0; |
10279 | } |
10280 | |
10281 | int sync() override { |
10282 | if( pbase() != pptr() ) { |
10283 | m_writer( std::string( pbase(), static_cast<std::string::size_type>( pptr() - pbase() ) ) ); |
10284 | setp( pbase(), epptr() ); |
10285 | } |
10286 | return 0; |
10287 | } |
10288 | }; |
10289 | |
10290 | /////////////////////////////////////////////////////////////////////////// |
10291 | |
10292 | struct OutputDebugWriter { |
10293 | |
10294 | void operator()( std::string const&str ) { |
10295 | writeToDebugConsole( str ); |
10296 | } |
10297 | }; |
10298 | |
10299 | /////////////////////////////////////////////////////////////////////////// |
10300 | |
10301 | class FileStream : public IStream { |
10302 | mutable std::ofstream m_ofs; |
10303 | public: |
10304 | FileStream( StringRef filename ) { |
10305 | m_ofs.open( filename.c_str() ); |
10306 | CATCH_ENFORCE( !m_ofs.fail(), "Unable to open file: '" << filename << "'" ); |
10307 | } |
10308 | ~FileStream() override = default; |
10309 | public: // IStream |
10310 | std::ostream& stream() const override { |
10311 | return m_ofs; |
10312 | } |
10313 | }; |
10314 | |
10315 | /////////////////////////////////////////////////////////////////////////// |
10316 | |
10317 | class CoutStream : public IStream { |
10318 | mutable std::ostream m_os; |
10319 | public: |
10320 | // Store the streambuf from cout up-front because |
10321 | // cout may get redirected when running tests |
10322 | CoutStream() : m_os( Catch::cout().rdbuf() ) {} |
10323 | ~CoutStream() override = default; |
10324 | |
10325 | public: // IStream |
10326 | std::ostream& stream() const override { return m_os; } |
10327 | }; |
10328 | |
10329 | /////////////////////////////////////////////////////////////////////////// |
10330 | |
10331 | class DebugOutStream : public IStream { |
10332 | std::unique_ptr<StreamBufImpl<OutputDebugWriter>> m_streamBuf; |
10333 | mutable std::ostream m_os; |
10334 | public: |
10335 | DebugOutStream() |
10336 | : m_streamBuf( new StreamBufImpl<OutputDebugWriter>() ), |
10337 | m_os( m_streamBuf.get() ) |
10338 | {} |
10339 | |
10340 | ~DebugOutStream() override = default; |
10341 | |
10342 | public: // IStream |
10343 | std::ostream& stream() const override { return m_os; } |
10344 | }; |
10345 | |
10346 | }} // namespace anon::detail |
10347 | |
10348 | /////////////////////////////////////////////////////////////////////////// |
10349 | |
10350 | auto makeStream( StringRef const &filename ) -> IStream const* { |
10351 | if( filename.empty() ) |
10352 | return new detail::CoutStream(); |
10353 | else if( filename[0] == '%' ) { |
10354 | if( filename == "%debug" ) |
10355 | return new detail::DebugOutStream(); |
10356 | else |
10357 | CATCH_ERROR( "Unrecognised stream: '" << filename << "'" ); |
10358 | } |
10359 | else |
10360 | return new detail::FileStream( filename ); |
10361 | } |
10362 | |
10363 | // This class encapsulates the idea of a pool of ostringstreams that can be reused. |
10364 | struct StringStreams { |
10365 | std::vector<std::unique_ptr<std::ostringstream>> m_streams; |
10366 | std::vector<std::size_t> m_unused; |
10367 | std::ostringstream m_referenceStream; // Used for copy state/ flags from |
10368 | |
10369 | auto add() -> std::size_t { |
10370 | if( m_unused.empty() ) { |
10371 | m_streams.push_back( std::unique_ptr<std::ostringstream>( new std::ostringstream ) ); |
10372 | return m_streams.size()-1; |
10373 | } |
10374 | else { |
10375 | auto index = m_unused.back(); |
10376 | m_unused.pop_back(); |
10377 | return index; |
10378 | } |
10379 | } |
10380 | |
10381 | void release( std::size_t index ) { |
10382 | m_streams[index]->copyfmt( m_referenceStream ); // Restore initial flags and other state |
10383 | m_unused.push_back(index); |
10384 | } |
10385 | }; |
10386 | |
10387 | ReusableStringStream::ReusableStringStream() |
10388 | : m_index( Singleton<StringStreams>::getMutable().add() ), |
10389 | m_oss( Singleton<StringStreams>::getMutable().m_streams[m_index].get() ) |
10390 | {} |
10391 | |
10392 | ReusableStringStream::~ReusableStringStream() { |
10393 | static_cast<std::ostringstream*>( m_oss )->str("" ); |
10394 | m_oss->clear(); |
10395 | Singleton<StringStreams>::getMutable().release( m_index ); |
10396 | } |
10397 | |
10398 | auto ReusableStringStream::str() const -> std::string { |
10399 | return static_cast<std::ostringstream*>( m_oss )->str(); |
10400 | } |
10401 | |
10402 | /////////////////////////////////////////////////////////////////////////// |
10403 | |
10404 | #ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions |
10405 | std::ostream& cout() { return std::cout; } |
10406 | std::ostream& cerr() { return std::cerr; } |
10407 | std::ostream& clog() { return std::clog; } |
10408 | #endif |
10409 | } |
10410 | // end catch_stream.cpp |
10411 | // start catch_string_manip.cpp |
10412 | |
10413 | #include <algorithm> |
10414 | #include <ostream> |
10415 | #include <cstring> |
10416 | #include <cctype> |
10417 | |
10418 | namespace Catch { |
10419 | |
10420 | namespace { |
10421 | char toLowerCh(char c) { |
10422 | return static_cast<char>( std::tolower( c ) ); |
10423 | } |
10424 | } |
10425 | |
10426 | bool startsWith( std::string const& s, std::string const& prefix ) { |
10427 | return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin()); |
10428 | } |
10429 | bool startsWith( std::string const& s, char prefix ) { |
10430 | return !s.empty() && s[0] == prefix; |
10431 | } |
10432 | bool endsWith( std::string const& s, std::string const& suffix ) { |
10433 | return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin()); |
10434 | } |
10435 | bool endsWith( std::string const& s, char suffix ) { |
10436 | return !s.empty() && s[s.size()-1] == suffix; |
10437 | } |
10438 | bool contains( std::string const& s, std::string const& infix ) { |
10439 | return s.find( infix ) != std::string::npos; |
10440 | } |
10441 | void toLowerInPlace( std::string& s ) { |
10442 | std::transform( s.begin(), s.end(), s.begin(), toLowerCh ); |
10443 | } |
10444 | std::string toLower( std::string const& s ) { |
10445 | std::string lc = s; |
10446 | toLowerInPlace( lc ); |
10447 | return lc; |
10448 | } |
10449 | std::string trim( std::string const& str ) { |
10450 | static char const* whitespaceChars = "\n\r\t " ; |
10451 | std::string::size_type start = str.find_first_not_of( whitespaceChars ); |
10452 | std::string::size_type end = str.find_last_not_of( whitespaceChars ); |
10453 | |
10454 | return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string(); |
10455 | } |
10456 | |
10457 | bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { |
10458 | bool replaced = false; |
10459 | std::size_t i = str.find( replaceThis ); |
10460 | while( i != std::string::npos ) { |
10461 | replaced = true; |
10462 | str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() ); |
10463 | if( i < str.size()-withThis.size() ) |
10464 | i = str.find( replaceThis, i+withThis.size() ); |
10465 | else |
10466 | i = std::string::npos; |
10467 | } |
10468 | return replaced; |
10469 | } |
10470 | |
10471 | pluralise::pluralise( std::size_t count, std::string const& label ) |
10472 | : m_count( count ), |
10473 | m_label( label ) |
10474 | {} |
10475 | |
10476 | std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { |
10477 | os << pluraliser.m_count << ' ' << pluraliser.m_label; |
10478 | if( pluraliser.m_count != 1 ) |
10479 | os << 's'; |
10480 | return os; |
10481 | } |
10482 | |
10483 | } |
10484 | // end catch_string_manip.cpp |
10485 | // start catch_stringref.cpp |
10486 | |
10487 | #if defined(__clang__) |
10488 | # pragma clang diagnostic push |
10489 | # pragma clang diagnostic ignored "-Wexit-time-destructors" |
10490 | #endif |
10491 | |
10492 | #include <ostream> |
10493 | #include <cstring> |
10494 | #include <cstdint> |
10495 | |
10496 | namespace { |
10497 | const uint32_t byte_2_lead = 0xC0; |
10498 | const uint32_t byte_3_lead = 0xE0; |
10499 | const uint32_t byte_4_lead = 0xF0; |
10500 | } |
10501 | |
10502 | namespace Catch { |
10503 | StringRef::StringRef( char const* rawChars ) noexcept |
10504 | : StringRef( rawChars, static_cast<StringRef::size_type>(std::strlen(rawChars) ) ) |
10505 | {} |
10506 | |
10507 | StringRef::operator std::string() const { |
10508 | return std::string( m_start, m_size ); |
10509 | } |
10510 | |
10511 | void StringRef::swap( StringRef& other ) noexcept { |
10512 | std::swap( m_start, other.m_start ); |
10513 | std::swap( m_size, other.m_size ); |
10514 | std::swap( m_data, other.m_data ); |
10515 | } |
10516 | |
10517 | auto StringRef::c_str() const -> char const* { |
10518 | if( isSubstring() ) |
10519 | const_cast<StringRef*>( this )->takeOwnership(); |
10520 | return m_start; |
10521 | } |
10522 | auto StringRef::currentData() const noexcept -> char const* { |
10523 | return m_start; |
10524 | } |
10525 | |
10526 | auto StringRef::isOwned() const noexcept -> bool { |
10527 | return m_data != nullptr; |
10528 | } |
10529 | auto StringRef::isSubstring() const noexcept -> bool { |
10530 | return m_start[m_size] != '\0'; |
10531 | } |
10532 | |
10533 | void StringRef::takeOwnership() { |
10534 | if( !isOwned() ) { |
10535 | m_data = new char[m_size+1]; |
10536 | memcpy( m_data, m_start, m_size ); |
10537 | m_data[m_size] = '\0'; |
10538 | m_start = m_data; |
10539 | } |
10540 | } |
10541 | auto StringRef::substr( size_type start, size_type size ) const noexcept -> StringRef { |
10542 | if( start < m_size ) |
10543 | return StringRef( m_start+start, size ); |
10544 | else |
10545 | return StringRef(); |
10546 | } |
10547 | auto StringRef::operator == ( StringRef const& other ) const noexcept -> bool { |
10548 | return |
10549 | size() == other.size() && |
10550 | (std::strncmp( m_start, other.m_start, size() ) == 0); |
10551 | } |
10552 | auto StringRef::operator != ( StringRef const& other ) const noexcept -> bool { |
10553 | return !operator==( other ); |
10554 | } |
10555 | |
10556 | auto StringRef::operator[](size_type index) const noexcept -> char { |
10557 | return m_start[index]; |
10558 | } |
10559 | |
10560 | auto StringRef::numberOfCharacters() const noexcept -> size_type { |
10561 | size_type noChars = m_size; |
10562 | // Make adjustments for uft encodings |
10563 | for( size_type i=0; i < m_size; ++i ) { |
10564 | char c = m_start[i]; |
10565 | if( ( c & byte_2_lead ) == byte_2_lead ) { |
10566 | noChars--; |
10567 | if (( c & byte_3_lead ) == byte_3_lead ) |
10568 | noChars--; |
10569 | if( ( c & byte_4_lead ) == byte_4_lead ) |
10570 | noChars--; |
10571 | } |
10572 | } |
10573 | return noChars; |
10574 | } |
10575 | |
10576 | auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string { |
10577 | std::string str; |
10578 | str.reserve( lhs.size() + rhs.size() ); |
10579 | str += lhs; |
10580 | str += rhs; |
10581 | return str; |
10582 | } |
10583 | auto operator + ( StringRef const& lhs, const char* rhs ) -> std::string { |
10584 | return std::string( lhs ) + std::string( rhs ); |
10585 | } |
10586 | auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string { |
10587 | return std::string( lhs ) + std::string( rhs ); |
10588 | } |
10589 | |
10590 | auto operator << ( std::ostream& os, StringRef const& str ) -> std::ostream& { |
10591 | return os.write(str.currentData(), str.size()); |
10592 | } |
10593 | |
10594 | auto operator+=( std::string& lhs, StringRef const& rhs ) -> std::string& { |
10595 | lhs.append(rhs.currentData(), rhs.size()); |
10596 | return lhs; |
10597 | } |
10598 | |
10599 | } // namespace Catch |
10600 | |
10601 | #if defined(__clang__) |
10602 | # pragma clang diagnostic pop |
10603 | #endif |
10604 | // end catch_stringref.cpp |
10605 | // start catch_tag_alias.cpp |
10606 | |
10607 | namespace Catch { |
10608 | TagAlias::TagAlias(std::string const & _tag, SourceLineInfo _lineInfo): tag(_tag), lineInfo(_lineInfo) {} |
10609 | } |
10610 | // end catch_tag_alias.cpp |
10611 | // start catch_tag_alias_autoregistrar.cpp |
10612 | |
10613 | namespace Catch { |
10614 | |
10615 | RegistrarForTagAliases::RegistrarForTagAliases(char const* alias, char const* tag, SourceLineInfo const& lineInfo) { |
10616 | CATCH_TRY { |
10617 | getMutableRegistryHub().registerTagAlias(alias, tag, lineInfo); |
10618 | } CATCH_CATCH_ALL { |
10619 | // Do not throw when constructing global objects, instead register the exception to be processed later |
10620 | getMutableRegistryHub().registerStartupException(); |
10621 | } |
10622 | } |
10623 | |
10624 | } |
10625 | // end catch_tag_alias_autoregistrar.cpp |
10626 | // start catch_tag_alias_registry.cpp |
10627 | |
10628 | #include <sstream> |
10629 | |
10630 | namespace Catch { |
10631 | |
10632 | TagAliasRegistry::~TagAliasRegistry() {} |
10633 | |
10634 | TagAlias const* TagAliasRegistry::find( std::string const& alias ) const { |
10635 | auto it = m_registry.find( alias ); |
10636 | if( it != m_registry.end() ) |
10637 | return &(it->second); |
10638 | else |
10639 | return nullptr; |
10640 | } |
10641 | |
10642 | std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { |
10643 | std::string expandedTestSpec = unexpandedTestSpec; |
10644 | for( auto const& registryKvp : m_registry ) { |
10645 | std::size_t pos = expandedTestSpec.find( registryKvp.first ); |
10646 | if( pos != std::string::npos ) { |
10647 | expandedTestSpec = expandedTestSpec.substr( 0, pos ) + |
10648 | registryKvp.second.tag + |
10649 | expandedTestSpec.substr( pos + registryKvp.first.size() ); |
10650 | } |
10651 | } |
10652 | return expandedTestSpec; |
10653 | } |
10654 | |
10655 | void TagAliasRegistry::add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) { |
10656 | CATCH_ENFORCE( startsWith(alias, "[@" ) && endsWith(alias, ']'), |
10657 | "error: tag alias, '" << alias << "' is not of the form [@alias name].\n" << lineInfo ); |
10658 | |
10659 | CATCH_ENFORCE( m_registry.insert(std::make_pair(alias, TagAlias(tag, lineInfo))).second, |
10660 | "error: tag alias, '" << alias << "' already registered.\n" |
10661 | << "\tFirst seen at: " << find(alias)->lineInfo << "\n" |
10662 | << "\tRedefined at: " << lineInfo ); |
10663 | } |
10664 | |
10665 | ITagAliasRegistry::~ITagAliasRegistry() {} |
10666 | |
10667 | ITagAliasRegistry const& ITagAliasRegistry::get() { |
10668 | return getRegistryHub().getTagAliasRegistry(); |
10669 | } |
10670 | |
10671 | } // end namespace Catch |
10672 | // end catch_tag_alias_registry.cpp |
10673 | // start catch_test_case_info.cpp |
10674 | |
10675 | #include <cctype> |
10676 | #include <exception> |
10677 | #include <algorithm> |
10678 | #include <sstream> |
10679 | |
10680 | namespace Catch { |
10681 | |
10682 | namespace { |
10683 | TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { |
10684 | if( startsWith( tag, '.' ) || |
10685 | tag == "!hide" ) |
10686 | return TestCaseInfo::IsHidden; |
10687 | else if( tag == "!throws" ) |
10688 | return TestCaseInfo::Throws; |
10689 | else if( tag == "!shouldfail" ) |
10690 | return TestCaseInfo::ShouldFail; |
10691 | else if( tag == "!mayfail" ) |
10692 | return TestCaseInfo::MayFail; |
10693 | else if( tag == "!nonportable" ) |
10694 | return TestCaseInfo::NonPortable; |
10695 | else if( tag == "!benchmark" ) |
10696 | return static_cast<TestCaseInfo::SpecialProperties>( TestCaseInfo::Benchmark | TestCaseInfo::IsHidden ); |
10697 | else |
10698 | return TestCaseInfo::None; |
10699 | } |
10700 | bool isReservedTag( std::string const& tag ) { |
10701 | return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( static_cast<unsigned char>(tag[0]) ); |
10702 | } |
10703 | void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { |
10704 | CATCH_ENFORCE( !isReservedTag(tag), |
10705 | "Tag name: [" << tag << "] is not allowed.\n" |
10706 | << "Tag names starting with non alpha-numeric characters are reserved\n" |
10707 | << _lineInfo ); |
10708 | } |
10709 | } |
10710 | |
10711 | TestCase makeTestCase( ITestInvoker* _testCase, |
10712 | std::string const& _className, |
10713 | NameAndTags const& nameAndTags, |
10714 | SourceLineInfo const& _lineInfo ) |
10715 | { |
10716 | bool isHidden = false; |
10717 | |
10718 | // Parse out tags |
10719 | std::vector<std::string> tags; |
10720 | std::string desc, tag; |
10721 | bool inTag = false; |
10722 | std::string _descOrTags = nameAndTags.tags; |
10723 | for (char c : _descOrTags) { |
10724 | if( !inTag ) { |
10725 | if( c == '[' ) |
10726 | inTag = true; |
10727 | else |
10728 | desc += c; |
10729 | } |
10730 | else { |
10731 | if( c == ']' ) { |
10732 | TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag ); |
10733 | if( ( prop & TestCaseInfo::IsHidden ) != 0 ) |
10734 | isHidden = true; |
10735 | else if( prop == TestCaseInfo::None ) |
10736 | enforceNotReservedTag( tag, _lineInfo ); |
10737 | |
10738 | tags.push_back( tag ); |
10739 | tag.clear(); |
10740 | inTag = false; |
10741 | } |
10742 | else |
10743 | tag += c; |
10744 | } |
10745 | } |
10746 | if( isHidden ) { |
10747 | tags.push_back( "." ); |
10748 | } |
10749 | |
10750 | TestCaseInfo info( nameAndTags.name, _className, desc, tags, _lineInfo ); |
10751 | return TestCase( _testCase, std::move(info) ); |
10752 | } |
10753 | |
10754 | void setTags( TestCaseInfo& testCaseInfo, std::vector<std::string> tags ) { |
10755 | std::sort(begin(tags), end(tags)); |
10756 | tags.erase(std::unique(begin(tags), end(tags)), end(tags)); |
10757 | testCaseInfo.lcaseTags.clear(); |
10758 | |
10759 | for( auto const& tag : tags ) { |
10760 | std::string lcaseTag = toLower( tag ); |
10761 | testCaseInfo.properties = static_cast<TestCaseInfo::SpecialProperties>( testCaseInfo.properties | parseSpecialTag( lcaseTag ) ); |
10762 | testCaseInfo.lcaseTags.push_back( lcaseTag ); |
10763 | } |
10764 | testCaseInfo.tags = std::move(tags); |
10765 | } |
10766 | |
10767 | TestCaseInfo::TestCaseInfo( std::string const& _name, |
10768 | std::string const& _className, |
10769 | std::string const& _description, |
10770 | std::vector<std::string> const& _tags, |
10771 | SourceLineInfo const& _lineInfo ) |
10772 | : name( _name ), |
10773 | className( _className ), |
10774 | description( _description ), |
10775 | lineInfo( _lineInfo ), |
10776 | properties( None ) |
10777 | { |
10778 | setTags( *this, _tags ); |
10779 | } |
10780 | |
10781 | bool TestCaseInfo::isHidden() const { |
10782 | return ( properties & IsHidden ) != 0; |
10783 | } |
10784 | bool TestCaseInfo::throws() const { |
10785 | return ( properties & Throws ) != 0; |
10786 | } |
10787 | bool TestCaseInfo::okToFail() const { |
10788 | return ( properties & (ShouldFail | MayFail ) ) != 0; |
10789 | } |
10790 | bool TestCaseInfo::expectedToFail() const { |
10791 | return ( properties & (ShouldFail ) ) != 0; |
10792 | } |
10793 | |
10794 | std::string TestCaseInfo::tagsAsString() const { |
10795 | std::string ret; |
10796 | // '[' and ']' per tag |
10797 | std::size_t full_size = 2 * tags.size(); |
10798 | for (const auto& tag : tags) { |
10799 | full_size += tag.size(); |
10800 | } |
10801 | ret.reserve(full_size); |
10802 | for (const auto& tag : tags) { |
10803 | ret.push_back('['); |
10804 | ret.append(tag); |
10805 | ret.push_back(']'); |
10806 | } |
10807 | |
10808 | return ret; |
10809 | } |
10810 | |
10811 | TestCase::TestCase( ITestInvoker* testCase, TestCaseInfo&& info ) : TestCaseInfo( std::move(info) ), test( testCase ) {} |
10812 | |
10813 | TestCase TestCase::withName( std::string const& _newName ) const { |
10814 | TestCase other( *this ); |
10815 | other.name = _newName; |
10816 | return other; |
10817 | } |
10818 | |
10819 | void TestCase::invoke() const { |
10820 | test->invoke(); |
10821 | } |
10822 | |
10823 | bool TestCase::operator == ( TestCase const& other ) const { |
10824 | return test.get() == other.test.get() && |
10825 | name == other.name && |
10826 | className == other.className; |
10827 | } |
10828 | |
10829 | bool TestCase::operator < ( TestCase const& other ) const { |
10830 | return name < other.name; |
10831 | } |
10832 | |
10833 | TestCaseInfo const& TestCase::getTestCaseInfo() const |
10834 | { |
10835 | return *this; |
10836 | } |
10837 | |
10838 | } // end namespace Catch |
10839 | // end catch_test_case_info.cpp |
10840 | // start catch_test_case_registry_impl.cpp |
10841 | |
10842 | #include <sstream> |
10843 | |
10844 | namespace Catch { |
10845 | |
10846 | std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) { |
10847 | |
10848 | std::vector<TestCase> sorted = unsortedTestCases; |
10849 | |
10850 | switch( config.runOrder() ) { |
10851 | case RunTests::InLexicographicalOrder: |
10852 | std::sort( sorted.begin(), sorted.end() ); |
10853 | break; |
10854 | case RunTests::InRandomOrder: |
10855 | seedRng( config ); |
10856 | std::shuffle( sorted.begin(), sorted.end(), rng() ); |
10857 | break; |
10858 | case RunTests::InDeclarationOrder: |
10859 | // already in declaration order |
10860 | break; |
10861 | } |
10862 | return sorted; |
10863 | } |
10864 | bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) { |
10865 | return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() ); |
10866 | } |
10867 | |
10868 | void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions ) { |
10869 | std::set<TestCase> seenFunctions; |
10870 | for( auto const& function : functions ) { |
10871 | auto prev = seenFunctions.insert( function ); |
10872 | CATCH_ENFORCE( prev.second, |
10873 | "error: TEST_CASE( \"" << function.name << "\" ) already defined.\n" |
10874 | << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" |
10875 | << "\tRedefined at " << function.getTestCaseInfo().lineInfo ); |
10876 | } |
10877 | } |
10878 | |
10879 | std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ) { |
10880 | std::vector<TestCase> filtered; |
10881 | filtered.reserve( testCases.size() ); |
10882 | for( auto const& testCase : testCases ) |
10883 | if( matchTest( testCase, testSpec, config ) ) |
10884 | filtered.push_back( testCase ); |
10885 | return filtered; |
10886 | } |
10887 | std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ) { |
10888 | return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config ); |
10889 | } |
10890 | |
10891 | void TestRegistry::registerTest( TestCase const& testCase ) { |
10892 | std::string name = testCase.getTestCaseInfo().name; |
10893 | if( name.empty() ) { |
10894 | ReusableStringStream ; |
10895 | rss << "Anonymous test case " << ++m_unnamedCount; |
10896 | return registerTest( testCase.withName( rss.str() ) ); |
10897 | } |
10898 | m_functions.push_back( testCase ); |
10899 | } |
10900 | |
10901 | std::vector<TestCase> const& TestRegistry::getAllTests() const { |
10902 | return m_functions; |
10903 | } |
10904 | std::vector<TestCase> const& TestRegistry::getAllTestsSorted( IConfig const& config ) const { |
10905 | if( m_sortedFunctions.empty() ) |
10906 | enforceNoDuplicateTestCases( m_functions ); |
10907 | |
10908 | if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) { |
10909 | m_sortedFunctions = sortTests( config, m_functions ); |
10910 | m_currentSortOrder = config.runOrder(); |
10911 | } |
10912 | return m_sortedFunctions; |
10913 | } |
10914 | |
10915 | /////////////////////////////////////////////////////////////////////////// |
10916 | TestInvokerAsFunction::TestInvokerAsFunction( void(*testAsFunction)() ) noexcept : m_testAsFunction( testAsFunction ) {} |
10917 | |
10918 | void TestInvokerAsFunction::invoke() const { |
10919 | m_testAsFunction(); |
10920 | } |
10921 | |
10922 | std::string ( StringRef const& classOrQualifiedMethodName ) { |
10923 | std::string className = classOrQualifiedMethodName; |
10924 | if( startsWith( className, '&' ) ) |
10925 | { |
10926 | std::size_t lastColons = className.rfind( "::" ); |
10927 | std::size_t penultimateColons = className.rfind( "::" , lastColons-1 ); |
10928 | if( penultimateColons == std::string::npos ) |
10929 | penultimateColons = 1; |
10930 | className = className.substr( penultimateColons, lastColons-penultimateColons ); |
10931 | } |
10932 | return className; |
10933 | } |
10934 | |
10935 | } // end namespace Catch |
10936 | // end catch_test_case_registry_impl.cpp |
10937 | // start catch_test_case_tracker.cpp |
10938 | |
10939 | #include <algorithm> |
10940 | #include <cassert> |
10941 | #include <stdexcept> |
10942 | #include <memory> |
10943 | #include <sstream> |
10944 | |
10945 | #if defined(__clang__) |
10946 | # pragma clang diagnostic push |
10947 | # pragma clang diagnostic ignored "-Wexit-time-destructors" |
10948 | #endif |
10949 | |
10950 | namespace Catch { |
10951 | namespace TestCaseTracking { |
10952 | |
10953 | NameAndLocation::NameAndLocation( std::string const& _name, SourceLineInfo const& _location ) |
10954 | : name( _name ), |
10955 | location( _location ) |
10956 | {} |
10957 | |
10958 | ITracker::~ITracker() = default; |
10959 | |
10960 | TrackerContext& TrackerContext::instance() { |
10961 | static TrackerContext s_instance; |
10962 | return s_instance; |
10963 | } |
10964 | |
10965 | ITracker& TrackerContext::startRun() { |
10966 | m_rootTracker = std::make_shared<SectionTracker>( NameAndLocation( "{root}" , CATCH_INTERNAL_LINEINFO ), *this, nullptr ); |
10967 | m_currentTracker = nullptr; |
10968 | m_runState = Executing; |
10969 | return *m_rootTracker; |
10970 | } |
10971 | |
10972 | void TrackerContext::endRun() { |
10973 | m_rootTracker.reset(); |
10974 | m_currentTracker = nullptr; |
10975 | m_runState = NotStarted; |
10976 | } |
10977 | |
10978 | void TrackerContext::startCycle() { |
10979 | m_currentTracker = m_rootTracker.get(); |
10980 | m_runState = Executing; |
10981 | } |
10982 | void TrackerContext::completeCycle() { |
10983 | m_runState = CompletedCycle; |
10984 | } |
10985 | |
10986 | bool TrackerContext::completedCycle() const { |
10987 | return m_runState == CompletedCycle; |
10988 | } |
10989 | ITracker& TrackerContext::currentTracker() { |
10990 | return *m_currentTracker; |
10991 | } |
10992 | void TrackerContext::setCurrentTracker( ITracker* tracker ) { |
10993 | m_currentTracker = tracker; |
10994 | } |
10995 | |
10996 | TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) |
10997 | : m_nameAndLocation( nameAndLocation ), |
10998 | m_ctx( ctx ), |
10999 | m_parent( parent ) |
11000 | {} |
11001 | |
11002 | NameAndLocation const& TrackerBase::nameAndLocation() const { |
11003 | return m_nameAndLocation; |
11004 | } |
11005 | bool TrackerBase::isComplete() const { |
11006 | return m_runState == CompletedSuccessfully || m_runState == Failed; |
11007 | } |
11008 | bool TrackerBase::isSuccessfullyCompleted() const { |
11009 | return m_runState == CompletedSuccessfully; |
11010 | } |
11011 | bool TrackerBase::isOpen() const { |
11012 | return m_runState != NotStarted && !isComplete(); |
11013 | } |
11014 | bool TrackerBase::hasChildren() const { |
11015 | return !m_children.empty(); |
11016 | } |
11017 | |
11018 | void TrackerBase::addChild( ITrackerPtr const& child ) { |
11019 | m_children.push_back( child ); |
11020 | } |
11021 | |
11022 | ITrackerPtr TrackerBase::findChild( NameAndLocation const& nameAndLocation ) { |
11023 | auto it = std::find_if( m_children.begin(), m_children.end(), |
11024 | [&nameAndLocation]( ITrackerPtr const& tracker ){ |
11025 | return |
11026 | tracker->nameAndLocation().location == nameAndLocation.location && |
11027 | tracker->nameAndLocation().name == nameAndLocation.name; |
11028 | } ); |
11029 | return( it != m_children.end() ) |
11030 | ? *it |
11031 | : nullptr; |
11032 | } |
11033 | ITracker& TrackerBase::parent() { |
11034 | assert( m_parent ); // Should always be non-null except for root |
11035 | return *m_parent; |
11036 | } |
11037 | |
11038 | void TrackerBase::openChild() { |
11039 | if( m_runState != ExecutingChildren ) { |
11040 | m_runState = ExecutingChildren; |
11041 | if( m_parent ) |
11042 | m_parent->openChild(); |
11043 | } |
11044 | } |
11045 | |
11046 | bool TrackerBase::isSectionTracker() const { return false; } |
11047 | bool TrackerBase::() const { return false; } |
11048 | |
11049 | void TrackerBase::open() { |
11050 | m_runState = Executing; |
11051 | moveToThis(); |
11052 | if( m_parent ) |
11053 | m_parent->openChild(); |
11054 | } |
11055 | |
11056 | void TrackerBase::close() { |
11057 | |
11058 | // Close any still open children (e.g. generators) |
11059 | while( &m_ctx.currentTracker() != this ) |
11060 | m_ctx.currentTracker().close(); |
11061 | |
11062 | switch( m_runState ) { |
11063 | case NeedsAnotherRun: |
11064 | break; |
11065 | |
11066 | case Executing: |
11067 | m_runState = CompletedSuccessfully; |
11068 | break; |
11069 | case ExecutingChildren: |
11070 | if( m_children.empty() || m_children.back()->isComplete() ) |
11071 | m_runState = CompletedSuccessfully; |
11072 | break; |
11073 | |
11074 | case NotStarted: |
11075 | case CompletedSuccessfully: |
11076 | case Failed: |
11077 | CATCH_INTERNAL_ERROR( "Illogical state: " << m_runState ); |
11078 | |
11079 | default: |
11080 | CATCH_INTERNAL_ERROR( "Unknown state: " << m_runState ); |
11081 | } |
11082 | moveToParent(); |
11083 | m_ctx.completeCycle(); |
11084 | } |
11085 | void TrackerBase::fail() { |
11086 | m_runState = Failed; |
11087 | if( m_parent ) |
11088 | m_parent->markAsNeedingAnotherRun(); |
11089 | moveToParent(); |
11090 | m_ctx.completeCycle(); |
11091 | } |
11092 | void TrackerBase::markAsNeedingAnotherRun() { |
11093 | m_runState = NeedsAnotherRun; |
11094 | } |
11095 | |
11096 | void TrackerBase::moveToParent() { |
11097 | assert( m_parent ); |
11098 | m_ctx.setCurrentTracker( m_parent ); |
11099 | } |
11100 | void TrackerBase::moveToThis() { |
11101 | m_ctx.setCurrentTracker( this ); |
11102 | } |
11103 | |
11104 | SectionTracker::SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) |
11105 | : TrackerBase( nameAndLocation, ctx, parent ) |
11106 | { |
11107 | if( parent ) { |
11108 | while( !parent->isSectionTracker() ) |
11109 | parent = &parent->parent(); |
11110 | |
11111 | SectionTracker& parentSection = static_cast<SectionTracker&>( *parent ); |
11112 | addNextFilters( parentSection.m_filters ); |
11113 | } |
11114 | } |
11115 | |
11116 | bool SectionTracker::isSectionTracker() const { return true; } |
11117 | |
11118 | SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) { |
11119 | std::shared_ptr<SectionTracker> section; |
11120 | |
11121 | ITracker& currentTracker = ctx.currentTracker(); |
11122 | if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { |
11123 | assert( childTracker ); |
11124 | assert( childTracker->isSectionTracker() ); |
11125 | section = std::static_pointer_cast<SectionTracker>( childTracker ); |
11126 | } |
11127 | else { |
11128 | section = std::make_shared<SectionTracker>( nameAndLocation, ctx, ¤tTracker ); |
11129 | currentTracker.addChild( section ); |
11130 | } |
11131 | if( !ctx.completedCycle() ) |
11132 | section->tryOpen(); |
11133 | return *section; |
11134 | } |
11135 | |
11136 | void SectionTracker::tryOpen() { |
11137 | if( !isComplete() && (m_filters.empty() || m_filters[0].empty() || m_filters[0] == m_nameAndLocation.name ) ) |
11138 | open(); |
11139 | } |
11140 | |
11141 | void SectionTracker::addInitialFilters( std::vector<std::string> const& filters ) { |
11142 | if( !filters.empty() ) { |
11143 | m_filters.push_back("" ); // Root - should never be consulted |
11144 | m_filters.push_back("" ); // Test Case - not a section filter |
11145 | m_filters.insert( m_filters.end(), filters.begin(), filters.end() ); |
11146 | } |
11147 | } |
11148 | void SectionTracker::addNextFilters( std::vector<std::string> const& filters ) { |
11149 | if( filters.size() > 1 ) |
11150 | m_filters.insert( m_filters.end(), ++filters.begin(), filters.end() ); |
11151 | } |
11152 | |
11153 | IndexTracker::IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size ) |
11154 | : TrackerBase( nameAndLocation, ctx, parent ), |
11155 | m_size( size ) |
11156 | {} |
11157 | |
11158 | bool IndexTracker::() const { return true; } |
11159 | |
11160 | IndexTracker& IndexTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ) { |
11161 | std::shared_ptr<IndexTracker> tracker; |
11162 | |
11163 | ITracker& currentTracker = ctx.currentTracker(); |
11164 | if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { |
11165 | assert( childTracker ); |
11166 | assert( childTracker->isIndexTracker() ); |
11167 | tracker = std::static_pointer_cast<IndexTracker>( childTracker ); |
11168 | } |
11169 | else { |
11170 | tracker = std::make_shared<IndexTracker>( nameAndLocation, ctx, ¤tTracker, size ); |
11171 | currentTracker.addChild( tracker ); |
11172 | } |
11173 | |
11174 | if( !ctx.completedCycle() && !tracker->isComplete() ) { |
11175 | if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun ) |
11176 | tracker->moveNext(); |
11177 | tracker->open(); |
11178 | } |
11179 | |
11180 | return *tracker; |
11181 | } |
11182 | |
11183 | int IndexTracker::() const { return m_index; } |
11184 | |
11185 | void IndexTracker::() { |
11186 | m_index++; |
11187 | m_children.clear(); |
11188 | } |
11189 | |
11190 | void IndexTracker::() { |
11191 | TrackerBase::close(); |
11192 | if( m_runState == CompletedSuccessfully && m_index < m_size-1 ) |
11193 | m_runState = Executing; |
11194 | } |
11195 | |
11196 | } // namespace TestCaseTracking |
11197 | |
11198 | using TestCaseTracking::ITracker; |
11199 | using TestCaseTracking::TrackerContext; |
11200 | using TestCaseTracking::SectionTracker; |
11201 | using TestCaseTracking::IndexTracker; |
11202 | |
11203 | } // namespace Catch |
11204 | |
11205 | #if defined(__clang__) |
11206 | # pragma clang diagnostic pop |
11207 | #endif |
11208 | // end catch_test_case_tracker.cpp |
11209 | // start catch_test_registry.cpp |
11210 | |
11211 | namespace Catch { |
11212 | |
11213 | auto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker* { |
11214 | return new(std::nothrow) TestInvokerAsFunction( testAsFunction ); |
11215 | } |
11216 | |
11217 | NameAndTags::NameAndTags( StringRef const& name_ , StringRef const& tags_ ) noexcept : name( name_ ), tags( tags_ ) {} |
11218 | |
11219 | AutoReg::AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept { |
11220 | CATCH_TRY { |
11221 | getMutableRegistryHub() |
11222 | .registerTest( |
11223 | makeTestCase( |
11224 | invoker, |
11225 | extractClassName( classOrMethod ), |
11226 | nameAndTags, |
11227 | lineInfo)); |
11228 | } CATCH_CATCH_ALL { |
11229 | // Do not throw when constructing global objects, instead register the exception to be processed later |
11230 | getMutableRegistryHub().registerStartupException(); |
11231 | } |
11232 | } |
11233 | |
11234 | AutoReg::~AutoReg() = default; |
11235 | } |
11236 | // end catch_test_registry.cpp |
11237 | // start catch_test_spec.cpp |
11238 | |
11239 | #include <algorithm> |
11240 | #include <string> |
11241 | #include <vector> |
11242 | #include <memory> |
11243 | |
11244 | namespace Catch { |
11245 | |
11246 | TestSpec::Pattern::~Pattern() = default; |
11247 | TestSpec::NamePattern::~NamePattern() = default; |
11248 | TestSpec::TagPattern::~TagPattern() = default; |
11249 | TestSpec::ExcludedPattern::~ExcludedPattern() = default; |
11250 | |
11251 | TestSpec::NamePattern::NamePattern( std::string const& name ) |
11252 | : m_wildcardPattern( toLower( name ), CaseSensitive::No ) |
11253 | {} |
11254 | bool TestSpec::NamePattern::matches( TestCaseInfo const& testCase ) const { |
11255 | return m_wildcardPattern.matches( toLower( testCase.name ) ); |
11256 | } |
11257 | |
11258 | TestSpec::TagPattern::TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} |
11259 | bool TestSpec::TagPattern::matches( TestCaseInfo const& testCase ) const { |
11260 | return std::find(begin(testCase.lcaseTags), |
11261 | end(testCase.lcaseTags), |
11262 | m_tag) != end(testCase.lcaseTags); |
11263 | } |
11264 | |
11265 | TestSpec::ExcludedPattern::ExcludedPattern( PatternPtr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} |
11266 | bool TestSpec::ExcludedPattern::matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); } |
11267 | |
11268 | bool TestSpec::Filter::matches( TestCaseInfo const& testCase ) const { |
11269 | // All patterns in a filter must match for the filter to be a match |
11270 | for( auto const& pattern : m_patterns ) { |
11271 | if( !pattern->matches( testCase ) ) |
11272 | return false; |
11273 | } |
11274 | return true; |
11275 | } |
11276 | |
11277 | bool TestSpec::hasFilters() const { |
11278 | return !m_filters.empty(); |
11279 | } |
11280 | bool TestSpec::matches( TestCaseInfo const& testCase ) const { |
11281 | // A TestSpec matches if any filter matches |
11282 | for( auto const& filter : m_filters ) |
11283 | if( filter.matches( testCase ) ) |
11284 | return true; |
11285 | return false; |
11286 | } |
11287 | } |
11288 | // end catch_test_spec.cpp |
11289 | // start catch_test_spec_parser.cpp |
11290 | |
11291 | namespace Catch { |
11292 | |
11293 | TestSpecParser::TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {} |
11294 | |
11295 | TestSpecParser& TestSpecParser::parse( std::string const& arg ) { |
11296 | m_mode = None; |
11297 | m_exclusion = false; |
11298 | m_start = std::string::npos; |
11299 | m_arg = m_tagAliases->expandAliases( arg ); |
11300 | m_escapeChars.clear(); |
11301 | for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) |
11302 | visitChar( m_arg[m_pos] ); |
11303 | if( m_mode == Name ) |
11304 | addPattern<TestSpec::NamePattern>(); |
11305 | return *this; |
11306 | } |
11307 | TestSpec TestSpecParser::testSpec() { |
11308 | addFilter(); |
11309 | return m_testSpec; |
11310 | } |
11311 | |
11312 | void TestSpecParser::visitChar( char c ) { |
11313 | if( m_mode == None ) { |
11314 | switch( c ) { |
11315 | case ' ': return; |
11316 | case '~': m_exclusion = true; return; |
11317 | case '[': return startNewMode( Tag, ++m_pos ); |
11318 | case '"': return startNewMode( QuotedName, ++m_pos ); |
11319 | case '\\': return escape(); |
11320 | default: startNewMode( Name, m_pos ); break; |
11321 | } |
11322 | } |
11323 | if( m_mode == Name ) { |
11324 | if( c == ',' ) { |
11325 | addPattern<TestSpec::NamePattern>(); |
11326 | addFilter(); |
11327 | } |
11328 | else if( c == '[' ) { |
11329 | if( subString() == "exclude:" ) |
11330 | m_exclusion = true; |
11331 | else |
11332 | addPattern<TestSpec::NamePattern>(); |
11333 | startNewMode( Tag, ++m_pos ); |
11334 | } |
11335 | else if( c == '\\' ) |
11336 | escape(); |
11337 | } |
11338 | else if( m_mode == EscapedName ) |
11339 | m_mode = Name; |
11340 | else if( m_mode == QuotedName && c == '"' ) |
11341 | addPattern<TestSpec::NamePattern>(); |
11342 | else if( m_mode == Tag && c == ']' ) |
11343 | addPattern<TestSpec::TagPattern>(); |
11344 | } |
11345 | void TestSpecParser::startNewMode( Mode mode, std::size_t start ) { |
11346 | m_mode = mode; |
11347 | m_start = start; |
11348 | } |
11349 | void TestSpecParser::escape() { |
11350 | if( m_mode == None ) |
11351 | m_start = m_pos; |
11352 | m_mode = EscapedName; |
11353 | m_escapeChars.push_back( m_pos ); |
11354 | } |
11355 | std::string TestSpecParser::subString() const { return m_arg.substr( m_start, m_pos - m_start ); } |
11356 | |
11357 | void TestSpecParser::addFilter() { |
11358 | if( !m_currentFilter.m_patterns.empty() ) { |
11359 | m_testSpec.m_filters.push_back( m_currentFilter ); |
11360 | m_currentFilter = TestSpec::Filter(); |
11361 | } |
11362 | } |
11363 | |
11364 | TestSpec parseTestSpec( std::string const& arg ) { |
11365 | return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); |
11366 | } |
11367 | |
11368 | } // namespace Catch |
11369 | // end catch_test_spec_parser.cpp |
11370 | // start catch_timer.cpp |
11371 | |
11372 | #include <chrono> |
11373 | |
11374 | static const uint64_t nanosecondsInSecond = 1000000000; |
11375 | |
11376 | namespace Catch { |
11377 | |
11378 | auto getCurrentNanosecondsSinceEpoch() -> uint64_t { |
11379 | return std::chrono::duration_cast<std::chrono::nanoseconds>( std::chrono::high_resolution_clock::now().time_since_epoch() ).count(); |
11380 | } |
11381 | |
11382 | namespace { |
11383 | auto estimateClockResolution() -> uint64_t { |
11384 | uint64_t sum = 0; |
11385 | static const uint64_t iterations = 1000000; |
11386 | |
11387 | auto startTime = getCurrentNanosecondsSinceEpoch(); |
11388 | |
11389 | for( std::size_t i = 0; i < iterations; ++i ) { |
11390 | |
11391 | uint64_t ticks; |
11392 | uint64_t baseTicks = getCurrentNanosecondsSinceEpoch(); |
11393 | do { |
11394 | ticks = getCurrentNanosecondsSinceEpoch(); |
11395 | } while( ticks == baseTicks ); |
11396 | |
11397 | auto delta = ticks - baseTicks; |
11398 | sum += delta; |
11399 | |
11400 | // If we have been calibrating for over 3 seconds -- the clock |
11401 | // is terrible and we should move on. |
11402 | // TBD: How to signal that the measured resolution is probably wrong? |
11403 | if (ticks > startTime + 3 * nanosecondsInSecond) { |
11404 | return sum / i; |
11405 | } |
11406 | } |
11407 | |
11408 | // We're just taking the mean, here. To do better we could take the std. dev and exclude outliers |
11409 | // - and potentially do more iterations if there's a high variance. |
11410 | return sum/iterations; |
11411 | } |
11412 | } |
11413 | auto getEstimatedClockResolution() -> uint64_t { |
11414 | static auto s_resolution = estimateClockResolution(); |
11415 | return s_resolution; |
11416 | } |
11417 | |
11418 | void Timer::start() { |
11419 | m_nanoseconds = getCurrentNanosecondsSinceEpoch(); |
11420 | } |
11421 | auto Timer::getElapsedNanoseconds() const -> uint64_t { |
11422 | return getCurrentNanosecondsSinceEpoch() - m_nanoseconds; |
11423 | } |
11424 | auto Timer::getElapsedMicroseconds() const -> uint64_t { |
11425 | return getElapsedNanoseconds()/1000; |
11426 | } |
11427 | auto Timer::getElapsedMilliseconds() const -> unsigned int { |
11428 | return static_cast<unsigned int>(getElapsedMicroseconds()/1000); |
11429 | } |
11430 | auto Timer::getElapsedSeconds() const -> double { |
11431 | return getElapsedMicroseconds()/1000000.0; |
11432 | } |
11433 | |
11434 | } // namespace Catch |
11435 | // end catch_timer.cpp |
11436 | // start catch_tostring.cpp |
11437 | |
11438 | #if defined(__clang__) |
11439 | # pragma clang diagnostic push |
11440 | # pragma clang diagnostic ignored "-Wexit-time-destructors" |
11441 | # pragma clang diagnostic ignored "-Wglobal-constructors" |
11442 | #endif |
11443 | |
11444 | // Enable specific decls locally |
11445 | #if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) |
11446 | #define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER |
11447 | #endif |
11448 | |
11449 | #include <cmath> |
11450 | #include <iomanip> |
11451 | |
11452 | namespace Catch { |
11453 | |
11454 | namespace Detail { |
11455 | |
11456 | const std::string unprintableString = "{?}" ; |
11457 | |
11458 | namespace { |
11459 | const int hexThreshold = 255; |
11460 | |
11461 | struct Endianness { |
11462 | enum Arch { Big, Little }; |
11463 | |
11464 | static Arch which() { |
11465 | union _{ |
11466 | int asInt; |
11467 | char asChar[sizeof (int)]; |
11468 | } u; |
11469 | |
11470 | u.asInt = 1; |
11471 | return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little; |
11472 | } |
11473 | }; |
11474 | } |
11475 | |
11476 | std::string rawMemoryToString( const void *object, std::size_t size ) { |
11477 | // Reverse order for little endian architectures |
11478 | int i = 0, end = static_cast<int>( size ), inc = 1; |
11479 | if( Endianness::which() == Endianness::Little ) { |
11480 | i = end-1; |
11481 | end = inc = -1; |
11482 | } |
11483 | |
11484 | unsigned char const *bytes = static_cast<unsigned char const *>(object); |
11485 | ReusableStringStream ; |
11486 | rss << "0x" << std::setfill('0') << std::hex; |
11487 | for( ; i != end; i += inc ) |
11488 | rss << std::setw(2) << static_cast<unsigned>(bytes[i]); |
11489 | return rss.str(); |
11490 | } |
11491 | } |
11492 | |
11493 | template<typename T> |
11494 | std::string fpToString( T value, int precision ) { |
11495 | if (std::isnan(value)) { |
11496 | return "nan" ; |
11497 | } |
11498 | |
11499 | ReusableStringStream ; |
11500 | rss << std::setprecision( precision ) |
11501 | << std::fixed |
11502 | << value; |
11503 | std::string d = rss.str(); |
11504 | std::size_t i = d.find_last_not_of( '0' ); |
11505 | if( i != std::string::npos && i != d.size()-1 ) { |
11506 | if( d[i] == '.' ) |
11507 | i++; |
11508 | d = d.substr( 0, i+1 ); |
11509 | } |
11510 | return d; |
11511 | } |
11512 | |
11513 | //// ======================================================= //// |
11514 | // |
11515 | // Out-of-line defs for full specialization of StringMaker |
11516 | // |
11517 | //// ======================================================= //// |
11518 | |
11519 | std::string StringMaker<std::string>::convert(const std::string& str) { |
11520 | if (!getCurrentContext().getConfig()->showInvisibles()) { |
11521 | return '"' + str + '"'; |
11522 | } |
11523 | |
11524 | std::string s("\"" ); |
11525 | for (char c : str) { |
11526 | switch (c) { |
11527 | case '\n': |
11528 | s.append("\\n" ); |
11529 | break; |
11530 | case '\t': |
11531 | s.append("\\t" ); |
11532 | break; |
11533 | default: |
11534 | s.push_back(c); |
11535 | break; |
11536 | } |
11537 | } |
11538 | s.append("\"" ); |
11539 | return s; |
11540 | } |
11541 | |
11542 | #ifdef CATCH_CONFIG_WCHAR |
11543 | std::string StringMaker<std::wstring>::convert(const std::wstring& wstr) { |
11544 | std::string s; |
11545 | s.reserve(wstr.size()); |
11546 | for (auto c : wstr) { |
11547 | s += (c <= 0xff) ? static_cast<char>(c) : '?'; |
11548 | } |
11549 | return ::Catch::Detail::stringify(s); |
11550 | } |
11551 | #endif |
11552 | |
11553 | std::string StringMaker<char const*>::convert(char const* str) { |
11554 | if (str) { |
11555 | return ::Catch::Detail::stringify(std::string{ str }); |
11556 | } else { |
11557 | return{ "{null string}" }; |
11558 | } |
11559 | } |
11560 | std::string StringMaker<char*>::convert(char* str) { |
11561 | if (str) { |
11562 | return ::Catch::Detail::stringify(std::string{ str }); |
11563 | } else { |
11564 | return{ "{null string}" }; |
11565 | } |
11566 | } |
11567 | #ifdef CATCH_CONFIG_WCHAR |
11568 | std::string StringMaker<wchar_t const*>::convert(wchar_t const * str) { |
11569 | if (str) { |
11570 | return ::Catch::Detail::stringify(std::wstring{ str }); |
11571 | } else { |
11572 | return{ "{null string}" }; |
11573 | } |
11574 | } |
11575 | std::string StringMaker<wchar_t *>::convert(wchar_t * str) { |
11576 | if (str) { |
11577 | return ::Catch::Detail::stringify(std::wstring{ str }); |
11578 | } else { |
11579 | return{ "{null string}" }; |
11580 | } |
11581 | } |
11582 | #endif |
11583 | |
11584 | std::string StringMaker<int>::convert(int value) { |
11585 | return ::Catch::Detail::stringify(static_cast<long long>(value)); |
11586 | } |
11587 | std::string StringMaker<long>::convert(long value) { |
11588 | return ::Catch::Detail::stringify(static_cast<long long>(value)); |
11589 | } |
11590 | std::string StringMaker<long long>::convert(long long value) { |
11591 | ReusableStringStream ; |
11592 | rss << value; |
11593 | if (value > Detail::hexThreshold) { |
11594 | rss << " (0x" << std::hex << value << ')'; |
11595 | } |
11596 | return rss.str(); |
11597 | } |
11598 | |
11599 | std::string StringMaker<unsigned int>::convert(unsigned int value) { |
11600 | return ::Catch::Detail::stringify(static_cast<unsigned long long>(value)); |
11601 | } |
11602 | std::string StringMaker<unsigned long>::convert(unsigned long value) { |
11603 | return ::Catch::Detail::stringify(static_cast<unsigned long long>(value)); |
11604 | } |
11605 | std::string StringMaker<unsigned long long>::convert(unsigned long long value) { |
11606 | ReusableStringStream ; |
11607 | rss << value; |
11608 | if (value > Detail::hexThreshold) { |
11609 | rss << " (0x" << std::hex << value << ')'; |
11610 | } |
11611 | return rss.str(); |
11612 | } |
11613 | |
11614 | std::string StringMaker<bool>::convert(bool b) { |
11615 | return b ? "true" : "false" ; |
11616 | } |
11617 | |
11618 | std::string StringMaker<char>::convert(char value) { |
11619 | if (value == '\r') { |
11620 | return "'\\r'" ; |
11621 | } else if (value == '\f') { |
11622 | return "'\\f'" ; |
11623 | } else if (value == '\n') { |
11624 | return "'\\n'" ; |
11625 | } else if (value == '\t') { |
11626 | return "'\\t'" ; |
11627 | } else if ('\0' <= value && value < ' ') { |
11628 | return ::Catch::Detail::stringify(static_cast<unsigned int>(value)); |
11629 | } else { |
11630 | char chstr[] = "' '" ; |
11631 | chstr[1] = value; |
11632 | return chstr; |
11633 | } |
11634 | } |
11635 | std::string StringMaker<signed char>::convert(signed char c) { |
11636 | return ::Catch::Detail::stringify(static_cast<char>(c)); |
11637 | } |
11638 | std::string StringMaker<unsigned char>::convert(unsigned char c) { |
11639 | return ::Catch::Detail::stringify(static_cast<char>(c)); |
11640 | } |
11641 | |
11642 | std::string StringMaker<std::nullptr_t>::convert(std::nullptr_t) { |
11643 | return "nullptr" ; |
11644 | } |
11645 | |
11646 | std::string StringMaker<float>::convert(float value) { |
11647 | return fpToString(value, 5) + 'f'; |
11648 | } |
11649 | std::string StringMaker<double>::convert(double value) { |
11650 | return fpToString(value, 10); |
11651 | } |
11652 | |
11653 | std::string ratio_string<std::atto>::symbol() { return "a" ; } |
11654 | std::string ratio_string<std::femto>::symbol() { return "f" ; } |
11655 | std::string ratio_string<std::pico>::symbol() { return "p" ; } |
11656 | std::string ratio_string<std::nano>::symbol() { return "n" ; } |
11657 | std::string ratio_string<std::micro>::symbol() { return "u" ; } |
11658 | std::string ratio_string<std::milli>::symbol() { return "m" ; } |
11659 | |
11660 | } // end namespace Catch |
11661 | |
11662 | #if defined(__clang__) |
11663 | # pragma clang diagnostic pop |
11664 | #endif |
11665 | |
11666 | // end catch_tostring.cpp |
11667 | // start catch_totals.cpp |
11668 | |
11669 | namespace Catch { |
11670 | |
11671 | Counts Counts::operator - ( Counts const& other ) const { |
11672 | Counts diff; |
11673 | diff.passed = passed - other.passed; |
11674 | diff.failed = failed - other.failed; |
11675 | diff.failedButOk = failedButOk - other.failedButOk; |
11676 | return diff; |
11677 | } |
11678 | |
11679 | Counts& Counts::operator += ( Counts const& other ) { |
11680 | passed += other.passed; |
11681 | failed += other.failed; |
11682 | failedButOk += other.failedButOk; |
11683 | return *this; |
11684 | } |
11685 | |
11686 | std::size_t Counts::total() const { |
11687 | return passed + failed + failedButOk; |
11688 | } |
11689 | bool Counts::allPassed() const { |
11690 | return failed == 0 && failedButOk == 0; |
11691 | } |
11692 | bool Counts::allOk() const { |
11693 | return failed == 0; |
11694 | } |
11695 | |
11696 | Totals Totals::operator - ( Totals const& other ) const { |
11697 | Totals diff; |
11698 | diff.assertions = assertions - other.assertions; |
11699 | diff.testCases = testCases - other.testCases; |
11700 | return diff; |
11701 | } |
11702 | |
11703 | Totals& Totals::operator += ( Totals const& other ) { |
11704 | assertions += other.assertions; |
11705 | testCases += other.testCases; |
11706 | return *this; |
11707 | } |
11708 | |
11709 | Totals Totals::delta( Totals const& prevTotals ) const { |
11710 | Totals diff = *this - prevTotals; |
11711 | if( diff.assertions.failed > 0 ) |
11712 | ++diff.testCases.failed; |
11713 | else if( diff.assertions.failedButOk > 0 ) |
11714 | ++diff.testCases.failedButOk; |
11715 | else |
11716 | ++diff.testCases.passed; |
11717 | return diff; |
11718 | } |
11719 | |
11720 | } |
11721 | // end catch_totals.cpp |
11722 | // start catch_uncaught_exceptions.cpp |
11723 | |
11724 | #include <exception> |
11725 | |
11726 | namespace Catch { |
11727 | bool uncaught_exceptions() { |
11728 | #if defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) |
11729 | return std::uncaught_exceptions() > 0; |
11730 | #else |
11731 | return std::uncaught_exception(); |
11732 | #endif |
11733 | } |
11734 | } // end namespace Catch |
11735 | // end catch_uncaught_exceptions.cpp |
11736 | // start catch_version.cpp |
11737 | |
11738 | #include <ostream> |
11739 | |
11740 | namespace Catch { |
11741 | |
11742 | Version::Version |
11743 | ( unsigned int _majorVersion, |
11744 | unsigned int _minorVersion, |
11745 | unsigned int _patchNumber, |
11746 | char const * const _branchName, |
11747 | unsigned int _buildNumber ) |
11748 | : majorVersion( _majorVersion ), |
11749 | minorVersion( _minorVersion ), |
11750 | patchNumber( _patchNumber ), |
11751 | branchName( _branchName ), |
11752 | buildNumber( _buildNumber ) |
11753 | {} |
11754 | |
11755 | std::ostream& operator << ( std::ostream& os, Version const& version ) { |
11756 | os << version.majorVersion << '.' |
11757 | << version.minorVersion << '.' |
11758 | << version.patchNumber; |
11759 | // branchName is never null -> 0th char is \0 if it is empty |
11760 | if (version.branchName[0]) { |
11761 | os << '-' << version.branchName |
11762 | << '.' << version.buildNumber; |
11763 | } |
11764 | return os; |
11765 | } |
11766 | |
11767 | Version const& libraryVersion() { |
11768 | static Version version( 2, 4, 0, "" , 0 ); |
11769 | return version; |
11770 | } |
11771 | |
11772 | } |
11773 | // end catch_version.cpp |
11774 | // start catch_wildcard_pattern.cpp |
11775 | |
11776 | #include <sstream> |
11777 | |
11778 | namespace Catch { |
11779 | |
11780 | WildcardPattern::WildcardPattern( std::string const& pattern, |
11781 | CaseSensitive::Choice caseSensitivity ) |
11782 | : m_caseSensitivity( caseSensitivity ), |
11783 | m_pattern( adjustCase( pattern ) ) |
11784 | { |
11785 | if( startsWith( m_pattern, '*' ) ) { |
11786 | m_pattern = m_pattern.substr( 1 ); |
11787 | m_wildcard = WildcardAtStart; |
11788 | } |
11789 | if( endsWith( m_pattern, '*' ) ) { |
11790 | m_pattern = m_pattern.substr( 0, m_pattern.size()-1 ); |
11791 | m_wildcard = static_cast<WildcardPosition>( m_wildcard | WildcardAtEnd ); |
11792 | } |
11793 | } |
11794 | |
11795 | bool WildcardPattern::matches( std::string const& str ) const { |
11796 | switch( m_wildcard ) { |
11797 | case NoWildcard: |
11798 | return m_pattern == adjustCase( str ); |
11799 | case WildcardAtStart: |
11800 | return endsWith( adjustCase( str ), m_pattern ); |
11801 | case WildcardAtEnd: |
11802 | return startsWith( adjustCase( str ), m_pattern ); |
11803 | case WildcardAtBothEnds: |
11804 | return contains( adjustCase( str ), m_pattern ); |
11805 | default: |
11806 | CATCH_INTERNAL_ERROR( "Unknown enum" ); |
11807 | } |
11808 | } |
11809 | |
11810 | std::string WildcardPattern::adjustCase( std::string const& str ) const { |
11811 | return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str; |
11812 | } |
11813 | } |
11814 | // end catch_wildcard_pattern.cpp |
11815 | // start catch_xmlwriter.cpp |
11816 | |
11817 | #include <iomanip> |
11818 | |
11819 | using uchar = unsigned char; |
11820 | |
11821 | namespace Catch { |
11822 | |
11823 | namespace { |
11824 | |
11825 | size_t trailingBytes(unsigned char c) { |
11826 | if ((c & 0xE0) == 0xC0) { |
11827 | return 2; |
11828 | } |
11829 | if ((c & 0xF0) == 0xE0) { |
11830 | return 3; |
11831 | } |
11832 | if ((c & 0xF8) == 0xF0) { |
11833 | return 4; |
11834 | } |
11835 | CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered" ); |
11836 | } |
11837 | |
11838 | uint32_t (unsigned char c) { |
11839 | if ((c & 0xE0) == 0xC0) { |
11840 | return c & 0x1F; |
11841 | } |
11842 | if ((c & 0xF0) == 0xE0) { |
11843 | return c & 0x0F; |
11844 | } |
11845 | if ((c & 0xF8) == 0xF0) { |
11846 | return c & 0x07; |
11847 | } |
11848 | CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered" ); |
11849 | } |
11850 | |
11851 | void hexEscapeChar(std::ostream& os, unsigned char c) { |
11852 | os << "\\x" |
11853 | << std::uppercase << std::hex << std::setfill('0') << std::setw(2) |
11854 | << static_cast<int>(c); |
11855 | } |
11856 | |
11857 | } // anonymous namespace |
11858 | |
11859 | XmlEncode::XmlEncode( std::string const& str, ForWhat forWhat ) |
11860 | : m_str( str ), |
11861 | m_forWhat( forWhat ) |
11862 | {} |
11863 | |
11864 | void XmlEncode::encodeTo( std::ostream& os ) const { |
11865 | // Apostrophe escaping not necessary if we always use " to write attributes |
11866 | // (see: http://www.w3.org/TR/xml/#syntax) |
11867 | |
11868 | for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) { |
11869 | uchar c = m_str[idx]; |
11870 | switch (c) { |
11871 | case '<': os << "<" ; break; |
11872 | case '&': os << "&" ; break; |
11873 | |
11874 | case '>': |
11875 | // See: http://www.w3.org/TR/xml/#syntax |
11876 | if (idx > 2 && m_str[idx - 1] == ']' && m_str[idx - 2] == ']') |
11877 | os << ">" ; |
11878 | else |
11879 | os << c; |
11880 | break; |
11881 | |
11882 | case '\"': |
11883 | if (m_forWhat == ForAttributes) |
11884 | os << """ ; |
11885 | else |
11886 | os << c; |
11887 | break; |
11888 | |
11889 | default: |
11890 | // Check for control characters and invalid utf-8 |
11891 | |
11892 | // Escape control characters in standard ascii |
11893 | // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0 |
11894 | if (c < 0x09 || (c > 0x0D && c < 0x20) || c == 0x7F) { |
11895 | hexEscapeChar(os, c); |
11896 | break; |
11897 | } |
11898 | |
11899 | // Plain ASCII: Write it to stream |
11900 | if (c < 0x7F) { |
11901 | os << c; |
11902 | break; |
11903 | } |
11904 | |
11905 | // UTF-8 territory |
11906 | // Check if the encoding is valid and if it is not, hex escape bytes. |
11907 | // Important: We do not check the exact decoded values for validity, only the encoding format |
11908 | // First check that this bytes is a valid lead byte: |
11909 | // This means that it is not encoded as 1111 1XXX |
11910 | // Or as 10XX XXXX |
11911 | if (c < 0xC0 || |
11912 | c >= 0xF8) { |
11913 | hexEscapeChar(os, c); |
11914 | break; |
11915 | } |
11916 | |
11917 | auto encBytes = trailingBytes(c); |
11918 | // Are there enough bytes left to avoid accessing out-of-bounds memory? |
11919 | if (idx + encBytes - 1 >= m_str.size()) { |
11920 | hexEscapeChar(os, c); |
11921 | break; |
11922 | } |
11923 | // The header is valid, check data |
11924 | // The next encBytes bytes must together be a valid utf-8 |
11925 | // This means: bitpattern 10XX XXXX and the extracted value is sane (ish) |
11926 | bool valid = true; |
11927 | uint32_t value = headerValue(c); |
11928 | for (std::size_t n = 1; n < encBytes; ++n) { |
11929 | uchar nc = m_str[idx + n]; |
11930 | valid &= ((nc & 0xC0) == 0x80); |
11931 | value = (value << 6) | (nc & 0x3F); |
11932 | } |
11933 | |
11934 | if ( |
11935 | // Wrong bit pattern of following bytes |
11936 | (!valid) || |
11937 | // Overlong encodings |
11938 | (value < 0x80) || |
11939 | (0x80 <= value && value < 0x800 && encBytes > 2) || |
11940 | (0x800 < value && value < 0x10000 && encBytes > 3) || |
11941 | // Encoded value out of range |
11942 | (value >= 0x110000) |
11943 | ) { |
11944 | hexEscapeChar(os, c); |
11945 | break; |
11946 | } |
11947 | |
11948 | // If we got here, this is in fact a valid(ish) utf-8 sequence |
11949 | for (std::size_t n = 0; n < encBytes; ++n) { |
11950 | os << m_str[idx + n]; |
11951 | } |
11952 | idx += encBytes - 1; |
11953 | break; |
11954 | } |
11955 | } |
11956 | } |
11957 | |
11958 | std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { |
11959 | xmlEncode.encodeTo( os ); |
11960 | return os; |
11961 | } |
11962 | |
11963 | XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer ) |
11964 | : m_writer( writer ) |
11965 | {} |
11966 | |
11967 | XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) noexcept |
11968 | : m_writer( other.m_writer ){ |
11969 | other.m_writer = nullptr; |
11970 | } |
11971 | XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) noexcept { |
11972 | if ( m_writer ) { |
11973 | m_writer->endElement(); |
11974 | } |
11975 | m_writer = other.m_writer; |
11976 | other.m_writer = nullptr; |
11977 | return *this; |
11978 | } |
11979 | |
11980 | XmlWriter::ScopedElement::~ScopedElement() { |
11981 | if( m_writer ) |
11982 | m_writer->endElement(); |
11983 | } |
11984 | |
11985 | XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, bool indent ) { |
11986 | m_writer->writeText( text, indent ); |
11987 | return *this; |
11988 | } |
11989 | |
11990 | XmlWriter::XmlWriter( std::ostream& os ) : m_os( os ) |
11991 | { |
11992 | writeDeclaration(); |
11993 | } |
11994 | |
11995 | XmlWriter::~XmlWriter() { |
11996 | while( !m_tags.empty() ) |
11997 | endElement(); |
11998 | } |
11999 | |
12000 | XmlWriter& XmlWriter::startElement( std::string const& name ) { |
12001 | ensureTagClosed(); |
12002 | newlineIfNecessary(); |
12003 | m_os << m_indent << '<' << name; |
12004 | m_tags.push_back( name ); |
12005 | m_indent += " " ; |
12006 | m_tagIsOpen = true; |
12007 | return *this; |
12008 | } |
12009 | |
12010 | XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name ) { |
12011 | ScopedElement scoped( this ); |
12012 | startElement( name ); |
12013 | return scoped; |
12014 | } |
12015 | |
12016 | XmlWriter& XmlWriter::endElement() { |
12017 | newlineIfNecessary(); |
12018 | m_indent = m_indent.substr( 0, m_indent.size()-2 ); |
12019 | if( m_tagIsOpen ) { |
12020 | m_os << "/>" ; |
12021 | m_tagIsOpen = false; |
12022 | } |
12023 | else { |
12024 | m_os << m_indent << "</" << m_tags.back() << ">" ; |
12025 | } |
12026 | m_os << std::endl; |
12027 | m_tags.pop_back(); |
12028 | return *this; |
12029 | } |
12030 | |
12031 | XmlWriter& XmlWriter::writeAttribute( std::string const& name, std::string const& attribute ) { |
12032 | if( !name.empty() && !attribute.empty() ) |
12033 | m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"'; |
12034 | return *this; |
12035 | } |
12036 | |
12037 | XmlWriter& XmlWriter::writeAttribute( std::string const& name, bool attribute ) { |
12038 | m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"'; |
12039 | return *this; |
12040 | } |
12041 | |
12042 | XmlWriter& XmlWriter::writeText( std::string const& text, bool indent ) { |
12043 | if( !text.empty() ){ |
12044 | bool tagWasOpen = m_tagIsOpen; |
12045 | ensureTagClosed(); |
12046 | if( tagWasOpen && indent ) |
12047 | m_os << m_indent; |
12048 | m_os << XmlEncode( text ); |
12049 | m_needsNewline = true; |
12050 | } |
12051 | return *this; |
12052 | } |
12053 | |
12054 | XmlWriter& XmlWriter::( std::string const& text ) { |
12055 | ensureTagClosed(); |
12056 | m_os << m_indent << "<!--" << text << "-->" ; |
12057 | m_needsNewline = true; |
12058 | return *this; |
12059 | } |
12060 | |
12061 | void XmlWriter::writeStylesheetRef( std::string const& url ) { |
12062 | m_os << "<?xml-stylesheet type=\"text/xsl\" href=\"" << url << "\"?>\n" ; |
12063 | } |
12064 | |
12065 | XmlWriter& XmlWriter::writeBlankLine() { |
12066 | ensureTagClosed(); |
12067 | m_os << '\n'; |
12068 | return *this; |
12069 | } |
12070 | |
12071 | void XmlWriter::ensureTagClosed() { |
12072 | if( m_tagIsOpen ) { |
12073 | m_os << ">" << std::endl; |
12074 | m_tagIsOpen = false; |
12075 | } |
12076 | } |
12077 | |
12078 | void XmlWriter::writeDeclaration() { |
12079 | m_os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ; |
12080 | } |
12081 | |
12082 | void XmlWriter::newlineIfNecessary() { |
12083 | if( m_needsNewline ) { |
12084 | m_os << std::endl; |
12085 | m_needsNewline = false; |
12086 | } |
12087 | } |
12088 | } |
12089 | // end catch_xmlwriter.cpp |
12090 | // start catch_reporter_bases.cpp |
12091 | |
12092 | #include <cstring> |
12093 | #include <cfloat> |
12094 | #include <cstdio> |
12095 | #include <cassert> |
12096 | #include <memory> |
12097 | |
12098 | namespace Catch { |
12099 | void prepareExpandedExpression(AssertionResult& result) { |
12100 | result.getExpandedExpression(); |
12101 | } |
12102 | |
12103 | // Because formatting using c++ streams is stateful, drop down to C is required |
12104 | // Alternatively we could use stringstream, but its performance is... not good. |
12105 | std::string getFormattedDuration( double duration ) { |
12106 | // Max exponent + 1 is required to represent the whole part |
12107 | // + 1 for decimal point |
12108 | // + 3 for the 3 decimal places |
12109 | // + 1 for null terminator |
12110 | const std::size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1; |
12111 | char buffer[maxDoubleSize]; |
12112 | |
12113 | // Save previous errno, to prevent sprintf from overwriting it |
12114 | ErrnoGuard guard; |
12115 | #ifdef _MSC_VER |
12116 | sprintf_s(buffer, "%.3f" , duration); |
12117 | #else |
12118 | sprintf(buffer, "%.3f" , duration); |
12119 | #endif |
12120 | return std::string(buffer); |
12121 | } |
12122 | |
12123 | TestEventListenerBase::TestEventListenerBase(ReporterConfig const & _config) |
12124 | :StreamingReporterBase(_config) {} |
12125 | |
12126 | void TestEventListenerBase::assertionStarting(AssertionInfo const &) {} |
12127 | |
12128 | bool TestEventListenerBase::assertionEnded(AssertionStats const &) { |
12129 | return false; |
12130 | } |
12131 | |
12132 | } // end namespace Catch |
12133 | // end catch_reporter_bases.cpp |
12134 | // start catch_reporter_compact.cpp |
12135 | |
12136 | namespace { |
12137 | |
12138 | #ifdef CATCH_PLATFORM_MAC |
12139 | const char* failedString() { return "FAILED" ; } |
12140 | const char* passedString() { return "PASSED" ; } |
12141 | #else |
12142 | const char* failedString() { return "failed" ; } |
12143 | const char* passedString() { return "passed" ; } |
12144 | #endif |
12145 | |
12146 | // Colour::LightGrey |
12147 | Catch::Colour::Code dimColour() { return Catch::Colour::FileName; } |
12148 | |
12149 | std::string bothOrAll( std::size_t count ) { |
12150 | return count == 1 ? std::string() : |
12151 | count == 2 ? "both " : "all " ; |
12152 | } |
12153 | |
12154 | } // anon namespace |
12155 | |
12156 | namespace Catch { |
12157 | namespace { |
12158 | // Colour, message variants: |
12159 | // - white: No tests ran. |
12160 | // - red: Failed [both/all] N test cases, failed [both/all] M assertions. |
12161 | // - white: Passed [both/all] N test cases (no assertions). |
12162 | // - red: Failed N tests cases, failed M assertions. |
12163 | // - green: Passed [both/all] N tests cases with M assertions. |
12164 | void printTotals(std::ostream& out, const Totals& totals) { |
12165 | if (totals.testCases.total() == 0) { |
12166 | out << "No tests ran." ; |
12167 | } else if (totals.testCases.failed == totals.testCases.total()) { |
12168 | Colour colour(Colour::ResultError); |
12169 | const std::string qualify_assertions_failed = |
12170 | totals.assertions.failed == totals.assertions.total() ? |
12171 | bothOrAll(totals.assertions.failed) : std::string(); |
12172 | out << |
12173 | "Failed " << bothOrAll(totals.testCases.failed) |
12174 | << pluralise(totals.testCases.failed, "test case" ) << ", " |
12175 | "failed " << qualify_assertions_failed << |
12176 | pluralise(totals.assertions.failed, "assertion" ) << '.'; |
12177 | } else if (totals.assertions.total() == 0) { |
12178 | out << |
12179 | "Passed " << bothOrAll(totals.testCases.total()) |
12180 | << pluralise(totals.testCases.total(), "test case" ) |
12181 | << " (no assertions)." ; |
12182 | } else if (totals.assertions.failed) { |
12183 | Colour colour(Colour::ResultError); |
12184 | out << |
12185 | "Failed " << pluralise(totals.testCases.failed, "test case" ) << ", " |
12186 | "failed " << pluralise(totals.assertions.failed, "assertion" ) << '.'; |
12187 | } else { |
12188 | Colour colour(Colour::ResultSuccess); |
12189 | out << |
12190 | "Passed " << bothOrAll(totals.testCases.passed) |
12191 | << pluralise(totals.testCases.passed, "test case" ) << |
12192 | " with " << pluralise(totals.assertions.passed, "assertion" ) << '.'; |
12193 | } |
12194 | } |
12195 | |
12196 | // Implementation of CompactReporter formatting |
12197 | class AssertionPrinter { |
12198 | public: |
12199 | AssertionPrinter& operator= (AssertionPrinter const&) = delete; |
12200 | AssertionPrinter(AssertionPrinter const&) = delete; |
12201 | AssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages) |
12202 | : stream(_stream) |
12203 | , result(_stats.assertionResult) |
12204 | , messages(_stats.infoMessages) |
12205 | , itMessage(_stats.infoMessages.begin()) |
12206 | , printInfoMessages(_printInfoMessages) {} |
12207 | |
12208 | void print() { |
12209 | printSourceInfo(); |
12210 | |
12211 | itMessage = messages.begin(); |
12212 | |
12213 | switch (result.getResultType()) { |
12214 | case ResultWas::Ok: |
12215 | printResultType(Colour::ResultSuccess, passedString()); |
12216 | printOriginalExpression(); |
12217 | printReconstructedExpression(); |
12218 | if (!result.hasExpression()) |
12219 | printRemainingMessages(Colour::None); |
12220 | else |
12221 | printRemainingMessages(); |
12222 | break; |
12223 | case ResultWas::ExpressionFailed: |
12224 | if (result.isOk()) |
12225 | printResultType(Colour::ResultSuccess, failedString() + std::string(" - but was ok" )); |
12226 | else |
12227 | printResultType(Colour::Error, failedString()); |
12228 | printOriginalExpression(); |
12229 | printReconstructedExpression(); |
12230 | printRemainingMessages(); |
12231 | break; |
12232 | case ResultWas::ThrewException: |
12233 | printResultType(Colour::Error, failedString()); |
12234 | printIssue("unexpected exception with message:" ); |
12235 | printMessage(); |
12236 | printExpressionWas(); |
12237 | printRemainingMessages(); |
12238 | break; |
12239 | case ResultWas::FatalErrorCondition: |
12240 | printResultType(Colour::Error, failedString()); |
12241 | printIssue("fatal error condition with message:" ); |
12242 | printMessage(); |
12243 | printExpressionWas(); |
12244 | printRemainingMessages(); |
12245 | break; |
12246 | case ResultWas::DidntThrowException: |
12247 | printResultType(Colour::Error, failedString()); |
12248 | printIssue("expected exception, got none" ); |
12249 | printExpressionWas(); |
12250 | printRemainingMessages(); |
12251 | break; |
12252 | case ResultWas::Info: |
12253 | printResultType(Colour::None, "info" ); |
12254 | printMessage(); |
12255 | printRemainingMessages(); |
12256 | break; |
12257 | case ResultWas::Warning: |
12258 | printResultType(Colour::None, "warning" ); |
12259 | printMessage(); |
12260 | printRemainingMessages(); |
12261 | break; |
12262 | case ResultWas::ExplicitFailure: |
12263 | printResultType(Colour::Error, failedString()); |
12264 | printIssue("explicitly" ); |
12265 | printRemainingMessages(Colour::None); |
12266 | break; |
12267 | // These cases are here to prevent compiler warnings |
12268 | case ResultWas::Unknown: |
12269 | case ResultWas::FailureBit: |
12270 | case ResultWas::Exception: |
12271 | printResultType(Colour::Error, "** internal error **" ); |
12272 | break; |
12273 | } |
12274 | } |
12275 | |
12276 | private: |
12277 | void printSourceInfo() const { |
12278 | Colour colourGuard(Colour::FileName); |
12279 | stream << result.getSourceInfo() << ':'; |
12280 | } |
12281 | |
12282 | void printResultType(Colour::Code colour, std::string const& passOrFail) const { |
12283 | if (!passOrFail.empty()) { |
12284 | { |
12285 | Colour colourGuard(colour); |
12286 | stream << ' ' << passOrFail; |
12287 | } |
12288 | stream << ':'; |
12289 | } |
12290 | } |
12291 | |
12292 | void printIssue(std::string const& issue) const { |
12293 | stream << ' ' << issue; |
12294 | } |
12295 | |
12296 | void printExpressionWas() { |
12297 | if (result.hasExpression()) { |
12298 | stream << ';'; |
12299 | { |
12300 | Colour colour(dimColour()); |
12301 | stream << " expression was:" ; |
12302 | } |
12303 | printOriginalExpression(); |
12304 | } |
12305 | } |
12306 | |
12307 | void printOriginalExpression() const { |
12308 | if (result.hasExpression()) { |
12309 | stream << ' ' << result.getExpression(); |
12310 | } |
12311 | } |
12312 | |
12313 | void printReconstructedExpression() const { |
12314 | if (result.hasExpandedExpression()) { |
12315 | { |
12316 | Colour colour(dimColour()); |
12317 | stream << " for: " ; |
12318 | } |
12319 | stream << result.getExpandedExpression(); |
12320 | } |
12321 | } |
12322 | |
12323 | void printMessage() { |
12324 | if (itMessage != messages.end()) { |
12325 | stream << " '" << itMessage->message << '\''; |
12326 | ++itMessage; |
12327 | } |
12328 | } |
12329 | |
12330 | void printRemainingMessages(Colour::Code colour = dimColour()) { |
12331 | if (itMessage == messages.end()) |
12332 | return; |
12333 | |
12334 | // using messages.end() directly yields (or auto) compilation error: |
12335 | std::vector<MessageInfo>::const_iterator itEnd = messages.end(); |
12336 | const std::size_t N = static_cast<std::size_t>(std::distance(itMessage, itEnd)); |
12337 | |
12338 | { |
12339 | Colour colourGuard(colour); |
12340 | stream << " with " << pluralise(N, "message" ) << ':'; |
12341 | } |
12342 | |
12343 | for (; itMessage != itEnd; ) { |
12344 | // If this assertion is a warning ignore any INFO messages |
12345 | if (printInfoMessages || itMessage->type != ResultWas::Info) { |
12346 | stream << " '" << itMessage->message << '\''; |
12347 | if (++itMessage != itEnd) { |
12348 | Colour colourGuard(dimColour()); |
12349 | stream << " and" ; |
12350 | } |
12351 | } |
12352 | } |
12353 | } |
12354 | |
12355 | private: |
12356 | std::ostream& stream; |
12357 | AssertionResult const& result; |
12358 | std::vector<MessageInfo> messages; |
12359 | std::vector<MessageInfo>::const_iterator itMessage; |
12360 | bool printInfoMessages; |
12361 | }; |
12362 | |
12363 | } // anon namespace |
12364 | |
12365 | std::string CompactReporter::getDescription() { |
12366 | return "Reports test results on a single line, suitable for IDEs" ; |
12367 | } |
12368 | |
12369 | ReporterPreferences CompactReporter::getPreferences() const { |
12370 | return m_reporterPrefs; |
12371 | } |
12372 | |
12373 | void CompactReporter::noMatchingTestCases( std::string const& spec ) { |
12374 | stream << "No test cases matched '" << spec << '\'' << std::endl; |
12375 | } |
12376 | |
12377 | void CompactReporter::assertionStarting( AssertionInfo const& ) {} |
12378 | |
12379 | bool CompactReporter::assertionEnded( AssertionStats const& _assertionStats ) { |
12380 | AssertionResult const& result = _assertionStats.assertionResult; |
12381 | |
12382 | bool printInfoMessages = true; |
12383 | |
12384 | // Drop out if result was successful and we're not printing those |
12385 | if( !m_config->includeSuccessfulResults() && result.isOk() ) { |
12386 | if( result.getResultType() != ResultWas::Warning ) |
12387 | return false; |
12388 | printInfoMessages = false; |
12389 | } |
12390 | |
12391 | AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); |
12392 | printer.print(); |
12393 | |
12394 | stream << std::endl; |
12395 | return true; |
12396 | } |
12397 | |
12398 | void CompactReporter::sectionEnded(SectionStats const& _sectionStats) { |
12399 | if (m_config->showDurations() == ShowDurations::Always) { |
12400 | stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; |
12401 | } |
12402 | } |
12403 | |
12404 | void CompactReporter::testRunEnded( TestRunStats const& _testRunStats ) { |
12405 | printTotals( stream, _testRunStats.totals ); |
12406 | stream << '\n' << std::endl; |
12407 | StreamingReporterBase::testRunEnded( _testRunStats ); |
12408 | } |
12409 | |
12410 | CompactReporter::~CompactReporter() {} |
12411 | |
12412 | CATCH_REGISTER_REPORTER( "compact" , CompactReporter ) |
12413 | |
12414 | } // end namespace Catch |
12415 | // end catch_reporter_compact.cpp |
12416 | // start catch_reporter_console.cpp |
12417 | |
12418 | #include <cfloat> |
12419 | #include <cstdio> |
12420 | |
12421 | #if defined(_MSC_VER) |
12422 | #pragma warning(push) |
12423 | #pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch |
12424 | // Note that 4062 (not all labels are handled |
12425 | // and default is missing) is enabled |
12426 | #endif |
12427 | |
12428 | namespace Catch { |
12429 | |
12430 | namespace { |
12431 | |
12432 | // Formatter impl for ConsoleReporter |
12433 | class ConsoleAssertionPrinter { |
12434 | public: |
12435 | ConsoleAssertionPrinter& operator= (ConsoleAssertionPrinter const&) = delete; |
12436 | ConsoleAssertionPrinter(ConsoleAssertionPrinter const&) = delete; |
12437 | ConsoleAssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages) |
12438 | : stream(_stream), |
12439 | stats(_stats), |
12440 | result(_stats.assertionResult), |
12441 | colour(Colour::None), |
12442 | message(result.getMessage()), |
12443 | messages(_stats.infoMessages), |
12444 | printInfoMessages(_printInfoMessages) { |
12445 | switch (result.getResultType()) { |
12446 | case ResultWas::Ok: |
12447 | colour = Colour::Success; |
12448 | passOrFail = "PASSED" ; |
12449 | //if( result.hasMessage() ) |
12450 | if (_stats.infoMessages.size() == 1) |
12451 | messageLabel = "with message" ; |
12452 | if (_stats.infoMessages.size() > 1) |
12453 | messageLabel = "with messages" ; |
12454 | break; |
12455 | case ResultWas::ExpressionFailed: |
12456 | if (result.isOk()) { |
12457 | colour = Colour::Success; |
12458 | passOrFail = "FAILED - but was ok" ; |
12459 | } else { |
12460 | colour = Colour::Error; |
12461 | passOrFail = "FAILED" ; |
12462 | } |
12463 | if (_stats.infoMessages.size() == 1) |
12464 | messageLabel = "with message" ; |
12465 | if (_stats.infoMessages.size() > 1) |
12466 | messageLabel = "with messages" ; |
12467 | break; |
12468 | case ResultWas::ThrewException: |
12469 | colour = Colour::Error; |
12470 | passOrFail = "FAILED" ; |
12471 | messageLabel = "due to unexpected exception with " ; |
12472 | if (_stats.infoMessages.size() == 1) |
12473 | messageLabel += "message" ; |
12474 | if (_stats.infoMessages.size() > 1) |
12475 | messageLabel += "messages" ; |
12476 | break; |
12477 | case ResultWas::FatalErrorCondition: |
12478 | colour = Colour::Error; |
12479 | passOrFail = "FAILED" ; |
12480 | messageLabel = "due to a fatal error condition" ; |
12481 | break; |
12482 | case ResultWas::DidntThrowException: |
12483 | colour = Colour::Error; |
12484 | passOrFail = "FAILED" ; |
12485 | messageLabel = "because no exception was thrown where one was expected" ; |
12486 | break; |
12487 | case ResultWas::Info: |
12488 | messageLabel = "info" ; |
12489 | break; |
12490 | case ResultWas::Warning: |
12491 | messageLabel = "warning" ; |
12492 | break; |
12493 | case ResultWas::ExplicitFailure: |
12494 | passOrFail = "FAILED" ; |
12495 | colour = Colour::Error; |
12496 | if (_stats.infoMessages.size() == 1) |
12497 | messageLabel = "explicitly with message" ; |
12498 | if (_stats.infoMessages.size() > 1) |
12499 | messageLabel = "explicitly with messages" ; |
12500 | break; |
12501 | // These cases are here to prevent compiler warnings |
12502 | case ResultWas::Unknown: |
12503 | case ResultWas::FailureBit: |
12504 | case ResultWas::Exception: |
12505 | passOrFail = "** internal error **" ; |
12506 | colour = Colour::Error; |
12507 | break; |
12508 | } |
12509 | } |
12510 | |
12511 | void print() const { |
12512 | printSourceInfo(); |
12513 | if (stats.totals.assertions.total() > 0) { |
12514 | if (result.isOk()) |
12515 | stream << '\n'; |
12516 | printResultType(); |
12517 | printOriginalExpression(); |
12518 | printReconstructedExpression(); |
12519 | } else { |
12520 | stream << '\n'; |
12521 | } |
12522 | printMessage(); |
12523 | } |
12524 | |
12525 | private: |
12526 | void printResultType() const { |
12527 | if (!passOrFail.empty()) { |
12528 | Colour colourGuard(colour); |
12529 | stream << passOrFail << ":\n" ; |
12530 | } |
12531 | } |
12532 | void printOriginalExpression() const { |
12533 | if (result.hasExpression()) { |
12534 | Colour colourGuard(Colour::OriginalExpression); |
12535 | stream << " " ; |
12536 | stream << result.getExpressionInMacro(); |
12537 | stream << '\n'; |
12538 | } |
12539 | } |
12540 | void printReconstructedExpression() const { |
12541 | if (result.hasExpandedExpression()) { |
12542 | stream << "with expansion:\n" ; |
12543 | Colour colourGuard(Colour::ReconstructedExpression); |
12544 | stream << Column(result.getExpandedExpression()).indent(2) << '\n'; |
12545 | } |
12546 | } |
12547 | void printMessage() const { |
12548 | if (!messageLabel.empty()) |
12549 | stream << messageLabel << ':' << '\n'; |
12550 | for (auto const& msg : messages) { |
12551 | // If this assertion is a warning ignore any INFO messages |
12552 | if (printInfoMessages || msg.type != ResultWas::Info) |
12553 | stream << Column(msg.message).indent(2) << '\n'; |
12554 | } |
12555 | } |
12556 | void printSourceInfo() const { |
12557 | Colour colourGuard(Colour::FileName); |
12558 | stream << result.getSourceInfo() << ": " ; |
12559 | } |
12560 | |
12561 | std::ostream& stream; |
12562 | AssertionStats const& stats; |
12563 | AssertionResult const& result; |
12564 | Colour::Code colour; |
12565 | std::string passOrFail; |
12566 | std::string messageLabel; |
12567 | std::string message; |
12568 | std::vector<MessageInfo> messages; |
12569 | bool printInfoMessages; |
12570 | }; |
12571 | |
12572 | std::size_t makeRatio(std::size_t number, std::size_t total) { |
12573 | std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number / total : 0; |
12574 | return (ratio == 0 && number > 0) ? 1 : ratio; |
12575 | } |
12576 | |
12577 | std::size_t& findMax(std::size_t& i, std::size_t& j, std::size_t& k) { |
12578 | if (i > j && i > k) |
12579 | return i; |
12580 | else if (j > k) |
12581 | return j; |
12582 | else |
12583 | return k; |
12584 | } |
12585 | |
12586 | struct ColumnInfo { |
12587 | enum Justification { Left, Right }; |
12588 | std::string name; |
12589 | int width; |
12590 | Justification justification; |
12591 | }; |
12592 | struct ColumnBreak {}; |
12593 | struct RowBreak {}; |
12594 | |
12595 | class Duration { |
12596 | enum class Unit { |
12597 | Auto, |
12598 | Nanoseconds, |
12599 | Microseconds, |
12600 | Milliseconds, |
12601 | Seconds, |
12602 | Minutes |
12603 | }; |
12604 | static const uint64_t s_nanosecondsInAMicrosecond = 1000; |
12605 | static const uint64_t s_nanosecondsInAMillisecond = 1000 * s_nanosecondsInAMicrosecond; |
12606 | static const uint64_t s_nanosecondsInASecond = 1000 * s_nanosecondsInAMillisecond; |
12607 | static const uint64_t s_nanosecondsInAMinute = 60 * s_nanosecondsInASecond; |
12608 | |
12609 | uint64_t m_inNanoseconds; |
12610 | Unit m_units; |
12611 | |
12612 | public: |
12613 | explicit Duration(uint64_t inNanoseconds, Unit units = Unit::Auto) |
12614 | : m_inNanoseconds(inNanoseconds), |
12615 | m_units(units) { |
12616 | if (m_units == Unit::Auto) { |
12617 | if (m_inNanoseconds < s_nanosecondsInAMicrosecond) |
12618 | m_units = Unit::Nanoseconds; |
12619 | else if (m_inNanoseconds < s_nanosecondsInAMillisecond) |
12620 | m_units = Unit::Microseconds; |
12621 | else if (m_inNanoseconds < s_nanosecondsInASecond) |
12622 | m_units = Unit::Milliseconds; |
12623 | else if (m_inNanoseconds < s_nanosecondsInAMinute) |
12624 | m_units = Unit::Seconds; |
12625 | else |
12626 | m_units = Unit::Minutes; |
12627 | } |
12628 | |
12629 | } |
12630 | |
12631 | auto value() const -> double { |
12632 | switch (m_units) { |
12633 | case Unit::Microseconds: |
12634 | return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMicrosecond); |
12635 | case Unit::Milliseconds: |
12636 | return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMillisecond); |
12637 | case Unit::Seconds: |
12638 | return m_inNanoseconds / static_cast<double>(s_nanosecondsInASecond); |
12639 | case Unit::Minutes: |
12640 | return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMinute); |
12641 | default: |
12642 | return static_cast<double>(m_inNanoseconds); |
12643 | } |
12644 | } |
12645 | auto unitsAsString() const -> std::string { |
12646 | switch (m_units) { |
12647 | case Unit::Nanoseconds: |
12648 | return "ns" ; |
12649 | case Unit::Microseconds: |
12650 | return "µs" ; |
12651 | case Unit::Milliseconds: |
12652 | return "ms" ; |
12653 | case Unit::Seconds: |
12654 | return "s" ; |
12655 | case Unit::Minutes: |
12656 | return "m" ; |
12657 | default: |
12658 | return "** internal error **" ; |
12659 | } |
12660 | |
12661 | } |
12662 | friend auto operator << (std::ostream& os, Duration const& duration) -> std::ostream& { |
12663 | return os << duration.value() << " " << duration.unitsAsString(); |
12664 | } |
12665 | }; |
12666 | } // end anon namespace |
12667 | |
12668 | class TablePrinter { |
12669 | std::ostream& m_os; |
12670 | std::vector<ColumnInfo> m_columnInfos; |
12671 | std::ostringstream m_oss; |
12672 | int m_currentColumn = -1; |
12673 | bool m_isOpen = false; |
12674 | |
12675 | public: |
12676 | TablePrinter( std::ostream& os, std::vector<ColumnInfo> columnInfos ) |
12677 | : m_os( os ), |
12678 | m_columnInfos( std::move( columnInfos ) ) {} |
12679 | |
12680 | auto columnInfos() const -> std::vector<ColumnInfo> const& { |
12681 | return m_columnInfos; |
12682 | } |
12683 | |
12684 | void open() { |
12685 | if (!m_isOpen) { |
12686 | m_isOpen = true; |
12687 | *this << RowBreak(); |
12688 | for (auto const& info : m_columnInfos) |
12689 | *this << info.name << ColumnBreak(); |
12690 | *this << RowBreak(); |
12691 | m_os << Catch::getLineOfChars<'-'>() << "\n" ; |
12692 | } |
12693 | } |
12694 | void close() { |
12695 | if (m_isOpen) { |
12696 | *this << RowBreak(); |
12697 | m_os << std::endl; |
12698 | m_isOpen = false; |
12699 | } |
12700 | } |
12701 | |
12702 | template<typename T> |
12703 | friend TablePrinter& operator << (TablePrinter& tp, T const& value) { |
12704 | tp.m_oss << value; |
12705 | return tp; |
12706 | } |
12707 | |
12708 | friend TablePrinter& operator << (TablePrinter& tp, ColumnBreak) { |
12709 | auto colStr = tp.m_oss.str(); |
12710 | // This takes account of utf8 encodings |
12711 | auto strSize = Catch::StringRef(colStr).numberOfCharacters(); |
12712 | tp.m_oss.str("" ); |
12713 | tp.open(); |
12714 | if (tp.m_currentColumn == static_cast<int>(tp.m_columnInfos.size() - 1)) { |
12715 | tp.m_currentColumn = -1; |
12716 | tp.m_os << "\n" ; |
12717 | } |
12718 | tp.m_currentColumn++; |
12719 | |
12720 | auto colInfo = tp.m_columnInfos[tp.m_currentColumn]; |
12721 | auto padding = (strSize + 2 < static_cast<std::size_t>(colInfo.width)) |
12722 | ? std::string(colInfo.width - (strSize + 2), ' ') |
12723 | : std::string(); |
12724 | if (colInfo.justification == ColumnInfo::Left) |
12725 | tp.m_os << colStr << padding << " " ; |
12726 | else |
12727 | tp.m_os << padding << colStr << " " ; |
12728 | return tp; |
12729 | } |
12730 | |
12731 | friend TablePrinter& operator << (TablePrinter& tp, RowBreak) { |
12732 | if (tp.m_currentColumn > 0) { |
12733 | tp.m_os << "\n" ; |
12734 | tp.m_currentColumn = -1; |
12735 | } |
12736 | return tp; |
12737 | } |
12738 | }; |
12739 | |
12740 | ConsoleReporter::ConsoleReporter(ReporterConfig const& config) |
12741 | : StreamingReporterBase(config), |
12742 | m_tablePrinter(new TablePrinter(config.stream(), |
12743 | { |
12744 | { "benchmark name" , CATCH_CONFIG_CONSOLE_WIDTH - 32, ColumnInfo::Left }, |
12745 | { "iters" , 8, ColumnInfo::Right }, |
12746 | { "elapsed ns" , 14, ColumnInfo::Right }, |
12747 | { "average" , 14, ColumnInfo::Right } |
12748 | })) {} |
12749 | ConsoleReporter::~ConsoleReporter() = default; |
12750 | |
12751 | std::string ConsoleReporter::getDescription() { |
12752 | return "Reports test results as plain lines of text" ; |
12753 | } |
12754 | |
12755 | void ConsoleReporter::noMatchingTestCases(std::string const& spec) { |
12756 | stream << "No test cases matched '" << spec << '\'' << std::endl; |
12757 | } |
12758 | |
12759 | void ConsoleReporter::assertionStarting(AssertionInfo const&) {} |
12760 | |
12761 | bool ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) { |
12762 | AssertionResult const& result = _assertionStats.assertionResult; |
12763 | |
12764 | bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); |
12765 | |
12766 | // Drop out if result was successful but we're not printing them. |
12767 | if (!includeResults && result.getResultType() != ResultWas::Warning) |
12768 | return false; |
12769 | |
12770 | lazyPrint(); |
12771 | |
12772 | ConsoleAssertionPrinter printer(stream, _assertionStats, includeResults); |
12773 | printer.print(); |
12774 | stream << std::endl; |
12775 | return true; |
12776 | } |
12777 | |
12778 | void ConsoleReporter::sectionStarting(SectionInfo const& _sectionInfo) { |
12779 | m_headerPrinted = false; |
12780 | StreamingReporterBase::sectionStarting(_sectionInfo); |
12781 | } |
12782 | void ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) { |
12783 | m_tablePrinter->close(); |
12784 | if (_sectionStats.missingAssertions) { |
12785 | lazyPrint(); |
12786 | Colour colour(Colour::ResultError); |
12787 | if (m_sectionStack.size() > 1) |
12788 | stream << "\nNo assertions in section" ; |
12789 | else |
12790 | stream << "\nNo assertions in test case" ; |
12791 | stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; |
12792 | } |
12793 | if (m_config->showDurations() == ShowDurations::Always) { |
12794 | stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; |
12795 | } |
12796 | if (m_headerPrinted) { |
12797 | m_headerPrinted = false; |
12798 | } |
12799 | StreamingReporterBase::sectionEnded(_sectionStats); |
12800 | } |
12801 | |
12802 | void ConsoleReporter::benchmarkStarting(BenchmarkInfo const& info) { |
12803 | lazyPrintWithoutClosingBenchmarkTable(); |
12804 | |
12805 | auto nameCol = Column( info.name ).width( static_cast<std::size_t>( m_tablePrinter->columnInfos()[0].width - 2 ) ); |
12806 | |
12807 | bool firstLine = true; |
12808 | for (auto line : nameCol) { |
12809 | if (!firstLine) |
12810 | (*m_tablePrinter) << ColumnBreak() << ColumnBreak() << ColumnBreak(); |
12811 | else |
12812 | firstLine = false; |
12813 | |
12814 | (*m_tablePrinter) << line << ColumnBreak(); |
12815 | } |
12816 | } |
12817 | void ConsoleReporter::benchmarkEnded(BenchmarkStats const& stats) { |
12818 | Duration average(stats.elapsedTimeInNanoseconds / stats.iterations); |
12819 | (*m_tablePrinter) |
12820 | << stats.iterations << ColumnBreak() |
12821 | << stats.elapsedTimeInNanoseconds << ColumnBreak() |
12822 | << average << ColumnBreak(); |
12823 | } |
12824 | |
12825 | void ConsoleReporter::testCaseEnded(TestCaseStats const& _testCaseStats) { |
12826 | m_tablePrinter->close(); |
12827 | StreamingReporterBase::testCaseEnded(_testCaseStats); |
12828 | m_headerPrinted = false; |
12829 | } |
12830 | void ConsoleReporter::testGroupEnded(TestGroupStats const& _testGroupStats) { |
12831 | if (currentGroupInfo.used) { |
12832 | printSummaryDivider(); |
12833 | stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n" ; |
12834 | printTotals(_testGroupStats.totals); |
12835 | stream << '\n' << std::endl; |
12836 | } |
12837 | StreamingReporterBase::testGroupEnded(_testGroupStats); |
12838 | } |
12839 | void ConsoleReporter::testRunEnded(TestRunStats const& _testRunStats) { |
12840 | printTotalsDivider(_testRunStats.totals); |
12841 | printTotals(_testRunStats.totals); |
12842 | stream << std::endl; |
12843 | StreamingReporterBase::testRunEnded(_testRunStats); |
12844 | } |
12845 | |
12846 | void ConsoleReporter::lazyPrint() { |
12847 | |
12848 | m_tablePrinter->close(); |
12849 | lazyPrintWithoutClosingBenchmarkTable(); |
12850 | } |
12851 | |
12852 | void ConsoleReporter::lazyPrintWithoutClosingBenchmarkTable() { |
12853 | |
12854 | if (!currentTestRunInfo.used) |
12855 | lazyPrintRunInfo(); |
12856 | if (!currentGroupInfo.used) |
12857 | lazyPrintGroupInfo(); |
12858 | |
12859 | if (!m_headerPrinted) { |
12860 | printTestCaseAndSectionHeader(); |
12861 | m_headerPrinted = true; |
12862 | } |
12863 | } |
12864 | void ConsoleReporter::lazyPrintRunInfo() { |
12865 | stream << '\n' << getLineOfChars<'~'>() << '\n'; |
12866 | Colour colour(Colour::SecondaryText); |
12867 | stream << currentTestRunInfo->name |
12868 | << " is a Catch v" << libraryVersion() << " host application.\n" |
12869 | << "Run with -? for options\n\n" ; |
12870 | |
12871 | if (m_config->rngSeed() != 0) |
12872 | stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n" ; |
12873 | |
12874 | currentTestRunInfo.used = true; |
12875 | } |
12876 | void ConsoleReporter::lazyPrintGroupInfo() { |
12877 | if (!currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1) { |
12878 | printClosedHeader("Group: " + currentGroupInfo->name); |
12879 | currentGroupInfo.used = true; |
12880 | } |
12881 | } |
12882 | void ConsoleReporter::printTestCaseAndSectionHeader() { |
12883 | assert(!m_sectionStack.empty()); |
12884 | printOpenHeader(currentTestCaseInfo->name); |
12885 | |
12886 | if (m_sectionStack.size() > 1) { |
12887 | Colour colourGuard(Colour::Headers); |
12888 | |
12889 | auto |
12890 | it = m_sectionStack.begin() + 1, // Skip first section (test case) |
12891 | itEnd = m_sectionStack.end(); |
12892 | for (; it != itEnd; ++it) |
12893 | printHeaderString(it->name, 2); |
12894 | } |
12895 | |
12896 | SourceLineInfo lineInfo = m_sectionStack.back().lineInfo; |
12897 | |
12898 | if (!lineInfo.empty()) { |
12899 | stream << getLineOfChars<'-'>() << '\n'; |
12900 | Colour colourGuard(Colour::FileName); |
12901 | stream << lineInfo << '\n'; |
12902 | } |
12903 | stream << getLineOfChars<'.'>() << '\n' << std::endl; |
12904 | } |
12905 | |
12906 | void ConsoleReporter::(std::string const& _name) { |
12907 | printOpenHeader(_name); |
12908 | stream << getLineOfChars<'.'>() << '\n'; |
12909 | } |
12910 | void ConsoleReporter::(std::string const& _name) { |
12911 | stream << getLineOfChars<'-'>() << '\n'; |
12912 | { |
12913 | Colour colourGuard(Colour::Headers); |
12914 | printHeaderString(_name); |
12915 | } |
12916 | } |
12917 | |
12918 | // if string has a : in first line will set indent to follow it on |
12919 | // subsequent lines |
12920 | void ConsoleReporter::(std::string const& _string, std::size_t indent) { |
12921 | std::size_t i = _string.find(": " ); |
12922 | if (i != std::string::npos) |
12923 | i += 2; |
12924 | else |
12925 | i = 0; |
12926 | stream << Column(_string).indent(indent + i).initialIndent(indent) << '\n'; |
12927 | } |
12928 | |
12929 | struct SummaryColumn { |
12930 | |
12931 | SummaryColumn( std::string _label, Colour::Code _colour ) |
12932 | : label( std::move( _label ) ), |
12933 | colour( _colour ) {} |
12934 | SummaryColumn addRow( std::size_t count ) { |
12935 | ReusableStringStream ; |
12936 | rss << count; |
12937 | std::string row = rss.str(); |
12938 | for (auto& oldRow : rows) { |
12939 | while (oldRow.size() < row.size()) |
12940 | oldRow = ' ' + oldRow; |
12941 | while (oldRow.size() > row.size()) |
12942 | row = ' ' + row; |
12943 | } |
12944 | rows.push_back(row); |
12945 | return *this; |
12946 | } |
12947 | |
12948 | std::string label; |
12949 | Colour::Code colour; |
12950 | std::vector<std::string> rows; |
12951 | |
12952 | }; |
12953 | |
12954 | void ConsoleReporter::printTotals( Totals const& totals ) { |
12955 | if (totals.testCases.total() == 0) { |
12956 | stream << Colour(Colour::Warning) << "No tests ran\n" ; |
12957 | } else if (totals.assertions.total() > 0 && totals.testCases.allPassed()) { |
12958 | stream << Colour(Colour::ResultSuccess) << "All tests passed" ; |
12959 | stream << " (" |
12960 | << pluralise(totals.assertions.passed, "assertion" ) << " in " |
12961 | << pluralise(totals.testCases.passed, "test case" ) << ')' |
12962 | << '\n'; |
12963 | } else { |
12964 | |
12965 | std::vector<SummaryColumn> columns; |
12966 | columns.push_back(SummaryColumn("" , Colour::None) |
12967 | .addRow(totals.testCases.total()) |
12968 | .addRow(totals.assertions.total())); |
12969 | columns.push_back(SummaryColumn("passed" , Colour::Success) |
12970 | .addRow(totals.testCases.passed) |
12971 | .addRow(totals.assertions.passed)); |
12972 | columns.push_back(SummaryColumn("failed" , Colour::ResultError) |
12973 | .addRow(totals.testCases.failed) |
12974 | .addRow(totals.assertions.failed)); |
12975 | columns.push_back(SummaryColumn("failed as expected" , Colour::ResultExpectedFailure) |
12976 | .addRow(totals.testCases.failedButOk) |
12977 | .addRow(totals.assertions.failedButOk)); |
12978 | |
12979 | printSummaryRow("test cases" , columns, 0); |
12980 | printSummaryRow("assertions" , columns, 1); |
12981 | } |
12982 | } |
12983 | void ConsoleReporter::printSummaryRow(std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row) { |
12984 | for (auto col : cols) { |
12985 | std::string value = col.rows[row]; |
12986 | if (col.label.empty()) { |
12987 | stream << label << ": " ; |
12988 | if (value != "0" ) |
12989 | stream << value; |
12990 | else |
12991 | stream << Colour(Colour::Warning) << "- none -" ; |
12992 | } else if (value != "0" ) { |
12993 | stream << Colour(Colour::LightGrey) << " | " ; |
12994 | stream << Colour(col.colour) |
12995 | << value << ' ' << col.label; |
12996 | } |
12997 | } |
12998 | stream << '\n'; |
12999 | } |
13000 | |
13001 | void ConsoleReporter::printTotalsDivider(Totals const& totals) { |
13002 | if (totals.testCases.total() > 0) { |
13003 | std::size_t failedRatio = makeRatio(totals.testCases.failed, totals.testCases.total()); |
13004 | std::size_t failedButOkRatio = makeRatio(totals.testCases.failedButOk, totals.testCases.total()); |
13005 | std::size_t passedRatio = makeRatio(totals.testCases.passed, totals.testCases.total()); |
13006 | while (failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH - 1) |
13007 | findMax(failedRatio, failedButOkRatio, passedRatio)++; |
13008 | while (failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH - 1) |
13009 | findMax(failedRatio, failedButOkRatio, passedRatio)--; |
13010 | |
13011 | stream << Colour(Colour::Error) << std::string(failedRatio, '='); |
13012 | stream << Colour(Colour::ResultExpectedFailure) << std::string(failedButOkRatio, '='); |
13013 | if (totals.testCases.allPassed()) |
13014 | stream << Colour(Colour::ResultSuccess) << std::string(passedRatio, '='); |
13015 | else |
13016 | stream << Colour(Colour::Success) << std::string(passedRatio, '='); |
13017 | } else { |
13018 | stream << Colour(Colour::Warning) << std::string(CATCH_CONFIG_CONSOLE_WIDTH - 1, '='); |
13019 | } |
13020 | stream << '\n'; |
13021 | } |
13022 | void ConsoleReporter::printSummaryDivider() { |
13023 | stream << getLineOfChars<'-'>() << '\n'; |
13024 | } |
13025 | |
13026 | CATCH_REGISTER_REPORTER("console" , ConsoleReporter) |
13027 | |
13028 | } // end namespace Catch |
13029 | |
13030 | #if defined(_MSC_VER) |
13031 | #pragma warning(pop) |
13032 | #endif |
13033 | // end catch_reporter_console.cpp |
13034 | // start catch_reporter_junit.cpp |
13035 | |
13036 | #include <cassert> |
13037 | #include <sstream> |
13038 | #include <ctime> |
13039 | #include <algorithm> |
13040 | |
13041 | namespace Catch { |
13042 | |
13043 | namespace { |
13044 | std::string getCurrentTimestamp() { |
13045 | // Beware, this is not reentrant because of backward compatibility issues |
13046 | // Also, UTC only, again because of backward compatibility (%z is C++11) |
13047 | time_t rawtime; |
13048 | std::time(&rawtime); |
13049 | auto const timeStampSize = sizeof("2017-01-16T17:06:45Z" ); |
13050 | |
13051 | #ifdef _MSC_VER |
13052 | std::tm timeInfo = {}; |
13053 | gmtime_s(&timeInfo, &rawtime); |
13054 | #else |
13055 | std::tm* timeInfo; |
13056 | timeInfo = std::gmtime(&rawtime); |
13057 | #endif |
13058 | |
13059 | char timeStamp[timeStampSize]; |
13060 | const char * const fmt = "%Y-%m-%dT%H:%M:%SZ" ; |
13061 | |
13062 | #ifdef _MSC_VER |
13063 | std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); |
13064 | #else |
13065 | std::strftime(timeStamp, timeStampSize, fmt, timeInfo); |
13066 | #endif |
13067 | return std::string(timeStamp); |
13068 | } |
13069 | |
13070 | std::string fileNameTag(const std::vector<std::string> &tags) { |
13071 | auto it = std::find_if(begin(tags), |
13072 | end(tags), |
13073 | [] (std::string const& tag) {return tag.front() == '#'; }); |
13074 | if (it != tags.end()) |
13075 | return it->substr(1); |
13076 | return std::string(); |
13077 | } |
13078 | } // anonymous namespace |
13079 | |
13080 | JunitReporter::JunitReporter( ReporterConfig const& _config ) |
13081 | : CumulativeReporterBase( _config ), |
13082 | xml( _config.stream() ) |
13083 | { |
13084 | m_reporterPrefs.shouldRedirectStdOut = true; |
13085 | m_reporterPrefs.shouldReportAllAssertions = true; |
13086 | } |
13087 | |
13088 | JunitReporter::~JunitReporter() {} |
13089 | |
13090 | std::string JunitReporter::getDescription() { |
13091 | return "Reports test results in an XML format that looks like Ant's junitreport target" ; |
13092 | } |
13093 | |
13094 | void JunitReporter::noMatchingTestCases( std::string const& /*spec*/ ) {} |
13095 | |
13096 | void JunitReporter::testRunStarting( TestRunInfo const& runInfo ) { |
13097 | CumulativeReporterBase::testRunStarting( runInfo ); |
13098 | xml.startElement( "testsuites" ); |
13099 | } |
13100 | |
13101 | void JunitReporter::testGroupStarting( GroupInfo const& groupInfo ) { |
13102 | suiteTimer.start(); |
13103 | stdOutForSuite.clear(); |
13104 | stdErrForSuite.clear(); |
13105 | unexpectedExceptions = 0; |
13106 | CumulativeReporterBase::testGroupStarting( groupInfo ); |
13107 | } |
13108 | |
13109 | void JunitReporter::testCaseStarting( TestCaseInfo const& testCaseInfo ) { |
13110 | m_okToFail = testCaseInfo.okToFail(); |
13111 | } |
13112 | |
13113 | bool JunitReporter::assertionEnded( AssertionStats const& assertionStats ) { |
13114 | if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail ) |
13115 | unexpectedExceptions++; |
13116 | return CumulativeReporterBase::assertionEnded( assertionStats ); |
13117 | } |
13118 | |
13119 | void JunitReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { |
13120 | stdOutForSuite += testCaseStats.stdOut; |
13121 | stdErrForSuite += testCaseStats.stdErr; |
13122 | CumulativeReporterBase::testCaseEnded( testCaseStats ); |
13123 | } |
13124 | |
13125 | void JunitReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { |
13126 | double suiteTime = suiteTimer.getElapsedSeconds(); |
13127 | CumulativeReporterBase::testGroupEnded( testGroupStats ); |
13128 | writeGroup( *m_testGroups.back(), suiteTime ); |
13129 | } |
13130 | |
13131 | void JunitReporter::testRunEndedCumulative() { |
13132 | xml.endElement(); |
13133 | } |
13134 | |
13135 | void JunitReporter::writeGroup( TestGroupNode const& groupNode, double suiteTime ) { |
13136 | XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); |
13137 | TestGroupStats const& stats = groupNode.value; |
13138 | xml.writeAttribute( "name" , stats.groupInfo.name ); |
13139 | xml.writeAttribute( "errors" , unexpectedExceptions ); |
13140 | xml.writeAttribute( "failures" , stats.totals.assertions.failed-unexpectedExceptions ); |
13141 | xml.writeAttribute( "tests" , stats.totals.assertions.total() ); |
13142 | xml.writeAttribute( "hostname" , "tbd" ); // !TBD |
13143 | if( m_config->showDurations() == ShowDurations::Never ) |
13144 | xml.writeAttribute( "time" , "" ); |
13145 | else |
13146 | xml.writeAttribute( "time" , suiteTime ); |
13147 | xml.writeAttribute( "timestamp" , getCurrentTimestamp() ); |
13148 | |
13149 | // Write test cases |
13150 | for( auto const& child : groupNode.children ) |
13151 | writeTestCase( *child ); |
13152 | |
13153 | xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite ), false ); |
13154 | xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite ), false ); |
13155 | } |
13156 | |
13157 | void JunitReporter::writeTestCase( TestCaseNode const& testCaseNode ) { |
13158 | TestCaseStats const& stats = testCaseNode.value; |
13159 | |
13160 | // All test cases have exactly one section - which represents the |
13161 | // test case itself. That section may have 0-n nested sections |
13162 | assert( testCaseNode.children.size() == 1 ); |
13163 | SectionNode const& rootSection = *testCaseNode.children.front(); |
13164 | |
13165 | std::string className = stats.testInfo.className; |
13166 | |
13167 | if( className.empty() ) { |
13168 | className = fileNameTag(stats.testInfo.tags); |
13169 | if ( className.empty() ) |
13170 | className = "global" ; |
13171 | } |
13172 | |
13173 | if ( !m_config->name().empty() ) |
13174 | className = m_config->name() + "." + className; |
13175 | |
13176 | writeSection( className, "" , rootSection ); |
13177 | } |
13178 | |
13179 | void JunitReporter::writeSection( std::string const& className, |
13180 | std::string const& rootName, |
13181 | SectionNode const& sectionNode ) { |
13182 | std::string name = trim( sectionNode.stats.sectionInfo.name ); |
13183 | if( !rootName.empty() ) |
13184 | name = rootName + '/' + name; |
13185 | |
13186 | if( !sectionNode.assertions.empty() || |
13187 | !sectionNode.stdOut.empty() || |
13188 | !sectionNode.stdErr.empty() ) { |
13189 | XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); |
13190 | if( className.empty() ) { |
13191 | xml.writeAttribute( "classname" , name ); |
13192 | xml.writeAttribute( "name" , "root" ); |
13193 | } |
13194 | else { |
13195 | xml.writeAttribute( "classname" , className ); |
13196 | xml.writeAttribute( "name" , name ); |
13197 | } |
13198 | xml.writeAttribute( "time" , ::Catch::Detail::stringify( sectionNode.stats.durationInSeconds ) ); |
13199 | |
13200 | writeAssertions( sectionNode ); |
13201 | |
13202 | if( !sectionNode.stdOut.empty() ) |
13203 | xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false ); |
13204 | if( !sectionNode.stdErr.empty() ) |
13205 | xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false ); |
13206 | } |
13207 | for( auto const& childNode : sectionNode.childSections ) |
13208 | if( className.empty() ) |
13209 | writeSection( name, "" , *childNode ); |
13210 | else |
13211 | writeSection( className, name, *childNode ); |
13212 | } |
13213 | |
13214 | void JunitReporter::writeAssertions( SectionNode const& sectionNode ) { |
13215 | for( auto const& assertion : sectionNode.assertions ) |
13216 | writeAssertion( assertion ); |
13217 | } |
13218 | |
13219 | void JunitReporter::writeAssertion( AssertionStats const& stats ) { |
13220 | AssertionResult const& result = stats.assertionResult; |
13221 | if( !result.isOk() ) { |
13222 | std::string elementName; |
13223 | switch( result.getResultType() ) { |
13224 | case ResultWas::ThrewException: |
13225 | case ResultWas::FatalErrorCondition: |
13226 | elementName = "error" ; |
13227 | break; |
13228 | case ResultWas::ExplicitFailure: |
13229 | elementName = "failure" ; |
13230 | break; |
13231 | case ResultWas::ExpressionFailed: |
13232 | elementName = "failure" ; |
13233 | break; |
13234 | case ResultWas::DidntThrowException: |
13235 | elementName = "failure" ; |
13236 | break; |
13237 | |
13238 | // We should never see these here: |
13239 | case ResultWas::Info: |
13240 | case ResultWas::Warning: |
13241 | case ResultWas::Ok: |
13242 | case ResultWas::Unknown: |
13243 | case ResultWas::FailureBit: |
13244 | case ResultWas::Exception: |
13245 | elementName = "internalError" ; |
13246 | break; |
13247 | } |
13248 | |
13249 | XmlWriter::ScopedElement e = xml.scopedElement( elementName ); |
13250 | |
13251 | xml.writeAttribute( "message" , result.getExpandedExpression() ); |
13252 | xml.writeAttribute( "type" , result.getTestMacroName() ); |
13253 | |
13254 | ReusableStringStream ; |
13255 | if( !result.getMessage().empty() ) |
13256 | rss << result.getMessage() << '\n'; |
13257 | for( auto const& msg : stats.infoMessages ) |
13258 | if( msg.type == ResultWas::Info ) |
13259 | rss << msg.message << '\n'; |
13260 | |
13261 | rss << "at " << result.getSourceInfo(); |
13262 | xml.writeText( rss.str(), false ); |
13263 | } |
13264 | } |
13265 | |
13266 | CATCH_REGISTER_REPORTER( "junit" , JunitReporter ) |
13267 | |
13268 | } // end namespace Catch |
13269 | // end catch_reporter_junit.cpp |
13270 | // start catch_reporter_listening.cpp |
13271 | |
13272 | #include <cassert> |
13273 | |
13274 | namespace Catch { |
13275 | |
13276 | ListeningReporter::ListeningReporter() { |
13277 | // We will assume that listeners will always want all assertions |
13278 | m_preferences.shouldReportAllAssertions = true; |
13279 | } |
13280 | |
13281 | void ListeningReporter::addListener( IStreamingReporterPtr&& listener ) { |
13282 | m_listeners.push_back( std::move( listener ) ); |
13283 | } |
13284 | |
13285 | void ListeningReporter::addReporter(IStreamingReporterPtr&& reporter) { |
13286 | assert(!m_reporter && "Listening reporter can wrap only 1 real reporter" ); |
13287 | m_reporter = std::move( reporter ); |
13288 | m_preferences.shouldRedirectStdOut = m_reporter->getPreferences().shouldRedirectStdOut; |
13289 | } |
13290 | |
13291 | ReporterPreferences ListeningReporter::getPreferences() const { |
13292 | return m_preferences; |
13293 | } |
13294 | |
13295 | std::set<Verbosity> ListeningReporter::getSupportedVerbosities() { |
13296 | return std::set<Verbosity>{ }; |
13297 | } |
13298 | |
13299 | void ListeningReporter::noMatchingTestCases( std::string const& spec ) { |
13300 | for ( auto const& listener : m_listeners ) { |
13301 | listener->noMatchingTestCases( spec ); |
13302 | } |
13303 | m_reporter->noMatchingTestCases( spec ); |
13304 | } |
13305 | |
13306 | void ListeningReporter::benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) { |
13307 | for ( auto const& listener : m_listeners ) { |
13308 | listener->benchmarkStarting( benchmarkInfo ); |
13309 | } |
13310 | m_reporter->benchmarkStarting( benchmarkInfo ); |
13311 | } |
13312 | void ListeningReporter::benchmarkEnded( BenchmarkStats const& benchmarkStats ) { |
13313 | for ( auto const& listener : m_listeners ) { |
13314 | listener->benchmarkEnded( benchmarkStats ); |
13315 | } |
13316 | m_reporter->benchmarkEnded( benchmarkStats ); |
13317 | } |
13318 | |
13319 | void ListeningReporter::testRunStarting( TestRunInfo const& testRunInfo ) { |
13320 | for ( auto const& listener : m_listeners ) { |
13321 | listener->testRunStarting( testRunInfo ); |
13322 | } |
13323 | m_reporter->testRunStarting( testRunInfo ); |
13324 | } |
13325 | |
13326 | void ListeningReporter::testGroupStarting( GroupInfo const& groupInfo ) { |
13327 | for ( auto const& listener : m_listeners ) { |
13328 | listener->testGroupStarting( groupInfo ); |
13329 | } |
13330 | m_reporter->testGroupStarting( groupInfo ); |
13331 | } |
13332 | |
13333 | void ListeningReporter::testCaseStarting( TestCaseInfo const& testInfo ) { |
13334 | for ( auto const& listener : m_listeners ) { |
13335 | listener->testCaseStarting( testInfo ); |
13336 | } |
13337 | m_reporter->testCaseStarting( testInfo ); |
13338 | } |
13339 | |
13340 | void ListeningReporter::sectionStarting( SectionInfo const& sectionInfo ) { |
13341 | for ( auto const& listener : m_listeners ) { |
13342 | listener->sectionStarting( sectionInfo ); |
13343 | } |
13344 | m_reporter->sectionStarting( sectionInfo ); |
13345 | } |
13346 | |
13347 | void ListeningReporter::assertionStarting( AssertionInfo const& assertionInfo ) { |
13348 | for ( auto const& listener : m_listeners ) { |
13349 | listener->assertionStarting( assertionInfo ); |
13350 | } |
13351 | m_reporter->assertionStarting( assertionInfo ); |
13352 | } |
13353 | |
13354 | // The return value indicates if the messages buffer should be cleared: |
13355 | bool ListeningReporter::assertionEnded( AssertionStats const& assertionStats ) { |
13356 | for( auto const& listener : m_listeners ) { |
13357 | static_cast<void>( listener->assertionEnded( assertionStats ) ); |
13358 | } |
13359 | return m_reporter->assertionEnded( assertionStats ); |
13360 | } |
13361 | |
13362 | void ListeningReporter::sectionEnded( SectionStats const& sectionStats ) { |
13363 | for ( auto const& listener : m_listeners ) { |
13364 | listener->sectionEnded( sectionStats ); |
13365 | } |
13366 | m_reporter->sectionEnded( sectionStats ); |
13367 | } |
13368 | |
13369 | void ListeningReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { |
13370 | for ( auto const& listener : m_listeners ) { |
13371 | listener->testCaseEnded( testCaseStats ); |
13372 | } |
13373 | m_reporter->testCaseEnded( testCaseStats ); |
13374 | } |
13375 | |
13376 | void ListeningReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { |
13377 | for ( auto const& listener : m_listeners ) { |
13378 | listener->testGroupEnded( testGroupStats ); |
13379 | } |
13380 | m_reporter->testGroupEnded( testGroupStats ); |
13381 | } |
13382 | |
13383 | void ListeningReporter::testRunEnded( TestRunStats const& testRunStats ) { |
13384 | for ( auto const& listener : m_listeners ) { |
13385 | listener->testRunEnded( testRunStats ); |
13386 | } |
13387 | m_reporter->testRunEnded( testRunStats ); |
13388 | } |
13389 | |
13390 | void ListeningReporter::skipTest( TestCaseInfo const& testInfo ) { |
13391 | for ( auto const& listener : m_listeners ) { |
13392 | listener->skipTest( testInfo ); |
13393 | } |
13394 | m_reporter->skipTest( testInfo ); |
13395 | } |
13396 | |
13397 | bool ListeningReporter::isMulti() const { |
13398 | return true; |
13399 | } |
13400 | |
13401 | } // end namespace Catch |
13402 | // end catch_reporter_listening.cpp |
13403 | // start catch_reporter_xml.cpp |
13404 | |
13405 | #if defined(_MSC_VER) |
13406 | #pragma warning(push) |
13407 | #pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch |
13408 | // Note that 4062 (not all labels are handled |
13409 | // and default is missing) is enabled |
13410 | #endif |
13411 | |
13412 | namespace Catch { |
13413 | XmlReporter::XmlReporter( ReporterConfig const& _config ) |
13414 | : StreamingReporterBase( _config ), |
13415 | m_xml(_config.stream()) |
13416 | { |
13417 | m_reporterPrefs.shouldRedirectStdOut = true; |
13418 | m_reporterPrefs.shouldReportAllAssertions = true; |
13419 | } |
13420 | |
13421 | XmlReporter::~XmlReporter() = default; |
13422 | |
13423 | std::string XmlReporter::getDescription() { |
13424 | return "Reports test results as an XML document" ; |
13425 | } |
13426 | |
13427 | std::string XmlReporter::getStylesheetRef() const { |
13428 | return std::string(); |
13429 | } |
13430 | |
13431 | void XmlReporter::writeSourceInfo( SourceLineInfo const& sourceInfo ) { |
13432 | m_xml |
13433 | .writeAttribute( "filename" , sourceInfo.file ) |
13434 | .writeAttribute( "line" , sourceInfo.line ); |
13435 | } |
13436 | |
13437 | void XmlReporter::noMatchingTestCases( std::string const& s ) { |
13438 | StreamingReporterBase::noMatchingTestCases( s ); |
13439 | } |
13440 | |
13441 | void XmlReporter::testRunStarting( TestRunInfo const& testInfo ) { |
13442 | StreamingReporterBase::testRunStarting( testInfo ); |
13443 | std::string stylesheetRef = getStylesheetRef(); |
13444 | if( !stylesheetRef.empty() ) |
13445 | m_xml.writeStylesheetRef( stylesheetRef ); |
13446 | m_xml.startElement( "Catch" ); |
13447 | if( !m_config->name().empty() ) |
13448 | m_xml.writeAttribute( "name" , m_config->name() ); |
13449 | } |
13450 | |
13451 | void XmlReporter::testGroupStarting( GroupInfo const& groupInfo ) { |
13452 | StreamingReporterBase::testGroupStarting( groupInfo ); |
13453 | m_xml.startElement( "Group" ) |
13454 | .writeAttribute( "name" , groupInfo.name ); |
13455 | } |
13456 | |
13457 | void XmlReporter::testCaseStarting( TestCaseInfo const& testInfo ) { |
13458 | StreamingReporterBase::testCaseStarting(testInfo); |
13459 | m_xml.startElement( "TestCase" ) |
13460 | .writeAttribute( "name" , trim( testInfo.name ) ) |
13461 | .writeAttribute( "description" , testInfo.description ) |
13462 | .writeAttribute( "tags" , testInfo.tagsAsString() ); |
13463 | |
13464 | writeSourceInfo( testInfo.lineInfo ); |
13465 | |
13466 | if ( m_config->showDurations() == ShowDurations::Always ) |
13467 | m_testCaseTimer.start(); |
13468 | m_xml.ensureTagClosed(); |
13469 | } |
13470 | |
13471 | void XmlReporter::sectionStarting( SectionInfo const& sectionInfo ) { |
13472 | StreamingReporterBase::sectionStarting( sectionInfo ); |
13473 | if( m_sectionDepth++ > 0 ) { |
13474 | m_xml.startElement( "Section" ) |
13475 | .writeAttribute( "name" , trim( sectionInfo.name ) ); |
13476 | writeSourceInfo( sectionInfo.lineInfo ); |
13477 | m_xml.ensureTagClosed(); |
13478 | } |
13479 | } |
13480 | |
13481 | void XmlReporter::assertionStarting( AssertionInfo const& ) { } |
13482 | |
13483 | bool XmlReporter::assertionEnded( AssertionStats const& assertionStats ) { |
13484 | |
13485 | AssertionResult const& result = assertionStats.assertionResult; |
13486 | |
13487 | bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); |
13488 | |
13489 | if( includeResults || result.getResultType() == ResultWas::Warning ) { |
13490 | // Print any info messages in <Info> tags. |
13491 | for( auto const& msg : assertionStats.infoMessages ) { |
13492 | if( msg.type == ResultWas::Info && includeResults ) { |
13493 | m_xml.scopedElement( "Info" ) |
13494 | .writeText( msg.message ); |
13495 | } else if ( msg.type == ResultWas::Warning ) { |
13496 | m_xml.scopedElement( "Warning" ) |
13497 | .writeText( msg.message ); |
13498 | } |
13499 | } |
13500 | } |
13501 | |
13502 | // Drop out if result was successful but we're not printing them. |
13503 | if( !includeResults && result.getResultType() != ResultWas::Warning ) |
13504 | return true; |
13505 | |
13506 | // Print the expression if there is one. |
13507 | if( result.hasExpression() ) { |
13508 | m_xml.startElement( "Expression" ) |
13509 | .writeAttribute( "success" , result.succeeded() ) |
13510 | .writeAttribute( "type" , result.getTestMacroName() ); |
13511 | |
13512 | writeSourceInfo( result.getSourceInfo() ); |
13513 | |
13514 | m_xml.scopedElement( "Original" ) |
13515 | .writeText( result.getExpression() ); |
13516 | m_xml.scopedElement( "Expanded" ) |
13517 | .writeText( result.getExpandedExpression() ); |
13518 | } |
13519 | |
13520 | // And... Print a result applicable to each result type. |
13521 | switch( result.getResultType() ) { |
13522 | case ResultWas::ThrewException: |
13523 | m_xml.startElement( "Exception" ); |
13524 | writeSourceInfo( result.getSourceInfo() ); |
13525 | m_xml.writeText( result.getMessage() ); |
13526 | m_xml.endElement(); |
13527 | break; |
13528 | case ResultWas::FatalErrorCondition: |
13529 | m_xml.startElement( "FatalErrorCondition" ); |
13530 | writeSourceInfo( result.getSourceInfo() ); |
13531 | m_xml.writeText( result.getMessage() ); |
13532 | m_xml.endElement(); |
13533 | break; |
13534 | case ResultWas::Info: |
13535 | m_xml.scopedElement( "Info" ) |
13536 | .writeText( result.getMessage() ); |
13537 | break; |
13538 | case ResultWas::Warning: |
13539 | // Warning will already have been written |
13540 | break; |
13541 | case ResultWas::ExplicitFailure: |
13542 | m_xml.startElement( "Failure" ); |
13543 | writeSourceInfo( result.getSourceInfo() ); |
13544 | m_xml.writeText( result.getMessage() ); |
13545 | m_xml.endElement(); |
13546 | break; |
13547 | default: |
13548 | break; |
13549 | } |
13550 | |
13551 | if( result.hasExpression() ) |
13552 | m_xml.endElement(); |
13553 | |
13554 | return true; |
13555 | } |
13556 | |
13557 | void XmlReporter::sectionEnded( SectionStats const& sectionStats ) { |
13558 | StreamingReporterBase::sectionEnded( sectionStats ); |
13559 | if( --m_sectionDepth > 0 ) { |
13560 | XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); |
13561 | e.writeAttribute( "successes" , sectionStats.assertions.passed ); |
13562 | e.writeAttribute( "failures" , sectionStats.assertions.failed ); |
13563 | e.writeAttribute( "expectedFailures" , sectionStats.assertions.failedButOk ); |
13564 | |
13565 | if ( m_config->showDurations() == ShowDurations::Always ) |
13566 | e.writeAttribute( "durationInSeconds" , sectionStats.durationInSeconds ); |
13567 | |
13568 | m_xml.endElement(); |
13569 | } |
13570 | } |
13571 | |
13572 | void XmlReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { |
13573 | StreamingReporterBase::testCaseEnded( testCaseStats ); |
13574 | XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); |
13575 | e.writeAttribute( "success" , testCaseStats.totals.assertions.allOk() ); |
13576 | |
13577 | if ( m_config->showDurations() == ShowDurations::Always ) |
13578 | e.writeAttribute( "durationInSeconds" , m_testCaseTimer.getElapsedSeconds() ); |
13579 | |
13580 | if( !testCaseStats.stdOut.empty() ) |
13581 | m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), false ); |
13582 | if( !testCaseStats.stdErr.empty() ) |
13583 | m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), false ); |
13584 | |
13585 | m_xml.endElement(); |
13586 | } |
13587 | |
13588 | void XmlReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { |
13589 | StreamingReporterBase::testGroupEnded( testGroupStats ); |
13590 | // TODO: Check testGroupStats.aborting and act accordingly. |
13591 | m_xml.scopedElement( "OverallResults" ) |
13592 | .writeAttribute( "successes" , testGroupStats.totals.assertions.passed ) |
13593 | .writeAttribute( "failures" , testGroupStats.totals.assertions.failed ) |
13594 | .writeAttribute( "expectedFailures" , testGroupStats.totals.assertions.failedButOk ); |
13595 | m_xml.endElement(); |
13596 | } |
13597 | |
13598 | void XmlReporter::testRunEnded( TestRunStats const& testRunStats ) { |
13599 | StreamingReporterBase::testRunEnded( testRunStats ); |
13600 | m_xml.scopedElement( "OverallResults" ) |
13601 | .writeAttribute( "successes" , testRunStats.totals.assertions.passed ) |
13602 | .writeAttribute( "failures" , testRunStats.totals.assertions.failed ) |
13603 | .writeAttribute( "expectedFailures" , testRunStats.totals.assertions.failedButOk ); |
13604 | m_xml.endElement(); |
13605 | } |
13606 | |
13607 | CATCH_REGISTER_REPORTER( "xml" , XmlReporter ) |
13608 | |
13609 | } // end namespace Catch |
13610 | |
13611 | #if defined(_MSC_VER) |
13612 | #pragma warning(pop) |
13613 | #endif |
13614 | // end catch_reporter_xml.cpp |
13615 | |
13616 | namespace Catch { |
13617 | LeakDetector leakDetector; |
13618 | } |
13619 | |
13620 | #ifdef __clang__ |
13621 | #pragma clang diagnostic pop |
13622 | #endif |
13623 | |
13624 | // end catch_impl.hpp |
13625 | #endif |
13626 | |
13627 | #ifdef CATCH_CONFIG_MAIN |
13628 | // start catch_default_main.hpp |
13629 | |
13630 | #ifndef __OBJC__ |
13631 | |
13632 | #if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN) |
13633 | // Standard C/C++ Win32 Unicode wmain entry point |
13634 | extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) { |
13635 | #else |
13636 | // Standard C/C++ main entry point |
13637 | int main (int argc, char * argv[]) { |
13638 | #endif |
13639 | |
13640 | return Catch::Session().run( argc, argv ); |
13641 | } |
13642 | |
13643 | #else // __OBJC__ |
13644 | |
13645 | // Objective-C entry point |
13646 | int main (int argc, char * const argv[]) { |
13647 | #if !CATCH_ARC_ENABLED |
13648 | NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; |
13649 | #endif |
13650 | |
13651 | Catch::registerTestMethods(); |
13652 | int result = Catch::Session().run( argc, (char**)argv ); |
13653 | |
13654 | #if !CATCH_ARC_ENABLED |
13655 | [pool drain]; |
13656 | #endif |
13657 | |
13658 | return result; |
13659 | } |
13660 | |
13661 | #endif // __OBJC__ |
13662 | |
13663 | // end catch_default_main.hpp |
13664 | #endif |
13665 | |
13666 | #if !defined(CATCH_CONFIG_IMPL_ONLY) |
13667 | |
13668 | #ifdef CLARA_CONFIG_MAIN_NOT_DEFINED |
13669 | # undef CLARA_CONFIG_MAIN |
13670 | #endif |
13671 | |
13672 | #if !defined(CATCH_CONFIG_DISABLE) |
13673 | ////// |
13674 | // If this config identifier is defined then all CATCH macros are prefixed with CATCH_ |
13675 | #ifdef CATCH_CONFIG_PREFIX_ALL |
13676 | |
13677 | #define CATCH_REQUIRE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ ) |
13678 | #define CATCH_REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) |
13679 | |
13680 | #define CATCH_REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", __VA_ARGS__ ) |
13681 | #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) |
13682 | #define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) |
13683 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) |
13684 | #define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr ) |
13685 | #endif// CATCH_CONFIG_DISABLE_MATCHERS |
13686 | #define CATCH_REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ ) |
13687 | |
13688 | #define CATCH_CHECK( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) |
13689 | #define CATCH_CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) |
13690 | #define CATCH_CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CATCH_CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) |
13691 | #define CATCH_CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) |
13692 | #define CATCH_CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ ) |
13693 | |
13694 | #define CATCH_CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", __VA_ARGS__ ) |
13695 | #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) |
13696 | #define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) |
13697 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) |
13698 | #define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) |
13699 | #endif // CATCH_CONFIG_DISABLE_MATCHERS |
13700 | #define CATCH_CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) |
13701 | |
13702 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) |
13703 | #define CATCH_CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg ) |
13704 | |
13705 | #define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) |
13706 | #endif // CATCH_CONFIG_DISABLE_MATCHERS |
13707 | |
13708 | #define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg ) |
13709 | #define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) |
13710 | #define CATCH_CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CATCH_CAPTURE",__VA_ARGS__ ) |
13711 | |
13712 | #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) |
13713 | #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) |
13714 | #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) |
13715 | #define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) |
13716 | #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) |
13717 | #define CATCH_DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ ) |
13718 | #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) |
13719 | #define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) |
13720 | #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) |
13721 | |
13722 | #define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE() |
13723 | |
13724 | // "BDD-style" convenience wrappers |
13725 | #define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ ) |
13726 | #define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) |
13727 | #define CATCH_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc ) |
13728 | #define CATCH_AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc ) |
13729 | #define CATCH_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc ) |
13730 | #define CATCH_AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc ) |
13731 | #define CATCH_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc ) |
13732 | #define CATCH_AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc ) |
13733 | |
13734 | // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required |
13735 | #else |
13736 | |
13737 | #define REQUIRE( ... ) INTERNAL_CATCH_TEST( "REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ ) |
13738 | #define REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) |
13739 | |
13740 | #define REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ ) |
13741 | #define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) |
13742 | #define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) |
13743 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) |
13744 | #define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr ) |
13745 | #endif // CATCH_CONFIG_DISABLE_MATCHERS |
13746 | #define REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ ) |
13747 | |
13748 | #define CHECK( ... ) INTERNAL_CATCH_TEST( "CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) |
13749 | #define CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) |
13750 | #define CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) |
13751 | #define CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) |
13752 | #define CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ ) |
13753 | |
13754 | #define CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) |
13755 | #define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) |
13756 | #define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) |
13757 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) |
13758 | #define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) |
13759 | #endif // CATCH_CONFIG_DISABLE_MATCHERS |
13760 | #define CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) |
13761 | |
13762 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) |
13763 | #define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg ) |
13764 | |
13765 | #define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) |
13766 | #endif // CATCH_CONFIG_DISABLE_MATCHERS |
13767 | |
13768 | #define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg ) |
13769 | #define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) |
13770 | #define CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CAPTURE",__VA_ARGS__ ) |
13771 | |
13772 | #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) |
13773 | #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) |
13774 | #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) |
13775 | #define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) |
13776 | #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) |
13777 | #define DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ ) |
13778 | #define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) |
13779 | #define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) |
13780 | #define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) |
13781 | #define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE() |
13782 | |
13783 | #endif |
13784 | |
13785 | #define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) |
13786 | |
13787 | // "BDD-style" convenience wrappers |
13788 | #define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ ) |
13789 | #define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) |
13790 | |
13791 | #define GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc ) |
13792 | #define AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc ) |
13793 | #define WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc ) |
13794 | #define AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc ) |
13795 | #define THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc ) |
13796 | #define AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc ) |
13797 | |
13798 | using Catch::Detail::Approx; |
13799 | |
13800 | #else // CATCH_CONFIG_DISABLE |
13801 | |
13802 | ////// |
13803 | // If this config identifier is defined then all CATCH macros are prefixed with CATCH_ |
13804 | #ifdef CATCH_CONFIG_PREFIX_ALL |
13805 | |
13806 | #define CATCH_REQUIRE( ... ) (void)(0) |
13807 | #define CATCH_REQUIRE_FALSE( ... ) (void)(0) |
13808 | |
13809 | #define CATCH_REQUIRE_THROWS( ... ) (void)(0) |
13810 | #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0) |
13811 | #define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) (void)(0) |
13812 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) |
13813 | #define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) |
13814 | #endif// CATCH_CONFIG_DISABLE_MATCHERS |
13815 | #define CATCH_REQUIRE_NOTHROW( ... ) (void)(0) |
13816 | |
13817 | #define CATCH_CHECK( ... ) (void)(0) |
13818 | #define CATCH_CHECK_FALSE( ... ) (void)(0) |
13819 | #define CATCH_CHECKED_IF( ... ) if (__VA_ARGS__) |
13820 | #define CATCH_CHECKED_ELSE( ... ) if (!(__VA_ARGS__)) |
13821 | #define CATCH_CHECK_NOFAIL( ... ) (void)(0) |
13822 | |
13823 | #define CATCH_CHECK_THROWS( ... ) (void)(0) |
13824 | #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) (void)(0) |
13825 | #define CATCH_CHECK_THROWS_WITH( expr, matcher ) (void)(0) |
13826 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) |
13827 | #define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) |
13828 | #endif // CATCH_CONFIG_DISABLE_MATCHERS |
13829 | #define CATCH_CHECK_NOTHROW( ... ) (void)(0) |
13830 | |
13831 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) |
13832 | #define CATCH_CHECK_THAT( arg, matcher ) (void)(0) |
13833 | |
13834 | #define CATCH_REQUIRE_THAT( arg, matcher ) (void)(0) |
13835 | #endif // CATCH_CONFIG_DISABLE_MATCHERS |
13836 | |
13837 | #define CATCH_INFO( msg ) (void)(0) |
13838 | #define CATCH_WARN( msg ) (void)(0) |
13839 | #define CATCH_CAPTURE( msg ) (void)(0) |
13840 | |
13841 | #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) |
13842 | #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) |
13843 | #define CATCH_METHOD_AS_TEST_CASE( method, ... ) |
13844 | #define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0) |
13845 | #define CATCH_SECTION( ... ) |
13846 | #define CATCH_DYNAMIC_SECTION( ... ) |
13847 | #define CATCH_FAIL( ... ) (void)(0) |
13848 | #define CATCH_FAIL_CHECK( ... ) (void)(0) |
13849 | #define CATCH_SUCCEED( ... ) (void)(0) |
13850 | |
13851 | #define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) |
13852 | |
13853 | // "BDD-style" convenience wrappers |
13854 | #define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) |
13855 | #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 ) |
13856 | #define CATCH_GIVEN( desc ) |
13857 | #define CATCH_AND_GIVEN( desc ) |
13858 | #define CATCH_WHEN( desc ) |
13859 | #define CATCH_AND_WHEN( desc ) |
13860 | #define CATCH_THEN( desc ) |
13861 | #define CATCH_AND_THEN( desc ) |
13862 | |
13863 | // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required |
13864 | #else |
13865 | |
13866 | #define REQUIRE( ... ) (void)(0) |
13867 | #define REQUIRE_FALSE( ... ) (void)(0) |
13868 | |
13869 | #define REQUIRE_THROWS( ... ) (void)(0) |
13870 | #define REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0) |
13871 | #define REQUIRE_THROWS_WITH( expr, matcher ) (void)(0) |
13872 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) |
13873 | #define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) |
13874 | #endif // CATCH_CONFIG_DISABLE_MATCHERS |
13875 | #define REQUIRE_NOTHROW( ... ) (void)(0) |
13876 | |
13877 | #define CHECK( ... ) (void)(0) |
13878 | #define CHECK_FALSE( ... ) (void)(0) |
13879 | #define CHECKED_IF( ... ) if (__VA_ARGS__) |
13880 | #define CHECKED_ELSE( ... ) if (!(__VA_ARGS__)) |
13881 | #define CHECK_NOFAIL( ... ) (void)(0) |
13882 | |
13883 | #define CHECK_THROWS( ... ) (void)(0) |
13884 | #define CHECK_THROWS_AS( expr, exceptionType ) (void)(0) |
13885 | #define CHECK_THROWS_WITH( expr, matcher ) (void)(0) |
13886 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) |
13887 | #define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) |
13888 | #endif // CATCH_CONFIG_DISABLE_MATCHERS |
13889 | #define CHECK_NOTHROW( ... ) (void)(0) |
13890 | |
13891 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) |
13892 | #define CHECK_THAT( arg, matcher ) (void)(0) |
13893 | |
13894 | #define REQUIRE_THAT( arg, matcher ) (void)(0) |
13895 | #endif // CATCH_CONFIG_DISABLE_MATCHERS |
13896 | |
13897 | #define INFO( msg ) (void)(0) |
13898 | #define WARN( msg ) (void)(0) |
13899 | #define CAPTURE( msg ) (void)(0) |
13900 | |
13901 | #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) |
13902 | #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) |
13903 | #define METHOD_AS_TEST_CASE( method, ... ) |
13904 | #define REGISTER_TEST_CASE( Function, ... ) (void)(0) |
13905 | #define SECTION( ... ) |
13906 | #define DYNAMIC_SECTION( ... ) |
13907 | #define FAIL( ... ) (void)(0) |
13908 | #define FAIL_CHECK( ... ) (void)(0) |
13909 | #define SUCCEED( ... ) (void)(0) |
13910 | #define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) |
13911 | |
13912 | #endif |
13913 | |
13914 | #define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) |
13915 | |
13916 | // "BDD-style" convenience wrappers |
13917 | #define SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) ) |
13918 | #define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className ) |
13919 | |
13920 | #define GIVEN( desc ) |
13921 | #define AND_GIVEN( desc ) |
13922 | #define WHEN( desc ) |
13923 | #define AND_WHEN( desc ) |
13924 | #define THEN( desc ) |
13925 | #define AND_THEN( desc ) |
13926 | |
13927 | using Catch::Detail::Approx; |
13928 | |
13929 | #endif |
13930 | |
13931 | #endif // ! CATCH_CONFIG_IMPL_ONLY |
13932 | |
13933 | // start catch_reenable_warnings.h |
13934 | |
13935 | |
13936 | #ifdef __clang__ |
13937 | # ifdef __ICC // icpc defines the __clang__ macro |
13938 | # pragma warning(pop) |
13939 | # else |
13940 | # pragma clang diagnostic pop |
13941 | # endif |
13942 | #elif defined __GNUC__ |
13943 | # pragma GCC diagnostic pop |
13944 | #endif |
13945 | |
13946 | // end catch_reenable_warnings.h |
13947 | // end catch.hpp |
13948 | #endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED |
13949 | |
13950 | |