1 | /* |
2 | * Catch v2.13.7 |
3 | * Generated: 2021-07-28 20:29:27.753164 |
4 | * ---------------------------------------------------------- |
5 | * This file has been merged from multiple headers. Please don't edit it directly |
6 | * Copyright (c) 2021 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 13 |
18 | #define CATCH_VERSION_PATCH 7 |
19 | |
20 | #ifdef __clang__ |
21 | # pragma clang system_header |
22 | #elif defined __GNUC__ |
23 | # pragma GCC system_header |
24 | #endif |
25 | |
26 | // start catch_suppress_warnings.h |
27 | |
28 | #ifdef __clang__ |
29 | # ifdef __ICC // icpc defines the __clang__ macro |
30 | # pragma warning(push) |
31 | # pragma warning(disable: 161 1682) |
32 | # else // __ICC |
33 | # pragma clang diagnostic push |
34 | # pragma clang diagnostic ignored "-Wpadded" |
35 | # pragma clang diagnostic ignored "-Wswitch-enum" |
36 | # pragma clang diagnostic ignored "-Wcovered-switch-default" |
37 | # endif |
38 | #elif defined __GNUC__ |
39 | // Because REQUIREs trigger GCC's -Wparentheses, and because still |
40 | // supported version of g++ have only buggy support for _Pragmas, |
41 | // Wparentheses have to be suppressed globally. |
42 | # pragma GCC diagnostic ignored "-Wparentheses" // See #674 for details |
43 | |
44 | # pragma GCC diagnostic push |
45 | # pragma GCC diagnostic ignored "-Wunused-variable" |
46 | # pragma GCC diagnostic ignored "-Wpadded" |
47 | #endif |
48 | // end catch_suppress_warnings.h |
49 | #if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) |
50 | # define CATCH_IMPL |
51 | # define CATCH_CONFIG_ALL_PARTS |
52 | #endif |
53 | |
54 | // In the impl file, we want to have access to all parts of the headers |
55 | // Can also be used to sanely support PCHs |
56 | #if defined(CATCH_CONFIG_ALL_PARTS) |
57 | # define CATCH_CONFIG_EXTERNAL_INTERFACES |
58 | # if defined(CATCH_CONFIG_DISABLE_MATCHERS) |
59 | # undef CATCH_CONFIG_DISABLE_MATCHERS |
60 | # endif |
61 | # if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) |
62 | # define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER |
63 | # endif |
64 | #endif |
65 | |
66 | #if !defined(CATCH_CONFIG_IMPL_ONLY) |
67 | // start catch_platform.h |
68 | |
69 | // See e.g.: |
70 | // https://opensource.apple.com/source/CarbonHeaders/CarbonHeaders-18.1/TargetConditionals.h.auto.html |
71 | #ifdef __APPLE__ |
72 | # include <TargetConditionals.h> |
73 | # if (defined(TARGET_OS_OSX) && TARGET_OS_OSX == 1) || \ |
74 | (defined(TARGET_OS_MAC) && TARGET_OS_MAC == 1) |
75 | # define CATCH_PLATFORM_MAC |
76 | # elif (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE == 1) |
77 | # define CATCH_PLATFORM_IPHONE |
78 | # endif |
79 | |
80 | #elif defined(linux) || defined(__linux) || defined(__linux__) |
81 | # define CATCH_PLATFORM_LINUX |
82 | |
83 | #elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__) |
84 | # define CATCH_PLATFORM_WINDOWS |
85 | #endif |
86 | |
87 | // end catch_platform.h |
88 | |
89 | #ifdef CATCH_IMPL |
90 | # ifndef CLARA_CONFIG_MAIN |
91 | # define CLARA_CONFIG_MAIN_NOT_DEFINED |
92 | # define CLARA_CONFIG_MAIN |
93 | # endif |
94 | #endif |
95 | |
96 | // start catch_user_interfaces.h |
97 | |
98 | namespace Catch { |
99 | unsigned int rngSeed(); |
100 | } |
101 | |
102 | // end catch_user_interfaces.h |
103 | // start catch_tag_alias_autoregistrar.h |
104 | |
105 | // start catch_common.h |
106 | |
107 | // start catch_compiler_capabilities.h |
108 | |
109 | // Detect a number of compiler features - by compiler |
110 | // The following features are defined: |
111 | // |
112 | // CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported? |
113 | // CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? |
114 | // CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? |
115 | // CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled? |
116 | // **************** |
117 | // Note to maintainers: if new toggles are added please document them |
118 | // in configuration.md, too |
119 | // **************** |
120 | |
121 | // In general each macro has a _NO_<feature name> form |
122 | // (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature. |
123 | // Many features, at point of detection, define an _INTERNAL_ macro, so they |
124 | // can be combined, en-mass, with the _NO_ forms later. |
125 | |
126 | #ifdef __cplusplus |
127 | |
128 | # if (__cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L) |
129 | # define CATCH_CPP14_OR_GREATER |
130 | # endif |
131 | |
132 | # if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) |
133 | # define CATCH_CPP17_OR_GREATER |
134 | # endif |
135 | |
136 | #endif |
137 | |
138 | // Only GCC compiler should be used in this block, so other compilers trying to |
139 | // mask themselves as GCC should be ignored. |
140 | #if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__) |
141 | # define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" ) |
142 | # define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" ) |
143 | |
144 | # define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) |
145 | |
146 | #endif |
147 | |
148 | #if defined(__clang__) |
149 | |
150 | # define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" ) |
151 | # define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" ) |
152 | |
153 | // As of this writing, IBM XL's implementation of __builtin_constant_p has a bug |
154 | // which results in calls to destructors being emitted for each temporary, |
155 | // without a matching initialization. In practice, this can result in something |
156 | // like `std::string::~string` being called on an uninitialized value. |
157 | // |
158 | // For example, this code will likely segfault under IBM XL: |
159 | // ``` |
160 | // REQUIRE(std::string("12") + "34" == "1234") |
161 | // ``` |
162 | // |
163 | // Therefore, `CATCH_INTERNAL_IGNORE_BUT_WARN` is not implemented. |
164 | # if !defined(__ibmxl__) && !defined(__CUDACC__) |
165 | # define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg) */ |
166 | # endif |
167 | |
168 | # define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ |
169 | _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ |
170 | _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") |
171 | |
172 | # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ |
173 | _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) |
174 | |
175 | # define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ |
176 | _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" ) |
177 | |
178 | # define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ |
179 | _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" ) |
180 | |
181 | # define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ |
182 | _Pragma( "clang diagnostic ignored \"-Wunused-template\"" ) |
183 | |
184 | #endif // __clang__ |
185 | |
186 | //////////////////////////////////////////////////////////////////////////////// |
187 | // Assume that non-Windows platforms support posix signals by default |
188 | #if !defined(CATCH_PLATFORM_WINDOWS) |
189 | #define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS |
190 | #endif |
191 | |
192 | //////////////////////////////////////////////////////////////////////////////// |
193 | // We know some environments not to support full POSIX signals |
194 | #if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__) |
195 | #define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS |
196 | #endif |
197 | |
198 | #ifdef __OS400__ |
199 | # define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS |
200 | # define CATCH_CONFIG_COLOUR_NONE |
201 | #endif |
202 | |
203 | //////////////////////////////////////////////////////////////////////////////// |
204 | // Android somehow still does not support std::to_string |
205 | #if defined(__ANDROID__) |
206 | # define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING |
207 | # define CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE |
208 | #endif |
209 | |
210 | //////////////////////////////////////////////////////////////////////////////// |
211 | // Not all Windows environments support SEH properly |
212 | #if defined(__MINGW32__) |
213 | # define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH |
214 | #endif |
215 | |
216 | //////////////////////////////////////////////////////////////////////////////// |
217 | // PS4 |
218 | #if defined(__ORBIS__) |
219 | # define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE |
220 | #endif |
221 | |
222 | //////////////////////////////////////////////////////////////////////////////// |
223 | // Cygwin |
224 | #ifdef __CYGWIN__ |
225 | |
226 | // Required for some versions of Cygwin to declare gettimeofday |
227 | // see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin |
228 | # define _BSD_SOURCE |
229 | // some versions of cygwin (most) do not support std::to_string. Use the libstd check. |
230 | // https://gcc.gnu.org/onlinedocs/gcc-4.8.2/libstdc++/api/a01053_source.html line 2812-2813 |
231 | # if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \ |
232 | && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF)) |
233 | |
234 | # define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING |
235 | |
236 | # endif |
237 | #endif // __CYGWIN__ |
238 | |
239 | //////////////////////////////////////////////////////////////////////////////// |
240 | // Visual C++ |
241 | #if defined(_MSC_VER) |
242 | |
243 | # define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) ) |
244 | # define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) ) |
245 | |
246 | // Universal Windows platform does not support SEH |
247 | // Or console colours (or console at all...) |
248 | # if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) |
249 | # define CATCH_CONFIG_COLOUR_NONE |
250 | # else |
251 | # define CATCH_INTERNAL_CONFIG_WINDOWS_SEH |
252 | # endif |
253 | |
254 | // MSVC traditional preprocessor needs some workaround for __VA_ARGS__ |
255 | // _MSVC_TRADITIONAL == 0 means new conformant preprocessor |
256 | // _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor |
257 | # if !defined(__clang__) // Handle Clang masquerading for msvc |
258 | # if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL) |
259 | # define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
260 | # endif // MSVC_TRADITIONAL |
261 | # endif // __clang__ |
262 | |
263 | #endif // _MSC_VER |
264 | |
265 | #if defined(_REENTRANT) || defined(_MSC_VER) |
266 | // Enable async processing, as -pthread is specified or no additional linking is required |
267 | # define CATCH_INTERNAL_CONFIG_USE_ASYNC |
268 | #endif // _MSC_VER |
269 | |
270 | //////////////////////////////////////////////////////////////////////////////// |
271 | // Check if we are compiled with -fno-exceptions or equivalent |
272 | #if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND) |
273 | # define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED |
274 | #endif |
275 | |
276 | //////////////////////////////////////////////////////////////////////////////// |
277 | // DJGPP |
278 | #ifdef __DJGPP__ |
279 | # define CATCH_INTERNAL_CONFIG_NO_WCHAR |
280 | #endif // __DJGPP__ |
281 | |
282 | //////////////////////////////////////////////////////////////////////////////// |
283 | // Embarcadero C++Build |
284 | #if defined(__BORLANDC__) |
285 | #define CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN |
286 | #endif |
287 | |
288 | //////////////////////////////////////////////////////////////////////////////// |
289 | |
290 | // Use of __COUNTER__ is suppressed during code analysis in |
291 | // CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly |
292 | // handled by it. |
293 | // Otherwise all supported compilers support COUNTER macro, |
294 | // but user still might want to turn it off |
295 | #if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) |
296 | #define CATCH_INTERNAL_CONFIG_COUNTER |
297 | #endif |
298 | |
299 | //////////////////////////////////////////////////////////////////////////////// |
300 | |
301 | // RTX is a special version of Windows that is real time. |
302 | // This means that it is detected as Windows, but does not provide |
303 | // the same set of capabilities as real Windows does. |
304 | #if defined(UNDER_RTSS) || defined(RTX64_BUILD) |
305 | #define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH |
306 | #define CATCH_INTERNAL_CONFIG_NO_ASYNC |
307 | #define CATCH_CONFIG_COLOUR_NONE |
308 | #endif |
309 | |
310 | #if !defined(_GLIBCXX_USE_C99_MATH_TR1) |
311 | #define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER |
312 | #endif |
313 | |
314 | // Various stdlib support checks that require __has_include |
315 | #if defined(__has_include) |
316 | // Check if string_view is available and usable |
317 | #if __has_include(<string_view>) && defined(CATCH_CPP17_OR_GREATER) |
318 | # define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW |
319 | #endif |
320 | |
321 | // Check if optional is available and usable |
322 | # if __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER) |
323 | # define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL |
324 | # endif // __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER) |
325 | |
326 | // Check if byte is available and usable |
327 | # if __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER) |
328 | # include <cstddef> |
329 | # if defined(__cpp_lib_byte) && (__cpp_lib_byte > 0) |
330 | # define CATCH_INTERNAL_CONFIG_CPP17_BYTE |
331 | # endif |
332 | # endif // __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER) |
333 | |
334 | // Check if variant is available and usable |
335 | # if __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER) |
336 | # if defined(__clang__) && (__clang_major__ < 8) |
337 | // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852 |
338 | // fix should be in clang 8, workaround in libstdc++ 8.2 |
339 | # include <ciso646> |
340 | # if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) |
341 | # define CATCH_CONFIG_NO_CPP17_VARIANT |
342 | # else |
343 | # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT |
344 | # endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) |
345 | # else |
346 | # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT |
347 | # endif // defined(__clang__) && (__clang_major__ < 8) |
348 | # endif // __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER) |
349 | #endif // defined(__has_include) |
350 | |
351 | #if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) |
352 | # define CATCH_CONFIG_COUNTER |
353 | #endif |
354 | #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) |
355 | # define CATCH_CONFIG_WINDOWS_SEH |
356 | #endif |
357 | // This is set by default, because we assume that unix compilers are posix-signal-compatible by default. |
358 | #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) |
359 | # define CATCH_CONFIG_POSIX_SIGNALS |
360 | #endif |
361 | // This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions. |
362 | #if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR) |
363 | # define CATCH_CONFIG_WCHAR |
364 | #endif |
365 | |
366 | #if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING) |
367 | # define CATCH_CONFIG_CPP11_TO_STRING |
368 | #endif |
369 | |
370 | #if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL) |
371 | # define CATCH_CONFIG_CPP17_OPTIONAL |
372 | #endif |
373 | |
374 | #if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW) |
375 | # define CATCH_CONFIG_CPP17_STRING_VIEW |
376 | #endif |
377 | |
378 | #if defined(CATCH_INTERNAL_CONFIG_CPP17_VARIANT) && !defined(CATCH_CONFIG_NO_CPP17_VARIANT) && !defined(CATCH_CONFIG_CPP17_VARIANT) |
379 | # define CATCH_CONFIG_CPP17_VARIANT |
380 | #endif |
381 | |
382 | #if defined(CATCH_INTERNAL_CONFIG_CPP17_BYTE) && !defined(CATCH_CONFIG_NO_CPP17_BYTE) && !defined(CATCH_CONFIG_CPP17_BYTE) |
383 | # define CATCH_CONFIG_CPP17_BYTE |
384 | #endif |
385 | |
386 | #if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) |
387 | # define CATCH_INTERNAL_CONFIG_NEW_CAPTURE |
388 | #endif |
389 | |
390 | #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) |
391 | # define CATCH_CONFIG_NEW_CAPTURE |
392 | #endif |
393 | |
394 | #if !defined(CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) |
395 | # define CATCH_CONFIG_DISABLE_EXCEPTIONS |
396 | #endif |
397 | |
398 | #if defined(CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_NO_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_POLYFILL_ISNAN) |
399 | # define CATCH_CONFIG_POLYFILL_ISNAN |
400 | #endif |
401 | |
402 | #if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC) && !defined(CATCH_INTERNAL_CONFIG_NO_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC) |
403 | # define CATCH_CONFIG_USE_ASYNC |
404 | #endif |
405 | |
406 | #if defined(CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_NO_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_ANDROID_LOGWRITE) |
407 | # define CATCH_CONFIG_ANDROID_LOGWRITE |
408 | #endif |
409 | |
410 | #if defined(CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_NO_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) |
411 | # define CATCH_CONFIG_GLOBAL_NEXTAFTER |
412 | #endif |
413 | |
414 | // Even if we do not think the compiler has that warning, we still have |
415 | // to provide a macro that can be used by the code. |
416 | #if !defined(CATCH_INTERNAL_START_WARNINGS_SUPPRESSION) |
417 | # define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION |
418 | #endif |
419 | #if !defined(CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION) |
420 | # define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION |
421 | #endif |
422 | #if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) |
423 | # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS |
424 | #endif |
425 | #if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) |
426 | # define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS |
427 | #endif |
428 | #if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS) |
429 | # define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS |
430 | #endif |
431 | #if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS) |
432 | # define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS |
433 | #endif |
434 | |
435 | // The goal of this macro is to avoid evaluation of the arguments, but |
436 | // still have the compiler warn on problems inside... |
437 | #if !defined(CATCH_INTERNAL_IGNORE_BUT_WARN) |
438 | # define CATCH_INTERNAL_IGNORE_BUT_WARN(...) |
439 | #endif |
440 | |
441 | #if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10) |
442 | # undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS |
443 | #elif defined(__clang__) && (__clang_major__ < 5) |
444 | # undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS |
445 | #endif |
446 | |
447 | #if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS) |
448 | # define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS |
449 | #endif |
450 | |
451 | #if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) |
452 | #define CATCH_TRY if ((true)) |
453 | #define CATCH_CATCH_ALL if ((false)) |
454 | #define CATCH_CATCH_ANON(type) if ((false)) |
455 | #else |
456 | #define CATCH_TRY try |
457 | #define CATCH_CATCH_ALL catch (...) |
458 | #define CATCH_CATCH_ANON(type) catch (type) |
459 | #endif |
460 | |
461 | #if defined(CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_NO_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) |
462 | #define CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
463 | #endif |
464 | |
465 | // end catch_compiler_capabilities.h |
466 | #define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line |
467 | #define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) |
468 | #ifdef CATCH_CONFIG_COUNTER |
469 | # define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) |
470 | #else |
471 | # define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) |
472 | #endif |
473 | |
474 | #include <iosfwd> |
475 | #include <string> |
476 | #include <cstdint> |
477 | |
478 | // We need a dummy global operator<< so we can bring it into Catch namespace later |
479 | struct Catch_global_namespace_dummy {}; |
480 | std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy); |
481 | |
482 | namespace Catch { |
483 | |
484 | struct CaseSensitive { enum Choice { |
485 | Yes, |
486 | No |
487 | }; }; |
488 | |
489 | class NonCopyable { |
490 | NonCopyable( NonCopyable const& ) = delete; |
491 | NonCopyable( NonCopyable && ) = delete; |
492 | NonCopyable& operator = ( NonCopyable const& ) = delete; |
493 | NonCopyable& operator = ( NonCopyable && ) = delete; |
494 | |
495 | protected: |
496 | NonCopyable(); |
497 | virtual ~NonCopyable(); |
498 | }; |
499 | |
500 | struct SourceLineInfo { |
501 | |
502 | SourceLineInfo() = delete; |
503 | SourceLineInfo( char const* _file, std::size_t _line ) noexcept |
504 | : file( _file ), |
505 | line( _line ) |
506 | {} |
507 | |
508 | SourceLineInfo( SourceLineInfo const& other ) = default; |
509 | SourceLineInfo& operator = ( SourceLineInfo const& ) = default; |
510 | SourceLineInfo( SourceLineInfo&& ) noexcept = default; |
511 | SourceLineInfo& operator = ( SourceLineInfo&& ) noexcept = default; |
512 | |
513 | bool empty() const noexcept { return file[0] == '\0'; } |
514 | bool operator == ( SourceLineInfo const& other ) const noexcept; |
515 | bool operator < ( SourceLineInfo const& other ) const noexcept; |
516 | |
517 | char const* file; |
518 | std::size_t line; |
519 | }; |
520 | |
521 | std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); |
522 | |
523 | // Bring in operator<< from global namespace into Catch namespace |
524 | // This is necessary because the overload of operator<< above makes |
525 | // lookup stop at namespace Catch |
526 | using ::operator<<; |
527 | |
528 | // Use this in variadic streaming macros to allow |
529 | // >> +StreamEndStop |
530 | // as well as |
531 | // >> stuff +StreamEndStop |
532 | struct StreamEndStop { |
533 | std::string operator+() const; |
534 | }; |
535 | template<typename T> |
536 | T const& operator + ( T const& value, StreamEndStop ) { |
537 | return value; |
538 | } |
539 | } |
540 | |
541 | #define CATCH_INTERNAL_LINEINFO \ |
542 | ::Catch::SourceLineInfo( __FILE__, static_cast<std::size_t>( __LINE__ ) ) |
543 | |
544 | // end catch_common.h |
545 | namespace Catch { |
546 | |
547 | struct RegistrarForTagAliases { |
548 | RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); |
549 | }; |
550 | |
551 | } // end namespace Catch |
552 | |
553 | #define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \ |
554 | CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ |
555 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ |
556 | namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \ |
557 | CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION |
558 | |
559 | // end catch_tag_alias_autoregistrar.h |
560 | // start catch_test_registry.h |
561 | |
562 | // start catch_interfaces_testcase.h |
563 | |
564 | #include <vector> |
565 | |
566 | namespace Catch { |
567 | |
568 | class TestSpec; |
569 | |
570 | struct ITestInvoker { |
571 | virtual void invoke () const = 0; |
572 | virtual ~ITestInvoker(); |
573 | }; |
574 | |
575 | class TestCase; |
576 | struct IConfig; |
577 | |
578 | struct ITestCaseRegistry { |
579 | virtual ~ITestCaseRegistry(); |
580 | virtual std::vector<TestCase> const& getAllTests() const = 0; |
581 | virtual std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const = 0; |
582 | }; |
583 | |
584 | bool isThrowSafe( TestCase const& testCase, IConfig const& config ); |
585 | bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); |
586 | std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ); |
587 | std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ); |
588 | |
589 | } |
590 | |
591 | // end catch_interfaces_testcase.h |
592 | // start catch_stringref.h |
593 | |
594 | #include <cstddef> |
595 | #include <string> |
596 | #include <iosfwd> |
597 | #include <cassert> |
598 | |
599 | namespace Catch { |
600 | |
601 | /// A non-owning string class (similar to the forthcoming std::string_view) |
602 | /// Note that, because a StringRef may be a substring of another string, |
603 | /// it may not be null terminated. |
604 | class StringRef { |
605 | public: |
606 | using size_type = std::size_t; |
607 | using const_iterator = const char*; |
608 | |
609 | private: |
610 | static constexpr char const* const s_empty = "" ; |
611 | |
612 | char const* m_start = s_empty; |
613 | size_type m_size = 0; |
614 | |
615 | public: // construction |
616 | constexpr StringRef() noexcept = default; |
617 | |
618 | StringRef( char const* rawChars ) noexcept; |
619 | |
620 | constexpr StringRef( char const* rawChars, size_type size ) noexcept |
621 | : m_start( rawChars ), |
622 | m_size( size ) |
623 | {} |
624 | |
625 | StringRef( std::string const& stdString ) noexcept |
626 | : m_start( stdString.c_str() ), |
627 | m_size( stdString.size() ) |
628 | {} |
629 | |
630 | explicit operator std::string() const { |
631 | return std::string(m_start, m_size); |
632 | } |
633 | |
634 | public: // operators |
635 | auto operator == ( StringRef const& other ) const noexcept -> bool; |
636 | auto operator != (StringRef const& other) const noexcept -> bool { |
637 | return !(*this == other); |
638 | } |
639 | |
640 | auto operator[] ( size_type index ) const noexcept -> char { |
641 | assert(index < m_size); |
642 | return m_start[index]; |
643 | } |
644 | |
645 | public: // named queries |
646 | constexpr auto empty() const noexcept -> bool { |
647 | return m_size == 0; |
648 | } |
649 | constexpr auto size() const noexcept -> size_type { |
650 | return m_size; |
651 | } |
652 | |
653 | // Returns the current start pointer. If the StringRef is not |
654 | // null-terminated, throws std::domain_exception |
655 | auto c_str() const -> char const*; |
656 | |
657 | public: // substrings and searches |
658 | // Returns a substring of [start, start + length). |
659 | // If start + length > size(), then the substring is [start, size()). |
660 | // If start > size(), then the substring is empty. |
661 | auto substr( size_type start, size_type length ) const noexcept -> StringRef; |
662 | |
663 | // Returns the current start pointer. May not be null-terminated. |
664 | auto data() const noexcept -> char const*; |
665 | |
666 | constexpr auto isNullTerminated() const noexcept -> bool { |
667 | return m_start[m_size] == '\0'; |
668 | } |
669 | |
670 | public: // iterators |
671 | constexpr const_iterator begin() const { return m_start; } |
672 | constexpr const_iterator end() const { return m_start + m_size; } |
673 | }; |
674 | |
675 | auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&; |
676 | auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; |
677 | |
678 | constexpr auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { |
679 | return StringRef( rawChars, size ); |
680 | } |
681 | } // namespace Catch |
682 | |
683 | constexpr auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { |
684 | return Catch::StringRef( rawChars, size ); |
685 | } |
686 | |
687 | // end catch_stringref.h |
688 | // start catch_preprocessor.hpp |
689 | |
690 | |
691 | #define CATCH_RECURSION_LEVEL0(...) __VA_ARGS__ |
692 | #define CATCH_RECURSION_LEVEL1(...) CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(__VA_ARGS__))) |
693 | #define CATCH_RECURSION_LEVEL2(...) CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(__VA_ARGS__))) |
694 | #define CATCH_RECURSION_LEVEL3(...) CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(__VA_ARGS__))) |
695 | #define CATCH_RECURSION_LEVEL4(...) CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(__VA_ARGS__))) |
696 | #define CATCH_RECURSION_LEVEL5(...) CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(__VA_ARGS__))) |
697 | |
698 | #ifdef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
699 | #define INTERNAL_CATCH_EXPAND_VARGS(...) __VA_ARGS__ |
700 | // MSVC needs more evaluations |
701 | #define CATCH_RECURSION_LEVEL6(...) CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(__VA_ARGS__))) |
702 | #define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL6(CATCH_RECURSION_LEVEL6(__VA_ARGS__)) |
703 | #else |
704 | #define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL5(__VA_ARGS__) |
705 | #endif |
706 | |
707 | #define CATCH_REC_END(...) |
708 | #define CATCH_REC_OUT |
709 | |
710 | #define CATCH_EMPTY() |
711 | #define CATCH_DEFER(id) id CATCH_EMPTY() |
712 | |
713 | #define CATCH_REC_GET_END2() 0, CATCH_REC_END |
714 | #define CATCH_REC_GET_END1(...) CATCH_REC_GET_END2 |
715 | #define CATCH_REC_GET_END(...) CATCH_REC_GET_END1 |
716 | #define CATCH_REC_NEXT0(test, next, ...) next CATCH_REC_OUT |
717 | #define CATCH_REC_NEXT1(test, next) CATCH_DEFER ( CATCH_REC_NEXT0 ) ( test, next, 0) |
718 | #define CATCH_REC_NEXT(test, next) CATCH_REC_NEXT1(CATCH_REC_GET_END test, next) |
719 | |
720 | #define CATCH_REC_LIST0(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) |
721 | #define CATCH_REC_LIST1(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0) ) ( f, peek, __VA_ARGS__ ) |
722 | #define CATCH_REC_LIST2(f, x, peek, ...) f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) |
723 | |
724 | #define CATCH_REC_LIST0_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) |
725 | #define CATCH_REC_LIST1_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0_UD) ) ( f, userdata, peek, __VA_ARGS__ ) |
726 | #define CATCH_REC_LIST2_UD(f, userdata, x, peek, ...) f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) |
727 | |
728 | // Applies the function macro `f` to each of the remaining parameters, inserts commas between the results, |
729 | // and passes userdata as the first parameter to each invocation, |
730 | // e.g. CATCH_REC_LIST_UD(f, x, a, b, c) evaluates to f(x, a), f(x, b), f(x, c) |
731 | #define CATCH_REC_LIST_UD(f, userdata, ...) CATCH_RECURSE(CATCH_REC_LIST2_UD(f, userdata, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) |
732 | |
733 | #define CATCH_REC_LIST(f, ...) CATCH_RECURSE(CATCH_REC_LIST2(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) |
734 | |
735 | #define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param) |
736 | #define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__ |
737 | #define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__ |
738 | #define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF |
739 | #define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__) |
740 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
741 | #define INTERNAL_CATCH_STRINGIZE2(...) #__VA_ARGS__ |
742 | #define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) |
743 | #else |
744 | // MSVC is adding extra space and needs another indirection to expand INTERNAL_CATCH_NOINTERNAL_CATCH_DEF |
745 | #define INTERNAL_CATCH_STRINGIZE2(...) INTERNAL_CATCH_STRINGIZE3(__VA_ARGS__) |
746 | #define INTERNAL_CATCH_STRINGIZE3(...) #__VA_ARGS__ |
747 | #define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1) |
748 | #endif |
749 | |
750 | #define INTERNAL_CATCH_MAKE_NAMESPACE2(...) ns_##__VA_ARGS__ |
751 | #define INTERNAL_CATCH_MAKE_NAMESPACE(name) INTERNAL_CATCH_MAKE_NAMESPACE2(name) |
752 | |
753 | #define INTERNAL_CATCH_REMOVE_PARENS(...) INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF __VA_ARGS__) |
754 | |
755 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
756 | #define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS_GEN(__VA_ARGS__)>()) |
757 | #define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)) |
758 | #else |
759 | #define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) INTERNAL_CATCH_EXPAND_VARGS(decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS_GEN(__VA_ARGS__)>())) |
760 | #define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))) |
761 | #endif |
762 | |
763 | #define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(...)\ |
764 | CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,__VA_ARGS__) |
765 | |
766 | #define INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_0) INTERNAL_CATCH_REMOVE_PARENS(_0) |
767 | #define INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_0, _1) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_1) |
768 | #define INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_0, _1, _2) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_1, _2) |
769 | #define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3) |
770 | #define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4) |
771 | #define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5) |
772 | #define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _3, _4, _5, _6) |
773 | #define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7) |
774 | #define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8) |
775 | #define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9) |
776 | #define INTERNAL_CATCH_REMOVE_PARENS_11_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10) |
777 | |
778 | #define INTERNAL_CATCH_VA_NARGS_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N |
779 | |
780 | #define INTERNAL_CATCH_TYPE_GEN\ |
781 | template<typename...> struct TypeList {};\ |
782 | template<typename...Ts>\ |
783 | constexpr auto get_wrapper() noexcept -> TypeList<Ts...> { return {}; }\ |
784 | template<template<typename...> class...> struct TemplateTypeList{};\ |
785 | template<template<typename...> class...Cs>\ |
786 | constexpr auto get_wrapper() noexcept -> TemplateTypeList<Cs...> { return {}; }\ |
787 | template<typename...>\ |
788 | struct append;\ |
789 | template<typename...>\ |
790 | struct rewrap;\ |
791 | template<template<typename...> class, typename...>\ |
792 | struct create;\ |
793 | template<template<typename...> class, typename>\ |
794 | struct convert;\ |
795 | \ |
796 | template<typename T> \ |
797 | struct append<T> { using type = T; };\ |
798 | template< template<typename...> class L1, typename...E1, template<typename...> class L2, typename...E2, typename...Rest>\ |
799 | struct append<L1<E1...>, L2<E2...>, Rest...> { using type = typename append<L1<E1...,E2...>, Rest...>::type; };\ |
800 | template< template<typename...> class L1, typename...E1, typename...Rest>\ |
801 | struct append<L1<E1...>, TypeList<mpl_::na>, Rest...> { using type = L1<E1...>; };\ |
802 | \ |
803 | template< template<typename...> class Container, template<typename...> class List, typename...elems>\ |
804 | struct rewrap<TemplateTypeList<Container>, List<elems...>> { using type = TypeList<Container<elems...>>; };\ |
805 | template< template<typename...> class Container, template<typename...> class List, class...Elems, typename...Elements>\ |
806 | struct rewrap<TemplateTypeList<Container>, List<Elems...>, Elements...> { using type = typename append<TypeList<Container<Elems...>>, typename rewrap<TemplateTypeList<Container>, Elements...>::type>::type; };\ |
807 | \ |
808 | template<template <typename...> class Final, template< typename...> class...Containers, typename...Types>\ |
809 | struct create<Final, TemplateTypeList<Containers...>, TypeList<Types...>> { using type = typename append<Final<>, typename rewrap<TemplateTypeList<Containers>, Types...>::type...>::type; };\ |
810 | template<template <typename...> class Final, template <typename...> class List, typename...Ts>\ |
811 | struct convert<Final, List<Ts...>> { using type = typename append<Final<>,TypeList<Ts>...>::type; }; |
812 | |
813 | #define INTERNAL_CATCH_NTTP_1(signature, ...)\ |
814 | template<INTERNAL_CATCH_REMOVE_PARENS(signature)> struct Nttp{};\ |
815 | template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\ |
816 | constexpr auto get_wrapper() noexcept -> Nttp<__VA_ARGS__> { return {}; } \ |
817 | template<template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...> struct NttpTemplateTypeList{};\ |
818 | template<template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...Cs>\ |
819 | constexpr auto get_wrapper() noexcept -> NttpTemplateTypeList<Cs...> { return {}; } \ |
820 | \ |
821 | template< template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class Container, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class List, INTERNAL_CATCH_REMOVE_PARENS(signature)>\ |
822 | struct rewrap<NttpTemplateTypeList<Container>, List<__VA_ARGS__>> { using type = TypeList<Container<__VA_ARGS__>>; };\ |
823 | template< template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class Container, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class List, INTERNAL_CATCH_REMOVE_PARENS(signature), typename...Elements>\ |
824 | struct rewrap<NttpTemplateTypeList<Container>, List<__VA_ARGS__>, Elements...> { using type = typename append<TypeList<Container<__VA_ARGS__>>, typename rewrap<NttpTemplateTypeList<Container>, Elements...>::type>::type; };\ |
825 | template<template <typename...> class Final, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...Containers, typename...Types>\ |
826 | struct create<Final, NttpTemplateTypeList<Containers...>, TypeList<Types...>> { using type = typename append<Final<>, typename rewrap<NttpTemplateTypeList<Containers>, Types...>::type...>::type; }; |
827 | |
828 | #define INTERNAL_CATCH_DECLARE_SIG_TEST0(TestName) |
829 | #define INTERNAL_CATCH_DECLARE_SIG_TEST1(TestName, signature)\ |
830 | template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\ |
831 | static void TestName() |
832 | #define INTERNAL_CATCH_DECLARE_SIG_TEST_X(TestName, signature, ...)\ |
833 | template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\ |
834 | static void TestName() |
835 | |
836 | #define INTERNAL_CATCH_DEFINE_SIG_TEST0(TestName) |
837 | #define INTERNAL_CATCH_DEFINE_SIG_TEST1(TestName, signature)\ |
838 | template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\ |
839 | static void TestName() |
840 | #define INTERNAL_CATCH_DEFINE_SIG_TEST_X(TestName, signature,...)\ |
841 | template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\ |
842 | static void TestName() |
843 | |
844 | #define INTERNAL_CATCH_NTTP_REGISTER0(TestFunc, signature)\ |
845 | template<typename Type>\ |
846 | void reg_test(TypeList<Type>, Catch::NameAndTags nameAndTags)\ |
847 | {\ |
848 | Catch::AutoReg( Catch::makeTestInvoker(&TestFunc<Type>), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), nameAndTags);\ |
849 | } |
850 | |
851 | #define INTERNAL_CATCH_NTTP_REGISTER(TestFunc, signature, ...)\ |
852 | template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\ |
853 | void reg_test(Nttp<__VA_ARGS__>, Catch::NameAndTags nameAndTags)\ |
854 | {\ |
855 | Catch::AutoReg( Catch::makeTestInvoker(&TestFunc<__VA_ARGS__>), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), nameAndTags);\ |
856 | } |
857 | |
858 | #define INTERNAL_CATCH_NTTP_REGISTER_METHOD0(TestName, signature, ...)\ |
859 | template<typename Type>\ |
860 | void reg_test(TypeList<Type>, Catch::StringRef className, Catch::NameAndTags nameAndTags)\ |
861 | {\ |
862 | Catch::AutoReg( Catch::makeTestInvoker(&TestName<Type>::test), CATCH_INTERNAL_LINEINFO, className, nameAndTags);\ |
863 | } |
864 | |
865 | #define INTERNAL_CATCH_NTTP_REGISTER_METHOD(TestName, signature, ...)\ |
866 | template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\ |
867 | void reg_test(Nttp<__VA_ARGS__>, Catch::StringRef className, Catch::NameAndTags nameAndTags)\ |
868 | {\ |
869 | Catch::AutoReg( Catch::makeTestInvoker(&TestName<__VA_ARGS__>::test), CATCH_INTERNAL_LINEINFO, className, nameAndTags);\ |
870 | } |
871 | |
872 | #define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD0(TestName, ClassName) |
873 | #define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD1(TestName, ClassName, signature)\ |
874 | template<typename TestType> \ |
875 | struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName)<TestType> { \ |
876 | void test();\ |
877 | } |
878 | |
879 | #define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X(TestName, ClassName, signature, ...)\ |
880 | template<INTERNAL_CATCH_REMOVE_PARENS(signature)> \ |
881 | struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName)<__VA_ARGS__> { \ |
882 | void test();\ |
883 | } |
884 | |
885 | #define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD0(TestName) |
886 | #define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD1(TestName, signature)\ |
887 | template<typename TestType> \ |
888 | void INTERNAL_CATCH_MAKE_NAMESPACE(TestName)::TestName<TestType>::test() |
889 | #define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X(TestName, signature, ...)\ |
890 | template<INTERNAL_CATCH_REMOVE_PARENS(signature)> \ |
891 | void INTERNAL_CATCH_MAKE_NAMESPACE(TestName)::TestName<__VA_ARGS__>::test() |
892 | |
893 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
894 | #define INTERNAL_CATCH_NTTP_0 |
895 | #define INTERNAL_CATCH_NTTP_GEN(...) INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__),INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_0) |
896 | #define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD1, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD0)(TestName, __VA_ARGS__) |
897 | #define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD1, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD0)(TestName, ClassName, __VA_ARGS__) |
898 | #define INTERNAL_CATCH_NTTP_REG_METHOD_GEN(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD0, INTERNAL_CATCH_NTTP_REGISTER_METHOD0)(TestName, __VA_ARGS__) |
899 | #define INTERNAL_CATCH_NTTP_REG_GEN(TestFunc, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER0, INTERNAL_CATCH_NTTP_REGISTER0)(TestFunc, __VA_ARGS__) |
900 | #define INTERNAL_CATCH_DEFINE_SIG_TEST(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST1, INTERNAL_CATCH_DEFINE_SIG_TEST0)(TestName, __VA_ARGS__) |
901 | #define INTERNAL_CATCH_DECLARE_SIG_TEST(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST1, INTERNAL_CATCH_DECLARE_SIG_TEST0)(TestName, __VA_ARGS__) |
902 | #define INTERNAL_CATCH_REMOVE_PARENS_GEN(...) INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_REMOVE_PARENS_11_ARG,INTERNAL_CATCH_REMOVE_PARENS_10_ARG,INTERNAL_CATCH_REMOVE_PARENS_9_ARG,INTERNAL_CATCH_REMOVE_PARENS_8_ARG,INTERNAL_CATCH_REMOVE_PARENS_7_ARG,INTERNAL_CATCH_REMOVE_PARENS_6_ARG,INTERNAL_CATCH_REMOVE_PARENS_5_ARG,INTERNAL_CATCH_REMOVE_PARENS_4_ARG,INTERNAL_CATCH_REMOVE_PARENS_3_ARG,INTERNAL_CATCH_REMOVE_PARENS_2_ARG,INTERNAL_CATCH_REMOVE_PARENS_1_ARG)(__VA_ARGS__) |
903 | #else |
904 | #define INTERNAL_CATCH_NTTP_0(signature) |
905 | #define INTERNAL_CATCH_NTTP_GEN(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1,INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_0)( __VA_ARGS__)) |
906 | #define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD1, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD0)(TestName, __VA_ARGS__)) |
907 | #define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD1, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD0)(TestName, ClassName, __VA_ARGS__)) |
908 | #define INTERNAL_CATCH_NTTP_REG_METHOD_GEN(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD0, INTERNAL_CATCH_NTTP_REGISTER_METHOD0)(TestName, __VA_ARGS__)) |
909 | #define INTERNAL_CATCH_NTTP_REG_GEN(TestFunc, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER0, INTERNAL_CATCH_NTTP_REGISTER0)(TestFunc, __VA_ARGS__)) |
910 | #define INTERNAL_CATCH_DEFINE_SIG_TEST(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST1, INTERNAL_CATCH_DEFINE_SIG_TEST0)(TestName, __VA_ARGS__)) |
911 | #define INTERNAL_CATCH_DECLARE_SIG_TEST(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST1, INTERNAL_CATCH_DECLARE_SIG_TEST0)(TestName, __VA_ARGS__)) |
912 | #define INTERNAL_CATCH_REMOVE_PARENS_GEN(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_REMOVE_PARENS_11_ARG,INTERNAL_CATCH_REMOVE_PARENS_10_ARG,INTERNAL_CATCH_REMOVE_PARENS_9_ARG,INTERNAL_CATCH_REMOVE_PARENS_8_ARG,INTERNAL_CATCH_REMOVE_PARENS_7_ARG,INTERNAL_CATCH_REMOVE_PARENS_6_ARG,INTERNAL_CATCH_REMOVE_PARENS_5_ARG,INTERNAL_CATCH_REMOVE_PARENS_4_ARG,INTERNAL_CATCH_REMOVE_PARENS_3_ARG,INTERNAL_CATCH_REMOVE_PARENS_2_ARG,INTERNAL_CATCH_REMOVE_PARENS_1_ARG)(__VA_ARGS__)) |
913 | #endif |
914 | |
915 | // end catch_preprocessor.hpp |
916 | // start catch_meta.hpp |
917 | |
918 | |
919 | #include <type_traits> |
920 | |
921 | namespace Catch { |
922 | template<typename T> |
923 | struct always_false : std::false_type {}; |
924 | |
925 | template <typename> struct true_given : std::true_type {}; |
926 | struct is_callable_tester { |
927 | template <typename Fun, typename... Args> |
928 | true_given<decltype(std::declval<Fun>()(std::declval<Args>()...))> static test(int); |
929 | template <typename...> |
930 | std::false_type static test(...); |
931 | }; |
932 | |
933 | template <typename T> |
934 | struct is_callable; |
935 | |
936 | template <typename Fun, typename... Args> |
937 | struct is_callable<Fun(Args...)> : decltype(is_callable_tester::test<Fun, Args...>(0)) {}; |
938 | |
939 | #if defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703 |
940 | // std::result_of is deprecated in C++17 and removed in C++20. Hence, it is |
941 | // replaced with std::invoke_result here. |
942 | template <typename Func, typename... U> |
943 | using FunctionReturnType = std::remove_reference_t<std::remove_cv_t<std::invoke_result_t<Func, U...>>>; |
944 | #else |
945 | // Keep ::type here because we still support C++11 |
946 | template <typename Func, typename... U> |
947 | using FunctionReturnType = typename std::remove_reference<typename std::remove_cv<typename std::result_of<Func(U...)>::type>::type>::type; |
948 | #endif |
949 | |
950 | } // namespace Catch |
951 | |
952 | namespace mpl_{ |
953 | struct na; |
954 | } |
955 | |
956 | // end catch_meta.hpp |
957 | namespace Catch { |
958 | |
959 | template<typename C> |
960 | class TestInvokerAsMethod : public ITestInvoker { |
961 | void (C::*m_testAsMethod)(); |
962 | public: |
963 | TestInvokerAsMethod( void (C::*testAsMethod)() ) noexcept : m_testAsMethod( testAsMethod ) {} |
964 | |
965 | void invoke() const override { |
966 | C obj; |
967 | (obj.*m_testAsMethod)(); |
968 | } |
969 | }; |
970 | |
971 | auto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker*; |
972 | |
973 | template<typename C> |
974 | auto makeTestInvoker( void (C::*testAsMethod)() ) noexcept -> ITestInvoker* { |
975 | return new(std::nothrow) TestInvokerAsMethod<C>( testAsMethod ); |
976 | } |
977 | |
978 | struct NameAndTags { |
979 | NameAndTags( StringRef const& name_ = StringRef(), StringRef const& tags_ = StringRef() ) noexcept; |
980 | StringRef name; |
981 | StringRef tags; |
982 | }; |
983 | |
984 | struct AutoReg : NonCopyable { |
985 | AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept; |
986 | ~AutoReg(); |
987 | }; |
988 | |
989 | } // end namespace Catch |
990 | |
991 | #if defined(CATCH_CONFIG_DISABLE) |
992 | #define INTERNAL_CATCH_TESTCASE_NO_REGISTRATION( TestName, ... ) \ |
993 | static void TestName() |
994 | #define INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... ) \ |
995 | namespace{ \ |
996 | struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \ |
997 | void test(); \ |
998 | }; \ |
999 | } \ |
1000 | void TestName::test() |
1001 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( TestName, TestFunc, Name, Tags, Signature, ... ) \ |
1002 | INTERNAL_CATCH_DEFINE_SIG_TEST(TestFunc, INTERNAL_CATCH_REMOVE_PARENS(Signature)) |
1003 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( TestNameClass, TestName, ClassName, Name, Tags, Signature, ... ) \ |
1004 | namespace{ \ |
1005 | namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName) { \ |
1006 | INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, INTERNAL_CATCH_REMOVE_PARENS(Signature));\ |
1007 | } \ |
1008 | } \ |
1009 | INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature)) |
1010 | |
1011 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
1012 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(Name, Tags, ...) \ |
1013 | INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename TestType, __VA_ARGS__ ) |
1014 | #else |
1015 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(Name, Tags, ...) \ |
1016 | INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename TestType, __VA_ARGS__ ) ) |
1017 | #endif |
1018 | |
1019 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
1020 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(Name, Tags, Signature, ...) \ |
1021 | INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ ) |
1022 | #else |
1023 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(Name, Tags, Signature, ...) \ |
1024 | INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ ) ) |
1025 | #endif |
1026 | |
1027 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
1028 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( ClassName, Name, Tags,... ) \ |
1029 | INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) |
1030 | #else |
1031 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( ClassName, Name, Tags,... ) \ |
1032 | INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) ) |
1033 | #endif |
1034 | |
1035 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
1036 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION( ClassName, Name, Tags, Signature, ... ) \ |
1037 | INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) |
1038 | #else |
1039 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION( ClassName, Name, Tags, Signature, ... ) \ |
1040 | INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) ) |
1041 | #endif |
1042 | #endif |
1043 | |
1044 | /////////////////////////////////////////////////////////////////////////////// |
1045 | #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \ |
1046 | static void TestName(); \ |
1047 | CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ |
1048 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ |
1049 | namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ |
1050 | CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ |
1051 | static void TestName() |
1052 | #define INTERNAL_CATCH_TESTCASE( ... ) \ |
1053 | INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ ) |
1054 | |
1055 | /////////////////////////////////////////////////////////////////////////////// |
1056 | #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ |
1057 | CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ |
1058 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ |
1059 | namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &QualifiedMethod ), CATCH_INTERNAL_LINEINFO, "&" #QualifiedMethod, Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ |
1060 | CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION |
1061 | |
1062 | /////////////////////////////////////////////////////////////////////////////// |
1063 | #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\ |
1064 | CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ |
1065 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ |
1066 | namespace{ \ |
1067 | struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \ |
1068 | void test(); \ |
1069 | }; \ |
1070 | Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ |
1071 | } \ |
1072 | CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ |
1073 | void TestName::test() |
1074 | #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \ |
1075 | INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ ) |
1076 | |
1077 | /////////////////////////////////////////////////////////////////////////////// |
1078 | #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ |
1079 | CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ |
1080 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ |
1081 | Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ |
1082 | CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION |
1083 | |
1084 | /////////////////////////////////////////////////////////////////////////////// |
1085 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_2(TestName, TestFunc, Name, Tags, Signature, ... )\ |
1086 | CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ |
1087 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ |
1088 | CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ |
1089 | CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ |
1090 | INTERNAL_CATCH_DECLARE_SIG_TEST(TestFunc, INTERNAL_CATCH_REMOVE_PARENS(Signature));\ |
1091 | namespace {\ |
1092 | namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){\ |
1093 | INTERNAL_CATCH_TYPE_GEN\ |
1094 | INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\ |
1095 | INTERNAL_CATCH_NTTP_REG_GEN(TestFunc,INTERNAL_CATCH_REMOVE_PARENS(Signature))\ |
1096 | template<typename...Types> \ |
1097 | struct TestName{\ |
1098 | TestName(){\ |
1099 | int index = 0; \ |
1100 | constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, __VA_ARGS__)};\ |
1101 | using expander = int[];\ |
1102 | (void)expander{(reg_test(Types{}, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++)... };/* NOLINT */ \ |
1103 | }\ |
1104 | };\ |
1105 | static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\ |
1106 | TestName<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(__VA_ARGS__)>();\ |
1107 | return 0;\ |
1108 | }();\ |
1109 | }\ |
1110 | }\ |
1111 | CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ |
1112 | INTERNAL_CATCH_DEFINE_SIG_TEST(TestFunc,INTERNAL_CATCH_REMOVE_PARENS(Signature)) |
1113 | |
1114 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
1115 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \ |
1116 | INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename TestType, __VA_ARGS__ ) |
1117 | #else |
1118 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \ |
1119 | INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename TestType, __VA_ARGS__ ) ) |
1120 | #endif |
1121 | |
1122 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
1123 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG(Name, Tags, Signature, ...) \ |
1124 | INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ ) |
1125 | #else |
1126 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG(Name, Tags, Signature, ...) \ |
1127 | INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ ) ) |
1128 | #endif |
1129 | |
1130 | #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(TestName, TestFuncName, Name, Tags, Signature, TmplTypes, TypesList) \ |
1131 | CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ |
1132 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ |
1133 | CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ |
1134 | CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ |
1135 | template<typename TestType> static void TestFuncName(); \ |
1136 | namespace {\ |
1137 | namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName) { \ |
1138 | INTERNAL_CATCH_TYPE_GEN \ |
1139 | INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature)) \ |
1140 | template<typename... Types> \ |
1141 | struct TestName { \ |
1142 | void reg_tests() { \ |
1143 | int index = 0; \ |
1144 | using expander = int[]; \ |
1145 | constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\ |
1146 | constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\ |
1147 | constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\ |
1148 | (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFuncName<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + "<" + std::string(types_list[index % num_types]) + ">", Tags } ), index++)... };/* NOLINT */\ |
1149 | } \ |
1150 | }; \ |
1151 | static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \ |
1152 | using TestInit = typename create<TestName, decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>()), TypeList<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(INTERNAL_CATCH_REMOVE_PARENS(TypesList))>>::type; \ |
1153 | TestInit t; \ |
1154 | t.reg_tests(); \ |
1155 | return 0; \ |
1156 | }(); \ |
1157 | } \ |
1158 | } \ |
1159 | CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ |
1160 | template<typename TestType> \ |
1161 | static void TestFuncName() |
1162 | |
1163 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
1164 | #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\ |
1165 | INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename T,__VA_ARGS__) |
1166 | #else |
1167 | #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\ |
1168 | INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename T, __VA_ARGS__ ) ) |
1169 | #endif |
1170 | |
1171 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
1172 | #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG(Name, Tags, Signature, ...)\ |
1173 | INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__) |
1174 | #else |
1175 | #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG(Name, Tags, Signature, ...)\ |
1176 | INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ ) ) |
1177 | #endif |
1178 | |
1179 | #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_2(TestName, TestFunc, Name, Tags, TmplList)\ |
1180 | CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ |
1181 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ |
1182 | CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ |
1183 | template<typename TestType> static void TestFunc(); \ |
1184 | namespace {\ |
1185 | namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){\ |
1186 | INTERNAL_CATCH_TYPE_GEN\ |
1187 | template<typename... Types> \ |
1188 | struct TestName { \ |
1189 | void reg_tests() { \ |
1190 | int index = 0; \ |
1191 | using expander = int[]; \ |
1192 | (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */\ |
1193 | } \ |
1194 | };\ |
1195 | static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \ |
1196 | using TestInit = typename convert<TestName, TmplList>::type; \ |
1197 | TestInit t; \ |
1198 | t.reg_tests(); \ |
1199 | return 0; \ |
1200 | }(); \ |
1201 | }}\ |
1202 | CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ |
1203 | template<typename TestType> \ |
1204 | static void TestFunc() |
1205 | |
1206 | #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE(Name, Tags, TmplList) \ |
1207 | INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, TmplList ) |
1208 | |
1209 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, Signature, ... ) \ |
1210 | CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ |
1211 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ |
1212 | CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ |
1213 | CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ |
1214 | namespace {\ |
1215 | namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){ \ |
1216 | INTERNAL_CATCH_TYPE_GEN\ |
1217 | INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\ |
1218 | INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, INTERNAL_CATCH_REMOVE_PARENS(Signature));\ |
1219 | INTERNAL_CATCH_NTTP_REG_METHOD_GEN(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature))\ |
1220 | template<typename...Types> \ |
1221 | struct TestNameClass{\ |
1222 | TestNameClass(){\ |
1223 | int index = 0; \ |
1224 | constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, __VA_ARGS__)};\ |
1225 | using expander = int[];\ |
1226 | (void)expander{(reg_test(Types{}, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++)... };/* NOLINT */ \ |
1227 | }\ |
1228 | };\ |
1229 | static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\ |
1230 | TestNameClass<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(__VA_ARGS__)>();\ |
1231 | return 0;\ |
1232 | }();\ |
1233 | }\ |
1234 | }\ |
1235 | CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ |
1236 | INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature)) |
1237 | |
1238 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
1239 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \ |
1240 | INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) |
1241 | #else |
1242 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \ |
1243 | INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) ) |
1244 | #endif |
1245 | |
1246 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
1247 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... ) \ |
1248 | INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) |
1249 | #else |
1250 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... ) \ |
1251 | INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) ) |
1252 | #endif |
1253 | |
1254 | #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2(TestNameClass, TestName, ClassName, Name, Tags, Signature, TmplTypes, TypesList)\ |
1255 | CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ |
1256 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ |
1257 | CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ |
1258 | CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ |
1259 | template<typename TestType> \ |
1260 | struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \ |
1261 | void test();\ |
1262 | };\ |
1263 | namespace {\ |
1264 | namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestNameClass) {\ |
1265 | INTERNAL_CATCH_TYPE_GEN \ |
1266 | INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\ |
1267 | template<typename...Types>\ |
1268 | struct TestNameClass{\ |
1269 | void reg_tests(){\ |
1270 | int index = 0;\ |
1271 | using expander = int[];\ |
1272 | constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\ |
1273 | constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\ |
1274 | constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\ |
1275 | (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + "<" + std::string(types_list[index % num_types]) + ">", Tags } ), index++)... };/* NOLINT */ \ |
1276 | }\ |
1277 | };\ |
1278 | static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\ |
1279 | using TestInit = typename create<TestNameClass, decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>()), TypeList<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(INTERNAL_CATCH_REMOVE_PARENS(TypesList))>>::type;\ |
1280 | TestInit t;\ |
1281 | t.reg_tests();\ |
1282 | return 0;\ |
1283 | }(); \ |
1284 | }\ |
1285 | }\ |
1286 | CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ |
1287 | template<typename TestType> \ |
1288 | void TestName<TestType>::test() |
1289 | |
1290 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
1291 | #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\ |
1292 | INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, typename T, __VA_ARGS__ ) |
1293 | #else |
1294 | #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\ |
1295 | INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, typename T,__VA_ARGS__ ) ) |
1296 | #endif |
1297 | |
1298 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
1299 | #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... )\ |
1300 | INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, Signature, __VA_ARGS__ ) |
1301 | #else |
1302 | #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... )\ |
1303 | INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, Signature,__VA_ARGS__ ) ) |
1304 | #endif |
1305 | |
1306 | #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, TmplList) \ |
1307 | CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ |
1308 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ |
1309 | CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ |
1310 | template<typename TestType> \ |
1311 | struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \ |
1312 | void test();\ |
1313 | };\ |
1314 | namespace {\ |
1315 | namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){ \ |
1316 | INTERNAL_CATCH_TYPE_GEN\ |
1317 | template<typename...Types>\ |
1318 | struct TestNameClass{\ |
1319 | void reg_tests(){\ |
1320 | int index = 0;\ |
1321 | using expander = int[];\ |
1322 | (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */ \ |
1323 | }\ |
1324 | };\ |
1325 | static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\ |
1326 | using TestInit = typename convert<TestNameClass, TmplList>::type;\ |
1327 | TestInit t;\ |
1328 | t.reg_tests();\ |
1329 | return 0;\ |
1330 | }(); \ |
1331 | }}\ |
1332 | CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ |
1333 | template<typename TestType> \ |
1334 | void TestName<TestType>::test() |
1335 | |
1336 | #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD(ClassName, Name, Tags, TmplList) \ |
1337 | INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, TmplList ) |
1338 | |
1339 | // end catch_test_registry.h |
1340 | // start catch_capture.hpp |
1341 | |
1342 | // start catch_assertionhandler.h |
1343 | |
1344 | // start catch_assertioninfo.h |
1345 | |
1346 | // start catch_result_type.h |
1347 | |
1348 | namespace Catch { |
1349 | |
1350 | // ResultWas::OfType enum |
1351 | struct ResultWas { enum OfType { |
1352 | Unknown = -1, |
1353 | Ok = 0, |
1354 | Info = 1, |
1355 | Warning = 2, |
1356 | |
1357 | FailureBit = 0x10, |
1358 | |
1359 | ExpressionFailed = FailureBit | 1, |
1360 | ExplicitFailure = FailureBit | 2, |
1361 | |
1362 | Exception = 0x100 | FailureBit, |
1363 | |
1364 | ThrewException = Exception | 1, |
1365 | DidntThrowException = Exception | 2, |
1366 | |
1367 | FatalErrorCondition = 0x200 | FailureBit |
1368 | |
1369 | }; }; |
1370 | |
1371 | bool isOk( ResultWas::OfType resultType ); |
1372 | bool isJustInfo( int flags ); |
1373 | |
1374 | // ResultDisposition::Flags enum |
1375 | struct ResultDisposition { enum Flags { |
1376 | Normal = 0x01, |
1377 | |
1378 | ContinueOnFailure = 0x02, // Failures fail test, but execution continues |
1379 | FalseTest = 0x04, // Prefix expression with ! |
1380 | SuppressFail = 0x08 // Failures are reported but do not fail the test |
1381 | }; }; |
1382 | |
1383 | ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ); |
1384 | |
1385 | bool shouldContinueOnFailure( int flags ); |
1386 | inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } |
1387 | bool shouldSuppressFailure( int flags ); |
1388 | |
1389 | } // end namespace Catch |
1390 | |
1391 | // end catch_result_type.h |
1392 | namespace Catch { |
1393 | |
1394 | struct AssertionInfo |
1395 | { |
1396 | StringRef macroName; |
1397 | SourceLineInfo lineInfo; |
1398 | StringRef capturedExpression; |
1399 | ResultDisposition::Flags resultDisposition; |
1400 | |
1401 | // We want to delete this constructor but a compiler bug in 4.8 means |
1402 | // the struct is then treated as non-aggregate |
1403 | //AssertionInfo() = delete; |
1404 | }; |
1405 | |
1406 | } // end namespace Catch |
1407 | |
1408 | // end catch_assertioninfo.h |
1409 | // start catch_decomposer.h |
1410 | |
1411 | // start catch_tostring.h |
1412 | |
1413 | #include <vector> |
1414 | #include <cstddef> |
1415 | #include <type_traits> |
1416 | #include <string> |
1417 | // start catch_stream.h |
1418 | |
1419 | #include <iosfwd> |
1420 | #include <cstddef> |
1421 | #include <ostream> |
1422 | |
1423 | namespace Catch { |
1424 | |
1425 | std::ostream& cout(); |
1426 | std::ostream& cerr(); |
1427 | std::ostream& clog(); |
1428 | |
1429 | class StringRef; |
1430 | |
1431 | struct IStream { |
1432 | virtual ~IStream(); |
1433 | virtual std::ostream& stream() const = 0; |
1434 | }; |
1435 | |
1436 | auto makeStream( StringRef const &filename ) -> IStream const*; |
1437 | |
1438 | class ReusableStringStream : NonCopyable { |
1439 | std::size_t m_index; |
1440 | std::ostream* m_oss; |
1441 | public: |
1442 | ReusableStringStream(); |
1443 | ~ReusableStringStream(); |
1444 | |
1445 | auto str() const -> std::string; |
1446 | |
1447 | template<typename T> |
1448 | auto operator << ( T const& value ) -> ReusableStringStream& { |
1449 | *m_oss << value; |
1450 | return *this; |
1451 | } |
1452 | auto get() -> std::ostream& { return *m_oss; } |
1453 | }; |
1454 | } |
1455 | |
1456 | // end catch_stream.h |
1457 | // start catch_interfaces_enum_values_registry.h |
1458 | |
1459 | #include <vector> |
1460 | |
1461 | namespace Catch { |
1462 | |
1463 | namespace Detail { |
1464 | struct EnumInfo { |
1465 | StringRef m_name; |
1466 | std::vector<std::pair<int, StringRef>> m_values; |
1467 | |
1468 | ~EnumInfo(); |
1469 | |
1470 | StringRef lookup( int value ) const; |
1471 | }; |
1472 | } // namespace Detail |
1473 | |
1474 | struct IMutableEnumValuesRegistry { |
1475 | virtual ~IMutableEnumValuesRegistry(); |
1476 | |
1477 | virtual Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::vector<int> const& values ) = 0; |
1478 | |
1479 | template<typename E> |
1480 | Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::initializer_list<E> values ) { |
1481 | static_assert(sizeof(int) >= sizeof(E), "Cannot serialize enum to int" ); |
1482 | std::vector<int> intValues; |
1483 | intValues.reserve( values.size() ); |
1484 | for( auto enumValue : values ) |
1485 | intValues.push_back( static_cast<int>( enumValue ) ); |
1486 | return registerEnum( enumName, allEnums, intValues ); |
1487 | } |
1488 | }; |
1489 | |
1490 | } // Catch |
1491 | |
1492 | // end catch_interfaces_enum_values_registry.h |
1493 | |
1494 | #ifdef CATCH_CONFIG_CPP17_STRING_VIEW |
1495 | #include <string_view> |
1496 | #endif |
1497 | |
1498 | #ifdef __OBJC__ |
1499 | // start catch_objc_arc.hpp |
1500 | |
1501 | #import <Foundation/Foundation.h> |
1502 | |
1503 | #ifdef __has_feature |
1504 | #define CATCH_ARC_ENABLED __has_feature(objc_arc) |
1505 | #else |
1506 | #define CATCH_ARC_ENABLED 0 |
1507 | #endif |
1508 | |
1509 | void arcSafeRelease( NSObject* obj ); |
1510 | id performOptionalSelector( id obj, SEL sel ); |
1511 | |
1512 | #if !CATCH_ARC_ENABLED |
1513 | inline void arcSafeRelease( NSObject* obj ) { |
1514 | [obj release]; |
1515 | } |
1516 | inline id performOptionalSelector( id obj, SEL sel ) { |
1517 | if( [obj respondsToSelector: sel] ) |
1518 | return [obj performSelector: sel]; |
1519 | return nil; |
1520 | } |
1521 | #define CATCH_UNSAFE_UNRETAINED |
1522 | #define CATCH_ARC_STRONG |
1523 | #else |
1524 | inline void arcSafeRelease( NSObject* ){} |
1525 | inline id performOptionalSelector( id obj, SEL sel ) { |
1526 | #ifdef __clang__ |
1527 | #pragma clang diagnostic push |
1528 | #pragma clang diagnostic ignored "-Warc-performSelector-leaks" |
1529 | #endif |
1530 | if( [obj respondsToSelector: sel] ) |
1531 | return [obj performSelector: sel]; |
1532 | #ifdef __clang__ |
1533 | #pragma clang diagnostic pop |
1534 | #endif |
1535 | return nil; |
1536 | } |
1537 | #define CATCH_UNSAFE_UNRETAINED __unsafe_unretained |
1538 | #define CATCH_ARC_STRONG __strong |
1539 | #endif |
1540 | |
1541 | // end catch_objc_arc.hpp |
1542 | #endif |
1543 | |
1544 | #ifdef _MSC_VER |
1545 | #pragma warning(push) |
1546 | #pragma warning(disable:4180) // We attempt to stream a function (address) by const&, which MSVC complains about but is harmless |
1547 | #endif |
1548 | |
1549 | namespace Catch { |
1550 | namespace Detail { |
1551 | |
1552 | extern const std::string unprintableString; |
1553 | |
1554 | std::string rawMemoryToString( const void *object, std::size_t size ); |
1555 | |
1556 | template<typename T> |
1557 | std::string rawMemoryToString( const T& object ) { |
1558 | return rawMemoryToString( &object, sizeof(object) ); |
1559 | } |
1560 | |
1561 | template<typename T> |
1562 | class IsStreamInsertable { |
1563 | template<typename Stream, typename U> |
1564 | static auto test(int) |
1565 | -> decltype(std::declval<Stream&>() << std::declval<U>(), std::true_type()); |
1566 | |
1567 | template<typename, typename> |
1568 | static auto test(...)->std::false_type; |
1569 | |
1570 | public: |
1571 | static const bool value = decltype(test<std::ostream, const T&>(0))::value; |
1572 | }; |
1573 | |
1574 | template<typename E> |
1575 | std::string convertUnknownEnumToString( E e ); |
1576 | |
1577 | template<typename T> |
1578 | typename std::enable_if< |
1579 | !std::is_enum<T>::value && !std::is_base_of<std::exception, T>::value, |
1580 | std::string>::type convertUnstreamable( T const& ) { |
1581 | return Detail::unprintableString; |
1582 | } |
1583 | template<typename T> |
1584 | typename std::enable_if< |
1585 | !std::is_enum<T>::value && std::is_base_of<std::exception, T>::value, |
1586 | std::string>::type convertUnstreamable(T const& ex) { |
1587 | return ex.what(); |
1588 | } |
1589 | |
1590 | template<typename T> |
1591 | typename std::enable_if< |
1592 | std::is_enum<T>::value |
1593 | , std::string>::type convertUnstreamable( T const& value ) { |
1594 | return convertUnknownEnumToString( value ); |
1595 | } |
1596 | |
1597 | #if defined(_MANAGED) |
1598 | //! Convert a CLR string to a utf8 std::string |
1599 | template<typename T> |
1600 | std::string clrReferenceToString( T^ ref ) { |
1601 | if (ref == nullptr) |
1602 | return std::string("null" ); |
1603 | auto bytes = System::Text::Encoding::UTF8->GetBytes(ref->ToString()); |
1604 | cli::pin_ptr<System::Byte> p = &bytes[0]; |
1605 | return std::string(reinterpret_cast<char const *>(p), bytes->Length); |
1606 | } |
1607 | #endif |
1608 | |
1609 | } // namespace Detail |
1610 | |
1611 | // If we decide for C++14, change these to enable_if_ts |
1612 | template <typename T, typename = void> |
1613 | struct StringMaker { |
1614 | template <typename Fake = T> |
1615 | static |
1616 | typename std::enable_if<::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>::type |
1617 | convert(const Fake& value) { |
1618 | ReusableStringStream rss; |
1619 | // NB: call using the function-like syntax to avoid ambiguity with |
1620 | // user-defined templated operator<< under clang. |
1621 | rss.operator<<(value); |
1622 | return rss.str(); |
1623 | } |
1624 | |
1625 | template <typename Fake = T> |
1626 | static |
1627 | typename std::enable_if<!::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>::type |
1628 | convert( const Fake& value ) { |
1629 | #if !defined(CATCH_CONFIG_FALLBACK_STRINGIFIER) |
1630 | return Detail::convertUnstreamable(value); |
1631 | #else |
1632 | return CATCH_CONFIG_FALLBACK_STRINGIFIER(value); |
1633 | #endif |
1634 | } |
1635 | }; |
1636 | |
1637 | namespace Detail { |
1638 | |
1639 | // This function dispatches all stringification requests inside of Catch. |
1640 | // Should be preferably called fully qualified, like ::Catch::Detail::stringify |
1641 | template <typename T> |
1642 | std::string stringify(const T& e) { |
1643 | return ::Catch::StringMaker<typename std::remove_cv<typename std::remove_reference<T>::type>::type>::convert(e); |
1644 | } |
1645 | |
1646 | template<typename E> |
1647 | std::string convertUnknownEnumToString( E e ) { |
1648 | return ::Catch::Detail::stringify(static_cast<typename std::underlying_type<E>::type>(e)); |
1649 | } |
1650 | |
1651 | #if defined(_MANAGED) |
1652 | template <typename T> |
1653 | std::string stringify( T^ e ) { |
1654 | return ::Catch::StringMaker<T^>::convert(e); |
1655 | } |
1656 | #endif |
1657 | |
1658 | } // namespace Detail |
1659 | |
1660 | // Some predefined specializations |
1661 | |
1662 | template<> |
1663 | struct StringMaker<std::string> { |
1664 | static std::string convert(const std::string& str); |
1665 | }; |
1666 | |
1667 | #ifdef CATCH_CONFIG_CPP17_STRING_VIEW |
1668 | template<> |
1669 | struct StringMaker<std::string_view> { |
1670 | static std::string convert(std::string_view str); |
1671 | }; |
1672 | #endif |
1673 | |
1674 | template<> |
1675 | struct StringMaker<char const *> { |
1676 | static std::string convert(char const * str); |
1677 | }; |
1678 | template<> |
1679 | struct StringMaker<char *> { |
1680 | static std::string convert(char * str); |
1681 | }; |
1682 | |
1683 | #ifdef CATCH_CONFIG_WCHAR |
1684 | template<> |
1685 | struct StringMaker<std::wstring> { |
1686 | static std::string convert(const std::wstring& wstr); |
1687 | }; |
1688 | |
1689 | # ifdef CATCH_CONFIG_CPP17_STRING_VIEW |
1690 | template<> |
1691 | struct StringMaker<std::wstring_view> { |
1692 | static std::string convert(std::wstring_view str); |
1693 | }; |
1694 | # endif |
1695 | |
1696 | template<> |
1697 | struct StringMaker<wchar_t const *> { |
1698 | static std::string convert(wchar_t const * str); |
1699 | }; |
1700 | template<> |
1701 | struct StringMaker<wchar_t *> { |
1702 | static std::string convert(wchar_t * str); |
1703 | }; |
1704 | #endif |
1705 | |
1706 | // TBD: Should we use `strnlen` to ensure that we don't go out of the buffer, |
1707 | // while keeping string semantics? |
1708 | template<int SZ> |
1709 | struct StringMaker<char[SZ]> { |
1710 | static std::string convert(char const* str) { |
1711 | return ::Catch::Detail::stringify(std::string{ str }); |
1712 | } |
1713 | }; |
1714 | template<int SZ> |
1715 | struct StringMaker<signed char[SZ]> { |
1716 | static std::string convert(signed char const* str) { |
1717 | return ::Catch::Detail::stringify(std::string{ reinterpret_cast<char const *>(str) }); |
1718 | } |
1719 | }; |
1720 | template<int SZ> |
1721 | struct StringMaker<unsigned char[SZ]> { |
1722 | static std::string convert(unsigned char const* str) { |
1723 | return ::Catch::Detail::stringify(std::string{ reinterpret_cast<char const *>(str) }); |
1724 | } |
1725 | }; |
1726 | |
1727 | #if defined(CATCH_CONFIG_CPP17_BYTE) |
1728 | template<> |
1729 | struct StringMaker<std::byte> { |
1730 | static std::string convert(std::byte value); |
1731 | }; |
1732 | #endif // defined(CATCH_CONFIG_CPP17_BYTE) |
1733 | template<> |
1734 | struct StringMaker<int> { |
1735 | static std::string convert(int value); |
1736 | }; |
1737 | template<> |
1738 | struct StringMaker<long> { |
1739 | static std::string convert(long value); |
1740 | }; |
1741 | template<> |
1742 | struct StringMaker<long long> { |
1743 | static std::string convert(long long value); |
1744 | }; |
1745 | template<> |
1746 | struct StringMaker<unsigned int> { |
1747 | static std::string convert(unsigned int value); |
1748 | }; |
1749 | template<> |
1750 | struct StringMaker<unsigned long> { |
1751 | static std::string convert(unsigned long value); |
1752 | }; |
1753 | template<> |
1754 | struct StringMaker<unsigned long long> { |
1755 | static std::string convert(unsigned long long value); |
1756 | }; |
1757 | |
1758 | template<> |
1759 | struct StringMaker<bool> { |
1760 | static std::string convert(bool b); |
1761 | }; |
1762 | |
1763 | template<> |
1764 | struct StringMaker<char> { |
1765 | static std::string convert(char c); |
1766 | }; |
1767 | template<> |
1768 | struct StringMaker<signed char> { |
1769 | static std::string convert(signed char c); |
1770 | }; |
1771 | template<> |
1772 | struct StringMaker<unsigned char> { |
1773 | static std::string convert(unsigned char c); |
1774 | }; |
1775 | |
1776 | template<> |
1777 | struct StringMaker<std::nullptr_t> { |
1778 | static std::string convert(std::nullptr_t); |
1779 | }; |
1780 | |
1781 | template<> |
1782 | struct StringMaker<float> { |
1783 | static std::string convert(float value); |
1784 | static int precision; |
1785 | }; |
1786 | |
1787 | template<> |
1788 | struct StringMaker<double> { |
1789 | static std::string convert(double value); |
1790 | static int precision; |
1791 | }; |
1792 | |
1793 | template <typename T> |
1794 | struct StringMaker<T*> { |
1795 | template <typename U> |
1796 | static std::string convert(U* p) { |
1797 | if (p) { |
1798 | return ::Catch::Detail::rawMemoryToString(p); |
1799 | } else { |
1800 | return "nullptr" ; |
1801 | } |
1802 | } |
1803 | }; |
1804 | |
1805 | template <typename R, typename C> |
1806 | struct StringMaker<R C::*> { |
1807 | static std::string convert(R C::* p) { |
1808 | if (p) { |
1809 | return ::Catch::Detail::rawMemoryToString(p); |
1810 | } else { |
1811 | return "nullptr" ; |
1812 | } |
1813 | } |
1814 | }; |
1815 | |
1816 | #if defined(_MANAGED) |
1817 | template <typename T> |
1818 | struct StringMaker<T^> { |
1819 | static std::string convert( T^ ref ) { |
1820 | return ::Catch::Detail::clrReferenceToString(ref); |
1821 | } |
1822 | }; |
1823 | #endif |
1824 | |
1825 | namespace Detail { |
1826 | template<typename InputIterator, typename Sentinel = InputIterator> |
1827 | std::string rangeToString(InputIterator first, Sentinel last) { |
1828 | ReusableStringStream ; |
1829 | rss << "{ " ; |
1830 | if (first != last) { |
1831 | rss << ::Catch::Detail::stringify(*first); |
1832 | for (++first; first != last; ++first) |
1833 | rss << ", " << ::Catch::Detail::stringify(*first); |
1834 | } |
1835 | rss << " }" ; |
1836 | return rss.str(); |
1837 | } |
1838 | } |
1839 | |
1840 | #ifdef __OBJC__ |
1841 | template<> |
1842 | struct StringMaker<NSString*> { |
1843 | static std::string convert(NSString * nsstring) { |
1844 | if (!nsstring) |
1845 | return "nil" ; |
1846 | return std::string("@" ) + [nsstring UTF8String]; |
1847 | } |
1848 | }; |
1849 | template<> |
1850 | struct StringMaker<NSObject*> { |
1851 | static std::string convert(NSObject* nsObject) { |
1852 | return ::Catch::Detail::stringify([nsObject description]); |
1853 | } |
1854 | |
1855 | }; |
1856 | namespace Detail { |
1857 | inline std::string stringify( NSString* nsstring ) { |
1858 | return StringMaker<NSString*>::convert( nsstring ); |
1859 | } |
1860 | |
1861 | } // namespace Detail |
1862 | #endif // __OBJC__ |
1863 | |
1864 | } // namespace Catch |
1865 | |
1866 | ////////////////////////////////////////////////////// |
1867 | // Separate std-lib types stringification, so it can be selectively enabled |
1868 | // This means that we do not bring in |
1869 | |
1870 | #if defined(CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS) |
1871 | # define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER |
1872 | # define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER |
1873 | # define CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER |
1874 | # define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER |
1875 | # define CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER |
1876 | #endif |
1877 | |
1878 | // Separate std::pair specialization |
1879 | #if defined(CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER) |
1880 | #include <utility> |
1881 | namespace Catch { |
1882 | template<typename T1, typename T2> |
1883 | struct StringMaker<std::pair<T1, T2> > { |
1884 | static std::string convert(const std::pair<T1, T2>& pair) { |
1885 | ReusableStringStream rss; |
1886 | rss << "{ " |
1887 | << ::Catch::Detail::stringify(pair.first) |
1888 | << ", " |
1889 | << ::Catch::Detail::stringify(pair.second) |
1890 | << " }" ; |
1891 | return rss.str(); |
1892 | } |
1893 | }; |
1894 | } |
1895 | #endif // CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER |
1896 | |
1897 | #if defined(CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_OPTIONAL) |
1898 | #include <optional> |
1899 | namespace Catch { |
1900 | template<typename T> |
1901 | struct StringMaker<std::optional<T> > { |
1902 | static std::string convert(const std::optional<T>& optional) { |
1903 | ReusableStringStream rss; |
1904 | if (optional.has_value()) { |
1905 | rss << ::Catch::Detail::stringify(*optional); |
1906 | } else { |
1907 | rss << "{ }" ; |
1908 | } |
1909 | return rss.str(); |
1910 | } |
1911 | }; |
1912 | } |
1913 | #endif // CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER |
1914 | |
1915 | // Separate std::tuple specialization |
1916 | #if defined(CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER) |
1917 | #include <tuple> |
1918 | namespace Catch { |
1919 | namespace Detail { |
1920 | template< |
1921 | typename Tuple, |
1922 | std::size_t N = 0, |
1923 | bool = (N < std::tuple_size<Tuple>::value) |
1924 | > |
1925 | struct TupleElementPrinter { |
1926 | static void print(const Tuple& tuple, std::ostream& os) { |
1927 | os << (N ? ", " : " " ) |
1928 | << ::Catch::Detail::stringify(std::get<N>(tuple)); |
1929 | TupleElementPrinter<Tuple, N + 1>::print(tuple, os); |
1930 | } |
1931 | }; |
1932 | |
1933 | template< |
1934 | typename Tuple, |
1935 | std::size_t N |
1936 | > |
1937 | struct TupleElementPrinter<Tuple, N, false> { |
1938 | static void print(const Tuple&, std::ostream&) {} |
1939 | }; |
1940 | |
1941 | } |
1942 | |
1943 | template<typename ...Types> |
1944 | struct StringMaker<std::tuple<Types...>> { |
1945 | static std::string convert(const std::tuple<Types...>& tuple) { |
1946 | ReusableStringStream rss; |
1947 | rss << '{'; |
1948 | Detail::TupleElementPrinter<std::tuple<Types...>>::print(tuple, rss.get()); |
1949 | rss << " }" ; |
1950 | return rss.str(); |
1951 | } |
1952 | }; |
1953 | } |
1954 | #endif // CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER |
1955 | |
1956 | #if defined(CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_VARIANT) |
1957 | #include <variant> |
1958 | namespace Catch { |
1959 | template<> |
1960 | struct StringMaker<std::monostate> { |
1961 | static std::string convert(const std::monostate&) { |
1962 | return "{ }" ; |
1963 | } |
1964 | }; |
1965 | |
1966 | template<typename... Elements> |
1967 | struct StringMaker<std::variant<Elements...>> { |
1968 | static std::string convert(const std::variant<Elements...>& variant) { |
1969 | if (variant.valueless_by_exception()) { |
1970 | return "{valueless variant}" ; |
1971 | } else { |
1972 | return std::visit( |
1973 | [](const auto& value) { |
1974 | return ::Catch::Detail::stringify(value); |
1975 | }, |
1976 | variant |
1977 | ); |
1978 | } |
1979 | } |
1980 | }; |
1981 | } |
1982 | #endif // CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER |
1983 | |
1984 | namespace Catch { |
1985 | // Import begin/ end from std here |
1986 | using std::begin; |
1987 | using std::end; |
1988 | |
1989 | namespace detail { |
1990 | template <typename...> |
1991 | struct void_type { |
1992 | using type = void; |
1993 | }; |
1994 | |
1995 | template <typename T, typename = void> |
1996 | struct is_range_impl : std::false_type { |
1997 | }; |
1998 | |
1999 | template <typename T> |
2000 | struct is_range_impl<T, typename void_type<decltype(begin(std::declval<T>()))>::type> : std::true_type { |
2001 | }; |
2002 | } // namespace detail |
2003 | |
2004 | template <typename T> |
2005 | struct is_range : detail::is_range_impl<T> { |
2006 | }; |
2007 | |
2008 | #if defined(_MANAGED) // Managed types are never ranges |
2009 | template <typename T> |
2010 | struct is_range<T^> { |
2011 | static const bool value = false; |
2012 | }; |
2013 | #endif |
2014 | |
2015 | template<typename Range> |
2016 | std::string rangeToString( Range const& range ) { |
2017 | return ::Catch::Detail::rangeToString( begin( range ), end( range ) ); |
2018 | } |
2019 | |
2020 | // Handle vector<bool> specially |
2021 | template<typename Allocator> |
2022 | std::string rangeToString( std::vector<bool, Allocator> const& v ) { |
2023 | ReusableStringStream rss; |
2024 | rss << "{ " ; |
2025 | bool first = true; |
2026 | for( bool b : v ) { |
2027 | if( first ) |
2028 | first = false; |
2029 | else |
2030 | rss << ", " ; |
2031 | rss << ::Catch::Detail::stringify( b ); |
2032 | } |
2033 | rss << " }" ; |
2034 | return rss.str(); |
2035 | } |
2036 | |
2037 | template<typename R> |
2038 | struct StringMaker<R, typename std::enable_if<is_range<R>::value && !::Catch::Detail::IsStreamInsertable<R>::value>::type> { |
2039 | static std::string convert( R const& range ) { |
2040 | return rangeToString( range ); |
2041 | } |
2042 | }; |
2043 | |
2044 | template <typename T, int SZ> |
2045 | struct StringMaker<T[SZ]> { |
2046 | static std::string convert(T const(&arr)[SZ]) { |
2047 | return rangeToString(arr); |
2048 | } |
2049 | }; |
2050 | |
2051 | } // namespace Catch |
2052 | |
2053 | // Separate std::chrono::duration specialization |
2054 | #if defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) |
2055 | #include <ctime> |
2056 | #include <ratio> |
2057 | #include <chrono> |
2058 | |
2059 | namespace Catch { |
2060 | |
2061 | template <class Ratio> |
2062 | struct ratio_string { |
2063 | static std::string symbol(); |
2064 | }; |
2065 | |
2066 | template <class Ratio> |
2067 | std::string ratio_string<Ratio>::symbol() { |
2068 | Catch::ReusableStringStream ; |
2069 | rss << '[' << Ratio::num << '/' |
2070 | << Ratio::den << ']'; |
2071 | return rss.str(); |
2072 | } |
2073 | template <> |
2074 | struct ratio_string<std::atto> { |
2075 | static std::string symbol(); |
2076 | }; |
2077 | template <> |
2078 | struct ratio_string<std::femto> { |
2079 | static std::string symbol(); |
2080 | }; |
2081 | template <> |
2082 | struct ratio_string<std::pico> { |
2083 | static std::string symbol(); |
2084 | }; |
2085 | template <> |
2086 | struct ratio_string<std::nano> { |
2087 | static std::string symbol(); |
2088 | }; |
2089 | template <> |
2090 | struct ratio_string<std::micro> { |
2091 | static std::string symbol(); |
2092 | }; |
2093 | template <> |
2094 | struct ratio_string<std::milli> { |
2095 | static std::string symbol(); |
2096 | }; |
2097 | |
2098 | //////////// |
2099 | // std::chrono::duration specializations |
2100 | template<typename Value, typename Ratio> |
2101 | struct StringMaker<std::chrono::duration<Value, Ratio>> { |
2102 | static std::string convert(std::chrono::duration<Value, Ratio> const& duration) { |
2103 | ReusableStringStream rss; |
2104 | rss << duration.count() << ' ' << ratio_string<Ratio>::symbol() << 's'; |
2105 | return rss.str(); |
2106 | } |
2107 | }; |
2108 | template<typename Value> |
2109 | struct StringMaker<std::chrono::duration<Value, std::ratio<1>>> { |
2110 | static std::string convert(std::chrono::duration<Value, std::ratio<1>> const& duration) { |
2111 | ReusableStringStream rss; |
2112 | rss << duration.count() << " s" ; |
2113 | return rss.str(); |
2114 | } |
2115 | }; |
2116 | template<typename Value> |
2117 | struct StringMaker<std::chrono::duration<Value, std::ratio<60>>> { |
2118 | static std::string convert(std::chrono::duration<Value, std::ratio<60>> const& duration) { |
2119 | ReusableStringStream rss; |
2120 | rss << duration.count() << " m" ; |
2121 | return rss.str(); |
2122 | } |
2123 | }; |
2124 | template<typename Value> |
2125 | struct StringMaker<std::chrono::duration<Value, std::ratio<3600>>> { |
2126 | static std::string convert(std::chrono::duration<Value, std::ratio<3600>> const& duration) { |
2127 | ReusableStringStream rss; |
2128 | rss << duration.count() << " h" ; |
2129 | return rss.str(); |
2130 | } |
2131 | }; |
2132 | |
2133 | //////////// |
2134 | // std::chrono::time_point specialization |
2135 | // Generic time_point cannot be specialized, only std::chrono::time_point<system_clock> |
2136 | template<typename Clock, typename Duration> |
2137 | struct StringMaker<std::chrono::time_point<Clock, Duration>> { |
2138 | static std::string convert(std::chrono::time_point<Clock, Duration> const& time_point) { |
2139 | return ::Catch::Detail::stringify(time_point.time_since_epoch()) + " since epoch" ; |
2140 | } |
2141 | }; |
2142 | // std::chrono::time_point<system_clock> specialization |
2143 | template<typename Duration> |
2144 | struct StringMaker<std::chrono::time_point<std::chrono::system_clock, Duration>> { |
2145 | static std::string convert(std::chrono::time_point<std::chrono::system_clock, Duration> const& time_point) { |
2146 | auto converted = std::chrono::system_clock::to_time_t(time_point); |
2147 | |
2148 | #ifdef _MSC_VER |
2149 | std::tm timeInfo = {}; |
2150 | gmtime_s(&timeInfo, &converted); |
2151 | #else |
2152 | std::tm* timeInfo = std::gmtime(&converted); |
2153 | #endif |
2154 | |
2155 | auto const timeStampSize = sizeof("2017-01-16T17:06:45Z" ); |
2156 | char timeStamp[timeStampSize]; |
2157 | const char * const fmt = "%Y-%m-%dT%H:%M:%SZ" ; |
2158 | |
2159 | #ifdef _MSC_VER |
2160 | std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); |
2161 | #else |
2162 | std::strftime(timeStamp, timeStampSize, fmt, timeInfo); |
2163 | #endif |
2164 | return std::string(timeStamp); |
2165 | } |
2166 | }; |
2167 | } |
2168 | #endif // CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER |
2169 | |
2170 | #define INTERNAL_CATCH_REGISTER_ENUM( enumName, ... ) \ |
2171 | namespace Catch { \ |
2172 | template<> struct StringMaker<enumName> { \ |
2173 | static std::string convert( enumName value ) { \ |
2174 | static const auto& enumInfo = ::Catch::getMutableRegistryHub().getMutableEnumValuesRegistry().registerEnum( #enumName, #__VA_ARGS__, { __VA_ARGS__ } ); \ |
2175 | return static_cast<std::string>(enumInfo.lookup( static_cast<int>( value ) )); \ |
2176 | } \ |
2177 | }; \ |
2178 | } |
2179 | |
2180 | #define CATCH_REGISTER_ENUM( enumName, ... ) INTERNAL_CATCH_REGISTER_ENUM( enumName, __VA_ARGS__ ) |
2181 | |
2182 | #ifdef _MSC_VER |
2183 | #pragma warning(pop) |
2184 | #endif |
2185 | |
2186 | // end catch_tostring.h |
2187 | #include <iosfwd> |
2188 | |
2189 | #ifdef _MSC_VER |
2190 | #pragma warning(push) |
2191 | #pragma warning(disable:4389) // '==' : signed/unsigned mismatch |
2192 | #pragma warning(disable:4018) // more "signed/unsigned mismatch" |
2193 | #pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform) |
2194 | #pragma warning(disable:4180) // qualifier applied to function type has no meaning |
2195 | #pragma warning(disable:4800) // Forcing result to true or false |
2196 | #endif |
2197 | |
2198 | namespace Catch { |
2199 | |
2200 | struct ITransientExpression { |
2201 | auto isBinaryExpression() const -> bool { return m_isBinaryExpression; } |
2202 | auto getResult() const -> bool { return m_result; } |
2203 | virtual void streamReconstructedExpression( std::ostream &os ) const = 0; |
2204 | |
2205 | ITransientExpression( bool isBinaryExpression, bool result ) |
2206 | : m_isBinaryExpression( isBinaryExpression ), |
2207 | m_result( result ) |
2208 | {} |
2209 | |
2210 | // We don't actually need a virtual destructor, but many static analysers |
2211 | // complain if it's not here :-( |
2212 | virtual ~ITransientExpression(); |
2213 | |
2214 | bool m_isBinaryExpression; |
2215 | bool m_result; |
2216 | |
2217 | }; |
2218 | |
2219 | void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ); |
2220 | |
2221 | template<typename LhsT, typename RhsT> |
2222 | class BinaryExpr : public ITransientExpression { |
2223 | LhsT m_lhs; |
2224 | StringRef m_op; |
2225 | RhsT m_rhs; |
2226 | |
2227 | void streamReconstructedExpression( std::ostream &os ) const override { |
2228 | formatReconstructedExpression |
2229 | ( os, Catch::Detail::stringify( m_lhs ), m_op, Catch::Detail::stringify( m_rhs ) ); |
2230 | } |
2231 | |
2232 | public: |
2233 | BinaryExpr( bool comparisonResult, LhsT lhs, StringRef op, RhsT rhs ) |
2234 | : ITransientExpression{ true, comparisonResult }, |
2235 | m_lhs( lhs ), |
2236 | m_op( op ), |
2237 | m_rhs( rhs ) |
2238 | {} |
2239 | |
2240 | template<typename T> |
2241 | auto operator && ( T ) const -> BinaryExpr<LhsT, RhsT const&> const { |
2242 | static_assert(always_false<T>::value, |
2243 | "chained comparisons are not supported inside assertions, " |
2244 | "wrap the expression inside parentheses, or decompose it" ); |
2245 | } |
2246 | |
2247 | template<typename T> |
2248 | auto operator || ( T ) const -> BinaryExpr<LhsT, RhsT const&> const { |
2249 | static_assert(always_false<T>::value, |
2250 | "chained comparisons are not supported inside assertions, " |
2251 | "wrap the expression inside parentheses, or decompose it" ); |
2252 | } |
2253 | |
2254 | template<typename T> |
2255 | auto operator == ( T ) const -> BinaryExpr<LhsT, RhsT const&> const { |
2256 | static_assert(always_false<T>::value, |
2257 | "chained comparisons are not supported inside assertions, " |
2258 | "wrap the expression inside parentheses, or decompose it" ); |
2259 | } |
2260 | |
2261 | template<typename T> |
2262 | auto operator != ( T ) const -> BinaryExpr<LhsT, RhsT const&> const { |
2263 | static_assert(always_false<T>::value, |
2264 | "chained comparisons are not supported inside assertions, " |
2265 | "wrap the expression inside parentheses, or decompose it" ); |
2266 | } |
2267 | |
2268 | template<typename T> |
2269 | auto operator > ( T ) const -> BinaryExpr<LhsT, RhsT const&> const { |
2270 | static_assert(always_false<T>::value, |
2271 | "chained comparisons are not supported inside assertions, " |
2272 | "wrap the expression inside parentheses, or decompose it" ); |
2273 | } |
2274 | |
2275 | template<typename T> |
2276 | auto operator < ( T ) const -> BinaryExpr<LhsT, RhsT const&> const { |
2277 | static_assert(always_false<T>::value, |
2278 | "chained comparisons are not supported inside assertions, " |
2279 | "wrap the expression inside parentheses, or decompose it" ); |
2280 | } |
2281 | |
2282 | template<typename T> |
2283 | auto operator >= ( T ) const -> BinaryExpr<LhsT, RhsT const&> const { |
2284 | static_assert(always_false<T>::value, |
2285 | "chained comparisons are not supported inside assertions, " |
2286 | "wrap the expression inside parentheses, or decompose it" ); |
2287 | } |
2288 | |
2289 | template<typename T> |
2290 | auto operator <= ( T ) const -> BinaryExpr<LhsT, RhsT const&> const { |
2291 | static_assert(always_false<T>::value, |
2292 | "chained comparisons are not supported inside assertions, " |
2293 | "wrap the expression inside parentheses, or decompose it" ); |
2294 | } |
2295 | }; |
2296 | |
2297 | template<typename LhsT> |
2298 | class UnaryExpr : public ITransientExpression { |
2299 | LhsT m_lhs; |
2300 | |
2301 | void streamReconstructedExpression( std::ostream &os ) const override { |
2302 | os << Catch::Detail::stringify( m_lhs ); |
2303 | } |
2304 | |
2305 | public: |
2306 | explicit UnaryExpr( LhsT lhs ) |
2307 | : ITransientExpression{ false, static_cast<bool>(lhs) }, |
2308 | m_lhs( lhs ) |
2309 | {} |
2310 | }; |
2311 | |
2312 | // Specialised comparison functions to handle equality comparisons between ints and pointers (NULL deduces as an int) |
2313 | template<typename LhsT, typename RhsT> |
2314 | auto compareEqual( LhsT const& lhs, RhsT const& rhs ) -> bool { return static_cast<bool>(lhs == rhs); } |
2315 | template<typename T> |
2316 | auto compareEqual( T* const& lhs, int rhs ) -> bool { return lhs == reinterpret_cast<void const*>( rhs ); } |
2317 | template<typename T> |
2318 | auto compareEqual( T* const& lhs, long rhs ) -> bool { return lhs == reinterpret_cast<void const*>( rhs ); } |
2319 | template<typename T> |
2320 | auto compareEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) == rhs; } |
2321 | template<typename T> |
2322 | auto compareEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) == rhs; } |
2323 | |
2324 | template<typename LhsT, typename RhsT> |
2325 | auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return static_cast<bool>(lhs != rhs); } |
2326 | template<typename T> |
2327 | auto compareNotEqual( T* const& lhs, int rhs ) -> bool { return lhs != reinterpret_cast<void const*>( rhs ); } |
2328 | template<typename T> |
2329 | auto compareNotEqual( T* const& lhs, long rhs ) -> bool { return lhs != reinterpret_cast<void const*>( rhs ); } |
2330 | template<typename T> |
2331 | auto compareNotEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) != rhs; } |
2332 | template<typename T> |
2333 | auto compareNotEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) != rhs; } |
2334 | |
2335 | template<typename LhsT> |
2336 | class ExprLhs { |
2337 | LhsT m_lhs; |
2338 | public: |
2339 | explicit ExprLhs( LhsT lhs ) : m_lhs( lhs ) {} |
2340 | |
2341 | template<typename RhsT> |
2342 | auto operator == ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { |
2343 | return { compareEqual( m_lhs, rhs ), m_lhs, "==" , rhs }; |
2344 | } |
2345 | auto operator == ( bool rhs ) -> BinaryExpr<LhsT, bool> const { |
2346 | return { m_lhs == rhs, m_lhs, "==" , rhs }; |
2347 | } |
2348 | |
2349 | template<typename RhsT> |
2350 | auto operator != ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { |
2351 | return { compareNotEqual( m_lhs, rhs ), m_lhs, "!=" , rhs }; |
2352 | } |
2353 | auto operator != ( bool rhs ) -> BinaryExpr<LhsT, bool> const { |
2354 | return { m_lhs != rhs, m_lhs, "!=" , rhs }; |
2355 | } |
2356 | |
2357 | template<typename RhsT> |
2358 | auto operator > ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { |
2359 | return { static_cast<bool>(m_lhs > rhs), m_lhs, ">" , rhs }; |
2360 | } |
2361 | template<typename RhsT> |
2362 | auto operator < ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { |
2363 | return { static_cast<bool>(m_lhs < rhs), m_lhs, "<" , rhs }; |
2364 | } |
2365 | template<typename RhsT> |
2366 | auto operator >= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { |
2367 | return { static_cast<bool>(m_lhs >= rhs), m_lhs, ">=" , rhs }; |
2368 | } |
2369 | template<typename RhsT> |
2370 | auto operator <= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { |
2371 | return { static_cast<bool>(m_lhs <= rhs), m_lhs, "<=" , rhs }; |
2372 | } |
2373 | template <typename RhsT> |
2374 | auto operator | (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const { |
2375 | return { static_cast<bool>(m_lhs | rhs), m_lhs, "|" , rhs }; |
2376 | } |
2377 | template <typename RhsT> |
2378 | auto operator & (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const { |
2379 | return { static_cast<bool>(m_lhs & rhs), m_lhs, "&" , rhs }; |
2380 | } |
2381 | template <typename RhsT> |
2382 | auto operator ^ (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const { |
2383 | return { static_cast<bool>(m_lhs ^ rhs), m_lhs, "^" , rhs }; |
2384 | } |
2385 | |
2386 | template<typename RhsT> |
2387 | auto operator && ( RhsT const& ) -> BinaryExpr<LhsT, RhsT const&> const { |
2388 | static_assert(always_false<RhsT>::value, |
2389 | "operator&& is not supported inside assertions, " |
2390 | "wrap the expression inside parentheses, or decompose it" ); |
2391 | } |
2392 | |
2393 | template<typename RhsT> |
2394 | auto operator || ( RhsT const& ) -> BinaryExpr<LhsT, RhsT const&> const { |
2395 | static_assert(always_false<RhsT>::value, |
2396 | "operator|| is not supported inside assertions, " |
2397 | "wrap the expression inside parentheses, or decompose it" ); |
2398 | } |
2399 | |
2400 | auto makeUnaryExpr() const -> UnaryExpr<LhsT> { |
2401 | return UnaryExpr<LhsT>{ m_lhs }; |
2402 | } |
2403 | }; |
2404 | |
2405 | void handleExpression( ITransientExpression const& expr ); |
2406 | |
2407 | template<typename T> |
2408 | void handleExpression( ExprLhs<T> const& expr ) { |
2409 | handleExpression( expr.makeUnaryExpr() ); |
2410 | } |
2411 | |
2412 | struct Decomposer { |
2413 | template<typename T> |
2414 | auto operator <= ( T const& lhs ) -> ExprLhs<T const&> { |
2415 | return ExprLhs<T const&>{ lhs }; |
2416 | } |
2417 | |
2418 | auto operator <=( bool value ) -> ExprLhs<bool> { |
2419 | return ExprLhs<bool>{ value }; |
2420 | } |
2421 | }; |
2422 | |
2423 | } // end namespace Catch |
2424 | |
2425 | #ifdef _MSC_VER |
2426 | #pragma warning(pop) |
2427 | #endif |
2428 | |
2429 | // end catch_decomposer.h |
2430 | // start catch_interfaces_capture.h |
2431 | |
2432 | #include <string> |
2433 | #include <chrono> |
2434 | |
2435 | namespace Catch { |
2436 | |
2437 | class AssertionResult; |
2438 | struct AssertionInfo; |
2439 | struct SectionInfo; |
2440 | struct SectionEndInfo; |
2441 | struct MessageInfo; |
2442 | struct MessageBuilder; |
2443 | struct Counts; |
2444 | struct AssertionReaction; |
2445 | struct SourceLineInfo; |
2446 | |
2447 | struct ITransientExpression; |
2448 | struct IGeneratorTracker; |
2449 | |
2450 | #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) |
2451 | struct BenchmarkInfo; |
2452 | template <typename Duration = std::chrono::duration<double, std::nano>> |
2453 | struct BenchmarkStats; |
2454 | #endif // CATCH_CONFIG_ENABLE_BENCHMARKING |
2455 | |
2456 | struct IResultCapture { |
2457 | |
2458 | virtual ~IResultCapture(); |
2459 | |
2460 | virtual bool sectionStarted( SectionInfo const& sectionInfo, |
2461 | Counts& assertions ) = 0; |
2462 | virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; |
2463 | virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; |
2464 | |
2465 | virtual auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0; |
2466 | |
2467 | #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) |
2468 | virtual void benchmarkPreparing( std::string const& name ) = 0; |
2469 | virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0; |
2470 | virtual void benchmarkEnded( BenchmarkStats<> const& stats ) = 0; |
2471 | virtual void benchmarkFailed( std::string const& error ) = 0; |
2472 | #endif // CATCH_CONFIG_ENABLE_BENCHMARKING |
2473 | |
2474 | virtual void pushScopedMessage( MessageInfo const& message ) = 0; |
2475 | virtual void popScopedMessage( MessageInfo const& message ) = 0; |
2476 | |
2477 | virtual void emplaceUnscopedMessage( MessageBuilder const& builder ) = 0; |
2478 | |
2479 | virtual void handleFatalErrorCondition( StringRef message ) = 0; |
2480 | |
2481 | virtual void handleExpr |
2482 | ( AssertionInfo const& info, |
2483 | ITransientExpression const& expr, |
2484 | AssertionReaction& reaction ) = 0; |
2485 | virtual void handleMessage |
2486 | ( AssertionInfo const& info, |
2487 | ResultWas::OfType resultType, |
2488 | StringRef const& message, |
2489 | AssertionReaction& reaction ) = 0; |
2490 | virtual void handleUnexpectedExceptionNotThrown |
2491 | ( AssertionInfo const& info, |
2492 | AssertionReaction& reaction ) = 0; |
2493 | virtual void handleUnexpectedInflightException |
2494 | ( AssertionInfo const& info, |
2495 | std::string const& message, |
2496 | AssertionReaction& reaction ) = 0; |
2497 | virtual void handleIncomplete |
2498 | ( AssertionInfo const& info ) = 0; |
2499 | virtual void handleNonExpr |
2500 | ( AssertionInfo const &info, |
2501 | ResultWas::OfType resultType, |
2502 | AssertionReaction &reaction ) = 0; |
2503 | |
2504 | virtual bool lastAssertionPassed() = 0; |
2505 | virtual void assertionPassed() = 0; |
2506 | |
2507 | // Deprecated, do not use: |
2508 | virtual std::string getCurrentTestName() const = 0; |
2509 | virtual const AssertionResult* getLastResult() const = 0; |
2510 | virtual void exceptionEarlyReported() = 0; |
2511 | }; |
2512 | |
2513 | IResultCapture& getResultCapture(); |
2514 | } |
2515 | |
2516 | // end catch_interfaces_capture.h |
2517 | namespace Catch { |
2518 | |
2519 | struct TestFailureException{}; |
2520 | struct AssertionResultData; |
2521 | struct IResultCapture; |
2522 | class RunContext; |
2523 | |
2524 | class LazyExpression { |
2525 | friend class AssertionHandler; |
2526 | friend struct AssertionStats; |
2527 | friend class RunContext; |
2528 | |
2529 | ITransientExpression const* m_transientExpression = nullptr; |
2530 | bool m_isNegated; |
2531 | public: |
2532 | LazyExpression( bool isNegated ); |
2533 | LazyExpression( LazyExpression const& other ); |
2534 | LazyExpression& operator = ( LazyExpression const& ) = delete; |
2535 | |
2536 | explicit operator bool() const; |
2537 | |
2538 | friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&; |
2539 | }; |
2540 | |
2541 | struct AssertionReaction { |
2542 | bool shouldDebugBreak = false; |
2543 | bool shouldThrow = false; |
2544 | }; |
2545 | |
2546 | class AssertionHandler { |
2547 | AssertionInfo m_assertionInfo; |
2548 | AssertionReaction m_reaction; |
2549 | bool m_completed = false; |
2550 | IResultCapture& m_resultCapture; |
2551 | |
2552 | public: |
2553 | AssertionHandler |
2554 | ( StringRef const& macroName, |
2555 | SourceLineInfo const& lineInfo, |
2556 | StringRef capturedExpression, |
2557 | ResultDisposition::Flags resultDisposition ); |
2558 | ~AssertionHandler() { |
2559 | if ( !m_completed ) { |
2560 | m_resultCapture.handleIncomplete( m_assertionInfo ); |
2561 | } |
2562 | } |
2563 | |
2564 | template<typename T> |
2565 | void handleExpr( ExprLhs<T> const& expr ) { |
2566 | handleExpr( expr.makeUnaryExpr() ); |
2567 | } |
2568 | void handleExpr( ITransientExpression const& expr ); |
2569 | |
2570 | void handleMessage(ResultWas::OfType resultType, StringRef const& message); |
2571 | |
2572 | void handleExceptionThrownAsExpected(); |
2573 | void handleUnexpectedExceptionNotThrown(); |
2574 | void handleExceptionNotThrownAsExpected(); |
2575 | void handleThrowingCallSkipped(); |
2576 | void handleUnexpectedInflightException(); |
2577 | |
2578 | void complete(); |
2579 | void setCompleted(); |
2580 | |
2581 | // query |
2582 | auto allowThrows() const -> bool; |
2583 | }; |
2584 | |
2585 | void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef const& matcherString ); |
2586 | |
2587 | } // namespace Catch |
2588 | |
2589 | // end catch_assertionhandler.h |
2590 | // start catch_message.h |
2591 | |
2592 | #include <string> |
2593 | #include <vector> |
2594 | |
2595 | namespace Catch { |
2596 | |
2597 | struct MessageInfo { |
2598 | MessageInfo( StringRef const& _macroName, |
2599 | SourceLineInfo const& _lineInfo, |
2600 | ResultWas::OfType _type ); |
2601 | |
2602 | StringRef macroName; |
2603 | std::string message; |
2604 | SourceLineInfo lineInfo; |
2605 | ResultWas::OfType type; |
2606 | unsigned int sequence; |
2607 | |
2608 | bool operator == ( MessageInfo const& other ) const; |
2609 | bool operator < ( MessageInfo const& other ) const; |
2610 | private: |
2611 | static unsigned int globalCount; |
2612 | }; |
2613 | |
2614 | struct MessageStream { |
2615 | |
2616 | template<typename T> |
2617 | MessageStream& operator << ( T const& value ) { |
2618 | m_stream << value; |
2619 | return *this; |
2620 | } |
2621 | |
2622 | ReusableStringStream m_stream; |
2623 | }; |
2624 | |
2625 | struct MessageBuilder : MessageStream { |
2626 | MessageBuilder( StringRef const& macroName, |
2627 | SourceLineInfo const& lineInfo, |
2628 | ResultWas::OfType type ); |
2629 | |
2630 | template<typename T> |
2631 | MessageBuilder& operator << ( T const& value ) { |
2632 | m_stream << value; |
2633 | return *this; |
2634 | } |
2635 | |
2636 | MessageInfo m_info; |
2637 | }; |
2638 | |
2639 | class ScopedMessage { |
2640 | public: |
2641 | explicit ScopedMessage( MessageBuilder const& builder ); |
2642 | ScopedMessage( ScopedMessage& duplicate ) = delete; |
2643 | ScopedMessage( ScopedMessage&& old ); |
2644 | ~ScopedMessage(); |
2645 | |
2646 | MessageInfo m_info; |
2647 | bool m_moved; |
2648 | }; |
2649 | |
2650 | class Capturer { |
2651 | std::vector<MessageInfo> m_messages; |
2652 | IResultCapture& m_resultCapture = getResultCapture(); |
2653 | size_t m_captured = 0; |
2654 | public: |
2655 | Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ); |
2656 | ~Capturer(); |
2657 | |
2658 | void captureValue( size_t index, std::string const& value ); |
2659 | |
2660 | template<typename T> |
2661 | void captureValues( size_t index, T const& value ) { |
2662 | captureValue( index, Catch::Detail::stringify( value ) ); |
2663 | } |
2664 | |
2665 | template<typename T, typename... Ts> |
2666 | void captureValues( size_t index, T const& value, Ts const&... values ) { |
2667 | captureValue( index, Catch::Detail::stringify(value) ); |
2668 | captureValues( index+1, values... ); |
2669 | } |
2670 | }; |
2671 | |
2672 | } // end namespace Catch |
2673 | |
2674 | // end catch_message.h |
2675 | #if !defined(CATCH_CONFIG_DISABLE) |
2676 | |
2677 | #if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION) |
2678 | #define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__ |
2679 | #else |
2680 | #define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION" |
2681 | #endif |
2682 | |
2683 | #if defined(CATCH_CONFIG_FAST_COMPILE) || defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) |
2684 | |
2685 | /////////////////////////////////////////////////////////////////////////////// |
2686 | // Another way to speed-up compilation is to omit local try-catch for REQUIRE* |
2687 | // macros. |
2688 | #define INTERNAL_CATCH_TRY |
2689 | #define INTERNAL_CATCH_CATCH( capturer ) |
2690 | |
2691 | #else // CATCH_CONFIG_FAST_COMPILE |
2692 | |
2693 | #define INTERNAL_CATCH_TRY try |
2694 | #define INTERNAL_CATCH_CATCH( handler ) catch(...) { handler.handleUnexpectedInflightException(); } |
2695 | |
2696 | #endif |
2697 | |
2698 | #define INTERNAL_CATCH_REACT( handler ) handler.complete(); |
2699 | |
2700 | /////////////////////////////////////////////////////////////////////////////// |
2701 | #define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \ |
2702 | do { \ |
2703 | CATCH_INTERNAL_IGNORE_BUT_WARN(__VA_ARGS__); \ |
2704 | Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ |
2705 | INTERNAL_CATCH_TRY { \ |
2706 | CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ |
2707 | CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ |
2708 | catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); \ |
2709 | CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ |
2710 | } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ |
2711 | INTERNAL_CATCH_REACT( catchAssertionHandler ) \ |
2712 | } while( (void)0, (false) && static_cast<bool>( !!(__VA_ARGS__) ) ) |
2713 | |
2714 | /////////////////////////////////////////////////////////////////////////////// |
2715 | #define INTERNAL_CATCH_IF( macroName, resultDisposition, ... ) \ |
2716 | INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \ |
2717 | if( Catch::getResultCapture().lastAssertionPassed() ) |
2718 | |
2719 | /////////////////////////////////////////////////////////////////////////////// |
2720 | #define INTERNAL_CATCH_ELSE( macroName, resultDisposition, ... ) \ |
2721 | INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \ |
2722 | if( !Catch::getResultCapture().lastAssertionPassed() ) |
2723 | |
2724 | /////////////////////////////////////////////////////////////////////////////// |
2725 | #define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \ |
2726 | do { \ |
2727 | Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ |
2728 | try { \ |
2729 | static_cast<void>(__VA_ARGS__); \ |
2730 | catchAssertionHandler.handleExceptionNotThrownAsExpected(); \ |
2731 | } \ |
2732 | catch( ... ) { \ |
2733 | catchAssertionHandler.handleUnexpectedInflightException(); \ |
2734 | } \ |
2735 | INTERNAL_CATCH_REACT( catchAssertionHandler ) \ |
2736 | } while( false ) |
2737 | |
2738 | /////////////////////////////////////////////////////////////////////////////// |
2739 | #define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \ |
2740 | do { \ |
2741 | Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition); \ |
2742 | if( catchAssertionHandler.allowThrows() ) \ |
2743 | try { \ |
2744 | static_cast<void>(__VA_ARGS__); \ |
2745 | catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ |
2746 | } \ |
2747 | catch( ... ) { \ |
2748 | catchAssertionHandler.handleExceptionThrownAsExpected(); \ |
2749 | } \ |
2750 | else \ |
2751 | catchAssertionHandler.handleThrowingCallSkipped(); \ |
2752 | INTERNAL_CATCH_REACT( catchAssertionHandler ) \ |
2753 | } while( false ) |
2754 | |
2755 | /////////////////////////////////////////////////////////////////////////////// |
2756 | #define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \ |
2757 | do { \ |
2758 | Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \ |
2759 | if( catchAssertionHandler.allowThrows() ) \ |
2760 | try { \ |
2761 | static_cast<void>(expr); \ |
2762 | catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ |
2763 | } \ |
2764 | catch( exceptionType const& ) { \ |
2765 | catchAssertionHandler.handleExceptionThrownAsExpected(); \ |
2766 | } \ |
2767 | catch( ... ) { \ |
2768 | catchAssertionHandler.handleUnexpectedInflightException(); \ |
2769 | } \ |
2770 | else \ |
2771 | catchAssertionHandler.handleThrowingCallSkipped(); \ |
2772 | INTERNAL_CATCH_REACT( catchAssertionHandler ) \ |
2773 | } while( false ) |
2774 | |
2775 | /////////////////////////////////////////////////////////////////////////////// |
2776 | #define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \ |
2777 | do { \ |
2778 | Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::StringRef(), resultDisposition ); \ |
2779 | catchAssertionHandler.handleMessage( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \ |
2780 | INTERNAL_CATCH_REACT( catchAssertionHandler ) \ |
2781 | } while( false ) |
2782 | |
2783 | /////////////////////////////////////////////////////////////////////////////// |
2784 | #define INTERNAL_CATCH_CAPTURE( varName, macroName, ... ) \ |
2785 | auto varName = Catch::Capturer( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info, #__VA_ARGS__ ); \ |
2786 | varName.captureValues( 0, __VA_ARGS__ ) |
2787 | |
2788 | /////////////////////////////////////////////////////////////////////////////// |
2789 | #define INTERNAL_CATCH_INFO( macroName, log ) \ |
2790 | Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log ); |
2791 | |
2792 | /////////////////////////////////////////////////////////////////////////////// |
2793 | #define INTERNAL_CATCH_UNSCOPED_INFO( macroName, log ) \ |
2794 | Catch::getResultCapture().emplaceUnscopedMessage( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log ) |
2795 | |
2796 | /////////////////////////////////////////////////////////////////////////////// |
2797 | // Although this is matcher-based, it can be used with just a string |
2798 | #define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \ |
2799 | do { \ |
2800 | Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ |
2801 | if( catchAssertionHandler.allowThrows() ) \ |
2802 | try { \ |
2803 | static_cast<void>(__VA_ARGS__); \ |
2804 | catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ |
2805 | } \ |
2806 | catch( ... ) { \ |
2807 | Catch::handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher##_catch_sr ); \ |
2808 | } \ |
2809 | else \ |
2810 | catchAssertionHandler.handleThrowingCallSkipped(); \ |
2811 | INTERNAL_CATCH_REACT( catchAssertionHandler ) \ |
2812 | } while( false ) |
2813 | |
2814 | #endif // CATCH_CONFIG_DISABLE |
2815 | |
2816 | // end catch_capture.hpp |
2817 | // start catch_section.h |
2818 | |
2819 | // start catch_section_info.h |
2820 | |
2821 | // start catch_totals.h |
2822 | |
2823 | #include <cstddef> |
2824 | |
2825 | namespace Catch { |
2826 | |
2827 | struct Counts { |
2828 | Counts operator - ( Counts const& other ) const; |
2829 | Counts& operator += ( Counts const& other ); |
2830 | |
2831 | std::size_t total() const; |
2832 | bool allPassed() const; |
2833 | bool allOk() const; |
2834 | |
2835 | std::size_t passed = 0; |
2836 | std::size_t failed = 0; |
2837 | std::size_t failedButOk = 0; |
2838 | }; |
2839 | |
2840 | struct Totals { |
2841 | |
2842 | Totals operator - ( Totals const& other ) const; |
2843 | Totals& operator += ( Totals const& other ); |
2844 | |
2845 | Totals delta( Totals const& prevTotals ) const; |
2846 | |
2847 | int error = 0; |
2848 | Counts assertions; |
2849 | Counts testCases; |
2850 | }; |
2851 | } |
2852 | |
2853 | // end catch_totals.h |
2854 | #include <string> |
2855 | |
2856 | namespace Catch { |
2857 | |
2858 | struct SectionInfo { |
2859 | SectionInfo |
2860 | ( SourceLineInfo const& _lineInfo, |
2861 | std::string const& _name ); |
2862 | |
2863 | // Deprecated |
2864 | SectionInfo |
2865 | ( SourceLineInfo const& _lineInfo, |
2866 | std::string const& _name, |
2867 | std::string const& ) : SectionInfo( _lineInfo, _name ) {} |
2868 | |
2869 | std::string name; |
2870 | std::string description; // !Deprecated: this will always be empty |
2871 | SourceLineInfo lineInfo; |
2872 | }; |
2873 | |
2874 | struct SectionEndInfo { |
2875 | SectionInfo sectionInfo; |
2876 | Counts prevAssertions; |
2877 | double durationInSeconds; |
2878 | }; |
2879 | |
2880 | } // end namespace Catch |
2881 | |
2882 | // end catch_section_info.h |
2883 | // start catch_timer.h |
2884 | |
2885 | #include <cstdint> |
2886 | |
2887 | namespace Catch { |
2888 | |
2889 | auto getCurrentNanosecondsSinceEpoch() -> uint64_t; |
2890 | auto getEstimatedClockResolution() -> uint64_t; |
2891 | |
2892 | class Timer { |
2893 | uint64_t m_nanoseconds = 0; |
2894 | public: |
2895 | void start(); |
2896 | auto getElapsedNanoseconds() const -> uint64_t; |
2897 | auto getElapsedMicroseconds() const -> uint64_t; |
2898 | auto getElapsedMilliseconds() const -> unsigned int; |
2899 | auto getElapsedSeconds() const -> double; |
2900 | }; |
2901 | |
2902 | } // namespace Catch |
2903 | |
2904 | // end catch_timer.h |
2905 | #include <string> |
2906 | |
2907 | namespace Catch { |
2908 | |
2909 | class Section : NonCopyable { |
2910 | public: |
2911 | Section( SectionInfo const& info ); |
2912 | ~Section(); |
2913 | |
2914 | // This indicates whether the section should be executed or not |
2915 | explicit operator bool() const; |
2916 | |
2917 | private: |
2918 | SectionInfo m_info; |
2919 | |
2920 | std::string m_name; |
2921 | Counts m_assertions; |
2922 | bool m_sectionIncluded; |
2923 | Timer m_timer; |
2924 | }; |
2925 | |
2926 | } // end namespace Catch |
2927 | |
2928 | #define INTERNAL_CATCH_SECTION( ... ) \ |
2929 | CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ |
2930 | CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ |
2931 | if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \ |
2932 | CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION |
2933 | |
2934 | #define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \ |
2935 | CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ |
2936 | CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ |
2937 | if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, (Catch::ReusableStringStream() << __VA_ARGS__).str() ) ) \ |
2938 | CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION |
2939 | |
2940 | // end catch_section.h |
2941 | // start catch_interfaces_exception.h |
2942 | |
2943 | // start catch_interfaces_registry_hub.h |
2944 | |
2945 | #include <string> |
2946 | #include <memory> |
2947 | |
2948 | namespace Catch { |
2949 | |
2950 | class TestCase; |
2951 | struct ITestCaseRegistry; |
2952 | struct IExceptionTranslatorRegistry; |
2953 | struct IExceptionTranslator; |
2954 | struct IReporterRegistry; |
2955 | struct IReporterFactory; |
2956 | struct ITagAliasRegistry; |
2957 | struct IMutableEnumValuesRegistry; |
2958 | |
2959 | class StartupExceptionRegistry; |
2960 | |
2961 | using IReporterFactoryPtr = std::shared_ptr<IReporterFactory>; |
2962 | |
2963 | struct IRegistryHub { |
2964 | virtual ~IRegistryHub(); |
2965 | |
2966 | virtual IReporterRegistry const& getReporterRegistry() const = 0; |
2967 | virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; |
2968 | virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0; |
2969 | virtual IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const = 0; |
2970 | |
2971 | virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0; |
2972 | }; |
2973 | |
2974 | struct IMutableRegistryHub { |
2975 | virtual ~IMutableRegistryHub(); |
2976 | virtual void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) = 0; |
2977 | virtual void registerListener( IReporterFactoryPtr const& factory ) = 0; |
2978 | virtual void registerTest( TestCase const& testInfo ) = 0; |
2979 | virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; |
2980 | virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0; |
2981 | virtual void registerStartupException() noexcept = 0; |
2982 | virtual IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() = 0; |
2983 | }; |
2984 | |
2985 | IRegistryHub const& getRegistryHub(); |
2986 | IMutableRegistryHub& getMutableRegistryHub(); |
2987 | void cleanUp(); |
2988 | std::string translateActiveException(); |
2989 | |
2990 | } |
2991 | |
2992 | // end catch_interfaces_registry_hub.h |
2993 | #if defined(CATCH_CONFIG_DISABLE) |
2994 | #define INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( translatorName, signature) \ |
2995 | static std::string translatorName( signature ) |
2996 | #endif |
2997 | |
2998 | #include <exception> |
2999 | #include <string> |
3000 | #include <vector> |
3001 | |
3002 | namespace Catch { |
3003 | using exceptionTranslateFunction = std::string(*)(); |
3004 | |
3005 | struct IExceptionTranslator; |
3006 | using ExceptionTranslators = std::vector<std::unique_ptr<IExceptionTranslator const>>; |
3007 | |
3008 | struct IExceptionTranslator { |
3009 | virtual ~IExceptionTranslator(); |
3010 | virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0; |
3011 | }; |
3012 | |
3013 | struct IExceptionTranslatorRegistry { |
3014 | virtual ~IExceptionTranslatorRegistry(); |
3015 | |
3016 | virtual std::string translateActiveException() const = 0; |
3017 | }; |
3018 | |
3019 | class ExceptionTranslatorRegistrar { |
3020 | template<typename T> |
3021 | class ExceptionTranslator : public IExceptionTranslator { |
3022 | public: |
3023 | |
3024 | ExceptionTranslator( std::string(*translateFunction)( T& ) ) |
3025 | : m_translateFunction( translateFunction ) |
3026 | {} |
3027 | |
3028 | std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const override { |
3029 | #if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) |
3030 | return "" ; |
3031 | #else |
3032 | try { |
3033 | if( it == itEnd ) |
3034 | std::rethrow_exception(std::current_exception()); |
3035 | else |
3036 | return (*it)->translate( it+1, itEnd ); |
3037 | } |
3038 | catch( T& ex ) { |
3039 | return m_translateFunction( ex ); |
3040 | } |
3041 | #endif |
3042 | } |
3043 | |
3044 | protected: |
3045 | std::string(*m_translateFunction)( T& ); |
3046 | }; |
3047 | |
3048 | public: |
3049 | template<typename T> |
3050 | ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) { |
3051 | getMutableRegistryHub().registerTranslator |
3052 | ( new ExceptionTranslator<T>( translateFunction ) ); |
3053 | } |
3054 | }; |
3055 | } |
3056 | |
3057 | /////////////////////////////////////////////////////////////////////////////// |
3058 | #define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \ |
3059 | static std::string translatorName( signature ); \ |
3060 | CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ |
3061 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ |
3062 | namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); } \ |
3063 | CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ |
3064 | static std::string translatorName( signature ) |
3065 | |
3066 | #define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) |
3067 | |
3068 | // end catch_interfaces_exception.h |
3069 | // start catch_approx.h |
3070 | |
3071 | #include <type_traits> |
3072 | |
3073 | namespace Catch { |
3074 | namespace Detail { |
3075 | |
3076 | class Approx { |
3077 | private: |
3078 | bool equalityComparisonImpl(double other) const; |
3079 | // Validates the new margin (margin >= 0) |
3080 | // out-of-line to avoid including stdexcept in the header |
3081 | void setMargin(double margin); |
3082 | // Validates the new epsilon (0 < epsilon < 1) |
3083 | // out-of-line to avoid including stdexcept in the header |
3084 | void setEpsilon(double epsilon); |
3085 | |
3086 | public: |
3087 | explicit Approx ( double value ); |
3088 | |
3089 | static Approx custom(); |
3090 | |
3091 | Approx operator-() const; |
3092 | |
3093 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
3094 | Approx operator()( T const& value ) { |
3095 | Approx approx( static_cast<double>(value) ); |
3096 | approx.m_epsilon = m_epsilon; |
3097 | approx.m_margin = m_margin; |
3098 | approx.m_scale = m_scale; |
3099 | return approx; |
3100 | } |
3101 | |
3102 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
3103 | explicit Approx( T const& value ): Approx(static_cast<double>(value)) |
3104 | {} |
3105 | |
3106 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
3107 | friend bool operator == ( const T& lhs, Approx const& rhs ) { |
3108 | auto lhs_v = static_cast<double>(lhs); |
3109 | return rhs.equalityComparisonImpl(lhs_v); |
3110 | } |
3111 | |
3112 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
3113 | friend bool operator == ( Approx const& lhs, const T& rhs ) { |
3114 | return operator==( rhs, lhs ); |
3115 | } |
3116 | |
3117 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
3118 | friend bool operator != ( T const& lhs, Approx const& rhs ) { |
3119 | return !operator==( lhs, rhs ); |
3120 | } |
3121 | |
3122 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
3123 | friend bool operator != ( Approx const& lhs, T const& rhs ) { |
3124 | return !operator==( rhs, lhs ); |
3125 | } |
3126 | |
3127 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
3128 | friend bool operator <= ( T const& lhs, Approx const& rhs ) { |
3129 | return static_cast<double>(lhs) < rhs.m_value || lhs == rhs; |
3130 | } |
3131 | |
3132 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
3133 | friend bool operator <= ( Approx const& lhs, T const& rhs ) { |
3134 | return lhs.m_value < static_cast<double>(rhs) || lhs == rhs; |
3135 | } |
3136 | |
3137 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
3138 | friend bool operator >= ( T const& lhs, Approx const& rhs ) { |
3139 | return static_cast<double>(lhs) > rhs.m_value || lhs == rhs; |
3140 | } |
3141 | |
3142 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
3143 | friend bool operator >= ( Approx const& lhs, T const& rhs ) { |
3144 | return lhs.m_value > static_cast<double>(rhs) || lhs == rhs; |
3145 | } |
3146 | |
3147 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
3148 | Approx& epsilon( T const& newEpsilon ) { |
3149 | double epsilonAsDouble = static_cast<double>(newEpsilon); |
3150 | setEpsilon(epsilonAsDouble); |
3151 | return *this; |
3152 | } |
3153 | |
3154 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
3155 | Approx& margin( T const& newMargin ) { |
3156 | double marginAsDouble = static_cast<double>(newMargin); |
3157 | setMargin(marginAsDouble); |
3158 | return *this; |
3159 | } |
3160 | |
3161 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
3162 | Approx& scale( T const& newScale ) { |
3163 | m_scale = static_cast<double>(newScale); |
3164 | return *this; |
3165 | } |
3166 | |
3167 | std::string toString() const; |
3168 | |
3169 | private: |
3170 | double m_epsilon; |
3171 | double m_margin; |
3172 | double m_scale; |
3173 | double m_value; |
3174 | }; |
3175 | } // end namespace Detail |
3176 | |
3177 | namespace literals { |
3178 | Detail::Approx operator "" _a(long double val); |
3179 | Detail::Approx operator "" _a(unsigned long long val); |
3180 | } // end namespace literals |
3181 | |
3182 | template<> |
3183 | struct StringMaker<Catch::Detail::Approx> { |
3184 | static std::string convert(Catch::Detail::Approx const& value); |
3185 | }; |
3186 | |
3187 | } // end namespace Catch |
3188 | |
3189 | // end catch_approx.h |
3190 | // start catch_string_manip.h |
3191 | |
3192 | #include <string> |
3193 | #include <iosfwd> |
3194 | #include <vector> |
3195 | |
3196 | namespace Catch { |
3197 | |
3198 | bool startsWith( std::string const& s, std::string const& prefix ); |
3199 | bool startsWith( std::string const& s, char prefix ); |
3200 | bool endsWith( std::string const& s, std::string const& suffix ); |
3201 | bool endsWith( std::string const& s, char suffix ); |
3202 | bool contains( std::string const& s, std::string const& infix ); |
3203 | void toLowerInPlace( std::string& s ); |
3204 | std::string toLower( std::string const& s ); |
3205 | //! Returns a new string without whitespace at the start/end |
3206 | std::string trim( std::string const& str ); |
3207 | //! Returns a substring of the original ref without whitespace. Beware lifetimes! |
3208 | StringRef trim(StringRef ref); |
3209 | |
3210 | // !!! Be aware, returns refs into original string - make sure original string outlives them |
3211 | std::vector<StringRef> splitStringRef( StringRef str, char delimiter ); |
3212 | bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); |
3213 | |
3214 | struct pluralise { |
3215 | pluralise( std::size_t count, std::string const& label ); |
3216 | |
3217 | friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ); |
3218 | |
3219 | std::size_t m_count; |
3220 | std::string m_label; |
3221 | }; |
3222 | } |
3223 | |
3224 | // end catch_string_manip.h |
3225 | #ifndef CATCH_CONFIG_DISABLE_MATCHERS |
3226 | // start catch_capture_matchers.h |
3227 | |
3228 | // start catch_matchers.h |
3229 | |
3230 | #include <string> |
3231 | #include <vector> |
3232 | |
3233 | namespace Catch { |
3234 | namespace Matchers { |
3235 | namespace Impl { |
3236 | |
3237 | template<typename ArgT> struct MatchAllOf; |
3238 | template<typename ArgT> struct MatchAnyOf; |
3239 | template<typename ArgT> struct MatchNotOf; |
3240 | |
3241 | class MatcherUntypedBase { |
3242 | public: |
3243 | MatcherUntypedBase() = default; |
3244 | MatcherUntypedBase ( MatcherUntypedBase const& ) = default; |
3245 | MatcherUntypedBase& operator = ( MatcherUntypedBase const& ) = delete; |
3246 | std::string toString() const; |
3247 | |
3248 | protected: |
3249 | virtual ~MatcherUntypedBase(); |
3250 | virtual std::string describe() const = 0; |
3251 | mutable std::string m_cachedToString; |
3252 | }; |
3253 | |
3254 | #ifdef __clang__ |
3255 | # pragma clang diagnostic push |
3256 | # pragma clang diagnostic ignored "-Wnon-virtual-dtor" |
3257 | #endif |
3258 | |
3259 | template<typename ObjectT> |
3260 | struct MatcherMethod { |
3261 | virtual bool match( ObjectT const& arg ) const = 0; |
3262 | }; |
3263 | |
3264 | #if defined(__OBJC__) |
3265 | // Hack to fix Catch GH issue #1661. Could use id for generic Object support. |
3266 | // use of const for Object pointers is very uncommon and under ARC it causes some kind of signature mismatch that breaks compilation |
3267 | template<> |
3268 | struct MatcherMethod<NSString*> { |
3269 | virtual bool match( NSString* arg ) const = 0; |
3270 | }; |
3271 | #endif |
3272 | |
3273 | #ifdef __clang__ |
3274 | # pragma clang diagnostic pop |
3275 | #endif |
3276 | |
3277 | template<typename T> |
3278 | struct MatcherBase : MatcherUntypedBase, MatcherMethod<T> { |
3279 | |
3280 | MatchAllOf<T> operator && ( MatcherBase const& other ) const; |
3281 | MatchAnyOf<T> operator || ( MatcherBase const& other ) const; |
3282 | MatchNotOf<T> operator ! () const; |
3283 | }; |
3284 | |
3285 | template<typename ArgT> |
3286 | struct MatchAllOf : MatcherBase<ArgT> { |
3287 | bool match( ArgT const& arg ) const override { |
3288 | for( auto matcher : m_matchers ) { |
3289 | if (!matcher->match(arg)) |
3290 | return false; |
3291 | } |
3292 | return true; |
3293 | } |
3294 | std::string describe() const override { |
3295 | std::string description; |
3296 | description.reserve( 4 + m_matchers.size()*32 ); |
3297 | description += "( " ; |
3298 | bool first = true; |
3299 | for( auto matcher : m_matchers ) { |
3300 | if( first ) |
3301 | first = false; |
3302 | else |
3303 | description += " and " ; |
3304 | description += matcher->toString(); |
3305 | } |
3306 | description += " )" ; |
3307 | return description; |
3308 | } |
3309 | |
3310 | MatchAllOf<ArgT> operator && ( MatcherBase<ArgT> const& other ) { |
3311 | auto copy(*this); |
3312 | copy.m_matchers.push_back( &other ); |
3313 | return copy; |
3314 | } |
3315 | |
3316 | std::vector<MatcherBase<ArgT> const*> m_matchers; |
3317 | }; |
3318 | template<typename ArgT> |
3319 | struct MatchAnyOf : MatcherBase<ArgT> { |
3320 | |
3321 | bool match( ArgT const& arg ) const override { |
3322 | for( auto matcher : m_matchers ) { |
3323 | if (matcher->match(arg)) |
3324 | return true; |
3325 | } |
3326 | return false; |
3327 | } |
3328 | std::string describe() const override { |
3329 | std::string description; |
3330 | description.reserve( 4 + m_matchers.size()*32 ); |
3331 | description += "( " ; |
3332 | bool first = true; |
3333 | for( auto matcher : m_matchers ) { |
3334 | if( first ) |
3335 | first = false; |
3336 | else |
3337 | description += " or " ; |
3338 | description += matcher->toString(); |
3339 | } |
3340 | description += " )" ; |
3341 | return description; |
3342 | } |
3343 | |
3344 | MatchAnyOf<ArgT> operator || ( MatcherBase<ArgT> const& other ) { |
3345 | auto copy(*this); |
3346 | copy.m_matchers.push_back( &other ); |
3347 | return copy; |
3348 | } |
3349 | |
3350 | std::vector<MatcherBase<ArgT> const*> m_matchers; |
3351 | }; |
3352 | |
3353 | template<typename ArgT> |
3354 | struct MatchNotOf : MatcherBase<ArgT> { |
3355 | |
3356 | MatchNotOf( MatcherBase<ArgT> const& underlyingMatcher ) : m_underlyingMatcher( underlyingMatcher ) {} |
3357 | |
3358 | bool match( ArgT const& arg ) const override { |
3359 | return !m_underlyingMatcher.match( arg ); |
3360 | } |
3361 | |
3362 | std::string describe() const override { |
3363 | return "not " + m_underlyingMatcher.toString(); |
3364 | } |
3365 | MatcherBase<ArgT> const& m_underlyingMatcher; |
3366 | }; |
3367 | |
3368 | template<typename T> |
3369 | MatchAllOf<T> MatcherBase<T>::operator && ( MatcherBase const& other ) const { |
3370 | return MatchAllOf<T>() && *this && other; |
3371 | } |
3372 | template<typename T> |
3373 | MatchAnyOf<T> MatcherBase<T>::operator || ( MatcherBase const& other ) const { |
3374 | return MatchAnyOf<T>() || *this || other; |
3375 | } |
3376 | template<typename T> |
3377 | MatchNotOf<T> MatcherBase<T>::operator ! () const { |
3378 | return MatchNotOf<T>( *this ); |
3379 | } |
3380 | |
3381 | } // namespace Impl |
3382 | |
3383 | } // namespace Matchers |
3384 | |
3385 | using namespace Matchers; |
3386 | using Matchers::Impl::MatcherBase; |
3387 | |
3388 | } // namespace Catch |
3389 | |
3390 | // end catch_matchers.h |
3391 | // start catch_matchers_exception.hpp |
3392 | |
3393 | namespace Catch { |
3394 | namespace Matchers { |
3395 | namespace Exception { |
3396 | |
3397 | class ExceptionMessageMatcher : public MatcherBase<std::exception> { |
3398 | std::string m_message; |
3399 | public: |
3400 | |
3401 | ExceptionMessageMatcher(std::string const& message): |
3402 | m_message(message) |
3403 | {} |
3404 | |
3405 | bool match(std::exception const& ex) const override; |
3406 | |
3407 | std::string describe() const override; |
3408 | }; |
3409 | |
3410 | } // namespace Exception |
3411 | |
3412 | Exception::ExceptionMessageMatcher Message(std::string const& message); |
3413 | |
3414 | } // namespace Matchers |
3415 | } // namespace Catch |
3416 | |
3417 | // end catch_matchers_exception.hpp |
3418 | // start catch_matchers_floating.h |
3419 | |
3420 | namespace Catch { |
3421 | namespace Matchers { |
3422 | |
3423 | namespace Floating { |
3424 | |
3425 | enum class FloatingPointKind : uint8_t; |
3426 | |
3427 | struct WithinAbsMatcher : MatcherBase<double> { |
3428 | WithinAbsMatcher(double target, double margin); |
3429 | bool match(double const& matchee) const override; |
3430 | std::string describe() const override; |
3431 | private: |
3432 | double m_target; |
3433 | double m_margin; |
3434 | }; |
3435 | |
3436 | struct WithinUlpsMatcher : MatcherBase<double> { |
3437 | WithinUlpsMatcher(double target, uint64_t ulps, FloatingPointKind baseType); |
3438 | bool match(double const& matchee) const override; |
3439 | std::string describe() const override; |
3440 | private: |
3441 | double m_target; |
3442 | uint64_t m_ulps; |
3443 | FloatingPointKind m_type; |
3444 | }; |
3445 | |
3446 | // Given IEEE-754 format for floats and doubles, we can assume |
3447 | // that float -> double promotion is lossless. Given this, we can |
3448 | // assume that if we do the standard relative comparison of |
3449 | // |lhs - rhs| <= epsilon * max(fabs(lhs), fabs(rhs)), then we get |
3450 | // the same result if we do this for floats, as if we do this for |
3451 | // doubles that were promoted from floats. |
3452 | struct WithinRelMatcher : MatcherBase<double> { |
3453 | WithinRelMatcher(double target, double epsilon); |
3454 | bool match(double const& matchee) const override; |
3455 | std::string describe() const override; |
3456 | private: |
3457 | double m_target; |
3458 | double m_epsilon; |
3459 | }; |
3460 | |
3461 | } // namespace Floating |
3462 | |
3463 | // The following functions create the actual matcher objects. |
3464 | // This allows the types to be inferred |
3465 | Floating::WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff); |
3466 | Floating::WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff); |
3467 | Floating::WithinAbsMatcher WithinAbs(double target, double margin); |
3468 | Floating::WithinRelMatcher WithinRel(double target, double eps); |
3469 | // defaults epsilon to 100*numeric_limits<double>::epsilon() |
3470 | Floating::WithinRelMatcher WithinRel(double target); |
3471 | Floating::WithinRelMatcher WithinRel(float target, float eps); |
3472 | // defaults epsilon to 100*numeric_limits<float>::epsilon() |
3473 | Floating::WithinRelMatcher WithinRel(float target); |
3474 | |
3475 | } // namespace Matchers |
3476 | } // namespace Catch |
3477 | |
3478 | // end catch_matchers_floating.h |
3479 | // start catch_matchers_generic.hpp |
3480 | |
3481 | #include <functional> |
3482 | #include <string> |
3483 | |
3484 | namespace Catch { |
3485 | namespace Matchers { |
3486 | namespace Generic { |
3487 | |
3488 | namespace Detail { |
3489 | std::string finalizeDescription(const std::string& desc); |
3490 | } |
3491 | |
3492 | template <typename T> |
3493 | class PredicateMatcher : public MatcherBase<T> { |
3494 | std::function<bool(T const&)> m_predicate; |
3495 | std::string m_description; |
3496 | public: |
3497 | |
3498 | PredicateMatcher(std::function<bool(T const&)> const& elem, std::string const& descr) |
3499 | :m_predicate(std::move(elem)), |
3500 | m_description(Detail::finalizeDescription(descr)) |
3501 | {} |
3502 | |
3503 | bool match( T const& item ) const override { |
3504 | return m_predicate(item); |
3505 | } |
3506 | |
3507 | std::string describe() const override { |
3508 | return m_description; |
3509 | } |
3510 | }; |
3511 | |
3512 | } // namespace Generic |
3513 | |
3514 | // The following functions create the actual matcher objects. |
3515 | // The user has to explicitly specify type to the function, because |
3516 | // inferring std::function<bool(T const&)> is hard (but possible) and |
3517 | // requires a lot of TMP. |
3518 | template<typename T> |
3519 | Generic::PredicateMatcher<T> Predicate(std::function<bool(T const&)> const& predicate, std::string const& description = "" ) { |
3520 | return Generic::PredicateMatcher<T>(predicate, description); |
3521 | } |
3522 | |
3523 | } // namespace Matchers |
3524 | } // namespace Catch |
3525 | |
3526 | // end catch_matchers_generic.hpp |
3527 | // start catch_matchers_string.h |
3528 | |
3529 | #include <string> |
3530 | |
3531 | namespace Catch { |
3532 | namespace Matchers { |
3533 | |
3534 | namespace StdString { |
3535 | |
3536 | struct CasedString |
3537 | { |
3538 | CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ); |
3539 | std::string adjustString( std::string const& str ) const; |
3540 | std::string caseSensitivitySuffix() const; |
3541 | |
3542 | CaseSensitive::Choice m_caseSensitivity; |
3543 | std::string m_str; |
3544 | }; |
3545 | |
3546 | struct StringMatcherBase : MatcherBase<std::string> { |
3547 | StringMatcherBase( std::string const& operation, CasedString const& comparator ); |
3548 | std::string describe() const override; |
3549 | |
3550 | CasedString m_comparator; |
3551 | std::string m_operation; |
3552 | }; |
3553 | |
3554 | struct EqualsMatcher : StringMatcherBase { |
3555 | EqualsMatcher( CasedString const& comparator ); |
3556 | bool match( std::string const& source ) const override; |
3557 | }; |
3558 | struct ContainsMatcher : StringMatcherBase { |
3559 | ContainsMatcher( CasedString const& comparator ); |
3560 | bool match( std::string const& source ) const override; |
3561 | }; |
3562 | struct StartsWithMatcher : StringMatcherBase { |
3563 | StartsWithMatcher( CasedString const& comparator ); |
3564 | bool match( std::string const& source ) const override; |
3565 | }; |
3566 | struct EndsWithMatcher : StringMatcherBase { |
3567 | EndsWithMatcher( CasedString const& comparator ); |
3568 | bool match( std::string const& source ) const override; |
3569 | }; |
3570 | |
3571 | struct RegexMatcher : MatcherBase<std::string> { |
3572 | RegexMatcher( std::string regex, CaseSensitive::Choice caseSensitivity ); |
3573 | bool match( std::string const& matchee ) const override; |
3574 | std::string describe() const override; |
3575 | |
3576 | private: |
3577 | std::string m_regex; |
3578 | CaseSensitive::Choice m_caseSensitivity; |
3579 | }; |
3580 | |
3581 | } // namespace StdString |
3582 | |
3583 | // The following functions create the actual matcher objects. |
3584 | // This allows the types to be inferred |
3585 | |
3586 | StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); |
3587 | StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); |
3588 | StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); |
3589 | StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); |
3590 | StdString::RegexMatcher Matches( std::string const& regex, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); |
3591 | |
3592 | } // namespace Matchers |
3593 | } // namespace Catch |
3594 | |
3595 | // end catch_matchers_string.h |
3596 | // start catch_matchers_vector.h |
3597 | |
3598 | #include <algorithm> |
3599 | |
3600 | namespace Catch { |
3601 | namespace Matchers { |
3602 | |
3603 | namespace Vector { |
3604 | template<typename T, typename Alloc> |
3605 | struct ContainsElementMatcher : MatcherBase<std::vector<T, Alloc>> { |
3606 | |
3607 | ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {} |
3608 | |
3609 | bool match(std::vector<T, Alloc> const &v) const override { |
3610 | for (auto const& el : v) { |
3611 | if (el == m_comparator) { |
3612 | return true; |
3613 | } |
3614 | } |
3615 | return false; |
3616 | } |
3617 | |
3618 | std::string describe() const override { |
3619 | return "Contains: " + ::Catch::Detail::stringify( m_comparator ); |
3620 | } |
3621 | |
3622 | T const& m_comparator; |
3623 | }; |
3624 | |
3625 | template<typename T, typename AllocComp, typename AllocMatch> |
3626 | struct ContainsMatcher : MatcherBase<std::vector<T, AllocMatch>> { |
3627 | |
3628 | ContainsMatcher(std::vector<T, AllocComp> const &comparator) : m_comparator( comparator ) {} |
3629 | |
3630 | bool match(std::vector<T, AllocMatch> const &v) const override { |
3631 | // !TBD: see note in EqualsMatcher |
3632 | if (m_comparator.size() > v.size()) |
3633 | return false; |
3634 | for (auto const& comparator : m_comparator) { |
3635 | auto present = false; |
3636 | for (const auto& el : v) { |
3637 | if (el == comparator) { |
3638 | present = true; |
3639 | break; |
3640 | } |
3641 | } |
3642 | if (!present) { |
3643 | return false; |
3644 | } |
3645 | } |
3646 | return true; |
3647 | } |
3648 | std::string describe() const override { |
3649 | return "Contains: " + ::Catch::Detail::stringify( m_comparator ); |
3650 | } |
3651 | |
3652 | std::vector<T, AllocComp> const& m_comparator; |
3653 | }; |
3654 | |
3655 | template<typename T, typename AllocComp, typename AllocMatch> |
3656 | struct EqualsMatcher : MatcherBase<std::vector<T, AllocMatch>> { |
3657 | |
3658 | EqualsMatcher(std::vector<T, AllocComp> const &comparator) : m_comparator( comparator ) {} |
3659 | |
3660 | bool match(std::vector<T, AllocMatch> const &v) const override { |
3661 | // !TBD: This currently works if all elements can be compared using != |
3662 | // - a more general approach would be via a compare template that defaults |
3663 | // to using !=. but could be specialised for, e.g. std::vector<T, Alloc> etc |
3664 | // - then just call that directly |
3665 | if (m_comparator.size() != v.size()) |
3666 | return false; |
3667 | for (std::size_t i = 0; i < v.size(); ++i) |
3668 | if (m_comparator[i] != v[i]) |
3669 | return false; |
3670 | return true; |
3671 | } |
3672 | std::string describe() const override { |
3673 | return "Equals: " + ::Catch::Detail::stringify( m_comparator ); |
3674 | } |
3675 | std::vector<T, AllocComp> const& m_comparator; |
3676 | }; |
3677 | |
3678 | template<typename T, typename AllocComp, typename AllocMatch> |
3679 | struct ApproxMatcher : MatcherBase<std::vector<T, AllocMatch>> { |
3680 | |
3681 | ApproxMatcher(std::vector<T, AllocComp> const& comparator) : m_comparator( comparator ) {} |
3682 | |
3683 | bool match(std::vector<T, AllocMatch> const &v) const override { |
3684 | if (m_comparator.size() != v.size()) |
3685 | return false; |
3686 | for (std::size_t i = 0; i < v.size(); ++i) |
3687 | if (m_comparator[i] != approx(v[i])) |
3688 | return false; |
3689 | return true; |
3690 | } |
3691 | std::string describe() const override { |
3692 | return "is approx: " + ::Catch::Detail::stringify( m_comparator ); |
3693 | } |
3694 | template <typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
3695 | ApproxMatcher& epsilon( T const& newEpsilon ) { |
3696 | approx.epsilon(newEpsilon); |
3697 | return *this; |
3698 | } |
3699 | template <typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
3700 | ApproxMatcher& margin( T const& newMargin ) { |
3701 | approx.margin(newMargin); |
3702 | return *this; |
3703 | } |
3704 | template <typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
3705 | ApproxMatcher& scale( T const& newScale ) { |
3706 | approx.scale(newScale); |
3707 | return *this; |
3708 | } |
3709 | |
3710 | std::vector<T, AllocComp> const& m_comparator; |
3711 | mutable Catch::Detail::Approx approx = Catch::Detail::Approx::custom(); |
3712 | }; |
3713 | |
3714 | template<typename T, typename AllocComp, typename AllocMatch> |
3715 | struct UnorderedEqualsMatcher : MatcherBase<std::vector<T, AllocMatch>> { |
3716 | UnorderedEqualsMatcher(std::vector<T, AllocComp> const& target) : m_target(target) {} |
3717 | bool match(std::vector<T, AllocMatch> const& vec) const override { |
3718 | if (m_target.size() != vec.size()) { |
3719 | return false; |
3720 | } |
3721 | return std::is_permutation(m_target.begin(), m_target.end(), vec.begin()); |
3722 | } |
3723 | |
3724 | std::string describe() const override { |
3725 | return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target); |
3726 | } |
3727 | private: |
3728 | std::vector<T, AllocComp> const& m_target; |
3729 | }; |
3730 | |
3731 | } // namespace Vector |
3732 | |
3733 | // The following functions create the actual matcher objects. |
3734 | // This allows the types to be inferred |
3735 | |
3736 | template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp> |
3737 | Vector::ContainsMatcher<T, AllocComp, AllocMatch> Contains( std::vector<T, AllocComp> const& comparator ) { |
3738 | return Vector::ContainsMatcher<T, AllocComp, AllocMatch>( comparator ); |
3739 | } |
3740 | |
3741 | template<typename T, typename Alloc = std::allocator<T>> |
3742 | Vector::ContainsElementMatcher<T, Alloc> VectorContains( T const& comparator ) { |
3743 | return Vector::ContainsElementMatcher<T, Alloc>( comparator ); |
3744 | } |
3745 | |
3746 | template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp> |
3747 | Vector::EqualsMatcher<T, AllocComp, AllocMatch> Equals( std::vector<T, AllocComp> const& comparator ) { |
3748 | return Vector::EqualsMatcher<T, AllocComp, AllocMatch>( comparator ); |
3749 | } |
3750 | |
3751 | template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp> |
3752 | Vector::ApproxMatcher<T, AllocComp, AllocMatch> Approx( std::vector<T, AllocComp> const& comparator ) { |
3753 | return Vector::ApproxMatcher<T, AllocComp, AllocMatch>( comparator ); |
3754 | } |
3755 | |
3756 | template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp> |
3757 | Vector::UnorderedEqualsMatcher<T, AllocComp, AllocMatch> UnorderedEquals(std::vector<T, AllocComp> const& target) { |
3758 | return Vector::UnorderedEqualsMatcher<T, AllocComp, AllocMatch>( target ); |
3759 | } |
3760 | |
3761 | } // namespace Matchers |
3762 | } // namespace Catch |
3763 | |
3764 | // end catch_matchers_vector.h |
3765 | namespace Catch { |
3766 | |
3767 | template<typename ArgT, typename MatcherT> |
3768 | class MatchExpr : public ITransientExpression { |
3769 | ArgT const& m_arg; |
3770 | MatcherT m_matcher; |
3771 | StringRef m_matcherString; |
3772 | public: |
3773 | MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef const& matcherString ) |
3774 | : ITransientExpression{ true, matcher.match( arg ) }, |
3775 | m_arg( arg ), |
3776 | m_matcher( matcher ), |
3777 | m_matcherString( matcherString ) |
3778 | {} |
3779 | |
3780 | void streamReconstructedExpression( std::ostream &os ) const override { |
3781 | auto matcherAsString = m_matcher.toString(); |
3782 | os << Catch::Detail::stringify( m_arg ) << ' '; |
3783 | if( matcherAsString == Detail::unprintableString ) |
3784 | os << m_matcherString; |
3785 | else |
3786 | os << matcherAsString; |
3787 | } |
3788 | }; |
3789 | |
3790 | using StringMatcher = Matchers::Impl::MatcherBase<std::string>; |
3791 | |
3792 | void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString ); |
3793 | |
3794 | template<typename ArgT, typename MatcherT> |
3795 | auto makeMatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef const& matcherString ) -> MatchExpr<ArgT, MatcherT> { |
3796 | return MatchExpr<ArgT, MatcherT>( arg, matcher, matcherString ); |
3797 | } |
3798 | |
3799 | } // namespace Catch |
3800 | |
3801 | /////////////////////////////////////////////////////////////////////////////// |
3802 | #define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \ |
3803 | do { \ |
3804 | Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ |
3805 | INTERNAL_CATCH_TRY { \ |
3806 | catchAssertionHandler.handleExpr( Catch::makeMatchExpr( arg, matcher, #matcher##_catch_sr ) ); \ |
3807 | } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ |
3808 | INTERNAL_CATCH_REACT( catchAssertionHandler ) \ |
3809 | } while( false ) |
3810 | |
3811 | /////////////////////////////////////////////////////////////////////////////// |
3812 | #define INTERNAL_CATCH_THROWS_MATCHES( macroName, exceptionType, resultDisposition, matcher, ... ) \ |
3813 | do { \ |
3814 | Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(exceptionType) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ |
3815 | if( catchAssertionHandler.allowThrows() ) \ |
3816 | try { \ |
3817 | static_cast<void>(__VA_ARGS__ ); \ |
3818 | catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ |
3819 | } \ |
3820 | catch( exceptionType const& ex ) { \ |
3821 | catchAssertionHandler.handleExpr( Catch::makeMatchExpr( ex, matcher, #matcher##_catch_sr ) ); \ |
3822 | } \ |
3823 | catch( ... ) { \ |
3824 | catchAssertionHandler.handleUnexpectedInflightException(); \ |
3825 | } \ |
3826 | else \ |
3827 | catchAssertionHandler.handleThrowingCallSkipped(); \ |
3828 | INTERNAL_CATCH_REACT( catchAssertionHandler ) \ |
3829 | } while( false ) |
3830 | |
3831 | // end catch_capture_matchers.h |
3832 | #endif |
3833 | // start catch_generators.hpp |
3834 | |
3835 | // start catch_interfaces_generatortracker.h |
3836 | |
3837 | |
3838 | #include <memory> |
3839 | |
3840 | namespace Catch { |
3841 | |
3842 | namespace Generators { |
3843 | class GeneratorUntypedBase { |
3844 | public: |
3845 | GeneratorUntypedBase() = default; |
3846 | virtual ~GeneratorUntypedBase(); |
3847 | // Attempts to move the generator to the next element |
3848 | // |
3849 | // Returns true iff the move succeeded (and a valid element |
3850 | // can be retrieved). |
3851 | virtual bool next() = 0; |
3852 | }; |
3853 | using GeneratorBasePtr = std::unique_ptr<GeneratorUntypedBase>; |
3854 | |
3855 | } // namespace Generators |
3856 | |
3857 | struct IGeneratorTracker { |
3858 | virtual ~IGeneratorTracker(); |
3859 | virtual auto hasGenerator() const -> bool = 0; |
3860 | virtual auto getGenerator() const -> Generators::GeneratorBasePtr const& = 0; |
3861 | virtual void setGenerator( Generators::GeneratorBasePtr&& generator ) = 0; |
3862 | }; |
3863 | |
3864 | } // namespace Catch |
3865 | |
3866 | // end catch_interfaces_generatortracker.h |
3867 | // start catch_enforce.h |
3868 | |
3869 | #include <exception> |
3870 | |
3871 | namespace Catch { |
3872 | #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) |
3873 | template <typename Ex> |
3874 | [[noreturn]] |
3875 | void throw_exception(Ex const& e) { |
3876 | throw e; |
3877 | } |
3878 | #else // ^^ Exceptions are enabled // Exceptions are disabled vv |
3879 | [[noreturn]] |
3880 | void throw_exception(std::exception const& e); |
3881 | #endif |
3882 | |
3883 | [[noreturn]] |
3884 | void throw_logic_error(std::string const& msg); |
3885 | [[noreturn]] |
3886 | void throw_domain_error(std::string const& msg); |
3887 | [[noreturn]] |
3888 | void throw_runtime_error(std::string const& msg); |
3889 | |
3890 | } // namespace Catch; |
3891 | |
3892 | #define CATCH_MAKE_MSG(...) \ |
3893 | (Catch::ReusableStringStream() << __VA_ARGS__).str() |
3894 | |
3895 | #define CATCH_INTERNAL_ERROR(...) \ |
3896 | Catch::throw_logic_error(CATCH_MAKE_MSG( CATCH_INTERNAL_LINEINFO << ": Internal Catch2 error: " << __VA_ARGS__)) |
3897 | |
3898 | #define CATCH_ERROR(...) \ |
3899 | Catch::throw_domain_error(CATCH_MAKE_MSG( __VA_ARGS__ )) |
3900 | |
3901 | #define CATCH_RUNTIME_ERROR(...) \ |
3902 | Catch::throw_runtime_error(CATCH_MAKE_MSG( __VA_ARGS__ )) |
3903 | |
3904 | #define CATCH_ENFORCE( condition, ... ) \ |
3905 | do{ if( !(condition) ) CATCH_ERROR( __VA_ARGS__ ); } while(false) |
3906 | |
3907 | // end catch_enforce.h |
3908 | #include <memory> |
3909 | #include <vector> |
3910 | #include <cassert> |
3911 | |
3912 | #include <utility> |
3913 | #include <exception> |
3914 | |
3915 | namespace Catch { |
3916 | |
3917 | class GeneratorException : public std::exception { |
3918 | const char* const m_msg = "" ; |
3919 | |
3920 | public: |
3921 | GeneratorException(const char* msg): |
3922 | m_msg(msg) |
3923 | {} |
3924 | |
3925 | const char* what() const noexcept override final; |
3926 | }; |
3927 | |
3928 | namespace Generators { |
3929 | |
3930 | // !TBD move this into its own location? |
3931 | namespace pf{ |
3932 | template<typename T, typename... Args> |
3933 | std::unique_ptr<T> make_unique( Args&&... args ) { |
3934 | return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); |
3935 | } |
3936 | } |
3937 | |
3938 | template<typename T> |
3939 | struct IGenerator : GeneratorUntypedBase { |
3940 | virtual ~IGenerator() = default; |
3941 | |
3942 | // Returns the current element of the generator |
3943 | // |
3944 | // \Precondition The generator is either freshly constructed, |
3945 | // or the last call to `next()` returned true |
3946 | virtual T const& get() const = 0; |
3947 | using type = T; |
3948 | }; |
3949 | |
3950 | template<typename T> |
3951 | class SingleValueGenerator final : public IGenerator<T> { |
3952 | T m_value; |
3953 | public: |
3954 | SingleValueGenerator(T&& value) : m_value(std::move(value)) {} |
3955 | |
3956 | T const& get() const override { |
3957 | return m_value; |
3958 | } |
3959 | bool next() override { |
3960 | return false; |
3961 | } |
3962 | }; |
3963 | |
3964 | template<typename T> |
3965 | class FixedValuesGenerator final : public IGenerator<T> { |
3966 | static_assert(!std::is_same<T, bool>::value, |
3967 | "FixedValuesGenerator does not support bools because of std::vector<bool>" |
3968 | "specialization, use SingleValue Generator instead." ); |
3969 | std::vector<T> m_values; |
3970 | size_t m_idx = 0; |
3971 | public: |
3972 | FixedValuesGenerator( std::initializer_list<T> values ) : m_values( values ) {} |
3973 | |
3974 | T const& get() const override { |
3975 | return m_values[m_idx]; |
3976 | } |
3977 | bool next() override { |
3978 | ++m_idx; |
3979 | return m_idx < m_values.size(); |
3980 | } |
3981 | }; |
3982 | |
3983 | template <typename T> |
3984 | class GeneratorWrapper final { |
3985 | std::unique_ptr<IGenerator<T>> m_generator; |
3986 | public: |
3987 | GeneratorWrapper(std::unique_ptr<IGenerator<T>> generator): |
3988 | m_generator(std::move(generator)) |
3989 | {} |
3990 | T const& get() const { |
3991 | return m_generator->get(); |
3992 | } |
3993 | bool next() { |
3994 | return m_generator->next(); |
3995 | } |
3996 | }; |
3997 | |
3998 | template <typename T> |
3999 | GeneratorWrapper<T> value(T&& value) { |
4000 | return GeneratorWrapper<T>(pf::make_unique<SingleValueGenerator<T>>(std::forward<T>(value))); |
4001 | } |
4002 | template <typename T> |
4003 | GeneratorWrapper<T> values(std::initializer_list<T> values) { |
4004 | return GeneratorWrapper<T>(pf::make_unique<FixedValuesGenerator<T>>(values)); |
4005 | } |
4006 | |
4007 | template<typename T> |
4008 | class Generators : public IGenerator<T> { |
4009 | std::vector<GeneratorWrapper<T>> m_generators; |
4010 | size_t m_current = 0; |
4011 | |
4012 | void populate(GeneratorWrapper<T>&& generator) { |
4013 | m_generators.emplace_back(std::move(generator)); |
4014 | } |
4015 | void populate(T&& val) { |
4016 | m_generators.emplace_back(value(std::forward<T>(val))); |
4017 | } |
4018 | template<typename U> |
4019 | void populate(U&& val) { |
4020 | populate(T(std::forward<U>(val))); |
4021 | } |
4022 | template<typename U, typename... Gs> |
4023 | void populate(U&& valueOrGenerator, Gs &&... moreGenerators) { |
4024 | populate(std::forward<U>(valueOrGenerator)); |
4025 | populate(std::forward<Gs>(moreGenerators)...); |
4026 | } |
4027 | |
4028 | public: |
4029 | template <typename... Gs> |
4030 | Generators(Gs &&... moreGenerators) { |
4031 | m_generators.reserve(sizeof...(Gs)); |
4032 | populate(std::forward<Gs>(moreGenerators)...); |
4033 | } |
4034 | |
4035 | T const& get() const override { |
4036 | return m_generators[m_current].get(); |
4037 | } |
4038 | |
4039 | bool next() override { |
4040 | if (m_current >= m_generators.size()) { |
4041 | return false; |
4042 | } |
4043 | const bool current_status = m_generators[m_current].next(); |
4044 | if (!current_status) { |
4045 | ++m_current; |
4046 | } |
4047 | return m_current < m_generators.size(); |
4048 | } |
4049 | }; |
4050 | |
4051 | template<typename... Ts> |
4052 | GeneratorWrapper<std::tuple<Ts...>> table( std::initializer_list<std::tuple<typename std::decay<Ts>::type...>> tuples ) { |
4053 | return values<std::tuple<Ts...>>( tuples ); |
4054 | } |
4055 | |
4056 | // Tag type to signal that a generator sequence should convert arguments to a specific type |
4057 | template <typename T> |
4058 | struct as {}; |
4059 | |
4060 | template<typename T, typename... Gs> |
4061 | auto makeGenerators( GeneratorWrapper<T>&& generator, Gs &&... moreGenerators ) -> Generators<T> { |
4062 | return Generators<T>(std::move(generator), std::forward<Gs>(moreGenerators)...); |
4063 | } |
4064 | template<typename T> |
4065 | auto makeGenerators( GeneratorWrapper<T>&& generator ) -> Generators<T> { |
4066 | return Generators<T>(std::move(generator)); |
4067 | } |
4068 | template<typename T, typename... Gs> |
4069 | auto makeGenerators( T&& val, Gs &&... moreGenerators ) -> Generators<T> { |
4070 | return makeGenerators( value( std::forward<T>( val ) ), std::forward<Gs>( moreGenerators )... ); |
4071 | } |
4072 | template<typename T, typename U, typename... Gs> |
4073 | auto makeGenerators( as<T>, U&& val, Gs &&... moreGenerators ) -> Generators<T> { |
4074 | return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... ); |
4075 | } |
4076 | |
4077 | auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker&; |
4078 | |
4079 | template<typename L> |
4080 | // Note: The type after -> is weird, because VS2015 cannot parse |
4081 | // the expression used in the typedef inside, when it is in |
4082 | // return type. Yeah. |
4083 | auto generate( StringRef generatorName, SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>().get()) { |
4084 | using UnderlyingType = typename decltype(generatorExpression())::type; |
4085 | |
4086 | IGeneratorTracker& tracker = acquireGeneratorTracker( generatorName, lineInfo ); |
4087 | if (!tracker.hasGenerator()) { |
4088 | tracker.setGenerator(pf::make_unique<Generators<UnderlyingType>>(generatorExpression())); |
4089 | } |
4090 | |
4091 | auto const& generator = static_cast<IGenerator<UnderlyingType> const&>( *tracker.getGenerator() ); |
4092 | return generator.get(); |
4093 | } |
4094 | |
4095 | } // namespace Generators |
4096 | } // namespace Catch |
4097 | |
4098 | #define GENERATE( ... ) \ |
4099 | Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \ |
4100 | CATCH_INTERNAL_LINEINFO, \ |
4101 | [ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace) |
4102 | #define GENERATE_COPY( ... ) \ |
4103 | Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \ |
4104 | CATCH_INTERNAL_LINEINFO, \ |
4105 | [=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace) |
4106 | #define GENERATE_REF( ... ) \ |
4107 | Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \ |
4108 | CATCH_INTERNAL_LINEINFO, \ |
4109 | [&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace) |
4110 | |
4111 | // end catch_generators.hpp |
4112 | // start catch_generators_generic.hpp |
4113 | |
4114 | namespace Catch { |
4115 | namespace Generators { |
4116 | |
4117 | template <typename T> |
4118 | class TakeGenerator : public IGenerator<T> { |
4119 | GeneratorWrapper<T> m_generator; |
4120 | size_t m_returned = 0; |
4121 | size_t m_target; |
4122 | public: |
4123 | TakeGenerator(size_t target, GeneratorWrapper<T>&& generator): |
4124 | m_generator(std::move(generator)), |
4125 | m_target(target) |
4126 | { |
4127 | assert(target != 0 && "Empty generators are not allowed" ); |
4128 | } |
4129 | T const& get() const override { |
4130 | return m_generator.get(); |
4131 | } |
4132 | bool next() override { |
4133 | ++m_returned; |
4134 | if (m_returned >= m_target) { |
4135 | return false; |
4136 | } |
4137 | |
4138 | const auto success = m_generator.next(); |
4139 | // If the underlying generator does not contain enough values |
4140 | // then we cut short as well |
4141 | if (!success) { |
4142 | m_returned = m_target; |
4143 | } |
4144 | return success; |
4145 | } |
4146 | }; |
4147 | |
4148 | template <typename T> |
4149 | GeneratorWrapper<T> take(size_t target, GeneratorWrapper<T>&& generator) { |
4150 | return GeneratorWrapper<T>(pf::make_unique<TakeGenerator<T>>(target, std::move(generator))); |
4151 | } |
4152 | |
4153 | template <typename T, typename Predicate> |
4154 | class FilterGenerator : public IGenerator<T> { |
4155 | GeneratorWrapper<T> m_generator; |
4156 | Predicate m_predicate; |
4157 | public: |
4158 | template <typename P = Predicate> |
4159 | FilterGenerator(P&& pred, GeneratorWrapper<T>&& generator): |
4160 | m_generator(std::move(generator)), |
4161 | m_predicate(std::forward<P>(pred)) |
4162 | { |
4163 | if (!m_predicate(m_generator.get())) { |
4164 | // It might happen that there are no values that pass the |
4165 | // filter. In that case we throw an exception. |
4166 | auto has_initial_value = next(); |
4167 | if (!has_initial_value) { |
4168 | Catch::throw_exception(GeneratorException("No valid value found in filtered generator" )); |
4169 | } |
4170 | } |
4171 | } |
4172 | |
4173 | T const& get() const override { |
4174 | return m_generator.get(); |
4175 | } |
4176 | |
4177 | bool next() override { |
4178 | bool success = m_generator.next(); |
4179 | if (!success) { |
4180 | return false; |
4181 | } |
4182 | while (!m_predicate(m_generator.get()) && (success = m_generator.next()) == true); |
4183 | return success; |
4184 | } |
4185 | }; |
4186 | |
4187 | template <typename T, typename Predicate> |
4188 | GeneratorWrapper<T> filter(Predicate&& pred, GeneratorWrapper<T>&& generator) { |
4189 | return GeneratorWrapper<T>(std::unique_ptr<IGenerator<T>>(pf::make_unique<FilterGenerator<T, Predicate>>(std::forward<Predicate>(pred), std::move(generator)))); |
4190 | } |
4191 | |
4192 | template <typename T> |
4193 | class RepeatGenerator : public IGenerator<T> { |
4194 | static_assert(!std::is_same<T, bool>::value, |
4195 | "RepeatGenerator currently does not support bools" |
4196 | "because of std::vector<bool> specialization" ); |
4197 | GeneratorWrapper<T> m_generator; |
4198 | mutable std::vector<T> m_returned; |
4199 | size_t m_target_repeats; |
4200 | size_t m_current_repeat = 0; |
4201 | size_t m_repeat_index = 0; |
4202 | public: |
4203 | RepeatGenerator(size_t repeats, GeneratorWrapper<T>&& generator): |
4204 | m_generator(std::move(generator)), |
4205 | m_target_repeats(repeats) |
4206 | { |
4207 | assert(m_target_repeats > 0 && "Repeat generator must repeat at least once" ); |
4208 | } |
4209 | |
4210 | T const& get() const override { |
4211 | if (m_current_repeat == 0) { |
4212 | m_returned.push_back(m_generator.get()); |
4213 | return m_returned.back(); |
4214 | } |
4215 | return m_returned[m_repeat_index]; |
4216 | } |
4217 | |
4218 | bool next() override { |
4219 | // There are 2 basic cases: |
4220 | // 1) We are still reading the generator |
4221 | // 2) We are reading our own cache |
4222 | |
4223 | // In the first case, we need to poke the underlying generator. |
4224 | // If it happily moves, we are left in that state, otherwise it is time to start reading from our cache |
4225 | if (m_current_repeat == 0) { |
4226 | const auto success = m_generator.next(); |
4227 | if (!success) { |
4228 | ++m_current_repeat; |
4229 | } |
4230 | return m_current_repeat < m_target_repeats; |
4231 | } |
4232 | |
4233 | // In the second case, we need to move indices forward and check that we haven't run up against the end |
4234 | ++m_repeat_index; |
4235 | if (m_repeat_index == m_returned.size()) { |
4236 | m_repeat_index = 0; |
4237 | ++m_current_repeat; |
4238 | } |
4239 | return m_current_repeat < m_target_repeats; |
4240 | } |
4241 | }; |
4242 | |
4243 | template <typename T> |
4244 | GeneratorWrapper<T> repeat(size_t repeats, GeneratorWrapper<T>&& generator) { |
4245 | return GeneratorWrapper<T>(pf::make_unique<RepeatGenerator<T>>(repeats, std::move(generator))); |
4246 | } |
4247 | |
4248 | template <typename T, typename U, typename Func> |
4249 | class MapGenerator : public IGenerator<T> { |
4250 | // TBD: provide static assert for mapping function, for friendly error message |
4251 | GeneratorWrapper<U> m_generator; |
4252 | Func m_function; |
4253 | // To avoid returning dangling reference, we have to save the values |
4254 | T m_cache; |
4255 | public: |
4256 | template <typename F2 = Func> |
4257 | MapGenerator(F2&& function, GeneratorWrapper<U>&& generator) : |
4258 | m_generator(std::move(generator)), |
4259 | m_function(std::forward<F2>(function)), |
4260 | m_cache(m_function(m_generator.get())) |
4261 | {} |
4262 | |
4263 | T const& get() const override { |
4264 | return m_cache; |
4265 | } |
4266 | bool next() override { |
4267 | const auto success = m_generator.next(); |
4268 | if (success) { |
4269 | m_cache = m_function(m_generator.get()); |
4270 | } |
4271 | return success; |
4272 | } |
4273 | }; |
4274 | |
4275 | template <typename Func, typename U, typename T = FunctionReturnType<Func, U>> |
4276 | GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) { |
4277 | return GeneratorWrapper<T>( |
4278 | pf::make_unique<MapGenerator<T, U, Func>>(std::forward<Func>(function), std::move(generator)) |
4279 | ); |
4280 | } |
4281 | |
4282 | template <typename T, typename U, typename Func> |
4283 | GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) { |
4284 | return GeneratorWrapper<T>( |
4285 | pf::make_unique<MapGenerator<T, U, Func>>(std::forward<Func>(function), std::move(generator)) |
4286 | ); |
4287 | } |
4288 | |
4289 | template <typename T> |
4290 | class ChunkGenerator final : public IGenerator<std::vector<T>> { |
4291 | std::vector<T> m_chunk; |
4292 | size_t m_chunk_size; |
4293 | GeneratorWrapper<T> m_generator; |
4294 | bool m_used_up = false; |
4295 | public: |
4296 | ChunkGenerator(size_t size, GeneratorWrapper<T> generator) : |
4297 | m_chunk_size(size), m_generator(std::move(generator)) |
4298 | { |
4299 | m_chunk.reserve(m_chunk_size); |
4300 | if (m_chunk_size != 0) { |
4301 | m_chunk.push_back(m_generator.get()); |
4302 | for (size_t i = 1; i < m_chunk_size; ++i) { |
4303 | if (!m_generator.next()) { |
4304 | Catch::throw_exception(GeneratorException("Not enough values to initialize the first chunk" )); |
4305 | } |
4306 | m_chunk.push_back(m_generator.get()); |
4307 | } |
4308 | } |
4309 | } |
4310 | std::vector<T> const& get() const override { |
4311 | return m_chunk; |
4312 | } |
4313 | bool next() override { |
4314 | m_chunk.clear(); |
4315 | for (size_t idx = 0; idx < m_chunk_size; ++idx) { |
4316 | if (!m_generator.next()) { |
4317 | return false; |
4318 | } |
4319 | m_chunk.push_back(m_generator.get()); |
4320 | } |
4321 | return true; |
4322 | } |
4323 | }; |
4324 | |
4325 | template <typename T> |
4326 | GeneratorWrapper<std::vector<T>> chunk(size_t size, GeneratorWrapper<T>&& generator) { |
4327 | return GeneratorWrapper<std::vector<T>>( |
4328 | pf::make_unique<ChunkGenerator<T>>(size, std::move(generator)) |
4329 | ); |
4330 | } |
4331 | |
4332 | } // namespace Generators |
4333 | } // namespace Catch |
4334 | |
4335 | // end catch_generators_generic.hpp |
4336 | // start catch_generators_specific.hpp |
4337 | |
4338 | // start catch_context.h |
4339 | |
4340 | #include <memory> |
4341 | |
4342 | namespace Catch { |
4343 | |
4344 | struct IResultCapture; |
4345 | struct IRunner; |
4346 | struct IConfig; |
4347 | struct IMutableContext; |
4348 | |
4349 | using IConfigPtr = std::shared_ptr<IConfig const>; |
4350 | |
4351 | struct IContext |
4352 | { |
4353 | virtual ~IContext(); |
4354 | |
4355 | virtual IResultCapture* getResultCapture() = 0; |
4356 | virtual IRunner* getRunner() = 0; |
4357 | virtual IConfigPtr const& getConfig() const = 0; |
4358 | }; |
4359 | |
4360 | struct IMutableContext : IContext |
4361 | { |
4362 | virtual ~IMutableContext(); |
4363 | virtual void setResultCapture( IResultCapture* resultCapture ) = 0; |
4364 | virtual void setRunner( IRunner* runner ) = 0; |
4365 | virtual void setConfig( IConfigPtr const& config ) = 0; |
4366 | |
4367 | private: |
4368 | static IMutableContext *currentContext; |
4369 | friend IMutableContext& getCurrentMutableContext(); |
4370 | friend void cleanUpContext(); |
4371 | static void createContext(); |
4372 | }; |
4373 | |
4374 | inline IMutableContext& getCurrentMutableContext() |
4375 | { |
4376 | if( !IMutableContext::currentContext ) |
4377 | IMutableContext::createContext(); |
4378 | // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn) |
4379 | return *IMutableContext::currentContext; |
4380 | } |
4381 | |
4382 | inline IContext& getCurrentContext() |
4383 | { |
4384 | return getCurrentMutableContext(); |
4385 | } |
4386 | |
4387 | void cleanUpContext(); |
4388 | |
4389 | class SimplePcg32; |
4390 | SimplePcg32& rng(); |
4391 | } |
4392 | |
4393 | // end catch_context.h |
4394 | // start catch_interfaces_config.h |
4395 | |
4396 | // start catch_option.hpp |
4397 | |
4398 | namespace Catch { |
4399 | |
4400 | // An optional type |
4401 | template<typename T> |
4402 | class Option { |
4403 | public: |
4404 | Option() : nullableValue( nullptr ) {} |
4405 | Option( T const& _value ) |
4406 | : nullableValue( new( storage ) T( _value ) ) |
4407 | {} |
4408 | Option( Option const& _other ) |
4409 | : nullableValue( _other ? new( storage ) T( *_other ) : nullptr ) |
4410 | {} |
4411 | |
4412 | ~Option() { |
4413 | reset(); |
4414 | } |
4415 | |
4416 | Option& operator= ( Option const& _other ) { |
4417 | if( &_other != this ) { |
4418 | reset(); |
4419 | if( _other ) |
4420 | nullableValue = new( storage ) T( *_other ); |
4421 | } |
4422 | return *this; |
4423 | } |
4424 | Option& operator = ( T const& _value ) { |
4425 | reset(); |
4426 | nullableValue = new( storage ) T( _value ); |
4427 | return *this; |
4428 | } |
4429 | |
4430 | void reset() { |
4431 | if( nullableValue ) |
4432 | nullableValue->~T(); |
4433 | nullableValue = nullptr; |
4434 | } |
4435 | |
4436 | T& operator*() { return *nullableValue; } |
4437 | T const& operator*() const { return *nullableValue; } |
4438 | T* operator->() { return nullableValue; } |
4439 | const T* operator->() const { return nullableValue; } |
4440 | |
4441 | T valueOr( T const& defaultValue ) const { |
4442 | return nullableValue ? *nullableValue : defaultValue; |
4443 | } |
4444 | |
4445 | bool some() const { return nullableValue != nullptr; } |
4446 | bool none() const { return nullableValue == nullptr; } |
4447 | |
4448 | bool operator !() const { return nullableValue == nullptr; } |
4449 | explicit operator bool() const { |
4450 | return some(); |
4451 | } |
4452 | |
4453 | private: |
4454 | T *nullableValue; |
4455 | alignas(alignof(T)) char storage[sizeof(T)]; |
4456 | }; |
4457 | |
4458 | } // end namespace Catch |
4459 | |
4460 | // end catch_option.hpp |
4461 | #include <chrono> |
4462 | #include <iosfwd> |
4463 | #include <string> |
4464 | #include <vector> |
4465 | #include <memory> |
4466 | |
4467 | namespace Catch { |
4468 | |
4469 | enum class Verbosity { |
4470 | Quiet = 0, |
4471 | Normal, |
4472 | High |
4473 | }; |
4474 | |
4475 | struct WarnAbout { enum What { |
4476 | Nothing = 0x00, |
4477 | NoAssertions = 0x01, |
4478 | NoTests = 0x02 |
4479 | }; }; |
4480 | |
4481 | struct ShowDurations { enum OrNot { |
4482 | DefaultForReporter, |
4483 | Always, |
4484 | Never |
4485 | }; }; |
4486 | struct RunTests { enum InWhatOrder { |
4487 | InDeclarationOrder, |
4488 | InLexicographicalOrder, |
4489 | InRandomOrder |
4490 | }; }; |
4491 | struct UseColour { enum YesOrNo { |
4492 | Auto, |
4493 | Yes, |
4494 | No |
4495 | }; }; |
4496 | struct WaitForKeypress { enum When { |
4497 | Never, |
4498 | BeforeStart = 1, |
4499 | BeforeExit = 2, |
4500 | BeforeStartAndExit = BeforeStart | BeforeExit |
4501 | }; }; |
4502 | |
4503 | class TestSpec; |
4504 | |
4505 | struct IConfig : NonCopyable { |
4506 | |
4507 | virtual ~IConfig(); |
4508 | |
4509 | virtual bool allowThrows() const = 0; |
4510 | virtual std::ostream& stream() const = 0; |
4511 | virtual std::string name() const = 0; |
4512 | virtual bool includeSuccessfulResults() const = 0; |
4513 | virtual bool shouldDebugBreak() const = 0; |
4514 | virtual bool warnAboutMissingAssertions() const = 0; |
4515 | virtual bool warnAboutNoTests() const = 0; |
4516 | virtual int abortAfter() const = 0; |
4517 | virtual bool showInvisibles() const = 0; |
4518 | virtual ShowDurations::OrNot showDurations() const = 0; |
4519 | virtual double minDuration() const = 0; |
4520 | virtual TestSpec const& testSpec() const = 0; |
4521 | virtual bool hasTestFilters() const = 0; |
4522 | virtual std::vector<std::string> const& getTestsOrTags() const = 0; |
4523 | virtual RunTests::InWhatOrder runOrder() const = 0; |
4524 | virtual unsigned int rngSeed() const = 0; |
4525 | virtual UseColour::YesOrNo useColour() const = 0; |
4526 | virtual std::vector<std::string> const& getSectionsToRun() const = 0; |
4527 | virtual Verbosity verbosity() const = 0; |
4528 | |
4529 | virtual bool benchmarkNoAnalysis() const = 0; |
4530 | virtual int benchmarkSamples() const = 0; |
4531 | virtual double benchmarkConfidenceInterval() const = 0; |
4532 | virtual unsigned int benchmarkResamples() const = 0; |
4533 | virtual std::chrono::milliseconds benchmarkWarmupTime() const = 0; |
4534 | }; |
4535 | |
4536 | using IConfigPtr = std::shared_ptr<IConfig const>; |
4537 | } |
4538 | |
4539 | // end catch_interfaces_config.h |
4540 | // start catch_random_number_generator.h |
4541 | |
4542 | #include <cstdint> |
4543 | |
4544 | namespace Catch { |
4545 | |
4546 | // This is a simple implementation of C++11 Uniform Random Number |
4547 | // Generator. It does not provide all operators, because Catch2 |
4548 | // does not use it, but it should behave as expected inside stdlib's |
4549 | // distributions. |
4550 | // The implementation is based on the PCG family (http://pcg-random.org) |
4551 | class SimplePcg32 { |
4552 | using state_type = std::uint64_t; |
4553 | public: |
4554 | using result_type = std::uint32_t; |
4555 | static constexpr result_type (min)() { |
4556 | return 0; |
4557 | } |
4558 | static constexpr result_type (max)() { |
4559 | return static_cast<result_type>(-1); |
4560 | } |
4561 | |
4562 | // Provide some default initial state for the default constructor |
4563 | SimplePcg32():SimplePcg32(0xed743cc4U) {} |
4564 | |
4565 | explicit SimplePcg32(result_type seed_); |
4566 | |
4567 | void seed(result_type seed_); |
4568 | void discard(uint64_t skip); |
4569 | |
4570 | result_type operator()(); |
4571 | |
4572 | private: |
4573 | friend bool operator==(SimplePcg32 const& lhs, SimplePcg32 const& rhs); |
4574 | friend bool operator!=(SimplePcg32 const& lhs, SimplePcg32 const& rhs); |
4575 | |
4576 | // In theory we also need operator<< and operator>> |
4577 | // In practice we do not use them, so we will skip them for now |
4578 | |
4579 | std::uint64_t m_state; |
4580 | // This part of the state determines which "stream" of the numbers |
4581 | // is chosen -- we take it as a constant for Catch2, so we only |
4582 | // need to deal with seeding the main state. |
4583 | // Picked by reading 8 bytes from `/dev/random` :-) |
4584 | static const std::uint64_t s_inc = (0x13ed0cc53f939476ULL << 1ULL) | 1ULL; |
4585 | }; |
4586 | |
4587 | } // end namespace Catch |
4588 | |
4589 | // end catch_random_number_generator.h |
4590 | #include <random> |
4591 | |
4592 | namespace Catch { |
4593 | namespace Generators { |
4594 | |
4595 | template <typename Float> |
4596 | class RandomFloatingGenerator final : public IGenerator<Float> { |
4597 | Catch::SimplePcg32& m_rng; |
4598 | std::uniform_real_distribution<Float> m_dist; |
4599 | Float m_current_number; |
4600 | public: |
4601 | |
4602 | RandomFloatingGenerator(Float a, Float b): |
4603 | m_rng(rng()), |
4604 | m_dist(a, b) { |
4605 | static_cast<void>(next()); |
4606 | } |
4607 | |
4608 | Float const& get() const override { |
4609 | return m_current_number; |
4610 | } |
4611 | bool next() override { |
4612 | m_current_number = m_dist(m_rng); |
4613 | return true; |
4614 | } |
4615 | }; |
4616 | |
4617 | template <typename Integer> |
4618 | class RandomIntegerGenerator final : public IGenerator<Integer> { |
4619 | Catch::SimplePcg32& m_rng; |
4620 | std::uniform_int_distribution<Integer> m_dist; |
4621 | Integer m_current_number; |
4622 | public: |
4623 | |
4624 | RandomIntegerGenerator(Integer a, Integer b): |
4625 | m_rng(rng()), |
4626 | m_dist(a, b) { |
4627 | static_cast<void>(next()); |
4628 | } |
4629 | |
4630 | Integer const& get() const override { |
4631 | return m_current_number; |
4632 | } |
4633 | bool next() override { |
4634 | m_current_number = m_dist(m_rng); |
4635 | return true; |
4636 | } |
4637 | }; |
4638 | |
4639 | // TODO: Ideally this would be also constrained against the various char types, |
4640 | // but I don't expect users to run into that in practice. |
4641 | template <typename T> |
4642 | typename std::enable_if<std::is_integral<T>::value && !std::is_same<T, bool>::value, |
4643 | GeneratorWrapper<T>>::type |
4644 | random(T a, T b) { |
4645 | return GeneratorWrapper<T>( |
4646 | pf::make_unique<RandomIntegerGenerator<T>>(a, b) |
4647 | ); |
4648 | } |
4649 | |
4650 | template <typename T> |
4651 | typename std::enable_if<std::is_floating_point<T>::value, |
4652 | GeneratorWrapper<T>>::type |
4653 | random(T a, T b) { |
4654 | return GeneratorWrapper<T>( |
4655 | pf::make_unique<RandomFloatingGenerator<T>>(a, b) |
4656 | ); |
4657 | } |
4658 | |
4659 | template <typename T> |
4660 | class RangeGenerator final : public IGenerator<T> { |
4661 | T m_current; |
4662 | T m_end; |
4663 | T m_step; |
4664 | bool m_positive; |
4665 | |
4666 | public: |
4667 | RangeGenerator(T const& start, T const& end, T const& step): |
4668 | m_current(start), |
4669 | m_end(end), |
4670 | m_step(step), |
4671 | m_positive(m_step > T(0)) |
4672 | { |
4673 | assert(m_current != m_end && "Range start and end cannot be equal" ); |
4674 | assert(m_step != T(0) && "Step size cannot be zero" ); |
4675 | assert(((m_positive && m_current <= m_end) || (!m_positive && m_current >= m_end)) && "Step moves away from end" ); |
4676 | } |
4677 | |
4678 | RangeGenerator(T const& start, T const& end): |
4679 | RangeGenerator(start, end, (start < end) ? T(1) : T(-1)) |
4680 | {} |
4681 | |
4682 | T const& get() const override { |
4683 | return m_current; |
4684 | } |
4685 | |
4686 | bool next() override { |
4687 | m_current += m_step; |
4688 | return (m_positive) ? (m_current < m_end) : (m_current > m_end); |
4689 | } |
4690 | }; |
4691 | |
4692 | template <typename T> |
4693 | GeneratorWrapper<T> range(T const& start, T const& end, T const& step) { |
4694 | static_assert(std::is_arithmetic<T>::value && !std::is_same<T, bool>::value, "Type must be numeric" ); |
4695 | return GeneratorWrapper<T>(pf::make_unique<RangeGenerator<T>>(start, end, step)); |
4696 | } |
4697 | |
4698 | template <typename T> |
4699 | GeneratorWrapper<T> range(T const& start, T const& end) { |
4700 | static_assert(std::is_integral<T>::value && !std::is_same<T, bool>::value, "Type must be an integer" ); |
4701 | return GeneratorWrapper<T>(pf::make_unique<RangeGenerator<T>>(start, end)); |
4702 | } |
4703 | |
4704 | template <typename T> |
4705 | class IteratorGenerator final : public IGenerator<T> { |
4706 | static_assert(!std::is_same<T, bool>::value, |
4707 | "IteratorGenerator currently does not support bools" |
4708 | "because of std::vector<bool> specialization" ); |
4709 | |
4710 | std::vector<T> m_elems; |
4711 | size_t m_current = 0; |
4712 | public: |
4713 | template <typename InputIterator, typename InputSentinel> |
4714 | IteratorGenerator(InputIterator first, InputSentinel last):m_elems(first, last) { |
4715 | if (m_elems.empty()) { |
4716 | Catch::throw_exception(GeneratorException("IteratorGenerator received no valid values" )); |
4717 | } |
4718 | } |
4719 | |
4720 | T const& get() const override { |
4721 | return m_elems[m_current]; |
4722 | } |
4723 | |
4724 | bool next() override { |
4725 | ++m_current; |
4726 | return m_current != m_elems.size(); |
4727 | } |
4728 | }; |
4729 | |
4730 | template <typename InputIterator, |
4731 | typename InputSentinel, |
4732 | typename ResultType = typename std::iterator_traits<InputIterator>::value_type> |
4733 | GeneratorWrapper<ResultType> from_range(InputIterator from, InputSentinel to) { |
4734 | return GeneratorWrapper<ResultType>(pf::make_unique<IteratorGenerator<ResultType>>(from, to)); |
4735 | } |
4736 | |
4737 | template <typename Container, |
4738 | typename ResultType = typename Container::value_type> |
4739 | GeneratorWrapper<ResultType> from_range(Container const& cnt) { |
4740 | return GeneratorWrapper<ResultType>(pf::make_unique<IteratorGenerator<ResultType>>(cnt.begin(), cnt.end())); |
4741 | } |
4742 | |
4743 | } // namespace Generators |
4744 | } // namespace Catch |
4745 | |
4746 | // end catch_generators_specific.hpp |
4747 | |
4748 | // These files are included here so the single_include script doesn't put them |
4749 | // in the conditionally compiled sections |
4750 | // start catch_test_case_info.h |
4751 | |
4752 | #include <string> |
4753 | #include <vector> |
4754 | #include <memory> |
4755 | |
4756 | #ifdef __clang__ |
4757 | #pragma clang diagnostic push |
4758 | #pragma clang diagnostic ignored "-Wpadded" |
4759 | #endif |
4760 | |
4761 | namespace Catch { |
4762 | |
4763 | struct ITestInvoker; |
4764 | |
4765 | struct TestCaseInfo { |
4766 | enum SpecialProperties{ |
4767 | None = 0, |
4768 | IsHidden = 1 << 1, |
4769 | ShouldFail = 1 << 2, |
4770 | MayFail = 1 << 3, |
4771 | Throws = 1 << 4, |
4772 | NonPortable = 1 << 5, |
4773 | Benchmark = 1 << 6 |
4774 | }; |
4775 | |
4776 | TestCaseInfo( std::string const& _name, |
4777 | std::string const& _className, |
4778 | std::string const& _description, |
4779 | std::vector<std::string> const& _tags, |
4780 | SourceLineInfo const& _lineInfo ); |
4781 | |
4782 | friend void setTags( TestCaseInfo& testCaseInfo, std::vector<std::string> tags ); |
4783 | |
4784 | bool isHidden() const; |
4785 | bool throws() const; |
4786 | bool okToFail() const; |
4787 | bool expectedToFail() const; |
4788 | |
4789 | std::string tagsAsString() const; |
4790 | |
4791 | std::string name; |
4792 | std::string className; |
4793 | std::string description; |
4794 | std::vector<std::string> tags; |
4795 | std::vector<std::string> lcaseTags; |
4796 | SourceLineInfo lineInfo; |
4797 | SpecialProperties properties; |
4798 | }; |
4799 | |
4800 | class TestCase : public TestCaseInfo { |
4801 | public: |
4802 | |
4803 | TestCase( ITestInvoker* testCase, TestCaseInfo&& info ); |
4804 | |
4805 | TestCase withName( std::string const& _newName ) const; |
4806 | |
4807 | void invoke() const; |
4808 | |
4809 | TestCaseInfo const& getTestCaseInfo() const; |
4810 | |
4811 | bool operator == ( TestCase const& other ) const; |
4812 | bool operator < ( TestCase const& other ) const; |
4813 | |
4814 | private: |
4815 | std::shared_ptr<ITestInvoker> test; |
4816 | }; |
4817 | |
4818 | TestCase makeTestCase( ITestInvoker* testCase, |
4819 | std::string const& className, |
4820 | NameAndTags const& nameAndTags, |
4821 | SourceLineInfo const& lineInfo ); |
4822 | } |
4823 | |
4824 | #ifdef __clang__ |
4825 | #pragma clang diagnostic pop |
4826 | #endif |
4827 | |
4828 | // end catch_test_case_info.h |
4829 | // start catch_interfaces_runner.h |
4830 | |
4831 | namespace Catch { |
4832 | |
4833 | struct IRunner { |
4834 | virtual ~IRunner(); |
4835 | virtual bool aborting() const = 0; |
4836 | }; |
4837 | } |
4838 | |
4839 | // end catch_interfaces_runner.h |
4840 | |
4841 | #ifdef __OBJC__ |
4842 | // start catch_objc.hpp |
4843 | |
4844 | #import <objc/runtime.h> |
4845 | |
4846 | #include <string> |
4847 | |
4848 | // NB. Any general catch headers included here must be included |
4849 | // in catch.hpp first to make sure they are included by the single |
4850 | // header for non obj-usage |
4851 | |
4852 | /////////////////////////////////////////////////////////////////////////////// |
4853 | // This protocol is really only here for (self) documenting purposes, since |
4854 | // all its methods are optional. |
4855 | @protocol OcFixture |
4856 | |
4857 | @optional |
4858 | |
4859 | -(void) setUp; |
4860 | -(void) tearDown; |
4861 | |
4862 | @end |
4863 | |
4864 | namespace Catch { |
4865 | |
4866 | class OcMethod : public ITestInvoker { |
4867 | |
4868 | public: |
4869 | OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {} |
4870 | |
4871 | virtual void invoke() const { |
4872 | id obj = [[m_cls alloc] init]; |
4873 | |
4874 | performOptionalSelector( obj, @selector(setUp) ); |
4875 | performOptionalSelector( obj, m_sel ); |
4876 | performOptionalSelector( obj, @selector(tearDown) ); |
4877 | |
4878 | arcSafeRelease( obj ); |
4879 | } |
4880 | private: |
4881 | virtual ~OcMethod() {} |
4882 | |
4883 | Class m_cls; |
4884 | SEL m_sel; |
4885 | }; |
4886 | |
4887 | namespace Detail{ |
4888 | |
4889 | inline std::string getAnnotation( Class cls, |
4890 | std::string const& annotationName, |
4891 | std::string const& testCaseName ) { |
4892 | NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s" , annotationName.c_str(), testCaseName.c_str()]; |
4893 | SEL sel = NSSelectorFromString( selStr ); |
4894 | arcSafeRelease( selStr ); |
4895 | id value = performOptionalSelector( cls, sel ); |
4896 | if( value ) |
4897 | return [(NSString*)value UTF8String]; |
4898 | return "" ; |
4899 | } |
4900 | } |
4901 | |
4902 | inline std::size_t registerTestMethods() { |
4903 | std::size_t noTestMethods = 0; |
4904 | int noClasses = objc_getClassList( nullptr, 0 ); |
4905 | |
4906 | Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); |
4907 | objc_getClassList( classes, noClasses ); |
4908 | |
4909 | for( int c = 0; c < noClasses; c++ ) { |
4910 | Class cls = classes[c]; |
4911 | { |
4912 | u_int count; |
4913 | Method* methods = class_copyMethodList( cls, &count ); |
4914 | for( u_int m = 0; m < count ; m++ ) { |
4915 | SEL selector = method_getName(methods[m]); |
4916 | std::string methodName = sel_getName(selector); |
4917 | if( startsWith( methodName, "Catch_TestCase_" ) ) { |
4918 | std::string testCaseName = methodName.substr( 15 ); |
4919 | std::string name = Detail::getAnnotation( cls, "Name" , testCaseName ); |
4920 | std::string desc = Detail::getAnnotation( cls, "Description" , testCaseName ); |
4921 | const char* className = class_getName( cls ); |
4922 | |
4923 | getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, NameAndTags( name.c_str(), desc.c_str() ), SourceLineInfo("" ,0) ) ); |
4924 | noTestMethods++; |
4925 | } |
4926 | } |
4927 | free(methods); |
4928 | } |
4929 | } |
4930 | return noTestMethods; |
4931 | } |
4932 | |
4933 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) |
4934 | |
4935 | namespace Matchers { |
4936 | namespace Impl { |
4937 | namespace NSStringMatchers { |
4938 | |
4939 | struct StringHolder : MatcherBase<NSString*>{ |
4940 | StringHolder( NSString* substr ) : m_substr( [substr copy] ){} |
4941 | StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){} |
4942 | StringHolder() { |
4943 | arcSafeRelease( m_substr ); |
4944 | } |
4945 | |
4946 | bool match( NSString* str ) const override { |
4947 | return false; |
4948 | } |
4949 | |
4950 | NSString* CATCH_ARC_STRONG m_substr; |
4951 | }; |
4952 | |
4953 | struct Equals : StringHolder { |
4954 | Equals( NSString* substr ) : StringHolder( substr ){} |
4955 | |
4956 | bool match( NSString* str ) const override { |
4957 | return (str != nil || m_substr == nil ) && |
4958 | [str isEqualToString:m_substr]; |
4959 | } |
4960 | |
4961 | std::string describe() const override { |
4962 | return "equals string: " + Catch::Detail::stringify( m_substr ); |
4963 | } |
4964 | }; |
4965 | |
4966 | struct Contains : StringHolder { |
4967 | Contains( NSString* substr ) : StringHolder( substr ){} |
4968 | |
4969 | bool match( NSString* str ) const override { |
4970 | return (str != nil || m_substr == nil ) && |
4971 | [str rangeOfString:m_substr].location != NSNotFound; |
4972 | } |
4973 | |
4974 | std::string describe() const override { |
4975 | return "contains string: " + Catch::Detail::stringify( m_substr ); |
4976 | } |
4977 | }; |
4978 | |
4979 | struct StartsWith : StringHolder { |
4980 | StartsWith( NSString* substr ) : StringHolder( substr ){} |
4981 | |
4982 | bool match( NSString* str ) const override { |
4983 | return (str != nil || m_substr == nil ) && |
4984 | [str rangeOfString:m_substr].location == 0; |
4985 | } |
4986 | |
4987 | std::string describe() const override { |
4988 | return "starts with: " + Catch::Detail::stringify( m_substr ); |
4989 | } |
4990 | }; |
4991 | struct EndsWith : StringHolder { |
4992 | EndsWith( NSString* substr ) : StringHolder( substr ){} |
4993 | |
4994 | bool match( NSString* str ) const override { |
4995 | return (str != nil || m_substr == nil ) && |
4996 | [str rangeOfString:m_substr].location == [str length] - [m_substr length]; |
4997 | } |
4998 | |
4999 | std::string describe() const override { |
5000 | return "ends with: " + Catch::Detail::stringify( m_substr ); |
5001 | } |
5002 | }; |
5003 | |
5004 | } // namespace NSStringMatchers |
5005 | } // namespace Impl |
5006 | |
5007 | inline Impl::NSStringMatchers::Equals |
5008 | Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); } |
5009 | |
5010 | inline Impl::NSStringMatchers::Contains |
5011 | Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); } |
5012 | |
5013 | inline Impl::NSStringMatchers::StartsWith |
5014 | StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); } |
5015 | |
5016 | inline Impl::NSStringMatchers::EndsWith |
5017 | EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); } |
5018 | |
5019 | } // namespace Matchers |
5020 | |
5021 | using namespace Matchers; |
5022 | |
5023 | #endif // CATCH_CONFIG_DISABLE_MATCHERS |
5024 | |
5025 | } // namespace Catch |
5026 | |
5027 | /////////////////////////////////////////////////////////////////////////////// |
5028 | #define OC_MAKE_UNIQUE_NAME( root, uniqueSuffix ) root##uniqueSuffix |
5029 | #define OC_TEST_CASE2( name, desc, uniqueSuffix ) \ |
5030 | +(NSString*) OC_MAKE_UNIQUE_NAME( Catch_Name_test_, uniqueSuffix ) \ |
5031 | { \ |
5032 | return @ name; \ |
5033 | } \ |
5034 | +(NSString*) OC_MAKE_UNIQUE_NAME( Catch_Description_test_, uniqueSuffix ) \ |
5035 | { \ |
5036 | return @ desc; \ |
5037 | } \ |
5038 | -(void) OC_MAKE_UNIQUE_NAME( Catch_TestCase_test_, uniqueSuffix ) |
5039 | |
5040 | #define OC_TEST_CASE( name, desc ) OC_TEST_CASE2( name, desc, __LINE__ ) |
5041 | |
5042 | // end catch_objc.hpp |
5043 | #endif |
5044 | |
5045 | // Benchmarking needs the externally-facing parts of reporters to work |
5046 | #if defined(CATCH_CONFIG_EXTERNAL_INTERFACES) || defined(CATCH_CONFIG_ENABLE_BENCHMARKING) |
5047 | // start catch_external_interfaces.h |
5048 | |
5049 | // start catch_reporter_bases.hpp |
5050 | |
5051 | // start catch_interfaces_reporter.h |
5052 | |
5053 | // start catch_config.hpp |
5054 | |
5055 | // start catch_test_spec_parser.h |
5056 | |
5057 | #ifdef __clang__ |
5058 | #pragma clang diagnostic push |
5059 | #pragma clang diagnostic ignored "-Wpadded" |
5060 | #endif |
5061 | |
5062 | // start catch_test_spec.h |
5063 | |
5064 | #ifdef __clang__ |
5065 | #pragma clang diagnostic push |
5066 | #pragma clang diagnostic ignored "-Wpadded" |
5067 | #endif |
5068 | |
5069 | // start catch_wildcard_pattern.h |
5070 | |
5071 | namespace Catch |
5072 | { |
5073 | class WildcardPattern { |
5074 | enum WildcardPosition { |
5075 | NoWildcard = 0, |
5076 | WildcardAtStart = 1, |
5077 | WildcardAtEnd = 2, |
5078 | WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd |
5079 | }; |
5080 | |
5081 | public: |
5082 | |
5083 | WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity ); |
5084 | virtual ~WildcardPattern() = default; |
5085 | virtual bool matches( std::string const& str ) const; |
5086 | |
5087 | private: |
5088 | std::string normaliseString( std::string const& str ) const; |
5089 | CaseSensitive::Choice m_caseSensitivity; |
5090 | WildcardPosition m_wildcard = NoWildcard; |
5091 | std::string m_pattern; |
5092 | }; |
5093 | } |
5094 | |
5095 | // end catch_wildcard_pattern.h |
5096 | #include <string> |
5097 | #include <vector> |
5098 | #include <memory> |
5099 | |
5100 | namespace Catch { |
5101 | |
5102 | struct IConfig; |
5103 | |
5104 | class TestSpec { |
5105 | class Pattern { |
5106 | public: |
5107 | explicit Pattern( std::string const& name ); |
5108 | virtual ~Pattern(); |
5109 | virtual bool matches( TestCaseInfo const& testCase ) const = 0; |
5110 | std::string const& name() const; |
5111 | private: |
5112 | std::string const m_name; |
5113 | }; |
5114 | using PatternPtr = std::shared_ptr<Pattern>; |
5115 | |
5116 | class NamePattern : public Pattern { |
5117 | public: |
5118 | explicit NamePattern( std::string const& name, std::string const& filterString ); |
5119 | bool matches( TestCaseInfo const& testCase ) const override; |
5120 | private: |
5121 | WildcardPattern m_wildcardPattern; |
5122 | }; |
5123 | |
5124 | class TagPattern : public Pattern { |
5125 | public: |
5126 | explicit TagPattern( std::string const& tag, std::string const& filterString ); |
5127 | bool matches( TestCaseInfo const& testCase ) const override; |
5128 | private: |
5129 | std::string m_tag; |
5130 | }; |
5131 | |
5132 | class ExcludedPattern : public Pattern { |
5133 | public: |
5134 | explicit ExcludedPattern( PatternPtr const& underlyingPattern ); |
5135 | bool matches( TestCaseInfo const& testCase ) const override; |
5136 | private: |
5137 | PatternPtr m_underlyingPattern; |
5138 | }; |
5139 | |
5140 | struct Filter { |
5141 | std::vector<PatternPtr> m_patterns; |
5142 | |
5143 | bool matches( TestCaseInfo const& testCase ) const; |
5144 | std::string name() const; |
5145 | }; |
5146 | |
5147 | public: |
5148 | struct FilterMatch { |
5149 | std::string name; |
5150 | std::vector<TestCase const*> tests; |
5151 | }; |
5152 | using Matches = std::vector<FilterMatch>; |
5153 | using vectorStrings = std::vector<std::string>; |
5154 | |
5155 | bool hasFilters() const; |
5156 | bool matches( TestCaseInfo const& testCase ) const; |
5157 | Matches matchesByFilter( std::vector<TestCase> const& testCases, IConfig const& config ) const; |
5158 | const vectorStrings & getInvalidArgs() const; |
5159 | |
5160 | private: |
5161 | std::vector<Filter> m_filters; |
5162 | std::vector<std::string> m_invalidArgs; |
5163 | friend class TestSpecParser; |
5164 | }; |
5165 | } |
5166 | |
5167 | #ifdef __clang__ |
5168 | #pragma clang diagnostic pop |
5169 | #endif |
5170 | |
5171 | // end catch_test_spec.h |
5172 | // start catch_interfaces_tag_alias_registry.h |
5173 | |
5174 | #include <string> |
5175 | |
5176 | namespace Catch { |
5177 | |
5178 | struct TagAlias; |
5179 | |
5180 | struct ITagAliasRegistry { |
5181 | virtual ~ITagAliasRegistry(); |
5182 | // Nullptr if not present |
5183 | virtual TagAlias const* find( std::string const& alias ) const = 0; |
5184 | virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0; |
5185 | |
5186 | static ITagAliasRegistry const& get(); |
5187 | }; |
5188 | |
5189 | } // end namespace Catch |
5190 | |
5191 | // end catch_interfaces_tag_alias_registry.h |
5192 | namespace Catch { |
5193 | |
5194 | class TestSpecParser { |
5195 | enum Mode{ None, Name, QuotedName, Tag, EscapedName }; |
5196 | Mode m_mode = None; |
5197 | Mode lastMode = None; |
5198 | bool m_exclusion = false; |
5199 | std::size_t m_pos = 0; |
5200 | std::size_t m_realPatternPos = 0; |
5201 | std::string m_arg; |
5202 | std::string m_substring; |
5203 | std::string m_patternName; |
5204 | std::vector<std::size_t> m_escapeChars; |
5205 | TestSpec::Filter m_currentFilter; |
5206 | TestSpec m_testSpec; |
5207 | ITagAliasRegistry const* m_tagAliases = nullptr; |
5208 | |
5209 | public: |
5210 | TestSpecParser( ITagAliasRegistry const& tagAliases ); |
5211 | |
5212 | TestSpecParser& parse( std::string const& arg ); |
5213 | TestSpec testSpec(); |
5214 | |
5215 | private: |
5216 | bool visitChar( char c ); |
5217 | void startNewMode( Mode mode ); |
5218 | bool processNoneChar( char c ); |
5219 | void processNameChar( char c ); |
5220 | bool processOtherChar( char c ); |
5221 | void endMode(); |
5222 | void escape(); |
5223 | bool isControlChar( char c ) const; |
5224 | void saveLastMode(); |
5225 | void revertBackToLastMode(); |
5226 | void addFilter(); |
5227 | bool separate(); |
5228 | |
5229 | // Handles common preprocessing of the pattern for name/tag patterns |
5230 | std::string preprocessPattern(); |
5231 | // Adds the current pattern as a test name |
5232 | void addNamePattern(); |
5233 | // Adds the current pattern as a tag |
5234 | void addTagPattern(); |
5235 | |
5236 | inline void addCharToPattern(char c) { |
5237 | m_substring += c; |
5238 | m_patternName += c; |
5239 | m_realPatternPos++; |
5240 | } |
5241 | |
5242 | }; |
5243 | TestSpec parseTestSpec( std::string const& arg ); |
5244 | |
5245 | } // namespace Catch |
5246 | |
5247 | #ifdef __clang__ |
5248 | #pragma clang diagnostic pop |
5249 | #endif |
5250 | |
5251 | // end catch_test_spec_parser.h |
5252 | // Libstdc++ doesn't like incomplete classes for unique_ptr |
5253 | |
5254 | #include <memory> |
5255 | #include <vector> |
5256 | #include <string> |
5257 | |
5258 | #ifndef CATCH_CONFIG_CONSOLE_WIDTH |
5259 | #define CATCH_CONFIG_CONSOLE_WIDTH 80 |
5260 | #endif |
5261 | |
5262 | namespace Catch { |
5263 | |
5264 | struct IStream; |
5265 | |
5266 | struct ConfigData { |
5267 | bool listTests = false; |
5268 | bool listTags = false; |
5269 | bool listReporters = false; |
5270 | bool listTestNamesOnly = false; |
5271 | |
5272 | bool showSuccessfulTests = false; |
5273 | bool shouldDebugBreak = false; |
5274 | bool noThrow = false; |
5275 | bool showHelp = false; |
5276 | bool showInvisibles = false; |
5277 | bool filenamesAsTags = false; |
5278 | bool libIdentify = false; |
5279 | |
5280 | int abortAfter = -1; |
5281 | unsigned int rngSeed = 0; |
5282 | |
5283 | bool benchmarkNoAnalysis = false; |
5284 | unsigned int benchmarkSamples = 100; |
5285 | double benchmarkConfidenceInterval = 0.95; |
5286 | unsigned int benchmarkResamples = 100000; |
5287 | std::chrono::milliseconds::rep benchmarkWarmupTime = 100; |
5288 | |
5289 | Verbosity verbosity = Verbosity::Normal; |
5290 | WarnAbout::What warnings = WarnAbout::Nothing; |
5291 | ShowDurations::OrNot showDurations = ShowDurations::DefaultForReporter; |
5292 | double minDuration = -1; |
5293 | RunTests::InWhatOrder runOrder = RunTests::InDeclarationOrder; |
5294 | UseColour::YesOrNo useColour = UseColour::Auto; |
5295 | WaitForKeypress::When waitForKeypress = WaitForKeypress::Never; |
5296 | |
5297 | std::string outputFilename; |
5298 | std::string name; |
5299 | std::string processName; |
5300 | #ifndef CATCH_CONFIG_DEFAULT_REPORTER |
5301 | #define CATCH_CONFIG_DEFAULT_REPORTER "console" |
5302 | #endif |
5303 | std::string reporterName = CATCH_CONFIG_DEFAULT_REPORTER; |
5304 | #undef CATCH_CONFIG_DEFAULT_REPORTER |
5305 | |
5306 | std::vector<std::string> testsOrTags; |
5307 | std::vector<std::string> sectionsToRun; |
5308 | }; |
5309 | |
5310 | class Config : public IConfig { |
5311 | public: |
5312 | |
5313 | Config() = default; |
5314 | Config( ConfigData const& data ); |
5315 | virtual ~Config() = default; |
5316 | |
5317 | std::string const& getFilename() const; |
5318 | |
5319 | bool listTests() const; |
5320 | bool listTestNamesOnly() const; |
5321 | bool listTags() const; |
5322 | bool listReporters() const; |
5323 | |
5324 | std::string getProcessName() const; |
5325 | std::string const& getReporterName() const; |
5326 | |
5327 | std::vector<std::string> const& getTestsOrTags() const override; |
5328 | std::vector<std::string> const& getSectionsToRun() const override; |
5329 | |
5330 | TestSpec const& testSpec() const override; |
5331 | bool hasTestFilters() const override; |
5332 | |
5333 | bool showHelp() const; |
5334 | |
5335 | // IConfig interface |
5336 | bool allowThrows() const override; |
5337 | std::ostream& stream() const override; |
5338 | std::string name() const override; |
5339 | bool includeSuccessfulResults() const override; |
5340 | bool warnAboutMissingAssertions() const override; |
5341 | bool warnAboutNoTests() const override; |
5342 | ShowDurations::OrNot showDurations() const override; |
5343 | double minDuration() const override; |
5344 | RunTests::InWhatOrder runOrder() const override; |
5345 | unsigned int rngSeed() const override; |
5346 | UseColour::YesOrNo useColour() const override; |
5347 | bool shouldDebugBreak() const override; |
5348 | int abortAfter() const override; |
5349 | bool showInvisibles() const override; |
5350 | Verbosity verbosity() const override; |
5351 | bool benchmarkNoAnalysis() const override; |
5352 | int benchmarkSamples() const override; |
5353 | double benchmarkConfidenceInterval() const override; |
5354 | unsigned int benchmarkResamples() const override; |
5355 | std::chrono::milliseconds benchmarkWarmupTime() const override; |
5356 | |
5357 | private: |
5358 | |
5359 | IStream const* openStream(); |
5360 | ConfigData m_data; |
5361 | |
5362 | std::unique_ptr<IStream const> m_stream; |
5363 | TestSpec m_testSpec; |
5364 | bool m_hasTestFilters = false; |
5365 | }; |
5366 | |
5367 | } // end namespace Catch |
5368 | |
5369 | // end catch_config.hpp |
5370 | // start catch_assertionresult.h |
5371 | |
5372 | #include <string> |
5373 | |
5374 | namespace Catch { |
5375 | |
5376 | struct AssertionResultData |
5377 | { |
5378 | AssertionResultData() = delete; |
5379 | |
5380 | AssertionResultData( ResultWas::OfType _resultType, LazyExpression const& _lazyExpression ); |
5381 | |
5382 | std::string message; |
5383 | mutable std::string reconstructedExpression; |
5384 | LazyExpression lazyExpression; |
5385 | ResultWas::OfType resultType; |
5386 | |
5387 | std::string reconstructExpression() const; |
5388 | }; |
5389 | |
5390 | class AssertionResult { |
5391 | public: |
5392 | AssertionResult() = delete; |
5393 | AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); |
5394 | |
5395 | bool isOk() const; |
5396 | bool succeeded() const; |
5397 | ResultWas::OfType getResultType() const; |
5398 | bool hasExpression() const; |
5399 | bool hasMessage() const; |
5400 | std::string getExpression() const; |
5401 | std::string getExpressionInMacro() const; |
5402 | bool hasExpandedExpression() const; |
5403 | std::string getExpandedExpression() const; |
5404 | std::string getMessage() const; |
5405 | SourceLineInfo getSourceInfo() const; |
5406 | StringRef getTestMacroName() const; |
5407 | |
5408 | //protected: |
5409 | AssertionInfo m_info; |
5410 | AssertionResultData m_resultData; |
5411 | }; |
5412 | |
5413 | } // end namespace Catch |
5414 | |
5415 | // end catch_assertionresult.h |
5416 | #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) |
5417 | // start catch_estimate.hpp |
5418 | |
5419 | // Statistics estimates |
5420 | |
5421 | |
5422 | namespace Catch { |
5423 | namespace Benchmark { |
5424 | template <typename Duration> |
5425 | struct Estimate { |
5426 | Duration point; |
5427 | Duration lower_bound; |
5428 | Duration upper_bound; |
5429 | double confidence_interval; |
5430 | |
5431 | template <typename Duration2> |
5432 | operator Estimate<Duration2>() const { |
5433 | return { point, lower_bound, upper_bound, confidence_interval }; |
5434 | } |
5435 | }; |
5436 | } // namespace Benchmark |
5437 | } // namespace Catch |
5438 | |
5439 | // end catch_estimate.hpp |
5440 | // start catch_outlier_classification.hpp |
5441 | |
5442 | // Outlier information |
5443 | |
5444 | namespace Catch { |
5445 | namespace Benchmark { |
5446 | struct OutlierClassification { |
5447 | int samples_seen = 0; |
5448 | int low_severe = 0; // more than 3 times IQR below Q1 |
5449 | int low_mild = 0; // 1.5 to 3 times IQR below Q1 |
5450 | int high_mild = 0; // 1.5 to 3 times IQR above Q3 |
5451 | int high_severe = 0; // more than 3 times IQR above Q3 |
5452 | |
5453 | int total() const { |
5454 | return low_severe + low_mild + high_mild + high_severe; |
5455 | } |
5456 | }; |
5457 | } // namespace Benchmark |
5458 | } // namespace Catch |
5459 | |
5460 | // end catch_outlier_classification.hpp |
5461 | |
5462 | #include <iterator> |
5463 | #endif // CATCH_CONFIG_ENABLE_BENCHMARKING |
5464 | |
5465 | #include <string> |
5466 | #include <iosfwd> |
5467 | #include <map> |
5468 | #include <set> |
5469 | #include <memory> |
5470 | #include <algorithm> |
5471 | |
5472 | namespace Catch { |
5473 | |
5474 | struct ReporterConfig { |
5475 | explicit ReporterConfig( IConfigPtr const& _fullConfig ); |
5476 | |
5477 | ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream ); |
5478 | |
5479 | std::ostream& stream() const; |
5480 | IConfigPtr fullConfig() const; |
5481 | |
5482 | private: |
5483 | std::ostream* m_stream; |
5484 | IConfigPtr m_fullConfig; |
5485 | }; |
5486 | |
5487 | struct ReporterPreferences { |
5488 | bool shouldRedirectStdOut = false; |
5489 | bool shouldReportAllAssertions = false; |
5490 | }; |
5491 | |
5492 | template<typename T> |
5493 | struct LazyStat : Option<T> { |
5494 | LazyStat& operator=( T const& _value ) { |
5495 | Option<T>::operator=( _value ); |
5496 | used = false; |
5497 | return *this; |
5498 | } |
5499 | void reset() { |
5500 | Option<T>::reset(); |
5501 | used = false; |
5502 | } |
5503 | bool used = false; |
5504 | }; |
5505 | |
5506 | struct TestRunInfo { |
5507 | TestRunInfo( std::string const& _name ); |
5508 | std::string name; |
5509 | }; |
5510 | struct GroupInfo { |
5511 | GroupInfo( std::string const& _name, |
5512 | std::size_t _groupIndex, |
5513 | std::size_t _groupsCount ); |
5514 | |
5515 | std::string name; |
5516 | std::size_t groupIndex; |
5517 | std::size_t groupsCounts; |
5518 | }; |
5519 | |
5520 | struct AssertionStats { |
5521 | AssertionStats( AssertionResult const& _assertionResult, |
5522 | std::vector<MessageInfo> const& _infoMessages, |
5523 | Totals const& _totals ); |
5524 | |
5525 | AssertionStats( AssertionStats const& ) = default; |
5526 | AssertionStats( AssertionStats && ) = default; |
5527 | AssertionStats& operator = ( AssertionStats const& ) = delete; |
5528 | AssertionStats& operator = ( AssertionStats && ) = delete; |
5529 | virtual ~AssertionStats(); |
5530 | |
5531 | AssertionResult assertionResult; |
5532 | std::vector<MessageInfo> infoMessages; |
5533 | Totals totals; |
5534 | }; |
5535 | |
5536 | struct SectionStats { |
5537 | SectionStats( SectionInfo const& _sectionInfo, |
5538 | Counts const& _assertions, |
5539 | double _durationInSeconds, |
5540 | bool _missingAssertions ); |
5541 | SectionStats( SectionStats const& ) = default; |
5542 | SectionStats( SectionStats && ) = default; |
5543 | SectionStats& operator = ( SectionStats const& ) = default; |
5544 | SectionStats& operator = ( SectionStats && ) = default; |
5545 | virtual ~SectionStats(); |
5546 | |
5547 | SectionInfo sectionInfo; |
5548 | Counts assertions; |
5549 | double durationInSeconds; |
5550 | bool missingAssertions; |
5551 | }; |
5552 | |
5553 | struct TestCaseStats { |
5554 | TestCaseStats( TestCaseInfo const& _testInfo, |
5555 | Totals const& _totals, |
5556 | std::string const& _stdOut, |
5557 | std::string const& _stdErr, |
5558 | bool _aborting ); |
5559 | |
5560 | TestCaseStats( TestCaseStats const& ) = default; |
5561 | TestCaseStats( TestCaseStats && ) = default; |
5562 | TestCaseStats& operator = ( TestCaseStats const& ) = default; |
5563 | TestCaseStats& operator = ( TestCaseStats && ) = default; |
5564 | virtual ~TestCaseStats(); |
5565 | |
5566 | TestCaseInfo testInfo; |
5567 | Totals totals; |
5568 | std::string stdOut; |
5569 | std::string stdErr; |
5570 | bool aborting; |
5571 | }; |
5572 | |
5573 | struct TestGroupStats { |
5574 | TestGroupStats( GroupInfo const& _groupInfo, |
5575 | Totals const& _totals, |
5576 | bool _aborting ); |
5577 | TestGroupStats( GroupInfo const& _groupInfo ); |
5578 | |
5579 | TestGroupStats( TestGroupStats const& ) = default; |
5580 | TestGroupStats( TestGroupStats && ) = default; |
5581 | TestGroupStats& operator = ( TestGroupStats const& ) = default; |
5582 | TestGroupStats& operator = ( TestGroupStats && ) = default; |
5583 | virtual ~TestGroupStats(); |
5584 | |
5585 | GroupInfo groupInfo; |
5586 | Totals totals; |
5587 | bool aborting; |
5588 | }; |
5589 | |
5590 | struct TestRunStats { |
5591 | TestRunStats( TestRunInfo const& _runInfo, |
5592 | Totals const& _totals, |
5593 | bool _aborting ); |
5594 | |
5595 | TestRunStats( TestRunStats const& ) = default; |
5596 | TestRunStats( TestRunStats && ) = default; |
5597 | TestRunStats& operator = ( TestRunStats const& ) = default; |
5598 | TestRunStats& operator = ( TestRunStats && ) = default; |
5599 | virtual ~TestRunStats(); |
5600 | |
5601 | TestRunInfo runInfo; |
5602 | Totals totals; |
5603 | bool aborting; |
5604 | }; |
5605 | |
5606 | #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) |
5607 | struct BenchmarkInfo { |
5608 | std::string name; |
5609 | double estimatedDuration; |
5610 | int iterations; |
5611 | int samples; |
5612 | unsigned int resamples; |
5613 | double clockResolution; |
5614 | double clockCost; |
5615 | }; |
5616 | |
5617 | template <class Duration> |
5618 | struct BenchmarkStats { |
5619 | BenchmarkInfo info; |
5620 | |
5621 | std::vector<Duration> samples; |
5622 | Benchmark::Estimate<Duration> mean; |
5623 | Benchmark::Estimate<Duration> standardDeviation; |
5624 | Benchmark::OutlierClassification outliers; |
5625 | double outlierVariance; |
5626 | |
5627 | template <typename Duration2> |
5628 | operator BenchmarkStats<Duration2>() const { |
5629 | std::vector<Duration2> samples2; |
5630 | samples2.reserve(samples.size()); |
5631 | std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](Duration d) { return Duration2(d); }); |
5632 | return { |
5633 | info, |
5634 | std::move(samples2), |
5635 | mean, |
5636 | standardDeviation, |
5637 | outliers, |
5638 | outlierVariance, |
5639 | }; |
5640 | } |
5641 | }; |
5642 | #endif // CATCH_CONFIG_ENABLE_BENCHMARKING |
5643 | |
5644 | struct IStreamingReporter { |
5645 | virtual ~IStreamingReporter() = default; |
5646 | |
5647 | // Implementing class must also provide the following static methods: |
5648 | // static std::string getDescription(); |
5649 | // static std::set<Verbosity> getSupportedVerbosities() |
5650 | |
5651 | virtual ReporterPreferences getPreferences() const = 0; |
5652 | |
5653 | virtual void noMatchingTestCases( std::string const& spec ) = 0; |
5654 | |
5655 | virtual void reportInvalidArguments(std::string const&) {} |
5656 | |
5657 | virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; |
5658 | virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0; |
5659 | |
5660 | virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; |
5661 | virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; |
5662 | |
5663 | #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) |
5664 | virtual void benchmarkPreparing( std::string const& ) {} |
5665 | virtual void benchmarkStarting( BenchmarkInfo const& ) {} |
5666 | virtual void benchmarkEnded( BenchmarkStats<> const& ) {} |
5667 | virtual void benchmarkFailed( std::string const& ) {} |
5668 | #endif // CATCH_CONFIG_ENABLE_BENCHMARKING |
5669 | |
5670 | virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; |
5671 | |
5672 | // The return value indicates if the messages buffer should be cleared: |
5673 | virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; |
5674 | |
5675 | virtual void sectionEnded( SectionStats const& sectionStats ) = 0; |
5676 | virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; |
5677 | virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; |
5678 | virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; |
5679 | |
5680 | virtual void skipTest( TestCaseInfo const& testInfo ) = 0; |
5681 | |
5682 | // Default empty implementation provided |
5683 | virtual void fatalErrorEncountered( StringRef name ); |
5684 | |
5685 | virtual bool isMulti() const; |
5686 | }; |
5687 | using IStreamingReporterPtr = std::unique_ptr<IStreamingReporter>; |
5688 | |
5689 | struct IReporterFactory { |
5690 | virtual ~IReporterFactory(); |
5691 | virtual IStreamingReporterPtr create( ReporterConfig const& config ) const = 0; |
5692 | virtual std::string getDescription() const = 0; |
5693 | }; |
5694 | using IReporterFactoryPtr = std::shared_ptr<IReporterFactory>; |
5695 | |
5696 | struct IReporterRegistry { |
5697 | using FactoryMap = std::map<std::string, IReporterFactoryPtr>; |
5698 | using Listeners = std::vector<IReporterFactoryPtr>; |
5699 | |
5700 | virtual ~IReporterRegistry(); |
5701 | virtual IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const = 0; |
5702 | virtual FactoryMap const& getFactories() const = 0; |
5703 | virtual Listeners const& getListeners() const = 0; |
5704 | }; |
5705 | |
5706 | } // end namespace Catch |
5707 | |
5708 | // end catch_interfaces_reporter.h |
5709 | #include <algorithm> |
5710 | #include <cstring> |
5711 | #include <cfloat> |
5712 | #include <cstdio> |
5713 | #include <cassert> |
5714 | #include <memory> |
5715 | #include <ostream> |
5716 | |
5717 | namespace Catch { |
5718 | void prepareExpandedExpression(AssertionResult& result); |
5719 | |
5720 | // Returns double formatted as %.3f (format expected on output) |
5721 | std::string getFormattedDuration( double duration ); |
5722 | |
5723 | //! Should the reporter show |
5724 | bool shouldShowDuration( IConfig const& config, double duration ); |
5725 | |
5726 | std::string serializeFilters( std::vector<std::string> const& container ); |
5727 | |
5728 | template<typename DerivedT> |
5729 | struct StreamingReporterBase : IStreamingReporter { |
5730 | |
5731 | StreamingReporterBase( ReporterConfig const& _config ) |
5732 | : m_config( _config.fullConfig() ), |
5733 | stream( _config.stream() ) |
5734 | { |
5735 | m_reporterPrefs.shouldRedirectStdOut = false; |
5736 | if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) ) |
5737 | CATCH_ERROR( "Verbosity level not supported by this reporter" ); |
5738 | } |
5739 | |
5740 | ReporterPreferences getPreferences() const override { |
5741 | return m_reporterPrefs; |
5742 | } |
5743 | |
5744 | static std::set<Verbosity> getSupportedVerbosities() { |
5745 | return { Verbosity::Normal }; |
5746 | } |
5747 | |
5748 | ~StreamingReporterBase() override = default; |
5749 | |
5750 | void noMatchingTestCases(std::string const&) override {} |
5751 | |
5752 | void reportInvalidArguments(std::string const&) override {} |
5753 | |
5754 | void testRunStarting(TestRunInfo const& _testRunInfo) override { |
5755 | currentTestRunInfo = _testRunInfo; |
5756 | } |
5757 | |
5758 | void testGroupStarting(GroupInfo const& _groupInfo) override { |
5759 | currentGroupInfo = _groupInfo; |
5760 | } |
5761 | |
5762 | void testCaseStarting(TestCaseInfo const& _testInfo) override { |
5763 | currentTestCaseInfo = _testInfo; |
5764 | } |
5765 | void sectionStarting(SectionInfo const& _sectionInfo) override { |
5766 | m_sectionStack.push_back(_sectionInfo); |
5767 | } |
5768 | |
5769 | void sectionEnded(SectionStats const& /* _sectionStats */) override { |
5770 | m_sectionStack.pop_back(); |
5771 | } |
5772 | void testCaseEnded(TestCaseStats const& /* _testCaseStats */) override { |
5773 | currentTestCaseInfo.reset(); |
5774 | } |
5775 | void testGroupEnded(TestGroupStats const& /* _testGroupStats */) override { |
5776 | currentGroupInfo.reset(); |
5777 | } |
5778 | void testRunEnded(TestRunStats const& /* _testRunStats */) override { |
5779 | currentTestCaseInfo.reset(); |
5780 | currentGroupInfo.reset(); |
5781 | currentTestRunInfo.reset(); |
5782 | } |
5783 | |
5784 | void skipTest(TestCaseInfo const&) override { |
5785 | // Don't do anything with this by default. |
5786 | // It can optionally be overridden in the derived class. |
5787 | } |
5788 | |
5789 | IConfigPtr m_config; |
5790 | std::ostream& stream; |
5791 | |
5792 | LazyStat<TestRunInfo> currentTestRunInfo; |
5793 | LazyStat<GroupInfo> currentGroupInfo; |
5794 | LazyStat<TestCaseInfo> currentTestCaseInfo; |
5795 | |
5796 | std::vector<SectionInfo> m_sectionStack; |
5797 | ReporterPreferences m_reporterPrefs; |
5798 | }; |
5799 | |
5800 | template<typename DerivedT> |
5801 | struct CumulativeReporterBase : IStreamingReporter { |
5802 | template<typename T, typename ChildNodeT> |
5803 | struct Node { |
5804 | explicit Node( T const& _value ) : value( _value ) {} |
5805 | virtual ~Node() {} |
5806 | |
5807 | using ChildNodes = std::vector<std::shared_ptr<ChildNodeT>>; |
5808 | T value; |
5809 | ChildNodes children; |
5810 | }; |
5811 | struct SectionNode { |
5812 | explicit SectionNode(SectionStats const& _stats) : stats(_stats) {} |
5813 | virtual ~SectionNode() = default; |
5814 | |
5815 | bool operator == (SectionNode const& other) const { |
5816 | return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo; |
5817 | } |
5818 | bool operator == (std::shared_ptr<SectionNode> const& other) const { |
5819 | return operator==(*other); |
5820 | } |
5821 | |
5822 | SectionStats stats; |
5823 | using ChildSections = std::vector<std::shared_ptr<SectionNode>>; |
5824 | using Assertions = std::vector<AssertionStats>; |
5825 | ChildSections childSections; |
5826 | Assertions assertions; |
5827 | std::string stdOut; |
5828 | std::string stdErr; |
5829 | }; |
5830 | |
5831 | struct BySectionInfo { |
5832 | BySectionInfo( SectionInfo const& other ) : m_other( other ) {} |
5833 | BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} |
5834 | bool operator() (std::shared_ptr<SectionNode> const& node) const { |
5835 | return ((node->stats.sectionInfo.name == m_other.name) && |
5836 | (node->stats.sectionInfo.lineInfo == m_other.lineInfo)); |
5837 | } |
5838 | void operator=(BySectionInfo const&) = delete; |
5839 | |
5840 | private: |
5841 | SectionInfo const& m_other; |
5842 | }; |
5843 | |
5844 | using TestCaseNode = Node<TestCaseStats, SectionNode>; |
5845 | using TestGroupNode = Node<TestGroupStats, TestCaseNode>; |
5846 | using TestRunNode = Node<TestRunStats, TestGroupNode>; |
5847 | |
5848 | CumulativeReporterBase( ReporterConfig const& _config ) |
5849 | : m_config( _config.fullConfig() ), |
5850 | stream( _config.stream() ) |
5851 | { |
5852 | m_reporterPrefs.shouldRedirectStdOut = false; |
5853 | if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) ) |
5854 | CATCH_ERROR( "Verbosity level not supported by this reporter" ); |
5855 | } |
5856 | ~CumulativeReporterBase() override = default; |
5857 | |
5858 | ReporterPreferences getPreferences() const override { |
5859 | return m_reporterPrefs; |
5860 | } |
5861 | |
5862 | static std::set<Verbosity> getSupportedVerbosities() { |
5863 | return { Verbosity::Normal }; |
5864 | } |
5865 | |
5866 | void testRunStarting( TestRunInfo const& ) override {} |
5867 | void testGroupStarting( GroupInfo const& ) override {} |
5868 | |
5869 | void testCaseStarting( TestCaseInfo const& ) override {} |
5870 | |
5871 | void sectionStarting( SectionInfo const& sectionInfo ) override { |
5872 | SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); |
5873 | std::shared_ptr<SectionNode> node; |
5874 | if( m_sectionStack.empty() ) { |
5875 | if( !m_rootSection ) |
5876 | m_rootSection = std::make_shared<SectionNode>( incompleteStats ); |
5877 | node = m_rootSection; |
5878 | } |
5879 | else { |
5880 | SectionNode& parentNode = *m_sectionStack.back(); |
5881 | auto it = |
5882 | std::find_if( parentNode.childSections.begin(), |
5883 | parentNode.childSections.end(), |
5884 | BySectionInfo( sectionInfo ) ); |
5885 | if( it == parentNode.childSections.end() ) { |
5886 | node = std::make_shared<SectionNode>( incompleteStats ); |
5887 | parentNode.childSections.push_back( node ); |
5888 | } |
5889 | else |
5890 | node = *it; |
5891 | } |
5892 | m_sectionStack.push_back( node ); |
5893 | m_deepestSection = std::move(node); |
5894 | } |
5895 | |
5896 | void assertionStarting(AssertionInfo const&) override {} |
5897 | |
5898 | bool assertionEnded(AssertionStats const& assertionStats) override { |
5899 | assert(!m_sectionStack.empty()); |
5900 | // AssertionResult holds a pointer to a temporary DecomposedExpression, |
5901 | // which getExpandedExpression() calls to build the expression string. |
5902 | // Our section stack copy of the assertionResult will likely outlive the |
5903 | // temporary, so it must be expanded or discarded now to avoid calling |
5904 | // a destroyed object later. |
5905 | prepareExpandedExpression(const_cast<AssertionResult&>( assertionStats.assertionResult ) ); |
5906 | SectionNode& sectionNode = *m_sectionStack.back(); |
5907 | sectionNode.assertions.push_back(assertionStats); |
5908 | return true; |
5909 | } |
5910 | void sectionEnded(SectionStats const& sectionStats) override { |
5911 | assert(!m_sectionStack.empty()); |
5912 | SectionNode& node = *m_sectionStack.back(); |
5913 | node.stats = sectionStats; |
5914 | m_sectionStack.pop_back(); |
5915 | } |
5916 | void testCaseEnded(TestCaseStats const& testCaseStats) override { |
5917 | auto node = std::make_shared<TestCaseNode>(testCaseStats); |
5918 | assert(m_sectionStack.size() == 0); |
5919 | node->children.push_back(m_rootSection); |
5920 | m_testCases.push_back(node); |
5921 | m_rootSection.reset(); |
5922 | |
5923 | assert(m_deepestSection); |
5924 | m_deepestSection->stdOut = testCaseStats.stdOut; |
5925 | m_deepestSection->stdErr = testCaseStats.stdErr; |
5926 | } |
5927 | void testGroupEnded(TestGroupStats const& testGroupStats) override { |
5928 | auto node = std::make_shared<TestGroupNode>(testGroupStats); |
5929 | node->children.swap(m_testCases); |
5930 | m_testGroups.push_back(node); |
5931 | } |
5932 | void testRunEnded(TestRunStats const& testRunStats) override { |
5933 | auto node = std::make_shared<TestRunNode>(testRunStats); |
5934 | node->children.swap(m_testGroups); |
5935 | m_testRuns.push_back(node); |
5936 | testRunEndedCumulative(); |
5937 | } |
5938 | virtual void testRunEndedCumulative() = 0; |
5939 | |
5940 | void skipTest(TestCaseInfo const&) override {} |
5941 | |
5942 | IConfigPtr m_config; |
5943 | std::ostream& stream; |
5944 | std::vector<AssertionStats> m_assertions; |
5945 | std::vector<std::vector<std::shared_ptr<SectionNode>>> m_sections; |
5946 | std::vector<std::shared_ptr<TestCaseNode>> m_testCases; |
5947 | std::vector<std::shared_ptr<TestGroupNode>> m_testGroups; |
5948 | |
5949 | std::vector<std::shared_ptr<TestRunNode>> m_testRuns; |
5950 | |
5951 | std::shared_ptr<SectionNode> m_rootSection; |
5952 | std::shared_ptr<SectionNode> m_deepestSection; |
5953 | std::vector<std::shared_ptr<SectionNode>> m_sectionStack; |
5954 | ReporterPreferences m_reporterPrefs; |
5955 | }; |
5956 | |
5957 | template<char C> |
5958 | char const* getLineOfChars() { |
5959 | static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; |
5960 | if( !*line ) { |
5961 | std::memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); |
5962 | line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; |
5963 | } |
5964 | return line; |
5965 | } |
5966 | |
5967 | struct TestEventListenerBase : StreamingReporterBase<TestEventListenerBase> { |
5968 | TestEventListenerBase( ReporterConfig const& _config ); |
5969 | |
5970 | static std::set<Verbosity> getSupportedVerbosities(); |
5971 | |
5972 | void assertionStarting(AssertionInfo const&) override; |
5973 | bool assertionEnded(AssertionStats const&) override; |
5974 | }; |
5975 | |
5976 | } // end namespace Catch |
5977 | |
5978 | // end catch_reporter_bases.hpp |
5979 | // start catch_console_colour.h |
5980 | |
5981 | namespace Catch { |
5982 | |
5983 | struct Colour { |
5984 | enum Code { |
5985 | None = 0, |
5986 | |
5987 | White, |
5988 | Red, |
5989 | Green, |
5990 | Blue, |
5991 | Cyan, |
5992 | Yellow, |
5993 | Grey, |
5994 | |
5995 | Bright = 0x10, |
5996 | |
5997 | BrightRed = Bright | Red, |
5998 | BrightGreen = Bright | Green, |
5999 | LightGrey = Bright | Grey, |
6000 | BrightWhite = Bright | White, |
6001 | BrightYellow = Bright | Yellow, |
6002 | |
6003 | // By intention |
6004 | FileName = LightGrey, |
6005 | Warning = BrightYellow, |
6006 | ResultError = BrightRed, |
6007 | ResultSuccess = BrightGreen, |
6008 | ResultExpectedFailure = Warning, |
6009 | |
6010 | Error = BrightRed, |
6011 | Success = Green, |
6012 | |
6013 | OriginalExpression = Cyan, |
6014 | ReconstructedExpression = BrightYellow, |
6015 | |
6016 | SecondaryText = LightGrey, |
6017 | = White |
6018 | }; |
6019 | |
6020 | // Use constructed object for RAII guard |
6021 | Colour( Code _colourCode ); |
6022 | Colour( Colour&& other ) noexcept; |
6023 | Colour& operator=( Colour&& other ) noexcept; |
6024 | ~Colour(); |
6025 | |
6026 | // Use static method for one-shot changes |
6027 | static void use( Code _colourCode ); |
6028 | |
6029 | private: |
6030 | bool m_moved = false; |
6031 | }; |
6032 | |
6033 | std::ostream& operator << ( std::ostream& os, Colour const& ); |
6034 | |
6035 | } // end namespace Catch |
6036 | |
6037 | // end catch_console_colour.h |
6038 | // start catch_reporter_registrars.hpp |
6039 | |
6040 | |
6041 | namespace Catch { |
6042 | |
6043 | template<typename T> |
6044 | class ReporterRegistrar { |
6045 | |
6046 | class ReporterFactory : public IReporterFactory { |
6047 | |
6048 | IStreamingReporterPtr create( ReporterConfig const& config ) const override { |
6049 | return std::unique_ptr<T>( new T( config ) ); |
6050 | } |
6051 | |
6052 | std::string getDescription() const override { |
6053 | return T::getDescription(); |
6054 | } |
6055 | }; |
6056 | |
6057 | public: |
6058 | |
6059 | explicit ReporterRegistrar( std::string const& name ) { |
6060 | getMutableRegistryHub().registerReporter( name, std::make_shared<ReporterFactory>() ); |
6061 | } |
6062 | }; |
6063 | |
6064 | template<typename T> |
6065 | class ListenerRegistrar { |
6066 | |
6067 | class ListenerFactory : public IReporterFactory { |
6068 | |
6069 | IStreamingReporterPtr create( ReporterConfig const& config ) const override { |
6070 | return std::unique_ptr<T>( new T( config ) ); |
6071 | } |
6072 | std::string getDescription() const override { |
6073 | return std::string(); |
6074 | } |
6075 | }; |
6076 | |
6077 | public: |
6078 | |
6079 | ListenerRegistrar() { |
6080 | getMutableRegistryHub().registerListener( std::make_shared<ListenerFactory>() ); |
6081 | } |
6082 | }; |
6083 | } |
6084 | |
6085 | #if !defined(CATCH_CONFIG_DISABLE) |
6086 | |
6087 | #define CATCH_REGISTER_REPORTER( name, reporterType ) \ |
6088 | CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ |
6089 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ |
6090 | namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); } \ |
6091 | CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION |
6092 | |
6093 | #define CATCH_REGISTER_LISTENER( listenerType ) \ |
6094 | CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ |
6095 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ |
6096 | namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; } \ |
6097 | CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION |
6098 | #else // CATCH_CONFIG_DISABLE |
6099 | |
6100 | #define CATCH_REGISTER_REPORTER(name, reporterType) |
6101 | #define CATCH_REGISTER_LISTENER(listenerType) |
6102 | |
6103 | #endif // CATCH_CONFIG_DISABLE |
6104 | |
6105 | // end catch_reporter_registrars.hpp |
6106 | // Allow users to base their work off existing reporters |
6107 | // start catch_reporter_compact.h |
6108 | |
6109 | namespace Catch { |
6110 | |
6111 | struct CompactReporter : StreamingReporterBase<CompactReporter> { |
6112 | |
6113 | using StreamingReporterBase::StreamingReporterBase; |
6114 | |
6115 | ~CompactReporter() override; |
6116 | |
6117 | static std::string getDescription(); |
6118 | |
6119 | void noMatchingTestCases(std::string const& spec) override; |
6120 | |
6121 | void assertionStarting(AssertionInfo const&) override; |
6122 | |
6123 | bool assertionEnded(AssertionStats const& _assertionStats) override; |
6124 | |
6125 | void sectionEnded(SectionStats const& _sectionStats) override; |
6126 | |
6127 | void testRunEnded(TestRunStats const& _testRunStats) override; |
6128 | |
6129 | }; |
6130 | |
6131 | } // end namespace Catch |
6132 | |
6133 | // end catch_reporter_compact.h |
6134 | // start catch_reporter_console.h |
6135 | |
6136 | #if defined(_MSC_VER) |
6137 | #pragma warning(push) |
6138 | #pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch |
6139 | // Note that 4062 (not all labels are handled |
6140 | // and default is missing) is enabled |
6141 | #endif |
6142 | |
6143 | namespace Catch { |
6144 | // Fwd decls |
6145 | struct SummaryColumn; |
6146 | class TablePrinter; |
6147 | |
6148 | struct ConsoleReporter : StreamingReporterBase<ConsoleReporter> { |
6149 | std::unique_ptr<TablePrinter> m_tablePrinter; |
6150 | |
6151 | ConsoleReporter(ReporterConfig const& config); |
6152 | ~ConsoleReporter() override; |
6153 | static std::string getDescription(); |
6154 | |
6155 | void noMatchingTestCases(std::string const& spec) override; |
6156 | |
6157 | void reportInvalidArguments(std::string const&arg) override; |
6158 | |
6159 | void assertionStarting(AssertionInfo const&) override; |
6160 | |
6161 | bool assertionEnded(AssertionStats const& _assertionStats) override; |
6162 | |
6163 | void sectionStarting(SectionInfo const& _sectionInfo) override; |
6164 | void sectionEnded(SectionStats const& _sectionStats) override; |
6165 | |
6166 | #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) |
6167 | void benchmarkPreparing(std::string const& name) override; |
6168 | void benchmarkStarting(BenchmarkInfo const& info) override; |
6169 | void benchmarkEnded(BenchmarkStats<> const& stats) override; |
6170 | void benchmarkFailed(std::string const& error) override; |
6171 | #endif // CATCH_CONFIG_ENABLE_BENCHMARKING |
6172 | |
6173 | void testCaseEnded(TestCaseStats const& _testCaseStats) override; |
6174 | void testGroupEnded(TestGroupStats const& _testGroupStats) override; |
6175 | void testRunEnded(TestRunStats const& _testRunStats) override; |
6176 | void testRunStarting(TestRunInfo const& _testRunInfo) override; |
6177 | private: |
6178 | |
6179 | void lazyPrint(); |
6180 | |
6181 | void lazyPrintWithoutClosingBenchmarkTable(); |
6182 | void lazyPrintRunInfo(); |
6183 | void lazyPrintGroupInfo(); |
6184 | void printTestCaseAndSectionHeader(); |
6185 | |
6186 | void (std::string const& _name); |
6187 | void (std::string const& _name); |
6188 | |
6189 | // if string has a : in first line will set indent to follow it on |
6190 | // subsequent lines |
6191 | void (std::string const& _string, std::size_t indent = 0); |
6192 | |
6193 | void printTotals(Totals const& totals); |
6194 | void printSummaryRow(std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row); |
6195 | |
6196 | void printTotalsDivider(Totals const& totals); |
6197 | void printSummaryDivider(); |
6198 | void printTestFilters(); |
6199 | |
6200 | private: |
6201 | bool = false; |
6202 | }; |
6203 | |
6204 | } // end namespace Catch |
6205 | |
6206 | #if defined(_MSC_VER) |
6207 | #pragma warning(pop) |
6208 | #endif |
6209 | |
6210 | // end catch_reporter_console.h |
6211 | // start catch_reporter_junit.h |
6212 | |
6213 | // start catch_xmlwriter.h |
6214 | |
6215 | #include <vector> |
6216 | |
6217 | namespace Catch { |
6218 | enum class XmlFormatting { |
6219 | None = 0x00, |
6220 | Indent = 0x01, |
6221 | Newline = 0x02, |
6222 | }; |
6223 | |
6224 | XmlFormatting operator | (XmlFormatting lhs, XmlFormatting rhs); |
6225 | XmlFormatting operator & (XmlFormatting lhs, XmlFormatting rhs); |
6226 | |
6227 | class XmlEncode { |
6228 | public: |
6229 | enum ForWhat { ForTextNodes, ForAttributes }; |
6230 | |
6231 | XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ); |
6232 | |
6233 | void encodeTo( std::ostream& os ) const; |
6234 | |
6235 | friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ); |
6236 | |
6237 | private: |
6238 | std::string m_str; |
6239 | ForWhat m_forWhat; |
6240 | }; |
6241 | |
6242 | class XmlWriter { |
6243 | public: |
6244 | |
6245 | class ScopedElement { |
6246 | public: |
6247 | ScopedElement( XmlWriter* writer, XmlFormatting fmt ); |
6248 | |
6249 | ScopedElement( ScopedElement&& other ) noexcept; |
6250 | ScopedElement& operator=( ScopedElement&& other ) noexcept; |
6251 | |
6252 | ~ScopedElement(); |
6253 | |
6254 | ScopedElement& writeText( std::string const& text, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent ); |
6255 | |
6256 | template<typename T> |
6257 | ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { |
6258 | m_writer->writeAttribute( name, attribute ); |
6259 | return *this; |
6260 | } |
6261 | |
6262 | private: |
6263 | mutable XmlWriter* m_writer = nullptr; |
6264 | XmlFormatting m_fmt; |
6265 | }; |
6266 | |
6267 | XmlWriter( std::ostream& os = Catch::cout() ); |
6268 | ~XmlWriter(); |
6269 | |
6270 | XmlWriter( XmlWriter const& ) = delete; |
6271 | XmlWriter& operator=( XmlWriter const& ) = delete; |
6272 | |
6273 | XmlWriter& startElement( std::string const& name, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent); |
6274 | |
6275 | ScopedElement scopedElement( std::string const& name, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent); |
6276 | |
6277 | XmlWriter& endElement(XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent); |
6278 | |
6279 | XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ); |
6280 | |
6281 | XmlWriter& writeAttribute( std::string const& name, bool attribute ); |
6282 | |
6283 | template<typename T> |
6284 | XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { |
6285 | ReusableStringStream ; |
6286 | rss << attribute; |
6287 | return writeAttribute( name, rss.str() ); |
6288 | } |
6289 | |
6290 | XmlWriter& writeText( std::string const& text, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent); |
6291 | |
6292 | XmlWriter& (std::string const& text, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent); |
6293 | |
6294 | void writeStylesheetRef( std::string const& url ); |
6295 | |
6296 | XmlWriter& writeBlankLine(); |
6297 | |
6298 | void ensureTagClosed(); |
6299 | |
6300 | private: |
6301 | |
6302 | void applyFormatting(XmlFormatting fmt); |
6303 | |
6304 | void writeDeclaration(); |
6305 | |
6306 | void newlineIfNecessary(); |
6307 | |
6308 | bool m_tagIsOpen = false; |
6309 | bool m_needsNewline = false; |
6310 | std::vector<std::string> m_tags; |
6311 | std::string m_indent; |
6312 | std::ostream& m_os; |
6313 | }; |
6314 | |
6315 | } |
6316 | |
6317 | // end catch_xmlwriter.h |
6318 | namespace Catch { |
6319 | |
6320 | class JunitReporter : public CumulativeReporterBase<JunitReporter> { |
6321 | public: |
6322 | JunitReporter(ReporterConfig const& _config); |
6323 | |
6324 | ~JunitReporter() override; |
6325 | |
6326 | static std::string getDescription(); |
6327 | |
6328 | void noMatchingTestCases(std::string const& /*spec*/) override; |
6329 | |
6330 | void testRunStarting(TestRunInfo const& runInfo) override; |
6331 | |
6332 | void testGroupStarting(GroupInfo const& groupInfo) override; |
6333 | |
6334 | void testCaseStarting(TestCaseInfo const& testCaseInfo) override; |
6335 | bool assertionEnded(AssertionStats const& assertionStats) override; |
6336 | |
6337 | void testCaseEnded(TestCaseStats const& testCaseStats) override; |
6338 | |
6339 | void testGroupEnded(TestGroupStats const& testGroupStats) override; |
6340 | |
6341 | void testRunEndedCumulative() override; |
6342 | |
6343 | void writeGroup(TestGroupNode const& groupNode, double suiteTime); |
6344 | |
6345 | void writeTestCase(TestCaseNode const& testCaseNode); |
6346 | |
6347 | void writeSection( std::string const& className, |
6348 | std::string const& rootName, |
6349 | SectionNode const& sectionNode, |
6350 | bool testOkToFail ); |
6351 | |
6352 | void writeAssertions(SectionNode const& sectionNode); |
6353 | void writeAssertion(AssertionStats const& stats); |
6354 | |
6355 | XmlWriter xml; |
6356 | Timer suiteTimer; |
6357 | std::string stdOutForSuite; |
6358 | std::string stdErrForSuite; |
6359 | unsigned int unexpectedExceptions = 0; |
6360 | bool m_okToFail = false; |
6361 | }; |
6362 | |
6363 | } // end namespace Catch |
6364 | |
6365 | // end catch_reporter_junit.h |
6366 | // start catch_reporter_xml.h |
6367 | |
6368 | namespace Catch { |
6369 | class XmlReporter : public StreamingReporterBase<XmlReporter> { |
6370 | public: |
6371 | XmlReporter(ReporterConfig const& _config); |
6372 | |
6373 | ~XmlReporter() override; |
6374 | |
6375 | static std::string getDescription(); |
6376 | |
6377 | virtual std::string getStylesheetRef() const; |
6378 | |
6379 | void writeSourceInfo(SourceLineInfo const& sourceInfo); |
6380 | |
6381 | public: // StreamingReporterBase |
6382 | |
6383 | void noMatchingTestCases(std::string const& s) override; |
6384 | |
6385 | void testRunStarting(TestRunInfo const& testInfo) override; |
6386 | |
6387 | void testGroupStarting(GroupInfo const& groupInfo) override; |
6388 | |
6389 | void testCaseStarting(TestCaseInfo const& testInfo) override; |
6390 | |
6391 | void sectionStarting(SectionInfo const& sectionInfo) override; |
6392 | |
6393 | void assertionStarting(AssertionInfo const&) override; |
6394 | |
6395 | bool assertionEnded(AssertionStats const& assertionStats) override; |
6396 | |
6397 | void sectionEnded(SectionStats const& sectionStats) override; |
6398 | |
6399 | void testCaseEnded(TestCaseStats const& testCaseStats) override; |
6400 | |
6401 | void testGroupEnded(TestGroupStats const& testGroupStats) override; |
6402 | |
6403 | void testRunEnded(TestRunStats const& testRunStats) override; |
6404 | |
6405 | #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) |
6406 | void benchmarkPreparing(std::string const& name) override; |
6407 | void benchmarkStarting(BenchmarkInfo const&) override; |
6408 | void benchmarkEnded(BenchmarkStats<> const&) override; |
6409 | void benchmarkFailed(std::string const&) override; |
6410 | #endif // CATCH_CONFIG_ENABLE_BENCHMARKING |
6411 | |
6412 | private: |
6413 | Timer m_testCaseTimer; |
6414 | XmlWriter m_xml; |
6415 | int m_sectionDepth = 0; |
6416 | }; |
6417 | |
6418 | } // end namespace Catch |
6419 | |
6420 | // end catch_reporter_xml.h |
6421 | |
6422 | // end catch_external_interfaces.h |
6423 | #endif |
6424 | |
6425 | #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) |
6426 | // start catch_benchmarking_all.hpp |
6427 | |
6428 | // A proxy header that includes all of the benchmarking headers to allow |
6429 | // concise include of the benchmarking features. You should prefer the |
6430 | // individual includes in standard use. |
6431 | |
6432 | // start catch_benchmark.hpp |
6433 | |
6434 | // Benchmark |
6435 | |
6436 | // start catch_chronometer.hpp |
6437 | |
6438 | // User-facing chronometer |
6439 | |
6440 | |
6441 | // start catch_clock.hpp |
6442 | |
6443 | // Clocks |
6444 | |
6445 | |
6446 | #include <chrono> |
6447 | #include <ratio> |
6448 | |
6449 | namespace Catch { |
6450 | namespace Benchmark { |
6451 | template <typename Clock> |
6452 | using ClockDuration = typename Clock::duration; |
6453 | template <typename Clock> |
6454 | using FloatDuration = std::chrono::duration<double, typename Clock::period>; |
6455 | |
6456 | template <typename Clock> |
6457 | using TimePoint = typename Clock::time_point; |
6458 | |
6459 | using default_clock = std::chrono::steady_clock; |
6460 | |
6461 | template <typename Clock> |
6462 | struct now { |
6463 | TimePoint<Clock> operator()() const { |
6464 | return Clock::now(); |
6465 | } |
6466 | }; |
6467 | |
6468 | using fp_seconds = std::chrono::duration<double, std::ratio<1>>; |
6469 | } // namespace Benchmark |
6470 | } // namespace Catch |
6471 | |
6472 | // end catch_clock.hpp |
6473 | // start catch_optimizer.hpp |
6474 | |
6475 | // Hinting the optimizer |
6476 | |
6477 | |
6478 | #if defined(_MSC_VER) |
6479 | # include <atomic> // atomic_thread_fence |
6480 | #endif |
6481 | |
6482 | namespace Catch { |
6483 | namespace Benchmark { |
6484 | #if defined(__GNUC__) || defined(__clang__) |
6485 | template <typename T> |
6486 | inline void keep_memory(T* p) { |
6487 | asm volatile("" : : "g" (p) : "memory" ); |
6488 | } |
6489 | inline void keep_memory() { |
6490 | asm volatile("" : : : "memory" ); |
6491 | } |
6492 | |
6493 | namespace Detail { |
6494 | inline void optimizer_barrier() { keep_memory(); } |
6495 | } // namespace Detail |
6496 | #elif defined(_MSC_VER) |
6497 | |
6498 | #pragma optimize("", off) |
6499 | template <typename T> |
6500 | inline void keep_memory(T* p) { |
6501 | // thanks @milleniumbug |
6502 | *reinterpret_cast<char volatile*>(p) = *reinterpret_cast<char const volatile*>(p); |
6503 | } |
6504 | // TODO equivalent keep_memory() |
6505 | #pragma optimize("", on) |
6506 | |
6507 | namespace Detail { |
6508 | inline void optimizer_barrier() { |
6509 | std::atomic_thread_fence(std::memory_order_seq_cst); |
6510 | } |
6511 | } // namespace Detail |
6512 | |
6513 | #endif |
6514 | |
6515 | template <typename T> |
6516 | inline void deoptimize_value(T&& x) { |
6517 | keep_memory(&x); |
6518 | } |
6519 | |
6520 | template <typename Fn, typename... Args> |
6521 | inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> typename std::enable_if<!std::is_same<void, decltype(fn(args...))>::value>::type { |
6522 | deoptimize_value(std::forward<Fn>(fn) (std::forward<Args...>(args...))); |
6523 | } |
6524 | |
6525 | template <typename Fn, typename... Args> |
6526 | inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> typename std::enable_if<std::is_same<void, decltype(fn(args...))>::value>::type { |
6527 | std::forward<Fn>(fn) (std::forward<Args...>(args...)); |
6528 | } |
6529 | } // namespace Benchmark |
6530 | } // namespace Catch |
6531 | |
6532 | // end catch_optimizer.hpp |
6533 | // start catch_complete_invoke.hpp |
6534 | |
6535 | // Invoke with a special case for void |
6536 | |
6537 | |
6538 | #include <type_traits> |
6539 | #include <utility> |
6540 | |
6541 | namespace Catch { |
6542 | namespace Benchmark { |
6543 | namespace Detail { |
6544 | template <typename T> |
6545 | struct CompleteType { using type = T; }; |
6546 | template <> |
6547 | struct CompleteType<void> { struct type {}; }; |
6548 | |
6549 | template <typename T> |
6550 | using CompleteType_t = typename CompleteType<T>::type; |
6551 | |
6552 | template <typename Result> |
6553 | struct CompleteInvoker { |
6554 | template <typename Fun, typename... Args> |
6555 | static Result invoke(Fun&& fun, Args&&... args) { |
6556 | return std::forward<Fun>(fun)(std::forward<Args>(args)...); |
6557 | } |
6558 | }; |
6559 | template <> |
6560 | struct CompleteInvoker<void> { |
6561 | template <typename Fun, typename... Args> |
6562 | static CompleteType_t<void> invoke(Fun&& fun, Args&&... args) { |
6563 | std::forward<Fun>(fun)(std::forward<Args>(args)...); |
6564 | return {}; |
6565 | } |
6566 | }; |
6567 | |
6568 | // invoke and not return void :( |
6569 | template <typename Fun, typename... Args> |
6570 | CompleteType_t<FunctionReturnType<Fun, Args...>> complete_invoke(Fun&& fun, Args&&... args) { |
6571 | return CompleteInvoker<FunctionReturnType<Fun, Args...>>::invoke(std::forward<Fun>(fun), std::forward<Args>(args)...); |
6572 | } |
6573 | |
6574 | const std::string benchmarkErrorMsg = "a benchmark failed to run successfully" ; |
6575 | } // namespace Detail |
6576 | |
6577 | template <typename Fun> |
6578 | Detail::CompleteType_t<FunctionReturnType<Fun>> user_code(Fun&& fun) { |
6579 | CATCH_TRY{ |
6580 | return Detail::complete_invoke(std::forward<Fun>(fun)); |
6581 | } CATCH_CATCH_ALL{ |
6582 | getResultCapture().benchmarkFailed(translateActiveException()); |
6583 | CATCH_RUNTIME_ERROR(Detail::benchmarkErrorMsg); |
6584 | } |
6585 | } |
6586 | } // namespace Benchmark |
6587 | } // namespace Catch |
6588 | |
6589 | // end catch_complete_invoke.hpp |
6590 | namespace Catch { |
6591 | namespace Benchmark { |
6592 | namespace Detail { |
6593 | struct ChronometerConcept { |
6594 | virtual void start() = 0; |
6595 | virtual void finish() = 0; |
6596 | virtual ~ChronometerConcept() = default; |
6597 | }; |
6598 | template <typename Clock> |
6599 | struct ChronometerModel final : public ChronometerConcept { |
6600 | void start() override { started = Clock::now(); } |
6601 | void finish() override { finished = Clock::now(); } |
6602 | |
6603 | ClockDuration<Clock> elapsed() const { return finished - started; } |
6604 | |
6605 | TimePoint<Clock> started; |
6606 | TimePoint<Clock> finished; |
6607 | }; |
6608 | } // namespace Detail |
6609 | |
6610 | struct Chronometer { |
6611 | public: |
6612 | template <typename Fun> |
6613 | void measure(Fun&& fun) { measure(std::forward<Fun>(fun), is_callable<Fun(int)>()); } |
6614 | |
6615 | int runs() const { return k; } |
6616 | |
6617 | Chronometer(Detail::ChronometerConcept& meter, int k) |
6618 | : impl(&meter) |
6619 | , k(k) {} |
6620 | |
6621 | private: |
6622 | template <typename Fun> |
6623 | void measure(Fun&& fun, std::false_type) { |
6624 | measure([&fun](int) { return fun(); }, std::true_type()); |
6625 | } |
6626 | |
6627 | template <typename Fun> |
6628 | void measure(Fun&& fun, std::true_type) { |
6629 | Detail::optimizer_barrier(); |
6630 | impl->start(); |
6631 | for (int i = 0; i < k; ++i) invoke_deoptimized(fun, i); |
6632 | impl->finish(); |
6633 | Detail::optimizer_barrier(); |
6634 | } |
6635 | |
6636 | Detail::ChronometerConcept* impl; |
6637 | int k; |
6638 | }; |
6639 | } // namespace Benchmark |
6640 | } // namespace Catch |
6641 | |
6642 | // end catch_chronometer.hpp |
6643 | // start catch_environment.hpp |
6644 | |
6645 | // Environment information |
6646 | |
6647 | |
6648 | namespace Catch { |
6649 | namespace Benchmark { |
6650 | template <typename Duration> |
6651 | struct EnvironmentEstimate { |
6652 | Duration mean; |
6653 | OutlierClassification outliers; |
6654 | |
6655 | template <typename Duration2> |
6656 | operator EnvironmentEstimate<Duration2>() const { |
6657 | return { mean, outliers }; |
6658 | } |
6659 | }; |
6660 | template <typename Clock> |
6661 | struct Environment { |
6662 | using clock_type = Clock; |
6663 | EnvironmentEstimate<FloatDuration<Clock>> clock_resolution; |
6664 | EnvironmentEstimate<FloatDuration<Clock>> clock_cost; |
6665 | }; |
6666 | } // namespace Benchmark |
6667 | } // namespace Catch |
6668 | |
6669 | // end catch_environment.hpp |
6670 | // start catch_execution_plan.hpp |
6671 | |
6672 | // Execution plan |
6673 | |
6674 | |
6675 | // start catch_benchmark_function.hpp |
6676 | |
6677 | // Dumb std::function implementation for consistent call overhead |
6678 | |
6679 | |
6680 | #include <cassert> |
6681 | #include <type_traits> |
6682 | #include <utility> |
6683 | #include <memory> |
6684 | |
6685 | namespace Catch { |
6686 | namespace Benchmark { |
6687 | namespace Detail { |
6688 | template <typename T> |
6689 | using Decay = typename std::decay<T>::type; |
6690 | template <typename T, typename U> |
6691 | struct is_related |
6692 | : std::is_same<Decay<T>, Decay<U>> {}; |
6693 | |
6694 | /// We need to reinvent std::function because every piece of code that might add overhead |
6695 | /// in a measurement context needs to have consistent performance characteristics so that we |
6696 | /// can account for it in the measurement. |
6697 | /// Implementations of std::function with optimizations that aren't always applicable, like |
6698 | /// small buffer optimizations, are not uncommon. |
6699 | /// This is effectively an implementation of std::function without any such optimizations; |
6700 | /// it may be slow, but it is consistently slow. |
6701 | struct BenchmarkFunction { |
6702 | private: |
6703 | struct callable { |
6704 | virtual void call(Chronometer meter) const = 0; |
6705 | virtual callable* clone() const = 0; |
6706 | virtual ~callable() = default; |
6707 | }; |
6708 | template <typename Fun> |
6709 | struct model : public callable { |
6710 | model(Fun&& fun) : fun(std::move(fun)) {} |
6711 | model(Fun const& fun) : fun(fun) {} |
6712 | |
6713 | model<Fun>* clone() const override { return new model<Fun>(*this); } |
6714 | |
6715 | void call(Chronometer meter) const override { |
6716 | call(meter, is_callable<Fun(Chronometer)>()); |
6717 | } |
6718 | void call(Chronometer meter, std::true_type) const { |
6719 | fun(meter); |
6720 | } |
6721 | void call(Chronometer meter, std::false_type) const { |
6722 | meter.measure(fun); |
6723 | } |
6724 | |
6725 | Fun fun; |
6726 | }; |
6727 | |
6728 | struct do_nothing { void operator()() const {} }; |
6729 | |
6730 | template <typename T> |
6731 | BenchmarkFunction(model<T>* c) : f(c) {} |
6732 | |
6733 | public: |
6734 | BenchmarkFunction() |
6735 | : f(new model<do_nothing>{ {} }) {} |
6736 | |
6737 | template <typename Fun, |
6738 | typename std::enable_if<!is_related<Fun, BenchmarkFunction>::value, int>::type = 0> |
6739 | BenchmarkFunction(Fun&& fun) |
6740 | : f(new model<typename std::decay<Fun>::type>(std::forward<Fun>(fun))) {} |
6741 | |
6742 | BenchmarkFunction(BenchmarkFunction&& that) |
6743 | : f(std::move(that.f)) {} |
6744 | |
6745 | BenchmarkFunction(BenchmarkFunction const& that) |
6746 | : f(that.f->clone()) {} |
6747 | |
6748 | BenchmarkFunction& operator=(BenchmarkFunction&& that) { |
6749 | f = std::move(that.f); |
6750 | return *this; |
6751 | } |
6752 | |
6753 | BenchmarkFunction& operator=(BenchmarkFunction const& that) { |
6754 | f.reset(that.f->clone()); |
6755 | return *this; |
6756 | } |
6757 | |
6758 | void operator()(Chronometer meter) const { f->call(meter); } |
6759 | |
6760 | private: |
6761 | std::unique_ptr<callable> f; |
6762 | }; |
6763 | } // namespace Detail |
6764 | } // namespace Benchmark |
6765 | } // namespace Catch |
6766 | |
6767 | // end catch_benchmark_function.hpp |
6768 | // start catch_repeat.hpp |
6769 | |
6770 | // repeat algorithm |
6771 | |
6772 | |
6773 | #include <type_traits> |
6774 | #include <utility> |
6775 | |
6776 | namespace Catch { |
6777 | namespace Benchmark { |
6778 | namespace Detail { |
6779 | template <typename Fun> |
6780 | struct repeater { |
6781 | void operator()(int k) const { |
6782 | for (int i = 0; i < k; ++i) { |
6783 | fun(); |
6784 | } |
6785 | } |
6786 | Fun fun; |
6787 | }; |
6788 | template <typename Fun> |
6789 | repeater<typename std::decay<Fun>::type> repeat(Fun&& fun) { |
6790 | return { std::forward<Fun>(fun) }; |
6791 | } |
6792 | } // namespace Detail |
6793 | } // namespace Benchmark |
6794 | } // namespace Catch |
6795 | |
6796 | // end catch_repeat.hpp |
6797 | // start catch_run_for_at_least.hpp |
6798 | |
6799 | // Run a function for a minimum amount of time |
6800 | |
6801 | |
6802 | // start catch_measure.hpp |
6803 | |
6804 | // Measure |
6805 | |
6806 | |
6807 | // start catch_timing.hpp |
6808 | |
6809 | // Timing |
6810 | |
6811 | |
6812 | #include <tuple> |
6813 | #include <type_traits> |
6814 | |
6815 | namespace Catch { |
6816 | namespace Benchmark { |
6817 | template <typename Duration, typename Result> |
6818 | struct Timing { |
6819 | Duration elapsed; |
6820 | Result result; |
6821 | int iterations; |
6822 | }; |
6823 | template <typename Clock, typename Func, typename... Args> |
6824 | using TimingOf = Timing<ClockDuration<Clock>, Detail::CompleteType_t<FunctionReturnType<Func, Args...>>>; |
6825 | } // namespace Benchmark |
6826 | } // namespace Catch |
6827 | |
6828 | // end catch_timing.hpp |
6829 | #include <utility> |
6830 | |
6831 | namespace Catch { |
6832 | namespace Benchmark { |
6833 | namespace Detail { |
6834 | template <typename Clock, typename Fun, typename... Args> |
6835 | TimingOf<Clock, Fun, Args...> measure(Fun&& fun, Args&&... args) { |
6836 | auto start = Clock::now(); |
6837 | auto&& r = Detail::complete_invoke(fun, std::forward<Args>(args)...); |
6838 | auto end = Clock::now(); |
6839 | auto delta = end - start; |
6840 | return { delta, std::forward<decltype(r)>(r), 1 }; |
6841 | } |
6842 | } // namespace Detail |
6843 | } // namespace Benchmark |
6844 | } // namespace Catch |
6845 | |
6846 | // end catch_measure.hpp |
6847 | #include <utility> |
6848 | #include <type_traits> |
6849 | |
6850 | namespace Catch { |
6851 | namespace Benchmark { |
6852 | namespace Detail { |
6853 | template <typename Clock, typename Fun> |
6854 | TimingOf<Clock, Fun, int> measure_one(Fun&& fun, int iters, std::false_type) { |
6855 | return Detail::measure<Clock>(fun, iters); |
6856 | } |
6857 | template <typename Clock, typename Fun> |
6858 | TimingOf<Clock, Fun, Chronometer> measure_one(Fun&& fun, int iters, std::true_type) { |
6859 | Detail::ChronometerModel<Clock> meter; |
6860 | auto&& result = Detail::complete_invoke(fun, Chronometer(meter, iters)); |
6861 | |
6862 | return { meter.elapsed(), std::move(result), iters }; |
6863 | } |
6864 | |
6865 | template <typename Clock, typename Fun> |
6866 | using run_for_at_least_argument_t = typename std::conditional<is_callable<Fun(Chronometer)>::value, Chronometer, int>::type; |
6867 | |
6868 | struct optimized_away_error : std::exception { |
6869 | const char* what() const noexcept override { |
6870 | return "could not measure benchmark, maybe it was optimized away" ; |
6871 | } |
6872 | }; |
6873 | |
6874 | template <typename Clock, typename Fun> |
6875 | TimingOf<Clock, Fun, run_for_at_least_argument_t<Clock, Fun>> run_for_at_least(ClockDuration<Clock> how_long, int seed, Fun&& fun) { |
6876 | auto iters = seed; |
6877 | while (iters < (1 << 30)) { |
6878 | auto&& Timing = measure_one<Clock>(fun, iters, is_callable<Fun(Chronometer)>()); |
6879 | |
6880 | if (Timing.elapsed >= how_long) { |
6881 | return { Timing.elapsed, std::move(Timing.result), iters }; |
6882 | } |
6883 | iters *= 2; |
6884 | } |
6885 | Catch::throw_exception(optimized_away_error{}); |
6886 | } |
6887 | } // namespace Detail |
6888 | } // namespace Benchmark |
6889 | } // namespace Catch |
6890 | |
6891 | // end catch_run_for_at_least.hpp |
6892 | #include <algorithm> |
6893 | #include <iterator> |
6894 | |
6895 | namespace Catch { |
6896 | namespace Benchmark { |
6897 | template <typename Duration> |
6898 | struct ExecutionPlan { |
6899 | int iterations_per_sample; |
6900 | Duration estimated_duration; |
6901 | Detail::BenchmarkFunction benchmark; |
6902 | Duration warmup_time; |
6903 | int warmup_iterations; |
6904 | |
6905 | template <typename Duration2> |
6906 | operator ExecutionPlan<Duration2>() const { |
6907 | return { iterations_per_sample, estimated_duration, benchmark, warmup_time, warmup_iterations }; |
6908 | } |
6909 | |
6910 | template <typename Clock> |
6911 | std::vector<FloatDuration<Clock>> run(const IConfig &cfg, Environment<FloatDuration<Clock>> env) const { |
6912 | // warmup a bit |
6913 | Detail::run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(warmup_time), warmup_iterations, Detail::repeat(now<Clock>{})); |
6914 | |
6915 | std::vector<FloatDuration<Clock>> times; |
6916 | times.reserve(cfg.benchmarkSamples()); |
6917 | std::generate_n(std::back_inserter(times), cfg.benchmarkSamples(), [this, env] { |
6918 | Detail::ChronometerModel<Clock> model; |
6919 | this->benchmark(Chronometer(model, iterations_per_sample)); |
6920 | auto sample_time = model.elapsed() - env.clock_cost.mean; |
6921 | if (sample_time < FloatDuration<Clock>::zero()) sample_time = FloatDuration<Clock>::zero(); |
6922 | return sample_time / iterations_per_sample; |
6923 | }); |
6924 | return times; |
6925 | } |
6926 | }; |
6927 | } // namespace Benchmark |
6928 | } // namespace Catch |
6929 | |
6930 | // end catch_execution_plan.hpp |
6931 | // start catch_estimate_clock.hpp |
6932 | |
6933 | // Environment measurement |
6934 | |
6935 | |
6936 | // start catch_stats.hpp |
6937 | |
6938 | // Statistical analysis tools |
6939 | |
6940 | |
6941 | #include <algorithm> |
6942 | #include <functional> |
6943 | #include <vector> |
6944 | #include <iterator> |
6945 | #include <numeric> |
6946 | #include <tuple> |
6947 | #include <cmath> |
6948 | #include <utility> |
6949 | #include <cstddef> |
6950 | #include <random> |
6951 | |
6952 | namespace Catch { |
6953 | namespace Benchmark { |
6954 | namespace Detail { |
6955 | using sample = std::vector<double>; |
6956 | |
6957 | double weighted_average_quantile(int k, int q, std::vector<double>::iterator first, std::vector<double>::iterator last); |
6958 | |
6959 | template <typename Iterator> |
6960 | OutlierClassification classify_outliers(Iterator first, Iterator last) { |
6961 | std::vector<double> copy(first, last); |
6962 | |
6963 | auto q1 = weighted_average_quantile(1, 4, copy.begin(), copy.end()); |
6964 | auto q3 = weighted_average_quantile(3, 4, copy.begin(), copy.end()); |
6965 | auto iqr = q3 - q1; |
6966 | auto los = q1 - (iqr * 3.); |
6967 | auto lom = q1 - (iqr * 1.5); |
6968 | auto him = q3 + (iqr * 1.5); |
6969 | auto his = q3 + (iqr * 3.); |
6970 | |
6971 | OutlierClassification o; |
6972 | for (; first != last; ++first) { |
6973 | auto&& t = *first; |
6974 | if (t < los) ++o.low_severe; |
6975 | else if (t < lom) ++o.low_mild; |
6976 | else if (t > his) ++o.high_severe; |
6977 | else if (t > him) ++o.high_mild; |
6978 | ++o.samples_seen; |
6979 | } |
6980 | return o; |
6981 | } |
6982 | |
6983 | template <typename Iterator> |
6984 | double mean(Iterator first, Iterator last) { |
6985 | auto count = last - first; |
6986 | double sum = std::accumulate(first, last, 0.); |
6987 | return sum / count; |
6988 | } |
6989 | |
6990 | template <typename URng, typename Iterator, typename Estimator> |
6991 | sample resample(URng& rng, int resamples, Iterator first, Iterator last, Estimator& estimator) { |
6992 | auto n = last - first; |
6993 | std::uniform_int_distribution<decltype(n)> dist(0, n - 1); |
6994 | |
6995 | sample out; |
6996 | out.reserve(resamples); |
6997 | std::generate_n(std::back_inserter(out), resamples, [n, first, &estimator, &dist, &rng] { |
6998 | std::vector<double> resampled; |
6999 | resampled.reserve(n); |
7000 | std::generate_n(std::back_inserter(resampled), n, [first, &dist, &rng] { return first[dist(rng)]; }); |
7001 | return estimator(resampled.begin(), resampled.end()); |
7002 | }); |
7003 | std::sort(out.begin(), out.end()); |
7004 | return out; |
7005 | } |
7006 | |
7007 | template <typename Estimator, typename Iterator> |
7008 | sample jackknife(Estimator&& estimator, Iterator first, Iterator last) { |
7009 | auto n = last - first; |
7010 | auto second = std::next(first); |
7011 | sample results; |
7012 | results.reserve(n); |
7013 | |
7014 | for (auto it = first; it != last; ++it) { |
7015 | std::iter_swap(it, first); |
7016 | results.push_back(estimator(second, last)); |
7017 | } |
7018 | |
7019 | return results; |
7020 | } |
7021 | |
7022 | inline double normal_cdf(double x) { |
7023 | return std::erfc(-x / std::sqrt(2.0)) / 2.0; |
7024 | } |
7025 | |
7026 | double erfc_inv(double x); |
7027 | |
7028 | double normal_quantile(double p); |
7029 | |
7030 | template <typename Iterator, typename Estimator> |
7031 | Estimate<double> bootstrap(double confidence_level, Iterator first, Iterator last, sample const& resample, Estimator&& estimator) { |
7032 | auto n_samples = last - first; |
7033 | |
7034 | double point = estimator(first, last); |
7035 | // Degenerate case with a single sample |
7036 | if (n_samples == 1) return { point, point, point, confidence_level }; |
7037 | |
7038 | sample jack = jackknife(estimator, first, last); |
7039 | double jack_mean = mean(jack.begin(), jack.end()); |
7040 | double sum_squares, sum_cubes; |
7041 | std::tie(sum_squares, sum_cubes) = std::accumulate(jack.begin(), jack.end(), std::make_pair(0., 0.), [jack_mean](std::pair<double, double> sqcb, double x) -> std::pair<double, double> { |
7042 | auto d = jack_mean - x; |
7043 | auto d2 = d * d; |
7044 | auto d3 = d2 * d; |
7045 | return { sqcb.first + d2, sqcb.second + d3 }; |
7046 | }); |
7047 | |
7048 | double accel = sum_cubes / (6 * std::pow(sum_squares, 1.5)); |
7049 | int n = static_cast<int>(resample.size()); |
7050 | double prob_n = std::count_if(resample.begin(), resample.end(), [point](double x) { return x < point; }) / (double)n; |
7051 | // degenerate case with uniform samples |
7052 | if (prob_n == 0) return { point, point, point, confidence_level }; |
7053 | |
7054 | double bias = normal_quantile(prob_n); |
7055 | double z1 = normal_quantile((1. - confidence_level) / 2.); |
7056 | |
7057 | auto cumn = [n](double x) -> int { |
7058 | return std::lround(normal_cdf(x) * n); }; |
7059 | auto a = [bias, accel](double b) { return bias + b / (1. - accel * b); }; |
7060 | double b1 = bias + z1; |
7061 | double b2 = bias - z1; |
7062 | double a1 = a(b1); |
7063 | double a2 = a(b2); |
7064 | auto lo = (std::max)(cumn(a1), 0); |
7065 | auto hi = (std::min)(cumn(a2), n - 1); |
7066 | |
7067 | return { point, resample[lo], resample[hi], confidence_level }; |
7068 | } |
7069 | |
7070 | double outlier_variance(Estimate<double> mean, Estimate<double> stddev, int n); |
7071 | |
7072 | struct bootstrap_analysis { |
7073 | Estimate<double> mean; |
7074 | Estimate<double> standard_deviation; |
7075 | double outlier_variance; |
7076 | }; |
7077 | |
7078 | bootstrap_analysis analyse_samples(double confidence_level, int n_resamples, std::vector<double>::iterator first, std::vector<double>::iterator last); |
7079 | } // namespace Detail |
7080 | } // namespace Benchmark |
7081 | } // namespace Catch |
7082 | |
7083 | // end catch_stats.hpp |
7084 | #include <algorithm> |
7085 | #include <iterator> |
7086 | #include <tuple> |
7087 | #include <vector> |
7088 | #include <cmath> |
7089 | |
7090 | namespace Catch { |
7091 | namespace Benchmark { |
7092 | namespace Detail { |
7093 | template <typename Clock> |
7094 | std::vector<double> resolution(int k) { |
7095 | std::vector<TimePoint<Clock>> times; |
7096 | times.reserve(k + 1); |
7097 | std::generate_n(std::back_inserter(times), k + 1, now<Clock>{}); |
7098 | |
7099 | std::vector<double> deltas; |
7100 | deltas.reserve(k); |
7101 | std::transform(std::next(times.begin()), times.end(), times.begin(), |
7102 | std::back_inserter(deltas), |
7103 | [](TimePoint<Clock> a, TimePoint<Clock> b) { return static_cast<double>((a - b).count()); }); |
7104 | |
7105 | return deltas; |
7106 | } |
7107 | |
7108 | const auto warmup_iterations = 10000; |
7109 | const auto warmup_time = std::chrono::milliseconds(100); |
7110 | const auto minimum_ticks = 1000; |
7111 | const auto warmup_seed = 10000; |
7112 | const auto clock_resolution_estimation_time = std::chrono::milliseconds(500); |
7113 | const auto clock_cost_estimation_time_limit = std::chrono::seconds(1); |
7114 | const auto clock_cost_estimation_tick_limit = 100000; |
7115 | const auto clock_cost_estimation_time = std::chrono::milliseconds(10); |
7116 | const auto clock_cost_estimation_iterations = 10000; |
7117 | |
7118 | template <typename Clock> |
7119 | int warmup() { |
7120 | return run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(warmup_time), warmup_seed, &resolution<Clock>) |
7121 | .iterations; |
7122 | } |
7123 | template <typename Clock> |
7124 | EnvironmentEstimate<FloatDuration<Clock>> estimate_clock_resolution(int iterations) { |
7125 | auto r = run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(clock_resolution_estimation_time), iterations, &resolution<Clock>) |
7126 | .result; |
7127 | return { |
7128 | FloatDuration<Clock>(mean(r.begin(), r.end())), |
7129 | classify_outliers(r.begin(), r.end()), |
7130 | }; |
7131 | } |
7132 | template <typename Clock> |
7133 | EnvironmentEstimate<FloatDuration<Clock>> estimate_clock_cost(FloatDuration<Clock> resolution) { |
7134 | auto time_limit = (std::min)( |
7135 | resolution * clock_cost_estimation_tick_limit, |
7136 | FloatDuration<Clock>(clock_cost_estimation_time_limit)); |
7137 | auto time_clock = [](int k) { |
7138 | return Detail::measure<Clock>([k] { |
7139 | for (int i = 0; i < k; ++i) { |
7140 | volatile auto ignored = Clock::now(); |
7141 | (void)ignored; |
7142 | } |
7143 | }).elapsed; |
7144 | }; |
7145 | time_clock(1); |
7146 | int iters = clock_cost_estimation_iterations; |
7147 | auto&& r = run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(clock_cost_estimation_time), iters, time_clock); |
7148 | std::vector<double> times; |
7149 | int nsamples = static_cast<int>(std::ceil(time_limit / r.elapsed)); |
7150 | times.reserve(nsamples); |
7151 | std::generate_n(std::back_inserter(times), nsamples, [time_clock, &r] { |
7152 | return static_cast<double>((time_clock(r.iterations) / r.iterations).count()); |
7153 | }); |
7154 | return { |
7155 | FloatDuration<Clock>(mean(times.begin(), times.end())), |
7156 | classify_outliers(times.begin(), times.end()), |
7157 | }; |
7158 | } |
7159 | |
7160 | template <typename Clock> |
7161 | Environment<FloatDuration<Clock>> measure_environment() { |
7162 | static Environment<FloatDuration<Clock>>* env = nullptr; |
7163 | if (env) { |
7164 | return *env; |
7165 | } |
7166 | |
7167 | auto iters = Detail::warmup<Clock>(); |
7168 | auto resolution = Detail::estimate_clock_resolution<Clock>(iters); |
7169 | auto cost = Detail::estimate_clock_cost<Clock>(resolution.mean); |
7170 | |
7171 | env = new Environment<FloatDuration<Clock>>{ resolution, cost }; |
7172 | return *env; |
7173 | } |
7174 | } // namespace Detail |
7175 | } // namespace Benchmark |
7176 | } // namespace Catch |
7177 | |
7178 | // end catch_estimate_clock.hpp |
7179 | // start catch_analyse.hpp |
7180 | |
7181 | // Run and analyse one benchmark |
7182 | |
7183 | |
7184 | // start catch_sample_analysis.hpp |
7185 | |
7186 | // Benchmark results |
7187 | |
7188 | |
7189 | #include <algorithm> |
7190 | #include <vector> |
7191 | #include <string> |
7192 | #include <iterator> |
7193 | |
7194 | namespace Catch { |
7195 | namespace Benchmark { |
7196 | template <typename Duration> |
7197 | struct SampleAnalysis { |
7198 | std::vector<Duration> samples; |
7199 | Estimate<Duration> mean; |
7200 | Estimate<Duration> standard_deviation; |
7201 | OutlierClassification outliers; |
7202 | double outlier_variance; |
7203 | |
7204 | template <typename Duration2> |
7205 | operator SampleAnalysis<Duration2>() const { |
7206 | std::vector<Duration2> samples2; |
7207 | samples2.reserve(samples.size()); |
7208 | std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](Duration d) { return Duration2(d); }); |
7209 | return { |
7210 | std::move(samples2), |
7211 | mean, |
7212 | standard_deviation, |
7213 | outliers, |
7214 | outlier_variance, |
7215 | }; |
7216 | } |
7217 | }; |
7218 | } // namespace Benchmark |
7219 | } // namespace Catch |
7220 | |
7221 | // end catch_sample_analysis.hpp |
7222 | #include <algorithm> |
7223 | #include <iterator> |
7224 | #include <vector> |
7225 | |
7226 | namespace Catch { |
7227 | namespace Benchmark { |
7228 | namespace Detail { |
7229 | template <typename Duration, typename Iterator> |
7230 | SampleAnalysis<Duration> analyse(const IConfig &cfg, Environment<Duration>, Iterator first, Iterator last) { |
7231 | if (!cfg.benchmarkNoAnalysis()) { |
7232 | std::vector<double> samples; |
7233 | samples.reserve(last - first); |
7234 | std::transform(first, last, std::back_inserter(samples), [](Duration d) { return d.count(); }); |
7235 | |
7236 | auto analysis = Catch::Benchmark::Detail::analyse_samples(cfg.benchmarkConfidenceInterval(), cfg.benchmarkResamples(), samples.begin(), samples.end()); |
7237 | auto outliers = Catch::Benchmark::Detail::classify_outliers(samples.begin(), samples.end()); |
7238 | |
7239 | auto wrap_estimate = [](Estimate<double> e) { |
7240 | return Estimate<Duration> { |
7241 | Duration(e.point), |
7242 | Duration(e.lower_bound), |
7243 | Duration(e.upper_bound), |
7244 | e.confidence_interval, |
7245 | }; |
7246 | }; |
7247 | std::vector<Duration> samples2; |
7248 | samples2.reserve(samples.size()); |
7249 | std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](double d) { return Duration(d); }); |
7250 | return { |
7251 | std::move(samples2), |
7252 | wrap_estimate(analysis.mean), |
7253 | wrap_estimate(analysis.standard_deviation), |
7254 | outliers, |
7255 | analysis.outlier_variance, |
7256 | }; |
7257 | } else { |
7258 | std::vector<Duration> samples; |
7259 | samples.reserve(last - first); |
7260 | |
7261 | Duration mean = Duration(0); |
7262 | int i = 0; |
7263 | for (auto it = first; it < last; ++it, ++i) { |
7264 | samples.push_back(Duration(*it)); |
7265 | mean += Duration(*it); |
7266 | } |
7267 | mean /= i; |
7268 | |
7269 | return { |
7270 | std::move(samples), |
7271 | Estimate<Duration>{mean, mean, mean, 0.0}, |
7272 | Estimate<Duration>{Duration(0), Duration(0), Duration(0), 0.0}, |
7273 | OutlierClassification{}, |
7274 | 0.0 |
7275 | }; |
7276 | } |
7277 | } |
7278 | } // namespace Detail |
7279 | } // namespace Benchmark |
7280 | } // namespace Catch |
7281 | |
7282 | // end catch_analyse.hpp |
7283 | #include <algorithm> |
7284 | #include <functional> |
7285 | #include <string> |
7286 | #include <vector> |
7287 | #include <cmath> |
7288 | |
7289 | namespace Catch { |
7290 | namespace Benchmark { |
7291 | struct Benchmark { |
7292 | Benchmark(std::string &&name) |
7293 | : name(std::move(name)) {} |
7294 | |
7295 | template <class FUN> |
7296 | Benchmark(std::string &&name, FUN &&func) |
7297 | : fun(std::move(func)), name(std::move(name)) {} |
7298 | |
7299 | template <typename Clock> |
7300 | ExecutionPlan<FloatDuration<Clock>> prepare(const IConfig &cfg, Environment<FloatDuration<Clock>> env) const { |
7301 | auto min_time = env.clock_resolution.mean * Detail::minimum_ticks; |
7302 | auto run_time = std::max(min_time, std::chrono::duration_cast<decltype(min_time)>(cfg.benchmarkWarmupTime())); |
7303 | auto&& test = Detail::run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(run_time), 1, fun); |
7304 | int new_iters = static_cast<int>(std::ceil(min_time * test.iterations / test.elapsed)); |
7305 | return { new_iters, test.elapsed / test.iterations * new_iters * cfg.benchmarkSamples(), fun, std::chrono::duration_cast<FloatDuration<Clock>>(cfg.benchmarkWarmupTime()), Detail::warmup_iterations }; |
7306 | } |
7307 | |
7308 | template <typename Clock = default_clock> |
7309 | void run() { |
7310 | IConfigPtr cfg = getCurrentContext().getConfig(); |
7311 | |
7312 | auto env = Detail::measure_environment<Clock>(); |
7313 | |
7314 | getResultCapture().benchmarkPreparing(name); |
7315 | CATCH_TRY{ |
7316 | auto plan = user_code([&] { |
7317 | return prepare<Clock>(*cfg, env); |
7318 | }); |
7319 | |
7320 | BenchmarkInfo info { |
7321 | name, |
7322 | plan.estimated_duration.count(), |
7323 | plan.iterations_per_sample, |
7324 | cfg->benchmarkSamples(), |
7325 | cfg->benchmarkResamples(), |
7326 | env.clock_resolution.mean.count(), |
7327 | env.clock_cost.mean.count() |
7328 | }; |
7329 | |
7330 | getResultCapture().benchmarkStarting(info); |
7331 | |
7332 | auto samples = user_code([&] { |
7333 | return plan.template run<Clock>(*cfg, env); |
7334 | }); |
7335 | |
7336 | auto analysis = Detail::analyse(*cfg, env, samples.begin(), samples.end()); |
7337 | BenchmarkStats<FloatDuration<Clock>> stats{ info, analysis.samples, analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance }; |
7338 | getResultCapture().benchmarkEnded(stats); |
7339 | |
7340 | } CATCH_CATCH_ALL{ |
7341 | if (translateActiveException() != Detail::benchmarkErrorMsg) // benchmark errors have been reported, otherwise rethrow. |
7342 | std::rethrow_exception(std::current_exception()); |
7343 | } |
7344 | } |
7345 | |
7346 | // sets lambda to be used in fun *and* executes benchmark! |
7347 | template <typename Fun, |
7348 | typename std::enable_if<!Detail::is_related<Fun, Benchmark>::value, int>::type = 0> |
7349 | Benchmark & operator=(Fun func) { |
7350 | fun = Detail::BenchmarkFunction(func); |
7351 | run(); |
7352 | return *this; |
7353 | } |
7354 | |
7355 | explicit operator bool() { |
7356 | return true; |
7357 | } |
7358 | |
7359 | private: |
7360 | Detail::BenchmarkFunction fun; |
7361 | std::string name; |
7362 | }; |
7363 | } |
7364 | } // namespace Catch |
7365 | |
7366 | #define INTERNAL_CATCH_GET_1_ARG(arg1, arg2, ...) arg1 |
7367 | #define INTERNAL_CATCH_GET_2_ARG(arg1, arg2, ...) arg2 |
7368 | |
7369 | #define INTERNAL_CATCH_BENCHMARK(BenchmarkName, name, benchmarkIndex)\ |
7370 | if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \ |
7371 | BenchmarkName = [&](int benchmarkIndex) |
7372 | |
7373 | #define INTERNAL_CATCH_BENCHMARK_ADVANCED(BenchmarkName, name)\ |
7374 | if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \ |
7375 | BenchmarkName = [&] |
7376 | |
7377 | // end catch_benchmark.hpp |
7378 | // start catch_constructor.hpp |
7379 | |
7380 | // Constructor and destructor helpers |
7381 | |
7382 | |
7383 | #include <type_traits> |
7384 | |
7385 | namespace Catch { |
7386 | namespace Benchmark { |
7387 | namespace Detail { |
7388 | template <typename T, bool Destruct> |
7389 | struct ObjectStorage |
7390 | { |
7391 | using TStorage = typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type; |
7392 | |
7393 | ObjectStorage() : data() {} |
7394 | |
7395 | ObjectStorage(const ObjectStorage& other) |
7396 | { |
7397 | new(&data) T(other.stored_object()); |
7398 | } |
7399 | |
7400 | ObjectStorage(ObjectStorage&& other) |
7401 | { |
7402 | new(&data) T(std::move(other.stored_object())); |
7403 | } |
7404 | |
7405 | ~ObjectStorage() { destruct_on_exit<T>(); } |
7406 | |
7407 | template <typename... Args> |
7408 | void construct(Args&&... args) |
7409 | { |
7410 | new (&data) T(std::forward<Args>(args)...); |
7411 | } |
7412 | |
7413 | template <bool AllowManualDestruction = !Destruct> |
7414 | typename std::enable_if<AllowManualDestruction>::type destruct() |
7415 | { |
7416 | stored_object().~T(); |
7417 | } |
7418 | |
7419 | private: |
7420 | // If this is a constructor benchmark, destruct the underlying object |
7421 | template <typename U> |
7422 | void destruct_on_exit(typename std::enable_if<Destruct, U>::type* = 0) { destruct<true>(); } |
7423 | // Otherwise, don't |
7424 | template <typename U> |
7425 | void destruct_on_exit(typename std::enable_if<!Destruct, U>::type* = 0) { } |
7426 | |
7427 | T& stored_object() { |
7428 | return *static_cast<T*>(static_cast<void*>(&data)); |
7429 | } |
7430 | |
7431 | T const& stored_object() const { |
7432 | return *static_cast<T*>(static_cast<void*>(&data)); |
7433 | } |
7434 | |
7435 | TStorage data; |
7436 | }; |
7437 | } |
7438 | |
7439 | template <typename T> |
7440 | using storage_for = Detail::ObjectStorage<T, true>; |
7441 | |
7442 | template <typename T> |
7443 | using destructable_object = Detail::ObjectStorage<T, false>; |
7444 | } |
7445 | } |
7446 | |
7447 | // end catch_constructor.hpp |
7448 | // end catch_benchmarking_all.hpp |
7449 | #endif |
7450 | |
7451 | #endif // ! CATCH_CONFIG_IMPL_ONLY |
7452 | |
7453 | #ifdef CATCH_IMPL |
7454 | // start catch_impl.hpp |
7455 | |
7456 | #ifdef __clang__ |
7457 | #pragma clang diagnostic push |
7458 | #pragma clang diagnostic ignored "-Wweak-vtables" |
7459 | #endif |
7460 | |
7461 | // Keep these here for external reporters |
7462 | // start catch_test_case_tracker.h |
7463 | |
7464 | #include <string> |
7465 | #include <vector> |
7466 | #include <memory> |
7467 | |
7468 | namespace Catch { |
7469 | namespace TestCaseTracking { |
7470 | |
7471 | struct NameAndLocation { |
7472 | std::string name; |
7473 | SourceLineInfo location; |
7474 | |
7475 | NameAndLocation( std::string const& _name, SourceLineInfo const& _location ); |
7476 | friend bool operator==(NameAndLocation const& lhs, NameAndLocation const& rhs) { |
7477 | return lhs.name == rhs.name |
7478 | && lhs.location == rhs.location; |
7479 | } |
7480 | }; |
7481 | |
7482 | class ITracker; |
7483 | |
7484 | using ITrackerPtr = std::shared_ptr<ITracker>; |
7485 | |
7486 | class ITracker { |
7487 | NameAndLocation m_nameAndLocation; |
7488 | |
7489 | public: |
7490 | ITracker(NameAndLocation const& nameAndLoc) : |
7491 | m_nameAndLocation(nameAndLoc) |
7492 | {} |
7493 | |
7494 | // static queries |
7495 | NameAndLocation const& nameAndLocation() const { |
7496 | return m_nameAndLocation; |
7497 | } |
7498 | |
7499 | virtual ~ITracker(); |
7500 | |
7501 | // dynamic queries |
7502 | virtual bool isComplete() const = 0; // Successfully completed or failed |
7503 | virtual bool isSuccessfullyCompleted() const = 0; |
7504 | virtual bool isOpen() const = 0; // Started but not complete |
7505 | virtual bool hasChildren() const = 0; |
7506 | virtual bool hasStarted() const = 0; |
7507 | |
7508 | virtual ITracker& parent() = 0; |
7509 | |
7510 | // actions |
7511 | virtual void close() = 0; // Successfully complete |
7512 | virtual void fail() = 0; |
7513 | virtual void markAsNeedingAnotherRun() = 0; |
7514 | |
7515 | virtual void addChild( ITrackerPtr const& child ) = 0; |
7516 | virtual ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) = 0; |
7517 | virtual void openChild() = 0; |
7518 | |
7519 | // Debug/ checking |
7520 | virtual bool isSectionTracker() const = 0; |
7521 | virtual bool isGeneratorTracker() const = 0; |
7522 | }; |
7523 | |
7524 | class TrackerContext { |
7525 | |
7526 | enum RunState { |
7527 | NotStarted, |
7528 | Executing, |
7529 | CompletedCycle |
7530 | }; |
7531 | |
7532 | ITrackerPtr m_rootTracker; |
7533 | ITracker* m_currentTracker = nullptr; |
7534 | RunState m_runState = NotStarted; |
7535 | |
7536 | public: |
7537 | |
7538 | ITracker& startRun(); |
7539 | void endRun(); |
7540 | |
7541 | void startCycle(); |
7542 | void completeCycle(); |
7543 | |
7544 | bool completedCycle() const; |
7545 | ITracker& currentTracker(); |
7546 | void setCurrentTracker( ITracker* tracker ); |
7547 | }; |
7548 | |
7549 | class TrackerBase : public ITracker { |
7550 | protected: |
7551 | enum CycleState { |
7552 | NotStarted, |
7553 | Executing, |
7554 | ExecutingChildren, |
7555 | NeedsAnotherRun, |
7556 | CompletedSuccessfully, |
7557 | Failed |
7558 | }; |
7559 | |
7560 | using Children = std::vector<ITrackerPtr>; |
7561 | TrackerContext& m_ctx; |
7562 | ITracker* m_parent; |
7563 | Children m_children; |
7564 | CycleState m_runState = NotStarted; |
7565 | |
7566 | public: |
7567 | TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); |
7568 | |
7569 | bool isComplete() const override; |
7570 | bool isSuccessfullyCompleted() const override; |
7571 | bool isOpen() const override; |
7572 | bool hasChildren() const override; |
7573 | bool hasStarted() const override { |
7574 | return m_runState != NotStarted; |
7575 | } |
7576 | |
7577 | void addChild( ITrackerPtr const& child ) override; |
7578 | |
7579 | ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) override; |
7580 | ITracker& parent() override; |
7581 | |
7582 | void openChild() override; |
7583 | |
7584 | bool isSectionTracker() const override; |
7585 | bool isGeneratorTracker() const override; |
7586 | |
7587 | void open(); |
7588 | |
7589 | void close() override; |
7590 | void fail() override; |
7591 | void markAsNeedingAnotherRun() override; |
7592 | |
7593 | private: |
7594 | void moveToParent(); |
7595 | void moveToThis(); |
7596 | }; |
7597 | |
7598 | class SectionTracker : public TrackerBase { |
7599 | std::vector<std::string> m_filters; |
7600 | std::string m_trimmed_name; |
7601 | public: |
7602 | SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); |
7603 | |
7604 | bool isSectionTracker() const override; |
7605 | |
7606 | bool isComplete() const override; |
7607 | |
7608 | static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ); |
7609 | |
7610 | void tryOpen(); |
7611 | |
7612 | void addInitialFilters( std::vector<std::string> const& filters ); |
7613 | void addNextFilters( std::vector<std::string> const& filters ); |
7614 | //! Returns filters active in this tracker |
7615 | std::vector<std::string> const& getFilters() const; |
7616 | //! Returns whitespace-trimmed name of the tracked section |
7617 | std::string const& trimmedName() const; |
7618 | }; |
7619 | |
7620 | } // namespace TestCaseTracking |
7621 | |
7622 | using TestCaseTracking::ITracker; |
7623 | using TestCaseTracking::TrackerContext; |
7624 | using TestCaseTracking::SectionTracker; |
7625 | |
7626 | } // namespace Catch |
7627 | |
7628 | // end catch_test_case_tracker.h |
7629 | |
7630 | // start catch_leak_detector.h |
7631 | |
7632 | namespace Catch { |
7633 | |
7634 | struct LeakDetector { |
7635 | LeakDetector(); |
7636 | ~LeakDetector(); |
7637 | }; |
7638 | |
7639 | } |
7640 | // end catch_leak_detector.h |
7641 | // Cpp files will be included in the single-header file here |
7642 | // start catch_stats.cpp |
7643 | |
7644 | // Statistical analysis tools |
7645 | |
7646 | #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) |
7647 | |
7648 | #include <cassert> |
7649 | #include <random> |
7650 | |
7651 | #if defined(CATCH_CONFIG_USE_ASYNC) |
7652 | #include <future> |
7653 | #endif |
7654 | |
7655 | namespace { |
7656 | double erf_inv(double x) { |
7657 | // Code accompanying the article "Approximating the erfinv function" in GPU Computing Gems, Volume 2 |
7658 | double w, p; |
7659 | |
7660 | w = -log((1.0 - x) * (1.0 + x)); |
7661 | |
7662 | if (w < 6.250000) { |
7663 | w = w - 3.125000; |
7664 | p = -3.6444120640178196996e-21; |
7665 | p = -1.685059138182016589e-19 + p * w; |
7666 | p = 1.2858480715256400167e-18 + p * w; |
7667 | p = 1.115787767802518096e-17 + p * w; |
7668 | p = -1.333171662854620906e-16 + p * w; |
7669 | p = 2.0972767875968561637e-17 + p * w; |
7670 | p = 6.6376381343583238325e-15 + p * w; |
7671 | p = -4.0545662729752068639e-14 + p * w; |
7672 | p = -8.1519341976054721522e-14 + p * w; |
7673 | p = 2.6335093153082322977e-12 + p * w; |
7674 | p = -1.2975133253453532498e-11 + p * w; |
7675 | p = -5.4154120542946279317e-11 + p * w; |
7676 | p = 1.051212273321532285e-09 + p * w; |
7677 | p = -4.1126339803469836976e-09 + p * w; |
7678 | p = -2.9070369957882005086e-08 + p * w; |
7679 | p = 4.2347877827932403518e-07 + p * w; |
7680 | p = -1.3654692000834678645e-06 + p * w; |
7681 | p = -1.3882523362786468719e-05 + p * w; |
7682 | p = 0.0001867342080340571352 + p * w; |
7683 | p = -0.00074070253416626697512 + p * w; |
7684 | p = -0.0060336708714301490533 + p * w; |
7685 | p = 0.24015818242558961693 + p * w; |
7686 | p = 1.6536545626831027356 + p * w; |
7687 | } else if (w < 16.000000) { |
7688 | w = sqrt(w) - 3.250000; |
7689 | p = 2.2137376921775787049e-09; |
7690 | p = 9.0756561938885390979e-08 + p * w; |
7691 | p = -2.7517406297064545428e-07 + p * w; |
7692 | p = 1.8239629214389227755e-08 + p * w; |
7693 | p = 1.5027403968909827627e-06 + p * w; |
7694 | p = -4.013867526981545969e-06 + p * w; |
7695 | p = 2.9234449089955446044e-06 + p * w; |
7696 | p = 1.2475304481671778723e-05 + p * w; |
7697 | p = -4.7318229009055733981e-05 + p * w; |
7698 | p = 6.8284851459573175448e-05 + p * w; |
7699 | p = 2.4031110387097893999e-05 + p * w; |
7700 | p = -0.0003550375203628474796 + p * w; |
7701 | p = 0.00095328937973738049703 + p * w; |
7702 | p = -0.0016882755560235047313 + p * w; |
7703 | p = 0.0024914420961078508066 + p * w; |
7704 | p = -0.0037512085075692412107 + p * w; |
7705 | p = 0.005370914553590063617 + p * w; |
7706 | p = 1.0052589676941592334 + p * w; |
7707 | p = 3.0838856104922207635 + p * w; |
7708 | } else { |
7709 | w = sqrt(w) - 5.000000; |
7710 | p = -2.7109920616438573243e-11; |
7711 | p = -2.5556418169965252055e-10 + p * w; |
7712 | p = 1.5076572693500548083e-09 + p * w; |
7713 | p = -3.7894654401267369937e-09 + p * w; |
7714 | p = 7.6157012080783393804e-09 + p * w; |
7715 | p = -1.4960026627149240478e-08 + p * w; |
7716 | p = 2.9147953450901080826e-08 + p * w; |
7717 | p = -6.7711997758452339498e-08 + p * w; |
7718 | p = 2.2900482228026654717e-07 + p * w; |
7719 | p = -9.9298272942317002539e-07 + p * w; |
7720 | p = 4.5260625972231537039e-06 + p * w; |
7721 | p = -1.9681778105531670567e-05 + p * w; |
7722 | p = 7.5995277030017761139e-05 + p * w; |
7723 | p = -0.00021503011930044477347 + p * w; |
7724 | p = -0.00013871931833623122026 + p * w; |
7725 | p = 1.0103004648645343977 + p * w; |
7726 | p = 4.8499064014085844221 + p * w; |
7727 | } |
7728 | return p * x; |
7729 | } |
7730 | |
7731 | double standard_deviation(std::vector<double>::iterator first, std::vector<double>::iterator last) { |
7732 | auto m = Catch::Benchmark::Detail::mean(first, last); |
7733 | double variance = std::accumulate(first, last, 0., [m](double a, double b) { |
7734 | double diff = b - m; |
7735 | return a + diff * diff; |
7736 | }) / (last - first); |
7737 | return std::sqrt(variance); |
7738 | } |
7739 | |
7740 | } |
7741 | |
7742 | namespace Catch { |
7743 | namespace Benchmark { |
7744 | namespace Detail { |
7745 | |
7746 | double weighted_average_quantile(int k, int q, std::vector<double>::iterator first, std::vector<double>::iterator last) { |
7747 | auto count = last - first; |
7748 | double idx = (count - 1) * k / static_cast<double>(q); |
7749 | int j = static_cast<int>(idx); |
7750 | double g = idx - j; |
7751 | std::nth_element(first, first + j, last); |
7752 | auto xj = first[j]; |
7753 | if (g == 0) return xj; |
7754 | |
7755 | auto xj1 = *std::min_element(first + (j + 1), last); |
7756 | return xj + g * (xj1 - xj); |
7757 | } |
7758 | |
7759 | double erfc_inv(double x) { |
7760 | return erf_inv(1.0 - x); |
7761 | } |
7762 | |
7763 | double normal_quantile(double p) { |
7764 | static const double ROOT_TWO = std::sqrt(2.0); |
7765 | |
7766 | double result = 0.0; |
7767 | assert(p >= 0 && p <= 1); |
7768 | if (p < 0 || p > 1) { |
7769 | return result; |
7770 | } |
7771 | |
7772 | result = -erfc_inv(2.0 * p); |
7773 | // result *= normal distribution standard deviation (1.0) * sqrt(2) |
7774 | result *= /*sd * */ ROOT_TWO; |
7775 | // result += normal disttribution mean (0) |
7776 | return result; |
7777 | } |
7778 | |
7779 | double outlier_variance(Estimate<double> mean, Estimate<double> stddev, int n) { |
7780 | double sb = stddev.point; |
7781 | double mn = mean.point / n; |
7782 | double mg_min = mn / 2.; |
7783 | double sg = (std::min)(mg_min / 4., sb / std::sqrt(n)); |
7784 | double sg2 = sg * sg; |
7785 | double sb2 = sb * sb; |
7786 | |
7787 | auto c_max = [n, mn, sb2, sg2](double x) -> double { |
7788 | double k = mn - x; |
7789 | double d = k * k; |
7790 | double nd = n * d; |
7791 | double k0 = -n * nd; |
7792 | double k1 = sb2 - n * sg2 + nd; |
7793 | double det = k1 * k1 - 4 * sg2 * k0; |
7794 | return (int)(-2. * k0 / (k1 + std::sqrt(det))); |
7795 | }; |
7796 | |
7797 | auto var_out = [n, sb2, sg2](double c) { |
7798 | double nc = n - c; |
7799 | return (nc / n) * (sb2 - nc * sg2); |
7800 | }; |
7801 | |
7802 | return (std::min)(var_out(1), var_out((std::min)(c_max(0.), c_max(mg_min)))) / sb2; |
7803 | } |
7804 | |
7805 | bootstrap_analysis analyse_samples(double confidence_level, int n_resamples, std::vector<double>::iterator first, std::vector<double>::iterator last) { |
7806 | CATCH_INTERNAL_START_WARNINGS_SUPPRESSION |
7807 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS |
7808 | static std::random_device entropy; |
7809 | CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION |
7810 | |
7811 | auto n = static_cast<int>(last - first); // seriously, one can't use integral types without hell in C++ |
7812 | |
7813 | auto mean = &Detail::mean<std::vector<double>::iterator>; |
7814 | auto stddev = &standard_deviation; |
7815 | |
7816 | #if defined(CATCH_CONFIG_USE_ASYNC) |
7817 | auto Estimate = [=](double(*f)(std::vector<double>::iterator, std::vector<double>::iterator)) { |
7818 | auto seed = entropy(); |
7819 | return std::async(std::launch::async, [=] { |
7820 | std::mt19937 rng(seed); |
7821 | auto resampled = resample(rng, n_resamples, first, last, f); |
7822 | return bootstrap(confidence_level, first, last, resampled, f); |
7823 | }); |
7824 | }; |
7825 | |
7826 | auto mean_future = Estimate(mean); |
7827 | auto stddev_future = Estimate(stddev); |
7828 | |
7829 | auto mean_estimate = mean_future.get(); |
7830 | auto stddev_estimate = stddev_future.get(); |
7831 | #else |
7832 | auto Estimate = [=](double(*f)(std::vector<double>::iterator, std::vector<double>::iterator)) { |
7833 | auto seed = entropy(); |
7834 | std::mt19937 rng(seed); |
7835 | auto resampled = resample(rng, n_resamples, first, last, f); |
7836 | return bootstrap(confidence_level, first, last, resampled, f); |
7837 | }; |
7838 | |
7839 | auto mean_estimate = Estimate(mean); |
7840 | auto stddev_estimate = Estimate(stddev); |
7841 | #endif // CATCH_USE_ASYNC |
7842 | |
7843 | double outlier_variance = Detail::outlier_variance(mean_estimate, stddev_estimate, n); |
7844 | |
7845 | return { mean_estimate, stddev_estimate, outlier_variance }; |
7846 | } |
7847 | } // namespace Detail |
7848 | } // namespace Benchmark |
7849 | } // namespace Catch |
7850 | |
7851 | #endif // CATCH_CONFIG_ENABLE_BENCHMARKING |
7852 | // end catch_stats.cpp |
7853 | // start catch_approx.cpp |
7854 | |
7855 | #include <cmath> |
7856 | #include <limits> |
7857 | |
7858 | namespace { |
7859 | |
7860 | // Performs equivalent check of std::fabs(lhs - rhs) <= margin |
7861 | // But without the subtraction to allow for INFINITY in comparison |
7862 | bool marginComparison(double lhs, double rhs, double margin) { |
7863 | return (lhs + margin >= rhs) && (rhs + margin >= lhs); |
7864 | } |
7865 | |
7866 | } |
7867 | |
7868 | namespace Catch { |
7869 | namespace Detail { |
7870 | |
7871 | Approx::Approx ( double value ) |
7872 | : m_epsilon( std::numeric_limits<float>::epsilon()*100 ), |
7873 | m_margin( 0.0 ), |
7874 | m_scale( 0.0 ), |
7875 | m_value( value ) |
7876 | {} |
7877 | |
7878 | Approx Approx::custom() { |
7879 | return Approx( 0 ); |
7880 | } |
7881 | |
7882 | Approx Approx::operator-() const { |
7883 | auto temp(*this); |
7884 | temp.m_value = -temp.m_value; |
7885 | return temp; |
7886 | } |
7887 | |
7888 | std::string Approx::toString() const { |
7889 | ReusableStringStream ; |
7890 | rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )" ; |
7891 | return rss.str(); |
7892 | } |
7893 | |
7894 | bool Approx::equalityComparisonImpl(const double other) const { |
7895 | // First try with fixed margin, then compute margin based on epsilon, scale and Approx's value |
7896 | // Thanks to Richard Harris for his help refining the scaled margin value |
7897 | return marginComparison(m_value, other, m_margin) |
7898 | || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(std::isinf(m_value)? 0 : m_value))); |
7899 | } |
7900 | |
7901 | void Approx::setMargin(double newMargin) { |
7902 | CATCH_ENFORCE(newMargin >= 0, |
7903 | "Invalid Approx::margin: " << newMargin << '.' |
7904 | << " Approx::Margin has to be non-negative." ); |
7905 | m_margin = newMargin; |
7906 | } |
7907 | |
7908 | void Approx::setEpsilon(double newEpsilon) { |
7909 | CATCH_ENFORCE(newEpsilon >= 0 && newEpsilon <= 1.0, |
7910 | "Invalid Approx::epsilon: " << newEpsilon << '.' |
7911 | << " Approx::epsilon has to be in [0, 1]" ); |
7912 | m_epsilon = newEpsilon; |
7913 | } |
7914 | |
7915 | } // end namespace Detail |
7916 | |
7917 | namespace literals { |
7918 | Detail::Approx operator "" _a(long double val) { |
7919 | return Detail::Approx(val); |
7920 | } |
7921 | Detail::Approx operator "" _a(unsigned long long val) { |
7922 | return Detail::Approx(val); |
7923 | } |
7924 | } // end namespace literals |
7925 | |
7926 | std::string StringMaker<Catch::Detail::Approx>::convert(Catch::Detail::Approx const& value) { |
7927 | return value.toString(); |
7928 | } |
7929 | |
7930 | } // end namespace Catch |
7931 | // end catch_approx.cpp |
7932 | // start catch_assertionhandler.cpp |
7933 | |
7934 | // start catch_debugger.h |
7935 | |
7936 | namespace Catch { |
7937 | bool isDebuggerActive(); |
7938 | } |
7939 | |
7940 | #ifdef CATCH_PLATFORM_MAC |
7941 | |
7942 | #if defined(__i386__) || defined(__x86_64__) |
7943 | #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */ |
7944 | #elif defined(__aarch64__) |
7945 | #define CATCH_TRAP() __asm__(".inst 0xd4200000") |
7946 | #endif |
7947 | |
7948 | #elif defined(CATCH_PLATFORM_IPHONE) |
7949 | |
7950 | // use inline assembler |
7951 | #if defined(__i386__) || defined(__x86_64__) |
7952 | #define CATCH_TRAP() __asm__("int $3") |
7953 | #elif defined(__aarch64__) |
7954 | #define CATCH_TRAP() __asm__(".inst 0xd4200000") |
7955 | #elif defined(__arm__) && !defined(__thumb__) |
7956 | #define CATCH_TRAP() __asm__(".inst 0xe7f001f0") |
7957 | #elif defined(__arm__) && defined(__thumb__) |
7958 | #define CATCH_TRAP() __asm__(".inst 0xde01") |
7959 | #endif |
7960 | |
7961 | #elif defined(CATCH_PLATFORM_LINUX) |
7962 | // If we can use inline assembler, do it because this allows us to break |
7963 | // directly at the location of the failing check instead of breaking inside |
7964 | // raise() called from it, i.e. one stack frame below. |
7965 | #if defined(__GNUC__) && (defined(__i386) || defined(__x86_64)) |
7966 | #define CATCH_TRAP() asm volatile ("int $3") /* NOLINT */ |
7967 | #else // Fall back to the generic way. |
7968 | #include <signal.h> |
7969 | |
7970 | #define CATCH_TRAP() raise(SIGTRAP) |
7971 | #endif |
7972 | #elif defined(_MSC_VER) |
7973 | #define CATCH_TRAP() __debugbreak() |
7974 | #elif defined(__MINGW32__) |
7975 | extern "C" __declspec(dllimport) void __stdcall DebugBreak(); |
7976 | #define CATCH_TRAP() DebugBreak() |
7977 | #endif |
7978 | |
7979 | #ifndef CATCH_BREAK_INTO_DEBUGGER |
7980 | #ifdef CATCH_TRAP |
7981 | #define CATCH_BREAK_INTO_DEBUGGER() []{ if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } }() |
7982 | #else |
7983 | #define CATCH_BREAK_INTO_DEBUGGER() []{}() |
7984 | #endif |
7985 | #endif |
7986 | |
7987 | // end catch_debugger.h |
7988 | // start catch_run_context.h |
7989 | |
7990 | // start catch_fatal_condition.h |
7991 | |
7992 | #include <cassert> |
7993 | |
7994 | namespace Catch { |
7995 | |
7996 | // Wrapper for platform-specific fatal error (signals/SEH) handlers |
7997 | // |
7998 | // Tries to be cooperative with other handlers, and not step over |
7999 | // other handlers. This means that unknown structured exceptions |
8000 | // are passed on, previous signal handlers are called, and so on. |
8001 | // |
8002 | // Can only be instantiated once, and assumes that once a signal |
8003 | // is caught, the binary will end up terminating. Thus, there |
8004 | class FatalConditionHandler { |
8005 | bool m_started = false; |
8006 | |
8007 | // Install/disengage implementation for specific platform. |
8008 | // Should be if-defed to work on current platform, can assume |
8009 | // engage-disengage 1:1 pairing. |
8010 | void engage_platform(); |
8011 | void disengage_platform(); |
8012 | public: |
8013 | // Should also have platform-specific implementations as needed |
8014 | FatalConditionHandler(); |
8015 | ~FatalConditionHandler(); |
8016 | |
8017 | void engage() { |
8018 | assert(!m_started && "Handler cannot be installed twice." ); |
8019 | m_started = true; |
8020 | engage_platform(); |
8021 | } |
8022 | |
8023 | void disengage() { |
8024 | assert(m_started && "Handler cannot be uninstalled without being installed first" ); |
8025 | m_started = false; |
8026 | disengage_platform(); |
8027 | } |
8028 | }; |
8029 | |
8030 | //! Simple RAII guard for (dis)engaging the FatalConditionHandler |
8031 | class FatalConditionHandlerGuard { |
8032 | FatalConditionHandler* m_handler; |
8033 | public: |
8034 | FatalConditionHandlerGuard(FatalConditionHandler* handler): |
8035 | m_handler(handler) { |
8036 | m_handler->engage(); |
8037 | } |
8038 | ~FatalConditionHandlerGuard() { |
8039 | m_handler->disengage(); |
8040 | } |
8041 | }; |
8042 | |
8043 | } // end namespace Catch |
8044 | |
8045 | // end catch_fatal_condition.h |
8046 | #include <string> |
8047 | |
8048 | namespace Catch { |
8049 | |
8050 | struct IMutableContext; |
8051 | |
8052 | /////////////////////////////////////////////////////////////////////////// |
8053 | |
8054 | class RunContext : public IResultCapture, public IRunner { |
8055 | |
8056 | public: |
8057 | RunContext( RunContext const& ) = delete; |
8058 | RunContext& operator =( RunContext const& ) = delete; |
8059 | |
8060 | explicit RunContext( IConfigPtr const& _config, IStreamingReporterPtr&& reporter ); |
8061 | |
8062 | ~RunContext() override; |
8063 | |
8064 | void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ); |
8065 | void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ); |
8066 | |
8067 | Totals runTest(TestCase const& testCase); |
8068 | |
8069 | IConfigPtr config() const; |
8070 | IStreamingReporter& reporter() const; |
8071 | |
8072 | public: // IResultCapture |
8073 | |
8074 | // Assertion handlers |
8075 | void handleExpr |
8076 | ( AssertionInfo const& info, |
8077 | ITransientExpression const& expr, |
8078 | AssertionReaction& reaction ) override; |
8079 | void handleMessage |
8080 | ( AssertionInfo const& info, |
8081 | ResultWas::OfType resultType, |
8082 | StringRef const& message, |
8083 | AssertionReaction& reaction ) override; |
8084 | void handleUnexpectedExceptionNotThrown |
8085 | ( AssertionInfo const& info, |
8086 | AssertionReaction& reaction ) override; |
8087 | void handleUnexpectedInflightException |
8088 | ( AssertionInfo const& info, |
8089 | std::string const& message, |
8090 | AssertionReaction& reaction ) override; |
8091 | void handleIncomplete |
8092 | ( AssertionInfo const& info ) override; |
8093 | void handleNonExpr |
8094 | ( AssertionInfo const &info, |
8095 | ResultWas::OfType resultType, |
8096 | AssertionReaction &reaction ) override; |
8097 | |
8098 | bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) override; |
8099 | |
8100 | void sectionEnded( SectionEndInfo const& endInfo ) override; |
8101 | void sectionEndedEarly( SectionEndInfo const& endInfo ) override; |
8102 | |
8103 | auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override; |
8104 | |
8105 | #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) |
8106 | void benchmarkPreparing( std::string const& name ) override; |
8107 | void benchmarkStarting( BenchmarkInfo const& info ) override; |
8108 | void benchmarkEnded( BenchmarkStats<> const& stats ) override; |
8109 | void benchmarkFailed( std::string const& error ) override; |
8110 | #endif // CATCH_CONFIG_ENABLE_BENCHMARKING |
8111 | |
8112 | void pushScopedMessage( MessageInfo const& message ) override; |
8113 | void popScopedMessage( MessageInfo const& message ) override; |
8114 | |
8115 | void emplaceUnscopedMessage( MessageBuilder const& builder ) override; |
8116 | |
8117 | std::string getCurrentTestName() const override; |
8118 | |
8119 | const AssertionResult* getLastResult() const override; |
8120 | |
8121 | void exceptionEarlyReported() override; |
8122 | |
8123 | void handleFatalErrorCondition( StringRef message ) override; |
8124 | |
8125 | bool lastAssertionPassed() override; |
8126 | |
8127 | void assertionPassed() override; |
8128 | |
8129 | public: |
8130 | // !TBD We need to do this another way! |
8131 | bool aborting() const final; |
8132 | |
8133 | private: |
8134 | |
8135 | void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ); |
8136 | void invokeActiveTestCase(); |
8137 | |
8138 | void resetAssertionInfo(); |
8139 | bool testForMissingAssertions( Counts& assertions ); |
8140 | |
8141 | void assertionEnded( AssertionResult const& result ); |
8142 | void reportExpr |
8143 | ( AssertionInfo const &info, |
8144 | ResultWas::OfType resultType, |
8145 | ITransientExpression const *expr, |
8146 | bool negated ); |
8147 | |
8148 | void populateReaction( AssertionReaction& reaction ); |
8149 | |
8150 | private: |
8151 | |
8152 | void handleUnfinishedSections(); |
8153 | |
8154 | TestRunInfo m_runInfo; |
8155 | IMutableContext& m_context; |
8156 | TestCase const* m_activeTestCase = nullptr; |
8157 | ITracker* m_testCaseTracker = nullptr; |
8158 | Option<AssertionResult> m_lastResult; |
8159 | |
8160 | IConfigPtr m_config; |
8161 | Totals m_totals; |
8162 | IStreamingReporterPtr m_reporter; |
8163 | std::vector<MessageInfo> m_messages; |
8164 | std::vector<ScopedMessage> m_messageScopes; /* Keeps owners of so-called unscoped messages. */ |
8165 | AssertionInfo m_lastAssertionInfo; |
8166 | std::vector<SectionEndInfo> m_unfinishedSections; |
8167 | std::vector<ITracker*> m_activeSections; |
8168 | TrackerContext m_trackerContext; |
8169 | FatalConditionHandler m_fatalConditionhandler; |
8170 | bool m_lastAssertionPassed = false; |
8171 | bool m_shouldReportUnexpected = true; |
8172 | bool m_includeSuccessfulResults; |
8173 | }; |
8174 | |
8175 | void seedRng(IConfig const& config); |
8176 | unsigned int rngSeed(); |
8177 | } // end namespace Catch |
8178 | |
8179 | // end catch_run_context.h |
8180 | namespace Catch { |
8181 | |
8182 | namespace { |
8183 | auto operator <<( std::ostream& os, ITransientExpression const& expr ) -> std::ostream& { |
8184 | expr.streamReconstructedExpression( os ); |
8185 | return os; |
8186 | } |
8187 | } |
8188 | |
8189 | LazyExpression::LazyExpression( bool isNegated ) |
8190 | : m_isNegated( isNegated ) |
8191 | {} |
8192 | |
8193 | LazyExpression::LazyExpression( LazyExpression const& other ) : m_isNegated( other.m_isNegated ) {} |
8194 | |
8195 | LazyExpression::operator bool() const { |
8196 | return m_transientExpression != nullptr; |
8197 | } |
8198 | |
8199 | auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream& { |
8200 | if( lazyExpr.m_isNegated ) |
8201 | os << "!" ; |
8202 | |
8203 | if( lazyExpr ) { |
8204 | if( lazyExpr.m_isNegated && lazyExpr.m_transientExpression->isBinaryExpression() ) |
8205 | os << "(" << *lazyExpr.m_transientExpression << ")" ; |
8206 | else |
8207 | os << *lazyExpr.m_transientExpression; |
8208 | } |
8209 | else { |
8210 | os << "{** error - unchecked empty expression requested **}" ; |
8211 | } |
8212 | return os; |
8213 | } |
8214 | |
8215 | AssertionHandler::AssertionHandler |
8216 | ( StringRef const& macroName, |
8217 | SourceLineInfo const& lineInfo, |
8218 | StringRef capturedExpression, |
8219 | ResultDisposition::Flags resultDisposition ) |
8220 | : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition }, |
8221 | m_resultCapture( getResultCapture() ) |
8222 | {} |
8223 | |
8224 | void AssertionHandler::handleExpr( ITransientExpression const& expr ) { |
8225 | m_resultCapture.handleExpr( m_assertionInfo, expr, m_reaction ); |
8226 | } |
8227 | void AssertionHandler::handleMessage(ResultWas::OfType resultType, StringRef const& message) { |
8228 | m_resultCapture.handleMessage( m_assertionInfo, resultType, message, m_reaction ); |
8229 | } |
8230 | |
8231 | auto AssertionHandler::allowThrows() const -> bool { |
8232 | return getCurrentContext().getConfig()->allowThrows(); |
8233 | } |
8234 | |
8235 | void AssertionHandler::complete() { |
8236 | setCompleted(); |
8237 | if( m_reaction.shouldDebugBreak ) { |
8238 | |
8239 | // If you find your debugger stopping you here then go one level up on the |
8240 | // call-stack for the code that caused it (typically a failed assertion) |
8241 | |
8242 | // (To go back to the test and change execution, jump over the throw, next) |
8243 | CATCH_BREAK_INTO_DEBUGGER(); |
8244 | } |
8245 | if (m_reaction.shouldThrow) { |
8246 | #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) |
8247 | throw Catch::TestFailureException(); |
8248 | #else |
8249 | CATCH_ERROR( "Test failure requires aborting test!" ); |
8250 | #endif |
8251 | } |
8252 | } |
8253 | void AssertionHandler::setCompleted() { |
8254 | m_completed = true; |
8255 | } |
8256 | |
8257 | void AssertionHandler::handleUnexpectedInflightException() { |
8258 | m_resultCapture.handleUnexpectedInflightException( m_assertionInfo, Catch::translateActiveException(), m_reaction ); |
8259 | } |
8260 | |
8261 | void AssertionHandler::handleExceptionThrownAsExpected() { |
8262 | m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); |
8263 | } |
8264 | void AssertionHandler::handleExceptionNotThrownAsExpected() { |
8265 | m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); |
8266 | } |
8267 | |
8268 | void AssertionHandler::handleUnexpectedExceptionNotThrown() { |
8269 | m_resultCapture.handleUnexpectedExceptionNotThrown( m_assertionInfo, m_reaction ); |
8270 | } |
8271 | |
8272 | void AssertionHandler::handleThrowingCallSkipped() { |
8273 | m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); |
8274 | } |
8275 | |
8276 | // This is the overload that takes a string and infers the Equals matcher from it |
8277 | // The more general overload, that takes any string matcher, is in catch_capture_matchers.cpp |
8278 | void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef const& matcherString ) { |
8279 | handleExceptionMatchExpr( handler, Matchers::Equals( str ), matcherString ); |
8280 | } |
8281 | |
8282 | } // namespace Catch |
8283 | // end catch_assertionhandler.cpp |
8284 | // start catch_assertionresult.cpp |
8285 | |
8286 | namespace Catch { |
8287 | AssertionResultData::AssertionResultData(ResultWas::OfType _resultType, LazyExpression const & _lazyExpression): |
8288 | lazyExpression(_lazyExpression), |
8289 | resultType(_resultType) {} |
8290 | |
8291 | std::string AssertionResultData::reconstructExpression() const { |
8292 | |
8293 | if( reconstructedExpression.empty() ) { |
8294 | if( lazyExpression ) { |
8295 | ReusableStringStream ; |
8296 | rss << lazyExpression; |
8297 | reconstructedExpression = rss.str(); |
8298 | } |
8299 | } |
8300 | return reconstructedExpression; |
8301 | } |
8302 | |
8303 | AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) |
8304 | : m_info( info ), |
8305 | m_resultData( data ) |
8306 | {} |
8307 | |
8308 | // Result was a success |
8309 | bool AssertionResult::succeeded() const { |
8310 | return Catch::isOk( m_resultData.resultType ); |
8311 | } |
8312 | |
8313 | // Result was a success, or failure is suppressed |
8314 | bool AssertionResult::isOk() const { |
8315 | return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition ); |
8316 | } |
8317 | |
8318 | ResultWas::OfType AssertionResult::getResultType() const { |
8319 | return m_resultData.resultType; |
8320 | } |
8321 | |
8322 | bool AssertionResult::hasExpression() const { |
8323 | return !m_info.capturedExpression.empty(); |
8324 | } |
8325 | |
8326 | bool AssertionResult::hasMessage() const { |
8327 | return !m_resultData.message.empty(); |
8328 | } |
8329 | |
8330 | std::string AssertionResult::getExpression() const { |
8331 | // Possibly overallocating by 3 characters should be basically free |
8332 | std::string expr; expr.reserve(m_info.capturedExpression.size() + 3); |
8333 | if (isFalseTest(m_info.resultDisposition)) { |
8334 | expr += "!(" ; |
8335 | } |
8336 | expr += m_info.capturedExpression; |
8337 | if (isFalseTest(m_info.resultDisposition)) { |
8338 | expr += ')'; |
8339 | } |
8340 | return expr; |
8341 | } |
8342 | |
8343 | std::string AssertionResult::getExpressionInMacro() const { |
8344 | std::string expr; |
8345 | if( m_info.macroName.empty() ) |
8346 | expr = static_cast<std::string>(m_info.capturedExpression); |
8347 | else { |
8348 | expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 ); |
8349 | expr += m_info.macroName; |
8350 | expr += "( " ; |
8351 | expr += m_info.capturedExpression; |
8352 | expr += " )" ; |
8353 | } |
8354 | return expr; |
8355 | } |
8356 | |
8357 | bool AssertionResult::hasExpandedExpression() const { |
8358 | return hasExpression() && getExpandedExpression() != getExpression(); |
8359 | } |
8360 | |
8361 | std::string AssertionResult::getExpandedExpression() const { |
8362 | std::string expr = m_resultData.reconstructExpression(); |
8363 | return expr.empty() |
8364 | ? getExpression() |
8365 | : expr; |
8366 | } |
8367 | |
8368 | std::string AssertionResult::getMessage() const { |
8369 | return m_resultData.message; |
8370 | } |
8371 | SourceLineInfo AssertionResult::getSourceInfo() const { |
8372 | return m_info.lineInfo; |
8373 | } |
8374 | |
8375 | StringRef AssertionResult::getTestMacroName() const { |
8376 | return m_info.macroName; |
8377 | } |
8378 | |
8379 | } // end namespace Catch |
8380 | // end catch_assertionresult.cpp |
8381 | // start catch_capture_matchers.cpp |
8382 | |
8383 | namespace Catch { |
8384 | |
8385 | using StringMatcher = Matchers::Impl::MatcherBase<std::string>; |
8386 | |
8387 | // This is the general overload that takes a any string matcher |
8388 | // There is another overload, in catch_assertionhandler.h/.cpp, that only takes a string and infers |
8389 | // the Equals matcher (so the header does not mention matchers) |
8390 | void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString ) { |
8391 | std::string exceptionMessage = Catch::translateActiveException(); |
8392 | MatchExpr<std::string, StringMatcher const&> expr( exceptionMessage, matcher, matcherString ); |
8393 | handler.handleExpr( expr ); |
8394 | } |
8395 | |
8396 | } // namespace Catch |
8397 | // end catch_capture_matchers.cpp |
8398 | // start catch_commandline.cpp |
8399 | |
8400 | // start catch_commandline.h |
8401 | |
8402 | // start catch_clara.h |
8403 | |
8404 | // Use Catch's value for console width (store Clara's off to the side, if present) |
8405 | #ifdef CLARA_CONFIG_CONSOLE_WIDTH |
8406 | #define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH |
8407 | #undef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH |
8408 | #endif |
8409 | #define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH-1 |
8410 | |
8411 | #ifdef __clang__ |
8412 | #pragma clang diagnostic push |
8413 | #pragma clang diagnostic ignored "-Wweak-vtables" |
8414 | #pragma clang diagnostic ignored "-Wexit-time-destructors" |
8415 | #pragma clang diagnostic ignored "-Wshadow" |
8416 | #endif |
8417 | |
8418 | // start clara.hpp |
8419 | // Copyright 2017 Two Blue Cubes Ltd. All rights reserved. |
8420 | // |
8421 | // Distributed under the Boost Software License, Version 1.0. (See accompanying |
8422 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
8423 | // |
8424 | // See https://github.com/philsquared/Clara for more details |
8425 | |
8426 | // Clara v1.1.5 |
8427 | |
8428 | |
8429 | #ifndef CATCH_CLARA_CONFIG_CONSOLE_WIDTH |
8430 | #define CATCH_CLARA_CONFIG_CONSOLE_WIDTH 80 |
8431 | #endif |
8432 | |
8433 | #ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH |
8434 | #define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CLARA_CONFIG_CONSOLE_WIDTH |
8435 | #endif |
8436 | |
8437 | #ifndef CLARA_CONFIG_OPTIONAL_TYPE |
8438 | #ifdef __has_include |
8439 | #if __has_include(<optional>) && __cplusplus >= 201703L |
8440 | #include <optional> |
8441 | #define CLARA_CONFIG_OPTIONAL_TYPE std::optional |
8442 | #endif |
8443 | #endif |
8444 | #endif |
8445 | |
8446 | // ----------- #included from clara_textflow.hpp ----------- |
8447 | |
8448 | // TextFlowCpp |
8449 | // |
8450 | // A single-header library for wrapping and laying out basic text, by Phil Nash |
8451 | // |
8452 | // Distributed under the Boost Software License, Version 1.0. (See accompanying |
8453 | // file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
8454 | // |
8455 | // This project is hosted at https://github.com/philsquared/textflowcpp |
8456 | |
8457 | |
8458 | #include <cassert> |
8459 | #include <ostream> |
8460 | #include <sstream> |
8461 | #include <vector> |
8462 | |
8463 | #ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH |
8464 | #define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH 80 |
8465 | #endif |
8466 | |
8467 | namespace Catch { |
8468 | namespace clara { |
8469 | namespace TextFlow { |
8470 | |
8471 | inline auto isWhitespace(char c) -> bool { |
8472 | static std::string chars = " \t\n\r" ; |
8473 | return chars.find(c) != std::string::npos; |
8474 | } |
8475 | inline auto isBreakableBefore(char c) -> bool { |
8476 | static std::string chars = "[({<|" ; |
8477 | return chars.find(c) != std::string::npos; |
8478 | } |
8479 | inline auto isBreakableAfter(char c) -> bool { |
8480 | static std::string chars = "])}>.,:;*+-=&/\\" ; |
8481 | return chars.find(c) != std::string::npos; |
8482 | } |
8483 | |
8484 | class Columns; |
8485 | |
8486 | class Column { |
8487 | std::vector<std::string> m_strings; |
8488 | size_t m_width = CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH; |
8489 | size_t m_indent = 0; |
8490 | size_t m_initialIndent = std::string::npos; |
8491 | |
8492 | public: |
8493 | class iterator { |
8494 | friend Column; |
8495 | |
8496 | Column const& m_column; |
8497 | size_t m_stringIndex = 0; |
8498 | size_t m_pos = 0; |
8499 | |
8500 | size_t m_len = 0; |
8501 | size_t m_end = 0; |
8502 | bool m_suffix = false; |
8503 | |
8504 | iterator(Column const& column, size_t stringIndex) |
8505 | : m_column(column), |
8506 | m_stringIndex(stringIndex) {} |
8507 | |
8508 | auto line() const -> std::string const& { return m_column.m_strings[m_stringIndex]; } |
8509 | |
8510 | auto isBoundary(size_t at) const -> bool { |
8511 | assert(at > 0); |
8512 | assert(at <= line().size()); |
8513 | |
8514 | return at == line().size() || |
8515 | (isWhitespace(line()[at]) && !isWhitespace(line()[at - 1])) || |
8516 | isBreakableBefore(line()[at]) || |
8517 | isBreakableAfter(line()[at - 1]); |
8518 | } |
8519 | |
8520 | void calcLength() { |
8521 | assert(m_stringIndex < m_column.m_strings.size()); |
8522 | |
8523 | m_suffix = false; |
8524 | auto width = m_column.m_width - indent(); |
8525 | m_end = m_pos; |
8526 | if (line()[m_pos] == '\n') { |
8527 | ++m_end; |
8528 | } |
8529 | while (m_end < line().size() && line()[m_end] != '\n') |
8530 | ++m_end; |
8531 | |
8532 | if (m_end < m_pos + width) { |
8533 | m_len = m_end - m_pos; |
8534 | } else { |
8535 | size_t len = width; |
8536 | while (len > 0 && !isBoundary(m_pos + len)) |
8537 | --len; |
8538 | while (len > 0 && isWhitespace(line()[m_pos + len - 1])) |
8539 | --len; |
8540 | |
8541 | if (len > 0) { |
8542 | m_len = len; |
8543 | } else { |
8544 | m_suffix = true; |
8545 | m_len = width - 1; |
8546 | } |
8547 | } |
8548 | } |
8549 | |
8550 | auto indent() const -> size_t { |
8551 | auto initial = m_pos == 0 && m_stringIndex == 0 ? m_column.m_initialIndent : std::string::npos; |
8552 | return initial == std::string::npos ? m_column.m_indent : initial; |
8553 | } |
8554 | |
8555 | auto addIndentAndSuffix(std::string const &plain) const -> std::string { |
8556 | return std::string(indent(), ' ') + (m_suffix ? plain + "-" : plain); |
8557 | } |
8558 | |
8559 | public: |
8560 | using difference_type = std::ptrdiff_t; |
8561 | using value_type = std::string; |
8562 | using pointer = value_type * ; |
8563 | using reference = value_type & ; |
8564 | using iterator_category = std::forward_iterator_tag; |
8565 | |
8566 | explicit iterator(Column const& column) : m_column(column) { |
8567 | assert(m_column.m_width > m_column.m_indent); |
8568 | assert(m_column.m_initialIndent == std::string::npos || m_column.m_width > m_column.m_initialIndent); |
8569 | calcLength(); |
8570 | if (m_len == 0) |
8571 | m_stringIndex++; // Empty string |
8572 | } |
8573 | |
8574 | auto operator *() const -> std::string { |
8575 | assert(m_stringIndex < m_column.m_strings.size()); |
8576 | assert(m_pos <= m_end); |
8577 | return addIndentAndSuffix(line().substr(m_pos, m_len)); |
8578 | } |
8579 | |
8580 | auto operator ++() -> iterator& { |
8581 | m_pos += m_len; |
8582 | if (m_pos < line().size() && line()[m_pos] == '\n') |
8583 | m_pos += 1; |
8584 | else |
8585 | while (m_pos < line().size() && isWhitespace(line()[m_pos])) |
8586 | ++m_pos; |
8587 | |
8588 | if (m_pos == line().size()) { |
8589 | m_pos = 0; |
8590 | ++m_stringIndex; |
8591 | } |
8592 | if (m_stringIndex < m_column.m_strings.size()) |
8593 | calcLength(); |
8594 | return *this; |
8595 | } |
8596 | auto operator ++(int) -> iterator { |
8597 | iterator prev(*this); |
8598 | operator++(); |
8599 | return prev; |
8600 | } |
8601 | |
8602 | auto operator ==(iterator const& other) const -> bool { |
8603 | return |
8604 | m_pos == other.m_pos && |
8605 | m_stringIndex == other.m_stringIndex && |
8606 | &m_column == &other.m_column; |
8607 | } |
8608 | auto operator !=(iterator const& other) const -> bool { |
8609 | return !operator==(other); |
8610 | } |
8611 | }; |
8612 | using const_iterator = iterator; |
8613 | |
8614 | explicit Column(std::string const& text) { m_strings.push_back(text); } |
8615 | |
8616 | auto width(size_t newWidth) -> Column& { |
8617 | assert(newWidth > 0); |
8618 | m_width = newWidth; |
8619 | return *this; |
8620 | } |
8621 | auto indent(size_t newIndent) -> Column& { |
8622 | m_indent = newIndent; |
8623 | return *this; |
8624 | } |
8625 | auto initialIndent(size_t newIndent) -> Column& { |
8626 | m_initialIndent = newIndent; |
8627 | return *this; |
8628 | } |
8629 | |
8630 | auto width() const -> size_t { return m_width; } |
8631 | auto begin() const -> iterator { return iterator(*this); } |
8632 | auto end() const -> iterator { return { *this, m_strings.size() }; } |
8633 | |
8634 | inline friend std::ostream& operator << (std::ostream& os, Column const& col) { |
8635 | bool first = true; |
8636 | for (auto line : col) { |
8637 | if (first) |
8638 | first = false; |
8639 | else |
8640 | os << "\n" ; |
8641 | os << line; |
8642 | } |
8643 | return os; |
8644 | } |
8645 | |
8646 | auto operator + (Column const& other)->Columns; |
8647 | |
8648 | auto toString() const -> std::string { |
8649 | std::ostringstream oss; |
8650 | oss << *this; |
8651 | return oss.str(); |
8652 | } |
8653 | }; |
8654 | |
8655 | class Spacer : public Column { |
8656 | |
8657 | public: |
8658 | explicit Spacer(size_t spaceWidth) : Column("" ) { |
8659 | width(spaceWidth); |
8660 | } |
8661 | }; |
8662 | |
8663 | class Columns { |
8664 | std::vector<Column> m_columns; |
8665 | |
8666 | public: |
8667 | |
8668 | class iterator { |
8669 | friend Columns; |
8670 | struct EndTag {}; |
8671 | |
8672 | std::vector<Column> const& m_columns; |
8673 | std::vector<Column::iterator> m_iterators; |
8674 | size_t m_activeIterators; |
8675 | |
8676 | iterator(Columns const& columns, EndTag) |
8677 | : m_columns(columns.m_columns), |
8678 | m_activeIterators(0) { |
8679 | m_iterators.reserve(m_columns.size()); |
8680 | |
8681 | for (auto const& col : m_columns) |
8682 | m_iterators.push_back(col.end()); |
8683 | } |
8684 | |
8685 | public: |
8686 | using difference_type = std::ptrdiff_t; |
8687 | using value_type = std::string; |
8688 | using pointer = value_type * ; |
8689 | using reference = value_type & ; |
8690 | using iterator_category = std::forward_iterator_tag; |
8691 | |
8692 | explicit iterator(Columns const& columns) |
8693 | : m_columns(columns.m_columns), |
8694 | m_activeIterators(m_columns.size()) { |
8695 | m_iterators.reserve(m_columns.size()); |
8696 | |
8697 | for (auto const& col : m_columns) |
8698 | m_iterators.push_back(col.begin()); |
8699 | } |
8700 | |
8701 | auto operator ==(iterator const& other) const -> bool { |
8702 | return m_iterators == other.m_iterators; |
8703 | } |
8704 | auto operator !=(iterator const& other) const -> bool { |
8705 | return m_iterators != other.m_iterators; |
8706 | } |
8707 | auto operator *() const -> std::string { |
8708 | std::string row, padding; |
8709 | |
8710 | for (size_t i = 0; i < m_columns.size(); ++i) { |
8711 | auto width = m_columns[i].width(); |
8712 | if (m_iterators[i] != m_columns[i].end()) { |
8713 | std::string col = *m_iterators[i]; |
8714 | row += padding + col; |
8715 | if (col.size() < width) |
8716 | padding = std::string(width - col.size(), ' '); |
8717 | else |
8718 | padding = "" ; |
8719 | } else { |
8720 | padding += std::string(width, ' '); |
8721 | } |
8722 | } |
8723 | return row; |
8724 | } |
8725 | auto operator ++() -> iterator& { |
8726 | for (size_t i = 0; i < m_columns.size(); ++i) { |
8727 | if (m_iterators[i] != m_columns[i].end()) |
8728 | ++m_iterators[i]; |
8729 | } |
8730 | return *this; |
8731 | } |
8732 | auto operator ++(int) -> iterator { |
8733 | iterator prev(*this); |
8734 | operator++(); |
8735 | return prev; |
8736 | } |
8737 | }; |
8738 | using const_iterator = iterator; |
8739 | |
8740 | auto begin() const -> iterator { return iterator(*this); } |
8741 | auto end() const -> iterator { return { *this, iterator::EndTag() }; } |
8742 | |
8743 | auto operator += (Column const& col) -> Columns& { |
8744 | m_columns.push_back(col); |
8745 | return *this; |
8746 | } |
8747 | auto operator + (Column const& col) -> Columns { |
8748 | Columns combined = *this; |
8749 | combined += col; |
8750 | return combined; |
8751 | } |
8752 | |
8753 | inline friend std::ostream& operator << (std::ostream& os, Columns const& cols) { |
8754 | |
8755 | bool first = true; |
8756 | for (auto line : cols) { |
8757 | if (first) |
8758 | first = false; |
8759 | else |
8760 | os << "\n" ; |
8761 | os << line; |
8762 | } |
8763 | return os; |
8764 | } |
8765 | |
8766 | auto toString() const -> std::string { |
8767 | std::ostringstream oss; |
8768 | oss << *this; |
8769 | return oss.str(); |
8770 | } |
8771 | }; |
8772 | |
8773 | inline auto Column::operator + (Column const& other) -> Columns { |
8774 | Columns cols; |
8775 | cols += *this; |
8776 | cols += other; |
8777 | return cols; |
8778 | } |
8779 | } |
8780 | |
8781 | } |
8782 | } |
8783 | |
8784 | // ----------- end of #include from clara_textflow.hpp ----------- |
8785 | // ........... back in clara.hpp |
8786 | |
8787 | #include <cctype> |
8788 | #include <string> |
8789 | #include <memory> |
8790 | #include <set> |
8791 | #include <algorithm> |
8792 | |
8793 | #if !defined(CATCH_PLATFORM_WINDOWS) && ( defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) ) |
8794 | #define CATCH_PLATFORM_WINDOWS |
8795 | #endif |
8796 | |
8797 | namespace Catch { namespace clara { |
8798 | namespace detail { |
8799 | |
8800 | // Traits for extracting arg and return type of lambdas (for single argument lambdas) |
8801 | template<typename L> |
8802 | struct UnaryLambdaTraits : UnaryLambdaTraits<decltype( &L::operator() )> {}; |
8803 | |
8804 | template<typename ClassT, typename ReturnT, typename... Args> |
8805 | struct UnaryLambdaTraits<ReturnT( ClassT::* )( Args... ) const> { |
8806 | static const bool isValid = false; |
8807 | }; |
8808 | |
8809 | template<typename ClassT, typename ReturnT, typename ArgT> |
8810 | struct UnaryLambdaTraits<ReturnT( ClassT::* )( ArgT ) const> { |
8811 | static const bool isValid = true; |
8812 | using ArgType = typename std::remove_const<typename std::remove_reference<ArgT>::type>::type; |
8813 | using ReturnType = ReturnT; |
8814 | }; |
8815 | |
8816 | class TokenStream; |
8817 | |
8818 | // Transport for raw args (copied from main args, or supplied via init list for testing) |
8819 | class Args { |
8820 | friend TokenStream; |
8821 | std::string m_exeName; |
8822 | std::vector<std::string> m_args; |
8823 | |
8824 | public: |
8825 | Args( int argc, char const* const* argv ) |
8826 | : m_exeName(argv[0]), |
8827 | m_args(argv + 1, argv + argc) {} |
8828 | |
8829 | Args( std::initializer_list<std::string> args ) |
8830 | : m_exeName( *args.begin() ), |
8831 | m_args( args.begin()+1, args.end() ) |
8832 | {} |
8833 | |
8834 | auto exeName() const -> std::string { |
8835 | return m_exeName; |
8836 | } |
8837 | }; |
8838 | |
8839 | // Wraps a token coming from a token stream. These may not directly correspond to strings as a single string |
8840 | // may encode an option + its argument if the : or = form is used |
8841 | enum class TokenType { |
8842 | Option, Argument |
8843 | }; |
8844 | struct Token { |
8845 | TokenType type; |
8846 | std::string token; |
8847 | }; |
8848 | |
8849 | inline auto isOptPrefix( char c ) -> bool { |
8850 | return c == '-' |
8851 | #ifdef CATCH_PLATFORM_WINDOWS |
8852 | || c == '/' |
8853 | #endif |
8854 | ; |
8855 | } |
8856 | |
8857 | // Abstracts iterators into args as a stream of tokens, with option arguments uniformly handled |
8858 | class TokenStream { |
8859 | using Iterator = std::vector<std::string>::const_iterator; |
8860 | Iterator it; |
8861 | Iterator itEnd; |
8862 | std::vector<Token> m_tokenBuffer; |
8863 | |
8864 | void loadBuffer() { |
8865 | m_tokenBuffer.resize( 0 ); |
8866 | |
8867 | // Skip any empty strings |
8868 | while( it != itEnd && it->empty() ) |
8869 | ++it; |
8870 | |
8871 | if( it != itEnd ) { |
8872 | auto const &next = *it; |
8873 | if( isOptPrefix( next[0] ) ) { |
8874 | auto delimiterPos = next.find_first_of( " :=" ); |
8875 | if( delimiterPos != std::string::npos ) { |
8876 | m_tokenBuffer.push_back( { TokenType::Option, next.substr( 0, delimiterPos ) } ); |
8877 | m_tokenBuffer.push_back( { TokenType::Argument, next.substr( delimiterPos + 1 ) } ); |
8878 | } else { |
8879 | if( next[1] != '-' && next.size() > 2 ) { |
8880 | std::string opt = "- " ; |
8881 | for( size_t i = 1; i < next.size(); ++i ) { |
8882 | opt[1] = next[i]; |
8883 | m_tokenBuffer.push_back( { TokenType::Option, opt } ); |
8884 | } |
8885 | } else { |
8886 | m_tokenBuffer.push_back( { TokenType::Option, next } ); |
8887 | } |
8888 | } |
8889 | } else { |
8890 | m_tokenBuffer.push_back( { TokenType::Argument, next } ); |
8891 | } |
8892 | } |
8893 | } |
8894 | |
8895 | public: |
8896 | explicit TokenStream( Args const &args ) : TokenStream( args.m_args.begin(), args.m_args.end() ) {} |
8897 | |
8898 | TokenStream( Iterator it, Iterator itEnd ) : it( it ), itEnd( itEnd ) { |
8899 | loadBuffer(); |
8900 | } |
8901 | |
8902 | explicit operator bool() const { |
8903 | return !m_tokenBuffer.empty() || it != itEnd; |
8904 | } |
8905 | |
8906 | auto count() const -> size_t { return m_tokenBuffer.size() + (itEnd - it); } |
8907 | |
8908 | auto operator*() const -> Token { |
8909 | assert( !m_tokenBuffer.empty() ); |
8910 | return m_tokenBuffer.front(); |
8911 | } |
8912 | |
8913 | auto operator->() const -> Token const * { |
8914 | assert( !m_tokenBuffer.empty() ); |
8915 | return &m_tokenBuffer.front(); |
8916 | } |
8917 | |
8918 | auto operator++() -> TokenStream & { |
8919 | if( m_tokenBuffer.size() >= 2 ) { |
8920 | m_tokenBuffer.erase( m_tokenBuffer.begin() ); |
8921 | } else { |
8922 | if( it != itEnd ) |
8923 | ++it; |
8924 | loadBuffer(); |
8925 | } |
8926 | return *this; |
8927 | } |
8928 | }; |
8929 | |
8930 | class ResultBase { |
8931 | public: |
8932 | enum Type { |
8933 | Ok, LogicError, RuntimeError |
8934 | }; |
8935 | |
8936 | protected: |
8937 | ResultBase( Type type ) : m_type( type ) {} |
8938 | virtual ~ResultBase() = default; |
8939 | |
8940 | virtual void enforceOk() const = 0; |
8941 | |
8942 | Type m_type; |
8943 | }; |
8944 | |
8945 | template<typename T> |
8946 | class ResultValueBase : public ResultBase { |
8947 | public: |
8948 | auto value() const -> T const & { |
8949 | enforceOk(); |
8950 | return m_value; |
8951 | } |
8952 | |
8953 | protected: |
8954 | ResultValueBase( Type type ) : ResultBase( type ) {} |
8955 | |
8956 | ResultValueBase( ResultValueBase const &other ) : ResultBase( other ) { |
8957 | if( m_type == ResultBase::Ok ) |
8958 | new( &m_value ) T( other.m_value ); |
8959 | } |
8960 | |
8961 | ResultValueBase( Type, T const &value ) : ResultBase( Ok ) { |
8962 | new( &m_value ) T( value ); |
8963 | } |
8964 | |
8965 | auto operator=( ResultValueBase const &other ) -> ResultValueBase & { |
8966 | if( m_type == ResultBase::Ok ) |
8967 | m_value.~T(); |
8968 | ResultBase::operator=(other); |
8969 | if( m_type == ResultBase::Ok ) |
8970 | new( &m_value ) T( other.m_value ); |
8971 | return *this; |
8972 | } |
8973 | |
8974 | ~ResultValueBase() override { |
8975 | if( m_type == Ok ) |
8976 | m_value.~T(); |
8977 | } |
8978 | |
8979 | union { |
8980 | T m_value; |
8981 | }; |
8982 | }; |
8983 | |
8984 | template<> |
8985 | class ResultValueBase<void> : public ResultBase { |
8986 | protected: |
8987 | using ResultBase::ResultBase; |
8988 | }; |
8989 | |
8990 | template<typename T = void> |
8991 | class BasicResult : public ResultValueBase<T> { |
8992 | public: |
8993 | template<typename U> |
8994 | explicit BasicResult( BasicResult<U> const &other ) |
8995 | : ResultValueBase<T>( other.type() ), |
8996 | m_errorMessage( other.errorMessage() ) |
8997 | { |
8998 | assert( type() != ResultBase::Ok ); |
8999 | } |
9000 | |
9001 | template<typename U> |
9002 | static auto ok( U const &value ) -> BasicResult { return { ResultBase::Ok, value }; } |
9003 | static auto ok() -> BasicResult { return { ResultBase::Ok }; } |
9004 | static auto logicError( std::string const &message ) -> BasicResult { return { ResultBase::LogicError, message }; } |
9005 | static auto runtimeError( std::string const &message ) -> BasicResult { return { ResultBase::RuntimeError, message }; } |
9006 | |
9007 | explicit operator bool() const { return m_type == ResultBase::Ok; } |
9008 | auto type() const -> ResultBase::Type { return m_type; } |
9009 | auto errorMessage() const -> std::string { return m_errorMessage; } |
9010 | |
9011 | protected: |
9012 | void enforceOk() const override { |
9013 | |
9014 | // Errors shouldn't reach this point, but if they do |
9015 | // the actual error message will be in m_errorMessage |
9016 | assert( m_type != ResultBase::LogicError ); |
9017 | assert( m_type != ResultBase::RuntimeError ); |
9018 | if( m_type != ResultBase::Ok ) |
9019 | std::abort(); |
9020 | } |
9021 | |
9022 | std::string m_errorMessage; // Only populated if resultType is an error |
9023 | |
9024 | BasicResult( ResultBase::Type type, std::string const &message ) |
9025 | : ResultValueBase<T>(type), |
9026 | m_errorMessage(message) |
9027 | { |
9028 | assert( m_type != ResultBase::Ok ); |
9029 | } |
9030 | |
9031 | using ResultValueBase<T>::ResultValueBase; |
9032 | using ResultBase::m_type; |
9033 | }; |
9034 | |
9035 | enum class ParseResultType { |
9036 | Matched, NoMatch, ShortCircuitAll, ShortCircuitSame |
9037 | }; |
9038 | |
9039 | class ParseState { |
9040 | public: |
9041 | |
9042 | ParseState( ParseResultType type, TokenStream const &remainingTokens ) |
9043 | : m_type(type), |
9044 | m_remainingTokens( remainingTokens ) |
9045 | {} |
9046 | |
9047 | auto type() const -> ParseResultType { return m_type; } |
9048 | auto remainingTokens() const -> TokenStream { return m_remainingTokens; } |
9049 | |
9050 | private: |
9051 | ParseResultType m_type; |
9052 | TokenStream m_remainingTokens; |
9053 | }; |
9054 | |
9055 | using Result = BasicResult<void>; |
9056 | using ParserResult = BasicResult<ParseResultType>; |
9057 | using InternalParseResult = BasicResult<ParseState>; |
9058 | |
9059 | struct HelpColumns { |
9060 | std::string left; |
9061 | std::string right; |
9062 | }; |
9063 | |
9064 | template<typename T> |
9065 | inline auto convertInto( std::string const &source, T& target ) -> ParserResult { |
9066 | std::stringstream ss; |
9067 | ss << source; |
9068 | ss >> target; |
9069 | if( ss.fail() ) |
9070 | return ParserResult::runtimeError( "Unable to convert '" + source + "' to destination type" ); |
9071 | else |
9072 | return ParserResult::ok( ParseResultType::Matched ); |
9073 | } |
9074 | inline auto convertInto( std::string const &source, std::string& target ) -> ParserResult { |
9075 | target = source; |
9076 | return ParserResult::ok( ParseResultType::Matched ); |
9077 | } |
9078 | inline auto convertInto( std::string const &source, bool &target ) -> ParserResult { |
9079 | std::string srcLC = source; |
9080 | std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( unsigned char c ) { return static_cast<char>( std::tolower(c) ); } ); |
9081 | if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on" ) |
9082 | target = true; |
9083 | else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off" ) |
9084 | target = false; |
9085 | else |
9086 | return ParserResult::runtimeError( "Expected a boolean value but did not recognise: '" + source + "'" ); |
9087 | return ParserResult::ok( ParseResultType::Matched ); |
9088 | } |
9089 | #ifdef CLARA_CONFIG_OPTIONAL_TYPE |
9090 | template<typename T> |
9091 | inline auto convertInto( std::string const &source, CLARA_CONFIG_OPTIONAL_TYPE<T>& target ) -> ParserResult { |
9092 | T temp; |
9093 | auto result = convertInto( source, temp ); |
9094 | if( result ) |
9095 | target = std::move(temp); |
9096 | return result; |
9097 | } |
9098 | #endif // CLARA_CONFIG_OPTIONAL_TYPE |
9099 | |
9100 | struct NonCopyable { |
9101 | NonCopyable() = default; |
9102 | NonCopyable( NonCopyable const & ) = delete; |
9103 | NonCopyable( NonCopyable && ) = delete; |
9104 | NonCopyable &operator=( NonCopyable const & ) = delete; |
9105 | NonCopyable &operator=( NonCopyable && ) = delete; |
9106 | }; |
9107 | |
9108 | struct BoundRef : NonCopyable { |
9109 | virtual ~BoundRef() = default; |
9110 | virtual auto isContainer() const -> bool { return false; } |
9111 | virtual auto isFlag() const -> bool { return false; } |
9112 | }; |
9113 | struct BoundValueRefBase : BoundRef { |
9114 | virtual auto setValue( std::string const &arg ) -> ParserResult = 0; |
9115 | }; |
9116 | struct BoundFlagRefBase : BoundRef { |
9117 | virtual auto setFlag( bool flag ) -> ParserResult = 0; |
9118 | virtual auto isFlag() const -> bool { return true; } |
9119 | }; |
9120 | |
9121 | template<typename T> |
9122 | struct BoundValueRef : BoundValueRefBase { |
9123 | T &m_ref; |
9124 | |
9125 | explicit BoundValueRef( T &ref ) : m_ref( ref ) {} |
9126 | |
9127 | auto setValue( std::string const &arg ) -> ParserResult override { |
9128 | return convertInto( arg, m_ref ); |
9129 | } |
9130 | }; |
9131 | |
9132 | template<typename T> |
9133 | struct BoundValueRef<std::vector<T>> : BoundValueRefBase { |
9134 | std::vector<T> &m_ref; |
9135 | |
9136 | explicit BoundValueRef( std::vector<T> &ref ) : m_ref( ref ) {} |
9137 | |
9138 | auto isContainer() const -> bool override { return true; } |
9139 | |
9140 | auto setValue( std::string const &arg ) -> ParserResult override { |
9141 | T temp; |
9142 | auto result = convertInto( arg, temp ); |
9143 | if( result ) |
9144 | m_ref.push_back( temp ); |
9145 | return result; |
9146 | } |
9147 | }; |
9148 | |
9149 | struct BoundFlagRef : BoundFlagRefBase { |
9150 | bool &m_ref; |
9151 | |
9152 | explicit BoundFlagRef( bool &ref ) : m_ref( ref ) {} |
9153 | |
9154 | auto setFlag( bool flag ) -> ParserResult override { |
9155 | m_ref = flag; |
9156 | return ParserResult::ok( ParseResultType::Matched ); |
9157 | } |
9158 | }; |
9159 | |
9160 | template<typename ReturnType> |
9161 | struct LambdaInvoker { |
9162 | static_assert( std::is_same<ReturnType, ParserResult>::value, "Lambda must return void or clara::ParserResult" ); |
9163 | |
9164 | template<typename L, typename ArgType> |
9165 | static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult { |
9166 | return lambda( arg ); |
9167 | } |
9168 | }; |
9169 | |
9170 | template<> |
9171 | struct LambdaInvoker<void> { |
9172 | template<typename L, typename ArgType> |
9173 | static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult { |
9174 | lambda( arg ); |
9175 | return ParserResult::ok( ParseResultType::Matched ); |
9176 | } |
9177 | }; |
9178 | |
9179 | template<typename ArgType, typename L> |
9180 | inline auto invokeLambda( L const &lambda, std::string const &arg ) -> ParserResult { |
9181 | ArgType temp{}; |
9182 | auto result = convertInto( arg, temp ); |
9183 | return !result |
9184 | ? result |
9185 | : LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( lambda, temp ); |
9186 | } |
9187 | |
9188 | template<typename L> |
9189 | struct BoundLambda : BoundValueRefBase { |
9190 | L m_lambda; |
9191 | |
9192 | static_assert( UnaryLambdaTraits<L>::isValid, "Supplied lambda must take exactly one argument" ); |
9193 | explicit BoundLambda( L const &lambda ) : m_lambda( lambda ) {} |
9194 | |
9195 | auto setValue( std::string const &arg ) -> ParserResult override { |
9196 | return invokeLambda<typename UnaryLambdaTraits<L>::ArgType>( m_lambda, arg ); |
9197 | } |
9198 | }; |
9199 | |
9200 | template<typename L> |
9201 | struct BoundFlagLambda : BoundFlagRefBase { |
9202 | L m_lambda; |
9203 | |
9204 | static_assert( UnaryLambdaTraits<L>::isValid, "Supplied lambda must take exactly one argument" ); |
9205 | static_assert( std::is_same<typename UnaryLambdaTraits<L>::ArgType, bool>::value, "flags must be boolean" ); |
9206 | |
9207 | explicit BoundFlagLambda( L const &lambda ) : m_lambda( lambda ) {} |
9208 | |
9209 | auto setFlag( bool flag ) -> ParserResult override { |
9210 | return LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( m_lambda, flag ); |
9211 | } |
9212 | }; |
9213 | |
9214 | enum class Optionality { Optional, Required }; |
9215 | |
9216 | struct Parser; |
9217 | |
9218 | class ParserBase { |
9219 | public: |
9220 | virtual ~ParserBase() = default; |
9221 | virtual auto validate() const -> Result { return Result::ok(); } |
9222 | virtual auto parse( std::string const& exeName, TokenStream const &tokens) const -> InternalParseResult = 0; |
9223 | virtual auto cardinality() const -> size_t { return 1; } |
9224 | |
9225 | auto parse( Args const &args ) const -> InternalParseResult { |
9226 | return parse( args.exeName(), TokenStream( args ) ); |
9227 | } |
9228 | }; |
9229 | |
9230 | template<typename DerivedT> |
9231 | class ComposableParserImpl : public ParserBase { |
9232 | public: |
9233 | template<typename T> |
9234 | auto operator|( T const &other ) const -> Parser; |
9235 | |
9236 | template<typename T> |
9237 | auto operator+( T const &other ) const -> Parser; |
9238 | }; |
9239 | |
9240 | // Common code and state for Args and Opts |
9241 | template<typename DerivedT> |
9242 | class ParserRefImpl : public ComposableParserImpl<DerivedT> { |
9243 | protected: |
9244 | Optionality m_optionality = Optionality::Optional; |
9245 | std::shared_ptr<BoundRef> m_ref; |
9246 | std::string m_hint; |
9247 | std::string m_description; |
9248 | |
9249 | explicit ParserRefImpl( std::shared_ptr<BoundRef> const &ref ) : m_ref( ref ) {} |
9250 | |
9251 | public: |
9252 | template<typename T> |
9253 | ParserRefImpl( T &ref, std::string const &hint ) |
9254 | : m_ref( std::make_shared<BoundValueRef<T>>( ref ) ), |
9255 | m_hint( hint ) |
9256 | {} |
9257 | |
9258 | template<typename LambdaT> |
9259 | ParserRefImpl( LambdaT const &ref, std::string const &hint ) |
9260 | : m_ref( std::make_shared<BoundLambda<LambdaT>>( ref ) ), |
9261 | m_hint(hint) |
9262 | {} |
9263 | |
9264 | auto operator()( std::string const &description ) -> DerivedT & { |
9265 | m_description = description; |
9266 | return static_cast<DerivedT &>( *this ); |
9267 | } |
9268 | |
9269 | auto optional() -> DerivedT & { |
9270 | m_optionality = Optionality::Optional; |
9271 | return static_cast<DerivedT &>( *this ); |
9272 | }; |
9273 | |
9274 | auto required() -> DerivedT & { |
9275 | m_optionality = Optionality::Required; |
9276 | return static_cast<DerivedT &>( *this ); |
9277 | }; |
9278 | |
9279 | auto isOptional() const -> bool { |
9280 | return m_optionality == Optionality::Optional; |
9281 | } |
9282 | |
9283 | auto cardinality() const -> size_t override { |
9284 | if( m_ref->isContainer() ) |
9285 | return 0; |
9286 | else |
9287 | return 1; |
9288 | } |
9289 | |
9290 | auto hint() const -> std::string { return m_hint; } |
9291 | }; |
9292 | |
9293 | class ExeName : public ComposableParserImpl<ExeName> { |
9294 | std::shared_ptr<std::string> m_name; |
9295 | std::shared_ptr<BoundValueRefBase> m_ref; |
9296 | |
9297 | template<typename LambdaT> |
9298 | static auto makeRef(LambdaT const &lambda) -> std::shared_ptr<BoundValueRefBase> { |
9299 | return std::make_shared<BoundLambda<LambdaT>>( lambda) ; |
9300 | } |
9301 | |
9302 | public: |
9303 | ExeName() : m_name( std::make_shared<std::string>( "<executable>" ) ) {} |
9304 | |
9305 | explicit ExeName( std::string &ref ) : ExeName() { |
9306 | m_ref = std::make_shared<BoundValueRef<std::string>>( ref ); |
9307 | } |
9308 | |
9309 | template<typename LambdaT> |
9310 | explicit ExeName( LambdaT const& lambda ) : ExeName() { |
9311 | m_ref = std::make_shared<BoundLambda<LambdaT>>( lambda ); |
9312 | } |
9313 | |
9314 | // The exe name is not parsed out of the normal tokens, but is handled specially |
9315 | auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override { |
9316 | return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) ); |
9317 | } |
9318 | |
9319 | auto name() const -> std::string { return *m_name; } |
9320 | auto set( std::string const& newName ) -> ParserResult { |
9321 | |
9322 | auto lastSlash = newName.find_last_of( "\\/" ); |
9323 | auto filename = ( lastSlash == std::string::npos ) |
9324 | ? newName |
9325 | : newName.substr( lastSlash+1 ); |
9326 | |
9327 | *m_name = filename; |
9328 | if( m_ref ) |
9329 | return m_ref->setValue( filename ); |
9330 | else |
9331 | return ParserResult::ok( ParseResultType::Matched ); |
9332 | } |
9333 | }; |
9334 | |
9335 | class Arg : public ParserRefImpl<Arg> { |
9336 | public: |
9337 | using ParserRefImpl::ParserRefImpl; |
9338 | |
9339 | auto parse( std::string const &, TokenStream const &tokens ) const -> InternalParseResult override { |
9340 | auto validationResult = validate(); |
9341 | if( !validationResult ) |
9342 | return InternalParseResult( validationResult ); |
9343 | |
9344 | auto remainingTokens = tokens; |
9345 | auto const &token = *remainingTokens; |
9346 | if( token.type != TokenType::Argument ) |
9347 | return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) ); |
9348 | |
9349 | assert( !m_ref->isFlag() ); |
9350 | auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() ); |
9351 | |
9352 | auto result = valueRef->setValue( remainingTokens->token ); |
9353 | if( !result ) |
9354 | return InternalParseResult( result ); |
9355 | else |
9356 | return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) ); |
9357 | } |
9358 | }; |
9359 | |
9360 | inline auto normaliseOpt( std::string const &optName ) -> std::string { |
9361 | #ifdef CATCH_PLATFORM_WINDOWS |
9362 | if( optName[0] == '/' ) |
9363 | return "-" + optName.substr( 1 ); |
9364 | else |
9365 | #endif |
9366 | return optName; |
9367 | } |
9368 | |
9369 | class Opt : public ParserRefImpl<Opt> { |
9370 | protected: |
9371 | std::vector<std::string> m_optNames; |
9372 | |
9373 | public: |
9374 | template<typename LambdaT> |
9375 | explicit Opt( LambdaT const &ref ) : ParserRefImpl( std::make_shared<BoundFlagLambda<LambdaT>>( ref ) ) {} |
9376 | |
9377 | explicit Opt( bool &ref ) : ParserRefImpl( std::make_shared<BoundFlagRef>( ref ) ) {} |
9378 | |
9379 | template<typename LambdaT> |
9380 | Opt( LambdaT const &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {} |
9381 | |
9382 | template<typename T> |
9383 | Opt( T &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {} |
9384 | |
9385 | auto operator[]( std::string const &optName ) -> Opt & { |
9386 | m_optNames.push_back( optName ); |
9387 | return *this; |
9388 | } |
9389 | |
9390 | auto getHelpColumns() const -> std::vector<HelpColumns> { |
9391 | std::ostringstream oss; |
9392 | bool first = true; |
9393 | for( auto const &opt : m_optNames ) { |
9394 | if (first) |
9395 | first = false; |
9396 | else |
9397 | oss << ", " ; |
9398 | oss << opt; |
9399 | } |
9400 | if( !m_hint.empty() ) |
9401 | oss << " <" << m_hint << ">" ; |
9402 | return { { oss.str(), m_description } }; |
9403 | } |
9404 | |
9405 | auto isMatch( std::string const &optToken ) const -> bool { |
9406 | auto normalisedToken = normaliseOpt( optToken ); |
9407 | for( auto const &name : m_optNames ) { |
9408 | if( normaliseOpt( name ) == normalisedToken ) |
9409 | return true; |
9410 | } |
9411 | return false; |
9412 | } |
9413 | |
9414 | using ParserBase::parse; |
9415 | |
9416 | auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override { |
9417 | auto validationResult = validate(); |
9418 | if( !validationResult ) |
9419 | return InternalParseResult( validationResult ); |
9420 | |
9421 | auto remainingTokens = tokens; |
9422 | if( remainingTokens && remainingTokens->type == TokenType::Option ) { |
9423 | auto const &token = *remainingTokens; |
9424 | if( isMatch(token.token ) ) { |
9425 | if( m_ref->isFlag() ) { |
9426 | auto flagRef = static_cast<detail::BoundFlagRefBase*>( m_ref.get() ); |
9427 | auto result = flagRef->setFlag( true ); |
9428 | if( !result ) |
9429 | return InternalParseResult( result ); |
9430 | if( result.value() == ParseResultType::ShortCircuitAll ) |
9431 | return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) ); |
9432 | } else { |
9433 | auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() ); |
9434 | ++remainingTokens; |
9435 | if( !remainingTokens ) |
9436 | return InternalParseResult::runtimeError( "Expected argument following " + token.token ); |
9437 | auto const &argToken = *remainingTokens; |
9438 | if( argToken.type != TokenType::Argument ) |
9439 | return InternalParseResult::runtimeError( "Expected argument following " + token.token ); |
9440 | auto result = valueRef->setValue( argToken.token ); |
9441 | if( !result ) |
9442 | return InternalParseResult( result ); |
9443 | if( result.value() == ParseResultType::ShortCircuitAll ) |
9444 | return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) ); |
9445 | } |
9446 | return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) ); |
9447 | } |
9448 | } |
9449 | return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) ); |
9450 | } |
9451 | |
9452 | auto validate() const -> Result override { |
9453 | if( m_optNames.empty() ) |
9454 | return Result::logicError( "No options supplied to Opt" ); |
9455 | for( auto const &name : m_optNames ) { |
9456 | if( name.empty() ) |
9457 | return Result::logicError( "Option name cannot be empty" ); |
9458 | #ifdef CATCH_PLATFORM_WINDOWS |
9459 | if( name[0] != '-' && name[0] != '/' ) |
9460 | return Result::logicError( "Option name must begin with '-' or '/'" ); |
9461 | #else |
9462 | if( name[0] != '-' ) |
9463 | return Result::logicError( "Option name must begin with '-'" ); |
9464 | #endif |
9465 | } |
9466 | return ParserRefImpl::validate(); |
9467 | } |
9468 | }; |
9469 | |
9470 | struct Help : Opt { |
9471 | Help( bool &showHelpFlag ) |
9472 | : Opt([&]( bool flag ) { |
9473 | showHelpFlag = flag; |
9474 | return ParserResult::ok( ParseResultType::ShortCircuitAll ); |
9475 | }) |
9476 | { |
9477 | static_cast<Opt &>( *this ) |
9478 | ("display usage information" ) |
9479 | ["-?" ]["-h" ]["--help" ] |
9480 | .optional(); |
9481 | } |
9482 | }; |
9483 | |
9484 | struct Parser : ParserBase { |
9485 | |
9486 | mutable ExeName m_exeName; |
9487 | std::vector<Opt> m_options; |
9488 | std::vector<Arg> m_args; |
9489 | |
9490 | auto operator|=( ExeName const &exeName ) -> Parser & { |
9491 | m_exeName = exeName; |
9492 | return *this; |
9493 | } |
9494 | |
9495 | auto operator|=( Arg const &arg ) -> Parser & { |
9496 | m_args.push_back(arg); |
9497 | return *this; |
9498 | } |
9499 | |
9500 | auto operator|=( Opt const &opt ) -> Parser & { |
9501 | m_options.push_back(opt); |
9502 | return *this; |
9503 | } |
9504 | |
9505 | auto operator|=( Parser const &other ) -> Parser & { |
9506 | m_options.insert(m_options.end(), other.m_options.begin(), other.m_options.end()); |
9507 | m_args.insert(m_args.end(), other.m_args.begin(), other.m_args.end()); |
9508 | return *this; |
9509 | } |
9510 | |
9511 | template<typename T> |
9512 | auto operator|( T const &other ) const -> Parser { |
9513 | return Parser( *this ) |= other; |
9514 | } |
9515 | |
9516 | // Forward deprecated interface with '+' instead of '|' |
9517 | template<typename T> |
9518 | auto operator+=( T const &other ) -> Parser & { return operator|=( other ); } |
9519 | template<typename T> |
9520 | auto operator+( T const &other ) const -> Parser { return operator|( other ); } |
9521 | |
9522 | auto getHelpColumns() const -> std::vector<HelpColumns> { |
9523 | std::vector<HelpColumns> cols; |
9524 | for (auto const &o : m_options) { |
9525 | auto childCols = o.getHelpColumns(); |
9526 | cols.insert( cols.end(), childCols.begin(), childCols.end() ); |
9527 | } |
9528 | return cols; |
9529 | } |
9530 | |
9531 | void writeToStream( std::ostream &os ) const { |
9532 | if (!m_exeName.name().empty()) { |
9533 | os << "usage:\n" << " " << m_exeName.name() << " " ; |
9534 | bool required = true, first = true; |
9535 | for( auto const &arg : m_args ) { |
9536 | if (first) |
9537 | first = false; |
9538 | else |
9539 | os << " " ; |
9540 | if( arg.isOptional() && required ) { |
9541 | os << "[" ; |
9542 | required = false; |
9543 | } |
9544 | os << "<" << arg.hint() << ">" ; |
9545 | if( arg.cardinality() == 0 ) |
9546 | os << " ... " ; |
9547 | } |
9548 | if( !required ) |
9549 | os << "]" ; |
9550 | if( !m_options.empty() ) |
9551 | os << " options" ; |
9552 | os << "\n\nwhere options are:" << std::endl; |
9553 | } |
9554 | |
9555 | auto rows = getHelpColumns(); |
9556 | size_t consoleWidth = CATCH_CLARA_CONFIG_CONSOLE_WIDTH; |
9557 | size_t optWidth = 0; |
9558 | for( auto const &cols : rows ) |
9559 | optWidth = (std::max)(optWidth, cols.left.size() + 2); |
9560 | |
9561 | optWidth = (std::min)(optWidth, consoleWidth/2); |
9562 | |
9563 | for( auto const &cols : rows ) { |
9564 | auto row = |
9565 | TextFlow::Column( cols.left ).width( optWidth ).indent( 2 ) + |
9566 | TextFlow::Spacer(4) + |
9567 | TextFlow::Column( cols.right ).width( consoleWidth - 7 - optWidth ); |
9568 | os << row << std::endl; |
9569 | } |
9570 | } |
9571 | |
9572 | friend auto operator<<( std::ostream &os, Parser const &parser ) -> std::ostream& { |
9573 | parser.writeToStream( os ); |
9574 | return os; |
9575 | } |
9576 | |
9577 | auto validate() const -> Result override { |
9578 | for( auto const &opt : m_options ) { |
9579 | auto result = opt.validate(); |
9580 | if( !result ) |
9581 | return result; |
9582 | } |
9583 | for( auto const &arg : m_args ) { |
9584 | auto result = arg.validate(); |
9585 | if( !result ) |
9586 | return result; |
9587 | } |
9588 | return Result::ok(); |
9589 | } |
9590 | |
9591 | using ParserBase::parse; |
9592 | |
9593 | auto parse( std::string const& exeName, TokenStream const &tokens ) const -> InternalParseResult override { |
9594 | |
9595 | struct ParserInfo { |
9596 | ParserBase const* parser = nullptr; |
9597 | size_t count = 0; |
9598 | }; |
9599 | const size_t totalParsers = m_options.size() + m_args.size(); |
9600 | assert( totalParsers < 512 ); |
9601 | // ParserInfo parseInfos[totalParsers]; // <-- this is what we really want to do |
9602 | ParserInfo parseInfos[512]; |
9603 | |
9604 | { |
9605 | size_t i = 0; |
9606 | for (auto const &opt : m_options) parseInfos[i++].parser = &opt; |
9607 | for (auto const &arg : m_args) parseInfos[i++].parser = &arg; |
9608 | } |
9609 | |
9610 | m_exeName.set( exeName ); |
9611 | |
9612 | auto result = InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) ); |
9613 | while( result.value().remainingTokens() ) { |
9614 | bool tokenParsed = false; |
9615 | |
9616 | for( size_t i = 0; i < totalParsers; ++i ) { |
9617 | auto& parseInfo = parseInfos[i]; |
9618 | if( parseInfo.parser->cardinality() == 0 || parseInfo.count < parseInfo.parser->cardinality() ) { |
9619 | result = parseInfo.parser->parse(exeName, result.value().remainingTokens()); |
9620 | if (!result) |
9621 | return result; |
9622 | if (result.value().type() != ParseResultType::NoMatch) { |
9623 | tokenParsed = true; |
9624 | ++parseInfo.count; |
9625 | break; |
9626 | } |
9627 | } |
9628 | } |
9629 | |
9630 | if( result.value().type() == ParseResultType::ShortCircuitAll ) |
9631 | return result; |
9632 | if( !tokenParsed ) |
9633 | return InternalParseResult::runtimeError( "Unrecognised token: " + result.value().remainingTokens()->token ); |
9634 | } |
9635 | // !TBD Check missing required options |
9636 | return result; |
9637 | } |
9638 | }; |
9639 | |
9640 | template<typename DerivedT> |
9641 | template<typename T> |
9642 | auto ComposableParserImpl<DerivedT>::operator|( T const &other ) const -> Parser { |
9643 | return Parser() | static_cast<DerivedT const &>( *this ) | other; |
9644 | } |
9645 | } // namespace detail |
9646 | |
9647 | // A Combined parser |
9648 | using detail::Parser; |
9649 | |
9650 | // A parser for options |
9651 | using detail::Opt; |
9652 | |
9653 | // A parser for arguments |
9654 | using detail::Arg; |
9655 | |
9656 | // Wrapper for argc, argv from main() |
9657 | using detail::Args; |
9658 | |
9659 | // Specifies the name of the executable |
9660 | using detail::ExeName; |
9661 | |
9662 | // Convenience wrapper for option parser that specifies the help option |
9663 | using detail::Help; |
9664 | |
9665 | // enum of result types from a parse |
9666 | using detail::ParseResultType; |
9667 | |
9668 | // Result type for parser operation |
9669 | using detail::ParserResult; |
9670 | |
9671 | }} // namespace Catch::clara |
9672 | |
9673 | // end clara.hpp |
9674 | #ifdef __clang__ |
9675 | #pragma clang diagnostic pop |
9676 | #endif |
9677 | |
9678 | // Restore Clara's value for console width, if present |
9679 | #ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH |
9680 | #define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH |
9681 | #undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH |
9682 | #endif |
9683 | |
9684 | // end catch_clara.h |
9685 | namespace Catch { |
9686 | |
9687 | clara::Parser makeCommandLineParser( ConfigData& config ); |
9688 | |
9689 | } // end namespace Catch |
9690 | |
9691 | // end catch_commandline.h |
9692 | #include <fstream> |
9693 | #include <ctime> |
9694 | |
9695 | namespace Catch { |
9696 | |
9697 | clara::Parser makeCommandLineParser( ConfigData& config ) { |
9698 | |
9699 | using namespace clara; |
9700 | |
9701 | auto const setWarning = [&]( std::string const& warning ) { |
9702 | auto warningSet = [&]() { |
9703 | if( warning == "NoAssertions" ) |
9704 | return WarnAbout::NoAssertions; |
9705 | |
9706 | if ( warning == "NoTests" ) |
9707 | return WarnAbout::NoTests; |
9708 | |
9709 | return WarnAbout::Nothing; |
9710 | }(); |
9711 | |
9712 | if (warningSet == WarnAbout::Nothing) |
9713 | return ParserResult::runtimeError( "Unrecognised warning: '" + warning + "'" ); |
9714 | config.warnings = static_cast<WarnAbout::What>( config.warnings | warningSet ); |
9715 | return ParserResult::ok( ParseResultType::Matched ); |
9716 | }; |
9717 | auto const loadTestNamesFromFile = [&]( std::string const& filename ) { |
9718 | std::ifstream f( filename.c_str() ); |
9719 | if( !f.is_open() ) |
9720 | return ParserResult::runtimeError( "Unable to load input file: '" + filename + "'" ); |
9721 | |
9722 | std::string line; |
9723 | while( std::getline( f, line ) ) { |
9724 | line = trim(line); |
9725 | if( !line.empty() && !startsWith( line, '#' ) ) { |
9726 | if( !startsWith( line, '"' ) ) |
9727 | line = '"' + line + '"'; |
9728 | config.testsOrTags.push_back( line ); |
9729 | config.testsOrTags.emplace_back( "," ); |
9730 | } |
9731 | } |
9732 | //Remove comma in the end |
9733 | if(!config.testsOrTags.empty()) |
9734 | config.testsOrTags.erase( config.testsOrTags.end()-1 ); |
9735 | |
9736 | return ParserResult::ok( ParseResultType::Matched ); |
9737 | }; |
9738 | auto const setTestOrder = [&]( std::string const& order ) { |
9739 | if( startsWith( "declared" , order ) ) |
9740 | config.runOrder = RunTests::InDeclarationOrder; |
9741 | else if( startsWith( "lexical" , order ) ) |
9742 | config.runOrder = RunTests::InLexicographicalOrder; |
9743 | else if( startsWith( "random" , order ) ) |
9744 | config.runOrder = RunTests::InRandomOrder; |
9745 | else |
9746 | return clara::ParserResult::runtimeError( "Unrecognised ordering: '" + order + "'" ); |
9747 | return ParserResult::ok( ParseResultType::Matched ); |
9748 | }; |
9749 | auto const setRngSeed = [&]( std::string const& seed ) { |
9750 | if( seed != "time" ) |
9751 | return clara::detail::convertInto( seed, config.rngSeed ); |
9752 | config.rngSeed = static_cast<unsigned int>( std::time(nullptr) ); |
9753 | return ParserResult::ok( ParseResultType::Matched ); |
9754 | }; |
9755 | auto const setColourUsage = [&]( std::string const& useColour ) { |
9756 | auto mode = toLower( useColour ); |
9757 | |
9758 | if( mode == "yes" ) |
9759 | config.useColour = UseColour::Yes; |
9760 | else if( mode == "no" ) |
9761 | config.useColour = UseColour::No; |
9762 | else if( mode == "auto" ) |
9763 | config.useColour = UseColour::Auto; |
9764 | else |
9765 | return ParserResult::runtimeError( "colour mode must be one of: auto, yes or no. '" + useColour + "' not recognised" ); |
9766 | return ParserResult::ok( ParseResultType::Matched ); |
9767 | }; |
9768 | auto const setWaitForKeypress = [&]( std::string const& keypress ) { |
9769 | auto keypressLc = toLower( keypress ); |
9770 | if (keypressLc == "never" ) |
9771 | config.waitForKeypress = WaitForKeypress::Never; |
9772 | else if( keypressLc == "start" ) |
9773 | config.waitForKeypress = WaitForKeypress::BeforeStart; |
9774 | else if( keypressLc == "exit" ) |
9775 | config.waitForKeypress = WaitForKeypress::BeforeExit; |
9776 | else if( keypressLc == "both" ) |
9777 | config.waitForKeypress = WaitForKeypress::BeforeStartAndExit; |
9778 | else |
9779 | return ParserResult::runtimeError( "keypress argument must be one of: never, start, exit or both. '" + keypress + "' not recognised" ); |
9780 | return ParserResult::ok( ParseResultType::Matched ); |
9781 | }; |
9782 | auto const setVerbosity = [&]( std::string const& verbosity ) { |
9783 | auto lcVerbosity = toLower( verbosity ); |
9784 | if( lcVerbosity == "quiet" ) |
9785 | config.verbosity = Verbosity::Quiet; |
9786 | else if( lcVerbosity == "normal" ) |
9787 | config.verbosity = Verbosity::Normal; |
9788 | else if( lcVerbosity == "high" ) |
9789 | config.verbosity = Verbosity::High; |
9790 | else |
9791 | return ParserResult::runtimeError( "Unrecognised verbosity, '" + verbosity + "'" ); |
9792 | return ParserResult::ok( ParseResultType::Matched ); |
9793 | }; |
9794 | auto const setReporter = [&]( std::string const& reporter ) { |
9795 | IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); |
9796 | |
9797 | auto lcReporter = toLower( reporter ); |
9798 | auto result = factories.find( lcReporter ); |
9799 | |
9800 | if( factories.end() != result ) |
9801 | config.reporterName = lcReporter; |
9802 | else |
9803 | return ParserResult::runtimeError( "Unrecognized reporter, '" + reporter + "'. Check available with --list-reporters" ); |
9804 | return ParserResult::ok( ParseResultType::Matched ); |
9805 | }; |
9806 | |
9807 | auto cli |
9808 | = ExeName( config.processName ) |
9809 | | Help( config.showHelp ) |
9810 | | Opt( config.listTests ) |
9811 | ["-l" ]["--list-tests" ] |
9812 | ( "list all/matching test cases" ) |
9813 | | Opt( config.listTags ) |
9814 | ["-t" ]["--list-tags" ] |
9815 | ( "list all/matching tags" ) |
9816 | | Opt( config.showSuccessfulTests ) |
9817 | ["-s" ]["--success" ] |
9818 | ( "include successful tests in output" ) |
9819 | | Opt( config.shouldDebugBreak ) |
9820 | ["-b" ]["--break" ] |
9821 | ( "break into debugger on failure" ) |
9822 | | Opt( config.noThrow ) |
9823 | ["-e" ]["--nothrow" ] |
9824 | ( "skip exception tests" ) |
9825 | | Opt( config.showInvisibles ) |
9826 | ["-i" ]["--invisibles" ] |
9827 | ( "show invisibles (tabs, newlines)" ) |
9828 | | Opt( config.outputFilename, "filename" ) |
9829 | ["-o" ]["--out" ] |
9830 | ( "output filename" ) |
9831 | | Opt( setReporter, "name" ) |
9832 | ["-r" ]["--reporter" ] |
9833 | ( "reporter to use (defaults to console)" ) |
9834 | | Opt( config.name, "name" ) |
9835 | ["-n" ]["--name" ] |
9836 | ( "suite name" ) |
9837 | | Opt( [&]( bool ){ config.abortAfter = 1; } ) |
9838 | ["-a" ]["--abort" ] |
9839 | ( "abort at first failure" ) |
9840 | | Opt( [&]( int x ){ config.abortAfter = x; }, "no. failures" ) |
9841 | ["-x" ]["--abortx" ] |
9842 | ( "abort after x failures" ) |
9843 | | Opt( setWarning, "warning name" ) |
9844 | ["-w" ]["--warn" ] |
9845 | ( "enable warnings" ) |
9846 | | Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" ) |
9847 | ["-d" ]["--durations" ] |
9848 | ( "show test durations" ) |
9849 | | Opt( config.minDuration, "seconds" ) |
9850 | ["-D" ]["--min-duration" ] |
9851 | ( "show test durations for tests taking at least the given number of seconds" ) |
9852 | | Opt( loadTestNamesFromFile, "filename" ) |
9853 | ["-f" ]["--input-file" ] |
9854 | ( "load test names to run from a file" ) |
9855 | | Opt( config.filenamesAsTags ) |
9856 | ["-#" ]["--filenames-as-tags" ] |
9857 | ( "adds a tag for the filename" ) |
9858 | | Opt( config.sectionsToRun, "section name" ) |
9859 | ["-c" ]["--section" ] |
9860 | ( "specify section to run" ) |
9861 | | Opt( setVerbosity, "quiet|normal|high" ) |
9862 | ["-v" ]["--verbosity" ] |
9863 | ( "set output verbosity" ) |
9864 | | Opt( config.listTestNamesOnly ) |
9865 | ["--list-test-names-only" ] |
9866 | ( "list all/matching test cases names only" ) |
9867 | | Opt( config.listReporters ) |
9868 | ["--list-reporters" ] |
9869 | ( "list all reporters" ) |
9870 | | Opt( setTestOrder, "decl|lex|rand" ) |
9871 | ["--order" ] |
9872 | ( "test case order (defaults to decl)" ) |
9873 | | Opt( setRngSeed, "'time'|number" ) |
9874 | ["--rng-seed" ] |
9875 | ( "set a specific seed for random numbers" ) |
9876 | | Opt( setColourUsage, "yes|no" ) |
9877 | ["--use-colour" ] |
9878 | ( "should output be colourised" ) |
9879 | | Opt( config.libIdentify ) |
9880 | ["--libidentify" ] |
9881 | ( "report name and version according to libidentify standard" ) |
9882 | | Opt( setWaitForKeypress, "never|start|exit|both" ) |
9883 | ["--wait-for-keypress" ] |
9884 | ( "waits for a keypress before exiting" ) |
9885 | | Opt( config.benchmarkSamples, "samples" ) |
9886 | ["--benchmark-samples" ] |
9887 | ( "number of samples to collect (default: 100)" ) |
9888 | | Opt( config.benchmarkResamples, "resamples" ) |
9889 | ["--benchmark-resamples" ] |
9890 | ( "number of resamples for the bootstrap (default: 100000)" ) |
9891 | | Opt( config.benchmarkConfidenceInterval, "confidence interval" ) |
9892 | ["--benchmark-confidence-interval" ] |
9893 | ( "confidence interval for the bootstrap (between 0 and 1, default: 0.95)" ) |
9894 | | Opt( config.benchmarkNoAnalysis ) |
9895 | ["--benchmark-no-analysis" ] |
9896 | ( "perform only measurements; do not perform any analysis" ) |
9897 | | Opt( config.benchmarkWarmupTime, "benchmarkWarmupTime" ) |
9898 | ["--benchmark-warmup-time" ] |
9899 | ( "amount of time in milliseconds spent on warming up each test (default: 100)" ) |
9900 | | Arg( config.testsOrTags, "test name|pattern|tags" ) |
9901 | ( "which test or tests to use" ); |
9902 | |
9903 | return cli; |
9904 | } |
9905 | |
9906 | } // end namespace Catch |
9907 | // end catch_commandline.cpp |
9908 | // start catch_common.cpp |
9909 | |
9910 | #include <cstring> |
9911 | #include <ostream> |
9912 | |
9913 | namespace Catch { |
9914 | |
9915 | bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const noexcept { |
9916 | return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0); |
9917 | } |
9918 | bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const noexcept { |
9919 | // We can assume that the same file will usually have the same pointer. |
9920 | // Thus, if the pointers are the same, there is no point in calling the strcmp |
9921 | return line < other.line || ( line == other.line && file != other.file && (std::strcmp(file, other.file) < 0)); |
9922 | } |
9923 | |
9924 | std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { |
9925 | #ifndef __GNUG__ |
9926 | os << info.file << '(' << info.line << ')'; |
9927 | #else |
9928 | os << info.file << ':' << info.line; |
9929 | #endif |
9930 | return os; |
9931 | } |
9932 | |
9933 | std::string StreamEndStop::operator+() const { |
9934 | return std::string(); |
9935 | } |
9936 | |
9937 | NonCopyable::NonCopyable() = default; |
9938 | NonCopyable::~NonCopyable() = default; |
9939 | |
9940 | } |
9941 | // end catch_common.cpp |
9942 | // start catch_config.cpp |
9943 | |
9944 | namespace Catch { |
9945 | |
9946 | Config::Config( ConfigData const& data ) |
9947 | : m_data( data ), |
9948 | m_stream( openStream() ) |
9949 | { |
9950 | // We need to trim filter specs to avoid trouble with superfluous |
9951 | // whitespace (esp. important for bdd macros, as those are manually |
9952 | // aligned with whitespace). |
9953 | |
9954 | for (auto& elem : m_data.testsOrTags) { |
9955 | elem = trim(elem); |
9956 | } |
9957 | for (auto& elem : m_data.sectionsToRun) { |
9958 | elem = trim(elem); |
9959 | } |
9960 | |
9961 | TestSpecParser parser(ITagAliasRegistry::get()); |
9962 | if (!m_data.testsOrTags.empty()) { |
9963 | m_hasTestFilters = true; |
9964 | for (auto const& testOrTags : m_data.testsOrTags) { |
9965 | parser.parse(testOrTags); |
9966 | } |
9967 | } |
9968 | m_testSpec = parser.testSpec(); |
9969 | } |
9970 | |
9971 | std::string const& Config::getFilename() const { |
9972 | return m_data.outputFilename ; |
9973 | } |
9974 | |
9975 | bool Config::listTests() const { return m_data.listTests; } |
9976 | bool Config::listTestNamesOnly() const { return m_data.listTestNamesOnly; } |
9977 | bool Config::listTags() const { return m_data.listTags; } |
9978 | bool Config::listReporters() const { return m_data.listReporters; } |
9979 | |
9980 | std::string Config::getProcessName() const { return m_data.processName; } |
9981 | std::string const& Config::getReporterName() const { return m_data.reporterName; } |
9982 | |
9983 | std::vector<std::string> const& Config::getTestsOrTags() const { return m_data.testsOrTags; } |
9984 | std::vector<std::string> const& Config::getSectionsToRun() const { return m_data.sectionsToRun; } |
9985 | |
9986 | TestSpec const& Config::testSpec() const { return m_testSpec; } |
9987 | bool Config::hasTestFilters() const { return m_hasTestFilters; } |
9988 | |
9989 | bool Config::showHelp() const { return m_data.showHelp; } |
9990 | |
9991 | // IConfig interface |
9992 | bool Config::allowThrows() const { return !m_data.noThrow; } |
9993 | std::ostream& Config::stream() const { return m_stream->stream(); } |
9994 | std::string Config::name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } |
9995 | bool Config::includeSuccessfulResults() const { return m_data.showSuccessfulTests; } |
9996 | bool Config::warnAboutMissingAssertions() const { return !!(m_data.warnings & WarnAbout::NoAssertions); } |
9997 | bool Config::warnAboutNoTests() const { return !!(m_data.warnings & WarnAbout::NoTests); } |
9998 | ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; } |
9999 | double Config::minDuration() const { return m_data.minDuration; } |
10000 | RunTests::InWhatOrder Config::runOrder() const { return m_data.runOrder; } |
10001 | unsigned int Config::rngSeed() const { return m_data.rngSeed; } |
10002 | UseColour::YesOrNo Config::useColour() const { return m_data.useColour; } |
10003 | bool Config::shouldDebugBreak() const { return m_data.shouldDebugBreak; } |
10004 | int Config::abortAfter() const { return m_data.abortAfter; } |
10005 | bool Config::showInvisibles() const { return m_data.showInvisibles; } |
10006 | Verbosity Config::verbosity() const { return m_data.verbosity; } |
10007 | |
10008 | bool Config::benchmarkNoAnalysis() const { return m_data.benchmarkNoAnalysis; } |
10009 | int Config::benchmarkSamples() const { return m_data.benchmarkSamples; } |
10010 | double Config::benchmarkConfidenceInterval() const { return m_data.benchmarkConfidenceInterval; } |
10011 | unsigned int Config::benchmarkResamples() const { return m_data.benchmarkResamples; } |
10012 | std::chrono::milliseconds Config::benchmarkWarmupTime() const { return std::chrono::milliseconds(m_data.benchmarkWarmupTime); } |
10013 | |
10014 | IStream const* Config::openStream() { |
10015 | return Catch::makeStream(m_data.outputFilename); |
10016 | } |
10017 | |
10018 | } // end namespace Catch |
10019 | // end catch_config.cpp |
10020 | // start catch_console_colour.cpp |
10021 | |
10022 | #if defined(__clang__) |
10023 | # pragma clang diagnostic push |
10024 | # pragma clang diagnostic ignored "-Wexit-time-destructors" |
10025 | #endif |
10026 | |
10027 | // start catch_errno_guard.h |
10028 | |
10029 | namespace Catch { |
10030 | |
10031 | class ErrnoGuard { |
10032 | public: |
10033 | ErrnoGuard(); |
10034 | ~ErrnoGuard(); |
10035 | private: |
10036 | int m_oldErrno; |
10037 | }; |
10038 | |
10039 | } |
10040 | |
10041 | // end catch_errno_guard.h |
10042 | // start catch_windows_h_proxy.h |
10043 | |
10044 | |
10045 | #if defined(CATCH_PLATFORM_WINDOWS) |
10046 | |
10047 | #if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX) |
10048 | # define CATCH_DEFINED_NOMINMAX |
10049 | # define NOMINMAX |
10050 | #endif |
10051 | #if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN) |
10052 | # define CATCH_DEFINED_WIN32_LEAN_AND_MEAN |
10053 | # define WIN32_LEAN_AND_MEAN |
10054 | #endif |
10055 | |
10056 | #ifdef __AFXDLL |
10057 | #include <AfxWin.h> |
10058 | #else |
10059 | #include <windows.h> |
10060 | #endif |
10061 | |
10062 | #ifdef CATCH_DEFINED_NOMINMAX |
10063 | # undef NOMINMAX |
10064 | #endif |
10065 | #ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN |
10066 | # undef WIN32_LEAN_AND_MEAN |
10067 | #endif |
10068 | |
10069 | #endif // defined(CATCH_PLATFORM_WINDOWS) |
10070 | |
10071 | // end catch_windows_h_proxy.h |
10072 | #include <sstream> |
10073 | |
10074 | namespace Catch { |
10075 | namespace { |
10076 | |
10077 | struct IColourImpl { |
10078 | virtual ~IColourImpl() = default; |
10079 | virtual void use( Colour::Code _colourCode ) = 0; |
10080 | }; |
10081 | |
10082 | struct NoColourImpl : IColourImpl { |
10083 | void use( Colour::Code ) override {} |
10084 | |
10085 | static IColourImpl* instance() { |
10086 | static NoColourImpl s_instance; |
10087 | return &s_instance; |
10088 | } |
10089 | }; |
10090 | |
10091 | } // anon namespace |
10092 | } // namespace Catch |
10093 | |
10094 | #if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI ) |
10095 | # ifdef CATCH_PLATFORM_WINDOWS |
10096 | # define CATCH_CONFIG_COLOUR_WINDOWS |
10097 | # else |
10098 | # define CATCH_CONFIG_COLOUR_ANSI |
10099 | # endif |
10100 | #endif |
10101 | |
10102 | #if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) ///////////////////////////////////////// |
10103 | |
10104 | namespace Catch { |
10105 | namespace { |
10106 | |
10107 | class Win32ColourImpl : public IColourImpl { |
10108 | public: |
10109 | Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) |
10110 | { |
10111 | CONSOLE_SCREEN_BUFFER_INFO csbiInfo; |
10112 | GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); |
10113 | originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY ); |
10114 | originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY ); |
10115 | } |
10116 | |
10117 | void use( Colour::Code _colourCode ) override { |
10118 | switch( _colourCode ) { |
10119 | case Colour::None: return setTextAttribute( originalForegroundAttributes ); |
10120 | case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); |
10121 | case Colour::Red: return setTextAttribute( FOREGROUND_RED ); |
10122 | case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); |
10123 | case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE ); |
10124 | case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN ); |
10125 | case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN ); |
10126 | case Colour::Grey: return setTextAttribute( 0 ); |
10127 | |
10128 | case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY ); |
10129 | case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED ); |
10130 | case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); |
10131 | case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); |
10132 | case Colour::BrightYellow: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN ); |
10133 | |
10134 | case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" ); |
10135 | |
10136 | default: |
10137 | CATCH_ERROR( "Unknown colour requested" ); |
10138 | } |
10139 | } |
10140 | |
10141 | private: |
10142 | void setTextAttribute( WORD _textAttribute ) { |
10143 | SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes ); |
10144 | } |
10145 | HANDLE stdoutHandle; |
10146 | WORD originalForegroundAttributes; |
10147 | WORD originalBackgroundAttributes; |
10148 | }; |
10149 | |
10150 | IColourImpl* platformColourInstance() { |
10151 | static Win32ColourImpl s_instance; |
10152 | |
10153 | IConfigPtr config = getCurrentContext().getConfig(); |
10154 | UseColour::YesOrNo colourMode = config |
10155 | ? config->useColour() |
10156 | : UseColour::Auto; |
10157 | if( colourMode == UseColour::Auto ) |
10158 | colourMode = UseColour::Yes; |
10159 | return colourMode == UseColour::Yes |
10160 | ? &s_instance |
10161 | : NoColourImpl::instance(); |
10162 | } |
10163 | |
10164 | } // end anon namespace |
10165 | } // end namespace Catch |
10166 | |
10167 | #elif defined( CATCH_CONFIG_COLOUR_ANSI ) ////////////////////////////////////// |
10168 | |
10169 | #include <unistd.h> |
10170 | |
10171 | namespace Catch { |
10172 | namespace { |
10173 | |
10174 | // use POSIX/ ANSI console terminal codes |
10175 | // Thanks to Adam Strzelecki for original contribution |
10176 | // (http://github.com/nanoant) |
10177 | // https://github.com/philsquared/Catch/pull/131 |
10178 | class PosixColourImpl : public IColourImpl { |
10179 | public: |
10180 | void use( Colour::Code _colourCode ) override { |
10181 | switch( _colourCode ) { |
10182 | case Colour::None: |
10183 | case Colour::White: return setColour( "[0m" ); |
10184 | case Colour::Red: return setColour( "[0;31m" ); |
10185 | case Colour::Green: return setColour( "[0;32m" ); |
10186 | case Colour::Blue: return setColour( "[0;34m" ); |
10187 | case Colour::Cyan: return setColour( "[0;36m" ); |
10188 | case Colour::Yellow: return setColour( "[0;33m" ); |
10189 | case Colour::Grey: return setColour( "[1;30m" ); |
10190 | |
10191 | case Colour::LightGrey: return setColour( "[0;37m" ); |
10192 | case Colour::BrightRed: return setColour( "[1;31m" ); |
10193 | case Colour::BrightGreen: return setColour( "[1;32m" ); |
10194 | case Colour::BrightWhite: return setColour( "[1;37m" ); |
10195 | case Colour::BrightYellow: return setColour( "[1;33m" ); |
10196 | |
10197 | case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" ); |
10198 | default: CATCH_INTERNAL_ERROR( "Unknown colour requested" ); |
10199 | } |
10200 | } |
10201 | static IColourImpl* instance() { |
10202 | static PosixColourImpl s_instance; |
10203 | return &s_instance; |
10204 | } |
10205 | |
10206 | private: |
10207 | void setColour( const char* _escapeCode ) { |
10208 | getCurrentContext().getConfig()->stream() |
10209 | << '\033' << _escapeCode; |
10210 | } |
10211 | }; |
10212 | |
10213 | bool useColourOnPlatform() { |
10214 | return |
10215 | #if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE) |
10216 | !isDebuggerActive() && |
10217 | #endif |
10218 | #if !(defined(__DJGPP__) && defined(__STRICT_ANSI__)) |
10219 | isatty(STDOUT_FILENO) |
10220 | #else |
10221 | false |
10222 | #endif |
10223 | ; |
10224 | } |
10225 | IColourImpl* platformColourInstance() { |
10226 | ErrnoGuard guard; |
10227 | IConfigPtr config = getCurrentContext().getConfig(); |
10228 | UseColour::YesOrNo colourMode = config |
10229 | ? config->useColour() |
10230 | : UseColour::Auto; |
10231 | if( colourMode == UseColour::Auto ) |
10232 | colourMode = useColourOnPlatform() |
10233 | ? UseColour::Yes |
10234 | : UseColour::No; |
10235 | return colourMode == UseColour::Yes |
10236 | ? PosixColourImpl::instance() |
10237 | : NoColourImpl::instance(); |
10238 | } |
10239 | |
10240 | } // end anon namespace |
10241 | } // end namespace Catch |
10242 | |
10243 | #else // not Windows or ANSI /////////////////////////////////////////////// |
10244 | |
10245 | namespace Catch { |
10246 | |
10247 | static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); } |
10248 | |
10249 | } // end namespace Catch |
10250 | |
10251 | #endif // Windows/ ANSI/ None |
10252 | |
10253 | namespace Catch { |
10254 | |
10255 | Colour::Colour( Code _colourCode ) { use( _colourCode ); } |
10256 | Colour::Colour( Colour&& other ) noexcept { |
10257 | m_moved = other.m_moved; |
10258 | other.m_moved = true; |
10259 | } |
10260 | Colour& Colour::operator=( Colour&& other ) noexcept { |
10261 | m_moved = other.m_moved; |
10262 | other.m_moved = true; |
10263 | return *this; |
10264 | } |
10265 | |
10266 | Colour::~Colour(){ if( !m_moved ) use( None ); } |
10267 | |
10268 | void Colour::use( Code _colourCode ) { |
10269 | static IColourImpl* impl = platformColourInstance(); |
10270 | // Strictly speaking, this cannot possibly happen. |
10271 | // However, under some conditions it does happen (see #1626), |
10272 | // and this change is small enough that we can let practicality |
10273 | // triumph over purity in this case. |
10274 | if (impl != nullptr) { |
10275 | impl->use( _colourCode ); |
10276 | } |
10277 | } |
10278 | |
10279 | std::ostream& operator << ( std::ostream& os, Colour const& ) { |
10280 | return os; |
10281 | } |
10282 | |
10283 | } // end namespace Catch |
10284 | |
10285 | #if defined(__clang__) |
10286 | # pragma clang diagnostic pop |
10287 | #endif |
10288 | |
10289 | // end catch_console_colour.cpp |
10290 | // start catch_context.cpp |
10291 | |
10292 | namespace Catch { |
10293 | |
10294 | class Context : public IMutableContext, NonCopyable { |
10295 | |
10296 | public: // IContext |
10297 | IResultCapture* getResultCapture() override { |
10298 | return m_resultCapture; |
10299 | } |
10300 | IRunner* getRunner() override { |
10301 | return m_runner; |
10302 | } |
10303 | |
10304 | IConfigPtr const& getConfig() const override { |
10305 | return m_config; |
10306 | } |
10307 | |
10308 | ~Context() override; |
10309 | |
10310 | public: // IMutableContext |
10311 | void setResultCapture( IResultCapture* resultCapture ) override { |
10312 | m_resultCapture = resultCapture; |
10313 | } |
10314 | void setRunner( IRunner* runner ) override { |
10315 | m_runner = runner; |
10316 | } |
10317 | void setConfig( IConfigPtr const& config ) override { |
10318 | m_config = config; |
10319 | } |
10320 | |
10321 | friend IMutableContext& getCurrentMutableContext(); |
10322 | |
10323 | private: |
10324 | IConfigPtr m_config; |
10325 | IRunner* m_runner = nullptr; |
10326 | IResultCapture* m_resultCapture = nullptr; |
10327 | }; |
10328 | |
10329 | IMutableContext *IMutableContext::currentContext = nullptr; |
10330 | |
10331 | void IMutableContext::createContext() |
10332 | { |
10333 | currentContext = new Context(); |
10334 | } |
10335 | |
10336 | void cleanUpContext() { |
10337 | delete IMutableContext::currentContext; |
10338 | IMutableContext::currentContext = nullptr; |
10339 | } |
10340 | IContext::~IContext() = default; |
10341 | IMutableContext::~IMutableContext() = default; |
10342 | Context::~Context() = default; |
10343 | |
10344 | SimplePcg32& rng() { |
10345 | static SimplePcg32 s_rng; |
10346 | return s_rng; |
10347 | } |
10348 | |
10349 | } |
10350 | // end catch_context.cpp |
10351 | // start catch_debug_console.cpp |
10352 | |
10353 | // start catch_debug_console.h |
10354 | |
10355 | #include <string> |
10356 | |
10357 | namespace Catch { |
10358 | void writeToDebugConsole( std::string const& text ); |
10359 | } |
10360 | |
10361 | // end catch_debug_console.h |
10362 | #if defined(CATCH_CONFIG_ANDROID_LOGWRITE) |
10363 | #include <android/log.h> |
10364 | |
10365 | namespace Catch { |
10366 | void writeToDebugConsole( std::string const& text ) { |
10367 | __android_log_write( ANDROID_LOG_DEBUG, "Catch" , text.c_str() ); |
10368 | } |
10369 | } |
10370 | |
10371 | #elif defined(CATCH_PLATFORM_WINDOWS) |
10372 | |
10373 | namespace Catch { |
10374 | void writeToDebugConsole( std::string const& text ) { |
10375 | ::OutputDebugStringA( text.c_str() ); |
10376 | } |
10377 | } |
10378 | |
10379 | #else |
10380 | |
10381 | namespace Catch { |
10382 | void writeToDebugConsole( std::string const& text ) { |
10383 | // !TBD: Need a version for Mac/ XCode and other IDEs |
10384 | Catch::cout() << text; |
10385 | } |
10386 | } |
10387 | |
10388 | #endif // Platform |
10389 | // end catch_debug_console.cpp |
10390 | // start catch_debugger.cpp |
10391 | |
10392 | #if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE) |
10393 | |
10394 | # include <cassert> |
10395 | # include <sys/types.h> |
10396 | # include <unistd.h> |
10397 | # include <cstddef> |
10398 | # include <ostream> |
10399 | |
10400 | #ifdef __apple_build_version__ |
10401 | // These headers will only compile with AppleClang (XCode) |
10402 | // For other compilers (Clang, GCC, ... ) we need to exclude them |
10403 | # include <sys/sysctl.h> |
10404 | #endif |
10405 | |
10406 | namespace Catch { |
10407 | #ifdef __apple_build_version__ |
10408 | // The following function is taken directly from the following technical note: |
10409 | // https://developer.apple.com/library/archive/qa/qa1361/_index.html |
10410 | |
10411 | // Returns true if the current process is being debugged (either |
10412 | // running under the debugger or has a debugger attached post facto). |
10413 | bool isDebuggerActive(){ |
10414 | int mib[4]; |
10415 | struct kinfo_proc info; |
10416 | std::size_t size; |
10417 | |
10418 | // Initialize the flags so that, if sysctl fails for some bizarre |
10419 | // reason, we get a predictable result. |
10420 | |
10421 | info.kp_proc.p_flag = 0; |
10422 | |
10423 | // Initialize mib, which tells sysctl the info we want, in this case |
10424 | // we're looking for information about a specific process ID. |
10425 | |
10426 | mib[0] = CTL_KERN; |
10427 | mib[1] = KERN_PROC; |
10428 | mib[2] = KERN_PROC_PID; |
10429 | mib[3] = getpid(); |
10430 | |
10431 | // Call sysctl. |
10432 | |
10433 | size = sizeof(info); |
10434 | if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, nullptr, 0) != 0 ) { |
10435 | Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; |
10436 | return false; |
10437 | } |
10438 | |
10439 | // We're being debugged if the P_TRACED flag is set. |
10440 | |
10441 | return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); |
10442 | } |
10443 | #else |
10444 | bool isDebuggerActive() { |
10445 | // We need to find another way to determine this for non-appleclang compilers on macOS |
10446 | return false; |
10447 | } |
10448 | #endif |
10449 | } // namespace Catch |
10450 | |
10451 | #elif defined(CATCH_PLATFORM_LINUX) |
10452 | #include <fstream> |
10453 | #include <string> |
10454 | |
10455 | namespace Catch{ |
10456 | // The standard POSIX way of detecting a debugger is to attempt to |
10457 | // ptrace() the process, but this needs to be done from a child and not |
10458 | // this process itself to still allow attaching to this process later |
10459 | // if wanted, so is rather heavy. Under Linux we have the PID of the |
10460 | // "debugger" (which doesn't need to be gdb, of course, it could also |
10461 | // be strace, for example) in /proc/$PID/status, so just get it from |
10462 | // there instead. |
10463 | bool isDebuggerActive(){ |
10464 | // Libstdc++ has a bug, where std::ifstream sets errno to 0 |
10465 | // This way our users can properly assert over errno values |
10466 | ErrnoGuard guard; |
10467 | std::ifstream in("/proc/self/status" ); |
10468 | for( std::string line; std::getline(in, line); ) { |
10469 | static const int PREFIX_LEN = 11; |
10470 | if( line.compare(0, PREFIX_LEN, "TracerPid:\t" ) == 0 ) { |
10471 | // We're traced if the PID is not 0 and no other PID starts |
10472 | // with 0 digit, so it's enough to check for just a single |
10473 | // character. |
10474 | return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0'; |
10475 | } |
10476 | } |
10477 | |
10478 | return false; |
10479 | } |
10480 | } // namespace Catch |
10481 | #elif defined(_MSC_VER) |
10482 | extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); |
10483 | namespace Catch { |
10484 | bool isDebuggerActive() { |
10485 | return IsDebuggerPresent() != 0; |
10486 | } |
10487 | } |
10488 | #elif defined(__MINGW32__) |
10489 | extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); |
10490 | namespace Catch { |
10491 | bool isDebuggerActive() { |
10492 | return IsDebuggerPresent() != 0; |
10493 | } |
10494 | } |
10495 | #else |
10496 | namespace Catch { |
10497 | bool isDebuggerActive() { return false; } |
10498 | } |
10499 | #endif // Platform |
10500 | // end catch_debugger.cpp |
10501 | // start catch_decomposer.cpp |
10502 | |
10503 | namespace Catch { |
10504 | |
10505 | ITransientExpression::~ITransientExpression() = default; |
10506 | |
10507 | void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ) { |
10508 | if( lhs.size() + rhs.size() < 40 && |
10509 | lhs.find('\n') == std::string::npos && |
10510 | rhs.find('\n') == std::string::npos ) |
10511 | os << lhs << " " << op << " " << rhs; |
10512 | else |
10513 | os << lhs << "\n" << op << "\n" << rhs; |
10514 | } |
10515 | } |
10516 | // end catch_decomposer.cpp |
10517 | // start catch_enforce.cpp |
10518 | |
10519 | #include <stdexcept> |
10520 | |
10521 | namespace Catch { |
10522 | #if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER) |
10523 | [[noreturn]] |
10524 | void throw_exception(std::exception const& e) { |
10525 | Catch::cerr() << "Catch will terminate because it needed to throw an exception.\n" |
10526 | << "The message was: " << e.what() << '\n'; |
10527 | std::terminate(); |
10528 | } |
10529 | #endif |
10530 | |
10531 | [[noreturn]] |
10532 | void throw_logic_error(std::string const& msg) { |
10533 | throw_exception(std::logic_error(msg)); |
10534 | } |
10535 | |
10536 | [[noreturn]] |
10537 | void throw_domain_error(std::string const& msg) { |
10538 | throw_exception(std::domain_error(msg)); |
10539 | } |
10540 | |
10541 | [[noreturn]] |
10542 | void throw_runtime_error(std::string const& msg) { |
10543 | throw_exception(std::runtime_error(msg)); |
10544 | } |
10545 | |
10546 | } // namespace Catch; |
10547 | // end catch_enforce.cpp |
10548 | // start catch_enum_values_registry.cpp |
10549 | // start catch_enum_values_registry.h |
10550 | |
10551 | #include <vector> |
10552 | #include <memory> |
10553 | |
10554 | namespace Catch { |
10555 | |
10556 | namespace Detail { |
10557 | |
10558 | std::unique_ptr<EnumInfo> makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ); |
10559 | |
10560 | class EnumValuesRegistry : public IMutableEnumValuesRegistry { |
10561 | |
10562 | std::vector<std::unique_ptr<EnumInfo>> m_enumInfos; |
10563 | |
10564 | EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::vector<int> const& values) override; |
10565 | }; |
10566 | |
10567 | std::vector<StringRef> parseEnums( StringRef enums ); |
10568 | |
10569 | } // Detail |
10570 | |
10571 | } // Catch |
10572 | |
10573 | // end catch_enum_values_registry.h |
10574 | |
10575 | #include <map> |
10576 | #include <cassert> |
10577 | |
10578 | namespace Catch { |
10579 | |
10580 | IMutableEnumValuesRegistry::~IMutableEnumValuesRegistry() {} |
10581 | |
10582 | namespace Detail { |
10583 | |
10584 | namespace { |
10585 | // Extracts the actual name part of an enum instance |
10586 | // In other words, it returns the Blue part of Bikeshed::Colour::Blue |
10587 | StringRef (StringRef enumInstance) { |
10588 | // Find last occurrence of ":" |
10589 | size_t name_start = enumInstance.size(); |
10590 | while (name_start > 0 && enumInstance[name_start - 1] != ':') { |
10591 | --name_start; |
10592 | } |
10593 | return enumInstance.substr(name_start, enumInstance.size() - name_start); |
10594 | } |
10595 | } |
10596 | |
10597 | std::vector<StringRef> parseEnums( StringRef enums ) { |
10598 | auto enumValues = splitStringRef( enums, ',' ); |
10599 | std::vector<StringRef> parsed; |
10600 | parsed.reserve( enumValues.size() ); |
10601 | for( auto const& enumValue : enumValues ) { |
10602 | parsed.push_back(trim(extractInstanceName(enumValue))); |
10603 | } |
10604 | return parsed; |
10605 | } |
10606 | |
10607 | EnumInfo::~EnumInfo() {} |
10608 | |
10609 | StringRef EnumInfo::lookup( int value ) const { |
10610 | for( auto const& valueToName : m_values ) { |
10611 | if( valueToName.first == value ) |
10612 | return valueToName.second; |
10613 | } |
10614 | return "{** unexpected enum value **}"_sr ; |
10615 | } |
10616 | |
10617 | std::unique_ptr<EnumInfo> makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ) { |
10618 | std::unique_ptr<EnumInfo> enumInfo( new EnumInfo ); |
10619 | enumInfo->m_name = enumName; |
10620 | enumInfo->m_values.reserve( values.size() ); |
10621 | |
10622 | const auto valueNames = Catch::Detail::parseEnums( allValueNames ); |
10623 | assert( valueNames.size() == values.size() ); |
10624 | std::size_t i = 0; |
10625 | for( auto value : values ) |
10626 | enumInfo->m_values.emplace_back(value, valueNames[i++]); |
10627 | |
10628 | return enumInfo; |
10629 | } |
10630 | |
10631 | EnumInfo const& EnumValuesRegistry::registerEnum( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ) { |
10632 | m_enumInfos.push_back(makeEnumInfo(enumName, allValueNames, values)); |
10633 | return *m_enumInfos.back(); |
10634 | } |
10635 | |
10636 | } // Detail |
10637 | } // Catch |
10638 | |
10639 | // end catch_enum_values_registry.cpp |
10640 | // start catch_errno_guard.cpp |
10641 | |
10642 | #include <cerrno> |
10643 | |
10644 | namespace Catch { |
10645 | ErrnoGuard::ErrnoGuard():m_oldErrno(errno){} |
10646 | ErrnoGuard::~ErrnoGuard() { errno = m_oldErrno; } |
10647 | } |
10648 | // end catch_errno_guard.cpp |
10649 | // start catch_exception_translator_registry.cpp |
10650 | |
10651 | // start catch_exception_translator_registry.h |
10652 | |
10653 | #include <vector> |
10654 | #include <string> |
10655 | #include <memory> |
10656 | |
10657 | namespace Catch { |
10658 | |
10659 | class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { |
10660 | public: |
10661 | ~ExceptionTranslatorRegistry(); |
10662 | virtual void registerTranslator( const IExceptionTranslator* translator ); |
10663 | std::string translateActiveException() const override; |
10664 | std::string tryTranslators() const; |
10665 | |
10666 | private: |
10667 | std::vector<std::unique_ptr<IExceptionTranslator const>> m_translators; |
10668 | }; |
10669 | } |
10670 | |
10671 | // end catch_exception_translator_registry.h |
10672 | #ifdef __OBJC__ |
10673 | #import "Foundation/Foundation.h" |
10674 | #endif |
10675 | |
10676 | namespace Catch { |
10677 | |
10678 | ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() { |
10679 | } |
10680 | |
10681 | void ExceptionTranslatorRegistry::registerTranslator( const IExceptionTranslator* translator ) { |
10682 | m_translators.push_back( std::unique_ptr<const IExceptionTranslator>( translator ) ); |
10683 | } |
10684 | |
10685 | #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) |
10686 | std::string ExceptionTranslatorRegistry::translateActiveException() const { |
10687 | try { |
10688 | #ifdef __OBJC__ |
10689 | // In Objective-C try objective-c exceptions first |
10690 | @try { |
10691 | return tryTranslators(); |
10692 | } |
10693 | @catch (NSException *exception) { |
10694 | return Catch::Detail::stringify( [exception description] ); |
10695 | } |
10696 | #else |
10697 | // Compiling a mixed mode project with MSVC means that CLR |
10698 | // exceptions will be caught in (...) as well. However, these |
10699 | // do not fill-in std::current_exception and thus lead to crash |
10700 | // when attempting rethrow. |
10701 | // /EHa switch also causes structured exceptions to be caught |
10702 | // here, but they fill-in current_exception properly, so |
10703 | // at worst the output should be a little weird, instead of |
10704 | // causing a crash. |
10705 | if (std::current_exception() == nullptr) { |
10706 | return "Non C++ exception. Possibly a CLR exception." ; |
10707 | } |
10708 | return tryTranslators(); |
10709 | #endif |
10710 | } |
10711 | catch( TestFailureException& ) { |
10712 | std::rethrow_exception(std::current_exception()); |
10713 | } |
10714 | catch( std::exception& ex ) { |
10715 | return ex.what(); |
10716 | } |
10717 | catch( std::string& msg ) { |
10718 | return msg; |
10719 | } |
10720 | catch( const char* msg ) { |
10721 | return msg; |
10722 | } |
10723 | catch(...) { |
10724 | return "Unknown exception" ; |
10725 | } |
10726 | } |
10727 | |
10728 | std::string ExceptionTranslatorRegistry::tryTranslators() const { |
10729 | if (m_translators.empty()) { |
10730 | std::rethrow_exception(std::current_exception()); |
10731 | } else { |
10732 | return m_translators[0]->translate(m_translators.begin() + 1, m_translators.end()); |
10733 | } |
10734 | } |
10735 | |
10736 | #else // ^^ Exceptions are enabled // Exceptions are disabled vv |
10737 | std::string ExceptionTranslatorRegistry::translateActiveException() const { |
10738 | CATCH_INTERNAL_ERROR("Attempted to translate active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!" ); |
10739 | } |
10740 | |
10741 | std::string ExceptionTranslatorRegistry::tryTranslators() const { |
10742 | CATCH_INTERNAL_ERROR("Attempted to use exception translators under CATCH_CONFIG_DISABLE_EXCEPTIONS!" ); |
10743 | } |
10744 | #endif |
10745 | |
10746 | } |
10747 | // end catch_exception_translator_registry.cpp |
10748 | // start catch_fatal_condition.cpp |
10749 | |
10750 | #include <algorithm> |
10751 | |
10752 | #if !defined( CATCH_CONFIG_WINDOWS_SEH ) && !defined( CATCH_CONFIG_POSIX_SIGNALS ) |
10753 | |
10754 | namespace Catch { |
10755 | |
10756 | // If neither SEH nor signal handling is required, the handler impls |
10757 | // do not have to do anything, and can be empty. |
10758 | void FatalConditionHandler::engage_platform() {} |
10759 | void FatalConditionHandler::disengage_platform() {} |
10760 | FatalConditionHandler::FatalConditionHandler() = default; |
10761 | FatalConditionHandler::~FatalConditionHandler() = default; |
10762 | |
10763 | } // end namespace Catch |
10764 | |
10765 | #endif // !CATCH_CONFIG_WINDOWS_SEH && !CATCH_CONFIG_POSIX_SIGNALS |
10766 | |
10767 | #if defined( CATCH_CONFIG_WINDOWS_SEH ) && defined( CATCH_CONFIG_POSIX_SIGNALS ) |
10768 | #error "Inconsistent configuration: Windows' SEH handling and POSIX signals cannot be enabled at the same time" |
10769 | #endif // CATCH_CONFIG_WINDOWS_SEH && CATCH_CONFIG_POSIX_SIGNALS |
10770 | |
10771 | #if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS ) |
10772 | |
10773 | namespace { |
10774 | //! Signals fatal error message to the run context |
10775 | void reportFatal( char const * const message ) { |
10776 | Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message ); |
10777 | } |
10778 | |
10779 | //! Minimal size Catch2 needs for its own fatal error handling. |
10780 | //! Picked anecdotally, so it might not be sufficient on all |
10781 | //! platforms, and for all configurations. |
10782 | constexpr std::size_t minStackSizeForErrors = 32 * 1024; |
10783 | } // end unnamed namespace |
10784 | |
10785 | #endif // CATCH_CONFIG_WINDOWS_SEH || CATCH_CONFIG_POSIX_SIGNALS |
10786 | |
10787 | #if defined( CATCH_CONFIG_WINDOWS_SEH ) |
10788 | |
10789 | namespace Catch { |
10790 | |
10791 | struct SignalDefs { DWORD id; const char* name; }; |
10792 | |
10793 | // There is no 1-1 mapping between signals and windows exceptions. |
10794 | // Windows can easily distinguish between SO and SigSegV, |
10795 | // but SigInt, SigTerm, etc are handled differently. |
10796 | static SignalDefs signalDefs[] = { |
10797 | { static_cast<DWORD>(EXCEPTION_ILLEGAL_INSTRUCTION), "SIGILL - Illegal instruction signal" }, |
10798 | { static_cast<DWORD>(EXCEPTION_STACK_OVERFLOW), "SIGSEGV - Stack overflow" }, |
10799 | { static_cast<DWORD>(EXCEPTION_ACCESS_VIOLATION), "SIGSEGV - Segmentation violation signal" }, |
10800 | { static_cast<DWORD>(EXCEPTION_INT_DIVIDE_BY_ZERO), "Divide by zero error" }, |
10801 | }; |
10802 | |
10803 | static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) { |
10804 | for (auto const& def : signalDefs) { |
10805 | if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) { |
10806 | reportFatal(def.name); |
10807 | } |
10808 | } |
10809 | // If its not an exception we care about, pass it along. |
10810 | // This stops us from eating debugger breaks etc. |
10811 | return EXCEPTION_CONTINUE_SEARCH; |
10812 | } |
10813 | |
10814 | // Since we do not support multiple instantiations, we put these |
10815 | // into global variables and rely on cleaning them up in outlined |
10816 | // constructors/destructors |
10817 | static PVOID exceptionHandlerHandle = nullptr; |
10818 | |
10819 | // For MSVC, we reserve part of the stack memory for handling |
10820 | // memory overflow structured exception. |
10821 | FatalConditionHandler::FatalConditionHandler() { |
10822 | ULONG guaranteeSize = static_cast<ULONG>(minStackSizeForErrors); |
10823 | if (!SetThreadStackGuarantee(&guaranteeSize)) { |
10824 | // We do not want to fully error out, because needing |
10825 | // the stack reserve should be rare enough anyway. |
10826 | Catch::cerr() |
10827 | << "Failed to reserve piece of stack." |
10828 | << " Stack overflows will not be reported successfully." ; |
10829 | } |
10830 | } |
10831 | |
10832 | // We do not attempt to unset the stack guarantee, because |
10833 | // Windows does not support lowering the stack size guarantee. |
10834 | FatalConditionHandler::~FatalConditionHandler() = default; |
10835 | |
10836 | void FatalConditionHandler::engage_platform() { |
10837 | // Register as first handler in current chain |
10838 | exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException); |
10839 | if (!exceptionHandlerHandle) { |
10840 | CATCH_RUNTIME_ERROR("Could not register vectored exception handler" ); |
10841 | } |
10842 | } |
10843 | |
10844 | void FatalConditionHandler::disengage_platform() { |
10845 | if (!RemoveVectoredExceptionHandler(exceptionHandlerHandle)) { |
10846 | CATCH_RUNTIME_ERROR("Could not unregister vectored exception handler" ); |
10847 | } |
10848 | exceptionHandlerHandle = nullptr; |
10849 | } |
10850 | |
10851 | } // end namespace Catch |
10852 | |
10853 | #endif // CATCH_CONFIG_WINDOWS_SEH |
10854 | |
10855 | #if defined( CATCH_CONFIG_POSIX_SIGNALS ) |
10856 | |
10857 | #include <signal.h> |
10858 | |
10859 | namespace Catch { |
10860 | |
10861 | struct SignalDefs { |
10862 | int id; |
10863 | const char* name; |
10864 | }; |
10865 | |
10866 | static SignalDefs signalDefs[] = { |
10867 | { SIGINT, "SIGINT - Terminal interrupt signal" }, |
10868 | { SIGILL, "SIGILL - Illegal instruction signal" }, |
10869 | { SIGFPE, "SIGFPE - Floating point error signal" }, |
10870 | { SIGSEGV, "SIGSEGV - Segmentation violation signal" }, |
10871 | { SIGTERM, "SIGTERM - Termination request signal" }, |
10872 | { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } |
10873 | }; |
10874 | |
10875 | // Older GCCs trigger -Wmissing-field-initializers for T foo = {} |
10876 | // which is zero initialization, but not explicit. We want to avoid |
10877 | // that. |
10878 | #if defined(__GNUC__) |
10879 | # pragma GCC diagnostic push |
10880 | # pragma GCC diagnostic ignored "-Wmissing-field-initializers" |
10881 | #endif |
10882 | |
10883 | static char* altStackMem = nullptr; |
10884 | static std::size_t altStackSize = 0; |
10885 | static stack_t oldSigStack{}; |
10886 | static struct sigaction oldSigActions[sizeof(signalDefs) / sizeof(SignalDefs)]{}; |
10887 | |
10888 | static void restorePreviousSignalHandlers() { |
10889 | // We set signal handlers back to the previous ones. Hopefully |
10890 | // nobody overwrote them in the meantime, and doesn't expect |
10891 | // their signal handlers to live past ours given that they |
10892 | // installed them after ours.. |
10893 | for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) { |
10894 | sigaction(signalDefs[i].id, &oldSigActions[i], nullptr); |
10895 | } |
10896 | // Return the old stack |
10897 | sigaltstack(&oldSigStack, nullptr); |
10898 | } |
10899 | |
10900 | static void handleSignal( int sig ) { |
10901 | char const * name = "<unknown signal>" ; |
10902 | for (auto const& def : signalDefs) { |
10903 | if (sig == def.id) { |
10904 | name = def.name; |
10905 | break; |
10906 | } |
10907 | } |
10908 | // We need to restore previous signal handlers and let them do |
10909 | // their thing, so that the users can have the debugger break |
10910 | // when a signal is raised, and so on. |
10911 | restorePreviousSignalHandlers(); |
10912 | reportFatal( name ); |
10913 | raise( sig ); |
10914 | } |
10915 | |
10916 | FatalConditionHandler::FatalConditionHandler() { |
10917 | assert(!altStackMem && "Cannot initialize POSIX signal handler when one already exists" ); |
10918 | if (altStackSize == 0) { |
10919 | altStackSize = std::max(static_cast<size_t>(SIGSTKSZ), minStackSizeForErrors); |
10920 | } |
10921 | altStackMem = new char[altStackSize](); |
10922 | } |
10923 | |
10924 | FatalConditionHandler::~FatalConditionHandler() { |
10925 | delete[] altStackMem; |
10926 | // We signal that another instance can be constructed by zeroing |
10927 | // out the pointer. |
10928 | altStackMem = nullptr; |
10929 | } |
10930 | |
10931 | void FatalConditionHandler::engage_platform() { |
10932 | stack_t sigStack; |
10933 | sigStack.ss_sp = altStackMem; |
10934 | sigStack.ss_size = altStackSize; |
10935 | sigStack.ss_flags = 0; |
10936 | sigaltstack(&sigStack, &oldSigStack); |
10937 | struct sigaction sa = { }; |
10938 | |
10939 | sa.sa_handler = handleSignal; |
10940 | sa.sa_flags = SA_ONSTACK; |
10941 | for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) { |
10942 | sigaction(signalDefs[i].id, &sa, &oldSigActions[i]); |
10943 | } |
10944 | } |
10945 | |
10946 | #if defined(__GNUC__) |
10947 | # pragma GCC diagnostic pop |
10948 | #endif |
10949 | |
10950 | void FatalConditionHandler::disengage_platform() { |
10951 | restorePreviousSignalHandlers(); |
10952 | } |
10953 | |
10954 | } // end namespace Catch |
10955 | |
10956 | #endif // CATCH_CONFIG_POSIX_SIGNALS |
10957 | // end catch_fatal_condition.cpp |
10958 | // start catch_generators.cpp |
10959 | |
10960 | #include <limits> |
10961 | #include <set> |
10962 | |
10963 | namespace Catch { |
10964 | |
10965 | IGeneratorTracker::~IGeneratorTracker() {} |
10966 | |
10967 | const char* GeneratorException::what() const noexcept { |
10968 | return m_msg; |
10969 | } |
10970 | |
10971 | namespace Generators { |
10972 | |
10973 | GeneratorUntypedBase::~GeneratorUntypedBase() {} |
10974 | |
10975 | auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { |
10976 | return getResultCapture().acquireGeneratorTracker( generatorName, lineInfo ); |
10977 | } |
10978 | |
10979 | } // namespace Generators |
10980 | } // namespace Catch |
10981 | // end catch_generators.cpp |
10982 | // start catch_interfaces_capture.cpp |
10983 | |
10984 | namespace Catch { |
10985 | IResultCapture::~IResultCapture() = default; |
10986 | } |
10987 | // end catch_interfaces_capture.cpp |
10988 | // start catch_interfaces_config.cpp |
10989 | |
10990 | namespace Catch { |
10991 | IConfig::~IConfig() = default; |
10992 | } |
10993 | // end catch_interfaces_config.cpp |
10994 | // start catch_interfaces_exception.cpp |
10995 | |
10996 | namespace Catch { |
10997 | IExceptionTranslator::~IExceptionTranslator() = default; |
10998 | IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() = default; |
10999 | } |
11000 | // end catch_interfaces_exception.cpp |
11001 | // start catch_interfaces_registry_hub.cpp |
11002 | |
11003 | namespace Catch { |
11004 | IRegistryHub::~IRegistryHub() = default; |
11005 | IMutableRegistryHub::~IMutableRegistryHub() = default; |
11006 | } |
11007 | // end catch_interfaces_registry_hub.cpp |
11008 | // start catch_interfaces_reporter.cpp |
11009 | |
11010 | // start catch_reporter_listening.h |
11011 | |
11012 | namespace Catch { |
11013 | |
11014 | class ListeningReporter : public IStreamingReporter { |
11015 | using Reporters = std::vector<IStreamingReporterPtr>; |
11016 | Reporters m_listeners; |
11017 | IStreamingReporterPtr m_reporter = nullptr; |
11018 | ReporterPreferences m_preferences; |
11019 | |
11020 | public: |
11021 | ListeningReporter(); |
11022 | |
11023 | void addListener( IStreamingReporterPtr&& listener ); |
11024 | void addReporter( IStreamingReporterPtr&& reporter ); |
11025 | |
11026 | public: // IStreamingReporter |
11027 | |
11028 | ReporterPreferences getPreferences() const override; |
11029 | |
11030 | void noMatchingTestCases( std::string const& spec ) override; |
11031 | |
11032 | void reportInvalidArguments(std::string const&arg) override; |
11033 | |
11034 | static std::set<Verbosity> getSupportedVerbosities(); |
11035 | |
11036 | #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) |
11037 | void benchmarkPreparing(std::string const& name) override; |
11038 | void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) override; |
11039 | void benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) override; |
11040 | void benchmarkFailed(std::string const&) override; |
11041 | #endif // CATCH_CONFIG_ENABLE_BENCHMARKING |
11042 | |
11043 | void testRunStarting( TestRunInfo const& testRunInfo ) override; |
11044 | void testGroupStarting( GroupInfo const& groupInfo ) override; |
11045 | void testCaseStarting( TestCaseInfo const& testInfo ) override; |
11046 | void sectionStarting( SectionInfo const& sectionInfo ) override; |
11047 | void assertionStarting( AssertionInfo const& assertionInfo ) override; |
11048 | |
11049 | // The return value indicates if the messages buffer should be cleared: |
11050 | bool assertionEnded( AssertionStats const& assertionStats ) override; |
11051 | void sectionEnded( SectionStats const& sectionStats ) override; |
11052 | void testCaseEnded( TestCaseStats const& testCaseStats ) override; |
11053 | void testGroupEnded( TestGroupStats const& testGroupStats ) override; |
11054 | void testRunEnded( TestRunStats const& testRunStats ) override; |
11055 | |
11056 | void skipTest( TestCaseInfo const& testInfo ) override; |
11057 | bool isMulti() const override; |
11058 | |
11059 | }; |
11060 | |
11061 | } // end namespace Catch |
11062 | |
11063 | // end catch_reporter_listening.h |
11064 | namespace Catch { |
11065 | |
11066 | ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig ) |
11067 | : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} |
11068 | |
11069 | ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream ) |
11070 | : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} |
11071 | |
11072 | std::ostream& ReporterConfig::stream() const { return *m_stream; } |
11073 | IConfigPtr ReporterConfig::fullConfig() const { return m_fullConfig; } |
11074 | |
11075 | TestRunInfo::TestRunInfo( std::string const& _name ) : name( _name ) {} |
11076 | |
11077 | GroupInfo::GroupInfo( std::string const& _name, |
11078 | std::size_t _groupIndex, |
11079 | std::size_t _groupsCount ) |
11080 | : name( _name ), |
11081 | groupIndex( _groupIndex ), |
11082 | groupsCounts( _groupsCount ) |
11083 | {} |
11084 | |
11085 | AssertionStats::AssertionStats( AssertionResult const& _assertionResult, |
11086 | std::vector<MessageInfo> const& _infoMessages, |
11087 | Totals const& _totals ) |
11088 | : assertionResult( _assertionResult ), |
11089 | infoMessages( _infoMessages ), |
11090 | totals( _totals ) |
11091 | { |
11092 | assertionResult.m_resultData.lazyExpression.m_transientExpression = _assertionResult.m_resultData.lazyExpression.m_transientExpression; |
11093 | |
11094 | if( assertionResult.hasMessage() ) { |
11095 | // Copy message into messages list. |
11096 | // !TBD This should have been done earlier, somewhere |
11097 | MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); |
11098 | builder << assertionResult.getMessage(); |
11099 | builder.m_info.message = builder.m_stream.str(); |
11100 | |
11101 | infoMessages.push_back( builder.m_info ); |
11102 | } |
11103 | } |
11104 | |
11105 | AssertionStats::~AssertionStats() = default; |
11106 | |
11107 | SectionStats::SectionStats( SectionInfo const& _sectionInfo, |
11108 | Counts const& _assertions, |
11109 | double _durationInSeconds, |
11110 | bool _missingAssertions ) |
11111 | : sectionInfo( _sectionInfo ), |
11112 | assertions( _assertions ), |
11113 | durationInSeconds( _durationInSeconds ), |
11114 | missingAssertions( _missingAssertions ) |
11115 | {} |
11116 | |
11117 | SectionStats::~SectionStats() = default; |
11118 | |
11119 | TestCaseStats::TestCaseStats( TestCaseInfo const& _testInfo, |
11120 | Totals const& _totals, |
11121 | std::string const& _stdOut, |
11122 | std::string const& _stdErr, |
11123 | bool _aborting ) |
11124 | : testInfo( _testInfo ), |
11125 | totals( _totals ), |
11126 | stdOut( _stdOut ), |
11127 | stdErr( _stdErr ), |
11128 | aborting( _aborting ) |
11129 | {} |
11130 | |
11131 | TestCaseStats::~TestCaseStats() = default; |
11132 | |
11133 | TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo, |
11134 | Totals const& _totals, |
11135 | bool _aborting ) |
11136 | : groupInfo( _groupInfo ), |
11137 | totals( _totals ), |
11138 | aborting( _aborting ) |
11139 | {} |
11140 | |
11141 | TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo ) |
11142 | : groupInfo( _groupInfo ), |
11143 | aborting( false ) |
11144 | {} |
11145 | |
11146 | TestGroupStats::~TestGroupStats() = default; |
11147 | |
11148 | TestRunStats::TestRunStats( TestRunInfo const& _runInfo, |
11149 | Totals const& _totals, |
11150 | bool _aborting ) |
11151 | : runInfo( _runInfo ), |
11152 | totals( _totals ), |
11153 | aborting( _aborting ) |
11154 | {} |
11155 | |
11156 | TestRunStats::~TestRunStats() = default; |
11157 | |
11158 | void IStreamingReporter::fatalErrorEncountered( StringRef ) {} |
11159 | bool IStreamingReporter::isMulti() const { return false; } |
11160 | |
11161 | IReporterFactory::~IReporterFactory() = default; |
11162 | IReporterRegistry::~IReporterRegistry() = default; |
11163 | |
11164 | } // end namespace Catch |
11165 | // end catch_interfaces_reporter.cpp |
11166 | // start catch_interfaces_runner.cpp |
11167 | |
11168 | namespace Catch { |
11169 | IRunner::~IRunner() = default; |
11170 | } |
11171 | // end catch_interfaces_runner.cpp |
11172 | // start catch_interfaces_testcase.cpp |
11173 | |
11174 | namespace Catch { |
11175 | ITestInvoker::~ITestInvoker() = default; |
11176 | ITestCaseRegistry::~ITestCaseRegistry() = default; |
11177 | } |
11178 | // end catch_interfaces_testcase.cpp |
11179 | // start catch_leak_detector.cpp |
11180 | |
11181 | #ifdef CATCH_CONFIG_WINDOWS_CRTDBG |
11182 | #include <crtdbg.h> |
11183 | |
11184 | namespace Catch { |
11185 | |
11186 | LeakDetector::LeakDetector() { |
11187 | int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); |
11188 | flag |= _CRTDBG_LEAK_CHECK_DF; |
11189 | flag |= _CRTDBG_ALLOC_MEM_DF; |
11190 | _CrtSetDbgFlag(flag); |
11191 | _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); |
11192 | _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); |
11193 | // Change this to leaking allocation's number to break there |
11194 | _CrtSetBreakAlloc(-1); |
11195 | } |
11196 | } |
11197 | |
11198 | #else |
11199 | |
11200 | Catch::LeakDetector::LeakDetector() {} |
11201 | |
11202 | #endif |
11203 | |
11204 | Catch::LeakDetector::~LeakDetector() { |
11205 | Catch::cleanUp(); |
11206 | } |
11207 | // end catch_leak_detector.cpp |
11208 | // start catch_list.cpp |
11209 | |
11210 | // start catch_list.h |
11211 | |
11212 | #include <set> |
11213 | |
11214 | namespace Catch { |
11215 | |
11216 | std::size_t listTests( Config const& config ); |
11217 | |
11218 | std::size_t listTestsNamesOnly( Config const& config ); |
11219 | |
11220 | struct TagInfo { |
11221 | void add( std::string const& spelling ); |
11222 | std::string all() const; |
11223 | |
11224 | std::set<std::string> spellings; |
11225 | std::size_t count = 0; |
11226 | }; |
11227 | |
11228 | std::size_t listTags( Config const& config ); |
11229 | |
11230 | std::size_t listReporters(); |
11231 | |
11232 | Option<std::size_t> list( std::shared_ptr<Config> const& config ); |
11233 | |
11234 | } // end namespace Catch |
11235 | |
11236 | // end catch_list.h |
11237 | // start catch_text.h |
11238 | |
11239 | namespace Catch { |
11240 | using namespace clara::TextFlow; |
11241 | } |
11242 | |
11243 | // end catch_text.h |
11244 | #include <limits> |
11245 | #include <algorithm> |
11246 | #include <iomanip> |
11247 | |
11248 | namespace Catch { |
11249 | |
11250 | std::size_t listTests( Config const& config ) { |
11251 | TestSpec const& testSpec = config.testSpec(); |
11252 | if( config.hasTestFilters() ) |
11253 | Catch::cout() << "Matching test cases:\n" ; |
11254 | else { |
11255 | Catch::cout() << "All available test cases:\n" ; |
11256 | } |
11257 | |
11258 | auto matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); |
11259 | for( auto const& testCaseInfo : matchedTestCases ) { |
11260 | Colour::Code colour = testCaseInfo.isHidden() |
11261 | ? Colour::SecondaryText |
11262 | : Colour::None; |
11263 | Colour colourGuard( colour ); |
11264 | |
11265 | Catch::cout() << Column( testCaseInfo.name ).initialIndent( 2 ).indent( 4 ) << "\n" ; |
11266 | if( config.verbosity() >= Verbosity::High ) { |
11267 | Catch::cout() << Column( Catch::Detail::stringify( testCaseInfo.lineInfo ) ).indent(4) << std::endl; |
11268 | std::string description = testCaseInfo.description; |
11269 | if( description.empty() ) |
11270 | description = "(NO DESCRIPTION)" ; |
11271 | Catch::cout() << Column( description ).indent(4) << std::endl; |
11272 | } |
11273 | if( !testCaseInfo.tags.empty() ) |
11274 | Catch::cout() << Column( testCaseInfo.tagsAsString() ).indent( 6 ) << "\n" ; |
11275 | } |
11276 | |
11277 | if( !config.hasTestFilters() ) |
11278 | Catch::cout() << pluralise( matchedTestCases.size(), "test case" ) << '\n' << std::endl; |
11279 | else |
11280 | Catch::cout() << pluralise( matchedTestCases.size(), "matching test case" ) << '\n' << std::endl; |
11281 | return matchedTestCases.size(); |
11282 | } |
11283 | |
11284 | std::size_t listTestsNamesOnly( Config const& config ) { |
11285 | TestSpec const& testSpec = config.testSpec(); |
11286 | std::size_t matchedTests = 0; |
11287 | std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); |
11288 | for( auto const& testCaseInfo : matchedTestCases ) { |
11289 | matchedTests++; |
11290 | if( startsWith( testCaseInfo.name, '#' ) ) |
11291 | Catch::cout() << '"' << testCaseInfo.name << '"'; |
11292 | else |
11293 | Catch::cout() << testCaseInfo.name; |
11294 | if ( config.verbosity() >= Verbosity::High ) |
11295 | Catch::cout() << "\t@" << testCaseInfo.lineInfo; |
11296 | Catch::cout() << std::endl; |
11297 | } |
11298 | return matchedTests; |
11299 | } |
11300 | |
11301 | void TagInfo::add( std::string const& spelling ) { |
11302 | ++count; |
11303 | spellings.insert( spelling ); |
11304 | } |
11305 | |
11306 | std::string TagInfo::all() const { |
11307 | size_t size = 0; |
11308 | for (auto const& spelling : spellings) { |
11309 | // Add 2 for the brackes |
11310 | size += spelling.size() + 2; |
11311 | } |
11312 | |
11313 | std::string out; out.reserve(size); |
11314 | for (auto const& spelling : spellings) { |
11315 | out += '['; |
11316 | out += spelling; |
11317 | out += ']'; |
11318 | } |
11319 | return out; |
11320 | } |
11321 | |
11322 | std::size_t listTags( Config const& config ) { |
11323 | TestSpec const& testSpec = config.testSpec(); |
11324 | if( config.hasTestFilters() ) |
11325 | Catch::cout() << "Tags for matching test cases:\n" ; |
11326 | else { |
11327 | Catch::cout() << "All available tags:\n" ; |
11328 | } |
11329 | |
11330 | std::map<std::string, TagInfo> tagCounts; |
11331 | |
11332 | std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); |
11333 | for( auto const& testCase : matchedTestCases ) { |
11334 | for( auto const& tagName : testCase.getTestCaseInfo().tags ) { |
11335 | std::string lcaseTagName = toLower( tagName ); |
11336 | auto countIt = tagCounts.find( lcaseTagName ); |
11337 | if( countIt == tagCounts.end() ) |
11338 | countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; |
11339 | countIt->second.add( tagName ); |
11340 | } |
11341 | } |
11342 | |
11343 | for( auto const& tagCount : tagCounts ) { |
11344 | ReusableStringStream rss; |
11345 | rss << " " << std::setw(2) << tagCount.second.count << " " ; |
11346 | auto str = rss.str(); |
11347 | auto wrapper = Column( tagCount.second.all() ) |
11348 | .initialIndent( 0 ) |
11349 | .indent( str.size() ) |
11350 | .width( CATCH_CONFIG_CONSOLE_WIDTH-10 ); |
11351 | Catch::cout() << str << wrapper << '\n'; |
11352 | } |
11353 | Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl; |
11354 | return tagCounts.size(); |
11355 | } |
11356 | |
11357 | std::size_t listReporters() { |
11358 | Catch::cout() << "Available reporters:\n" ; |
11359 | IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); |
11360 | std::size_t maxNameLen = 0; |
11361 | for( auto const& factoryKvp : factories ) |
11362 | maxNameLen = (std::max)( maxNameLen, factoryKvp.first.size() ); |
11363 | |
11364 | for( auto const& factoryKvp : factories ) { |
11365 | Catch::cout() |
11366 | << Column( factoryKvp.first + ":" ) |
11367 | .indent(2) |
11368 | .width( 5+maxNameLen ) |
11369 | + Column( factoryKvp.second->getDescription() ) |
11370 | .initialIndent(0) |
11371 | .indent(2) |
11372 | .width( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) |
11373 | << "\n" ; |
11374 | } |
11375 | Catch::cout() << std::endl; |
11376 | return factories.size(); |
11377 | } |
11378 | |
11379 | Option<std::size_t> list( std::shared_ptr<Config> const& config ) { |
11380 | Option<std::size_t> listedCount; |
11381 | getCurrentMutableContext().setConfig( config ); |
11382 | if( config->listTests() ) |
11383 | listedCount = listedCount.valueOr(0) + listTests( *config ); |
11384 | if( config->listTestNamesOnly() ) |
11385 | listedCount = listedCount.valueOr(0) + listTestsNamesOnly( *config ); |
11386 | if( config->listTags() ) |
11387 | listedCount = listedCount.valueOr(0) + listTags( *config ); |
11388 | if( config->listReporters() ) |
11389 | listedCount = listedCount.valueOr(0) + listReporters(); |
11390 | return listedCount; |
11391 | } |
11392 | |
11393 | } // end namespace Catch |
11394 | // end catch_list.cpp |
11395 | // start catch_matchers.cpp |
11396 | |
11397 | namespace Catch { |
11398 | namespace Matchers { |
11399 | namespace Impl { |
11400 | |
11401 | std::string MatcherUntypedBase::toString() const { |
11402 | if( m_cachedToString.empty() ) |
11403 | m_cachedToString = describe(); |
11404 | return m_cachedToString; |
11405 | } |
11406 | |
11407 | MatcherUntypedBase::~MatcherUntypedBase() = default; |
11408 | |
11409 | } // namespace Impl |
11410 | } // namespace Matchers |
11411 | |
11412 | using namespace Matchers; |
11413 | using Matchers::Impl::MatcherBase; |
11414 | |
11415 | } // namespace Catch |
11416 | // end catch_matchers.cpp |
11417 | // start catch_matchers_exception.cpp |
11418 | |
11419 | namespace Catch { |
11420 | namespace Matchers { |
11421 | namespace Exception { |
11422 | |
11423 | bool ExceptionMessageMatcher::match(std::exception const& ex) const { |
11424 | return ex.what() == m_message; |
11425 | } |
11426 | |
11427 | std::string ExceptionMessageMatcher::describe() const { |
11428 | return "exception message matches \"" + m_message + "\"" ; |
11429 | } |
11430 | |
11431 | } |
11432 | Exception::ExceptionMessageMatcher Message(std::string const& message) { |
11433 | return Exception::ExceptionMessageMatcher(message); |
11434 | } |
11435 | |
11436 | // namespace Exception |
11437 | } // namespace Matchers |
11438 | } // namespace Catch |
11439 | // end catch_matchers_exception.cpp |
11440 | // start catch_matchers_floating.cpp |
11441 | |
11442 | // start catch_polyfills.hpp |
11443 | |
11444 | namespace Catch { |
11445 | bool isnan(float f); |
11446 | bool isnan(double d); |
11447 | } |
11448 | |
11449 | // end catch_polyfills.hpp |
11450 | // start catch_to_string.hpp |
11451 | |
11452 | #include <string> |
11453 | |
11454 | namespace Catch { |
11455 | template <typename T> |
11456 | std::string to_string(T const& t) { |
11457 | #if defined(CATCH_CONFIG_CPP11_TO_STRING) |
11458 | return std::to_string(t); |
11459 | #else |
11460 | ReusableStringStream rss; |
11461 | rss << t; |
11462 | return rss.str(); |
11463 | #endif |
11464 | } |
11465 | } // end namespace Catch |
11466 | |
11467 | // end catch_to_string.hpp |
11468 | #include <algorithm> |
11469 | #include <cmath> |
11470 | #include <cstdlib> |
11471 | #include <cstdint> |
11472 | #include <cstring> |
11473 | #include <sstream> |
11474 | #include <type_traits> |
11475 | #include <iomanip> |
11476 | #include <limits> |
11477 | |
11478 | namespace Catch { |
11479 | namespace { |
11480 | |
11481 | int32_t convert(float f) { |
11482 | static_assert(sizeof(float) == sizeof(int32_t), "Important ULP matcher assumption violated" ); |
11483 | int32_t i; |
11484 | std::memcpy(&i, &f, sizeof(f)); |
11485 | return i; |
11486 | } |
11487 | |
11488 | int64_t convert(double d) { |
11489 | static_assert(sizeof(double) == sizeof(int64_t), "Important ULP matcher assumption violated" ); |
11490 | int64_t i; |
11491 | std::memcpy(&i, &d, sizeof(d)); |
11492 | return i; |
11493 | } |
11494 | |
11495 | template <typename FP> |
11496 | bool almostEqualUlps(FP lhs, FP rhs, uint64_t maxUlpDiff) { |
11497 | // Comparison with NaN should always be false. |
11498 | // This way we can rule it out before getting into the ugly details |
11499 | if (Catch::isnan(lhs) || Catch::isnan(rhs)) { |
11500 | return false; |
11501 | } |
11502 | |
11503 | auto lc = convert(lhs); |
11504 | auto rc = convert(rhs); |
11505 | |
11506 | if ((lc < 0) != (rc < 0)) { |
11507 | // Potentially we can have +0 and -0 |
11508 | return lhs == rhs; |
11509 | } |
11510 | |
11511 | // static cast as a workaround for IBM XLC |
11512 | auto ulpDiff = std::abs(static_cast<FP>(lc - rc)); |
11513 | return static_cast<uint64_t>(ulpDiff) <= maxUlpDiff; |
11514 | } |
11515 | |
11516 | #if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) |
11517 | |
11518 | float nextafter(float x, float y) { |
11519 | return ::nextafterf(x, y); |
11520 | } |
11521 | |
11522 | double nextafter(double x, double y) { |
11523 | return ::nextafter(x, y); |
11524 | } |
11525 | |
11526 | #endif // ^^^ CATCH_CONFIG_GLOBAL_NEXTAFTER ^^^ |
11527 | |
11528 | template <typename FP> |
11529 | FP step(FP start, FP direction, uint64_t steps) { |
11530 | for (uint64_t i = 0; i < steps; ++i) { |
11531 | #if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) |
11532 | start = Catch::nextafter(start, direction); |
11533 | #else |
11534 | start = std::nextafter(start, direction); |
11535 | #endif |
11536 | } |
11537 | return start; |
11538 | } |
11539 | |
11540 | // Performs equivalent check of std::fabs(lhs - rhs) <= margin |
11541 | // But without the subtraction to allow for INFINITY in comparison |
11542 | bool marginComparison(double lhs, double rhs, double margin) { |
11543 | return (lhs + margin >= rhs) && (rhs + margin >= lhs); |
11544 | } |
11545 | |
11546 | template <typename FloatingPoint> |
11547 | void write(std::ostream& out, FloatingPoint num) { |
11548 | out << std::scientific |
11549 | << std::setprecision(std::numeric_limits<FloatingPoint>::max_digits10 - 1) |
11550 | << num; |
11551 | } |
11552 | |
11553 | } // end anonymous namespace |
11554 | |
11555 | namespace Matchers { |
11556 | namespace Floating { |
11557 | |
11558 | enum class FloatingPointKind : uint8_t { |
11559 | Float, |
11560 | Double |
11561 | }; |
11562 | |
11563 | WithinAbsMatcher::WithinAbsMatcher(double target, double margin) |
11564 | :m_target{ target }, m_margin{ margin } { |
11565 | CATCH_ENFORCE(margin >= 0, "Invalid margin: " << margin << '.' |
11566 | << " Margin has to be non-negative." ); |
11567 | } |
11568 | |
11569 | // Performs equivalent check of std::fabs(lhs - rhs) <= margin |
11570 | // But without the subtraction to allow for INFINITY in comparison |
11571 | bool WithinAbsMatcher::match(double const& matchee) const { |
11572 | return (matchee + m_margin >= m_target) && (m_target + m_margin >= matchee); |
11573 | } |
11574 | |
11575 | std::string WithinAbsMatcher::describe() const { |
11576 | return "is within " + ::Catch::Detail::stringify(m_margin) + " of " + ::Catch::Detail::stringify(m_target); |
11577 | } |
11578 | |
11579 | WithinUlpsMatcher::WithinUlpsMatcher(double target, uint64_t ulps, FloatingPointKind baseType) |
11580 | :m_target{ target }, m_ulps{ ulps }, m_type{ baseType } { |
11581 | CATCH_ENFORCE(m_type == FloatingPointKind::Double |
11582 | || m_ulps < (std::numeric_limits<uint32_t>::max)(), |
11583 | "Provided ULP is impossibly large for a float comparison." ); |
11584 | } |
11585 | |
11586 | #if defined(__clang__) |
11587 | #pragma clang diagnostic push |
11588 | // Clang <3.5 reports on the default branch in the switch below |
11589 | #pragma clang diagnostic ignored "-Wunreachable-code" |
11590 | #endif |
11591 | |
11592 | bool WithinUlpsMatcher::match(double const& matchee) const { |
11593 | switch (m_type) { |
11594 | case FloatingPointKind::Float: |
11595 | return almostEqualUlps<float>(static_cast<float>(matchee), static_cast<float>(m_target), m_ulps); |
11596 | case FloatingPointKind::Double: |
11597 | return almostEqualUlps<double>(matchee, m_target, m_ulps); |
11598 | default: |
11599 | CATCH_INTERNAL_ERROR( "Unknown FloatingPointKind value" ); |
11600 | } |
11601 | } |
11602 | |
11603 | #if defined(__clang__) |
11604 | #pragma clang diagnostic pop |
11605 | #endif |
11606 | |
11607 | std::string WithinUlpsMatcher::describe() const { |
11608 | std::stringstream ret; |
11609 | |
11610 | ret << "is within " << m_ulps << " ULPs of " ; |
11611 | |
11612 | if (m_type == FloatingPointKind::Float) { |
11613 | write(ret, static_cast<float>(m_target)); |
11614 | ret << 'f'; |
11615 | } else { |
11616 | write(ret, m_target); |
11617 | } |
11618 | |
11619 | ret << " ([" ; |
11620 | if (m_type == FloatingPointKind::Double) { |
11621 | write(ret, step(m_target, static_cast<double>(-INFINITY), m_ulps)); |
11622 | ret << ", " ; |
11623 | write(ret, step(m_target, static_cast<double>( INFINITY), m_ulps)); |
11624 | } else { |
11625 | // We have to cast INFINITY to float because of MinGW, see #1782 |
11626 | write(ret, step(static_cast<float>(m_target), static_cast<float>(-INFINITY), m_ulps)); |
11627 | ret << ", " ; |
11628 | write(ret, step(static_cast<float>(m_target), static_cast<float>( INFINITY), m_ulps)); |
11629 | } |
11630 | ret << "])" ; |
11631 | |
11632 | return ret.str(); |
11633 | } |
11634 | |
11635 | WithinRelMatcher::WithinRelMatcher(double target, double epsilon): |
11636 | m_target(target), |
11637 | m_epsilon(epsilon){ |
11638 | CATCH_ENFORCE(m_epsilon >= 0., "Relative comparison with epsilon < 0 does not make sense." ); |
11639 | CATCH_ENFORCE(m_epsilon < 1., "Relative comparison with epsilon >= 1 does not make sense." ); |
11640 | } |
11641 | |
11642 | bool WithinRelMatcher::match(double const& matchee) const { |
11643 | const auto relMargin = m_epsilon * (std::max)(std::fabs(matchee), std::fabs(m_target)); |
11644 | return marginComparison(matchee, m_target, |
11645 | std::isinf(relMargin)? 0 : relMargin); |
11646 | } |
11647 | |
11648 | std::string WithinRelMatcher::describe() const { |
11649 | Catch::ReusableStringStream sstr; |
11650 | sstr << "and " << m_target << " are within " << m_epsilon * 100. << "% of each other" ; |
11651 | return sstr.str(); |
11652 | } |
11653 | |
11654 | }// namespace Floating |
11655 | |
11656 | Floating::WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff) { |
11657 | return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Double); |
11658 | } |
11659 | |
11660 | Floating::WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff) { |
11661 | return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Float); |
11662 | } |
11663 | |
11664 | Floating::WithinAbsMatcher WithinAbs(double target, double margin) { |
11665 | return Floating::WithinAbsMatcher(target, margin); |
11666 | } |
11667 | |
11668 | Floating::WithinRelMatcher WithinRel(double target, double eps) { |
11669 | return Floating::WithinRelMatcher(target, eps); |
11670 | } |
11671 | |
11672 | Floating::WithinRelMatcher WithinRel(double target) { |
11673 | return Floating::WithinRelMatcher(target, std::numeric_limits<double>::epsilon() * 100); |
11674 | } |
11675 | |
11676 | Floating::WithinRelMatcher WithinRel(float target, float eps) { |
11677 | return Floating::WithinRelMatcher(target, eps); |
11678 | } |
11679 | |
11680 | Floating::WithinRelMatcher WithinRel(float target) { |
11681 | return Floating::WithinRelMatcher(target, std::numeric_limits<float>::epsilon() * 100); |
11682 | } |
11683 | |
11684 | } // namespace Matchers |
11685 | } // namespace Catch |
11686 | // end catch_matchers_floating.cpp |
11687 | // start catch_matchers_generic.cpp |
11688 | |
11689 | std::string Catch::Matchers::Generic::Detail::finalizeDescription(const std::string& desc) { |
11690 | if (desc.empty()) { |
11691 | return "matches undescribed predicate" ; |
11692 | } else { |
11693 | return "matches predicate: \"" + desc + '"'; |
11694 | } |
11695 | } |
11696 | // end catch_matchers_generic.cpp |
11697 | // start catch_matchers_string.cpp |
11698 | |
11699 | #include <regex> |
11700 | |
11701 | namespace Catch { |
11702 | namespace Matchers { |
11703 | |
11704 | namespace StdString { |
11705 | |
11706 | CasedString::CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ) |
11707 | : m_caseSensitivity( caseSensitivity ), |
11708 | m_str( adjustString( str ) ) |
11709 | {} |
11710 | std::string CasedString::adjustString( std::string const& str ) const { |
11711 | return m_caseSensitivity == CaseSensitive::No |
11712 | ? toLower( str ) |
11713 | : str; |
11714 | } |
11715 | std::string CasedString::caseSensitivitySuffix() const { |
11716 | return m_caseSensitivity == CaseSensitive::No |
11717 | ? " (case insensitive)" |
11718 | : std::string(); |
11719 | } |
11720 | |
11721 | StringMatcherBase::StringMatcherBase( std::string const& operation, CasedString const& comparator ) |
11722 | : m_comparator( comparator ), |
11723 | m_operation( operation ) { |
11724 | } |
11725 | |
11726 | std::string StringMatcherBase::describe() const { |
11727 | std::string description; |
11728 | description.reserve(5 + m_operation.size() + m_comparator.m_str.size() + |
11729 | m_comparator.caseSensitivitySuffix().size()); |
11730 | description += m_operation; |
11731 | description += ": \"" ; |
11732 | description += m_comparator.m_str; |
11733 | description += "\"" ; |
11734 | description += m_comparator.caseSensitivitySuffix(); |
11735 | return description; |
11736 | } |
11737 | |
11738 | EqualsMatcher::EqualsMatcher( CasedString const& comparator ) : StringMatcherBase( "equals" , comparator ) {} |
11739 | |
11740 | bool EqualsMatcher::match( std::string const& source ) const { |
11741 | return m_comparator.adjustString( source ) == m_comparator.m_str; |
11742 | } |
11743 | |
11744 | ContainsMatcher::ContainsMatcher( CasedString const& comparator ) : StringMatcherBase( "contains" , comparator ) {} |
11745 | |
11746 | bool ContainsMatcher::match( std::string const& source ) const { |
11747 | return contains( m_comparator.adjustString( source ), m_comparator.m_str ); |
11748 | } |
11749 | |
11750 | StartsWithMatcher::StartsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "starts with" , comparator ) {} |
11751 | |
11752 | bool StartsWithMatcher::match( std::string const& source ) const { |
11753 | return startsWith( m_comparator.adjustString( source ), m_comparator.m_str ); |
11754 | } |
11755 | |
11756 | EndsWithMatcher::EndsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "ends with" , comparator ) {} |
11757 | |
11758 | bool EndsWithMatcher::match( std::string const& source ) const { |
11759 | return endsWith( m_comparator.adjustString( source ), m_comparator.m_str ); |
11760 | } |
11761 | |
11762 | RegexMatcher::RegexMatcher(std::string regex, CaseSensitive::Choice caseSensitivity): m_regex(std::move(regex)), m_caseSensitivity(caseSensitivity) {} |
11763 | |
11764 | bool RegexMatcher::match(std::string const& matchee) const { |
11765 | auto flags = std::regex::ECMAScript; // ECMAScript is the default syntax option anyway |
11766 | if (m_caseSensitivity == CaseSensitive::Choice::No) { |
11767 | flags |= std::regex::icase; |
11768 | } |
11769 | auto reg = std::regex(m_regex, flags); |
11770 | return std::regex_match(matchee, reg); |
11771 | } |
11772 | |
11773 | std::string RegexMatcher::describe() const { |
11774 | return "matches " + ::Catch::Detail::stringify(m_regex) + ((m_caseSensitivity == CaseSensitive::Choice::Yes)? " case sensitively" : " case insensitively" ); |
11775 | } |
11776 | |
11777 | } // namespace StdString |
11778 | |
11779 | StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity ) { |
11780 | return StdString::EqualsMatcher( StdString::CasedString( str, caseSensitivity) ); |
11781 | } |
11782 | StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity ) { |
11783 | return StdString::ContainsMatcher( StdString::CasedString( str, caseSensitivity) ); |
11784 | } |
11785 | StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) { |
11786 | return StdString::EndsWithMatcher( StdString::CasedString( str, caseSensitivity) ); |
11787 | } |
11788 | StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) { |
11789 | return StdString::StartsWithMatcher( StdString::CasedString( str, caseSensitivity) ); |
11790 | } |
11791 | |
11792 | StdString::RegexMatcher Matches(std::string const& regex, CaseSensitive::Choice caseSensitivity) { |
11793 | return StdString::RegexMatcher(regex, caseSensitivity); |
11794 | } |
11795 | |
11796 | } // namespace Matchers |
11797 | } // namespace Catch |
11798 | // end catch_matchers_string.cpp |
11799 | // start catch_message.cpp |
11800 | |
11801 | // start catch_uncaught_exceptions.h |
11802 | |
11803 | namespace Catch { |
11804 | bool uncaught_exceptions(); |
11805 | } // end namespace Catch |
11806 | |
11807 | // end catch_uncaught_exceptions.h |
11808 | #include <cassert> |
11809 | #include <stack> |
11810 | |
11811 | namespace Catch { |
11812 | |
11813 | MessageInfo::MessageInfo( StringRef const& _macroName, |
11814 | SourceLineInfo const& _lineInfo, |
11815 | ResultWas::OfType _type ) |
11816 | : macroName( _macroName ), |
11817 | lineInfo( _lineInfo ), |
11818 | type( _type ), |
11819 | sequence( ++globalCount ) |
11820 | {} |
11821 | |
11822 | bool MessageInfo::operator==( MessageInfo const& other ) const { |
11823 | return sequence == other.sequence; |
11824 | } |
11825 | |
11826 | bool MessageInfo::operator<( MessageInfo const& other ) const { |
11827 | return sequence < other.sequence; |
11828 | } |
11829 | |
11830 | // This may need protecting if threading support is added |
11831 | unsigned int MessageInfo::globalCount = 0; |
11832 | |
11833 | //////////////////////////////////////////////////////////////////////////// |
11834 | |
11835 | Catch::MessageBuilder::MessageBuilder( StringRef const& macroName, |
11836 | SourceLineInfo const& lineInfo, |
11837 | ResultWas::OfType type ) |
11838 | :m_info(macroName, lineInfo, type) {} |
11839 | |
11840 | //////////////////////////////////////////////////////////////////////////// |
11841 | |
11842 | ScopedMessage::ScopedMessage( MessageBuilder const& builder ) |
11843 | : m_info( builder.m_info ), m_moved() |
11844 | { |
11845 | m_info.message = builder.m_stream.str(); |
11846 | getResultCapture().pushScopedMessage( m_info ); |
11847 | } |
11848 | |
11849 | ScopedMessage::ScopedMessage( ScopedMessage&& old ) |
11850 | : m_info( old.m_info ), m_moved() |
11851 | { |
11852 | old.m_moved = true; |
11853 | } |
11854 | |
11855 | ScopedMessage::~ScopedMessage() { |
11856 | if ( !uncaught_exceptions() && !m_moved ){ |
11857 | getResultCapture().popScopedMessage(m_info); |
11858 | } |
11859 | } |
11860 | |
11861 | Capturer::Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ) { |
11862 | auto trimmed = [&] (size_t start, size_t end) { |
11863 | while (names[start] == ',' || isspace(static_cast<unsigned char>(names[start]))) { |
11864 | ++start; |
11865 | } |
11866 | while (names[end] == ',' || isspace(static_cast<unsigned char>(names[end]))) { |
11867 | --end; |
11868 | } |
11869 | return names.substr(start, end - start + 1); |
11870 | }; |
11871 | auto skipq = [&] (size_t start, char quote) { |
11872 | for (auto i = start + 1; i < names.size() ; ++i) { |
11873 | if (names[i] == quote) |
11874 | return i; |
11875 | if (names[i] == '\\') |
11876 | ++i; |
11877 | } |
11878 | CATCH_INTERNAL_ERROR("CAPTURE parsing encountered unmatched quote" ); |
11879 | }; |
11880 | |
11881 | size_t start = 0; |
11882 | std::stack<char> openings; |
11883 | for (size_t pos = 0; pos < names.size(); ++pos) { |
11884 | char c = names[pos]; |
11885 | switch (c) { |
11886 | case '[': |
11887 | case '{': |
11888 | case '(': |
11889 | // It is basically impossible to disambiguate between |
11890 | // comparison and start of template args in this context |
11891 | // case '<': |
11892 | openings.push(c); |
11893 | break; |
11894 | case ']': |
11895 | case '}': |
11896 | case ')': |
11897 | // case '>': |
11898 | openings.pop(); |
11899 | break; |
11900 | case '"': |
11901 | case '\'': |
11902 | pos = skipq(pos, c); |
11903 | break; |
11904 | case ',': |
11905 | if (start != pos && openings.empty()) { |
11906 | m_messages.emplace_back(macroName, lineInfo, resultType); |
11907 | m_messages.back().message = static_cast<std::string>(trimmed(start, pos)); |
11908 | m_messages.back().message += " := " ; |
11909 | start = pos; |
11910 | } |
11911 | } |
11912 | } |
11913 | assert(openings.empty() && "Mismatched openings" ); |
11914 | m_messages.emplace_back(macroName, lineInfo, resultType); |
11915 | m_messages.back().message = static_cast<std::string>(trimmed(start, names.size() - 1)); |
11916 | m_messages.back().message += " := " ; |
11917 | } |
11918 | Capturer::~Capturer() { |
11919 | if ( !uncaught_exceptions() ){ |
11920 | assert( m_captured == m_messages.size() ); |
11921 | for( size_t i = 0; i < m_captured; ++i ) |
11922 | m_resultCapture.popScopedMessage( m_messages[i] ); |
11923 | } |
11924 | } |
11925 | |
11926 | void Capturer::captureValue( size_t index, std::string const& value ) { |
11927 | assert( index < m_messages.size() ); |
11928 | m_messages[index].message += value; |
11929 | m_resultCapture.pushScopedMessage( m_messages[index] ); |
11930 | m_captured++; |
11931 | } |
11932 | |
11933 | } // end namespace Catch |
11934 | // end catch_message.cpp |
11935 | // start catch_output_redirect.cpp |
11936 | |
11937 | // start catch_output_redirect.h |
11938 | #ifndef TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H |
11939 | #define TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H |
11940 | |
11941 | #include <cstdio> |
11942 | #include <iosfwd> |
11943 | #include <string> |
11944 | |
11945 | namespace Catch { |
11946 | |
11947 | class RedirectedStream { |
11948 | std::ostream& m_originalStream; |
11949 | std::ostream& m_redirectionStream; |
11950 | std::streambuf* m_prevBuf; |
11951 | |
11952 | public: |
11953 | RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream ); |
11954 | ~RedirectedStream(); |
11955 | }; |
11956 | |
11957 | class RedirectedStdOut { |
11958 | ReusableStringStream ; |
11959 | RedirectedStream m_cout; |
11960 | public: |
11961 | RedirectedStdOut(); |
11962 | auto str() const -> std::string; |
11963 | }; |
11964 | |
11965 | // StdErr has two constituent streams in C++, std::cerr and std::clog |
11966 | // This means that we need to redirect 2 streams into 1 to keep proper |
11967 | // order of writes |
11968 | class RedirectedStdErr { |
11969 | ReusableStringStream ; |
11970 | RedirectedStream m_cerr; |
11971 | RedirectedStream m_clog; |
11972 | public: |
11973 | RedirectedStdErr(); |
11974 | auto str() const -> std::string; |
11975 | }; |
11976 | |
11977 | class RedirectedStreams { |
11978 | public: |
11979 | RedirectedStreams(RedirectedStreams const&) = delete; |
11980 | RedirectedStreams& operator=(RedirectedStreams const&) = delete; |
11981 | RedirectedStreams(RedirectedStreams&&) = delete; |
11982 | RedirectedStreams& operator=(RedirectedStreams&&) = delete; |
11983 | |
11984 | RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr); |
11985 | ~RedirectedStreams(); |
11986 | private: |
11987 | std::string& m_redirectedCout; |
11988 | std::string& m_redirectedCerr; |
11989 | RedirectedStdOut m_redirectedStdOut; |
11990 | RedirectedStdErr m_redirectedStdErr; |
11991 | }; |
11992 | |
11993 | #if defined(CATCH_CONFIG_NEW_CAPTURE) |
11994 | |
11995 | // Windows's implementation of std::tmpfile is terrible (it tries |
11996 | // to create a file inside system folder, thus requiring elevated |
11997 | // privileges for the binary), so we have to use tmpnam(_s) and |
11998 | // create the file ourselves there. |
11999 | class TempFile { |
12000 | public: |
12001 | TempFile(TempFile const&) = delete; |
12002 | TempFile& operator=(TempFile const&) = delete; |
12003 | TempFile(TempFile&&) = delete; |
12004 | TempFile& operator=(TempFile&&) = delete; |
12005 | |
12006 | TempFile(); |
12007 | ~TempFile(); |
12008 | |
12009 | std::FILE* getFile(); |
12010 | std::string getContents(); |
12011 | |
12012 | private: |
12013 | std::FILE* m_file = nullptr; |
12014 | #if defined(_MSC_VER) |
12015 | char m_buffer[L_tmpnam] = { 0 }; |
12016 | #endif |
12017 | }; |
12018 | |
12019 | class OutputRedirect { |
12020 | public: |
12021 | OutputRedirect(OutputRedirect const&) = delete; |
12022 | OutputRedirect& operator=(OutputRedirect const&) = delete; |
12023 | OutputRedirect(OutputRedirect&&) = delete; |
12024 | OutputRedirect& operator=(OutputRedirect&&) = delete; |
12025 | |
12026 | OutputRedirect(std::string& stdout_dest, std::string& stderr_dest); |
12027 | ~OutputRedirect(); |
12028 | |
12029 | private: |
12030 | int m_originalStdout = -1; |
12031 | int m_originalStderr = -1; |
12032 | TempFile m_stdoutFile; |
12033 | TempFile m_stderrFile; |
12034 | std::string& m_stdoutDest; |
12035 | std::string& m_stderrDest; |
12036 | }; |
12037 | |
12038 | #endif |
12039 | |
12040 | } // end namespace Catch |
12041 | |
12042 | #endif // TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H |
12043 | // end catch_output_redirect.h |
12044 | #include <cstdio> |
12045 | #include <cstring> |
12046 | #include <fstream> |
12047 | #include <sstream> |
12048 | #include <stdexcept> |
12049 | |
12050 | #if defined(CATCH_CONFIG_NEW_CAPTURE) |
12051 | #if defined(_MSC_VER) |
12052 | #include <io.h> //_dup and _dup2 |
12053 | #define dup _dup |
12054 | #define dup2 _dup2 |
12055 | #define fileno _fileno |
12056 | #else |
12057 | #include <unistd.h> // dup and dup2 |
12058 | #endif |
12059 | #endif |
12060 | |
12061 | namespace Catch { |
12062 | |
12063 | RedirectedStream::RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream ) |
12064 | : m_originalStream( originalStream ), |
12065 | m_redirectionStream( redirectionStream ), |
12066 | m_prevBuf( m_originalStream.rdbuf() ) |
12067 | { |
12068 | m_originalStream.rdbuf( m_redirectionStream.rdbuf() ); |
12069 | } |
12070 | |
12071 | RedirectedStream::~RedirectedStream() { |
12072 | m_originalStream.rdbuf( m_prevBuf ); |
12073 | } |
12074 | |
12075 | RedirectedStdOut::RedirectedStdOut() : m_cout( Catch::cout(), m_rss.get() ) {} |
12076 | auto RedirectedStdOut::str() const -> std::string { return m_rss.str(); } |
12077 | |
12078 | RedirectedStdErr::RedirectedStdErr() |
12079 | : m_cerr( Catch::cerr(), m_rss.get() ), |
12080 | m_clog( Catch::clog(), m_rss.get() ) |
12081 | {} |
12082 | auto RedirectedStdErr::str() const -> std::string { return m_rss.str(); } |
12083 | |
12084 | RedirectedStreams::RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr) |
12085 | : m_redirectedCout(redirectedCout), |
12086 | m_redirectedCerr(redirectedCerr) |
12087 | {} |
12088 | |
12089 | RedirectedStreams::~RedirectedStreams() { |
12090 | m_redirectedCout += m_redirectedStdOut.str(); |
12091 | m_redirectedCerr += m_redirectedStdErr.str(); |
12092 | } |
12093 | |
12094 | #if defined(CATCH_CONFIG_NEW_CAPTURE) |
12095 | |
12096 | #if defined(_MSC_VER) |
12097 | TempFile::TempFile() { |
12098 | if (tmpnam_s(m_buffer)) { |
12099 | CATCH_RUNTIME_ERROR("Could not get a temp filename" ); |
12100 | } |
12101 | if (fopen_s(&m_file, m_buffer, "w+" )) { |
12102 | char buffer[100]; |
12103 | if (strerror_s(buffer, errno)) { |
12104 | CATCH_RUNTIME_ERROR("Could not translate errno to a string" ); |
12105 | } |
12106 | CATCH_RUNTIME_ERROR("Could not open the temp file: '" << m_buffer << "' because: " << buffer); |
12107 | } |
12108 | } |
12109 | #else |
12110 | TempFile::TempFile() { |
12111 | m_file = std::tmpfile(); |
12112 | if (!m_file) { |
12113 | CATCH_RUNTIME_ERROR("Could not create a temp file." ); |
12114 | } |
12115 | } |
12116 | |
12117 | #endif |
12118 | |
12119 | TempFile::~TempFile() { |
12120 | // TBD: What to do about errors here? |
12121 | std::fclose(m_file); |
12122 | // We manually create the file on Windows only, on Linux |
12123 | // it will be autodeleted |
12124 | #if defined(_MSC_VER) |
12125 | std::remove(m_buffer); |
12126 | #endif |
12127 | } |
12128 | |
12129 | FILE* TempFile::getFile() { |
12130 | return m_file; |
12131 | } |
12132 | |
12133 | std::string TempFile::getContents() { |
12134 | std::stringstream sstr; |
12135 | char buffer[100] = {}; |
12136 | std::rewind(m_file); |
12137 | while (std::fgets(buffer, sizeof(buffer), m_file)) { |
12138 | sstr << buffer; |
12139 | } |
12140 | return sstr.str(); |
12141 | } |
12142 | |
12143 | OutputRedirect::OutputRedirect(std::string& stdout_dest, std::string& stderr_dest) : |
12144 | m_originalStdout(dup(1)), |
12145 | m_originalStderr(dup(2)), |
12146 | m_stdoutDest(stdout_dest), |
12147 | m_stderrDest(stderr_dest) { |
12148 | dup2(fileno(m_stdoutFile.getFile()), 1); |
12149 | dup2(fileno(m_stderrFile.getFile()), 2); |
12150 | } |
12151 | |
12152 | OutputRedirect::~OutputRedirect() { |
12153 | Catch::cout() << std::flush; |
12154 | fflush(stdout); |
12155 | // Since we support overriding these streams, we flush cerr |
12156 | // even though std::cerr is unbuffered |
12157 | Catch::cerr() << std::flush; |
12158 | Catch::clog() << std::flush; |
12159 | fflush(stderr); |
12160 | |
12161 | dup2(m_originalStdout, 1); |
12162 | dup2(m_originalStderr, 2); |
12163 | |
12164 | m_stdoutDest += m_stdoutFile.getContents(); |
12165 | m_stderrDest += m_stderrFile.getContents(); |
12166 | } |
12167 | |
12168 | #endif // CATCH_CONFIG_NEW_CAPTURE |
12169 | |
12170 | } // namespace Catch |
12171 | |
12172 | #if defined(CATCH_CONFIG_NEW_CAPTURE) |
12173 | #if defined(_MSC_VER) |
12174 | #undef dup |
12175 | #undef dup2 |
12176 | #undef fileno |
12177 | #endif |
12178 | #endif |
12179 | // end catch_output_redirect.cpp |
12180 | // start catch_polyfills.cpp |
12181 | |
12182 | #include <cmath> |
12183 | |
12184 | namespace Catch { |
12185 | |
12186 | #if !defined(CATCH_CONFIG_POLYFILL_ISNAN) |
12187 | bool isnan(float f) { |
12188 | return std::isnan(f); |
12189 | } |
12190 | bool isnan(double d) { |
12191 | return std::isnan(d); |
12192 | } |
12193 | #else |
12194 | // For now we only use this for embarcadero |
12195 | bool isnan(float f) { |
12196 | return std::_isnan(f); |
12197 | } |
12198 | bool isnan(double d) { |
12199 | return std::_isnan(d); |
12200 | } |
12201 | #endif |
12202 | |
12203 | } // end namespace Catch |
12204 | // end catch_polyfills.cpp |
12205 | // start catch_random_number_generator.cpp |
12206 | |
12207 | namespace Catch { |
12208 | |
12209 | namespace { |
12210 | |
12211 | #if defined(_MSC_VER) |
12212 | #pragma warning(push) |
12213 | #pragma warning(disable:4146) // we negate uint32 during the rotate |
12214 | #endif |
12215 | // Safe rotr implementation thanks to John Regehr |
12216 | uint32_t rotate_right(uint32_t val, uint32_t count) { |
12217 | const uint32_t mask = 31; |
12218 | count &= mask; |
12219 | return (val >> count) | (val << (-count & mask)); |
12220 | } |
12221 | |
12222 | #if defined(_MSC_VER) |
12223 | #pragma warning(pop) |
12224 | #endif |
12225 | |
12226 | } |
12227 | |
12228 | SimplePcg32::SimplePcg32(result_type seed_) { |
12229 | seed(seed_); |
12230 | } |
12231 | |
12232 | void SimplePcg32::seed(result_type seed_) { |
12233 | m_state = 0; |
12234 | (*this)(); |
12235 | m_state += seed_; |
12236 | (*this)(); |
12237 | } |
12238 | |
12239 | void SimplePcg32::discard(uint64_t skip) { |
12240 | // We could implement this to run in O(log n) steps, but this |
12241 | // should suffice for our use case. |
12242 | for (uint64_t s = 0; s < skip; ++s) { |
12243 | static_cast<void>((*this)()); |
12244 | } |
12245 | } |
12246 | |
12247 | SimplePcg32::result_type SimplePcg32::operator()() { |
12248 | // prepare the output value |
12249 | const uint32_t xorshifted = static_cast<uint32_t>(((m_state >> 18u) ^ m_state) >> 27u); |
12250 | const auto output = rotate_right(xorshifted, m_state >> 59u); |
12251 | |
12252 | // advance state |
12253 | m_state = m_state * 6364136223846793005ULL + s_inc; |
12254 | |
12255 | return output; |
12256 | } |
12257 | |
12258 | bool operator==(SimplePcg32 const& lhs, SimplePcg32 const& rhs) { |
12259 | return lhs.m_state == rhs.m_state; |
12260 | } |
12261 | |
12262 | bool operator!=(SimplePcg32 const& lhs, SimplePcg32 const& rhs) { |
12263 | return lhs.m_state != rhs.m_state; |
12264 | } |
12265 | } |
12266 | // end catch_random_number_generator.cpp |
12267 | // start catch_registry_hub.cpp |
12268 | |
12269 | // start catch_test_case_registry_impl.h |
12270 | |
12271 | #include <vector> |
12272 | #include <set> |
12273 | #include <algorithm> |
12274 | #include <ios> |
12275 | |
12276 | namespace Catch { |
12277 | |
12278 | class TestCase; |
12279 | struct IConfig; |
12280 | |
12281 | std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ); |
12282 | |
12283 | bool isThrowSafe( TestCase const& testCase, IConfig const& config ); |
12284 | bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); |
12285 | |
12286 | void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions ); |
12287 | |
12288 | std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ); |
12289 | std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ); |
12290 | |
12291 | class TestRegistry : public ITestCaseRegistry { |
12292 | public: |
12293 | virtual ~TestRegistry() = default; |
12294 | |
12295 | virtual void registerTest( TestCase const& testCase ); |
12296 | |
12297 | std::vector<TestCase> const& getAllTests() const override; |
12298 | std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const override; |
12299 | |
12300 | private: |
12301 | std::vector<TestCase> m_functions; |
12302 | mutable RunTests::InWhatOrder m_currentSortOrder = RunTests::InDeclarationOrder; |
12303 | mutable std::vector<TestCase> m_sortedFunctions; |
12304 | std::size_t m_unnamedCount = 0; |
12305 | std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised |
12306 | }; |
12307 | |
12308 | /////////////////////////////////////////////////////////////////////////// |
12309 | |
12310 | class TestInvokerAsFunction : public ITestInvoker { |
12311 | void(*m_testAsFunction)(); |
12312 | public: |
12313 | TestInvokerAsFunction( void(*testAsFunction)() ) noexcept; |
12314 | |
12315 | void invoke() const override; |
12316 | }; |
12317 | |
12318 | std::string ( StringRef const& classOrQualifiedMethodName ); |
12319 | |
12320 | /////////////////////////////////////////////////////////////////////////// |
12321 | |
12322 | } // end namespace Catch |
12323 | |
12324 | // end catch_test_case_registry_impl.h |
12325 | // start catch_reporter_registry.h |
12326 | |
12327 | #include <map> |
12328 | |
12329 | namespace Catch { |
12330 | |
12331 | class ReporterRegistry : public IReporterRegistry { |
12332 | |
12333 | public: |
12334 | |
12335 | ~ReporterRegistry() override; |
12336 | |
12337 | IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const override; |
12338 | |
12339 | void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ); |
12340 | void registerListener( IReporterFactoryPtr const& factory ); |
12341 | |
12342 | FactoryMap const& getFactories() const override; |
12343 | Listeners const& getListeners() const override; |
12344 | |
12345 | private: |
12346 | FactoryMap m_factories; |
12347 | Listeners m_listeners; |
12348 | }; |
12349 | } |
12350 | |
12351 | // end catch_reporter_registry.h |
12352 | // start catch_tag_alias_registry.h |
12353 | |
12354 | // start catch_tag_alias.h |
12355 | |
12356 | #include <string> |
12357 | |
12358 | namespace Catch { |
12359 | |
12360 | struct TagAlias { |
12361 | TagAlias(std::string const& _tag, SourceLineInfo _lineInfo); |
12362 | |
12363 | std::string tag; |
12364 | SourceLineInfo lineInfo; |
12365 | }; |
12366 | |
12367 | } // end namespace Catch |
12368 | |
12369 | // end catch_tag_alias.h |
12370 | #include <map> |
12371 | |
12372 | namespace Catch { |
12373 | |
12374 | class TagAliasRegistry : public ITagAliasRegistry { |
12375 | public: |
12376 | ~TagAliasRegistry() override; |
12377 | TagAlias const* find( std::string const& alias ) const override; |
12378 | std::string expandAliases( std::string const& unexpandedTestSpec ) const override; |
12379 | void add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ); |
12380 | |
12381 | private: |
12382 | std::map<std::string, TagAlias> m_registry; |
12383 | }; |
12384 | |
12385 | } // end namespace Catch |
12386 | |
12387 | // end catch_tag_alias_registry.h |
12388 | // start catch_startup_exception_registry.h |
12389 | |
12390 | #include <vector> |
12391 | #include <exception> |
12392 | |
12393 | namespace Catch { |
12394 | |
12395 | class StartupExceptionRegistry { |
12396 | #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) |
12397 | public: |
12398 | void add(std::exception_ptr const& exception) noexcept; |
12399 | std::vector<std::exception_ptr> const& getExceptions() const noexcept; |
12400 | private: |
12401 | std::vector<std::exception_ptr> m_exceptions; |
12402 | #endif |
12403 | }; |
12404 | |
12405 | } // end namespace Catch |
12406 | |
12407 | // end catch_startup_exception_registry.h |
12408 | // start catch_singletons.hpp |
12409 | |
12410 | namespace Catch { |
12411 | |
12412 | struct ISingleton { |
12413 | virtual ~ISingleton(); |
12414 | }; |
12415 | |
12416 | void addSingleton( ISingleton* singleton ); |
12417 | void cleanupSingletons(); |
12418 | |
12419 | template<typename SingletonImplT, typename InterfaceT = SingletonImplT, typename MutableInterfaceT = InterfaceT> |
12420 | class Singleton : SingletonImplT, public ISingleton { |
12421 | |
12422 | static auto getInternal() -> Singleton* { |
12423 | static Singleton* s_instance = nullptr; |
12424 | if( !s_instance ) { |
12425 | s_instance = new Singleton; |
12426 | addSingleton( s_instance ); |
12427 | } |
12428 | return s_instance; |
12429 | } |
12430 | |
12431 | public: |
12432 | static auto get() -> InterfaceT const& { |
12433 | return *getInternal(); |
12434 | } |
12435 | static auto getMutable() -> MutableInterfaceT& { |
12436 | return *getInternal(); |
12437 | } |
12438 | }; |
12439 | |
12440 | } // namespace Catch |
12441 | |
12442 | // end catch_singletons.hpp |
12443 | namespace Catch { |
12444 | |
12445 | namespace { |
12446 | |
12447 | class RegistryHub : public IRegistryHub, public IMutableRegistryHub, |
12448 | private NonCopyable { |
12449 | |
12450 | public: // IRegistryHub |
12451 | RegistryHub() = default; |
12452 | IReporterRegistry const& getReporterRegistry() const override { |
12453 | return m_reporterRegistry; |
12454 | } |
12455 | ITestCaseRegistry const& getTestCaseRegistry() const override { |
12456 | return m_testCaseRegistry; |
12457 | } |
12458 | IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const override { |
12459 | return m_exceptionTranslatorRegistry; |
12460 | } |
12461 | ITagAliasRegistry const& getTagAliasRegistry() const override { |
12462 | return m_tagAliasRegistry; |
12463 | } |
12464 | StartupExceptionRegistry const& getStartupExceptionRegistry() const override { |
12465 | return m_exceptionRegistry; |
12466 | } |
12467 | |
12468 | public: // IMutableRegistryHub |
12469 | void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) override { |
12470 | m_reporterRegistry.registerReporter( name, factory ); |
12471 | } |
12472 | void registerListener( IReporterFactoryPtr const& factory ) override { |
12473 | m_reporterRegistry.registerListener( factory ); |
12474 | } |
12475 | void registerTest( TestCase const& testInfo ) override { |
12476 | m_testCaseRegistry.registerTest( testInfo ); |
12477 | } |
12478 | void registerTranslator( const IExceptionTranslator* translator ) override { |
12479 | m_exceptionTranslatorRegistry.registerTranslator( translator ); |
12480 | } |
12481 | void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) override { |
12482 | m_tagAliasRegistry.add( alias, tag, lineInfo ); |
12483 | } |
12484 | void registerStartupException() noexcept override { |
12485 | #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) |
12486 | m_exceptionRegistry.add(std::current_exception()); |
12487 | #else |
12488 | CATCH_INTERNAL_ERROR("Attempted to register active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!" ); |
12489 | #endif |
12490 | } |
12491 | IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() override { |
12492 | return m_enumValuesRegistry; |
12493 | } |
12494 | |
12495 | private: |
12496 | TestRegistry m_testCaseRegistry; |
12497 | ReporterRegistry m_reporterRegistry; |
12498 | ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; |
12499 | TagAliasRegistry m_tagAliasRegistry; |
12500 | StartupExceptionRegistry m_exceptionRegistry; |
12501 | Detail::EnumValuesRegistry m_enumValuesRegistry; |
12502 | }; |
12503 | } |
12504 | |
12505 | using RegistryHubSingleton = Singleton<RegistryHub, IRegistryHub, IMutableRegistryHub>; |
12506 | |
12507 | IRegistryHub const& getRegistryHub() { |
12508 | return RegistryHubSingleton::get(); |
12509 | } |
12510 | IMutableRegistryHub& getMutableRegistryHub() { |
12511 | return RegistryHubSingleton::getMutable(); |
12512 | } |
12513 | void cleanUp() { |
12514 | cleanupSingletons(); |
12515 | cleanUpContext(); |
12516 | } |
12517 | std::string translateActiveException() { |
12518 | return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); |
12519 | } |
12520 | |
12521 | } // end namespace Catch |
12522 | // end catch_registry_hub.cpp |
12523 | // start catch_reporter_registry.cpp |
12524 | |
12525 | namespace Catch { |
12526 | |
12527 | ReporterRegistry::~ReporterRegistry() = default; |
12528 | |
12529 | IStreamingReporterPtr ReporterRegistry::create( std::string const& name, IConfigPtr const& config ) const { |
12530 | auto it = m_factories.find( name ); |
12531 | if( it == m_factories.end() ) |
12532 | return nullptr; |
12533 | return it->second->create( ReporterConfig( config ) ); |
12534 | } |
12535 | |
12536 | void ReporterRegistry::registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) { |
12537 | m_factories.emplace(name, factory); |
12538 | } |
12539 | void ReporterRegistry::registerListener( IReporterFactoryPtr const& factory ) { |
12540 | m_listeners.push_back( factory ); |
12541 | } |
12542 | |
12543 | IReporterRegistry::FactoryMap const& ReporterRegistry::getFactories() const { |
12544 | return m_factories; |
12545 | } |
12546 | IReporterRegistry::Listeners const& ReporterRegistry::getListeners() const { |
12547 | return m_listeners; |
12548 | } |
12549 | |
12550 | } |
12551 | // end catch_reporter_registry.cpp |
12552 | // start catch_result_type.cpp |
12553 | |
12554 | namespace Catch { |
12555 | |
12556 | bool isOk( ResultWas::OfType resultType ) { |
12557 | return ( resultType & ResultWas::FailureBit ) == 0; |
12558 | } |
12559 | bool isJustInfo( int flags ) { |
12560 | return flags == ResultWas::Info; |
12561 | } |
12562 | |
12563 | ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { |
12564 | return static_cast<ResultDisposition::Flags>( static_cast<int>( lhs ) | static_cast<int>( rhs ) ); |
12565 | } |
12566 | |
12567 | bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } |
12568 | bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } |
12569 | |
12570 | } // end namespace Catch |
12571 | // end catch_result_type.cpp |
12572 | // start catch_run_context.cpp |
12573 | |
12574 | #include <cassert> |
12575 | #include <algorithm> |
12576 | #include <sstream> |
12577 | |
12578 | namespace Catch { |
12579 | |
12580 | namespace Generators { |
12581 | struct GeneratorTracker : TestCaseTracking::TrackerBase, IGeneratorTracker { |
12582 | GeneratorBasePtr m_generator; |
12583 | |
12584 | GeneratorTracker( TestCaseTracking::NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) |
12585 | : TrackerBase( nameAndLocation, ctx, parent ) |
12586 | {} |
12587 | ~GeneratorTracker(); |
12588 | |
12589 | static GeneratorTracker& acquire( TrackerContext& ctx, TestCaseTracking::NameAndLocation const& nameAndLocation ) { |
12590 | std::shared_ptr<GeneratorTracker> tracker; |
12591 | |
12592 | ITracker& currentTracker = ctx.currentTracker(); |
12593 | // Under specific circumstances, the generator we want |
12594 | // to acquire is also the current tracker. If this is |
12595 | // the case, we have to avoid looking through current |
12596 | // tracker's children, and instead return the current |
12597 | // tracker. |
12598 | // A case where this check is important is e.g. |
12599 | // for (int i = 0; i < 5; ++i) { |
12600 | // int n = GENERATE(1, 2); |
12601 | // } |
12602 | // |
12603 | // without it, the code above creates 5 nested generators. |
12604 | if (currentTracker.nameAndLocation() == nameAndLocation) { |
12605 | auto thisTracker = currentTracker.parent().findChild(nameAndLocation); |
12606 | assert(thisTracker); |
12607 | assert(thisTracker->isGeneratorTracker()); |
12608 | tracker = std::static_pointer_cast<GeneratorTracker>(thisTracker); |
12609 | } else if ( TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { |
12610 | assert( childTracker ); |
12611 | assert( childTracker->isGeneratorTracker() ); |
12612 | tracker = std::static_pointer_cast<GeneratorTracker>( childTracker ); |
12613 | } else { |
12614 | tracker = std::make_shared<GeneratorTracker>( nameAndLocation, ctx, ¤tTracker ); |
12615 | currentTracker.addChild( tracker ); |
12616 | } |
12617 | |
12618 | if( !tracker->isComplete() ) { |
12619 | tracker->open(); |
12620 | } |
12621 | |
12622 | return *tracker; |
12623 | } |
12624 | |
12625 | // TrackerBase interface |
12626 | bool isGeneratorTracker() const override { return true; } |
12627 | auto hasGenerator() const -> bool override { |
12628 | return !!m_generator; |
12629 | } |
12630 | void close() override { |
12631 | TrackerBase::close(); |
12632 | // If a generator has a child (it is followed by a section) |
12633 | // and none of its children have started, then we must wait |
12634 | // until later to start consuming its values. |
12635 | // This catches cases where `GENERATE` is placed between two |
12636 | // `SECTION`s. |
12637 | // **The check for m_children.empty cannot be removed**. |
12638 | // doing so would break `GENERATE` _not_ followed by `SECTION`s. |
12639 | const bool should_wait_for_child = [&]() { |
12640 | // No children -> nobody to wait for |
12641 | if ( m_children.empty() ) { |
12642 | return false; |
12643 | } |
12644 | // If at least one child started executing, don't wait |
12645 | if ( std::find_if( |
12646 | m_children.begin(), |
12647 | m_children.end(), |
12648 | []( TestCaseTracking::ITrackerPtr tracker ) { |
12649 | return tracker->hasStarted(); |
12650 | } ) != m_children.end() ) { |
12651 | return false; |
12652 | } |
12653 | |
12654 | // No children have started. We need to check if they _can_ |
12655 | // start, and thus we should wait for them, or they cannot |
12656 | // start (due to filters), and we shouldn't wait for them |
12657 | auto* parent = m_parent; |
12658 | // This is safe: there is always at least one section |
12659 | // tracker in a test case tracking tree |
12660 | while ( !parent->isSectionTracker() ) { |
12661 | parent = &( parent->parent() ); |
12662 | } |
12663 | assert( parent && |
12664 | "Missing root (test case) level section" ); |
12665 | |
12666 | auto const& parentSection = |
12667 | static_cast<SectionTracker&>( *parent ); |
12668 | auto const& filters = parentSection.getFilters(); |
12669 | // No filters -> no restrictions on running sections |
12670 | if ( filters.empty() ) { |
12671 | return true; |
12672 | } |
12673 | |
12674 | for ( auto const& child : m_children ) { |
12675 | if ( child->isSectionTracker() && |
12676 | std::find( filters.begin(), |
12677 | filters.end(), |
12678 | static_cast<SectionTracker&>( *child ) |
12679 | .trimmedName() ) != |
12680 | filters.end() ) { |
12681 | return true; |
12682 | } |
12683 | } |
12684 | return false; |
12685 | }(); |
12686 | |
12687 | // This check is a bit tricky, because m_generator->next() |
12688 | // has a side-effect, where it consumes generator's current |
12689 | // value, but we do not want to invoke the side-effect if |
12690 | // this generator is still waiting for any child to start. |
12691 | if ( should_wait_for_child || |
12692 | ( m_runState == CompletedSuccessfully && |
12693 | m_generator->next() ) ) { |
12694 | m_children.clear(); |
12695 | m_runState = Executing; |
12696 | } |
12697 | } |
12698 | |
12699 | // IGeneratorTracker interface |
12700 | auto getGenerator() const -> GeneratorBasePtr const& override { |
12701 | return m_generator; |
12702 | } |
12703 | void setGenerator( GeneratorBasePtr&& generator ) override { |
12704 | m_generator = std::move( generator ); |
12705 | } |
12706 | }; |
12707 | GeneratorTracker::~GeneratorTracker() {} |
12708 | } |
12709 | |
12710 | RunContext::RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter) |
12711 | : m_runInfo(_config->name()), |
12712 | m_context(getCurrentMutableContext()), |
12713 | m_config(_config), |
12714 | m_reporter(std::move(reporter)), |
12715 | m_lastAssertionInfo{ StringRef(), SourceLineInfo("" ,0), StringRef(), ResultDisposition::Normal }, |
12716 | m_includeSuccessfulResults( m_config->includeSuccessfulResults() || m_reporter->getPreferences().shouldReportAllAssertions ) |
12717 | { |
12718 | m_context.setRunner(this); |
12719 | m_context.setConfig(m_config); |
12720 | m_context.setResultCapture(this); |
12721 | m_reporter->testRunStarting(m_runInfo); |
12722 | } |
12723 | |
12724 | RunContext::~RunContext() { |
12725 | m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, aborting())); |
12726 | } |
12727 | |
12728 | void RunContext::testGroupStarting(std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount) { |
12729 | m_reporter->testGroupStarting(GroupInfo(testSpec, groupIndex, groupsCount)); |
12730 | } |
12731 | |
12732 | void RunContext::testGroupEnded(std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount) { |
12733 | m_reporter->testGroupEnded(TestGroupStats(GroupInfo(testSpec, groupIndex, groupsCount), totals, aborting())); |
12734 | } |
12735 | |
12736 | Totals RunContext::runTest(TestCase const& testCase) { |
12737 | Totals prevTotals = m_totals; |
12738 | |
12739 | std::string redirectedCout; |
12740 | std::string redirectedCerr; |
12741 | |
12742 | auto const& testInfo = testCase.getTestCaseInfo(); |
12743 | |
12744 | m_reporter->testCaseStarting(testInfo); |
12745 | |
12746 | m_activeTestCase = &testCase; |
12747 | |
12748 | ITracker& rootTracker = m_trackerContext.startRun(); |
12749 | assert(rootTracker.isSectionTracker()); |
12750 | static_cast<SectionTracker&>(rootTracker).addInitialFilters(m_config->getSectionsToRun()); |
12751 | do { |
12752 | m_trackerContext.startCycle(); |
12753 | m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(testInfo.name, testInfo.lineInfo)); |
12754 | runCurrentTest(redirectedCout, redirectedCerr); |
12755 | } while (!m_testCaseTracker->isSuccessfullyCompleted() && !aborting()); |
12756 | |
12757 | Totals deltaTotals = m_totals.delta(prevTotals); |
12758 | if (testInfo.expectedToFail() && deltaTotals.testCases.passed > 0) { |
12759 | deltaTotals.assertions.failed++; |
12760 | deltaTotals.testCases.passed--; |
12761 | deltaTotals.testCases.failed++; |
12762 | } |
12763 | m_totals.testCases += deltaTotals.testCases; |
12764 | m_reporter->testCaseEnded(TestCaseStats(testInfo, |
12765 | deltaTotals, |
12766 | redirectedCout, |
12767 | redirectedCerr, |
12768 | aborting())); |
12769 | |
12770 | m_activeTestCase = nullptr; |
12771 | m_testCaseTracker = nullptr; |
12772 | |
12773 | return deltaTotals; |
12774 | } |
12775 | |
12776 | IConfigPtr RunContext::config() const { |
12777 | return m_config; |
12778 | } |
12779 | |
12780 | IStreamingReporter& RunContext::reporter() const { |
12781 | return *m_reporter; |
12782 | } |
12783 | |
12784 | void RunContext::assertionEnded(AssertionResult const & result) { |
12785 | if (result.getResultType() == ResultWas::Ok) { |
12786 | m_totals.assertions.passed++; |
12787 | m_lastAssertionPassed = true; |
12788 | } else if (!result.isOk()) { |
12789 | m_lastAssertionPassed = false; |
12790 | if( m_activeTestCase->getTestCaseInfo().okToFail() ) |
12791 | m_totals.assertions.failedButOk++; |
12792 | else |
12793 | m_totals.assertions.failed++; |
12794 | } |
12795 | else { |
12796 | m_lastAssertionPassed = true; |
12797 | } |
12798 | |
12799 | // We have no use for the return value (whether messages should be cleared), because messages were made scoped |
12800 | // and should be let to clear themselves out. |
12801 | static_cast<void>(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals))); |
12802 | |
12803 | if (result.getResultType() != ResultWas::Warning) |
12804 | m_messageScopes.clear(); |
12805 | |
12806 | // Reset working state |
12807 | resetAssertionInfo(); |
12808 | m_lastResult = result; |
12809 | } |
12810 | void RunContext::resetAssertionInfo() { |
12811 | m_lastAssertionInfo.macroName = StringRef(); |
12812 | m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"_sr ; |
12813 | } |
12814 | |
12815 | bool RunContext::sectionStarted(SectionInfo const & sectionInfo, Counts & assertions) { |
12816 | ITracker& sectionTracker = SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(sectionInfo.name, sectionInfo.lineInfo)); |
12817 | if (!sectionTracker.isOpen()) |
12818 | return false; |
12819 | m_activeSections.push_back(§ionTracker); |
12820 | |
12821 | m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; |
12822 | |
12823 | m_reporter->sectionStarting(sectionInfo); |
12824 | |
12825 | assertions = m_totals.assertions; |
12826 | |
12827 | return true; |
12828 | } |
12829 | auto RunContext::acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { |
12830 | using namespace Generators; |
12831 | GeneratorTracker& tracker = GeneratorTracker::acquire(m_trackerContext, |
12832 | TestCaseTracking::NameAndLocation( static_cast<std::string>(generatorName), lineInfo ) ); |
12833 | m_lastAssertionInfo.lineInfo = lineInfo; |
12834 | return tracker; |
12835 | } |
12836 | |
12837 | bool RunContext::testForMissingAssertions(Counts& assertions) { |
12838 | if (assertions.total() != 0) |
12839 | return false; |
12840 | if (!m_config->warnAboutMissingAssertions()) |
12841 | return false; |
12842 | if (m_trackerContext.currentTracker().hasChildren()) |
12843 | return false; |
12844 | m_totals.assertions.failed++; |
12845 | assertions.failed++; |
12846 | return true; |
12847 | } |
12848 | |
12849 | void RunContext::sectionEnded(SectionEndInfo const & endInfo) { |
12850 | Counts assertions = m_totals.assertions - endInfo.prevAssertions; |
12851 | bool missingAssertions = testForMissingAssertions(assertions); |
12852 | |
12853 | if (!m_activeSections.empty()) { |
12854 | m_activeSections.back()->close(); |
12855 | m_activeSections.pop_back(); |
12856 | } |
12857 | |
12858 | m_reporter->sectionEnded(SectionStats(endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions)); |
12859 | m_messages.clear(); |
12860 | m_messageScopes.clear(); |
12861 | } |
12862 | |
12863 | void RunContext::sectionEndedEarly(SectionEndInfo const & endInfo) { |
12864 | if (m_unfinishedSections.empty()) |
12865 | m_activeSections.back()->fail(); |
12866 | else |
12867 | m_activeSections.back()->close(); |
12868 | m_activeSections.pop_back(); |
12869 | |
12870 | m_unfinishedSections.push_back(endInfo); |
12871 | } |
12872 | |
12873 | #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) |
12874 | void RunContext::benchmarkPreparing(std::string const& name) { |
12875 | m_reporter->benchmarkPreparing(name); |
12876 | } |
12877 | void RunContext::benchmarkStarting( BenchmarkInfo const& info ) { |
12878 | m_reporter->benchmarkStarting( info ); |
12879 | } |
12880 | void RunContext::benchmarkEnded( BenchmarkStats<> const& stats ) { |
12881 | m_reporter->benchmarkEnded( stats ); |
12882 | } |
12883 | void RunContext::benchmarkFailed(std::string const & error) { |
12884 | m_reporter->benchmarkFailed(error); |
12885 | } |
12886 | #endif // CATCH_CONFIG_ENABLE_BENCHMARKING |
12887 | |
12888 | void RunContext::pushScopedMessage(MessageInfo const & message) { |
12889 | m_messages.push_back(message); |
12890 | } |
12891 | |
12892 | void RunContext::popScopedMessage(MessageInfo const & message) { |
12893 | m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end()); |
12894 | } |
12895 | |
12896 | void RunContext::emplaceUnscopedMessage( MessageBuilder const& builder ) { |
12897 | m_messageScopes.emplace_back( builder ); |
12898 | } |
12899 | |
12900 | std::string RunContext::getCurrentTestName() const { |
12901 | return m_activeTestCase |
12902 | ? m_activeTestCase->getTestCaseInfo().name |
12903 | : std::string(); |
12904 | } |
12905 | |
12906 | const AssertionResult * RunContext::getLastResult() const { |
12907 | return &(*m_lastResult); |
12908 | } |
12909 | |
12910 | void RunContext::exceptionEarlyReported() { |
12911 | m_shouldReportUnexpected = false; |
12912 | } |
12913 | |
12914 | void RunContext::handleFatalErrorCondition( StringRef message ) { |
12915 | // First notify reporter that bad things happened |
12916 | m_reporter->fatalErrorEncountered(message); |
12917 | |
12918 | // Don't rebuild the result -- the stringification itself can cause more fatal errors |
12919 | // Instead, fake a result data. |
12920 | AssertionResultData tempResult( ResultWas::FatalErrorCondition, { false } ); |
12921 | tempResult.message = static_cast<std::string>(message); |
12922 | AssertionResult result(m_lastAssertionInfo, tempResult); |
12923 | |
12924 | assertionEnded(result); |
12925 | |
12926 | handleUnfinishedSections(); |
12927 | |
12928 | // Recreate section for test case (as we will lose the one that was in scope) |
12929 | auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); |
12930 | SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name); |
12931 | |
12932 | Counts assertions; |
12933 | assertions.failed = 1; |
12934 | SectionStats testCaseSectionStats(testCaseSection, assertions, 0, false); |
12935 | m_reporter->sectionEnded(testCaseSectionStats); |
12936 | |
12937 | auto const& testInfo = m_activeTestCase->getTestCaseInfo(); |
12938 | |
12939 | Totals deltaTotals; |
12940 | deltaTotals.testCases.failed = 1; |
12941 | deltaTotals.assertions.failed = 1; |
12942 | m_reporter->testCaseEnded(TestCaseStats(testInfo, |
12943 | deltaTotals, |
12944 | std::string(), |
12945 | std::string(), |
12946 | false)); |
12947 | m_totals.testCases.failed++; |
12948 | testGroupEnded(std::string(), m_totals, 1, 1); |
12949 | m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, false)); |
12950 | } |
12951 | |
12952 | bool RunContext::lastAssertionPassed() { |
12953 | return m_lastAssertionPassed; |
12954 | } |
12955 | |
12956 | void RunContext::assertionPassed() { |
12957 | m_lastAssertionPassed = true; |
12958 | ++m_totals.assertions.passed; |
12959 | resetAssertionInfo(); |
12960 | m_messageScopes.clear(); |
12961 | } |
12962 | |
12963 | bool RunContext::aborting() const { |
12964 | return m_totals.assertions.failed >= static_cast<std::size_t>(m_config->abortAfter()); |
12965 | } |
12966 | |
12967 | void RunContext::runCurrentTest(std::string & redirectedCout, std::string & redirectedCerr) { |
12968 | auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); |
12969 | SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name); |
12970 | m_reporter->sectionStarting(testCaseSection); |
12971 | Counts prevAssertions = m_totals.assertions; |
12972 | double duration = 0; |
12973 | m_shouldReportUnexpected = true; |
12974 | m_lastAssertionInfo = { "TEST_CASE"_sr , testCaseInfo.lineInfo, StringRef(), ResultDisposition::Normal }; |
12975 | |
12976 | seedRng(*m_config); |
12977 | |
12978 | Timer timer; |
12979 | CATCH_TRY { |
12980 | if (m_reporter->getPreferences().shouldRedirectStdOut) { |
12981 | #if !defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) |
12982 | RedirectedStreams redirectedStreams(redirectedCout, redirectedCerr); |
12983 | |
12984 | timer.start(); |
12985 | invokeActiveTestCase(); |
12986 | #else |
12987 | OutputRedirect r(redirectedCout, redirectedCerr); |
12988 | timer.start(); |
12989 | invokeActiveTestCase(); |
12990 | #endif |
12991 | } else { |
12992 | timer.start(); |
12993 | invokeActiveTestCase(); |
12994 | } |
12995 | duration = timer.getElapsedSeconds(); |
12996 | } CATCH_CATCH_ANON (TestFailureException&) { |
12997 | // This just means the test was aborted due to failure |
12998 | } CATCH_CATCH_ALL { |
12999 | // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions |
13000 | // are reported without translation at the point of origin. |
13001 | if( m_shouldReportUnexpected ) { |
13002 | AssertionReaction dummyReaction; |
13003 | handleUnexpectedInflightException( m_lastAssertionInfo, translateActiveException(), dummyReaction ); |
13004 | } |
13005 | } |
13006 | Counts assertions = m_totals.assertions - prevAssertions; |
13007 | bool missingAssertions = testForMissingAssertions(assertions); |
13008 | |
13009 | m_testCaseTracker->close(); |
13010 | handleUnfinishedSections(); |
13011 | m_messages.clear(); |
13012 | m_messageScopes.clear(); |
13013 | |
13014 | SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions); |
13015 | m_reporter->sectionEnded(testCaseSectionStats); |
13016 | } |
13017 | |
13018 | void RunContext::invokeActiveTestCase() { |
13019 | FatalConditionHandlerGuard _(&m_fatalConditionhandler); |
13020 | m_activeTestCase->invoke(); |
13021 | } |
13022 | |
13023 | void RunContext::handleUnfinishedSections() { |
13024 | // If sections ended prematurely due to an exception we stored their |
13025 | // infos here so we can tear them down outside the unwind process. |
13026 | for (auto it = m_unfinishedSections.rbegin(), |
13027 | itEnd = m_unfinishedSections.rend(); |
13028 | it != itEnd; |
13029 | ++it) |
13030 | sectionEnded(*it); |
13031 | m_unfinishedSections.clear(); |
13032 | } |
13033 | |
13034 | void RunContext::handleExpr( |
13035 | AssertionInfo const& info, |
13036 | ITransientExpression const& expr, |
13037 | AssertionReaction& reaction |
13038 | ) { |
13039 | m_reporter->assertionStarting( info ); |
13040 | |
13041 | bool negated = isFalseTest( info.resultDisposition ); |
13042 | bool result = expr.getResult() != negated; |
13043 | |
13044 | if( result ) { |
13045 | if (!m_includeSuccessfulResults) { |
13046 | assertionPassed(); |
13047 | } |
13048 | else { |
13049 | reportExpr(info, ResultWas::Ok, &expr, negated); |
13050 | } |
13051 | } |
13052 | else { |
13053 | reportExpr(info, ResultWas::ExpressionFailed, &expr, negated ); |
13054 | populateReaction( reaction ); |
13055 | } |
13056 | } |
13057 | void RunContext::reportExpr( |
13058 | AssertionInfo const &info, |
13059 | ResultWas::OfType resultType, |
13060 | ITransientExpression const *expr, |
13061 | bool negated ) { |
13062 | |
13063 | m_lastAssertionInfo = info; |
13064 | AssertionResultData data( resultType, LazyExpression( negated ) ); |
13065 | |
13066 | AssertionResult assertionResult{ info, data }; |
13067 | assertionResult.m_resultData.lazyExpression.m_transientExpression = expr; |
13068 | |
13069 | assertionEnded( assertionResult ); |
13070 | } |
13071 | |
13072 | void RunContext::handleMessage( |
13073 | AssertionInfo const& info, |
13074 | ResultWas::OfType resultType, |
13075 | StringRef const& message, |
13076 | AssertionReaction& reaction |
13077 | ) { |
13078 | m_reporter->assertionStarting( info ); |
13079 | |
13080 | m_lastAssertionInfo = info; |
13081 | |
13082 | AssertionResultData data( resultType, LazyExpression( false ) ); |
13083 | data.message = static_cast<std::string>(message); |
13084 | AssertionResult assertionResult{ m_lastAssertionInfo, data }; |
13085 | assertionEnded( assertionResult ); |
13086 | if( !assertionResult.isOk() ) |
13087 | populateReaction( reaction ); |
13088 | } |
13089 | void RunContext::handleUnexpectedExceptionNotThrown( |
13090 | AssertionInfo const& info, |
13091 | AssertionReaction& reaction |
13092 | ) { |
13093 | handleNonExpr(info, Catch::ResultWas::DidntThrowException, reaction); |
13094 | } |
13095 | |
13096 | void RunContext::handleUnexpectedInflightException( |
13097 | AssertionInfo const& info, |
13098 | std::string const& message, |
13099 | AssertionReaction& reaction |
13100 | ) { |
13101 | m_lastAssertionInfo = info; |
13102 | |
13103 | AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); |
13104 | data.message = message; |
13105 | AssertionResult assertionResult{ info, data }; |
13106 | assertionEnded( assertionResult ); |
13107 | populateReaction( reaction ); |
13108 | } |
13109 | |
13110 | void RunContext::populateReaction( AssertionReaction& reaction ) { |
13111 | reaction.shouldDebugBreak = m_config->shouldDebugBreak(); |
13112 | reaction.shouldThrow = aborting() || (m_lastAssertionInfo.resultDisposition & ResultDisposition::Normal); |
13113 | } |
13114 | |
13115 | void RunContext::handleIncomplete( |
13116 | AssertionInfo const& info |
13117 | ) { |
13118 | m_lastAssertionInfo = info; |
13119 | |
13120 | AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); |
13121 | data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE" ; |
13122 | AssertionResult assertionResult{ info, data }; |
13123 | assertionEnded( assertionResult ); |
13124 | } |
13125 | void RunContext::handleNonExpr( |
13126 | AssertionInfo const &info, |
13127 | ResultWas::OfType resultType, |
13128 | AssertionReaction &reaction |
13129 | ) { |
13130 | m_lastAssertionInfo = info; |
13131 | |
13132 | AssertionResultData data( resultType, LazyExpression( false ) ); |
13133 | AssertionResult assertionResult{ info, data }; |
13134 | assertionEnded( assertionResult ); |
13135 | |
13136 | if( !assertionResult.isOk() ) |
13137 | populateReaction( reaction ); |
13138 | } |
13139 | |
13140 | IResultCapture& getResultCapture() { |
13141 | if (auto* capture = getCurrentContext().getResultCapture()) |
13142 | return *capture; |
13143 | else |
13144 | CATCH_INTERNAL_ERROR("No result capture instance" ); |
13145 | } |
13146 | |
13147 | void seedRng(IConfig const& config) { |
13148 | if (config.rngSeed() != 0) { |
13149 | std::srand(config.rngSeed()); |
13150 | rng().seed(config.rngSeed()); |
13151 | } |
13152 | } |
13153 | |
13154 | unsigned int rngSeed() { |
13155 | return getCurrentContext().getConfig()->rngSeed(); |
13156 | } |
13157 | |
13158 | } |
13159 | // end catch_run_context.cpp |
13160 | // start catch_section.cpp |
13161 | |
13162 | namespace Catch { |
13163 | |
13164 | Section::Section( SectionInfo const& info ) |
13165 | : m_info( info ), |
13166 | m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) ) |
13167 | { |
13168 | m_timer.start(); |
13169 | } |
13170 | |
13171 | Section::~Section() { |
13172 | if( m_sectionIncluded ) { |
13173 | SectionEndInfo endInfo{ m_info, m_assertions, m_timer.getElapsedSeconds() }; |
13174 | if( uncaught_exceptions() ) |
13175 | getResultCapture().sectionEndedEarly( endInfo ); |
13176 | else |
13177 | getResultCapture().sectionEnded( endInfo ); |
13178 | } |
13179 | } |
13180 | |
13181 | // This indicates whether the section should be executed or not |
13182 | Section::operator bool() const { |
13183 | return m_sectionIncluded; |
13184 | } |
13185 | |
13186 | } // end namespace Catch |
13187 | // end catch_section.cpp |
13188 | // start catch_section_info.cpp |
13189 | |
13190 | namespace Catch { |
13191 | |
13192 | SectionInfo::SectionInfo |
13193 | ( SourceLineInfo const& _lineInfo, |
13194 | std::string const& _name ) |
13195 | : name( _name ), |
13196 | lineInfo( _lineInfo ) |
13197 | {} |
13198 | |
13199 | } // end namespace Catch |
13200 | // end catch_section_info.cpp |
13201 | // start catch_session.cpp |
13202 | |
13203 | // start catch_session.h |
13204 | |
13205 | #include <memory> |
13206 | |
13207 | namespace Catch { |
13208 | |
13209 | class Session : NonCopyable { |
13210 | public: |
13211 | |
13212 | Session(); |
13213 | ~Session() override; |
13214 | |
13215 | void showHelp() const; |
13216 | void libIdentify(); |
13217 | |
13218 | int applyCommandLine( int argc, char const * const * argv ); |
13219 | #if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE) |
13220 | int applyCommandLine( int argc, wchar_t const * const * argv ); |
13221 | #endif |
13222 | |
13223 | void useConfigData( ConfigData const& configData ); |
13224 | |
13225 | template<typename CharT> |
13226 | int run(int argc, CharT const * const argv[]) { |
13227 | if (m_startupExceptions) |
13228 | return 1; |
13229 | int returnCode = applyCommandLine(argc, argv); |
13230 | if (returnCode == 0) |
13231 | returnCode = run(); |
13232 | return returnCode; |
13233 | } |
13234 | |
13235 | int run(); |
13236 | |
13237 | clara::Parser const& cli() const; |
13238 | void cli( clara::Parser const& newParser ); |
13239 | ConfigData& configData(); |
13240 | Config& config(); |
13241 | private: |
13242 | int runInternal(); |
13243 | |
13244 | clara::Parser m_cli; |
13245 | ConfigData m_configData; |
13246 | std::shared_ptr<Config> m_config; |
13247 | bool m_startupExceptions = false; |
13248 | }; |
13249 | |
13250 | } // end namespace Catch |
13251 | |
13252 | // end catch_session.h |
13253 | // start catch_version.h |
13254 | |
13255 | #include <iosfwd> |
13256 | |
13257 | namespace Catch { |
13258 | |
13259 | // Versioning information |
13260 | struct Version { |
13261 | Version( Version const& ) = delete; |
13262 | Version& operator=( Version const& ) = delete; |
13263 | Version( unsigned int _majorVersion, |
13264 | unsigned int _minorVersion, |
13265 | unsigned int _patchNumber, |
13266 | char const * const _branchName, |
13267 | unsigned int _buildNumber ); |
13268 | |
13269 | unsigned int const majorVersion; |
13270 | unsigned int const minorVersion; |
13271 | unsigned int const patchNumber; |
13272 | |
13273 | // buildNumber is only used if branchName is not null |
13274 | char const * const branchName; |
13275 | unsigned int const buildNumber; |
13276 | |
13277 | friend std::ostream& operator << ( std::ostream& os, Version const& version ); |
13278 | }; |
13279 | |
13280 | Version const& libraryVersion(); |
13281 | } |
13282 | |
13283 | // end catch_version.h |
13284 | #include <cstdlib> |
13285 | #include <iomanip> |
13286 | #include <set> |
13287 | #include <iterator> |
13288 | |
13289 | namespace Catch { |
13290 | |
13291 | namespace { |
13292 | const int MaxExitCode = 255; |
13293 | |
13294 | IStreamingReporterPtr createReporter(std::string const& reporterName, IConfigPtr const& config) { |
13295 | auto reporter = Catch::getRegistryHub().getReporterRegistry().create(reporterName, config); |
13296 | CATCH_ENFORCE(reporter, "No reporter registered with name: '" << reporterName << "'" ); |
13297 | |
13298 | return reporter; |
13299 | } |
13300 | |
13301 | IStreamingReporterPtr makeReporter(std::shared_ptr<Config> const& config) { |
13302 | if (Catch::getRegistryHub().getReporterRegistry().getListeners().empty()) { |
13303 | return createReporter(config->getReporterName(), config); |
13304 | } |
13305 | |
13306 | // On older platforms, returning std::unique_ptr<ListeningReporter> |
13307 | // when the return type is std::unique_ptr<IStreamingReporter> |
13308 | // doesn't compile without a std::move call. However, this causes |
13309 | // a warning on newer platforms. Thus, we have to work around |
13310 | // it a bit and downcast the pointer manually. |
13311 | auto ret = std::unique_ptr<IStreamingReporter>(new ListeningReporter); |
13312 | auto& multi = static_cast<ListeningReporter&>(*ret); |
13313 | auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners(); |
13314 | for (auto const& listener : listeners) { |
13315 | multi.addListener(listener->create(Catch::ReporterConfig(config))); |
13316 | } |
13317 | multi.addReporter(createReporter(config->getReporterName(), config)); |
13318 | return ret; |
13319 | } |
13320 | |
13321 | class TestGroup { |
13322 | public: |
13323 | explicit TestGroup(std::shared_ptr<Config> const& config) |
13324 | : m_config{config} |
13325 | , m_context{config, makeReporter(config)} |
13326 | { |
13327 | auto const& allTestCases = getAllTestCasesSorted(*m_config); |
13328 | m_matches = m_config->testSpec().matchesByFilter(allTestCases, *m_config); |
13329 | auto const& invalidArgs = m_config->testSpec().getInvalidArgs(); |
13330 | |
13331 | if (m_matches.empty() && invalidArgs.empty()) { |
13332 | for (auto const& test : allTestCases) |
13333 | if (!test.isHidden()) |
13334 | m_tests.emplace(&test); |
13335 | } else { |
13336 | for (auto const& match : m_matches) |
13337 | m_tests.insert(match.tests.begin(), match.tests.end()); |
13338 | } |
13339 | } |
13340 | |
13341 | Totals execute() { |
13342 | auto const& invalidArgs = m_config->testSpec().getInvalidArgs(); |
13343 | Totals totals; |
13344 | m_context.testGroupStarting(m_config->name(), 1, 1); |
13345 | for (auto const& testCase : m_tests) { |
13346 | if (!m_context.aborting()) |
13347 | totals += m_context.runTest(*testCase); |
13348 | else |
13349 | m_context.reporter().skipTest(*testCase); |
13350 | } |
13351 | |
13352 | for (auto const& match : m_matches) { |
13353 | if (match.tests.empty()) { |
13354 | m_context.reporter().noMatchingTestCases(match.name); |
13355 | totals.error = -1; |
13356 | } |
13357 | } |
13358 | |
13359 | if (!invalidArgs.empty()) { |
13360 | for (auto const& invalidArg: invalidArgs) |
13361 | m_context.reporter().reportInvalidArguments(invalidArg); |
13362 | } |
13363 | |
13364 | m_context.testGroupEnded(m_config->name(), totals, 1, 1); |
13365 | return totals; |
13366 | } |
13367 | |
13368 | private: |
13369 | using Tests = std::set<TestCase const*>; |
13370 | |
13371 | std::shared_ptr<Config> m_config; |
13372 | RunContext m_context; |
13373 | Tests m_tests; |
13374 | TestSpec::Matches m_matches; |
13375 | }; |
13376 | |
13377 | void applyFilenamesAsTags(Catch::IConfig const& config) { |
13378 | auto& tests = const_cast<std::vector<TestCase>&>(getAllTestCasesSorted(config)); |
13379 | for (auto& testCase : tests) { |
13380 | auto tags = testCase.tags; |
13381 | |
13382 | std::string filename = testCase.lineInfo.file; |
13383 | auto lastSlash = filename.find_last_of("\\/" ); |
13384 | if (lastSlash != std::string::npos) { |
13385 | filename.erase(0, lastSlash); |
13386 | filename[0] = '#'; |
13387 | } |
13388 | |
13389 | auto lastDot = filename.find_last_of('.'); |
13390 | if (lastDot != std::string::npos) { |
13391 | filename.erase(lastDot); |
13392 | } |
13393 | |
13394 | tags.push_back(std::move(filename)); |
13395 | setTags(testCase, tags); |
13396 | } |
13397 | } |
13398 | |
13399 | } // anon namespace |
13400 | |
13401 | Session::Session() { |
13402 | static bool alreadyInstantiated = false; |
13403 | if( alreadyInstantiated ) { |
13404 | CATCH_TRY { CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); } |
13405 | CATCH_CATCH_ALL { getMutableRegistryHub().registerStartupException(); } |
13406 | } |
13407 | |
13408 | // There cannot be exceptions at startup in no-exception mode. |
13409 | #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) |
13410 | const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions(); |
13411 | if ( !exceptions.empty() ) { |
13412 | config(); |
13413 | getCurrentMutableContext().setConfig(m_config); |
13414 | |
13415 | m_startupExceptions = true; |
13416 | Colour colourGuard( Colour::Red ); |
13417 | Catch::cerr() << "Errors occurred during startup!" << '\n'; |
13418 | // iterate over all exceptions and notify user |
13419 | for ( const auto& ex_ptr : exceptions ) { |
13420 | try { |
13421 | std::rethrow_exception(ex_ptr); |
13422 | } catch ( std::exception const& ex ) { |
13423 | Catch::cerr() << Column( ex.what() ).indent(2) << '\n'; |
13424 | } |
13425 | } |
13426 | } |
13427 | #endif |
13428 | |
13429 | alreadyInstantiated = true; |
13430 | m_cli = makeCommandLineParser( m_configData ); |
13431 | } |
13432 | Session::~Session() { |
13433 | Catch::cleanUp(); |
13434 | } |
13435 | |
13436 | void Session::showHelp() const { |
13437 | Catch::cout() |
13438 | << "\nCatch v" << libraryVersion() << "\n" |
13439 | << m_cli << std::endl |
13440 | << "For more detailed usage please see the project docs\n" << std::endl; |
13441 | } |
13442 | void Session::libIdentify() { |
13443 | Catch::cout() |
13444 | << std::left << std::setw(16) << "description: " << "A Catch2 test executable\n" |
13445 | << std::left << std::setw(16) << "category: " << "testframework\n" |
13446 | << std::left << std::setw(16) << "framework: " << "Catch Test\n" |
13447 | << std::left << std::setw(16) << "version: " << libraryVersion() << std::endl; |
13448 | } |
13449 | |
13450 | int Session::applyCommandLine( int argc, char const * const * argv ) { |
13451 | if( m_startupExceptions ) |
13452 | return 1; |
13453 | |
13454 | auto result = m_cli.parse( clara::Args( argc, argv ) ); |
13455 | if( !result ) { |
13456 | config(); |
13457 | getCurrentMutableContext().setConfig(m_config); |
13458 | Catch::cerr() |
13459 | << Colour( Colour::Red ) |
13460 | << "\nError(s) in input:\n" |
13461 | << Column( result.errorMessage() ).indent( 2 ) |
13462 | << "\n\n" ; |
13463 | Catch::cerr() << "Run with -? for usage\n" << std::endl; |
13464 | return MaxExitCode; |
13465 | } |
13466 | |
13467 | if( m_configData.showHelp ) |
13468 | showHelp(); |
13469 | if( m_configData.libIdentify ) |
13470 | libIdentify(); |
13471 | m_config.reset(); |
13472 | return 0; |
13473 | } |
13474 | |
13475 | #if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE) |
13476 | int Session::applyCommandLine( int argc, wchar_t const * const * argv ) { |
13477 | |
13478 | char **utf8Argv = new char *[ argc ]; |
13479 | |
13480 | for ( int i = 0; i < argc; ++i ) { |
13481 | int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, nullptr, 0, nullptr, nullptr ); |
13482 | |
13483 | utf8Argv[ i ] = new char[ bufSize ]; |
13484 | |
13485 | WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, nullptr, nullptr ); |
13486 | } |
13487 | |
13488 | int returnCode = applyCommandLine( argc, utf8Argv ); |
13489 | |
13490 | for ( int i = 0; i < argc; ++i ) |
13491 | delete [] utf8Argv[ i ]; |
13492 | |
13493 | delete [] utf8Argv; |
13494 | |
13495 | return returnCode; |
13496 | } |
13497 | #endif |
13498 | |
13499 | void Session::useConfigData( ConfigData const& configData ) { |
13500 | m_configData = configData; |
13501 | m_config.reset(); |
13502 | } |
13503 | |
13504 | int Session::run() { |
13505 | if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) { |
13506 | Catch::cout() << "...waiting for enter/ return before starting" << std::endl; |
13507 | static_cast<void>(std::getchar()); |
13508 | } |
13509 | int exitCode = runInternal(); |
13510 | if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) { |
13511 | Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << std::endl; |
13512 | static_cast<void>(std::getchar()); |
13513 | } |
13514 | return exitCode; |
13515 | } |
13516 | |
13517 | clara::Parser const& Session::cli() const { |
13518 | return m_cli; |
13519 | } |
13520 | void Session::cli( clara::Parser const& newParser ) { |
13521 | m_cli = newParser; |
13522 | } |
13523 | ConfigData& Session::configData() { |
13524 | return m_configData; |
13525 | } |
13526 | Config& Session::config() { |
13527 | if( !m_config ) |
13528 | m_config = std::make_shared<Config>( m_configData ); |
13529 | return *m_config; |
13530 | } |
13531 | |
13532 | int Session::runInternal() { |
13533 | if( m_startupExceptions ) |
13534 | return 1; |
13535 | |
13536 | if (m_configData.showHelp || m_configData.libIdentify) { |
13537 | return 0; |
13538 | } |
13539 | |
13540 | CATCH_TRY { |
13541 | config(); // Force config to be constructed |
13542 | |
13543 | seedRng( *m_config ); |
13544 | |
13545 | if( m_configData.filenamesAsTags ) |
13546 | applyFilenamesAsTags( *m_config ); |
13547 | |
13548 | // Handle list request |
13549 | if( Option<std::size_t> listed = list( m_config ) ) |
13550 | return static_cast<int>( *listed ); |
13551 | |
13552 | TestGroup tests { m_config }; |
13553 | auto const totals = tests.execute(); |
13554 | |
13555 | if( m_config->warnAboutNoTests() && totals.error == -1 ) |
13556 | return 2; |
13557 | |
13558 | // Note that on unices only the lower 8 bits are usually used, clamping |
13559 | // the return value to 255 prevents false negative when some multiple |
13560 | // of 256 tests has failed |
13561 | return (std::min) (MaxExitCode, (std::max) (totals.error, static_cast<int>(totals.assertions.failed))); |
13562 | } |
13563 | #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) |
13564 | catch( std::exception& ex ) { |
13565 | Catch::cerr() << ex.what() << std::endl; |
13566 | return MaxExitCode; |
13567 | } |
13568 | #endif |
13569 | } |
13570 | |
13571 | } // end namespace Catch |
13572 | // end catch_session.cpp |
13573 | // start catch_singletons.cpp |
13574 | |
13575 | #include <vector> |
13576 | |
13577 | namespace Catch { |
13578 | |
13579 | namespace { |
13580 | static auto getSingletons() -> std::vector<ISingleton*>*& { |
13581 | static std::vector<ISingleton*>* g_singletons = nullptr; |
13582 | if( !g_singletons ) |
13583 | g_singletons = new std::vector<ISingleton*>(); |
13584 | return g_singletons; |
13585 | } |
13586 | } |
13587 | |
13588 | ISingleton::~ISingleton() {} |
13589 | |
13590 | void addSingleton(ISingleton* singleton ) { |
13591 | getSingletons()->push_back( singleton ); |
13592 | } |
13593 | void cleanupSingletons() { |
13594 | auto& singletons = getSingletons(); |
13595 | for( auto singleton : *singletons ) |
13596 | delete singleton; |
13597 | delete singletons; |
13598 | singletons = nullptr; |
13599 | } |
13600 | |
13601 | } // namespace Catch |
13602 | // end catch_singletons.cpp |
13603 | // start catch_startup_exception_registry.cpp |
13604 | |
13605 | #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) |
13606 | namespace Catch { |
13607 | void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept { |
13608 | CATCH_TRY { |
13609 | m_exceptions.push_back(exception); |
13610 | } CATCH_CATCH_ALL { |
13611 | // If we run out of memory during start-up there's really not a lot more we can do about it |
13612 | std::terminate(); |
13613 | } |
13614 | } |
13615 | |
13616 | std::vector<std::exception_ptr> const& StartupExceptionRegistry::getExceptions() const noexcept { |
13617 | return m_exceptions; |
13618 | } |
13619 | |
13620 | } // end namespace Catch |
13621 | #endif |
13622 | // end catch_startup_exception_registry.cpp |
13623 | // start catch_stream.cpp |
13624 | |
13625 | #include <cstdio> |
13626 | #include <iostream> |
13627 | #include <fstream> |
13628 | #include <sstream> |
13629 | #include <vector> |
13630 | #include <memory> |
13631 | |
13632 | namespace Catch { |
13633 | |
13634 | Catch::IStream::~IStream() = default; |
13635 | |
13636 | namespace Detail { namespace { |
13637 | template<typename WriterF, std::size_t bufferSize=256> |
13638 | class StreamBufImpl : public std::streambuf { |
13639 | char data[bufferSize]; |
13640 | WriterF m_writer; |
13641 | |
13642 | public: |
13643 | StreamBufImpl() { |
13644 | setp( data, data + sizeof(data) ); |
13645 | } |
13646 | |
13647 | ~StreamBufImpl() noexcept { |
13648 | StreamBufImpl::sync(); |
13649 | } |
13650 | |
13651 | private: |
13652 | int overflow( int c ) override { |
13653 | sync(); |
13654 | |
13655 | if( c != EOF ) { |
13656 | if( pbase() == epptr() ) |
13657 | m_writer( std::string( 1, static_cast<char>( c ) ) ); |
13658 | else |
13659 | sputc( static_cast<char>( c ) ); |
13660 | } |
13661 | return 0; |
13662 | } |
13663 | |
13664 | int sync() override { |
13665 | if( pbase() != pptr() ) { |
13666 | m_writer( std::string( pbase(), static_cast<std::string::size_type>( pptr() - pbase() ) ) ); |
13667 | setp( pbase(), epptr() ); |
13668 | } |
13669 | return 0; |
13670 | } |
13671 | }; |
13672 | |
13673 | /////////////////////////////////////////////////////////////////////////// |
13674 | |
13675 | struct OutputDebugWriter { |
13676 | |
13677 | void operator()( std::string const&str ) { |
13678 | writeToDebugConsole( str ); |
13679 | } |
13680 | }; |
13681 | |
13682 | /////////////////////////////////////////////////////////////////////////// |
13683 | |
13684 | class FileStream : public IStream { |
13685 | mutable std::ofstream m_ofs; |
13686 | public: |
13687 | FileStream( StringRef filename ) { |
13688 | m_ofs.open( filename.c_str() ); |
13689 | CATCH_ENFORCE( !m_ofs.fail(), "Unable to open file: '" << filename << "'" ); |
13690 | } |
13691 | ~FileStream() override = default; |
13692 | public: // IStream |
13693 | std::ostream& stream() const override { |
13694 | return m_ofs; |
13695 | } |
13696 | }; |
13697 | |
13698 | /////////////////////////////////////////////////////////////////////////// |
13699 | |
13700 | class CoutStream : public IStream { |
13701 | mutable std::ostream m_os; |
13702 | public: |
13703 | // Store the streambuf from cout up-front because |
13704 | // cout may get redirected when running tests |
13705 | CoutStream() : m_os( Catch::cout().rdbuf() ) {} |
13706 | ~CoutStream() override = default; |
13707 | |
13708 | public: // IStream |
13709 | std::ostream& stream() const override { return m_os; } |
13710 | }; |
13711 | |
13712 | /////////////////////////////////////////////////////////////////////////// |
13713 | |
13714 | class DebugOutStream : public IStream { |
13715 | std::unique_ptr<StreamBufImpl<OutputDebugWriter>> m_streamBuf; |
13716 | mutable std::ostream m_os; |
13717 | public: |
13718 | DebugOutStream() |
13719 | : m_streamBuf( new StreamBufImpl<OutputDebugWriter>() ), |
13720 | m_os( m_streamBuf.get() ) |
13721 | {} |
13722 | |
13723 | ~DebugOutStream() override = default; |
13724 | |
13725 | public: // IStream |
13726 | std::ostream& stream() const override { return m_os; } |
13727 | }; |
13728 | |
13729 | }} // namespace anon::detail |
13730 | |
13731 | /////////////////////////////////////////////////////////////////////////// |
13732 | |
13733 | auto makeStream( StringRef const &filename ) -> IStream const* { |
13734 | if( filename.empty() ) |
13735 | return new Detail::CoutStream(); |
13736 | else if( filename[0] == '%' ) { |
13737 | if( filename == "%debug" ) |
13738 | return new Detail::DebugOutStream(); |
13739 | else |
13740 | CATCH_ERROR( "Unrecognised stream: '" << filename << "'" ); |
13741 | } |
13742 | else |
13743 | return new Detail::FileStream( filename ); |
13744 | } |
13745 | |
13746 | // This class encapsulates the idea of a pool of ostringstreams that can be reused. |
13747 | struct StringStreams { |
13748 | std::vector<std::unique_ptr<std::ostringstream>> m_streams; |
13749 | std::vector<std::size_t> m_unused; |
13750 | std::ostringstream m_referenceStream; // Used for copy state/ flags from |
13751 | |
13752 | auto add() -> std::size_t { |
13753 | if( m_unused.empty() ) { |
13754 | m_streams.push_back( std::unique_ptr<std::ostringstream>( new std::ostringstream ) ); |
13755 | return m_streams.size()-1; |
13756 | } |
13757 | else { |
13758 | auto index = m_unused.back(); |
13759 | m_unused.pop_back(); |
13760 | return index; |
13761 | } |
13762 | } |
13763 | |
13764 | void release( std::size_t index ) { |
13765 | m_streams[index]->copyfmt( m_referenceStream ); // Restore initial flags and other state |
13766 | m_unused.push_back(index); |
13767 | } |
13768 | }; |
13769 | |
13770 | ReusableStringStream::ReusableStringStream() |
13771 | : m_index( Singleton<StringStreams>::getMutable().add() ), |
13772 | m_oss( Singleton<StringStreams>::getMutable().m_streams[m_index].get() ) |
13773 | {} |
13774 | |
13775 | ReusableStringStream::~ReusableStringStream() { |
13776 | static_cast<std::ostringstream*>( m_oss )->str("" ); |
13777 | m_oss->clear(); |
13778 | Singleton<StringStreams>::getMutable().release( m_index ); |
13779 | } |
13780 | |
13781 | auto ReusableStringStream::str() const -> std::string { |
13782 | return static_cast<std::ostringstream*>( m_oss )->str(); |
13783 | } |
13784 | |
13785 | /////////////////////////////////////////////////////////////////////////// |
13786 | |
13787 | #ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions |
13788 | std::ostream& cout() { return std::cout; } |
13789 | std::ostream& cerr() { return std::cerr; } |
13790 | std::ostream& clog() { return std::clog; } |
13791 | #endif |
13792 | } |
13793 | // end catch_stream.cpp |
13794 | // start catch_string_manip.cpp |
13795 | |
13796 | #include <algorithm> |
13797 | #include <ostream> |
13798 | #include <cstring> |
13799 | #include <cctype> |
13800 | #include <vector> |
13801 | |
13802 | namespace Catch { |
13803 | |
13804 | namespace { |
13805 | char toLowerCh(char c) { |
13806 | return static_cast<char>( std::tolower( static_cast<unsigned char>(c) ) ); |
13807 | } |
13808 | } |
13809 | |
13810 | bool startsWith( std::string const& s, std::string const& prefix ) { |
13811 | return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin()); |
13812 | } |
13813 | bool startsWith( std::string const& s, char prefix ) { |
13814 | return !s.empty() && s[0] == prefix; |
13815 | } |
13816 | bool endsWith( std::string const& s, std::string const& suffix ) { |
13817 | return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin()); |
13818 | } |
13819 | bool endsWith( std::string const& s, char suffix ) { |
13820 | return !s.empty() && s[s.size()-1] == suffix; |
13821 | } |
13822 | bool contains( std::string const& s, std::string const& infix ) { |
13823 | return s.find( infix ) != std::string::npos; |
13824 | } |
13825 | void toLowerInPlace( std::string& s ) { |
13826 | std::transform( s.begin(), s.end(), s.begin(), toLowerCh ); |
13827 | } |
13828 | std::string toLower( std::string const& s ) { |
13829 | std::string lc = s; |
13830 | toLowerInPlace( lc ); |
13831 | return lc; |
13832 | } |
13833 | std::string trim( std::string const& str ) { |
13834 | static char const* whitespaceChars = "\n\r\t " ; |
13835 | std::string::size_type start = str.find_first_not_of( whitespaceChars ); |
13836 | std::string::size_type end = str.find_last_not_of( whitespaceChars ); |
13837 | |
13838 | return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string(); |
13839 | } |
13840 | |
13841 | StringRef trim(StringRef ref) { |
13842 | const auto is_ws = [](char c) { |
13843 | return c == ' ' || c == '\t' || c == '\n' || c == '\r'; |
13844 | }; |
13845 | size_t real_begin = 0; |
13846 | while (real_begin < ref.size() && is_ws(ref[real_begin])) { ++real_begin; } |
13847 | size_t real_end = ref.size(); |
13848 | while (real_end > real_begin && is_ws(ref[real_end - 1])) { --real_end; } |
13849 | |
13850 | return ref.substr(real_begin, real_end - real_begin); |
13851 | } |
13852 | |
13853 | bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { |
13854 | bool replaced = false; |
13855 | std::size_t i = str.find( replaceThis ); |
13856 | while( i != std::string::npos ) { |
13857 | replaced = true; |
13858 | str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() ); |
13859 | if( i < str.size()-withThis.size() ) |
13860 | i = str.find( replaceThis, i+withThis.size() ); |
13861 | else |
13862 | i = std::string::npos; |
13863 | } |
13864 | return replaced; |
13865 | } |
13866 | |
13867 | std::vector<StringRef> splitStringRef( StringRef str, char delimiter ) { |
13868 | std::vector<StringRef> subStrings; |
13869 | std::size_t start = 0; |
13870 | for(std::size_t pos = 0; pos < str.size(); ++pos ) { |
13871 | if( str[pos] == delimiter ) { |
13872 | if( pos - start > 1 ) |
13873 | subStrings.push_back( str.substr( start, pos-start ) ); |
13874 | start = pos+1; |
13875 | } |
13876 | } |
13877 | if( start < str.size() ) |
13878 | subStrings.push_back( str.substr( start, str.size()-start ) ); |
13879 | return subStrings; |
13880 | } |
13881 | |
13882 | pluralise::pluralise( std::size_t count, std::string const& label ) |
13883 | : m_count( count ), |
13884 | m_label( label ) |
13885 | {} |
13886 | |
13887 | std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { |
13888 | os << pluraliser.m_count << ' ' << pluraliser.m_label; |
13889 | if( pluraliser.m_count != 1 ) |
13890 | os << 's'; |
13891 | return os; |
13892 | } |
13893 | |
13894 | } |
13895 | // end catch_string_manip.cpp |
13896 | // start catch_stringref.cpp |
13897 | |
13898 | #include <algorithm> |
13899 | #include <ostream> |
13900 | #include <cstring> |
13901 | #include <cstdint> |
13902 | |
13903 | namespace Catch { |
13904 | StringRef::StringRef( char const* rawChars ) noexcept |
13905 | : StringRef( rawChars, static_cast<StringRef::size_type>(std::strlen(rawChars) ) ) |
13906 | {} |
13907 | |
13908 | auto StringRef::c_str() const -> char const* { |
13909 | CATCH_ENFORCE(isNullTerminated(), "Called StringRef::c_str() on a non-null-terminated instance" ); |
13910 | return m_start; |
13911 | } |
13912 | auto StringRef::data() const noexcept -> char const* { |
13913 | return m_start; |
13914 | } |
13915 | |
13916 | auto StringRef::substr( size_type start, size_type size ) const noexcept -> StringRef { |
13917 | if (start < m_size) { |
13918 | return StringRef(m_start + start, (std::min)(m_size - start, size)); |
13919 | } else { |
13920 | return StringRef(); |
13921 | } |
13922 | } |
13923 | auto StringRef::operator == ( StringRef const& other ) const noexcept -> bool { |
13924 | return m_size == other.m_size |
13925 | && (std::memcmp( m_start, other.m_start, m_size ) == 0); |
13926 | } |
13927 | |
13928 | auto operator << ( std::ostream& os, StringRef const& str ) -> std::ostream& { |
13929 | return os.write(str.data(), str.size()); |
13930 | } |
13931 | |
13932 | auto operator+=( std::string& lhs, StringRef const& rhs ) -> std::string& { |
13933 | lhs.append(rhs.data(), rhs.size()); |
13934 | return lhs; |
13935 | } |
13936 | |
13937 | } // namespace Catch |
13938 | // end catch_stringref.cpp |
13939 | // start catch_tag_alias.cpp |
13940 | |
13941 | namespace Catch { |
13942 | TagAlias::TagAlias(std::string const & _tag, SourceLineInfo _lineInfo): tag(_tag), lineInfo(_lineInfo) {} |
13943 | } |
13944 | // end catch_tag_alias.cpp |
13945 | // start catch_tag_alias_autoregistrar.cpp |
13946 | |
13947 | namespace Catch { |
13948 | |
13949 | RegistrarForTagAliases::RegistrarForTagAliases(char const* alias, char const* tag, SourceLineInfo const& lineInfo) { |
13950 | CATCH_TRY { |
13951 | getMutableRegistryHub().registerTagAlias(alias, tag, lineInfo); |
13952 | } CATCH_CATCH_ALL { |
13953 | // Do not throw when constructing global objects, instead register the exception to be processed later |
13954 | getMutableRegistryHub().registerStartupException(); |
13955 | } |
13956 | } |
13957 | |
13958 | } |
13959 | // end catch_tag_alias_autoregistrar.cpp |
13960 | // start catch_tag_alias_registry.cpp |
13961 | |
13962 | #include <sstream> |
13963 | |
13964 | namespace Catch { |
13965 | |
13966 | TagAliasRegistry::~TagAliasRegistry() {} |
13967 | |
13968 | TagAlias const* TagAliasRegistry::find( std::string const& alias ) const { |
13969 | auto it = m_registry.find( alias ); |
13970 | if( it != m_registry.end() ) |
13971 | return &(it->second); |
13972 | else |
13973 | return nullptr; |
13974 | } |
13975 | |
13976 | std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { |
13977 | std::string expandedTestSpec = unexpandedTestSpec; |
13978 | for( auto const& registryKvp : m_registry ) { |
13979 | std::size_t pos = expandedTestSpec.find( registryKvp.first ); |
13980 | if( pos != std::string::npos ) { |
13981 | expandedTestSpec = expandedTestSpec.substr( 0, pos ) + |
13982 | registryKvp.second.tag + |
13983 | expandedTestSpec.substr( pos + registryKvp.first.size() ); |
13984 | } |
13985 | } |
13986 | return expandedTestSpec; |
13987 | } |
13988 | |
13989 | void TagAliasRegistry::add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) { |
13990 | CATCH_ENFORCE( startsWith(alias, "[@" ) && endsWith(alias, ']'), |
13991 | "error: tag alias, '" << alias << "' is not of the form [@alias name].\n" << lineInfo ); |
13992 | |
13993 | CATCH_ENFORCE( m_registry.insert(std::make_pair(alias, TagAlias(tag, lineInfo))).second, |
13994 | "error: tag alias, '" << alias << "' already registered.\n" |
13995 | << "\tFirst seen at: " << find(alias)->lineInfo << "\n" |
13996 | << "\tRedefined at: " << lineInfo ); |
13997 | } |
13998 | |
13999 | ITagAliasRegistry::~ITagAliasRegistry() {} |
14000 | |
14001 | ITagAliasRegistry const& ITagAliasRegistry::get() { |
14002 | return getRegistryHub().getTagAliasRegistry(); |
14003 | } |
14004 | |
14005 | } // end namespace Catch |
14006 | // end catch_tag_alias_registry.cpp |
14007 | // start catch_test_case_info.cpp |
14008 | |
14009 | #include <cctype> |
14010 | #include <exception> |
14011 | #include <algorithm> |
14012 | #include <sstream> |
14013 | |
14014 | namespace Catch { |
14015 | |
14016 | namespace { |
14017 | TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { |
14018 | if( startsWith( tag, '.' ) || |
14019 | tag == "!hide" ) |
14020 | return TestCaseInfo::IsHidden; |
14021 | else if( tag == "!throws" ) |
14022 | return TestCaseInfo::Throws; |
14023 | else if( tag == "!shouldfail" ) |
14024 | return TestCaseInfo::ShouldFail; |
14025 | else if( tag == "!mayfail" ) |
14026 | return TestCaseInfo::MayFail; |
14027 | else if( tag == "!nonportable" ) |
14028 | return TestCaseInfo::NonPortable; |
14029 | else if( tag == "!benchmark" ) |
14030 | return static_cast<TestCaseInfo::SpecialProperties>( TestCaseInfo::Benchmark | TestCaseInfo::IsHidden ); |
14031 | else |
14032 | return TestCaseInfo::None; |
14033 | } |
14034 | bool isReservedTag( std::string const& tag ) { |
14035 | return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( static_cast<unsigned char>(tag[0]) ); |
14036 | } |
14037 | void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { |
14038 | CATCH_ENFORCE( !isReservedTag(tag), |
14039 | "Tag name: [" << tag << "] is not allowed.\n" |
14040 | << "Tag names starting with non alphanumeric characters are reserved\n" |
14041 | << _lineInfo ); |
14042 | } |
14043 | } |
14044 | |
14045 | TestCase makeTestCase( ITestInvoker* _testCase, |
14046 | std::string const& _className, |
14047 | NameAndTags const& nameAndTags, |
14048 | SourceLineInfo const& _lineInfo ) |
14049 | { |
14050 | bool isHidden = false; |
14051 | |
14052 | // Parse out tags |
14053 | std::vector<std::string> tags; |
14054 | std::string desc, tag; |
14055 | bool inTag = false; |
14056 | for (char c : nameAndTags.tags) { |
14057 | if( !inTag ) { |
14058 | if( c == '[' ) |
14059 | inTag = true; |
14060 | else |
14061 | desc += c; |
14062 | } |
14063 | else { |
14064 | if( c == ']' ) { |
14065 | TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag ); |
14066 | if( ( prop & TestCaseInfo::IsHidden ) != 0 ) |
14067 | isHidden = true; |
14068 | else if( prop == TestCaseInfo::None ) |
14069 | enforceNotReservedTag( tag, _lineInfo ); |
14070 | |
14071 | // Merged hide tags like `[.approvals]` should be added as |
14072 | // `[.][approvals]`. The `[.]` is added at later point, so |
14073 | // we only strip the prefix |
14074 | if (startsWith(tag, '.') && tag.size() > 1) { |
14075 | tag.erase(0, 1); |
14076 | } |
14077 | tags.push_back( tag ); |
14078 | tag.clear(); |
14079 | inTag = false; |
14080 | } |
14081 | else |
14082 | tag += c; |
14083 | } |
14084 | } |
14085 | if( isHidden ) { |
14086 | // Add all "hidden" tags to make them behave identically |
14087 | tags.insert( tags.end(), { "." , "!hide" } ); |
14088 | } |
14089 | |
14090 | TestCaseInfo info( static_cast<std::string>(nameAndTags.name), _className, desc, tags, _lineInfo ); |
14091 | return TestCase( _testCase, std::move(info) ); |
14092 | } |
14093 | |
14094 | void setTags( TestCaseInfo& testCaseInfo, std::vector<std::string> tags ) { |
14095 | std::sort(begin(tags), end(tags)); |
14096 | tags.erase(std::unique(begin(tags), end(tags)), end(tags)); |
14097 | testCaseInfo.lcaseTags.clear(); |
14098 | |
14099 | for( auto const& tag : tags ) { |
14100 | std::string lcaseTag = toLower( tag ); |
14101 | testCaseInfo.properties = static_cast<TestCaseInfo::SpecialProperties>( testCaseInfo.properties | parseSpecialTag( lcaseTag ) ); |
14102 | testCaseInfo.lcaseTags.push_back( lcaseTag ); |
14103 | } |
14104 | testCaseInfo.tags = std::move(tags); |
14105 | } |
14106 | |
14107 | TestCaseInfo::TestCaseInfo( std::string const& _name, |
14108 | std::string const& _className, |
14109 | std::string const& _description, |
14110 | std::vector<std::string> const& _tags, |
14111 | SourceLineInfo const& _lineInfo ) |
14112 | : name( _name ), |
14113 | className( _className ), |
14114 | description( _description ), |
14115 | lineInfo( _lineInfo ), |
14116 | properties( None ) |
14117 | { |
14118 | setTags( *this, _tags ); |
14119 | } |
14120 | |
14121 | bool TestCaseInfo::isHidden() const { |
14122 | return ( properties & IsHidden ) != 0; |
14123 | } |
14124 | bool TestCaseInfo::throws() const { |
14125 | return ( properties & Throws ) != 0; |
14126 | } |
14127 | bool TestCaseInfo::okToFail() const { |
14128 | return ( properties & (ShouldFail | MayFail ) ) != 0; |
14129 | } |
14130 | bool TestCaseInfo::expectedToFail() const { |
14131 | return ( properties & (ShouldFail ) ) != 0; |
14132 | } |
14133 | |
14134 | std::string TestCaseInfo::tagsAsString() const { |
14135 | std::string ret; |
14136 | // '[' and ']' per tag |
14137 | std::size_t full_size = 2 * tags.size(); |
14138 | for (const auto& tag : tags) { |
14139 | full_size += tag.size(); |
14140 | } |
14141 | ret.reserve(full_size); |
14142 | for (const auto& tag : tags) { |
14143 | ret.push_back('['); |
14144 | ret.append(tag); |
14145 | ret.push_back(']'); |
14146 | } |
14147 | |
14148 | return ret; |
14149 | } |
14150 | |
14151 | TestCase::TestCase( ITestInvoker* testCase, TestCaseInfo&& info ) : TestCaseInfo( std::move(info) ), test( testCase ) {} |
14152 | |
14153 | TestCase TestCase::withName( std::string const& _newName ) const { |
14154 | TestCase other( *this ); |
14155 | other.name = _newName; |
14156 | return other; |
14157 | } |
14158 | |
14159 | void TestCase::invoke() const { |
14160 | test->invoke(); |
14161 | } |
14162 | |
14163 | bool TestCase::operator == ( TestCase const& other ) const { |
14164 | return test.get() == other.test.get() && |
14165 | name == other.name && |
14166 | className == other.className; |
14167 | } |
14168 | |
14169 | bool TestCase::operator < ( TestCase const& other ) const { |
14170 | return name < other.name; |
14171 | } |
14172 | |
14173 | TestCaseInfo const& TestCase::getTestCaseInfo() const |
14174 | { |
14175 | return *this; |
14176 | } |
14177 | |
14178 | } // end namespace Catch |
14179 | // end catch_test_case_info.cpp |
14180 | // start catch_test_case_registry_impl.cpp |
14181 | |
14182 | #include <algorithm> |
14183 | #include <sstream> |
14184 | |
14185 | namespace Catch { |
14186 | |
14187 | namespace { |
14188 | struct TestHasher { |
14189 | using hash_t = uint64_t; |
14190 | |
14191 | explicit TestHasher( hash_t hashSuffix ): |
14192 | m_hashSuffix{ hashSuffix } {} |
14193 | |
14194 | uint32_t operator()( TestCase const& t ) const { |
14195 | // FNV-1a hash with multiplication fold. |
14196 | const hash_t prime = 1099511628211u; |
14197 | hash_t hash = 14695981039346656037u; |
14198 | for ( const char c : t.name ) { |
14199 | hash ^= c; |
14200 | hash *= prime; |
14201 | } |
14202 | hash ^= m_hashSuffix; |
14203 | hash *= prime; |
14204 | const uint32_t low{ static_cast<uint32_t>( hash ) }; |
14205 | const uint32_t high{ static_cast<uint32_t>( hash >> 32 ) }; |
14206 | return low * high; |
14207 | } |
14208 | |
14209 | private: |
14210 | hash_t m_hashSuffix; |
14211 | }; |
14212 | } // end unnamed namespace |
14213 | |
14214 | std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) { |
14215 | switch( config.runOrder() ) { |
14216 | case RunTests::InDeclarationOrder: |
14217 | // already in declaration order |
14218 | break; |
14219 | |
14220 | case RunTests::InLexicographicalOrder: { |
14221 | std::vector<TestCase> sorted = unsortedTestCases; |
14222 | std::sort( sorted.begin(), sorted.end() ); |
14223 | return sorted; |
14224 | } |
14225 | |
14226 | case RunTests::InRandomOrder: { |
14227 | seedRng( config ); |
14228 | TestHasher h{ config.rngSeed() }; |
14229 | |
14230 | using hashedTest = std::pair<TestHasher::hash_t, TestCase const*>; |
14231 | std::vector<hashedTest> indexed_tests; |
14232 | indexed_tests.reserve( unsortedTestCases.size() ); |
14233 | |
14234 | for (auto const& testCase : unsortedTestCases) { |
14235 | indexed_tests.emplace_back(h(testCase), &testCase); |
14236 | } |
14237 | |
14238 | std::sort(indexed_tests.begin(), indexed_tests.end(), |
14239 | [](hashedTest const& lhs, hashedTest const& rhs) { |
14240 | if (lhs.first == rhs.first) { |
14241 | return lhs.second->name < rhs.second->name; |
14242 | } |
14243 | return lhs.first < rhs.first; |
14244 | }); |
14245 | |
14246 | std::vector<TestCase> sorted; |
14247 | sorted.reserve( indexed_tests.size() ); |
14248 | |
14249 | for (auto const& hashed : indexed_tests) { |
14250 | sorted.emplace_back(*hashed.second); |
14251 | } |
14252 | |
14253 | return sorted; |
14254 | } |
14255 | } |
14256 | return unsortedTestCases; |
14257 | } |
14258 | |
14259 | bool isThrowSafe( TestCase const& testCase, IConfig const& config ) { |
14260 | return !testCase.throws() || config.allowThrows(); |
14261 | } |
14262 | |
14263 | bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) { |
14264 | return testSpec.matches( testCase ) && isThrowSafe( testCase, config ); |
14265 | } |
14266 | |
14267 | void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions ) { |
14268 | std::set<TestCase> seenFunctions; |
14269 | for( auto const& function : functions ) { |
14270 | auto prev = seenFunctions.insert( function ); |
14271 | CATCH_ENFORCE( prev.second, |
14272 | "error: TEST_CASE( \"" << function.name << "\" ) already defined.\n" |
14273 | << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" |
14274 | << "\tRedefined at " << function.getTestCaseInfo().lineInfo ); |
14275 | } |
14276 | } |
14277 | |
14278 | std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ) { |
14279 | std::vector<TestCase> filtered; |
14280 | filtered.reserve( testCases.size() ); |
14281 | for (auto const& testCase : testCases) { |
14282 | if ((!testSpec.hasFilters() && !testCase.isHidden()) || |
14283 | (testSpec.hasFilters() && matchTest(testCase, testSpec, config))) { |
14284 | filtered.push_back(testCase); |
14285 | } |
14286 | } |
14287 | return filtered; |
14288 | } |
14289 | std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ) { |
14290 | return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config ); |
14291 | } |
14292 | |
14293 | void TestRegistry::registerTest( TestCase const& testCase ) { |
14294 | std::string name = testCase.getTestCaseInfo().name; |
14295 | if( name.empty() ) { |
14296 | ReusableStringStream rss; |
14297 | rss << "Anonymous test case " << ++m_unnamedCount; |
14298 | return registerTest( testCase.withName( rss.str() ) ); |
14299 | } |
14300 | m_functions.push_back( testCase ); |
14301 | } |
14302 | |
14303 | std::vector<TestCase> const& TestRegistry::getAllTests() const { |
14304 | return m_functions; |
14305 | } |
14306 | std::vector<TestCase> const& TestRegistry::getAllTestsSorted( IConfig const& config ) const { |
14307 | if( m_sortedFunctions.empty() ) |
14308 | enforceNoDuplicateTestCases( m_functions ); |
14309 | |
14310 | if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) { |
14311 | m_sortedFunctions = sortTests( config, m_functions ); |
14312 | m_currentSortOrder = config.runOrder(); |
14313 | } |
14314 | return m_sortedFunctions; |
14315 | } |
14316 | |
14317 | /////////////////////////////////////////////////////////////////////////// |
14318 | TestInvokerAsFunction::TestInvokerAsFunction( void(*testAsFunction)() ) noexcept : m_testAsFunction( testAsFunction ) {} |
14319 | |
14320 | void TestInvokerAsFunction::invoke() const { |
14321 | m_testAsFunction(); |
14322 | } |
14323 | |
14324 | std::string extractClassName( StringRef const& classOrQualifiedMethodName ) { |
14325 | std::string className(classOrQualifiedMethodName); |
14326 | if( startsWith( className, '&' ) ) |
14327 | { |
14328 | std::size_t lastColons = className.rfind( "::" ); |
14329 | std::size_t penultimateColons = className.rfind( "::" , lastColons-1 ); |
14330 | if( penultimateColons == std::string::npos ) |
14331 | penultimateColons = 1; |
14332 | className = className.substr( penultimateColons, lastColons-penultimateColons ); |
14333 | } |
14334 | return className; |
14335 | } |
14336 | |
14337 | } // end namespace Catch |
14338 | // end catch_test_case_registry_impl.cpp |
14339 | // start catch_test_case_tracker.cpp |
14340 | |
14341 | #include <algorithm> |
14342 | #include <cassert> |
14343 | #include <stdexcept> |
14344 | #include <memory> |
14345 | #include <sstream> |
14346 | |
14347 | #if defined(__clang__) |
14348 | # pragma clang diagnostic push |
14349 | # pragma clang diagnostic ignored "-Wexit-time-destructors" |
14350 | #endif |
14351 | |
14352 | namespace Catch { |
14353 | namespace TestCaseTracking { |
14354 | |
14355 | NameAndLocation::NameAndLocation( std::string const& _name, SourceLineInfo const& _location ) |
14356 | : name( _name ), |
14357 | location( _location ) |
14358 | {} |
14359 | |
14360 | ITracker::~ITracker() = default; |
14361 | |
14362 | ITracker& TrackerContext::startRun() { |
14363 | m_rootTracker = std::make_shared<SectionTracker>( NameAndLocation( "{root}" , CATCH_INTERNAL_LINEINFO ), *this, nullptr ); |
14364 | m_currentTracker = nullptr; |
14365 | m_runState = Executing; |
14366 | return *m_rootTracker; |
14367 | } |
14368 | |
14369 | void TrackerContext::endRun() { |
14370 | m_rootTracker.reset(); |
14371 | m_currentTracker = nullptr; |
14372 | m_runState = NotStarted; |
14373 | } |
14374 | |
14375 | void TrackerContext::startCycle() { |
14376 | m_currentTracker = m_rootTracker.get(); |
14377 | m_runState = Executing; |
14378 | } |
14379 | void TrackerContext::completeCycle() { |
14380 | m_runState = CompletedCycle; |
14381 | } |
14382 | |
14383 | bool TrackerContext::completedCycle() const { |
14384 | return m_runState == CompletedCycle; |
14385 | } |
14386 | ITracker& TrackerContext::currentTracker() { |
14387 | return *m_currentTracker; |
14388 | } |
14389 | void TrackerContext::setCurrentTracker( ITracker* tracker ) { |
14390 | m_currentTracker = tracker; |
14391 | } |
14392 | |
14393 | TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ): |
14394 | ITracker(nameAndLocation), |
14395 | m_ctx( ctx ), |
14396 | m_parent( parent ) |
14397 | {} |
14398 | |
14399 | bool TrackerBase::isComplete() const { |
14400 | return m_runState == CompletedSuccessfully || m_runState == Failed; |
14401 | } |
14402 | bool TrackerBase::isSuccessfullyCompleted() const { |
14403 | return m_runState == CompletedSuccessfully; |
14404 | } |
14405 | bool TrackerBase::isOpen() const { |
14406 | return m_runState != NotStarted && !isComplete(); |
14407 | } |
14408 | bool TrackerBase::hasChildren() const { |
14409 | return !m_children.empty(); |
14410 | } |
14411 | |
14412 | void TrackerBase::addChild( ITrackerPtr const& child ) { |
14413 | m_children.push_back( child ); |
14414 | } |
14415 | |
14416 | ITrackerPtr TrackerBase::findChild( NameAndLocation const& nameAndLocation ) { |
14417 | auto it = std::find_if( m_children.begin(), m_children.end(), |
14418 | [&nameAndLocation]( ITrackerPtr const& tracker ){ |
14419 | return |
14420 | tracker->nameAndLocation().location == nameAndLocation.location && |
14421 | tracker->nameAndLocation().name == nameAndLocation.name; |
14422 | } ); |
14423 | return( it != m_children.end() ) |
14424 | ? *it |
14425 | : nullptr; |
14426 | } |
14427 | ITracker& TrackerBase::parent() { |
14428 | assert( m_parent ); // Should always be non-null except for root |
14429 | return *m_parent; |
14430 | } |
14431 | |
14432 | void TrackerBase::openChild() { |
14433 | if( m_runState != ExecutingChildren ) { |
14434 | m_runState = ExecutingChildren; |
14435 | if( m_parent ) |
14436 | m_parent->openChild(); |
14437 | } |
14438 | } |
14439 | |
14440 | bool TrackerBase::isSectionTracker() const { return false; } |
14441 | bool TrackerBase::isGeneratorTracker() const { return false; } |
14442 | |
14443 | void TrackerBase::open() { |
14444 | m_runState = Executing; |
14445 | moveToThis(); |
14446 | if( m_parent ) |
14447 | m_parent->openChild(); |
14448 | } |
14449 | |
14450 | void TrackerBase::close() { |
14451 | |
14452 | // Close any still open children (e.g. generators) |
14453 | while( &m_ctx.currentTracker() != this ) |
14454 | m_ctx.currentTracker().close(); |
14455 | |
14456 | switch( m_runState ) { |
14457 | case NeedsAnotherRun: |
14458 | break; |
14459 | |
14460 | case Executing: |
14461 | m_runState = CompletedSuccessfully; |
14462 | break; |
14463 | case ExecutingChildren: |
14464 | if( std::all_of(m_children.begin(), m_children.end(), [](ITrackerPtr const& t){ return t->isComplete(); }) ) |
14465 | m_runState = CompletedSuccessfully; |
14466 | break; |
14467 | |
14468 | case NotStarted: |
14469 | case CompletedSuccessfully: |
14470 | case Failed: |
14471 | CATCH_INTERNAL_ERROR( "Illogical state: " << m_runState ); |
14472 | |
14473 | default: |
14474 | CATCH_INTERNAL_ERROR( "Unknown state: " << m_runState ); |
14475 | } |
14476 | moveToParent(); |
14477 | m_ctx.completeCycle(); |
14478 | } |
14479 | void TrackerBase::fail() { |
14480 | m_runState = Failed; |
14481 | if( m_parent ) |
14482 | m_parent->markAsNeedingAnotherRun(); |
14483 | moveToParent(); |
14484 | m_ctx.completeCycle(); |
14485 | } |
14486 | void TrackerBase::markAsNeedingAnotherRun() { |
14487 | m_runState = NeedsAnotherRun; |
14488 | } |
14489 | |
14490 | void TrackerBase::moveToParent() { |
14491 | assert( m_parent ); |
14492 | m_ctx.setCurrentTracker( m_parent ); |
14493 | } |
14494 | void TrackerBase::moveToThis() { |
14495 | m_ctx.setCurrentTracker( this ); |
14496 | } |
14497 | |
14498 | SectionTracker::SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) |
14499 | : TrackerBase( nameAndLocation, ctx, parent ), |
14500 | m_trimmed_name(trim(nameAndLocation.name)) |
14501 | { |
14502 | if( parent ) { |
14503 | while( !parent->isSectionTracker() ) |
14504 | parent = &parent->parent(); |
14505 | |
14506 | SectionTracker& parentSection = static_cast<SectionTracker&>( *parent ); |
14507 | addNextFilters( parentSection.m_filters ); |
14508 | } |
14509 | } |
14510 | |
14511 | bool SectionTracker::isComplete() const { |
14512 | bool complete = true; |
14513 | |
14514 | if (m_filters.empty() |
14515 | || m_filters[0] == "" |
14516 | || std::find(m_filters.begin(), m_filters.end(), m_trimmed_name) != m_filters.end()) { |
14517 | complete = TrackerBase::isComplete(); |
14518 | } |
14519 | return complete; |
14520 | } |
14521 | |
14522 | bool SectionTracker::isSectionTracker() const { return true; } |
14523 | |
14524 | SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) { |
14525 | std::shared_ptr<SectionTracker> section; |
14526 | |
14527 | ITracker& currentTracker = ctx.currentTracker(); |
14528 | if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { |
14529 | assert( childTracker ); |
14530 | assert( childTracker->isSectionTracker() ); |
14531 | section = std::static_pointer_cast<SectionTracker>( childTracker ); |
14532 | } |
14533 | else { |
14534 | section = std::make_shared<SectionTracker>( nameAndLocation, ctx, ¤tTracker ); |
14535 | currentTracker.addChild( section ); |
14536 | } |
14537 | if( !ctx.completedCycle() ) |
14538 | section->tryOpen(); |
14539 | return *section; |
14540 | } |
14541 | |
14542 | void SectionTracker::tryOpen() { |
14543 | if( !isComplete() ) |
14544 | open(); |
14545 | } |
14546 | |
14547 | void SectionTracker::addInitialFilters( std::vector<std::string> const& filters ) { |
14548 | if( !filters.empty() ) { |
14549 | m_filters.reserve( m_filters.size() + filters.size() + 2 ); |
14550 | m_filters.emplace_back("" ); // Root - should never be consulted |
14551 | m_filters.emplace_back("" ); // Test Case - not a section filter |
14552 | m_filters.insert( m_filters.end(), filters.begin(), filters.end() ); |
14553 | } |
14554 | } |
14555 | void SectionTracker::addNextFilters( std::vector<std::string> const& filters ) { |
14556 | if( filters.size() > 1 ) |
14557 | m_filters.insert( m_filters.end(), filters.begin()+1, filters.end() ); |
14558 | } |
14559 | |
14560 | std::vector<std::string> const& SectionTracker::getFilters() const { |
14561 | return m_filters; |
14562 | } |
14563 | |
14564 | std::string const& SectionTracker::trimmedName() const { |
14565 | return m_trimmed_name; |
14566 | } |
14567 | |
14568 | } // namespace TestCaseTracking |
14569 | |
14570 | using TestCaseTracking::ITracker; |
14571 | using TestCaseTracking::TrackerContext; |
14572 | using TestCaseTracking::SectionTracker; |
14573 | |
14574 | } // namespace Catch |
14575 | |
14576 | #if defined(__clang__) |
14577 | # pragma clang diagnostic pop |
14578 | #endif |
14579 | // end catch_test_case_tracker.cpp |
14580 | // start catch_test_registry.cpp |
14581 | |
14582 | namespace Catch { |
14583 | |
14584 | auto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker* { |
14585 | return new(std::nothrow) TestInvokerAsFunction( testAsFunction ); |
14586 | } |
14587 | |
14588 | NameAndTags::NameAndTags( StringRef const& name_ , StringRef const& tags_ ) noexcept : name( name_ ), tags( tags_ ) {} |
14589 | |
14590 | AutoReg::AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept { |
14591 | CATCH_TRY { |
14592 | getMutableRegistryHub() |
14593 | .registerTest( |
14594 | makeTestCase( |
14595 | invoker, |
14596 | extractClassName( classOrMethod ), |
14597 | nameAndTags, |
14598 | lineInfo)); |
14599 | } CATCH_CATCH_ALL { |
14600 | // Do not throw when constructing global objects, instead register the exception to be processed later |
14601 | getMutableRegistryHub().registerStartupException(); |
14602 | } |
14603 | } |
14604 | |
14605 | AutoReg::~AutoReg() = default; |
14606 | } |
14607 | // end catch_test_registry.cpp |
14608 | // start catch_test_spec.cpp |
14609 | |
14610 | #include <algorithm> |
14611 | #include <string> |
14612 | #include <vector> |
14613 | #include <memory> |
14614 | |
14615 | namespace Catch { |
14616 | |
14617 | TestSpec::Pattern::Pattern( std::string const& name ) |
14618 | : m_name( name ) |
14619 | {} |
14620 | |
14621 | TestSpec::Pattern::~Pattern() = default; |
14622 | |
14623 | std::string const& TestSpec::Pattern::name() const { |
14624 | return m_name; |
14625 | } |
14626 | |
14627 | TestSpec::NamePattern::NamePattern( std::string const& name, std::string const& filterString ) |
14628 | : Pattern( filterString ) |
14629 | , m_wildcardPattern( toLower( name ), CaseSensitive::No ) |
14630 | {} |
14631 | |
14632 | bool TestSpec::NamePattern::matches( TestCaseInfo const& testCase ) const { |
14633 | return m_wildcardPattern.matches( testCase.name ); |
14634 | } |
14635 | |
14636 | TestSpec::TagPattern::TagPattern( std::string const& tag, std::string const& filterString ) |
14637 | : Pattern( filterString ) |
14638 | , m_tag( toLower( tag ) ) |
14639 | {} |
14640 | |
14641 | bool TestSpec::TagPattern::matches( TestCaseInfo const& testCase ) const { |
14642 | return std::find(begin(testCase.lcaseTags), |
14643 | end(testCase.lcaseTags), |
14644 | m_tag) != end(testCase.lcaseTags); |
14645 | } |
14646 | |
14647 | TestSpec::ExcludedPattern::ExcludedPattern( PatternPtr const& underlyingPattern ) |
14648 | : Pattern( underlyingPattern->name() ) |
14649 | , m_underlyingPattern( underlyingPattern ) |
14650 | {} |
14651 | |
14652 | bool TestSpec::ExcludedPattern::matches( TestCaseInfo const& testCase ) const { |
14653 | return !m_underlyingPattern->matches( testCase ); |
14654 | } |
14655 | |
14656 | bool TestSpec::Filter::matches( TestCaseInfo const& testCase ) const { |
14657 | return std::all_of( m_patterns.begin(), m_patterns.end(), [&]( PatternPtr const& p ){ return p->matches( testCase ); } ); |
14658 | } |
14659 | |
14660 | std::string TestSpec::Filter::name() const { |
14661 | std::string name; |
14662 | for( auto const& p : m_patterns ) |
14663 | name += p->name(); |
14664 | return name; |
14665 | } |
14666 | |
14667 | bool TestSpec::hasFilters() const { |
14668 | return !m_filters.empty(); |
14669 | } |
14670 | |
14671 | bool TestSpec::matches( TestCaseInfo const& testCase ) const { |
14672 | return std::any_of( m_filters.begin(), m_filters.end(), [&]( Filter const& f ){ return f.matches( testCase ); } ); |
14673 | } |
14674 | |
14675 | TestSpec::Matches TestSpec::matchesByFilter( std::vector<TestCase> const& testCases, IConfig const& config ) const |
14676 | { |
14677 | Matches matches( m_filters.size() ); |
14678 | std::transform( m_filters.begin(), m_filters.end(), matches.begin(), [&]( Filter const& filter ){ |
14679 | std::vector<TestCase const*> currentMatches; |
14680 | for( auto const& test : testCases ) |
14681 | if( isThrowSafe( test, config ) && filter.matches( test ) ) |
14682 | currentMatches.emplace_back( &test ); |
14683 | return FilterMatch{ filter.name(), currentMatches }; |
14684 | } ); |
14685 | return matches; |
14686 | } |
14687 | |
14688 | const TestSpec::vectorStrings& TestSpec::getInvalidArgs() const{ |
14689 | return (m_invalidArgs); |
14690 | } |
14691 | |
14692 | } |
14693 | // end catch_test_spec.cpp |
14694 | // start catch_test_spec_parser.cpp |
14695 | |
14696 | namespace Catch { |
14697 | |
14698 | TestSpecParser::TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {} |
14699 | |
14700 | TestSpecParser& TestSpecParser::parse( std::string const& arg ) { |
14701 | m_mode = None; |
14702 | m_exclusion = false; |
14703 | m_arg = m_tagAliases->expandAliases( arg ); |
14704 | m_escapeChars.clear(); |
14705 | m_substring.reserve(m_arg.size()); |
14706 | m_patternName.reserve(m_arg.size()); |
14707 | m_realPatternPos = 0; |
14708 | |
14709 | for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) |
14710 | //if visitChar fails |
14711 | if( !visitChar( m_arg[m_pos] ) ){ |
14712 | m_testSpec.m_invalidArgs.push_back(arg); |
14713 | break; |
14714 | } |
14715 | endMode(); |
14716 | return *this; |
14717 | } |
14718 | TestSpec TestSpecParser::testSpec() { |
14719 | addFilter(); |
14720 | return m_testSpec; |
14721 | } |
14722 | bool TestSpecParser::visitChar( char c ) { |
14723 | if( (m_mode != EscapedName) && (c == '\\') ) { |
14724 | escape(); |
14725 | addCharToPattern(c); |
14726 | return true; |
14727 | }else if((m_mode != EscapedName) && (c == ',') ) { |
14728 | return separate(); |
14729 | } |
14730 | |
14731 | switch( m_mode ) { |
14732 | case None: |
14733 | if( processNoneChar( c ) ) |
14734 | return true; |
14735 | break; |
14736 | case Name: |
14737 | processNameChar( c ); |
14738 | break; |
14739 | case EscapedName: |
14740 | endMode(); |
14741 | addCharToPattern(c); |
14742 | return true; |
14743 | default: |
14744 | case Tag: |
14745 | case QuotedName: |
14746 | if( processOtherChar( c ) ) |
14747 | return true; |
14748 | break; |
14749 | } |
14750 | |
14751 | m_substring += c; |
14752 | if( !isControlChar( c ) ) { |
14753 | m_patternName += c; |
14754 | m_realPatternPos++; |
14755 | } |
14756 | return true; |
14757 | } |
14758 | // Two of the processing methods return true to signal the caller to return |
14759 | // without adding the given character to the current pattern strings |
14760 | bool TestSpecParser::processNoneChar( char c ) { |
14761 | switch( c ) { |
14762 | case ' ': |
14763 | return true; |
14764 | case '~': |
14765 | m_exclusion = true; |
14766 | return false; |
14767 | case '[': |
14768 | startNewMode( Tag ); |
14769 | return false; |
14770 | case '"': |
14771 | startNewMode( QuotedName ); |
14772 | return false; |
14773 | default: |
14774 | startNewMode( Name ); |
14775 | return false; |
14776 | } |
14777 | } |
14778 | void TestSpecParser::processNameChar( char c ) { |
14779 | if( c == '[' ) { |
14780 | if( m_substring == "exclude:" ) |
14781 | m_exclusion = true; |
14782 | else |
14783 | endMode(); |
14784 | startNewMode( Tag ); |
14785 | } |
14786 | } |
14787 | bool TestSpecParser::processOtherChar( char c ) { |
14788 | if( !isControlChar( c ) ) |
14789 | return false; |
14790 | m_substring += c; |
14791 | endMode(); |
14792 | return true; |
14793 | } |
14794 | void TestSpecParser::startNewMode( Mode mode ) { |
14795 | m_mode = mode; |
14796 | } |
14797 | void TestSpecParser::endMode() { |
14798 | switch( m_mode ) { |
14799 | case Name: |
14800 | case QuotedName: |
14801 | return addNamePattern(); |
14802 | case Tag: |
14803 | return addTagPattern(); |
14804 | case EscapedName: |
14805 | revertBackToLastMode(); |
14806 | return; |
14807 | case None: |
14808 | default: |
14809 | return startNewMode( None ); |
14810 | } |
14811 | } |
14812 | void TestSpecParser::escape() { |
14813 | saveLastMode(); |
14814 | m_mode = EscapedName; |
14815 | m_escapeChars.push_back(m_realPatternPos); |
14816 | } |
14817 | bool TestSpecParser::isControlChar( char c ) const { |
14818 | switch( m_mode ) { |
14819 | default: |
14820 | return false; |
14821 | case None: |
14822 | return c == '~'; |
14823 | case Name: |
14824 | return c == '['; |
14825 | case EscapedName: |
14826 | return true; |
14827 | case QuotedName: |
14828 | return c == '"'; |
14829 | case Tag: |
14830 | return c == '[' || c == ']'; |
14831 | } |
14832 | } |
14833 | |
14834 | void TestSpecParser::addFilter() { |
14835 | if( !m_currentFilter.m_patterns.empty() ) { |
14836 | m_testSpec.m_filters.push_back( m_currentFilter ); |
14837 | m_currentFilter = TestSpec::Filter(); |
14838 | } |
14839 | } |
14840 | |
14841 | void TestSpecParser::saveLastMode() { |
14842 | lastMode = m_mode; |
14843 | } |
14844 | |
14845 | void TestSpecParser::revertBackToLastMode() { |
14846 | m_mode = lastMode; |
14847 | } |
14848 | |
14849 | bool TestSpecParser::separate() { |
14850 | if( (m_mode==QuotedName) || (m_mode==Tag) ){ |
14851 | //invalid argument, signal failure to previous scope. |
14852 | m_mode = None; |
14853 | m_pos = m_arg.size(); |
14854 | m_substring.clear(); |
14855 | m_patternName.clear(); |
14856 | m_realPatternPos = 0; |
14857 | return false; |
14858 | } |
14859 | endMode(); |
14860 | addFilter(); |
14861 | return true; //success |
14862 | } |
14863 | |
14864 | std::string TestSpecParser::preprocessPattern() { |
14865 | std::string token = m_patternName; |
14866 | for (std::size_t i = 0; i < m_escapeChars.size(); ++i) |
14867 | token = token.substr(0, m_escapeChars[i] - i) + token.substr(m_escapeChars[i] - i + 1); |
14868 | m_escapeChars.clear(); |
14869 | if (startsWith(token, "exclude:" )) { |
14870 | m_exclusion = true; |
14871 | token = token.substr(8); |
14872 | } |
14873 | |
14874 | m_patternName.clear(); |
14875 | m_realPatternPos = 0; |
14876 | |
14877 | return token; |
14878 | } |
14879 | |
14880 | void TestSpecParser::addNamePattern() { |
14881 | auto token = preprocessPattern(); |
14882 | |
14883 | if (!token.empty()) { |
14884 | TestSpec::PatternPtr pattern = std::make_shared<TestSpec::NamePattern>(token, m_substring); |
14885 | if (m_exclusion) |
14886 | pattern = std::make_shared<TestSpec::ExcludedPattern>(pattern); |
14887 | m_currentFilter.m_patterns.push_back(pattern); |
14888 | } |
14889 | m_substring.clear(); |
14890 | m_exclusion = false; |
14891 | m_mode = None; |
14892 | } |
14893 | |
14894 | void TestSpecParser::addTagPattern() { |
14895 | auto token = preprocessPattern(); |
14896 | |
14897 | if (!token.empty()) { |
14898 | // If the tag pattern is the "hide and tag" shorthand (e.g. [.foo]) |
14899 | // we have to create a separate hide tag and shorten the real one |
14900 | if (token.size() > 1 && token[0] == '.') { |
14901 | token.erase(token.begin()); |
14902 | TestSpec::PatternPtr pattern = std::make_shared<TestSpec::TagPattern>("." , m_substring); |
14903 | if (m_exclusion) { |
14904 | pattern = std::make_shared<TestSpec::ExcludedPattern>(pattern); |
14905 | } |
14906 | m_currentFilter.m_patterns.push_back(pattern); |
14907 | } |
14908 | |
14909 | TestSpec::PatternPtr pattern = std::make_shared<TestSpec::TagPattern>(token, m_substring); |
14910 | |
14911 | if (m_exclusion) { |
14912 | pattern = std::make_shared<TestSpec::ExcludedPattern>(pattern); |
14913 | } |
14914 | m_currentFilter.m_patterns.push_back(pattern); |
14915 | } |
14916 | m_substring.clear(); |
14917 | m_exclusion = false; |
14918 | m_mode = None; |
14919 | } |
14920 | |
14921 | TestSpec parseTestSpec( std::string const& arg ) { |
14922 | return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); |
14923 | } |
14924 | |
14925 | } // namespace Catch |
14926 | // end catch_test_spec_parser.cpp |
14927 | // start catch_timer.cpp |
14928 | |
14929 | #include <chrono> |
14930 | |
14931 | static const uint64_t nanosecondsInSecond = 1000000000; |
14932 | |
14933 | namespace Catch { |
14934 | |
14935 | auto getCurrentNanosecondsSinceEpoch() -> uint64_t { |
14936 | return std::chrono::duration_cast<std::chrono::nanoseconds>( std::chrono::high_resolution_clock::now().time_since_epoch() ).count(); |
14937 | } |
14938 | |
14939 | namespace { |
14940 | auto estimateClockResolution() -> uint64_t { |
14941 | uint64_t sum = 0; |
14942 | static const uint64_t iterations = 1000000; |
14943 | |
14944 | auto startTime = getCurrentNanosecondsSinceEpoch(); |
14945 | |
14946 | for( std::size_t i = 0; i < iterations; ++i ) { |
14947 | |
14948 | uint64_t ticks; |
14949 | uint64_t baseTicks = getCurrentNanosecondsSinceEpoch(); |
14950 | do { |
14951 | ticks = getCurrentNanosecondsSinceEpoch(); |
14952 | } while( ticks == baseTicks ); |
14953 | |
14954 | auto delta = ticks - baseTicks; |
14955 | sum += delta; |
14956 | |
14957 | // If we have been calibrating for over 3 seconds -- the clock |
14958 | // is terrible and we should move on. |
14959 | // TBD: How to signal that the measured resolution is probably wrong? |
14960 | if (ticks > startTime + 3 * nanosecondsInSecond) { |
14961 | return sum / ( i + 1u ); |
14962 | } |
14963 | } |
14964 | |
14965 | // We're just taking the mean, here. To do better we could take the std. dev and exclude outliers |
14966 | // - and potentially do more iterations if there's a high variance. |
14967 | return sum/iterations; |
14968 | } |
14969 | } |
14970 | auto getEstimatedClockResolution() -> uint64_t { |
14971 | static auto s_resolution = estimateClockResolution(); |
14972 | return s_resolution; |
14973 | } |
14974 | |
14975 | void Timer::start() { |
14976 | m_nanoseconds = getCurrentNanosecondsSinceEpoch(); |
14977 | } |
14978 | auto Timer::getElapsedNanoseconds() const -> uint64_t { |
14979 | return getCurrentNanosecondsSinceEpoch() - m_nanoseconds; |
14980 | } |
14981 | auto Timer::getElapsedMicroseconds() const -> uint64_t { |
14982 | return getElapsedNanoseconds()/1000; |
14983 | } |
14984 | auto Timer::getElapsedMilliseconds() const -> unsigned int { |
14985 | return static_cast<unsigned int>(getElapsedMicroseconds()/1000); |
14986 | } |
14987 | auto Timer::getElapsedSeconds() const -> double { |
14988 | return getElapsedMicroseconds()/1000000.0; |
14989 | } |
14990 | |
14991 | } // namespace Catch |
14992 | // end catch_timer.cpp |
14993 | // start catch_tostring.cpp |
14994 | |
14995 | #if defined(__clang__) |
14996 | # pragma clang diagnostic push |
14997 | # pragma clang diagnostic ignored "-Wexit-time-destructors" |
14998 | # pragma clang diagnostic ignored "-Wglobal-constructors" |
14999 | #endif |
15000 | |
15001 | // Enable specific decls locally |
15002 | #if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) |
15003 | #define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER |
15004 | #endif |
15005 | |
15006 | #include <cmath> |
15007 | #include <iomanip> |
15008 | |
15009 | namespace Catch { |
15010 | |
15011 | namespace Detail { |
15012 | |
15013 | const std::string unprintableString = "{?}" ; |
15014 | |
15015 | namespace { |
15016 | const int hexThreshold = 255; |
15017 | |
15018 | struct Endianness { |
15019 | enum Arch { Big, Little }; |
15020 | |
15021 | static Arch which() { |
15022 | int one = 1; |
15023 | // If the lowest byte we read is non-zero, we can assume |
15024 | // that little endian format is used. |
15025 | auto value = *reinterpret_cast<char*>(&one); |
15026 | return value ? Little : Big; |
15027 | } |
15028 | }; |
15029 | } |
15030 | |
15031 | std::string rawMemoryToString( const void *object, std::size_t size ) { |
15032 | // Reverse order for little endian architectures |
15033 | int i = 0, end = static_cast<int>( size ), inc = 1; |
15034 | if( Endianness::which() == Endianness::Little ) { |
15035 | i = end-1; |
15036 | end = inc = -1; |
15037 | } |
15038 | |
15039 | unsigned char const *bytes = static_cast<unsigned char const *>(object); |
15040 | ReusableStringStream ; |
15041 | rss << "0x" << std::setfill('0') << std::hex; |
15042 | for( ; i != end; i += inc ) |
15043 | rss << std::setw(2) << static_cast<unsigned>(bytes[i]); |
15044 | return rss.str(); |
15045 | } |
15046 | } |
15047 | |
15048 | template<typename T> |
15049 | std::string fpToString( T value, int precision ) { |
15050 | if (Catch::isnan(value)) { |
15051 | return "nan" ; |
15052 | } |
15053 | |
15054 | ReusableStringStream ; |
15055 | rss << std::setprecision( precision ) |
15056 | << std::fixed |
15057 | << value; |
15058 | std::string d = rss.str(); |
15059 | std::size_t i = d.find_last_not_of( '0' ); |
15060 | if( i != std::string::npos && i != d.size()-1 ) { |
15061 | if( d[i] == '.' ) |
15062 | i++; |
15063 | d = d.substr( 0, i+1 ); |
15064 | } |
15065 | return d; |
15066 | } |
15067 | |
15068 | //// ======================================================= //// |
15069 | // |
15070 | // Out-of-line defs for full specialization of StringMaker |
15071 | // |
15072 | //// ======================================================= //// |
15073 | |
15074 | std::string StringMaker<std::string>::convert(const std::string& str) { |
15075 | if (!getCurrentContext().getConfig()->showInvisibles()) { |
15076 | return '"' + str + '"'; |
15077 | } |
15078 | |
15079 | std::string s("\"" ); |
15080 | for (char c : str) { |
15081 | switch (c) { |
15082 | case '\n': |
15083 | s.append("\\n" ); |
15084 | break; |
15085 | case '\t': |
15086 | s.append("\\t" ); |
15087 | break; |
15088 | default: |
15089 | s.push_back(c); |
15090 | break; |
15091 | } |
15092 | } |
15093 | s.append("\"" ); |
15094 | return s; |
15095 | } |
15096 | |
15097 | #ifdef CATCH_CONFIG_CPP17_STRING_VIEW |
15098 | std::string StringMaker<std::string_view>::convert(std::string_view str) { |
15099 | return ::Catch::Detail::stringify(std::string{ str }); |
15100 | } |
15101 | #endif |
15102 | |
15103 | std::string StringMaker<char const*>::convert(char const* str) { |
15104 | if (str) { |
15105 | return ::Catch::Detail::stringify(std::string{ str }); |
15106 | } else { |
15107 | return{ "{null string}" }; |
15108 | } |
15109 | } |
15110 | std::string StringMaker<char*>::convert(char* str) { |
15111 | if (str) { |
15112 | return ::Catch::Detail::stringify(std::string{ str }); |
15113 | } else { |
15114 | return{ "{null string}" }; |
15115 | } |
15116 | } |
15117 | |
15118 | #ifdef CATCH_CONFIG_WCHAR |
15119 | std::string StringMaker<std::wstring>::convert(const std::wstring& wstr) { |
15120 | std::string s; |
15121 | s.reserve(wstr.size()); |
15122 | for (auto c : wstr) { |
15123 | s += (c <= 0xff) ? static_cast<char>(c) : '?'; |
15124 | } |
15125 | return ::Catch::Detail::stringify(s); |
15126 | } |
15127 | |
15128 | # ifdef CATCH_CONFIG_CPP17_STRING_VIEW |
15129 | std::string StringMaker<std::wstring_view>::convert(std::wstring_view str) { |
15130 | return StringMaker<std::wstring>::convert(std::wstring(str)); |
15131 | } |
15132 | # endif |
15133 | |
15134 | std::string StringMaker<wchar_t const*>::convert(wchar_t const * str) { |
15135 | if (str) { |
15136 | return ::Catch::Detail::stringify(std::wstring{ str }); |
15137 | } else { |
15138 | return{ "{null string}" }; |
15139 | } |
15140 | } |
15141 | std::string StringMaker<wchar_t *>::convert(wchar_t * str) { |
15142 | if (str) { |
15143 | return ::Catch::Detail::stringify(std::wstring{ str }); |
15144 | } else { |
15145 | return{ "{null string}" }; |
15146 | } |
15147 | } |
15148 | #endif |
15149 | |
15150 | #if defined(CATCH_CONFIG_CPP17_BYTE) |
15151 | #include <cstddef> |
15152 | std::string StringMaker<std::byte>::convert(std::byte value) { |
15153 | return ::Catch::Detail::stringify(std::to_integer<unsigned long long>(value)); |
15154 | } |
15155 | #endif // defined(CATCH_CONFIG_CPP17_BYTE) |
15156 | |
15157 | std::string StringMaker<int>::convert(int value) { |
15158 | return ::Catch::Detail::stringify(static_cast<long long>(value)); |
15159 | } |
15160 | std::string StringMaker<long>::convert(long value) { |
15161 | return ::Catch::Detail::stringify(static_cast<long long>(value)); |
15162 | } |
15163 | std::string StringMaker<long long>::convert(long long value) { |
15164 | ReusableStringStream ; |
15165 | rss << value; |
15166 | if (value > Detail::hexThreshold) { |
15167 | rss << " (0x" << std::hex << value << ')'; |
15168 | } |
15169 | return rss.str(); |
15170 | } |
15171 | |
15172 | std::string StringMaker<unsigned int>::convert(unsigned int value) { |
15173 | return ::Catch::Detail::stringify(static_cast<unsigned long long>(value)); |
15174 | } |
15175 | std::string StringMaker<unsigned long>::convert(unsigned long value) { |
15176 | return ::Catch::Detail::stringify(static_cast<unsigned long long>(value)); |
15177 | } |
15178 | std::string StringMaker<unsigned long long>::convert(unsigned long long value) { |
15179 | ReusableStringStream ; |
15180 | rss << value; |
15181 | if (value > Detail::hexThreshold) { |
15182 | rss << " (0x" << std::hex << value << ')'; |
15183 | } |
15184 | return rss.str(); |
15185 | } |
15186 | |
15187 | std::string StringMaker<bool>::convert(bool b) { |
15188 | return b ? "true" : "false" ; |
15189 | } |
15190 | |
15191 | std::string StringMaker<signed char>::convert(signed char value) { |
15192 | if (value == '\r') { |
15193 | return "'\\r'" ; |
15194 | } else if (value == '\f') { |
15195 | return "'\\f'" ; |
15196 | } else if (value == '\n') { |
15197 | return "'\\n'" ; |
15198 | } else if (value == '\t') { |
15199 | return "'\\t'" ; |
15200 | } else if ('\0' <= value && value < ' ') { |
15201 | return ::Catch::Detail::stringify(static_cast<unsigned int>(value)); |
15202 | } else { |
15203 | char chstr[] = "' '" ; |
15204 | chstr[1] = value; |
15205 | return chstr; |
15206 | } |
15207 | } |
15208 | std::string StringMaker<char>::convert(char c) { |
15209 | return ::Catch::Detail::stringify(static_cast<signed char>(c)); |
15210 | } |
15211 | std::string StringMaker<unsigned char>::convert(unsigned char c) { |
15212 | return ::Catch::Detail::stringify(static_cast<char>(c)); |
15213 | } |
15214 | |
15215 | std::string StringMaker<std::nullptr_t>::convert(std::nullptr_t) { |
15216 | return "nullptr" ; |
15217 | } |
15218 | |
15219 | int StringMaker<float>::precision = 5; |
15220 | |
15221 | std::string StringMaker<float>::convert(float value) { |
15222 | return fpToString(value, precision) + 'f'; |
15223 | } |
15224 | |
15225 | int StringMaker<double>::precision = 10; |
15226 | |
15227 | std::string StringMaker<double>::convert(double value) { |
15228 | return fpToString(value, precision); |
15229 | } |
15230 | |
15231 | std::string ratio_string<std::atto>::symbol() { return "a" ; } |
15232 | std::string ratio_string<std::femto>::symbol() { return "f" ; } |
15233 | std::string ratio_string<std::pico>::symbol() { return "p" ; } |
15234 | std::string ratio_string<std::nano>::symbol() { return "n" ; } |
15235 | std::string ratio_string<std::micro>::symbol() { return "u" ; } |
15236 | std::string ratio_string<std::milli>::symbol() { return "m" ; } |
15237 | |
15238 | } // end namespace Catch |
15239 | |
15240 | #if defined(__clang__) |
15241 | # pragma clang diagnostic pop |
15242 | #endif |
15243 | |
15244 | // end catch_tostring.cpp |
15245 | // start catch_totals.cpp |
15246 | |
15247 | namespace Catch { |
15248 | |
15249 | Counts Counts::operator - ( Counts const& other ) const { |
15250 | Counts diff; |
15251 | diff.passed = passed - other.passed; |
15252 | diff.failed = failed - other.failed; |
15253 | diff.failedButOk = failedButOk - other.failedButOk; |
15254 | return diff; |
15255 | } |
15256 | |
15257 | Counts& Counts::operator += ( Counts const& other ) { |
15258 | passed += other.passed; |
15259 | failed += other.failed; |
15260 | failedButOk += other.failedButOk; |
15261 | return *this; |
15262 | } |
15263 | |
15264 | std::size_t Counts::total() const { |
15265 | return passed + failed + failedButOk; |
15266 | } |
15267 | bool Counts::allPassed() const { |
15268 | return failed == 0 && failedButOk == 0; |
15269 | } |
15270 | bool Counts::allOk() const { |
15271 | return failed == 0; |
15272 | } |
15273 | |
15274 | Totals Totals::operator - ( Totals const& other ) const { |
15275 | Totals diff; |
15276 | diff.assertions = assertions - other.assertions; |
15277 | diff.testCases = testCases - other.testCases; |
15278 | return diff; |
15279 | } |
15280 | |
15281 | Totals& Totals::operator += ( Totals const& other ) { |
15282 | assertions += other.assertions; |
15283 | testCases += other.testCases; |
15284 | return *this; |
15285 | } |
15286 | |
15287 | Totals Totals::delta( Totals const& prevTotals ) const { |
15288 | Totals diff = *this - prevTotals; |
15289 | if( diff.assertions.failed > 0 ) |
15290 | ++diff.testCases.failed; |
15291 | else if( diff.assertions.failedButOk > 0 ) |
15292 | ++diff.testCases.failedButOk; |
15293 | else |
15294 | ++diff.testCases.passed; |
15295 | return diff; |
15296 | } |
15297 | |
15298 | } |
15299 | // end catch_totals.cpp |
15300 | // start catch_uncaught_exceptions.cpp |
15301 | |
15302 | // start catch_config_uncaught_exceptions.hpp |
15303 | |
15304 | // Copyright Catch2 Authors |
15305 | // Distributed under the Boost Software License, Version 1.0. |
15306 | // (See accompanying file LICENSE_1_0.txt or copy at |
15307 | // https://www.boost.org/LICENSE_1_0.txt) |
15308 | |
15309 | // SPDX-License-Identifier: BSL-1.0 |
15310 | |
15311 | #ifndef CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP |
15312 | #define CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP |
15313 | |
15314 | #if defined(_MSC_VER) |
15315 | # if _MSC_VER >= 1900 // Visual Studio 2015 or newer |
15316 | # define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS |
15317 | # endif |
15318 | #endif |
15319 | |
15320 | #include <exception> |
15321 | |
15322 | #if defined(__cpp_lib_uncaught_exceptions) \ |
15323 | && !defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) |
15324 | |
15325 | # define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS |
15326 | #endif // __cpp_lib_uncaught_exceptions |
15327 | |
15328 | #if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) \ |
15329 | && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) \ |
15330 | && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) |
15331 | |
15332 | # define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS |
15333 | #endif |
15334 | |
15335 | #endif // CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP |
15336 | // end catch_config_uncaught_exceptions.hpp |
15337 | #include <exception> |
15338 | |
15339 | namespace Catch { |
15340 | bool uncaught_exceptions() { |
15341 | #if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) |
15342 | return false; |
15343 | #elif defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) |
15344 | return std::uncaught_exceptions() > 0; |
15345 | #else |
15346 | return std::uncaught_exception(); |
15347 | #endif |
15348 | } |
15349 | } // end namespace Catch |
15350 | // end catch_uncaught_exceptions.cpp |
15351 | // start catch_version.cpp |
15352 | |
15353 | #include <ostream> |
15354 | |
15355 | namespace Catch { |
15356 | |
15357 | Version::Version |
15358 | ( unsigned int _majorVersion, |
15359 | unsigned int _minorVersion, |
15360 | unsigned int _patchNumber, |
15361 | char const * const _branchName, |
15362 | unsigned int _buildNumber ) |
15363 | : majorVersion( _majorVersion ), |
15364 | minorVersion( _minorVersion ), |
15365 | patchNumber( _patchNumber ), |
15366 | branchName( _branchName ), |
15367 | buildNumber( _buildNumber ) |
15368 | {} |
15369 | |
15370 | std::ostream& operator << ( std::ostream& os, Version const& version ) { |
15371 | os << version.majorVersion << '.' |
15372 | << version.minorVersion << '.' |
15373 | << version.patchNumber; |
15374 | // branchName is never null -> 0th char is \0 if it is empty |
15375 | if (version.branchName[0]) { |
15376 | os << '-' << version.branchName |
15377 | << '.' << version.buildNumber; |
15378 | } |
15379 | return os; |
15380 | } |
15381 | |
15382 | Version const& libraryVersion() { |
15383 | static Version version( 2, 13, 7, "" , 0 ); |
15384 | return version; |
15385 | } |
15386 | |
15387 | } |
15388 | // end catch_version.cpp |
15389 | // start catch_wildcard_pattern.cpp |
15390 | |
15391 | namespace Catch { |
15392 | |
15393 | WildcardPattern::WildcardPattern( std::string const& pattern, |
15394 | CaseSensitive::Choice caseSensitivity ) |
15395 | : m_caseSensitivity( caseSensitivity ), |
15396 | m_pattern( normaliseString( pattern ) ) |
15397 | { |
15398 | if( startsWith( m_pattern, '*' ) ) { |
15399 | m_pattern = m_pattern.substr( 1 ); |
15400 | m_wildcard = WildcardAtStart; |
15401 | } |
15402 | if( endsWith( m_pattern, '*' ) ) { |
15403 | m_pattern = m_pattern.substr( 0, m_pattern.size()-1 ); |
15404 | m_wildcard = static_cast<WildcardPosition>( m_wildcard | WildcardAtEnd ); |
15405 | } |
15406 | } |
15407 | |
15408 | bool WildcardPattern::matches( std::string const& str ) const { |
15409 | switch( m_wildcard ) { |
15410 | case NoWildcard: |
15411 | return m_pattern == normaliseString( str ); |
15412 | case WildcardAtStart: |
15413 | return endsWith( normaliseString( str ), m_pattern ); |
15414 | case WildcardAtEnd: |
15415 | return startsWith( normaliseString( str ), m_pattern ); |
15416 | case WildcardAtBothEnds: |
15417 | return contains( normaliseString( str ), m_pattern ); |
15418 | default: |
15419 | CATCH_INTERNAL_ERROR( "Unknown enum" ); |
15420 | } |
15421 | } |
15422 | |
15423 | std::string WildcardPattern::normaliseString( std::string const& str ) const { |
15424 | return trim( m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str ); |
15425 | } |
15426 | } |
15427 | // end catch_wildcard_pattern.cpp |
15428 | // start catch_xmlwriter.cpp |
15429 | |
15430 | #include <iomanip> |
15431 | #include <type_traits> |
15432 | |
15433 | namespace Catch { |
15434 | |
15435 | namespace { |
15436 | |
15437 | size_t trailingBytes(unsigned char c) { |
15438 | if ((c & 0xE0) == 0xC0) { |
15439 | return 2; |
15440 | } |
15441 | if ((c & 0xF0) == 0xE0) { |
15442 | return 3; |
15443 | } |
15444 | if ((c & 0xF8) == 0xF0) { |
15445 | return 4; |
15446 | } |
15447 | CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered" ); |
15448 | } |
15449 | |
15450 | uint32_t (unsigned char c) { |
15451 | if ((c & 0xE0) == 0xC0) { |
15452 | return c & 0x1F; |
15453 | } |
15454 | if ((c & 0xF0) == 0xE0) { |
15455 | return c & 0x0F; |
15456 | } |
15457 | if ((c & 0xF8) == 0xF0) { |
15458 | return c & 0x07; |
15459 | } |
15460 | CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered" ); |
15461 | } |
15462 | |
15463 | void hexEscapeChar(std::ostream& os, unsigned char c) { |
15464 | std::ios_base::fmtflags f(os.flags()); |
15465 | os << "\\x" |
15466 | << std::uppercase << std::hex << std::setfill('0') << std::setw(2) |
15467 | << static_cast<int>(c); |
15468 | os.flags(f); |
15469 | } |
15470 | |
15471 | bool shouldNewline(XmlFormatting fmt) { |
15472 | return !!(static_cast<std::underlying_type<XmlFormatting>::type>(fmt & XmlFormatting::Newline)); |
15473 | } |
15474 | |
15475 | bool shouldIndent(XmlFormatting fmt) { |
15476 | return !!(static_cast<std::underlying_type<XmlFormatting>::type>(fmt & XmlFormatting::Indent)); |
15477 | } |
15478 | |
15479 | } // anonymous namespace |
15480 | |
15481 | XmlFormatting operator | (XmlFormatting lhs, XmlFormatting rhs) { |
15482 | return static_cast<XmlFormatting>( |
15483 | static_cast<std::underlying_type<XmlFormatting>::type>(lhs) | |
15484 | static_cast<std::underlying_type<XmlFormatting>::type>(rhs) |
15485 | ); |
15486 | } |
15487 | |
15488 | XmlFormatting operator & (XmlFormatting lhs, XmlFormatting rhs) { |
15489 | return static_cast<XmlFormatting>( |
15490 | static_cast<std::underlying_type<XmlFormatting>::type>(lhs) & |
15491 | static_cast<std::underlying_type<XmlFormatting>::type>(rhs) |
15492 | ); |
15493 | } |
15494 | |
15495 | XmlEncode::XmlEncode( std::string const& str, ForWhat forWhat ) |
15496 | : m_str( str ), |
15497 | m_forWhat( forWhat ) |
15498 | {} |
15499 | |
15500 | void XmlEncode::encodeTo( std::ostream& os ) const { |
15501 | // Apostrophe escaping not necessary if we always use " to write attributes |
15502 | // (see: http://www.w3.org/TR/xml/#syntax) |
15503 | |
15504 | for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) { |
15505 | unsigned char c = m_str[idx]; |
15506 | switch (c) { |
15507 | case '<': os << "<" ; break; |
15508 | case '&': os << "&" ; break; |
15509 | |
15510 | case '>': |
15511 | // See: http://www.w3.org/TR/xml/#syntax |
15512 | if (idx > 2 && m_str[idx - 1] == ']' && m_str[idx - 2] == ']') |
15513 | os << ">" ; |
15514 | else |
15515 | os << c; |
15516 | break; |
15517 | |
15518 | case '\"': |
15519 | if (m_forWhat == ForAttributes) |
15520 | os << """ ; |
15521 | else |
15522 | os << c; |
15523 | break; |
15524 | |
15525 | default: |
15526 | // Check for control characters and invalid utf-8 |
15527 | |
15528 | // Escape control characters in standard ascii |
15529 | // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0 |
15530 | if (c < 0x09 || (c > 0x0D && c < 0x20) || c == 0x7F) { |
15531 | hexEscapeChar(os, c); |
15532 | break; |
15533 | } |
15534 | |
15535 | // Plain ASCII: Write it to stream |
15536 | if (c < 0x7F) { |
15537 | os << c; |
15538 | break; |
15539 | } |
15540 | |
15541 | // UTF-8 territory |
15542 | // Check if the encoding is valid and if it is not, hex escape bytes. |
15543 | // Important: We do not check the exact decoded values for validity, only the encoding format |
15544 | // First check that this bytes is a valid lead byte: |
15545 | // This means that it is not encoded as 1111 1XXX |
15546 | // Or as 10XX XXXX |
15547 | if (c < 0xC0 || |
15548 | c >= 0xF8) { |
15549 | hexEscapeChar(os, c); |
15550 | break; |
15551 | } |
15552 | |
15553 | auto encBytes = trailingBytes(c); |
15554 | // Are there enough bytes left to avoid accessing out-of-bounds memory? |
15555 | if (idx + encBytes - 1 >= m_str.size()) { |
15556 | hexEscapeChar(os, c); |
15557 | break; |
15558 | } |
15559 | // The header is valid, check data |
15560 | // The next encBytes bytes must together be a valid utf-8 |
15561 | // This means: bitpattern 10XX XXXX and the extracted value is sane (ish) |
15562 | bool valid = true; |
15563 | uint32_t value = headerValue(c); |
15564 | for (std::size_t n = 1; n < encBytes; ++n) { |
15565 | unsigned char nc = m_str[idx + n]; |
15566 | valid &= ((nc & 0xC0) == 0x80); |
15567 | value = (value << 6) | (nc & 0x3F); |
15568 | } |
15569 | |
15570 | if ( |
15571 | // Wrong bit pattern of following bytes |
15572 | (!valid) || |
15573 | // Overlong encodings |
15574 | (value < 0x80) || |
15575 | (0x80 <= value && value < 0x800 && encBytes > 2) || |
15576 | (0x800 < value && value < 0x10000 && encBytes > 3) || |
15577 | // Encoded value out of range |
15578 | (value >= 0x110000) |
15579 | ) { |
15580 | hexEscapeChar(os, c); |
15581 | break; |
15582 | } |
15583 | |
15584 | // If we got here, this is in fact a valid(ish) utf-8 sequence |
15585 | for (std::size_t n = 0; n < encBytes; ++n) { |
15586 | os << m_str[idx + n]; |
15587 | } |
15588 | idx += encBytes - 1; |
15589 | break; |
15590 | } |
15591 | } |
15592 | } |
15593 | |
15594 | std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { |
15595 | xmlEncode.encodeTo( os ); |
15596 | return os; |
15597 | } |
15598 | |
15599 | XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer, XmlFormatting fmt ) |
15600 | : m_writer( writer ), |
15601 | m_fmt(fmt) |
15602 | {} |
15603 | |
15604 | XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) noexcept |
15605 | : m_writer( other.m_writer ), |
15606 | m_fmt(other.m_fmt) |
15607 | { |
15608 | other.m_writer = nullptr; |
15609 | other.m_fmt = XmlFormatting::None; |
15610 | } |
15611 | XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) noexcept { |
15612 | if ( m_writer ) { |
15613 | m_writer->endElement(); |
15614 | } |
15615 | m_writer = other.m_writer; |
15616 | other.m_writer = nullptr; |
15617 | m_fmt = other.m_fmt; |
15618 | other.m_fmt = XmlFormatting::None; |
15619 | return *this; |
15620 | } |
15621 | |
15622 | XmlWriter::ScopedElement::~ScopedElement() { |
15623 | if (m_writer) { |
15624 | m_writer->endElement(m_fmt); |
15625 | } |
15626 | } |
15627 | |
15628 | XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, XmlFormatting fmt ) { |
15629 | m_writer->writeText( text, fmt ); |
15630 | return *this; |
15631 | } |
15632 | |
15633 | XmlWriter::XmlWriter( std::ostream& os ) : m_os( os ) |
15634 | { |
15635 | writeDeclaration(); |
15636 | } |
15637 | |
15638 | XmlWriter::~XmlWriter() { |
15639 | while (!m_tags.empty()) { |
15640 | endElement(); |
15641 | } |
15642 | newlineIfNecessary(); |
15643 | } |
15644 | |
15645 | XmlWriter& XmlWriter::startElement( std::string const& name, XmlFormatting fmt ) { |
15646 | ensureTagClosed(); |
15647 | newlineIfNecessary(); |
15648 | if (shouldIndent(fmt)) { |
15649 | m_os << m_indent; |
15650 | m_indent += " " ; |
15651 | } |
15652 | m_os << '<' << name; |
15653 | m_tags.push_back( name ); |
15654 | m_tagIsOpen = true; |
15655 | applyFormatting(fmt); |
15656 | return *this; |
15657 | } |
15658 | |
15659 | XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name, XmlFormatting fmt ) { |
15660 | ScopedElement scoped( this, fmt ); |
15661 | startElement( name, fmt ); |
15662 | return scoped; |
15663 | } |
15664 | |
15665 | XmlWriter& XmlWriter::endElement(XmlFormatting fmt) { |
15666 | m_indent = m_indent.substr(0, m_indent.size() - 2); |
15667 | |
15668 | if( m_tagIsOpen ) { |
15669 | m_os << "/>" ; |
15670 | m_tagIsOpen = false; |
15671 | } else { |
15672 | newlineIfNecessary(); |
15673 | if (shouldIndent(fmt)) { |
15674 | m_os << m_indent; |
15675 | } |
15676 | m_os << "</" << m_tags.back() << ">" ; |
15677 | } |
15678 | m_os << std::flush; |
15679 | applyFormatting(fmt); |
15680 | m_tags.pop_back(); |
15681 | return *this; |
15682 | } |
15683 | |
15684 | XmlWriter& XmlWriter::writeAttribute( std::string const& name, std::string const& attribute ) { |
15685 | if( !name.empty() && !attribute.empty() ) |
15686 | m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"'; |
15687 | return *this; |
15688 | } |
15689 | |
15690 | XmlWriter& XmlWriter::writeAttribute( std::string const& name, bool attribute ) { |
15691 | m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"'; |
15692 | return *this; |
15693 | } |
15694 | |
15695 | XmlWriter& XmlWriter::writeText( std::string const& text, XmlFormatting fmt) { |
15696 | if( !text.empty() ){ |
15697 | bool tagWasOpen = m_tagIsOpen; |
15698 | ensureTagClosed(); |
15699 | if (tagWasOpen && shouldIndent(fmt)) { |
15700 | m_os << m_indent; |
15701 | } |
15702 | m_os << XmlEncode( text ); |
15703 | applyFormatting(fmt); |
15704 | } |
15705 | return *this; |
15706 | } |
15707 | |
15708 | XmlWriter& XmlWriter::( std::string const& text, XmlFormatting fmt) { |
15709 | ensureTagClosed(); |
15710 | if (shouldIndent(fmt)) { |
15711 | m_os << m_indent; |
15712 | } |
15713 | m_os << "<!--" << text << "-->" ; |
15714 | applyFormatting(fmt); |
15715 | return *this; |
15716 | } |
15717 | |
15718 | void XmlWriter::writeStylesheetRef( std::string const& url ) { |
15719 | m_os << "<?xml-stylesheet type=\"text/xsl\" href=\"" << url << "\"?>\n" ; |
15720 | } |
15721 | |
15722 | XmlWriter& XmlWriter::writeBlankLine() { |
15723 | ensureTagClosed(); |
15724 | m_os << '\n'; |
15725 | return *this; |
15726 | } |
15727 | |
15728 | void XmlWriter::ensureTagClosed() { |
15729 | if( m_tagIsOpen ) { |
15730 | m_os << '>' << std::flush; |
15731 | newlineIfNecessary(); |
15732 | m_tagIsOpen = false; |
15733 | } |
15734 | } |
15735 | |
15736 | void XmlWriter::applyFormatting(XmlFormatting fmt) { |
15737 | m_needsNewline = shouldNewline(fmt); |
15738 | } |
15739 | |
15740 | void XmlWriter::writeDeclaration() { |
15741 | m_os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ; |
15742 | } |
15743 | |
15744 | void XmlWriter::newlineIfNecessary() { |
15745 | if( m_needsNewline ) { |
15746 | m_os << std::endl; |
15747 | m_needsNewline = false; |
15748 | } |
15749 | } |
15750 | } |
15751 | // end catch_xmlwriter.cpp |
15752 | // start catch_reporter_bases.cpp |
15753 | |
15754 | #include <cstring> |
15755 | #include <cfloat> |
15756 | #include <cstdio> |
15757 | #include <cassert> |
15758 | #include <memory> |
15759 | |
15760 | namespace Catch { |
15761 | void prepareExpandedExpression(AssertionResult& result) { |
15762 | result.getExpandedExpression(); |
15763 | } |
15764 | |
15765 | // Because formatting using c++ streams is stateful, drop down to C is required |
15766 | // Alternatively we could use stringstream, but its performance is... not good. |
15767 | std::string getFormattedDuration( double duration ) { |
15768 | // Max exponent + 1 is required to represent the whole part |
15769 | // + 1 for decimal point |
15770 | // + 3 for the 3 decimal places |
15771 | // + 1 for null terminator |
15772 | const std::size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1; |
15773 | char buffer[maxDoubleSize]; |
15774 | |
15775 | // Save previous errno, to prevent sprintf from overwriting it |
15776 | ErrnoGuard guard; |
15777 | #ifdef _MSC_VER |
15778 | sprintf_s(buffer, "%.3f" , duration); |
15779 | #else |
15780 | std::sprintf(buffer, "%.3f" , duration); |
15781 | #endif |
15782 | return std::string(buffer); |
15783 | } |
15784 | |
15785 | bool shouldShowDuration( IConfig const& config, double duration ) { |
15786 | if ( config.showDurations() == ShowDurations::Always ) { |
15787 | return true; |
15788 | } |
15789 | if ( config.showDurations() == ShowDurations::Never ) { |
15790 | return false; |
15791 | } |
15792 | const double min = config.minDuration(); |
15793 | return min >= 0 && duration >= min; |
15794 | } |
15795 | |
15796 | std::string serializeFilters( std::vector<std::string> const& container ) { |
15797 | ReusableStringStream oss; |
15798 | bool first = true; |
15799 | for (auto&& filter : container) |
15800 | { |
15801 | if (!first) |
15802 | oss << ' '; |
15803 | else |
15804 | first = false; |
15805 | |
15806 | oss << filter; |
15807 | } |
15808 | return oss.str(); |
15809 | } |
15810 | |
15811 | TestEventListenerBase::TestEventListenerBase(ReporterConfig const & _config) |
15812 | :StreamingReporterBase(_config) {} |
15813 | |
15814 | std::set<Verbosity> TestEventListenerBase::getSupportedVerbosities() { |
15815 | return { Verbosity::Quiet, Verbosity::Normal, Verbosity::High }; |
15816 | } |
15817 | |
15818 | void TestEventListenerBase::assertionStarting(AssertionInfo const &) {} |
15819 | |
15820 | bool TestEventListenerBase::assertionEnded(AssertionStats const &) { |
15821 | return false; |
15822 | } |
15823 | |
15824 | } // end namespace Catch |
15825 | // end catch_reporter_bases.cpp |
15826 | // start catch_reporter_compact.cpp |
15827 | |
15828 | namespace { |
15829 | |
15830 | #ifdef CATCH_PLATFORM_MAC |
15831 | const char* failedString() { return "FAILED" ; } |
15832 | const char* passedString() { return "PASSED" ; } |
15833 | #else |
15834 | const char* failedString() { return "failed" ; } |
15835 | const char* passedString() { return "passed" ; } |
15836 | #endif |
15837 | |
15838 | // Colour::LightGrey |
15839 | Catch::Colour::Code dimColour() { return Catch::Colour::FileName; } |
15840 | |
15841 | std::string bothOrAll( std::size_t count ) { |
15842 | return count == 1 ? std::string() : |
15843 | count == 2 ? "both " : "all " ; |
15844 | } |
15845 | |
15846 | } // anon namespace |
15847 | |
15848 | namespace Catch { |
15849 | namespace { |
15850 | // Colour, message variants: |
15851 | // - white: No tests ran. |
15852 | // - red: Failed [both/all] N test cases, failed [both/all] M assertions. |
15853 | // - white: Passed [both/all] N test cases (no assertions). |
15854 | // - red: Failed N tests cases, failed M assertions. |
15855 | // - green: Passed [both/all] N tests cases with M assertions. |
15856 | void printTotals(std::ostream& out, const Totals& totals) { |
15857 | if (totals.testCases.total() == 0) { |
15858 | out << "No tests ran." ; |
15859 | } else if (totals.testCases.failed == totals.testCases.total()) { |
15860 | Colour colour(Colour::ResultError); |
15861 | const std::string qualify_assertions_failed = |
15862 | totals.assertions.failed == totals.assertions.total() ? |
15863 | bothOrAll(totals.assertions.failed) : std::string(); |
15864 | out << |
15865 | "Failed " << bothOrAll(totals.testCases.failed) |
15866 | << pluralise(totals.testCases.failed, "test case" ) << ", " |
15867 | "failed " << qualify_assertions_failed << |
15868 | pluralise(totals.assertions.failed, "assertion" ) << '.'; |
15869 | } else if (totals.assertions.total() == 0) { |
15870 | out << |
15871 | "Passed " << bothOrAll(totals.testCases.total()) |
15872 | << pluralise(totals.testCases.total(), "test case" ) |
15873 | << " (no assertions)." ; |
15874 | } else if (totals.assertions.failed) { |
15875 | Colour colour(Colour::ResultError); |
15876 | out << |
15877 | "Failed " << pluralise(totals.testCases.failed, "test case" ) << ", " |
15878 | "failed " << pluralise(totals.assertions.failed, "assertion" ) << '.'; |
15879 | } else { |
15880 | Colour colour(Colour::ResultSuccess); |
15881 | out << |
15882 | "Passed " << bothOrAll(totals.testCases.passed) |
15883 | << pluralise(totals.testCases.passed, "test case" ) << |
15884 | " with " << pluralise(totals.assertions.passed, "assertion" ) << '.'; |
15885 | } |
15886 | } |
15887 | |
15888 | // Implementation of CompactReporter formatting |
15889 | class AssertionPrinter { |
15890 | public: |
15891 | AssertionPrinter& operator= (AssertionPrinter const&) = delete; |
15892 | AssertionPrinter(AssertionPrinter const&) = delete; |
15893 | AssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages) |
15894 | : stream(_stream) |
15895 | , result(_stats.assertionResult) |
15896 | , messages(_stats.infoMessages) |
15897 | , itMessage(_stats.infoMessages.begin()) |
15898 | , printInfoMessages(_printInfoMessages) {} |
15899 | |
15900 | void print() { |
15901 | printSourceInfo(); |
15902 | |
15903 | itMessage = messages.begin(); |
15904 | |
15905 | switch (result.getResultType()) { |
15906 | case ResultWas::Ok: |
15907 | printResultType(Colour::ResultSuccess, passedString()); |
15908 | printOriginalExpression(); |
15909 | printReconstructedExpression(); |
15910 | if (!result.hasExpression()) |
15911 | printRemainingMessages(Colour::None); |
15912 | else |
15913 | printRemainingMessages(); |
15914 | break; |
15915 | case ResultWas::ExpressionFailed: |
15916 | if (result.isOk()) |
15917 | printResultType(Colour::ResultSuccess, failedString() + std::string(" - but was ok" )); |
15918 | else |
15919 | printResultType(Colour::Error, failedString()); |
15920 | printOriginalExpression(); |
15921 | printReconstructedExpression(); |
15922 | printRemainingMessages(); |
15923 | break; |
15924 | case ResultWas::ThrewException: |
15925 | printResultType(Colour::Error, failedString()); |
15926 | printIssue("unexpected exception with message:" ); |
15927 | printMessage(); |
15928 | printExpressionWas(); |
15929 | printRemainingMessages(); |
15930 | break; |
15931 | case ResultWas::FatalErrorCondition: |
15932 | printResultType(Colour::Error, failedString()); |
15933 | printIssue("fatal error condition with message:" ); |
15934 | printMessage(); |
15935 | printExpressionWas(); |
15936 | printRemainingMessages(); |
15937 | break; |
15938 | case ResultWas::DidntThrowException: |
15939 | printResultType(Colour::Error, failedString()); |
15940 | printIssue("expected exception, got none" ); |
15941 | printExpressionWas(); |
15942 | printRemainingMessages(); |
15943 | break; |
15944 | case ResultWas::Info: |
15945 | printResultType(Colour::None, "info" ); |
15946 | printMessage(); |
15947 | printRemainingMessages(); |
15948 | break; |
15949 | case ResultWas::Warning: |
15950 | printResultType(Colour::None, "warning" ); |
15951 | printMessage(); |
15952 | printRemainingMessages(); |
15953 | break; |
15954 | case ResultWas::ExplicitFailure: |
15955 | printResultType(Colour::Error, failedString()); |
15956 | printIssue("explicitly" ); |
15957 | printRemainingMessages(Colour::None); |
15958 | break; |
15959 | // These cases are here to prevent compiler warnings |
15960 | case ResultWas::Unknown: |
15961 | case ResultWas::FailureBit: |
15962 | case ResultWas::Exception: |
15963 | printResultType(Colour::Error, "** internal error **" ); |
15964 | break; |
15965 | } |
15966 | } |
15967 | |
15968 | private: |
15969 | void printSourceInfo() const { |
15970 | Colour colourGuard(Colour::FileName); |
15971 | stream << result.getSourceInfo() << ':'; |
15972 | } |
15973 | |
15974 | void printResultType(Colour::Code colour, std::string const& passOrFail) const { |
15975 | if (!passOrFail.empty()) { |
15976 | { |
15977 | Colour colourGuard(colour); |
15978 | stream << ' ' << passOrFail; |
15979 | } |
15980 | stream << ':'; |
15981 | } |
15982 | } |
15983 | |
15984 | void printIssue(std::string const& issue) const { |
15985 | stream << ' ' << issue; |
15986 | } |
15987 | |
15988 | void printExpressionWas() { |
15989 | if (result.hasExpression()) { |
15990 | stream << ';'; |
15991 | { |
15992 | Colour colour(dimColour()); |
15993 | stream << " expression was:" ; |
15994 | } |
15995 | printOriginalExpression(); |
15996 | } |
15997 | } |
15998 | |
15999 | void printOriginalExpression() const { |
16000 | if (result.hasExpression()) { |
16001 | stream << ' ' << result.getExpression(); |
16002 | } |
16003 | } |
16004 | |
16005 | void printReconstructedExpression() const { |
16006 | if (result.hasExpandedExpression()) { |
16007 | { |
16008 | Colour colour(dimColour()); |
16009 | stream << " for: " ; |
16010 | } |
16011 | stream << result.getExpandedExpression(); |
16012 | } |
16013 | } |
16014 | |
16015 | void printMessage() { |
16016 | if (itMessage != messages.end()) { |
16017 | stream << " '" << itMessage->message << '\''; |
16018 | ++itMessage; |
16019 | } |
16020 | } |
16021 | |
16022 | void printRemainingMessages(Colour::Code colour = dimColour()) { |
16023 | if (itMessage == messages.end()) |
16024 | return; |
16025 | |
16026 | const auto itEnd = messages.cend(); |
16027 | const auto N = static_cast<std::size_t>(std::distance(itMessage, itEnd)); |
16028 | |
16029 | { |
16030 | Colour colourGuard(colour); |
16031 | stream << " with " << pluralise(N, "message" ) << ':'; |
16032 | } |
16033 | |
16034 | while (itMessage != itEnd) { |
16035 | // If this assertion is a warning ignore any INFO messages |
16036 | if (printInfoMessages || itMessage->type != ResultWas::Info) { |
16037 | printMessage(); |
16038 | if (itMessage != itEnd) { |
16039 | Colour colourGuard(dimColour()); |
16040 | stream << " and" ; |
16041 | } |
16042 | continue; |
16043 | } |
16044 | ++itMessage; |
16045 | } |
16046 | } |
16047 | |
16048 | private: |
16049 | std::ostream& stream; |
16050 | AssertionResult const& result; |
16051 | std::vector<MessageInfo> messages; |
16052 | std::vector<MessageInfo>::const_iterator itMessage; |
16053 | bool printInfoMessages; |
16054 | }; |
16055 | |
16056 | } // anon namespace |
16057 | |
16058 | std::string CompactReporter::getDescription() { |
16059 | return "Reports test results on a single line, suitable for IDEs" ; |
16060 | } |
16061 | |
16062 | void CompactReporter::noMatchingTestCases( std::string const& spec ) { |
16063 | stream << "No test cases matched '" << spec << '\'' << std::endl; |
16064 | } |
16065 | |
16066 | void CompactReporter::assertionStarting( AssertionInfo const& ) {} |
16067 | |
16068 | bool CompactReporter::assertionEnded( AssertionStats const& _assertionStats ) { |
16069 | AssertionResult const& result = _assertionStats.assertionResult; |
16070 | |
16071 | bool printInfoMessages = true; |
16072 | |
16073 | // Drop out if result was successful and we're not printing those |
16074 | if( !m_config->includeSuccessfulResults() && result.isOk() ) { |
16075 | if( result.getResultType() != ResultWas::Warning ) |
16076 | return false; |
16077 | printInfoMessages = false; |
16078 | } |
16079 | |
16080 | AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); |
16081 | printer.print(); |
16082 | |
16083 | stream << std::endl; |
16084 | return true; |
16085 | } |
16086 | |
16087 | void CompactReporter::sectionEnded(SectionStats const& _sectionStats) { |
16088 | double dur = _sectionStats.durationInSeconds; |
16089 | if ( shouldShowDuration( *m_config, dur ) ) { |
16090 | stream << getFormattedDuration( dur ) << " s: " << _sectionStats.sectionInfo.name << std::endl; |
16091 | } |
16092 | } |
16093 | |
16094 | void CompactReporter::testRunEnded( TestRunStats const& _testRunStats ) { |
16095 | printTotals( stream, _testRunStats.totals ); |
16096 | stream << '\n' << std::endl; |
16097 | StreamingReporterBase::testRunEnded( _testRunStats ); |
16098 | } |
16099 | |
16100 | CompactReporter::~CompactReporter() {} |
16101 | |
16102 | CATCH_REGISTER_REPORTER( "compact" , CompactReporter ) |
16103 | |
16104 | } // end namespace Catch |
16105 | // end catch_reporter_compact.cpp |
16106 | // start catch_reporter_console.cpp |
16107 | |
16108 | #include <cfloat> |
16109 | #include <cstdio> |
16110 | |
16111 | #if defined(_MSC_VER) |
16112 | #pragma warning(push) |
16113 | #pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch |
16114 | // Note that 4062 (not all labels are handled and default is missing) is enabled |
16115 | #endif |
16116 | |
16117 | #if defined(__clang__) |
16118 | # pragma clang diagnostic push |
16119 | // For simplicity, benchmarking-only helpers are always enabled |
16120 | # pragma clang diagnostic ignored "-Wunused-function" |
16121 | #endif |
16122 | |
16123 | namespace Catch { |
16124 | |
16125 | namespace { |
16126 | |
16127 | // Formatter impl for ConsoleReporter |
16128 | class ConsoleAssertionPrinter { |
16129 | public: |
16130 | ConsoleAssertionPrinter& operator= (ConsoleAssertionPrinter const&) = delete; |
16131 | ConsoleAssertionPrinter(ConsoleAssertionPrinter const&) = delete; |
16132 | ConsoleAssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages) |
16133 | : stream(_stream), |
16134 | stats(_stats), |
16135 | result(_stats.assertionResult), |
16136 | colour(Colour::None), |
16137 | message(result.getMessage()), |
16138 | messages(_stats.infoMessages), |
16139 | printInfoMessages(_printInfoMessages) { |
16140 | switch (result.getResultType()) { |
16141 | case ResultWas::Ok: |
16142 | colour = Colour::Success; |
16143 | passOrFail = "PASSED" ; |
16144 | //if( result.hasMessage() ) |
16145 | if (_stats.infoMessages.size() == 1) |
16146 | messageLabel = "with message" ; |
16147 | if (_stats.infoMessages.size() > 1) |
16148 | messageLabel = "with messages" ; |
16149 | break; |
16150 | case ResultWas::ExpressionFailed: |
16151 | if (result.isOk()) { |
16152 | colour = Colour::Success; |
16153 | passOrFail = "FAILED - but was ok" ; |
16154 | } else { |
16155 | colour = Colour::Error; |
16156 | passOrFail = "FAILED" ; |
16157 | } |
16158 | if (_stats.infoMessages.size() == 1) |
16159 | messageLabel = "with message" ; |
16160 | if (_stats.infoMessages.size() > 1) |
16161 | messageLabel = "with messages" ; |
16162 | break; |
16163 | case ResultWas::ThrewException: |
16164 | colour = Colour::Error; |
16165 | passOrFail = "FAILED" ; |
16166 | messageLabel = "due to unexpected exception with " ; |
16167 | if (_stats.infoMessages.size() == 1) |
16168 | messageLabel += "message" ; |
16169 | if (_stats.infoMessages.size() > 1) |
16170 | messageLabel += "messages" ; |
16171 | break; |
16172 | case ResultWas::FatalErrorCondition: |
16173 | colour = Colour::Error; |
16174 | passOrFail = "FAILED" ; |
16175 | messageLabel = "due to a fatal error condition" ; |
16176 | break; |
16177 | case ResultWas::DidntThrowException: |
16178 | colour = Colour::Error; |
16179 | passOrFail = "FAILED" ; |
16180 | messageLabel = "because no exception was thrown where one was expected" ; |
16181 | break; |
16182 | case ResultWas::Info: |
16183 | messageLabel = "info" ; |
16184 | break; |
16185 | case ResultWas::Warning: |
16186 | messageLabel = "warning" ; |
16187 | break; |
16188 | case ResultWas::ExplicitFailure: |
16189 | passOrFail = "FAILED" ; |
16190 | colour = Colour::Error; |
16191 | if (_stats.infoMessages.size() == 1) |
16192 | messageLabel = "explicitly with message" ; |
16193 | if (_stats.infoMessages.size() > 1) |
16194 | messageLabel = "explicitly with messages" ; |
16195 | break; |
16196 | // These cases are here to prevent compiler warnings |
16197 | case ResultWas::Unknown: |
16198 | case ResultWas::FailureBit: |
16199 | case ResultWas::Exception: |
16200 | passOrFail = "** internal error **" ; |
16201 | colour = Colour::Error; |
16202 | break; |
16203 | } |
16204 | } |
16205 | |
16206 | void print() const { |
16207 | printSourceInfo(); |
16208 | if (stats.totals.assertions.total() > 0) { |
16209 | printResultType(); |
16210 | printOriginalExpression(); |
16211 | printReconstructedExpression(); |
16212 | } else { |
16213 | stream << '\n'; |
16214 | } |
16215 | printMessage(); |
16216 | } |
16217 | |
16218 | private: |
16219 | void printResultType() const { |
16220 | if (!passOrFail.empty()) { |
16221 | Colour colourGuard(colour); |
16222 | stream << passOrFail << ":\n" ; |
16223 | } |
16224 | } |
16225 | void printOriginalExpression() const { |
16226 | if (result.hasExpression()) { |
16227 | Colour colourGuard(Colour::OriginalExpression); |
16228 | stream << " " ; |
16229 | stream << result.getExpressionInMacro(); |
16230 | stream << '\n'; |
16231 | } |
16232 | } |
16233 | void printReconstructedExpression() const { |
16234 | if (result.hasExpandedExpression()) { |
16235 | stream << "with expansion:\n" ; |
16236 | Colour colourGuard(Colour::ReconstructedExpression); |
16237 | stream << Column(result.getExpandedExpression()).indent(2) << '\n'; |
16238 | } |
16239 | } |
16240 | void printMessage() const { |
16241 | if (!messageLabel.empty()) |
16242 | stream << messageLabel << ':' << '\n'; |
16243 | for (auto const& msg : messages) { |
16244 | // If this assertion is a warning ignore any INFO messages |
16245 | if (printInfoMessages || msg.type != ResultWas::Info) |
16246 | stream << Column(msg.message).indent(2) << '\n'; |
16247 | } |
16248 | } |
16249 | void printSourceInfo() const { |
16250 | Colour colourGuard(Colour::FileName); |
16251 | stream << result.getSourceInfo() << ": " ; |
16252 | } |
16253 | |
16254 | std::ostream& stream; |
16255 | AssertionStats const& stats; |
16256 | AssertionResult const& result; |
16257 | Colour::Code colour; |
16258 | std::string passOrFail; |
16259 | std::string messageLabel; |
16260 | std::string message; |
16261 | std::vector<MessageInfo> messages; |
16262 | bool printInfoMessages; |
16263 | }; |
16264 | |
16265 | std::size_t makeRatio(std::size_t number, std::size_t total) { |
16266 | std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number / total : 0; |
16267 | return (ratio == 0 && number > 0) ? 1 : ratio; |
16268 | } |
16269 | |
16270 | std::size_t& findMax(std::size_t& i, std::size_t& j, std::size_t& k) { |
16271 | if (i > j && i > k) |
16272 | return i; |
16273 | else if (j > k) |
16274 | return j; |
16275 | else |
16276 | return k; |
16277 | } |
16278 | |
16279 | struct ColumnInfo { |
16280 | enum Justification { Left, Right }; |
16281 | std::string name; |
16282 | int width; |
16283 | Justification justification; |
16284 | }; |
16285 | struct ColumnBreak {}; |
16286 | struct RowBreak {}; |
16287 | |
16288 | class Duration { |
16289 | enum class Unit { |
16290 | Auto, |
16291 | Nanoseconds, |
16292 | Microseconds, |
16293 | Milliseconds, |
16294 | Seconds, |
16295 | Minutes |
16296 | }; |
16297 | static const uint64_t s_nanosecondsInAMicrosecond = 1000; |
16298 | static const uint64_t s_nanosecondsInAMillisecond = 1000 * s_nanosecondsInAMicrosecond; |
16299 | static const uint64_t s_nanosecondsInASecond = 1000 * s_nanosecondsInAMillisecond; |
16300 | static const uint64_t s_nanosecondsInAMinute = 60 * s_nanosecondsInASecond; |
16301 | |
16302 | double m_inNanoseconds; |
16303 | Unit m_units; |
16304 | |
16305 | public: |
16306 | explicit Duration(double inNanoseconds, Unit units = Unit::Auto) |
16307 | : m_inNanoseconds(inNanoseconds), |
16308 | m_units(units) { |
16309 | if (m_units == Unit::Auto) { |
16310 | if (m_inNanoseconds < s_nanosecondsInAMicrosecond) |
16311 | m_units = Unit::Nanoseconds; |
16312 | else if (m_inNanoseconds < s_nanosecondsInAMillisecond) |
16313 | m_units = Unit::Microseconds; |
16314 | else if (m_inNanoseconds < s_nanosecondsInASecond) |
16315 | m_units = Unit::Milliseconds; |
16316 | else if (m_inNanoseconds < s_nanosecondsInAMinute) |
16317 | m_units = Unit::Seconds; |
16318 | else |
16319 | m_units = Unit::Minutes; |
16320 | } |
16321 | |
16322 | } |
16323 | |
16324 | auto value() const -> double { |
16325 | switch (m_units) { |
16326 | case Unit::Microseconds: |
16327 | return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMicrosecond); |
16328 | case Unit::Milliseconds: |
16329 | return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMillisecond); |
16330 | case Unit::Seconds: |
16331 | return m_inNanoseconds / static_cast<double>(s_nanosecondsInASecond); |
16332 | case Unit::Minutes: |
16333 | return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMinute); |
16334 | default: |
16335 | return m_inNanoseconds; |
16336 | } |
16337 | } |
16338 | auto unitsAsString() const -> std::string { |
16339 | switch (m_units) { |
16340 | case Unit::Nanoseconds: |
16341 | return "ns" ; |
16342 | case Unit::Microseconds: |
16343 | return "us" ; |
16344 | case Unit::Milliseconds: |
16345 | return "ms" ; |
16346 | case Unit::Seconds: |
16347 | return "s" ; |
16348 | case Unit::Minutes: |
16349 | return "m" ; |
16350 | default: |
16351 | return "** internal error **" ; |
16352 | } |
16353 | |
16354 | } |
16355 | friend auto operator << (std::ostream& os, Duration const& duration) -> std::ostream& { |
16356 | return os << duration.value() << ' ' << duration.unitsAsString(); |
16357 | } |
16358 | }; |
16359 | } // end anon namespace |
16360 | |
16361 | class TablePrinter { |
16362 | std::ostream& m_os; |
16363 | std::vector<ColumnInfo> m_columnInfos; |
16364 | std::ostringstream m_oss; |
16365 | int m_currentColumn = -1; |
16366 | bool m_isOpen = false; |
16367 | |
16368 | public: |
16369 | TablePrinter( std::ostream& os, std::vector<ColumnInfo> columnInfos ) |
16370 | : m_os( os ), |
16371 | m_columnInfos( std::move( columnInfos ) ) {} |
16372 | |
16373 | auto columnInfos() const -> std::vector<ColumnInfo> const& { |
16374 | return m_columnInfos; |
16375 | } |
16376 | |
16377 | void open() { |
16378 | if (!m_isOpen) { |
16379 | m_isOpen = true; |
16380 | *this << RowBreak(); |
16381 | |
16382 | Columns ; |
16383 | Spacer spacer(2); |
16384 | for (auto const& info : m_columnInfos) { |
16385 | headerCols += Column(info.name).width(static_cast<std::size_t>(info.width - 2)); |
16386 | headerCols += spacer; |
16387 | } |
16388 | m_os << headerCols << '\n'; |
16389 | |
16390 | m_os << Catch::getLineOfChars<'-'>() << '\n'; |
16391 | } |
16392 | } |
16393 | void close() { |
16394 | if (m_isOpen) { |
16395 | *this << RowBreak(); |
16396 | m_os << std::endl; |
16397 | m_isOpen = false; |
16398 | } |
16399 | } |
16400 | |
16401 | template<typename T> |
16402 | friend TablePrinter& operator << (TablePrinter& tp, T const& value) { |
16403 | tp.m_oss << value; |
16404 | return tp; |
16405 | } |
16406 | |
16407 | friend TablePrinter& operator << (TablePrinter& tp, ColumnBreak) { |
16408 | auto colStr = tp.m_oss.str(); |
16409 | const auto strSize = colStr.size(); |
16410 | tp.m_oss.str("" ); |
16411 | tp.open(); |
16412 | if (tp.m_currentColumn == static_cast<int>(tp.m_columnInfos.size() - 1)) { |
16413 | tp.m_currentColumn = -1; |
16414 | tp.m_os << '\n'; |
16415 | } |
16416 | tp.m_currentColumn++; |
16417 | |
16418 | auto colInfo = tp.m_columnInfos[tp.m_currentColumn]; |
16419 | auto padding = (strSize + 1 < static_cast<std::size_t>(colInfo.width)) |
16420 | ? std::string(colInfo.width - (strSize + 1), ' ') |
16421 | : std::string(); |
16422 | if (colInfo.justification == ColumnInfo::Left) |
16423 | tp.m_os << colStr << padding << ' '; |
16424 | else |
16425 | tp.m_os << padding << colStr << ' '; |
16426 | return tp; |
16427 | } |
16428 | |
16429 | friend TablePrinter& operator << (TablePrinter& tp, RowBreak) { |
16430 | if (tp.m_currentColumn > 0) { |
16431 | tp.m_os << '\n'; |
16432 | tp.m_currentColumn = -1; |
16433 | } |
16434 | return tp; |
16435 | } |
16436 | }; |
16437 | |
16438 | ConsoleReporter::ConsoleReporter(ReporterConfig const& config) |
16439 | : StreamingReporterBase(config), |
16440 | m_tablePrinter(new TablePrinter(config.stream(), |
16441 | [&config]() -> std::vector<ColumnInfo> { |
16442 | if (config.fullConfig()->benchmarkNoAnalysis()) |
16443 | { |
16444 | return{ |
16445 | { "benchmark name" , CATCH_CONFIG_CONSOLE_WIDTH - 43, ColumnInfo::Left }, |
16446 | { " samples" , 14, ColumnInfo::Right }, |
16447 | { " iterations" , 14, ColumnInfo::Right }, |
16448 | { " mean" , 14, ColumnInfo::Right } |
16449 | }; |
16450 | } |
16451 | else |
16452 | { |
16453 | return{ |
16454 | { "benchmark name" , CATCH_CONFIG_CONSOLE_WIDTH - 43, ColumnInfo::Left }, |
16455 | { "samples mean std dev" , 14, ColumnInfo::Right }, |
16456 | { "iterations low mean low std dev" , 14, ColumnInfo::Right }, |
16457 | { "estimated high mean high std dev" , 14, ColumnInfo::Right } |
16458 | }; |
16459 | } |
16460 | }())) {} |
16461 | ConsoleReporter::~ConsoleReporter() = default; |
16462 | |
16463 | std::string ConsoleReporter::getDescription() { |
16464 | return "Reports test results as plain lines of text" ; |
16465 | } |
16466 | |
16467 | void ConsoleReporter::noMatchingTestCases(std::string const& spec) { |
16468 | stream << "No test cases matched '" << spec << '\'' << std::endl; |
16469 | } |
16470 | |
16471 | void ConsoleReporter::reportInvalidArguments(std::string const&arg){ |
16472 | stream << "Invalid Filter: " << arg << std::endl; |
16473 | } |
16474 | |
16475 | void ConsoleReporter::assertionStarting(AssertionInfo const&) {} |
16476 | |
16477 | bool ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) { |
16478 | AssertionResult const& result = _assertionStats.assertionResult; |
16479 | |
16480 | bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); |
16481 | |
16482 | // Drop out if result was successful but we're not printing them. |
16483 | if (!includeResults && result.getResultType() != ResultWas::Warning) |
16484 | return false; |
16485 | |
16486 | lazyPrint(); |
16487 | |
16488 | ConsoleAssertionPrinter printer(stream, _assertionStats, includeResults); |
16489 | printer.print(); |
16490 | stream << std::endl; |
16491 | return true; |
16492 | } |
16493 | |
16494 | void ConsoleReporter::sectionStarting(SectionInfo const& _sectionInfo) { |
16495 | m_tablePrinter->close(); |
16496 | m_headerPrinted = false; |
16497 | StreamingReporterBase::sectionStarting(_sectionInfo); |
16498 | } |
16499 | void ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) { |
16500 | m_tablePrinter->close(); |
16501 | if (_sectionStats.missingAssertions) { |
16502 | lazyPrint(); |
16503 | Colour colour(Colour::ResultError); |
16504 | if (m_sectionStack.size() > 1) |
16505 | stream << "\nNo assertions in section" ; |
16506 | else |
16507 | stream << "\nNo assertions in test case" ; |
16508 | stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; |
16509 | } |
16510 | double dur = _sectionStats.durationInSeconds; |
16511 | if (shouldShowDuration(*m_config, dur)) { |
16512 | stream << getFormattedDuration(dur) << " s: " << _sectionStats.sectionInfo.name << std::endl; |
16513 | } |
16514 | if (m_headerPrinted) { |
16515 | m_headerPrinted = false; |
16516 | } |
16517 | StreamingReporterBase::sectionEnded(_sectionStats); |
16518 | } |
16519 | |
16520 | #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) |
16521 | void ConsoleReporter::benchmarkPreparing(std::string const& name) { |
16522 | lazyPrintWithoutClosingBenchmarkTable(); |
16523 | |
16524 | auto nameCol = Column(name).width(static_cast<std::size_t>(m_tablePrinter->columnInfos()[0].width - 2)); |
16525 | |
16526 | bool firstLine = true; |
16527 | for (auto line : nameCol) { |
16528 | if (!firstLine) |
16529 | (*m_tablePrinter) << ColumnBreak() << ColumnBreak() << ColumnBreak(); |
16530 | else |
16531 | firstLine = false; |
16532 | |
16533 | (*m_tablePrinter) << line << ColumnBreak(); |
16534 | } |
16535 | } |
16536 | |
16537 | void ConsoleReporter::benchmarkStarting(BenchmarkInfo const& info) { |
16538 | (*m_tablePrinter) << info.samples << ColumnBreak() |
16539 | << info.iterations << ColumnBreak(); |
16540 | if (!m_config->benchmarkNoAnalysis()) |
16541 | (*m_tablePrinter) << Duration(info.estimatedDuration) << ColumnBreak(); |
16542 | } |
16543 | void ConsoleReporter::benchmarkEnded(BenchmarkStats<> const& stats) { |
16544 | if (m_config->benchmarkNoAnalysis()) |
16545 | { |
16546 | (*m_tablePrinter) << Duration(stats.mean.point.count()) << ColumnBreak(); |
16547 | } |
16548 | else |
16549 | { |
16550 | (*m_tablePrinter) << ColumnBreak() |
16551 | << Duration(stats.mean.point.count()) << ColumnBreak() |
16552 | << Duration(stats.mean.lower_bound.count()) << ColumnBreak() |
16553 | << Duration(stats.mean.upper_bound.count()) << ColumnBreak() << ColumnBreak() |
16554 | << Duration(stats.standardDeviation.point.count()) << ColumnBreak() |
16555 | << Duration(stats.standardDeviation.lower_bound.count()) << ColumnBreak() |
16556 | << Duration(stats.standardDeviation.upper_bound.count()) << ColumnBreak() << ColumnBreak() << ColumnBreak() << ColumnBreak() << ColumnBreak(); |
16557 | } |
16558 | } |
16559 | |
16560 | void ConsoleReporter::benchmarkFailed(std::string const& error) { |
16561 | Colour colour(Colour::Red); |
16562 | (*m_tablePrinter) |
16563 | << "Benchmark failed (" << error << ')' |
16564 | << ColumnBreak() << RowBreak(); |
16565 | } |
16566 | #endif // CATCH_CONFIG_ENABLE_BENCHMARKING |
16567 | |
16568 | void ConsoleReporter::testCaseEnded(TestCaseStats const& _testCaseStats) { |
16569 | m_tablePrinter->close(); |
16570 | StreamingReporterBase::testCaseEnded(_testCaseStats); |
16571 | m_headerPrinted = false; |
16572 | } |
16573 | void ConsoleReporter::testGroupEnded(TestGroupStats const& _testGroupStats) { |
16574 | if (currentGroupInfo.used) { |
16575 | printSummaryDivider(); |
16576 | stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n" ; |
16577 | printTotals(_testGroupStats.totals); |
16578 | stream << '\n' << std::endl; |
16579 | } |
16580 | StreamingReporterBase::testGroupEnded(_testGroupStats); |
16581 | } |
16582 | void ConsoleReporter::testRunEnded(TestRunStats const& _testRunStats) { |
16583 | printTotalsDivider(_testRunStats.totals); |
16584 | printTotals(_testRunStats.totals); |
16585 | stream << std::endl; |
16586 | StreamingReporterBase::testRunEnded(_testRunStats); |
16587 | } |
16588 | void ConsoleReporter::testRunStarting(TestRunInfo const& _testInfo) { |
16589 | StreamingReporterBase::testRunStarting(_testInfo); |
16590 | printTestFilters(); |
16591 | } |
16592 | |
16593 | void ConsoleReporter::lazyPrint() { |
16594 | |
16595 | m_tablePrinter->close(); |
16596 | lazyPrintWithoutClosingBenchmarkTable(); |
16597 | } |
16598 | |
16599 | void ConsoleReporter::lazyPrintWithoutClosingBenchmarkTable() { |
16600 | |
16601 | if (!currentTestRunInfo.used) |
16602 | lazyPrintRunInfo(); |
16603 | if (!currentGroupInfo.used) |
16604 | lazyPrintGroupInfo(); |
16605 | |
16606 | if (!m_headerPrinted) { |
16607 | printTestCaseAndSectionHeader(); |
16608 | m_headerPrinted = true; |
16609 | } |
16610 | } |
16611 | void ConsoleReporter::lazyPrintRunInfo() { |
16612 | stream << '\n' << getLineOfChars<'~'>() << '\n'; |
16613 | Colour colour(Colour::SecondaryText); |
16614 | stream << currentTestRunInfo->name |
16615 | << " is a Catch v" << libraryVersion() << " host application.\n" |
16616 | << "Run with -? for options\n\n" ; |
16617 | |
16618 | if (m_config->rngSeed() != 0) |
16619 | stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n" ; |
16620 | |
16621 | currentTestRunInfo.used = true; |
16622 | } |
16623 | void ConsoleReporter::lazyPrintGroupInfo() { |
16624 | if (!currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1) { |
16625 | printClosedHeader("Group: " + currentGroupInfo->name); |
16626 | currentGroupInfo.used = true; |
16627 | } |
16628 | } |
16629 | void ConsoleReporter::printTestCaseAndSectionHeader() { |
16630 | assert(!m_sectionStack.empty()); |
16631 | printOpenHeader(currentTestCaseInfo->name); |
16632 | |
16633 | if (m_sectionStack.size() > 1) { |
16634 | Colour colourGuard(Colour::Headers); |
16635 | |
16636 | auto |
16637 | it = m_sectionStack.begin() + 1, // Skip first section (test case) |
16638 | itEnd = m_sectionStack.end(); |
16639 | for (; it != itEnd; ++it) |
16640 | printHeaderString(it->name, 2); |
16641 | } |
16642 | |
16643 | SourceLineInfo lineInfo = m_sectionStack.back().lineInfo; |
16644 | |
16645 | stream << getLineOfChars<'-'>() << '\n'; |
16646 | Colour colourGuard(Colour::FileName); |
16647 | stream << lineInfo << '\n'; |
16648 | stream << getLineOfChars<'.'>() << '\n' << std::endl; |
16649 | } |
16650 | |
16651 | void ConsoleReporter::(std::string const& _name) { |
16652 | printOpenHeader(_name); |
16653 | stream << getLineOfChars<'.'>() << '\n'; |
16654 | } |
16655 | void ConsoleReporter::(std::string const& _name) { |
16656 | stream << getLineOfChars<'-'>() << '\n'; |
16657 | { |
16658 | Colour colourGuard(Colour::Headers); |
16659 | printHeaderString(_name); |
16660 | } |
16661 | } |
16662 | |
16663 | // if string has a : in first line will set indent to follow it on |
16664 | // subsequent lines |
16665 | void ConsoleReporter::(std::string const& _string, std::size_t indent) { |
16666 | std::size_t i = _string.find(": " ); |
16667 | if (i != std::string::npos) |
16668 | i += 2; |
16669 | else |
16670 | i = 0; |
16671 | stream << Column(_string).indent(indent + i).initialIndent(indent) << '\n'; |
16672 | } |
16673 | |
16674 | struct SummaryColumn { |
16675 | |
16676 | SummaryColumn( std::string _label, Colour::Code _colour ) |
16677 | : label( std::move( _label ) ), |
16678 | colour( _colour ) {} |
16679 | SummaryColumn addRow( std::size_t count ) { |
16680 | ReusableStringStream ; |
16681 | rss << count; |
16682 | std::string row = rss.str(); |
16683 | for (auto& oldRow : rows) { |
16684 | while (oldRow.size() < row.size()) |
16685 | oldRow = ' ' + oldRow; |
16686 | while (oldRow.size() > row.size()) |
16687 | row = ' ' + row; |
16688 | } |
16689 | rows.push_back(row); |
16690 | return *this; |
16691 | } |
16692 | |
16693 | std::string label; |
16694 | Colour::Code colour; |
16695 | std::vector<std::string> rows; |
16696 | |
16697 | }; |
16698 | |
16699 | void ConsoleReporter::printTotals( Totals const& totals ) { |
16700 | if (totals.testCases.total() == 0) { |
16701 | stream << Colour(Colour::Warning) << "No tests ran\n" ; |
16702 | } else if (totals.assertions.total() > 0 && totals.testCases.allPassed()) { |
16703 | stream << Colour(Colour::ResultSuccess) << "All tests passed" ; |
16704 | stream << " (" |
16705 | << pluralise(totals.assertions.passed, "assertion" ) << " in " |
16706 | << pluralise(totals.testCases.passed, "test case" ) << ')' |
16707 | << '\n'; |
16708 | } else { |
16709 | |
16710 | std::vector<SummaryColumn> columns; |
16711 | columns.push_back(SummaryColumn("" , Colour::None) |
16712 | .addRow(totals.testCases.total()) |
16713 | .addRow(totals.assertions.total())); |
16714 | columns.push_back(SummaryColumn("passed" , Colour::Success) |
16715 | .addRow(totals.testCases.passed) |
16716 | .addRow(totals.assertions.passed)); |
16717 | columns.push_back(SummaryColumn("failed" , Colour::ResultError) |
16718 | .addRow(totals.testCases.failed) |
16719 | .addRow(totals.assertions.failed)); |
16720 | columns.push_back(SummaryColumn("failed as expected" , Colour::ResultExpectedFailure) |
16721 | .addRow(totals.testCases.failedButOk) |
16722 | .addRow(totals.assertions.failedButOk)); |
16723 | |
16724 | printSummaryRow("test cases" , columns, 0); |
16725 | printSummaryRow("assertions" , columns, 1); |
16726 | } |
16727 | } |
16728 | void ConsoleReporter::printSummaryRow(std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row) { |
16729 | for (auto col : cols) { |
16730 | std::string value = col.rows[row]; |
16731 | if (col.label.empty()) { |
16732 | stream << label << ": " ; |
16733 | if (value != "0" ) |
16734 | stream << value; |
16735 | else |
16736 | stream << Colour(Colour::Warning) << "- none -" ; |
16737 | } else if (value != "0" ) { |
16738 | stream << Colour(Colour::LightGrey) << " | " ; |
16739 | stream << Colour(col.colour) |
16740 | << value << ' ' << col.label; |
16741 | } |
16742 | } |
16743 | stream << '\n'; |
16744 | } |
16745 | |
16746 | void ConsoleReporter::printTotalsDivider(Totals const& totals) { |
16747 | if (totals.testCases.total() > 0) { |
16748 | std::size_t failedRatio = makeRatio(totals.testCases.failed, totals.testCases.total()); |
16749 | std::size_t failedButOkRatio = makeRatio(totals.testCases.failedButOk, totals.testCases.total()); |
16750 | std::size_t passedRatio = makeRatio(totals.testCases.passed, totals.testCases.total()); |
16751 | while (failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH - 1) |
16752 | findMax(failedRatio, failedButOkRatio, passedRatio)++; |
16753 | while (failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH - 1) |
16754 | findMax(failedRatio, failedButOkRatio, passedRatio)--; |
16755 | |
16756 | stream << Colour(Colour::Error) << std::string(failedRatio, '='); |
16757 | stream << Colour(Colour::ResultExpectedFailure) << std::string(failedButOkRatio, '='); |
16758 | if (totals.testCases.allPassed()) |
16759 | stream << Colour(Colour::ResultSuccess) << std::string(passedRatio, '='); |
16760 | else |
16761 | stream << Colour(Colour::Success) << std::string(passedRatio, '='); |
16762 | } else { |
16763 | stream << Colour(Colour::Warning) << std::string(CATCH_CONFIG_CONSOLE_WIDTH - 1, '='); |
16764 | } |
16765 | stream << '\n'; |
16766 | } |
16767 | void ConsoleReporter::printSummaryDivider() { |
16768 | stream << getLineOfChars<'-'>() << '\n'; |
16769 | } |
16770 | |
16771 | void ConsoleReporter::printTestFilters() { |
16772 | if (m_config->testSpec().hasFilters()) { |
16773 | Colour guard(Colour::BrightYellow); |
16774 | stream << "Filters: " << serializeFilters(m_config->getTestsOrTags()) << '\n'; |
16775 | } |
16776 | } |
16777 | |
16778 | CATCH_REGISTER_REPORTER("console" , ConsoleReporter) |
16779 | |
16780 | } // end namespace Catch |
16781 | |
16782 | #if defined(_MSC_VER) |
16783 | #pragma warning(pop) |
16784 | #endif |
16785 | |
16786 | #if defined(__clang__) |
16787 | # pragma clang diagnostic pop |
16788 | #endif |
16789 | // end catch_reporter_console.cpp |
16790 | // start catch_reporter_junit.cpp |
16791 | |
16792 | #include <cassert> |
16793 | #include <sstream> |
16794 | #include <ctime> |
16795 | #include <algorithm> |
16796 | #include <iomanip> |
16797 | |
16798 | namespace Catch { |
16799 | |
16800 | namespace { |
16801 | std::string getCurrentTimestamp() { |
16802 | // Beware, this is not reentrant because of backward compatibility issues |
16803 | // Also, UTC only, again because of backward compatibility (%z is C++11) |
16804 | time_t rawtime; |
16805 | std::time(&rawtime); |
16806 | auto const timeStampSize = sizeof("2017-01-16T17:06:45Z" ); |
16807 | |
16808 | #ifdef _MSC_VER |
16809 | std::tm timeInfo = {}; |
16810 | gmtime_s(&timeInfo, &rawtime); |
16811 | #else |
16812 | std::tm* timeInfo; |
16813 | timeInfo = std::gmtime(&rawtime); |
16814 | #endif |
16815 | |
16816 | char timeStamp[timeStampSize]; |
16817 | const char * const fmt = "%Y-%m-%dT%H:%M:%SZ" ; |
16818 | |
16819 | #ifdef _MSC_VER |
16820 | std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); |
16821 | #else |
16822 | std::strftime(timeStamp, timeStampSize, fmt, timeInfo); |
16823 | #endif |
16824 | return std::string(timeStamp, timeStampSize-1); |
16825 | } |
16826 | |
16827 | std::string fileNameTag(const std::vector<std::string> &tags) { |
16828 | auto it = std::find_if(begin(tags), |
16829 | end(tags), |
16830 | [] (std::string const& tag) {return tag.front() == '#'; }); |
16831 | if (it != tags.end()) |
16832 | return it->substr(1); |
16833 | return std::string(); |
16834 | } |
16835 | |
16836 | // Formats the duration in seconds to 3 decimal places. |
16837 | // This is done because some genius defined Maven Surefire schema |
16838 | // in a way that only accepts 3 decimal places, and tools like |
16839 | // Jenkins use that schema for validation JUnit reporter output. |
16840 | std::string formatDuration( double seconds ) { |
16841 | ReusableStringStream ; |
16842 | rss << std::fixed << std::setprecision( 3 ) << seconds; |
16843 | return rss.str(); |
16844 | } |
16845 | |
16846 | } // anonymous namespace |
16847 | |
16848 | JunitReporter::JunitReporter( ReporterConfig const& _config ) |
16849 | : CumulativeReporterBase( _config ), |
16850 | xml( _config.stream() ) |
16851 | { |
16852 | m_reporterPrefs.shouldRedirectStdOut = true; |
16853 | m_reporterPrefs.shouldReportAllAssertions = true; |
16854 | } |
16855 | |
16856 | JunitReporter::~JunitReporter() {} |
16857 | |
16858 | std::string JunitReporter::getDescription() { |
16859 | return "Reports test results in an XML format that looks like Ant's junitreport target" ; |
16860 | } |
16861 | |
16862 | void JunitReporter::noMatchingTestCases( std::string const& /*spec*/ ) {} |
16863 | |
16864 | void JunitReporter::testRunStarting( TestRunInfo const& runInfo ) { |
16865 | CumulativeReporterBase::testRunStarting( runInfo ); |
16866 | xml.startElement( "testsuites" ); |
16867 | } |
16868 | |
16869 | void JunitReporter::testGroupStarting( GroupInfo const& groupInfo ) { |
16870 | suiteTimer.start(); |
16871 | stdOutForSuite.clear(); |
16872 | stdErrForSuite.clear(); |
16873 | unexpectedExceptions = 0; |
16874 | CumulativeReporterBase::testGroupStarting( groupInfo ); |
16875 | } |
16876 | |
16877 | void JunitReporter::testCaseStarting( TestCaseInfo const& testCaseInfo ) { |
16878 | m_okToFail = testCaseInfo.okToFail(); |
16879 | } |
16880 | |
16881 | bool JunitReporter::assertionEnded( AssertionStats const& assertionStats ) { |
16882 | if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail ) |
16883 | unexpectedExceptions++; |
16884 | return CumulativeReporterBase::assertionEnded( assertionStats ); |
16885 | } |
16886 | |
16887 | void JunitReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { |
16888 | stdOutForSuite += testCaseStats.stdOut; |
16889 | stdErrForSuite += testCaseStats.stdErr; |
16890 | CumulativeReporterBase::testCaseEnded( testCaseStats ); |
16891 | } |
16892 | |
16893 | void JunitReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { |
16894 | double suiteTime = suiteTimer.getElapsedSeconds(); |
16895 | CumulativeReporterBase::testGroupEnded( testGroupStats ); |
16896 | writeGroup( *m_testGroups.back(), suiteTime ); |
16897 | } |
16898 | |
16899 | void JunitReporter::testRunEndedCumulative() { |
16900 | xml.endElement(); |
16901 | } |
16902 | |
16903 | void JunitReporter::writeGroup( TestGroupNode const& groupNode, double suiteTime ) { |
16904 | XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); |
16905 | |
16906 | TestGroupStats const& stats = groupNode.value; |
16907 | xml.writeAttribute( "name" , stats.groupInfo.name ); |
16908 | xml.writeAttribute( "errors" , unexpectedExceptions ); |
16909 | xml.writeAttribute( "failures" , stats.totals.assertions.failed-unexpectedExceptions ); |
16910 | xml.writeAttribute( "tests" , stats.totals.assertions.total() ); |
16911 | xml.writeAttribute( "hostname" , "tbd" ); // !TBD |
16912 | if( m_config->showDurations() == ShowDurations::Never ) |
16913 | xml.writeAttribute( "time" , "" ); |
16914 | else |
16915 | xml.writeAttribute( "time" , formatDuration( suiteTime ) ); |
16916 | xml.writeAttribute( "timestamp" , getCurrentTimestamp() ); |
16917 | |
16918 | // Write properties if there are any |
16919 | if (m_config->hasTestFilters() || m_config->rngSeed() != 0) { |
16920 | auto properties = xml.scopedElement("properties" ); |
16921 | if (m_config->hasTestFilters()) { |
16922 | xml.scopedElement("property" ) |
16923 | .writeAttribute("name" , "filters" ) |
16924 | .writeAttribute("value" , serializeFilters(m_config->getTestsOrTags())); |
16925 | } |
16926 | if (m_config->rngSeed() != 0) { |
16927 | xml.scopedElement("property" ) |
16928 | .writeAttribute("name" , "random-seed" ) |
16929 | .writeAttribute("value" , m_config->rngSeed()); |
16930 | } |
16931 | } |
16932 | |
16933 | // Write test cases |
16934 | for( auto const& child : groupNode.children ) |
16935 | writeTestCase( *child ); |
16936 | |
16937 | xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite ), XmlFormatting::Newline ); |
16938 | xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite ), XmlFormatting::Newline ); |
16939 | } |
16940 | |
16941 | void JunitReporter::writeTestCase( TestCaseNode const& testCaseNode ) { |
16942 | TestCaseStats const& stats = testCaseNode.value; |
16943 | |
16944 | // All test cases have exactly one section - which represents the |
16945 | // test case itself. That section may have 0-n nested sections |
16946 | assert( testCaseNode.children.size() == 1 ); |
16947 | SectionNode const& rootSection = *testCaseNode.children.front(); |
16948 | |
16949 | std::string className = stats.testInfo.className; |
16950 | |
16951 | if( className.empty() ) { |
16952 | className = fileNameTag(stats.testInfo.tags); |
16953 | if ( className.empty() ) |
16954 | className = "global" ; |
16955 | } |
16956 | |
16957 | if ( !m_config->name().empty() ) |
16958 | className = m_config->name() + "." + className; |
16959 | |
16960 | writeSection( className, "" , rootSection, stats.testInfo.okToFail() ); |
16961 | } |
16962 | |
16963 | void JunitReporter::writeSection( std::string const& className, |
16964 | std::string const& rootName, |
16965 | SectionNode const& sectionNode, |
16966 | bool testOkToFail) { |
16967 | std::string name = trim( sectionNode.stats.sectionInfo.name ); |
16968 | if( !rootName.empty() ) |
16969 | name = rootName + '/' + name; |
16970 | |
16971 | if( !sectionNode.assertions.empty() || |
16972 | !sectionNode.stdOut.empty() || |
16973 | !sectionNode.stdErr.empty() ) { |
16974 | XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); |
16975 | if( className.empty() ) { |
16976 | xml.writeAttribute( "classname" , name ); |
16977 | xml.writeAttribute( "name" , "root" ); |
16978 | } |
16979 | else { |
16980 | xml.writeAttribute( "classname" , className ); |
16981 | xml.writeAttribute( "name" , name ); |
16982 | } |
16983 | xml.writeAttribute( "time" , formatDuration( sectionNode.stats.durationInSeconds ) ); |
16984 | // This is not ideal, but it should be enough to mimic gtest's |
16985 | // junit output. |
16986 | // Ideally the JUnit reporter would also handle `skipTest` |
16987 | // events and write those out appropriately. |
16988 | xml.writeAttribute( "status" , "run" ); |
16989 | |
16990 | if (sectionNode.stats.assertions.failedButOk) { |
16991 | xml.scopedElement("skipped" ) |
16992 | .writeAttribute("message" , "TEST_CASE tagged with !mayfail" ); |
16993 | } |
16994 | |
16995 | writeAssertions( sectionNode ); |
16996 | |
16997 | if( !sectionNode.stdOut.empty() ) |
16998 | xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), XmlFormatting::Newline ); |
16999 | if( !sectionNode.stdErr.empty() ) |
17000 | xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), XmlFormatting::Newline ); |
17001 | } |
17002 | for( auto const& childNode : sectionNode.childSections ) |
17003 | if( className.empty() ) |
17004 | writeSection( name, "" , *childNode, testOkToFail ); |
17005 | else |
17006 | writeSection( className, name, *childNode, testOkToFail ); |
17007 | } |
17008 | |
17009 | void JunitReporter::writeAssertions( SectionNode const& sectionNode ) { |
17010 | for( auto const& assertion : sectionNode.assertions ) |
17011 | writeAssertion( assertion ); |
17012 | } |
17013 | |
17014 | void JunitReporter::writeAssertion( AssertionStats const& stats ) { |
17015 | AssertionResult const& result = stats.assertionResult; |
17016 | if( !result.isOk() ) { |
17017 | std::string elementName; |
17018 | switch( result.getResultType() ) { |
17019 | case ResultWas::ThrewException: |
17020 | case ResultWas::FatalErrorCondition: |
17021 | elementName = "error" ; |
17022 | break; |
17023 | case ResultWas::ExplicitFailure: |
17024 | case ResultWas::ExpressionFailed: |
17025 | case ResultWas::DidntThrowException: |
17026 | elementName = "failure" ; |
17027 | break; |
17028 | |
17029 | // We should never see these here: |
17030 | case ResultWas::Info: |
17031 | case ResultWas::Warning: |
17032 | case ResultWas::Ok: |
17033 | case ResultWas::Unknown: |
17034 | case ResultWas::FailureBit: |
17035 | case ResultWas::Exception: |
17036 | elementName = "internalError" ; |
17037 | break; |
17038 | } |
17039 | |
17040 | XmlWriter::ScopedElement e = xml.scopedElement( elementName ); |
17041 | |
17042 | xml.writeAttribute( "message" , result.getExpression() ); |
17043 | xml.writeAttribute( "type" , result.getTestMacroName() ); |
17044 | |
17045 | ReusableStringStream ; |
17046 | if (stats.totals.assertions.total() > 0) { |
17047 | rss << "FAILED" << ":\n" ; |
17048 | if (result.hasExpression()) { |
17049 | rss << " " ; |
17050 | rss << result.getExpressionInMacro(); |
17051 | rss << '\n'; |
17052 | } |
17053 | if (result.hasExpandedExpression()) { |
17054 | rss << "with expansion:\n" ; |
17055 | rss << Column(result.getExpandedExpression()).indent(2) << '\n'; |
17056 | } |
17057 | } else { |
17058 | rss << '\n'; |
17059 | } |
17060 | |
17061 | if( !result.getMessage().empty() ) |
17062 | rss << result.getMessage() << '\n'; |
17063 | for( auto const& msg : stats.infoMessages ) |
17064 | if( msg.type == ResultWas::Info ) |
17065 | rss << msg.message << '\n'; |
17066 | |
17067 | rss << "at " << result.getSourceInfo(); |
17068 | xml.writeText( rss.str(), XmlFormatting::Newline ); |
17069 | } |
17070 | } |
17071 | |
17072 | CATCH_REGISTER_REPORTER( "junit" , JunitReporter ) |
17073 | |
17074 | } // end namespace Catch |
17075 | // end catch_reporter_junit.cpp |
17076 | // start catch_reporter_listening.cpp |
17077 | |
17078 | #include <cassert> |
17079 | |
17080 | namespace Catch { |
17081 | |
17082 | ListeningReporter::ListeningReporter() { |
17083 | // We will assume that listeners will always want all assertions |
17084 | m_preferences.shouldReportAllAssertions = true; |
17085 | } |
17086 | |
17087 | void ListeningReporter::addListener( IStreamingReporterPtr&& listener ) { |
17088 | m_listeners.push_back( std::move( listener ) ); |
17089 | } |
17090 | |
17091 | void ListeningReporter::addReporter(IStreamingReporterPtr&& reporter) { |
17092 | assert(!m_reporter && "Listening reporter can wrap only 1 real reporter" ); |
17093 | m_reporter = std::move( reporter ); |
17094 | m_preferences.shouldRedirectStdOut = m_reporter->getPreferences().shouldRedirectStdOut; |
17095 | } |
17096 | |
17097 | ReporterPreferences ListeningReporter::getPreferences() const { |
17098 | return m_preferences; |
17099 | } |
17100 | |
17101 | std::set<Verbosity> ListeningReporter::getSupportedVerbosities() { |
17102 | return std::set<Verbosity>{ }; |
17103 | } |
17104 | |
17105 | void ListeningReporter::noMatchingTestCases( std::string const& spec ) { |
17106 | for ( auto const& listener : m_listeners ) { |
17107 | listener->noMatchingTestCases( spec ); |
17108 | } |
17109 | m_reporter->noMatchingTestCases( spec ); |
17110 | } |
17111 | |
17112 | void ListeningReporter::reportInvalidArguments(std::string const&arg){ |
17113 | for ( auto const& listener : m_listeners ) { |
17114 | listener->reportInvalidArguments( arg ); |
17115 | } |
17116 | m_reporter->reportInvalidArguments( arg ); |
17117 | } |
17118 | |
17119 | #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) |
17120 | void ListeningReporter::benchmarkPreparing( std::string const& name ) { |
17121 | for (auto const& listener : m_listeners) { |
17122 | listener->benchmarkPreparing(name); |
17123 | } |
17124 | m_reporter->benchmarkPreparing(name); |
17125 | } |
17126 | void ListeningReporter::benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) { |
17127 | for ( auto const& listener : m_listeners ) { |
17128 | listener->benchmarkStarting( benchmarkInfo ); |
17129 | } |
17130 | m_reporter->benchmarkStarting( benchmarkInfo ); |
17131 | } |
17132 | void ListeningReporter::benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) { |
17133 | for ( auto const& listener : m_listeners ) { |
17134 | listener->benchmarkEnded( benchmarkStats ); |
17135 | } |
17136 | m_reporter->benchmarkEnded( benchmarkStats ); |
17137 | } |
17138 | |
17139 | void ListeningReporter::benchmarkFailed( std::string const& error ) { |
17140 | for (auto const& listener : m_listeners) { |
17141 | listener->benchmarkFailed(error); |
17142 | } |
17143 | m_reporter->benchmarkFailed(error); |
17144 | } |
17145 | #endif // CATCH_CONFIG_ENABLE_BENCHMARKING |
17146 | |
17147 | void ListeningReporter::testRunStarting( TestRunInfo const& testRunInfo ) { |
17148 | for ( auto const& listener : m_listeners ) { |
17149 | listener->testRunStarting( testRunInfo ); |
17150 | } |
17151 | m_reporter->testRunStarting( testRunInfo ); |
17152 | } |
17153 | |
17154 | void ListeningReporter::testGroupStarting( GroupInfo const& groupInfo ) { |
17155 | for ( auto const& listener : m_listeners ) { |
17156 | listener->testGroupStarting( groupInfo ); |
17157 | } |
17158 | m_reporter->testGroupStarting( groupInfo ); |
17159 | } |
17160 | |
17161 | void ListeningReporter::testCaseStarting( TestCaseInfo const& testInfo ) { |
17162 | for ( auto const& listener : m_listeners ) { |
17163 | listener->testCaseStarting( testInfo ); |
17164 | } |
17165 | m_reporter->testCaseStarting( testInfo ); |
17166 | } |
17167 | |
17168 | void ListeningReporter::sectionStarting( SectionInfo const& sectionInfo ) { |
17169 | for ( auto const& listener : m_listeners ) { |
17170 | listener->sectionStarting( sectionInfo ); |
17171 | } |
17172 | m_reporter->sectionStarting( sectionInfo ); |
17173 | } |
17174 | |
17175 | void ListeningReporter::assertionStarting( AssertionInfo const& assertionInfo ) { |
17176 | for ( auto const& listener : m_listeners ) { |
17177 | listener->assertionStarting( assertionInfo ); |
17178 | } |
17179 | m_reporter->assertionStarting( assertionInfo ); |
17180 | } |
17181 | |
17182 | // The return value indicates if the messages buffer should be cleared: |
17183 | bool ListeningReporter::assertionEnded( AssertionStats const& assertionStats ) { |
17184 | for( auto const& listener : m_listeners ) { |
17185 | static_cast<void>( listener->assertionEnded( assertionStats ) ); |
17186 | } |
17187 | return m_reporter->assertionEnded( assertionStats ); |
17188 | } |
17189 | |
17190 | void ListeningReporter::sectionEnded( SectionStats const& sectionStats ) { |
17191 | for ( auto const& listener : m_listeners ) { |
17192 | listener->sectionEnded( sectionStats ); |
17193 | } |
17194 | m_reporter->sectionEnded( sectionStats ); |
17195 | } |
17196 | |
17197 | void ListeningReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { |
17198 | for ( auto const& listener : m_listeners ) { |
17199 | listener->testCaseEnded( testCaseStats ); |
17200 | } |
17201 | m_reporter->testCaseEnded( testCaseStats ); |
17202 | } |
17203 | |
17204 | void ListeningReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { |
17205 | for ( auto const& listener : m_listeners ) { |
17206 | listener->testGroupEnded( testGroupStats ); |
17207 | } |
17208 | m_reporter->testGroupEnded( testGroupStats ); |
17209 | } |
17210 | |
17211 | void ListeningReporter::testRunEnded( TestRunStats const& testRunStats ) { |
17212 | for ( auto const& listener : m_listeners ) { |
17213 | listener->testRunEnded( testRunStats ); |
17214 | } |
17215 | m_reporter->testRunEnded( testRunStats ); |
17216 | } |
17217 | |
17218 | void ListeningReporter::skipTest( TestCaseInfo const& testInfo ) { |
17219 | for ( auto const& listener : m_listeners ) { |
17220 | listener->skipTest( testInfo ); |
17221 | } |
17222 | m_reporter->skipTest( testInfo ); |
17223 | } |
17224 | |
17225 | bool ListeningReporter::isMulti() const { |
17226 | return true; |
17227 | } |
17228 | |
17229 | } // end namespace Catch |
17230 | // end catch_reporter_listening.cpp |
17231 | // start catch_reporter_xml.cpp |
17232 | |
17233 | #if defined(_MSC_VER) |
17234 | #pragma warning(push) |
17235 | #pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch |
17236 | // Note that 4062 (not all labels are handled |
17237 | // and default is missing) is enabled |
17238 | #endif |
17239 | |
17240 | namespace Catch { |
17241 | XmlReporter::XmlReporter( ReporterConfig const& _config ) |
17242 | : StreamingReporterBase( _config ), |
17243 | m_xml(_config.stream()) |
17244 | { |
17245 | m_reporterPrefs.shouldRedirectStdOut = true; |
17246 | m_reporterPrefs.shouldReportAllAssertions = true; |
17247 | } |
17248 | |
17249 | XmlReporter::~XmlReporter() = default; |
17250 | |
17251 | std::string XmlReporter::getDescription() { |
17252 | return "Reports test results as an XML document" ; |
17253 | } |
17254 | |
17255 | std::string XmlReporter::getStylesheetRef() const { |
17256 | return std::string(); |
17257 | } |
17258 | |
17259 | void XmlReporter::writeSourceInfo( SourceLineInfo const& sourceInfo ) { |
17260 | m_xml |
17261 | .writeAttribute( "filename" , sourceInfo.file ) |
17262 | .writeAttribute( "line" , sourceInfo.line ); |
17263 | } |
17264 | |
17265 | void XmlReporter::noMatchingTestCases( std::string const& s ) { |
17266 | StreamingReporterBase::noMatchingTestCases( s ); |
17267 | } |
17268 | |
17269 | void XmlReporter::testRunStarting( TestRunInfo const& testInfo ) { |
17270 | StreamingReporterBase::testRunStarting( testInfo ); |
17271 | std::string stylesheetRef = getStylesheetRef(); |
17272 | if( !stylesheetRef.empty() ) |
17273 | m_xml.writeStylesheetRef( stylesheetRef ); |
17274 | m_xml.startElement( "Catch" ); |
17275 | if( !m_config->name().empty() ) |
17276 | m_xml.writeAttribute( "name" , m_config->name() ); |
17277 | if (m_config->testSpec().hasFilters()) |
17278 | m_xml.writeAttribute( "filters" , serializeFilters( m_config->getTestsOrTags() ) ); |
17279 | if( m_config->rngSeed() != 0 ) |
17280 | m_xml.scopedElement( "Randomness" ) |
17281 | .writeAttribute( "seed" , m_config->rngSeed() ); |
17282 | } |
17283 | |
17284 | void XmlReporter::testGroupStarting( GroupInfo const& groupInfo ) { |
17285 | StreamingReporterBase::testGroupStarting( groupInfo ); |
17286 | m_xml.startElement( "Group" ) |
17287 | .writeAttribute( "name" , groupInfo.name ); |
17288 | } |
17289 | |
17290 | void XmlReporter::testCaseStarting( TestCaseInfo const& testInfo ) { |
17291 | StreamingReporterBase::testCaseStarting(testInfo); |
17292 | m_xml.startElement( "TestCase" ) |
17293 | .writeAttribute( "name" , trim( testInfo.name ) ) |
17294 | .writeAttribute( "description" , testInfo.description ) |
17295 | .writeAttribute( "tags" , testInfo.tagsAsString() ); |
17296 | |
17297 | writeSourceInfo( testInfo.lineInfo ); |
17298 | |
17299 | if ( m_config->showDurations() == ShowDurations::Always ) |
17300 | m_testCaseTimer.start(); |
17301 | m_xml.ensureTagClosed(); |
17302 | } |
17303 | |
17304 | void XmlReporter::sectionStarting( SectionInfo const& sectionInfo ) { |
17305 | StreamingReporterBase::sectionStarting( sectionInfo ); |
17306 | if( m_sectionDepth++ > 0 ) { |
17307 | m_xml.startElement( "Section" ) |
17308 | .writeAttribute( "name" , trim( sectionInfo.name ) ); |
17309 | writeSourceInfo( sectionInfo.lineInfo ); |
17310 | m_xml.ensureTagClosed(); |
17311 | } |
17312 | } |
17313 | |
17314 | void XmlReporter::assertionStarting( AssertionInfo const& ) { } |
17315 | |
17316 | bool XmlReporter::assertionEnded( AssertionStats const& assertionStats ) { |
17317 | |
17318 | AssertionResult const& result = assertionStats.assertionResult; |
17319 | |
17320 | bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); |
17321 | |
17322 | if( includeResults || result.getResultType() == ResultWas::Warning ) { |
17323 | // Print any info messages in <Info> tags. |
17324 | for( auto const& msg : assertionStats.infoMessages ) { |
17325 | if( msg.type == ResultWas::Info && includeResults ) { |
17326 | m_xml.scopedElement( "Info" ) |
17327 | .writeText( msg.message ); |
17328 | } else if ( msg.type == ResultWas::Warning ) { |
17329 | m_xml.scopedElement( "Warning" ) |
17330 | .writeText( msg.message ); |
17331 | } |
17332 | } |
17333 | } |
17334 | |
17335 | // Drop out if result was successful but we're not printing them. |
17336 | if( !includeResults && result.getResultType() != ResultWas::Warning ) |
17337 | return true; |
17338 | |
17339 | // Print the expression if there is one. |
17340 | if( result.hasExpression() ) { |
17341 | m_xml.startElement( "Expression" ) |
17342 | .writeAttribute( "success" , result.succeeded() ) |
17343 | .writeAttribute( "type" , result.getTestMacroName() ); |
17344 | |
17345 | writeSourceInfo( result.getSourceInfo() ); |
17346 | |
17347 | m_xml.scopedElement( "Original" ) |
17348 | .writeText( result.getExpression() ); |
17349 | m_xml.scopedElement( "Expanded" ) |
17350 | .writeText( result.getExpandedExpression() ); |
17351 | } |
17352 | |
17353 | // And... Print a result applicable to each result type. |
17354 | switch( result.getResultType() ) { |
17355 | case ResultWas::ThrewException: |
17356 | m_xml.startElement( "Exception" ); |
17357 | writeSourceInfo( result.getSourceInfo() ); |
17358 | m_xml.writeText( result.getMessage() ); |
17359 | m_xml.endElement(); |
17360 | break; |
17361 | case ResultWas::FatalErrorCondition: |
17362 | m_xml.startElement( "FatalErrorCondition" ); |
17363 | writeSourceInfo( result.getSourceInfo() ); |
17364 | m_xml.writeText( result.getMessage() ); |
17365 | m_xml.endElement(); |
17366 | break; |
17367 | case ResultWas::Info: |
17368 | m_xml.scopedElement( "Info" ) |
17369 | .writeText( result.getMessage() ); |
17370 | break; |
17371 | case ResultWas::Warning: |
17372 | // Warning will already have been written |
17373 | break; |
17374 | case ResultWas::ExplicitFailure: |
17375 | m_xml.startElement( "Failure" ); |
17376 | writeSourceInfo( result.getSourceInfo() ); |
17377 | m_xml.writeText( result.getMessage() ); |
17378 | m_xml.endElement(); |
17379 | break; |
17380 | default: |
17381 | break; |
17382 | } |
17383 | |
17384 | if( result.hasExpression() ) |
17385 | m_xml.endElement(); |
17386 | |
17387 | return true; |
17388 | } |
17389 | |
17390 | void XmlReporter::sectionEnded( SectionStats const& sectionStats ) { |
17391 | StreamingReporterBase::sectionEnded( sectionStats ); |
17392 | if( --m_sectionDepth > 0 ) { |
17393 | XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); |
17394 | e.writeAttribute( "successes" , sectionStats.assertions.passed ); |
17395 | e.writeAttribute( "failures" , sectionStats.assertions.failed ); |
17396 | e.writeAttribute( "expectedFailures" , sectionStats.assertions.failedButOk ); |
17397 | |
17398 | if ( m_config->showDurations() == ShowDurations::Always ) |
17399 | e.writeAttribute( "durationInSeconds" , sectionStats.durationInSeconds ); |
17400 | |
17401 | m_xml.endElement(); |
17402 | } |
17403 | } |
17404 | |
17405 | void XmlReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { |
17406 | StreamingReporterBase::testCaseEnded( testCaseStats ); |
17407 | XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); |
17408 | e.writeAttribute( "success" , testCaseStats.totals.assertions.allOk() ); |
17409 | |
17410 | if ( m_config->showDurations() == ShowDurations::Always ) |
17411 | e.writeAttribute( "durationInSeconds" , m_testCaseTimer.getElapsedSeconds() ); |
17412 | |
17413 | if( !testCaseStats.stdOut.empty() ) |
17414 | m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), XmlFormatting::Newline ); |
17415 | if( !testCaseStats.stdErr.empty() ) |
17416 | m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), XmlFormatting::Newline ); |
17417 | |
17418 | m_xml.endElement(); |
17419 | } |
17420 | |
17421 | void XmlReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { |
17422 | StreamingReporterBase::testGroupEnded( testGroupStats ); |
17423 | // TODO: Check testGroupStats.aborting and act accordingly. |
17424 | m_xml.scopedElement( "OverallResults" ) |
17425 | .writeAttribute( "successes" , testGroupStats.totals.assertions.passed ) |
17426 | .writeAttribute( "failures" , testGroupStats.totals.assertions.failed ) |
17427 | .writeAttribute( "expectedFailures" , testGroupStats.totals.assertions.failedButOk ); |
17428 | m_xml.scopedElement( "OverallResultsCases" ) |
17429 | .writeAttribute( "successes" , testGroupStats.totals.testCases.passed ) |
17430 | .writeAttribute( "failures" , testGroupStats.totals.testCases.failed ) |
17431 | .writeAttribute( "expectedFailures" , testGroupStats.totals.testCases.failedButOk ); |
17432 | m_xml.endElement(); |
17433 | } |
17434 | |
17435 | void XmlReporter::testRunEnded( TestRunStats const& testRunStats ) { |
17436 | StreamingReporterBase::testRunEnded( testRunStats ); |
17437 | m_xml.scopedElement( "OverallResults" ) |
17438 | .writeAttribute( "successes" , testRunStats.totals.assertions.passed ) |
17439 | .writeAttribute( "failures" , testRunStats.totals.assertions.failed ) |
17440 | .writeAttribute( "expectedFailures" , testRunStats.totals.assertions.failedButOk ); |
17441 | m_xml.scopedElement( "OverallResultsCases" ) |
17442 | .writeAttribute( "successes" , testRunStats.totals.testCases.passed ) |
17443 | .writeAttribute( "failures" , testRunStats.totals.testCases.failed ) |
17444 | .writeAttribute( "expectedFailures" , testRunStats.totals.testCases.failedButOk ); |
17445 | m_xml.endElement(); |
17446 | } |
17447 | |
17448 | #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) |
17449 | void XmlReporter::benchmarkPreparing(std::string const& name) { |
17450 | m_xml.startElement("BenchmarkResults" ) |
17451 | .writeAttribute("name" , name); |
17452 | } |
17453 | |
17454 | void XmlReporter::benchmarkStarting(BenchmarkInfo const &info) { |
17455 | m_xml.writeAttribute("samples" , info.samples) |
17456 | .writeAttribute("resamples" , info.resamples) |
17457 | .writeAttribute("iterations" , info.iterations) |
17458 | .writeAttribute("clockResolution" , info.clockResolution) |
17459 | .writeAttribute("estimatedDuration" , info.estimatedDuration) |
17460 | .writeComment("All values in nano seconds" ); |
17461 | } |
17462 | |
17463 | void XmlReporter::benchmarkEnded(BenchmarkStats<> const& benchmarkStats) { |
17464 | m_xml.startElement("mean" ) |
17465 | .writeAttribute("value" , benchmarkStats.mean.point.count()) |
17466 | .writeAttribute("lowerBound" , benchmarkStats.mean.lower_bound.count()) |
17467 | .writeAttribute("upperBound" , benchmarkStats.mean.upper_bound.count()) |
17468 | .writeAttribute("ci" , benchmarkStats.mean.confidence_interval); |
17469 | m_xml.endElement(); |
17470 | m_xml.startElement("standardDeviation" ) |
17471 | .writeAttribute("value" , benchmarkStats.standardDeviation.point.count()) |
17472 | .writeAttribute("lowerBound" , benchmarkStats.standardDeviation.lower_bound.count()) |
17473 | .writeAttribute("upperBound" , benchmarkStats.standardDeviation.upper_bound.count()) |
17474 | .writeAttribute("ci" , benchmarkStats.standardDeviation.confidence_interval); |
17475 | m_xml.endElement(); |
17476 | m_xml.startElement("outliers" ) |
17477 | .writeAttribute("variance" , benchmarkStats.outlierVariance) |
17478 | .writeAttribute("lowMild" , benchmarkStats.outliers.low_mild) |
17479 | .writeAttribute("lowSevere" , benchmarkStats.outliers.low_severe) |
17480 | .writeAttribute("highMild" , benchmarkStats.outliers.high_mild) |
17481 | .writeAttribute("highSevere" , benchmarkStats.outliers.high_severe); |
17482 | m_xml.endElement(); |
17483 | m_xml.endElement(); |
17484 | } |
17485 | |
17486 | void XmlReporter::benchmarkFailed(std::string const &error) { |
17487 | m_xml.scopedElement("failed" ). |
17488 | writeAttribute("message" , error); |
17489 | m_xml.endElement(); |
17490 | } |
17491 | #endif // CATCH_CONFIG_ENABLE_BENCHMARKING |
17492 | |
17493 | CATCH_REGISTER_REPORTER( "xml" , XmlReporter ) |
17494 | |
17495 | } // end namespace Catch |
17496 | |
17497 | #if defined(_MSC_VER) |
17498 | #pragma warning(pop) |
17499 | #endif |
17500 | // end catch_reporter_xml.cpp |
17501 | |
17502 | namespace Catch { |
17503 | LeakDetector leakDetector; |
17504 | } |
17505 | |
17506 | #ifdef __clang__ |
17507 | #pragma clang diagnostic pop |
17508 | #endif |
17509 | |
17510 | // end catch_impl.hpp |
17511 | #endif |
17512 | |
17513 | #ifdef CATCH_CONFIG_MAIN |
17514 | // start catch_default_main.hpp |
17515 | |
17516 | #ifndef __OBJC__ |
17517 | |
17518 | #if defined(CATCH_CONFIG_WCHAR) && defined(CATCH_PLATFORM_WINDOWS) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN) |
17519 | // Standard C/C++ Win32 Unicode wmain entry point |
17520 | extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) { |
17521 | #else |
17522 | // Standard C/C++ main entry point |
17523 | int main (int argc, char * argv[]) { |
17524 | #endif |
17525 | |
17526 | return Catch::Session().run( argc, argv ); |
17527 | } |
17528 | |
17529 | #else // __OBJC__ |
17530 | |
17531 | // Objective-C entry point |
17532 | int main (int argc, char * const argv[]) { |
17533 | #if !CATCH_ARC_ENABLED |
17534 | NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; |
17535 | #endif |
17536 | |
17537 | Catch::registerTestMethods(); |
17538 | int result = Catch::Session().run( argc, (char**)argv ); |
17539 | |
17540 | #if !CATCH_ARC_ENABLED |
17541 | [pool drain]; |
17542 | #endif |
17543 | |
17544 | return result; |
17545 | } |
17546 | |
17547 | #endif // __OBJC__ |
17548 | |
17549 | // end catch_default_main.hpp |
17550 | #endif |
17551 | |
17552 | #if !defined(CATCH_CONFIG_IMPL_ONLY) |
17553 | |
17554 | #ifdef CLARA_CONFIG_MAIN_NOT_DEFINED |
17555 | # undef CLARA_CONFIG_MAIN |
17556 | #endif |
17557 | |
17558 | #if !defined(CATCH_CONFIG_DISABLE) |
17559 | ////// |
17560 | // If this config identifier is defined then all CATCH macros are prefixed with CATCH_ |
17561 | #ifdef CATCH_CONFIG_PREFIX_ALL |
17562 | |
17563 | #define CATCH_REQUIRE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ ) |
17564 | #define CATCH_REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) |
17565 | |
17566 | #define CATCH_REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ ) |
17567 | #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) |
17568 | #define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) |
17569 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) |
17570 | #define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr ) |
17571 | #endif// CATCH_CONFIG_DISABLE_MATCHERS |
17572 | #define CATCH_REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ ) |
17573 | |
17574 | #define CATCH_CHECK( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) |
17575 | #define CATCH_CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) |
17576 | #define CATCH_CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CATCH_CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) |
17577 | #define CATCH_CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) |
17578 | #define CATCH_CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ ) |
17579 | |
17580 | #define CATCH_CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) |
17581 | #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) |
17582 | #define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) |
17583 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) |
17584 | #define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) |
17585 | #endif // CATCH_CONFIG_DISABLE_MATCHERS |
17586 | #define CATCH_CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) |
17587 | |
17588 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) |
17589 | #define CATCH_CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg ) |
17590 | |
17591 | #define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) |
17592 | #endif // CATCH_CONFIG_DISABLE_MATCHERS |
17593 | |
17594 | #define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg ) |
17595 | #define CATCH_UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "CATCH_UNSCOPED_INFO", msg ) |
17596 | #define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) |
17597 | #define CATCH_CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CATCH_CAPTURE",__VA_ARGS__ ) |
17598 | |
17599 | #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) |
17600 | #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) |
17601 | #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) |
17602 | #define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) |
17603 | #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) |
17604 | #define CATCH_DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ ) |
17605 | #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) |
17606 | #define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) |
17607 | #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) |
17608 | |
17609 | #define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE() |
17610 | |
17611 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
17612 | #define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) |
17613 | #define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ ) |
17614 | #define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) |
17615 | #define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) |
17616 | #define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) |
17617 | #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ ) |
17618 | #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) |
17619 | #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) |
17620 | #else |
17621 | #define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) ) |
17622 | #define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ ) ) |
17623 | #define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) ) |
17624 | #define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) ) |
17625 | #define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) ) |
17626 | #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ ) ) |
17627 | #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) ) |
17628 | #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) ) |
17629 | #endif |
17630 | |
17631 | #if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE) |
17632 | #define CATCH_STATIC_REQUIRE( ... ) static_assert( __VA_ARGS__ , #__VA_ARGS__ ); CATCH_SUCCEED( #__VA_ARGS__ ) |
17633 | #define CATCH_STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); CATCH_SUCCEED( #__VA_ARGS__ ) |
17634 | #else |
17635 | #define CATCH_STATIC_REQUIRE( ... ) CATCH_REQUIRE( __VA_ARGS__ ) |
17636 | #define CATCH_STATIC_REQUIRE_FALSE( ... ) CATCH_REQUIRE_FALSE( __VA_ARGS__ ) |
17637 | #endif |
17638 | |
17639 | // "BDD-style" convenience wrappers |
17640 | #define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ ) |
17641 | #define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) |
17642 | #define CATCH_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc ) |
17643 | #define CATCH_AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc ) |
17644 | #define CATCH_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc ) |
17645 | #define CATCH_AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc ) |
17646 | #define CATCH_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc ) |
17647 | #define CATCH_AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc ) |
17648 | |
17649 | #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) |
17650 | #define CATCH_BENCHMARK(...) \ |
17651 | INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,)) |
17652 | #define CATCH_BENCHMARK_ADVANCED(name) \ |
17653 | INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), name) |
17654 | #endif // CATCH_CONFIG_ENABLE_BENCHMARKING |
17655 | |
17656 | // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required |
17657 | #else |
17658 | |
17659 | #define REQUIRE( ... ) INTERNAL_CATCH_TEST( "REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ ) |
17660 | #define REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) |
17661 | |
17662 | #define REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ ) |
17663 | #define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) |
17664 | #define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) |
17665 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) |
17666 | #define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr ) |
17667 | #endif // CATCH_CONFIG_DISABLE_MATCHERS |
17668 | #define REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ ) |
17669 | |
17670 | #define CHECK( ... ) INTERNAL_CATCH_TEST( "CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) |
17671 | #define CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) |
17672 | #define CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) |
17673 | #define CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) |
17674 | #define CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ ) |
17675 | |
17676 | #define CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) |
17677 | #define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) |
17678 | #define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) |
17679 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) |
17680 | #define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) |
17681 | #endif // CATCH_CONFIG_DISABLE_MATCHERS |
17682 | #define CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) |
17683 | |
17684 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) |
17685 | #define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg ) |
17686 | |
17687 | #define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) |
17688 | #endif // CATCH_CONFIG_DISABLE_MATCHERS |
17689 | |
17690 | #define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg ) |
17691 | #define UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "UNSCOPED_INFO", msg ) |
17692 | #define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) |
17693 | #define CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CAPTURE",__VA_ARGS__ ) |
17694 | |
17695 | #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) |
17696 | #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) |
17697 | #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) |
17698 | #define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) |
17699 | #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) |
17700 | #define DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ ) |
17701 | #define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) |
17702 | #define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) |
17703 | #define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) |
17704 | #define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE() |
17705 | |
17706 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
17707 | #define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) |
17708 | #define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ ) |
17709 | #define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) |
17710 | #define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) |
17711 | #define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) |
17712 | #define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ ) |
17713 | #define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) |
17714 | #define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) |
17715 | #define TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE(__VA_ARGS__) |
17716 | #define TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ ) |
17717 | #else |
17718 | #define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) ) |
17719 | #define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ ) ) |
17720 | #define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) ) |
17721 | #define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) ) |
17722 | #define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) ) |
17723 | #define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ ) ) |
17724 | #define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) ) |
17725 | #define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) ) |
17726 | #define TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE( __VA_ARGS__ ) ) |
17727 | #define TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ ) ) |
17728 | #endif |
17729 | |
17730 | #if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE) |
17731 | #define STATIC_REQUIRE( ... ) static_assert( __VA_ARGS__, #__VA_ARGS__ ); SUCCEED( #__VA_ARGS__ ) |
17732 | #define STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); SUCCEED( "!(" #__VA_ARGS__ ")" ) |
17733 | #else |
17734 | #define STATIC_REQUIRE( ... ) REQUIRE( __VA_ARGS__ ) |
17735 | #define STATIC_REQUIRE_FALSE( ... ) REQUIRE_FALSE( __VA_ARGS__ ) |
17736 | #endif |
17737 | |
17738 | #endif |
17739 | |
17740 | #define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) |
17741 | |
17742 | // "BDD-style" convenience wrappers |
17743 | #define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ ) |
17744 | #define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) |
17745 | |
17746 | #define GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc ) |
17747 | #define AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc ) |
17748 | #define WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc ) |
17749 | #define AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc ) |
17750 | #define THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc ) |
17751 | #define AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc ) |
17752 | |
17753 | #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) |
17754 | #define BENCHMARK(...) \ |
17755 | INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,)) |
17756 | #define BENCHMARK_ADVANCED(name) \ |
17757 | INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), name) |
17758 | #endif // CATCH_CONFIG_ENABLE_BENCHMARKING |
17759 | |
17760 | using Catch::Detail::Approx; |
17761 | |
17762 | #else // CATCH_CONFIG_DISABLE |
17763 | |
17764 | ////// |
17765 | // If this config identifier is defined then all CATCH macros are prefixed with CATCH_ |
17766 | #ifdef CATCH_CONFIG_PREFIX_ALL |
17767 | |
17768 | #define CATCH_REQUIRE( ... ) (void)(0) |
17769 | #define CATCH_REQUIRE_FALSE( ... ) (void)(0) |
17770 | |
17771 | #define CATCH_REQUIRE_THROWS( ... ) (void)(0) |
17772 | #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0) |
17773 | #define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) (void)(0) |
17774 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) |
17775 | #define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) |
17776 | #endif// CATCH_CONFIG_DISABLE_MATCHERS |
17777 | #define CATCH_REQUIRE_NOTHROW( ... ) (void)(0) |
17778 | |
17779 | #define CATCH_CHECK( ... ) (void)(0) |
17780 | #define CATCH_CHECK_FALSE( ... ) (void)(0) |
17781 | #define CATCH_CHECKED_IF( ... ) if (__VA_ARGS__) |
17782 | #define CATCH_CHECKED_ELSE( ... ) if (!(__VA_ARGS__)) |
17783 | #define CATCH_CHECK_NOFAIL( ... ) (void)(0) |
17784 | |
17785 | #define CATCH_CHECK_THROWS( ... ) (void)(0) |
17786 | #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) (void)(0) |
17787 | #define CATCH_CHECK_THROWS_WITH( expr, matcher ) (void)(0) |
17788 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) |
17789 | #define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) |
17790 | #endif // CATCH_CONFIG_DISABLE_MATCHERS |
17791 | #define CATCH_CHECK_NOTHROW( ... ) (void)(0) |
17792 | |
17793 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) |
17794 | #define CATCH_CHECK_THAT( arg, matcher ) (void)(0) |
17795 | |
17796 | #define CATCH_REQUIRE_THAT( arg, matcher ) (void)(0) |
17797 | #endif // CATCH_CONFIG_DISABLE_MATCHERS |
17798 | |
17799 | #define CATCH_INFO( msg ) (void)(0) |
17800 | #define CATCH_UNSCOPED_INFO( msg ) (void)(0) |
17801 | #define CATCH_WARN( msg ) (void)(0) |
17802 | #define CATCH_CAPTURE( msg ) (void)(0) |
17803 | |
17804 | #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) |
17805 | #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) |
17806 | #define CATCH_METHOD_AS_TEST_CASE( method, ... ) |
17807 | #define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0) |
17808 | #define CATCH_SECTION( ... ) |
17809 | #define CATCH_DYNAMIC_SECTION( ... ) |
17810 | #define CATCH_FAIL( ... ) (void)(0) |
17811 | #define CATCH_FAIL_CHECK( ... ) (void)(0) |
17812 | #define CATCH_SUCCEED( ... ) (void)(0) |
17813 | |
17814 | #define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) |
17815 | |
17816 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
17817 | #define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) |
17818 | #define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__) |
17819 | #define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__) |
17820 | #define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ ) |
17821 | #define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) |
17822 | #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) |
17823 | #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) |
17824 | #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) |
17825 | #else |
17826 | #define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) ) |
17827 | #define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__) ) |
17828 | #define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__ ) ) |
17829 | #define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ ) ) |
17830 | #define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) |
17831 | #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) |
17832 | #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) |
17833 | #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) |
17834 | #endif |
17835 | |
17836 | // "BDD-style" convenience wrappers |
17837 | #define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) |
17838 | #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 ) |
17839 | #define CATCH_GIVEN( desc ) |
17840 | #define CATCH_AND_GIVEN( desc ) |
17841 | #define CATCH_WHEN( desc ) |
17842 | #define CATCH_AND_WHEN( desc ) |
17843 | #define CATCH_THEN( desc ) |
17844 | #define CATCH_AND_THEN( desc ) |
17845 | |
17846 | #define CATCH_STATIC_REQUIRE( ... ) (void)(0) |
17847 | #define CATCH_STATIC_REQUIRE_FALSE( ... ) (void)(0) |
17848 | |
17849 | // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required |
17850 | #else |
17851 | |
17852 | #define REQUIRE( ... ) (void)(0) |
17853 | #define REQUIRE_FALSE( ... ) (void)(0) |
17854 | |
17855 | #define REQUIRE_THROWS( ... ) (void)(0) |
17856 | #define REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0) |
17857 | #define REQUIRE_THROWS_WITH( expr, matcher ) (void)(0) |
17858 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) |
17859 | #define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) |
17860 | #endif // CATCH_CONFIG_DISABLE_MATCHERS |
17861 | #define REQUIRE_NOTHROW( ... ) (void)(0) |
17862 | |
17863 | #define CHECK( ... ) (void)(0) |
17864 | #define CHECK_FALSE( ... ) (void)(0) |
17865 | #define CHECKED_IF( ... ) if (__VA_ARGS__) |
17866 | #define CHECKED_ELSE( ... ) if (!(__VA_ARGS__)) |
17867 | #define CHECK_NOFAIL( ... ) (void)(0) |
17868 | |
17869 | #define CHECK_THROWS( ... ) (void)(0) |
17870 | #define CHECK_THROWS_AS( expr, exceptionType ) (void)(0) |
17871 | #define CHECK_THROWS_WITH( expr, matcher ) (void)(0) |
17872 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) |
17873 | #define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) |
17874 | #endif // CATCH_CONFIG_DISABLE_MATCHERS |
17875 | #define CHECK_NOTHROW( ... ) (void)(0) |
17876 | |
17877 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) |
17878 | #define CHECK_THAT( arg, matcher ) (void)(0) |
17879 | |
17880 | #define REQUIRE_THAT( arg, matcher ) (void)(0) |
17881 | #endif // CATCH_CONFIG_DISABLE_MATCHERS |
17882 | |
17883 | #define INFO( msg ) (void)(0) |
17884 | #define UNSCOPED_INFO( msg ) (void)(0) |
17885 | #define WARN( msg ) (void)(0) |
17886 | #define CAPTURE( msg ) (void)(0) |
17887 | |
17888 | #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) |
17889 | #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) |
17890 | #define METHOD_AS_TEST_CASE( method, ... ) |
17891 | #define REGISTER_TEST_CASE( Function, ... ) (void)(0) |
17892 | #define SECTION( ... ) |
17893 | #define DYNAMIC_SECTION( ... ) |
17894 | #define FAIL( ... ) (void)(0) |
17895 | #define FAIL_CHECK( ... ) (void)(0) |
17896 | #define SUCCEED( ... ) (void)(0) |
17897 | #define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) |
17898 | |
17899 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
17900 | #define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) |
17901 | #define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__) |
17902 | #define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__) |
17903 | #define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ ) |
17904 | #define TEMPLATE_PRODUCT_TEST_CASE( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ ) |
17905 | #define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ ) |
17906 | #define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) |
17907 | #define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) |
17908 | #else |
17909 | #define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) ) |
17910 | #define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__) ) |
17911 | #define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__ ) ) |
17912 | #define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ ) ) |
17913 | #define TEMPLATE_PRODUCT_TEST_CASE( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ ) |
17914 | #define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ ) |
17915 | #define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) |
17916 | #define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) |
17917 | #endif |
17918 | |
17919 | #define STATIC_REQUIRE( ... ) (void)(0) |
17920 | #define STATIC_REQUIRE_FALSE( ... ) (void)(0) |
17921 | |
17922 | #endif |
17923 | |
17924 | #define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) |
17925 | |
17926 | // "BDD-style" convenience wrappers |
17927 | #define SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) ) |
17928 | #define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className ) |
17929 | |
17930 | #define GIVEN( desc ) |
17931 | #define AND_GIVEN( desc ) |
17932 | #define WHEN( desc ) |
17933 | #define AND_WHEN( desc ) |
17934 | #define THEN( desc ) |
17935 | #define AND_THEN( desc ) |
17936 | |
17937 | using Catch::Detail::Approx; |
17938 | |
17939 | #endif |
17940 | |
17941 | #endif // ! CATCH_CONFIG_IMPL_ONLY |
17942 | |
17943 | // start catch_reenable_warnings.h |
17944 | |
17945 | |
17946 | #ifdef __clang__ |
17947 | # ifdef __ICC // icpc defines the __clang__ macro |
17948 | # pragma warning(pop) |
17949 | # else |
17950 | # pragma clang diagnostic pop |
17951 | # endif |
17952 | #elif defined __GNUC__ |
17953 | # pragma GCC diagnostic pop |
17954 | #endif |
17955 | |
17956 | // end catch_reenable_warnings.h |
17957 | // end catch.hpp |
17958 | #endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED |
17959 | |
17960 | |