1 | /* |
2 | * Catch v2.13.8 |
3 | * Generated: 2022-01-03 21:20:09.589503 |
4 | * ---------------------------------------------------------- |
5 | * This file has been merged from multiple headers. Please don't edit it directly |
6 | * Copyright (c) 2022 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 8 |
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 | // Universal Windows platform does not support SEH |
244 | // Or console colours (or console at all...) |
245 | # if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) |
246 | # define CATCH_CONFIG_COLOUR_NONE |
247 | # else |
248 | # define CATCH_INTERNAL_CONFIG_WINDOWS_SEH |
249 | # endif |
250 | |
251 | # if !defined(__clang__) // Handle Clang masquerading for msvc |
252 | |
253 | // MSVC traditional preprocessor needs some workaround for __VA_ARGS__ |
254 | // _MSVC_TRADITIONAL == 0 means new conformant preprocessor |
255 | // _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor |
256 | # if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL) |
257 | # define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
258 | # endif // MSVC_TRADITIONAL |
259 | |
260 | // Only do this if we're not using clang on Windows, which uses `diagnostic push` & `diagnostic pop` |
261 | # define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) ) |
262 | # define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) ) |
263 | # endif // __clang__ |
264 | |
265 | #endif // _MSC_VER |
266 | |
267 | #if defined(_REENTRANT) || defined(_MSC_VER) |
268 | // Enable async processing, as -pthread is specified or no additional linking is required |
269 | # define CATCH_INTERNAL_CONFIG_USE_ASYNC |
270 | #endif // _MSC_VER |
271 | |
272 | //////////////////////////////////////////////////////////////////////////////// |
273 | // Check if we are compiled with -fno-exceptions or equivalent |
274 | #if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND) |
275 | # define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED |
276 | #endif |
277 | |
278 | //////////////////////////////////////////////////////////////////////////////// |
279 | // DJGPP |
280 | #ifdef __DJGPP__ |
281 | # define CATCH_INTERNAL_CONFIG_NO_WCHAR |
282 | #endif // __DJGPP__ |
283 | |
284 | //////////////////////////////////////////////////////////////////////////////// |
285 | // Embarcadero C++Build |
286 | #if defined(__BORLANDC__) |
287 | #define CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN |
288 | #endif |
289 | |
290 | //////////////////////////////////////////////////////////////////////////////// |
291 | |
292 | // Use of __COUNTER__ is suppressed during code analysis in |
293 | // CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly |
294 | // handled by it. |
295 | // Otherwise all supported compilers support COUNTER macro, |
296 | // but user still might want to turn it off |
297 | #if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) |
298 | #define CATCH_INTERNAL_CONFIG_COUNTER |
299 | #endif |
300 | |
301 | //////////////////////////////////////////////////////////////////////////////// |
302 | |
303 | // RTX is a special version of Windows that is real time. |
304 | // This means that it is detected as Windows, but does not provide |
305 | // the same set of capabilities as real Windows does. |
306 | #if defined(UNDER_RTSS) || defined(RTX64_BUILD) |
307 | #define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH |
308 | #define CATCH_INTERNAL_CONFIG_NO_ASYNC |
309 | #define CATCH_CONFIG_COLOUR_NONE |
310 | #endif |
311 | |
312 | #if !defined(_GLIBCXX_USE_C99_MATH_TR1) |
313 | #define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER |
314 | #endif |
315 | |
316 | // Various stdlib support checks that require __has_include |
317 | #if defined(__has_include) |
318 | // Check if string_view is available and usable |
319 | #if __has_include(<string_view>) && defined(CATCH_CPP17_OR_GREATER) |
320 | # define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW |
321 | #endif |
322 | |
323 | // Check if optional is available and usable |
324 | # if __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER) |
325 | # define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL |
326 | # endif // __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER) |
327 | |
328 | // Check if byte is available and usable |
329 | # if __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER) |
330 | # include <cstddef> |
331 | # if defined(__cpp_lib_byte) && (__cpp_lib_byte > 0) |
332 | # define CATCH_INTERNAL_CONFIG_CPP17_BYTE |
333 | # endif |
334 | # endif // __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER) |
335 | |
336 | // Check if variant is available and usable |
337 | # if __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER) |
338 | # if defined(__clang__) && (__clang_major__ < 8) |
339 | // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852 |
340 | // fix should be in clang 8, workaround in libstdc++ 8.2 |
341 | # include <ciso646> |
342 | # if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) |
343 | # define CATCH_CONFIG_NO_CPP17_VARIANT |
344 | # else |
345 | # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT |
346 | # endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) |
347 | # else |
348 | # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT |
349 | # endif // defined(__clang__) && (__clang_major__ < 8) |
350 | # endif // __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER) |
351 | #endif // defined(__has_include) |
352 | |
353 | #if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) |
354 | # define CATCH_CONFIG_COUNTER |
355 | #endif |
356 | #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) |
357 | # define CATCH_CONFIG_WINDOWS_SEH |
358 | #endif |
359 | // This is set by default, because we assume that unix compilers are posix-signal-compatible by default. |
360 | #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) |
361 | # define CATCH_CONFIG_POSIX_SIGNALS |
362 | #endif |
363 | // This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions. |
364 | #if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR) |
365 | # define CATCH_CONFIG_WCHAR |
366 | #endif |
367 | |
368 | #if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING) |
369 | # define CATCH_CONFIG_CPP11_TO_STRING |
370 | #endif |
371 | |
372 | #if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL) |
373 | # define CATCH_CONFIG_CPP17_OPTIONAL |
374 | #endif |
375 | |
376 | #if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW) |
377 | # define CATCH_CONFIG_CPP17_STRING_VIEW |
378 | #endif |
379 | |
380 | #if defined(CATCH_INTERNAL_CONFIG_CPP17_VARIANT) && !defined(CATCH_CONFIG_NO_CPP17_VARIANT) && !defined(CATCH_CONFIG_CPP17_VARIANT) |
381 | # define CATCH_CONFIG_CPP17_VARIANT |
382 | #endif |
383 | |
384 | #if defined(CATCH_INTERNAL_CONFIG_CPP17_BYTE) && !defined(CATCH_CONFIG_NO_CPP17_BYTE) && !defined(CATCH_CONFIG_CPP17_BYTE) |
385 | # define CATCH_CONFIG_CPP17_BYTE |
386 | #endif |
387 | |
388 | #if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) |
389 | # define CATCH_INTERNAL_CONFIG_NEW_CAPTURE |
390 | #endif |
391 | |
392 | #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) |
393 | # define CATCH_CONFIG_NEW_CAPTURE |
394 | #endif |
395 | |
396 | #if !defined(CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) |
397 | # define CATCH_CONFIG_DISABLE_EXCEPTIONS |
398 | #endif |
399 | |
400 | #if defined(CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_NO_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_POLYFILL_ISNAN) |
401 | # define CATCH_CONFIG_POLYFILL_ISNAN |
402 | #endif |
403 | |
404 | #if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC) && !defined(CATCH_INTERNAL_CONFIG_NO_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC) |
405 | # define CATCH_CONFIG_USE_ASYNC |
406 | #endif |
407 | |
408 | #if defined(CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_NO_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_ANDROID_LOGWRITE) |
409 | # define CATCH_CONFIG_ANDROID_LOGWRITE |
410 | #endif |
411 | |
412 | #if defined(CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_NO_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) |
413 | # define CATCH_CONFIG_GLOBAL_NEXTAFTER |
414 | #endif |
415 | |
416 | // Even if we do not think the compiler has that warning, we still have |
417 | // to provide a macro that can be used by the code. |
418 | #if !defined(CATCH_INTERNAL_START_WARNINGS_SUPPRESSION) |
419 | # define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION |
420 | #endif |
421 | #if !defined(CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION) |
422 | # define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION |
423 | #endif |
424 | #if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) |
425 | # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS |
426 | #endif |
427 | #if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) |
428 | # define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS |
429 | #endif |
430 | #if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS) |
431 | # define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS |
432 | #endif |
433 | #if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS) |
434 | # define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS |
435 | #endif |
436 | |
437 | // The goal of this macro is to avoid evaluation of the arguments, but |
438 | // still have the compiler warn on problems inside... |
439 | #if !defined(CATCH_INTERNAL_IGNORE_BUT_WARN) |
440 | # define CATCH_INTERNAL_IGNORE_BUT_WARN(...) |
441 | #endif |
442 | |
443 | #if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10) |
444 | # undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS |
445 | #elif defined(__clang__) && (__clang_major__ < 5) |
446 | # undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS |
447 | #endif |
448 | |
449 | #if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS) |
450 | # define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS |
451 | #endif |
452 | |
453 | #if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) |
454 | #define CATCH_TRY if ((true)) |
455 | #define CATCH_CATCH_ALL if ((false)) |
456 | #define CATCH_CATCH_ANON(type) if ((false)) |
457 | #else |
458 | #define CATCH_TRY try |
459 | #define CATCH_CATCH_ALL catch (...) |
460 | #define CATCH_CATCH_ANON(type) catch (type) |
461 | #endif |
462 | |
463 | #if defined(CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_NO_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) |
464 | #define CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
465 | #endif |
466 | |
467 | // end catch_compiler_capabilities.h |
468 | #define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line |
469 | #define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) |
470 | #ifdef CATCH_CONFIG_COUNTER |
471 | # define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) |
472 | #else |
473 | # define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) |
474 | #endif |
475 | |
476 | #include <iosfwd> |
477 | #include <string> |
478 | #include <cstdint> |
479 | |
480 | // We need a dummy global operator<< so we can bring it into Catch namespace later |
481 | struct Catch_global_namespace_dummy {}; |
482 | std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy); |
483 | |
484 | namespace Catch { |
485 | |
486 | struct CaseSensitive { enum Choice { |
487 | Yes, |
488 | No |
489 | }; }; |
490 | |
491 | class NonCopyable { |
492 | NonCopyable( NonCopyable const& ) = delete; |
493 | NonCopyable( NonCopyable && ) = delete; |
494 | NonCopyable& operator = ( NonCopyable const& ) = delete; |
495 | NonCopyable& operator = ( NonCopyable && ) = delete; |
496 | |
497 | protected: |
498 | NonCopyable(); |
499 | virtual ~NonCopyable(); |
500 | }; |
501 | |
502 | struct SourceLineInfo { |
503 | |
504 | SourceLineInfo() = delete; |
505 | SourceLineInfo( char const* _file, std::size_t _line ) noexcept |
506 | : file( _file ), |
507 | line( _line ) |
508 | {} |
509 | |
510 | SourceLineInfo( SourceLineInfo const& other ) = default; |
511 | SourceLineInfo& operator = ( SourceLineInfo const& ) = default; |
512 | SourceLineInfo( SourceLineInfo&& ) noexcept = default; |
513 | SourceLineInfo& operator = ( SourceLineInfo&& ) noexcept = default; |
514 | |
515 | bool empty() const noexcept { return file[0] == '\0'; } |
516 | bool operator == ( SourceLineInfo const& other ) const noexcept; |
517 | bool operator < ( SourceLineInfo const& other ) const noexcept; |
518 | |
519 | char const* file; |
520 | std::size_t line; |
521 | }; |
522 | |
523 | std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); |
524 | |
525 | // Bring in operator<< from global namespace into Catch namespace |
526 | // This is necessary because the overload of operator<< above makes |
527 | // lookup stop at namespace Catch |
528 | using ::operator<<; |
529 | |
530 | // Use this in variadic streaming macros to allow |
531 | // >> +StreamEndStop |
532 | // as well as |
533 | // >> stuff +StreamEndStop |
534 | struct StreamEndStop { |
535 | std::string operator+() const; |
536 | }; |
537 | template<typename T> |
538 | T const& operator + ( T const& value, StreamEndStop ) { |
539 | return value; |
540 | } |
541 | } |
542 | |
543 | #define CATCH_INTERNAL_LINEINFO \ |
544 | ::Catch::SourceLineInfo( __FILE__, static_cast<std::size_t>( __LINE__ ) ) |
545 | |
546 | // end catch_common.h |
547 | namespace Catch { |
548 | |
549 | struct RegistrarForTagAliases { |
550 | RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); |
551 | }; |
552 | |
553 | } // end namespace Catch |
554 | |
555 | #define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \ |
556 | CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ |
557 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ |
558 | namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \ |
559 | CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION |
560 | |
561 | // end catch_tag_alias_autoregistrar.h |
562 | // start catch_test_registry.h |
563 | |
564 | // start catch_interfaces_testcase.h |
565 | |
566 | #include <vector> |
567 | |
568 | namespace Catch { |
569 | |
570 | class TestSpec; |
571 | |
572 | struct ITestInvoker { |
573 | virtual void invoke () const = 0; |
574 | virtual ~ITestInvoker(); |
575 | }; |
576 | |
577 | class TestCase; |
578 | struct IConfig; |
579 | |
580 | struct ITestCaseRegistry { |
581 | virtual ~ITestCaseRegistry(); |
582 | virtual std::vector<TestCase> const& getAllTests() const = 0; |
583 | virtual std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const = 0; |
584 | }; |
585 | |
586 | bool isThrowSafe( TestCase const& testCase, IConfig const& config ); |
587 | bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); |
588 | std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ); |
589 | std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ); |
590 | |
591 | } |
592 | |
593 | // end catch_interfaces_testcase.h |
594 | // start catch_stringref.h |
595 | |
596 | #include <cstddef> |
597 | #include <string> |
598 | #include <iosfwd> |
599 | #include <cassert> |
600 | |
601 | namespace Catch { |
602 | |
603 | /// A non-owning string class (similar to the forthcoming std::string_view) |
604 | /// Note that, because a StringRef may be a substring of another string, |
605 | /// it may not be null terminated. |
606 | class StringRef { |
607 | public: |
608 | using size_type = std::size_t; |
609 | using const_iterator = const char*; |
610 | |
611 | private: |
612 | static constexpr char const* const s_empty = "" ; |
613 | |
614 | char const* m_start = s_empty; |
615 | size_type m_size = 0; |
616 | |
617 | public: // construction |
618 | constexpr StringRef() noexcept = default; |
619 | |
620 | StringRef( char const* rawChars ) noexcept; |
621 | |
622 | constexpr StringRef( char const* rawChars, size_type size ) noexcept |
623 | : m_start( rawChars ), |
624 | m_size( size ) |
625 | {} |
626 | |
627 | StringRef( std::string const& stdString ) noexcept |
628 | : m_start( stdString.c_str() ), |
629 | m_size( stdString.size() ) |
630 | {} |
631 | |
632 | explicit operator std::string() const { |
633 | return std::string(m_start, m_size); |
634 | } |
635 | |
636 | public: // operators |
637 | auto operator == ( StringRef const& other ) const noexcept -> bool; |
638 | auto operator != (StringRef const& other) const noexcept -> bool { |
639 | return !(*this == other); |
640 | } |
641 | |
642 | auto operator[] ( size_type index ) const noexcept -> char { |
643 | assert(index < m_size); |
644 | return m_start[index]; |
645 | } |
646 | |
647 | public: // named queries |
648 | constexpr auto empty() const noexcept -> bool { |
649 | return m_size == 0; |
650 | } |
651 | constexpr auto size() const noexcept -> size_type { |
652 | return m_size; |
653 | } |
654 | |
655 | // Returns the current start pointer. If the StringRef is not |
656 | // null-terminated, throws std::domain_exception |
657 | auto c_str() const -> char const*; |
658 | |
659 | public: // substrings and searches |
660 | // Returns a substring of [start, start + length). |
661 | // If start + length > size(), then the substring is [start, size()). |
662 | // If start > size(), then the substring is empty. |
663 | auto substr( size_type start, size_type length ) const noexcept -> StringRef; |
664 | |
665 | // Returns the current start pointer. May not be null-terminated. |
666 | auto data() const noexcept -> char const*; |
667 | |
668 | constexpr auto isNullTerminated() const noexcept -> bool { |
669 | return m_start[m_size] == '\0'; |
670 | } |
671 | |
672 | public: // iterators |
673 | constexpr const_iterator begin() const { return m_start; } |
674 | constexpr const_iterator end() const { return m_start + m_size; } |
675 | }; |
676 | |
677 | auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&; |
678 | auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; |
679 | |
680 | constexpr auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { |
681 | return StringRef( rawChars, size ); |
682 | } |
683 | } // namespace Catch |
684 | |
685 | constexpr auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { |
686 | return Catch::StringRef( rawChars, size ); |
687 | } |
688 | |
689 | // end catch_stringref.h |
690 | // start catch_preprocessor.hpp |
691 | |
692 | |
693 | #define CATCH_RECURSION_LEVEL0(...) __VA_ARGS__ |
694 | #define CATCH_RECURSION_LEVEL1(...) CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(__VA_ARGS__))) |
695 | #define CATCH_RECURSION_LEVEL2(...) CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(__VA_ARGS__))) |
696 | #define CATCH_RECURSION_LEVEL3(...) CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(__VA_ARGS__))) |
697 | #define CATCH_RECURSION_LEVEL4(...) CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(__VA_ARGS__))) |
698 | #define CATCH_RECURSION_LEVEL5(...) CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(__VA_ARGS__))) |
699 | |
700 | #ifdef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
701 | #define INTERNAL_CATCH_EXPAND_VARGS(...) __VA_ARGS__ |
702 | // MSVC needs more evaluations |
703 | #define CATCH_RECURSION_LEVEL6(...) CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(__VA_ARGS__))) |
704 | #define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL6(CATCH_RECURSION_LEVEL6(__VA_ARGS__)) |
705 | #else |
706 | #define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL5(__VA_ARGS__) |
707 | #endif |
708 | |
709 | #define CATCH_REC_END(...) |
710 | #define CATCH_REC_OUT |
711 | |
712 | #define CATCH_EMPTY() |
713 | #define CATCH_DEFER(id) id CATCH_EMPTY() |
714 | |
715 | #define CATCH_REC_GET_END2() 0, CATCH_REC_END |
716 | #define CATCH_REC_GET_END1(...) CATCH_REC_GET_END2 |
717 | #define CATCH_REC_GET_END(...) CATCH_REC_GET_END1 |
718 | #define CATCH_REC_NEXT0(test, next, ...) next CATCH_REC_OUT |
719 | #define CATCH_REC_NEXT1(test, next) CATCH_DEFER ( CATCH_REC_NEXT0 ) ( test, next, 0) |
720 | #define CATCH_REC_NEXT(test, next) CATCH_REC_NEXT1(CATCH_REC_GET_END test, next) |
721 | |
722 | #define CATCH_REC_LIST0(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) |
723 | #define CATCH_REC_LIST1(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0) ) ( f, peek, __VA_ARGS__ ) |
724 | #define CATCH_REC_LIST2(f, x, peek, ...) f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) |
725 | |
726 | #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__ ) |
727 | #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__ ) |
728 | #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__ ) |
729 | |
730 | // Applies the function macro `f` to each of the remaining parameters, inserts commas between the results, |
731 | // and passes userdata as the first parameter to each invocation, |
732 | // e.g. CATCH_REC_LIST_UD(f, x, a, b, c) evaluates to f(x, a), f(x, b), f(x, c) |
733 | #define CATCH_REC_LIST_UD(f, userdata, ...) CATCH_RECURSE(CATCH_REC_LIST2_UD(f, userdata, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) |
734 | |
735 | #define CATCH_REC_LIST(f, ...) CATCH_RECURSE(CATCH_REC_LIST2(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) |
736 | |
737 | #define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param) |
738 | #define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__ |
739 | #define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__ |
740 | #define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF |
741 | #define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__) |
742 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
743 | #define INTERNAL_CATCH_STRINGIZE2(...) #__VA_ARGS__ |
744 | #define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) |
745 | #else |
746 | // MSVC is adding extra space and needs another indirection to expand INTERNAL_CATCH_NOINTERNAL_CATCH_DEF |
747 | #define INTERNAL_CATCH_STRINGIZE2(...) INTERNAL_CATCH_STRINGIZE3(__VA_ARGS__) |
748 | #define INTERNAL_CATCH_STRINGIZE3(...) #__VA_ARGS__ |
749 | #define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1) |
750 | #endif |
751 | |
752 | #define INTERNAL_CATCH_MAKE_NAMESPACE2(...) ns_##__VA_ARGS__ |
753 | #define INTERNAL_CATCH_MAKE_NAMESPACE(name) INTERNAL_CATCH_MAKE_NAMESPACE2(name) |
754 | |
755 | #define INTERNAL_CATCH_REMOVE_PARENS(...) INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF __VA_ARGS__) |
756 | |
757 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
758 | #define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS_GEN(__VA_ARGS__)>()) |
759 | #define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)) |
760 | #else |
761 | #define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) INTERNAL_CATCH_EXPAND_VARGS(decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS_GEN(__VA_ARGS__)>())) |
762 | #define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))) |
763 | #endif |
764 | |
765 | #define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(...)\ |
766 | CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,__VA_ARGS__) |
767 | |
768 | #define INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_0) INTERNAL_CATCH_REMOVE_PARENS(_0) |
769 | #define INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_0, _1) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_1) |
770 | #define INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_0, _1, _2) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_1, _2) |
771 | #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) |
772 | #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) |
773 | #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) |
774 | #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) |
775 | #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) |
776 | #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) |
777 | #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) |
778 | #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) |
779 | |
780 | #define INTERNAL_CATCH_VA_NARGS_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N |
781 | |
782 | #define INTERNAL_CATCH_TYPE_GEN\ |
783 | template<typename...> struct TypeList {};\ |
784 | template<typename...Ts>\ |
785 | constexpr auto get_wrapper() noexcept -> TypeList<Ts...> { return {}; }\ |
786 | template<template<typename...> class...> struct TemplateTypeList{};\ |
787 | template<template<typename...> class...Cs>\ |
788 | constexpr auto get_wrapper() noexcept -> TemplateTypeList<Cs...> { return {}; }\ |
789 | template<typename...>\ |
790 | struct append;\ |
791 | template<typename...>\ |
792 | struct rewrap;\ |
793 | template<template<typename...> class, typename...>\ |
794 | struct create;\ |
795 | template<template<typename...> class, typename>\ |
796 | struct convert;\ |
797 | \ |
798 | template<typename T> \ |
799 | struct append<T> { using type = T; };\ |
800 | template< template<typename...> class L1, typename...E1, template<typename...> class L2, typename...E2, typename...Rest>\ |
801 | struct append<L1<E1...>, L2<E2...>, Rest...> { using type = typename append<L1<E1...,E2...>, Rest...>::type; };\ |
802 | template< template<typename...> class L1, typename...E1, typename...Rest>\ |
803 | struct append<L1<E1...>, TypeList<mpl_::na>, Rest...> { using type = L1<E1...>; };\ |
804 | \ |
805 | template< template<typename...> class Container, template<typename...> class List, typename...elems>\ |
806 | struct rewrap<TemplateTypeList<Container>, List<elems...>> { using type = TypeList<Container<elems...>>; };\ |
807 | template< template<typename...> class Container, template<typename...> class List, class...Elems, typename...Elements>\ |
808 | struct rewrap<TemplateTypeList<Container>, List<Elems...>, Elements...> { using type = typename append<TypeList<Container<Elems...>>, typename rewrap<TemplateTypeList<Container>, Elements...>::type>::type; };\ |
809 | \ |
810 | template<template <typename...> class Final, template< typename...> class...Containers, typename...Types>\ |
811 | struct create<Final, TemplateTypeList<Containers...>, TypeList<Types...>> { using type = typename append<Final<>, typename rewrap<TemplateTypeList<Containers>, Types...>::type...>::type; };\ |
812 | template<template <typename...> class Final, template <typename...> class List, typename...Ts>\ |
813 | struct convert<Final, List<Ts...>> { using type = typename append<Final<>,TypeList<Ts>...>::type; }; |
814 | |
815 | #define INTERNAL_CATCH_NTTP_1(signature, ...)\ |
816 | template<INTERNAL_CATCH_REMOVE_PARENS(signature)> struct Nttp{};\ |
817 | template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\ |
818 | constexpr auto get_wrapper() noexcept -> Nttp<__VA_ARGS__> { return {}; } \ |
819 | template<template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...> struct NttpTemplateTypeList{};\ |
820 | template<template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...Cs>\ |
821 | constexpr auto get_wrapper() noexcept -> NttpTemplateTypeList<Cs...> { return {}; } \ |
822 | \ |
823 | template< template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class Container, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class List, INTERNAL_CATCH_REMOVE_PARENS(signature)>\ |
824 | struct rewrap<NttpTemplateTypeList<Container>, List<__VA_ARGS__>> { using type = TypeList<Container<__VA_ARGS__>>; };\ |
825 | template< template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class Container, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class List, INTERNAL_CATCH_REMOVE_PARENS(signature), typename...Elements>\ |
826 | struct rewrap<NttpTemplateTypeList<Container>, List<__VA_ARGS__>, Elements...> { using type = typename append<TypeList<Container<__VA_ARGS__>>, typename rewrap<NttpTemplateTypeList<Container>, Elements...>::type>::type; };\ |
827 | template<template <typename...> class Final, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...Containers, typename...Types>\ |
828 | struct create<Final, NttpTemplateTypeList<Containers...>, TypeList<Types...>> { using type = typename append<Final<>, typename rewrap<NttpTemplateTypeList<Containers>, Types...>::type...>::type; }; |
829 | |
830 | #define INTERNAL_CATCH_DECLARE_SIG_TEST0(TestName) |
831 | #define INTERNAL_CATCH_DECLARE_SIG_TEST1(TestName, signature)\ |
832 | template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\ |
833 | static void TestName() |
834 | #define INTERNAL_CATCH_DECLARE_SIG_TEST_X(TestName, signature, ...)\ |
835 | template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\ |
836 | static void TestName() |
837 | |
838 | #define INTERNAL_CATCH_DEFINE_SIG_TEST0(TestName) |
839 | #define INTERNAL_CATCH_DEFINE_SIG_TEST1(TestName, signature)\ |
840 | template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\ |
841 | static void TestName() |
842 | #define INTERNAL_CATCH_DEFINE_SIG_TEST_X(TestName, signature,...)\ |
843 | template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\ |
844 | static void TestName() |
845 | |
846 | #define INTERNAL_CATCH_NTTP_REGISTER0(TestFunc, signature)\ |
847 | template<typename Type>\ |
848 | void reg_test(TypeList<Type>, Catch::NameAndTags nameAndTags)\ |
849 | {\ |
850 | Catch::AutoReg( Catch::makeTestInvoker(&TestFunc<Type>), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), nameAndTags);\ |
851 | } |
852 | |
853 | #define INTERNAL_CATCH_NTTP_REGISTER(TestFunc, signature, ...)\ |
854 | template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\ |
855 | void reg_test(Nttp<__VA_ARGS__>, Catch::NameAndTags nameAndTags)\ |
856 | {\ |
857 | Catch::AutoReg( Catch::makeTestInvoker(&TestFunc<__VA_ARGS__>), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), nameAndTags);\ |
858 | } |
859 | |
860 | #define INTERNAL_CATCH_NTTP_REGISTER_METHOD0(TestName, signature, ...)\ |
861 | template<typename Type>\ |
862 | void reg_test(TypeList<Type>, Catch::StringRef className, Catch::NameAndTags nameAndTags)\ |
863 | {\ |
864 | Catch::AutoReg( Catch::makeTestInvoker(&TestName<Type>::test), CATCH_INTERNAL_LINEINFO, className, nameAndTags);\ |
865 | } |
866 | |
867 | #define INTERNAL_CATCH_NTTP_REGISTER_METHOD(TestName, signature, ...)\ |
868 | template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\ |
869 | void reg_test(Nttp<__VA_ARGS__>, Catch::StringRef className, Catch::NameAndTags nameAndTags)\ |
870 | {\ |
871 | Catch::AutoReg( Catch::makeTestInvoker(&TestName<__VA_ARGS__>::test), CATCH_INTERNAL_LINEINFO, className, nameAndTags);\ |
872 | } |
873 | |
874 | #define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD0(TestName, ClassName) |
875 | #define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD1(TestName, ClassName, signature)\ |
876 | template<typename TestType> \ |
877 | struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName)<TestType> { \ |
878 | void test();\ |
879 | } |
880 | |
881 | #define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X(TestName, ClassName, signature, ...)\ |
882 | template<INTERNAL_CATCH_REMOVE_PARENS(signature)> \ |
883 | struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName)<__VA_ARGS__> { \ |
884 | void test();\ |
885 | } |
886 | |
887 | #define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD0(TestName) |
888 | #define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD1(TestName, signature)\ |
889 | template<typename TestType> \ |
890 | void INTERNAL_CATCH_MAKE_NAMESPACE(TestName)::TestName<TestType>::test() |
891 | #define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X(TestName, signature, ...)\ |
892 | template<INTERNAL_CATCH_REMOVE_PARENS(signature)> \ |
893 | void INTERNAL_CATCH_MAKE_NAMESPACE(TestName)::TestName<__VA_ARGS__>::test() |
894 | |
895 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
896 | #define INTERNAL_CATCH_NTTP_0 |
897 | #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) |
898 | #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__) |
899 | #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__) |
900 | #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__) |
901 | #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__) |
902 | #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__) |
903 | #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__) |
904 | #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__) |
905 | #else |
906 | #define INTERNAL_CATCH_NTTP_0(signature) |
907 | #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__)) |
908 | #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__)) |
909 | #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__)) |
910 | #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__)) |
911 | #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__)) |
912 | #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__)) |
913 | #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__)) |
914 | #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__)) |
915 | #endif |
916 | |
917 | // end catch_preprocessor.hpp |
918 | // start catch_meta.hpp |
919 | |
920 | |
921 | #include <type_traits> |
922 | |
923 | namespace Catch { |
924 | template<typename T> |
925 | struct always_false : std::false_type {}; |
926 | |
927 | template <typename> struct true_given : std::true_type {}; |
928 | struct is_callable_tester { |
929 | template <typename Fun, typename... Args> |
930 | true_given<decltype(std::declval<Fun>()(std::declval<Args>()...))> static test(int); |
931 | template <typename...> |
932 | std::false_type static test(...); |
933 | }; |
934 | |
935 | template <typename T> |
936 | struct is_callable; |
937 | |
938 | template <typename Fun, typename... Args> |
939 | struct is_callable<Fun(Args...)> : decltype(is_callable_tester::test<Fun, Args...>(0)) {}; |
940 | |
941 | #if defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703 |
942 | // std::result_of is deprecated in C++17 and removed in C++20. Hence, it is |
943 | // replaced with std::invoke_result here. |
944 | template <typename Func, typename... U> |
945 | using FunctionReturnType = std::remove_reference_t<std::remove_cv_t<std::invoke_result_t<Func, U...>>>; |
946 | #else |
947 | // Keep ::type here because we still support C++11 |
948 | template <typename Func, typename... U> |
949 | using FunctionReturnType = typename std::remove_reference<typename std::remove_cv<typename std::result_of<Func(U...)>::type>::type>::type; |
950 | #endif |
951 | |
952 | } // namespace Catch |
953 | |
954 | namespace mpl_{ |
955 | struct na; |
956 | } |
957 | |
958 | // end catch_meta.hpp |
959 | namespace Catch { |
960 | |
961 | template<typename C> |
962 | class TestInvokerAsMethod : public ITestInvoker { |
963 | void (C::*m_testAsMethod)(); |
964 | public: |
965 | TestInvokerAsMethod( void (C::*testAsMethod)() ) noexcept : m_testAsMethod( testAsMethod ) {} |
966 | |
967 | void invoke() const override { |
968 | C obj; |
969 | (obj.*m_testAsMethod)(); |
970 | } |
971 | }; |
972 | |
973 | auto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker*; |
974 | |
975 | template<typename C> |
976 | auto makeTestInvoker( void (C::*testAsMethod)() ) noexcept -> ITestInvoker* { |
977 | return new(std::nothrow) TestInvokerAsMethod<C>( testAsMethod ); |
978 | } |
979 | |
980 | struct NameAndTags { |
981 | NameAndTags( StringRef const& name_ = StringRef(), StringRef const& tags_ = StringRef() ) noexcept; |
982 | StringRef name; |
983 | StringRef tags; |
984 | }; |
985 | |
986 | struct AutoReg : NonCopyable { |
987 | AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept; |
988 | ~AutoReg(); |
989 | }; |
990 | |
991 | } // end namespace Catch |
992 | |
993 | #if defined(CATCH_CONFIG_DISABLE) |
994 | #define INTERNAL_CATCH_TESTCASE_NO_REGISTRATION( TestName, ... ) \ |
995 | static void TestName() |
996 | #define INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... ) \ |
997 | namespace{ \ |
998 | struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \ |
999 | void test(); \ |
1000 | }; \ |
1001 | } \ |
1002 | void TestName::test() |
1003 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( TestName, TestFunc, Name, Tags, Signature, ... ) \ |
1004 | INTERNAL_CATCH_DEFINE_SIG_TEST(TestFunc, INTERNAL_CATCH_REMOVE_PARENS(Signature)) |
1005 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( TestNameClass, TestName, ClassName, Name, Tags, Signature, ... ) \ |
1006 | namespace{ \ |
1007 | namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName) { \ |
1008 | INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, INTERNAL_CATCH_REMOVE_PARENS(Signature));\ |
1009 | } \ |
1010 | } \ |
1011 | INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature)) |
1012 | |
1013 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
1014 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(Name, Tags, ...) \ |
1015 | 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__ ) |
1016 | #else |
1017 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(Name, Tags, ...) \ |
1018 | 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__ ) ) |
1019 | #endif |
1020 | |
1021 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
1022 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(Name, Tags, Signature, ...) \ |
1023 | 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__ ) |
1024 | #else |
1025 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(Name, Tags, Signature, ...) \ |
1026 | 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__ ) ) |
1027 | #endif |
1028 | |
1029 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
1030 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( ClassName, Name, Tags,... ) \ |
1031 | 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__ ) |
1032 | #else |
1033 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( ClassName, Name, Tags,... ) \ |
1034 | 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__ ) ) |
1035 | #endif |
1036 | |
1037 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
1038 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION( ClassName, Name, Tags, Signature, ... ) \ |
1039 | 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__ ) |
1040 | #else |
1041 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION( ClassName, Name, Tags, Signature, ... ) \ |
1042 | 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__ ) ) |
1043 | #endif |
1044 | #endif |
1045 | |
1046 | /////////////////////////////////////////////////////////////////////////////// |
1047 | #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \ |
1048 | static void TestName(); \ |
1049 | CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ |
1050 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ |
1051 | namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ |
1052 | CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ |
1053 | static void TestName() |
1054 | #define INTERNAL_CATCH_TESTCASE( ... ) \ |
1055 | INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ), __VA_ARGS__ ) |
1056 | |
1057 | /////////////////////////////////////////////////////////////////////////////// |
1058 | #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ |
1059 | CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ |
1060 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ |
1061 | namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &QualifiedMethod ), CATCH_INTERNAL_LINEINFO, "&" #QualifiedMethod, Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \ |
1062 | CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION |
1063 | |
1064 | /////////////////////////////////////////////////////////////////////////////// |
1065 | #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\ |
1066 | CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ |
1067 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ |
1068 | namespace{ \ |
1069 | struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \ |
1070 | void test(); \ |
1071 | }; \ |
1072 | Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ |
1073 | } \ |
1074 | CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ |
1075 | void TestName::test() |
1076 | #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \ |
1077 | INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ), ClassName, __VA_ARGS__ ) |
1078 | |
1079 | /////////////////////////////////////////////////////////////////////////////// |
1080 | #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ |
1081 | CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ |
1082 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ |
1083 | Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \ |
1084 | CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION |
1085 | |
1086 | /////////////////////////////////////////////////////////////////////////////// |
1087 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_2(TestName, TestFunc, Name, Tags, Signature, ... )\ |
1088 | CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ |
1089 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ |
1090 | CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ |
1091 | CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ |
1092 | INTERNAL_CATCH_DECLARE_SIG_TEST(TestFunc, INTERNAL_CATCH_REMOVE_PARENS(Signature));\ |
1093 | namespace {\ |
1094 | namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){\ |
1095 | INTERNAL_CATCH_TYPE_GEN\ |
1096 | INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\ |
1097 | INTERNAL_CATCH_NTTP_REG_GEN(TestFunc,INTERNAL_CATCH_REMOVE_PARENS(Signature))\ |
1098 | template<typename...Types> \ |
1099 | struct TestName{\ |
1100 | TestName(){\ |
1101 | int index = 0; \ |
1102 | constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, __VA_ARGS__)};\ |
1103 | using expander = int[];\ |
1104 | (void)expander{(reg_test(Types{}, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++)... };/* NOLINT */ \ |
1105 | }\ |
1106 | };\ |
1107 | static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\ |
1108 | TestName<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(__VA_ARGS__)>();\ |
1109 | return 0;\ |
1110 | }();\ |
1111 | }\ |
1112 | }\ |
1113 | CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ |
1114 | INTERNAL_CATCH_DEFINE_SIG_TEST(TestFunc,INTERNAL_CATCH_REMOVE_PARENS(Signature)) |
1115 | |
1116 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
1117 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \ |
1118 | 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__ ) |
1119 | #else |
1120 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \ |
1121 | 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__ ) ) |
1122 | #endif |
1123 | |
1124 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
1125 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG(Name, Tags, Signature, ...) \ |
1126 | 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__ ) |
1127 | #else |
1128 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG(Name, Tags, Signature, ...) \ |
1129 | 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__ ) ) |
1130 | #endif |
1131 | |
1132 | #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(TestName, TestFuncName, Name, Tags, Signature, TmplTypes, TypesList) \ |
1133 | CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ |
1134 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ |
1135 | CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ |
1136 | CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ |
1137 | template<typename TestType> static void TestFuncName(); \ |
1138 | namespace {\ |
1139 | namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName) { \ |
1140 | INTERNAL_CATCH_TYPE_GEN \ |
1141 | INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature)) \ |
1142 | template<typename... Types> \ |
1143 | struct TestName { \ |
1144 | void reg_tests() { \ |
1145 | int index = 0; \ |
1146 | using expander = int[]; \ |
1147 | constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\ |
1148 | constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\ |
1149 | constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\ |
1150 | (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 */\ |
1151 | } \ |
1152 | }; \ |
1153 | static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \ |
1154 | 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; \ |
1155 | TestInit t; \ |
1156 | t.reg_tests(); \ |
1157 | return 0; \ |
1158 | }(); \ |
1159 | } \ |
1160 | } \ |
1161 | CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ |
1162 | template<typename TestType> \ |
1163 | static void TestFuncName() |
1164 | |
1165 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
1166 | #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\ |
1167 | 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__) |
1168 | #else |
1169 | #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\ |
1170 | 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__ ) ) |
1171 | #endif |
1172 | |
1173 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
1174 | #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG(Name, Tags, Signature, ...)\ |
1175 | 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__) |
1176 | #else |
1177 | #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG(Name, Tags, Signature, ...)\ |
1178 | 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__ ) ) |
1179 | #endif |
1180 | |
1181 | #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_2(TestName, TestFunc, Name, Tags, TmplList)\ |
1182 | CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ |
1183 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ |
1184 | CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ |
1185 | template<typename TestType> static void TestFunc(); \ |
1186 | namespace {\ |
1187 | namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){\ |
1188 | INTERNAL_CATCH_TYPE_GEN\ |
1189 | template<typename... Types> \ |
1190 | struct TestName { \ |
1191 | void reg_tests() { \ |
1192 | int index = 0; \ |
1193 | using expander = int[]; \ |
1194 | (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 */\ |
1195 | } \ |
1196 | };\ |
1197 | static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \ |
1198 | using TestInit = typename convert<TestName, TmplList>::type; \ |
1199 | TestInit t; \ |
1200 | t.reg_tests(); \ |
1201 | return 0; \ |
1202 | }(); \ |
1203 | }}\ |
1204 | CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ |
1205 | template<typename TestType> \ |
1206 | static void TestFunc() |
1207 | |
1208 | #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE(Name, Tags, TmplList) \ |
1209 | 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 ) |
1210 | |
1211 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, Signature, ... ) \ |
1212 | CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ |
1213 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ |
1214 | CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ |
1215 | CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ |
1216 | namespace {\ |
1217 | namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){ \ |
1218 | INTERNAL_CATCH_TYPE_GEN\ |
1219 | INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\ |
1220 | INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, INTERNAL_CATCH_REMOVE_PARENS(Signature));\ |
1221 | INTERNAL_CATCH_NTTP_REG_METHOD_GEN(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature))\ |
1222 | template<typename...Types> \ |
1223 | struct TestNameClass{\ |
1224 | TestNameClass(){\ |
1225 | int index = 0; \ |
1226 | constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, __VA_ARGS__)};\ |
1227 | using expander = int[];\ |
1228 | (void)expander{(reg_test(Types{}, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++)... };/* NOLINT */ \ |
1229 | }\ |
1230 | };\ |
1231 | static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\ |
1232 | TestNameClass<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(__VA_ARGS__)>();\ |
1233 | return 0;\ |
1234 | }();\ |
1235 | }\ |
1236 | }\ |
1237 | CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ |
1238 | INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature)) |
1239 | |
1240 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
1241 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \ |
1242 | 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__ ) |
1243 | #else |
1244 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \ |
1245 | 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__ ) ) |
1246 | #endif |
1247 | |
1248 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
1249 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... ) \ |
1250 | 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__ ) |
1251 | #else |
1252 | #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... ) \ |
1253 | 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__ ) ) |
1254 | #endif |
1255 | |
1256 | #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2(TestNameClass, TestName, ClassName, Name, Tags, Signature, TmplTypes, TypesList)\ |
1257 | CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ |
1258 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ |
1259 | CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ |
1260 | CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ |
1261 | template<typename TestType> \ |
1262 | struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \ |
1263 | void test();\ |
1264 | };\ |
1265 | namespace {\ |
1266 | namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestNameClass) {\ |
1267 | INTERNAL_CATCH_TYPE_GEN \ |
1268 | INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\ |
1269 | template<typename...Types>\ |
1270 | struct TestNameClass{\ |
1271 | void reg_tests(){\ |
1272 | int index = 0;\ |
1273 | using expander = int[];\ |
1274 | constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\ |
1275 | constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\ |
1276 | constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\ |
1277 | (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 */ \ |
1278 | }\ |
1279 | };\ |
1280 | static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\ |
1281 | 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;\ |
1282 | TestInit t;\ |
1283 | t.reg_tests();\ |
1284 | return 0;\ |
1285 | }(); \ |
1286 | }\ |
1287 | }\ |
1288 | CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ |
1289 | template<typename TestType> \ |
1290 | void TestName<TestType>::test() |
1291 | |
1292 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
1293 | #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\ |
1294 | 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__ ) |
1295 | #else |
1296 | #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\ |
1297 | 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__ ) ) |
1298 | #endif |
1299 | |
1300 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
1301 | #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... )\ |
1302 | 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__ ) |
1303 | #else |
1304 | #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... )\ |
1305 | 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__ ) ) |
1306 | #endif |
1307 | |
1308 | #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, TmplList) \ |
1309 | CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ |
1310 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ |
1311 | CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ |
1312 | template<typename TestType> \ |
1313 | struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \ |
1314 | void test();\ |
1315 | };\ |
1316 | namespace {\ |
1317 | namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){ \ |
1318 | INTERNAL_CATCH_TYPE_GEN\ |
1319 | template<typename...Types>\ |
1320 | struct TestNameClass{\ |
1321 | void reg_tests(){\ |
1322 | int index = 0;\ |
1323 | using expander = int[];\ |
1324 | (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 */ \ |
1325 | }\ |
1326 | };\ |
1327 | static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\ |
1328 | using TestInit = typename convert<TestNameClass, TmplList>::type;\ |
1329 | TestInit t;\ |
1330 | t.reg_tests();\ |
1331 | return 0;\ |
1332 | }(); \ |
1333 | }}\ |
1334 | CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ |
1335 | template<typename TestType> \ |
1336 | void TestName<TestType>::test() |
1337 | |
1338 | #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD(ClassName, Name, Tags, TmplList) \ |
1339 | 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 ) |
1340 | |
1341 | // end catch_test_registry.h |
1342 | // start catch_capture.hpp |
1343 | |
1344 | // start catch_assertionhandler.h |
1345 | |
1346 | // start catch_assertioninfo.h |
1347 | |
1348 | // start catch_result_type.h |
1349 | |
1350 | namespace Catch { |
1351 | |
1352 | // ResultWas::OfType enum |
1353 | struct ResultWas { enum OfType { |
1354 | Unknown = -1, |
1355 | Ok = 0, |
1356 | Info = 1, |
1357 | Warning = 2, |
1358 | |
1359 | FailureBit = 0x10, |
1360 | |
1361 | ExpressionFailed = FailureBit | 1, |
1362 | ExplicitFailure = FailureBit | 2, |
1363 | |
1364 | Exception = 0x100 | FailureBit, |
1365 | |
1366 | ThrewException = Exception | 1, |
1367 | DidntThrowException = Exception | 2, |
1368 | |
1369 | FatalErrorCondition = 0x200 | FailureBit |
1370 | |
1371 | }; }; |
1372 | |
1373 | bool isOk( ResultWas::OfType resultType ); |
1374 | bool isJustInfo( int flags ); |
1375 | |
1376 | // ResultDisposition::Flags enum |
1377 | struct ResultDisposition { enum Flags { |
1378 | Normal = 0x01, |
1379 | |
1380 | ContinueOnFailure = 0x02, // Failures fail test, but execution continues |
1381 | FalseTest = 0x04, // Prefix expression with ! |
1382 | SuppressFail = 0x08 // Failures are reported but do not fail the test |
1383 | }; }; |
1384 | |
1385 | ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ); |
1386 | |
1387 | bool shouldContinueOnFailure( int flags ); |
1388 | inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } |
1389 | bool shouldSuppressFailure( int flags ); |
1390 | |
1391 | } // end namespace Catch |
1392 | |
1393 | // end catch_result_type.h |
1394 | namespace Catch { |
1395 | |
1396 | struct AssertionInfo |
1397 | { |
1398 | StringRef macroName; |
1399 | SourceLineInfo lineInfo; |
1400 | StringRef capturedExpression; |
1401 | ResultDisposition::Flags resultDisposition; |
1402 | |
1403 | // We want to delete this constructor but a compiler bug in 4.8 means |
1404 | // the struct is then treated as non-aggregate |
1405 | //AssertionInfo() = delete; |
1406 | }; |
1407 | |
1408 | } // end namespace Catch |
1409 | |
1410 | // end catch_assertioninfo.h |
1411 | // start catch_decomposer.h |
1412 | |
1413 | // start catch_tostring.h |
1414 | |
1415 | #include <vector> |
1416 | #include <cstddef> |
1417 | #include <type_traits> |
1418 | #include <string> |
1419 | // start catch_stream.h |
1420 | |
1421 | #include <iosfwd> |
1422 | #include <cstddef> |
1423 | #include <ostream> |
1424 | |
1425 | namespace Catch { |
1426 | |
1427 | std::ostream& cout(); |
1428 | std::ostream& cerr(); |
1429 | std::ostream& clog(); |
1430 | |
1431 | class StringRef; |
1432 | |
1433 | struct IStream { |
1434 | virtual ~IStream(); |
1435 | virtual std::ostream& stream() const = 0; |
1436 | }; |
1437 | |
1438 | auto makeStream( StringRef const &filename ) -> IStream const*; |
1439 | |
1440 | class ReusableStringStream : NonCopyable { |
1441 | std::size_t m_index; |
1442 | std::ostream* m_oss; |
1443 | public: |
1444 | ReusableStringStream(); |
1445 | ~ReusableStringStream(); |
1446 | |
1447 | auto str() const -> std::string; |
1448 | |
1449 | template<typename T> |
1450 | auto operator << ( T const& value ) -> ReusableStringStream& { |
1451 | *m_oss << value; |
1452 | return *this; |
1453 | } |
1454 | auto get() -> std::ostream& { return *m_oss; } |
1455 | }; |
1456 | } |
1457 | |
1458 | // end catch_stream.h |
1459 | // start catch_interfaces_enum_values_registry.h |
1460 | |
1461 | #include <vector> |
1462 | |
1463 | namespace Catch { |
1464 | |
1465 | namespace Detail { |
1466 | struct EnumInfo { |
1467 | StringRef m_name; |
1468 | std::vector<std::pair<int, StringRef>> m_values; |
1469 | |
1470 | ~EnumInfo(); |
1471 | |
1472 | StringRef lookup( int value ) const; |
1473 | }; |
1474 | } // namespace Detail |
1475 | |
1476 | struct IMutableEnumValuesRegistry { |
1477 | virtual ~IMutableEnumValuesRegistry(); |
1478 | |
1479 | virtual Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::vector<int> const& values ) = 0; |
1480 | |
1481 | template<typename E> |
1482 | Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::initializer_list<E> values ) { |
1483 | static_assert(sizeof(int) >= sizeof(E), "Cannot serialize enum to int" ); |
1484 | std::vector<int> intValues; |
1485 | intValues.reserve( values.size() ); |
1486 | for( auto enumValue : values ) |
1487 | intValues.push_back( static_cast<int>( enumValue ) ); |
1488 | return registerEnum( enumName, allEnums, intValues ); |
1489 | } |
1490 | }; |
1491 | |
1492 | } // Catch |
1493 | |
1494 | // end catch_interfaces_enum_values_registry.h |
1495 | |
1496 | #ifdef CATCH_CONFIG_CPP17_STRING_VIEW |
1497 | #include <string_view> |
1498 | #endif |
1499 | |
1500 | #ifdef __OBJC__ |
1501 | // start catch_objc_arc.hpp |
1502 | |
1503 | #import <Foundation/Foundation.h> |
1504 | |
1505 | #ifdef __has_feature |
1506 | #define CATCH_ARC_ENABLED __has_feature(objc_arc) |
1507 | #else |
1508 | #define CATCH_ARC_ENABLED 0 |
1509 | #endif |
1510 | |
1511 | void arcSafeRelease( NSObject* obj ); |
1512 | id performOptionalSelector( id obj, SEL sel ); |
1513 | |
1514 | #if !CATCH_ARC_ENABLED |
1515 | inline void arcSafeRelease( NSObject* obj ) { |
1516 | [obj release]; |
1517 | } |
1518 | inline id performOptionalSelector( id obj, SEL sel ) { |
1519 | if( [obj respondsToSelector: sel] ) |
1520 | return [obj performSelector: sel]; |
1521 | return nil; |
1522 | } |
1523 | #define CATCH_UNSAFE_UNRETAINED |
1524 | #define CATCH_ARC_STRONG |
1525 | #else |
1526 | inline void arcSafeRelease( NSObject* ){} |
1527 | inline id performOptionalSelector( id obj, SEL sel ) { |
1528 | #ifdef __clang__ |
1529 | #pragma clang diagnostic push |
1530 | #pragma clang diagnostic ignored "-Warc-performSelector-leaks" |
1531 | #endif |
1532 | if( [obj respondsToSelector: sel] ) |
1533 | return [obj performSelector: sel]; |
1534 | #ifdef __clang__ |
1535 | #pragma clang diagnostic pop |
1536 | #endif |
1537 | return nil; |
1538 | } |
1539 | #define CATCH_UNSAFE_UNRETAINED __unsafe_unretained |
1540 | #define CATCH_ARC_STRONG __strong |
1541 | #endif |
1542 | |
1543 | // end catch_objc_arc.hpp |
1544 | #endif |
1545 | |
1546 | #ifdef _MSC_VER |
1547 | #pragma warning(push) |
1548 | #pragma warning(disable:4180) // We attempt to stream a function (address) by const&, which MSVC complains about but is harmless |
1549 | #endif |
1550 | |
1551 | namespace Catch { |
1552 | namespace Detail { |
1553 | |
1554 | extern const std::string unprintableString; |
1555 | |
1556 | std::string rawMemoryToString( const void *object, std::size_t size ); |
1557 | |
1558 | template<typename T> |
1559 | std::string rawMemoryToString( const T& object ) { |
1560 | return rawMemoryToString( &object, sizeof(object) ); |
1561 | } |
1562 | |
1563 | template<typename T> |
1564 | class IsStreamInsertable { |
1565 | template<typename Stream, typename U> |
1566 | static auto test(int) |
1567 | -> decltype(std::declval<Stream&>() << std::declval<U>(), std::true_type()); |
1568 | |
1569 | template<typename, typename> |
1570 | static auto test(...)->std::false_type; |
1571 | |
1572 | public: |
1573 | static const bool value = decltype(test<std::ostream, const T&>(0))::value; |
1574 | }; |
1575 | |
1576 | template<typename E> |
1577 | std::string convertUnknownEnumToString( E e ); |
1578 | |
1579 | template<typename T> |
1580 | typename std::enable_if< |
1581 | !std::is_enum<T>::value && !std::is_base_of<std::exception, T>::value, |
1582 | std::string>::type convertUnstreamable( T const& ) { |
1583 | return Detail::unprintableString; |
1584 | } |
1585 | template<typename T> |
1586 | typename std::enable_if< |
1587 | !std::is_enum<T>::value && std::is_base_of<std::exception, T>::value, |
1588 | std::string>::type convertUnstreamable(T const& ex) { |
1589 | return ex.what(); |
1590 | } |
1591 | |
1592 | template<typename T> |
1593 | typename std::enable_if< |
1594 | std::is_enum<T>::value |
1595 | , std::string>::type convertUnstreamable( T const& value ) { |
1596 | return convertUnknownEnumToString( value ); |
1597 | } |
1598 | |
1599 | #if defined(_MANAGED) |
1600 | //! Convert a CLR string to a utf8 std::string |
1601 | template<typename T> |
1602 | std::string clrReferenceToString( T^ ref ) { |
1603 | if (ref == nullptr) |
1604 | return std::string("null" ); |
1605 | auto bytes = System::Text::Encoding::UTF8->GetBytes(ref->ToString()); |
1606 | cli::pin_ptr<System::Byte> p = &bytes[0]; |
1607 | return std::string(reinterpret_cast<char const *>(p), bytes->Length); |
1608 | } |
1609 | #endif |
1610 | |
1611 | } // namespace Detail |
1612 | |
1613 | // If we decide for C++14, change these to enable_if_ts |
1614 | template <typename T, typename = void> |
1615 | struct StringMaker { |
1616 | template <typename Fake = T> |
1617 | static |
1618 | typename std::enable_if<::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>::type |
1619 | convert(const Fake& value) { |
1620 | ReusableStringStream ; |
1621 | // NB: call using the function-like syntax to avoid ambiguity with |
1622 | // user-defined templated operator<< under clang. |
1623 | rss.operator<<(value); |
1624 | return rss.str(); |
1625 | } |
1626 | |
1627 | template <typename Fake = T> |
1628 | static |
1629 | typename std::enable_if<!::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>::type |
1630 | convert( const Fake& value ) { |
1631 | #if !defined(CATCH_CONFIG_FALLBACK_STRINGIFIER) |
1632 | return Detail::convertUnstreamable(value); |
1633 | #else |
1634 | return CATCH_CONFIG_FALLBACK_STRINGIFIER(value); |
1635 | #endif |
1636 | } |
1637 | }; |
1638 | |
1639 | namespace Detail { |
1640 | |
1641 | // This function dispatches all stringification requests inside of Catch. |
1642 | // Should be preferably called fully qualified, like ::Catch::Detail::stringify |
1643 | template <typename T> |
1644 | std::string stringify(const T& e) { |
1645 | return ::Catch::StringMaker<typename std::remove_cv<typename std::remove_reference<T>::type>::type>::convert(e); |
1646 | } |
1647 | |
1648 | template<typename E> |
1649 | std::string convertUnknownEnumToString( E e ) { |
1650 | return ::Catch::Detail::stringify(static_cast<typename std::underlying_type<E>::type>(e)); |
1651 | } |
1652 | |
1653 | #if defined(_MANAGED) |
1654 | template <typename T> |
1655 | std::string stringify( T^ e ) { |
1656 | return ::Catch::StringMaker<T^>::convert(e); |
1657 | } |
1658 | #endif |
1659 | |
1660 | } // namespace Detail |
1661 | |
1662 | // Some predefined specializations |
1663 | |
1664 | template<> |
1665 | struct StringMaker<std::string> { |
1666 | static std::string convert(const std::string& str); |
1667 | }; |
1668 | |
1669 | #ifdef CATCH_CONFIG_CPP17_STRING_VIEW |
1670 | template<> |
1671 | struct StringMaker<std::string_view> { |
1672 | static std::string convert(std::string_view str); |
1673 | }; |
1674 | #endif |
1675 | |
1676 | template<> |
1677 | struct StringMaker<char const *> { |
1678 | static std::string convert(char const * str); |
1679 | }; |
1680 | template<> |
1681 | struct StringMaker<char *> { |
1682 | static std::string convert(char * str); |
1683 | }; |
1684 | |
1685 | #ifdef CATCH_CONFIG_WCHAR |
1686 | template<> |
1687 | struct StringMaker<std::wstring> { |
1688 | static std::string convert(const std::wstring& wstr); |
1689 | }; |
1690 | |
1691 | # ifdef CATCH_CONFIG_CPP17_STRING_VIEW |
1692 | template<> |
1693 | struct StringMaker<std::wstring_view> { |
1694 | static std::string convert(std::wstring_view str); |
1695 | }; |
1696 | # endif |
1697 | |
1698 | template<> |
1699 | struct StringMaker<wchar_t const *> { |
1700 | static std::string convert(wchar_t const * str); |
1701 | }; |
1702 | template<> |
1703 | struct StringMaker<wchar_t *> { |
1704 | static std::string convert(wchar_t * str); |
1705 | }; |
1706 | #endif |
1707 | |
1708 | // TBD: Should we use `strnlen` to ensure that we don't go out of the buffer, |
1709 | // while keeping string semantics? |
1710 | template<int SZ> |
1711 | struct StringMaker<char[SZ]> { |
1712 | static std::string convert(char const* str) { |
1713 | return ::Catch::Detail::stringify(std::string{ str }); |
1714 | } |
1715 | }; |
1716 | template<int SZ> |
1717 | struct StringMaker<signed char[SZ]> { |
1718 | static std::string convert(signed char const* str) { |
1719 | return ::Catch::Detail::stringify(std::string{ reinterpret_cast<char const *>(str) }); |
1720 | } |
1721 | }; |
1722 | template<int SZ> |
1723 | struct StringMaker<unsigned char[SZ]> { |
1724 | static std::string convert(unsigned char const* str) { |
1725 | return ::Catch::Detail::stringify(std::string{ reinterpret_cast<char const *>(str) }); |
1726 | } |
1727 | }; |
1728 | |
1729 | #if defined(CATCH_CONFIG_CPP17_BYTE) |
1730 | template<> |
1731 | struct StringMaker<std::byte> { |
1732 | static std::string convert(std::byte value); |
1733 | }; |
1734 | #endif // defined(CATCH_CONFIG_CPP17_BYTE) |
1735 | template<> |
1736 | struct StringMaker<int> { |
1737 | static std::string convert(int value); |
1738 | }; |
1739 | template<> |
1740 | struct StringMaker<long> { |
1741 | static std::string convert(long value); |
1742 | }; |
1743 | template<> |
1744 | struct StringMaker<long long> { |
1745 | static std::string convert(long long value); |
1746 | }; |
1747 | template<> |
1748 | struct StringMaker<unsigned int> { |
1749 | static std::string convert(unsigned int value); |
1750 | }; |
1751 | template<> |
1752 | struct StringMaker<unsigned long> { |
1753 | static std::string convert(unsigned long value); |
1754 | }; |
1755 | template<> |
1756 | struct StringMaker<unsigned long long> { |
1757 | static std::string convert(unsigned long long value); |
1758 | }; |
1759 | |
1760 | template<> |
1761 | struct StringMaker<bool> { |
1762 | static std::string convert(bool b); |
1763 | }; |
1764 | |
1765 | template<> |
1766 | struct StringMaker<char> { |
1767 | static std::string convert(char c); |
1768 | }; |
1769 | template<> |
1770 | struct StringMaker<signed char> { |
1771 | static std::string convert(signed char c); |
1772 | }; |
1773 | template<> |
1774 | struct StringMaker<unsigned char> { |
1775 | static std::string convert(unsigned char c); |
1776 | }; |
1777 | |
1778 | template<> |
1779 | struct StringMaker<std::nullptr_t> { |
1780 | static std::string convert(std::nullptr_t); |
1781 | }; |
1782 | |
1783 | template<> |
1784 | struct StringMaker<float> { |
1785 | static std::string convert(float value); |
1786 | static int precision; |
1787 | }; |
1788 | |
1789 | template<> |
1790 | struct StringMaker<double> { |
1791 | static std::string convert(double value); |
1792 | static int precision; |
1793 | }; |
1794 | |
1795 | template <typename T> |
1796 | struct StringMaker<T*> { |
1797 | template <typename U> |
1798 | static std::string convert(U* p) { |
1799 | if (p) { |
1800 | return ::Catch::Detail::rawMemoryToString(p); |
1801 | } else { |
1802 | return "nullptr" ; |
1803 | } |
1804 | } |
1805 | }; |
1806 | |
1807 | template <typename R, typename C> |
1808 | struct StringMaker<R C::*> { |
1809 | static std::string convert(R C::* p) { |
1810 | if (p) { |
1811 | return ::Catch::Detail::rawMemoryToString(p); |
1812 | } else { |
1813 | return "nullptr" ; |
1814 | } |
1815 | } |
1816 | }; |
1817 | |
1818 | #if defined(_MANAGED) |
1819 | template <typename T> |
1820 | struct StringMaker<T^> { |
1821 | static std::string convert( T^ ref ) { |
1822 | return ::Catch::Detail::clrReferenceToString(ref); |
1823 | } |
1824 | }; |
1825 | #endif |
1826 | |
1827 | namespace Detail { |
1828 | template<typename InputIterator, typename Sentinel = InputIterator> |
1829 | std::string rangeToString(InputIterator first, Sentinel last) { |
1830 | ReusableStringStream ; |
1831 | rss << "{ " ; |
1832 | if (first != last) { |
1833 | rss << ::Catch::Detail::stringify(*first); |
1834 | for (++first; first != last; ++first) |
1835 | rss << ", " << ::Catch::Detail::stringify(*first); |
1836 | } |
1837 | rss << " }" ; |
1838 | return rss.str(); |
1839 | } |
1840 | } |
1841 | |
1842 | #ifdef __OBJC__ |
1843 | template<> |
1844 | struct StringMaker<NSString*> { |
1845 | static std::string convert(NSString * nsstring) { |
1846 | if (!nsstring) |
1847 | return "nil" ; |
1848 | return std::string("@" ) + [nsstring UTF8String]; |
1849 | } |
1850 | }; |
1851 | template<> |
1852 | struct StringMaker<NSObject*> { |
1853 | static std::string convert(NSObject* nsObject) { |
1854 | return ::Catch::Detail::stringify([nsObject description]); |
1855 | } |
1856 | |
1857 | }; |
1858 | namespace Detail { |
1859 | inline std::string stringify( NSString* nsstring ) { |
1860 | return StringMaker<NSString*>::convert( nsstring ); |
1861 | } |
1862 | |
1863 | } // namespace Detail |
1864 | #endif // __OBJC__ |
1865 | |
1866 | } // namespace Catch |
1867 | |
1868 | ////////////////////////////////////////////////////// |
1869 | // Separate std-lib types stringification, so it can be selectively enabled |
1870 | // This means that we do not bring in |
1871 | |
1872 | #if defined(CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS) |
1873 | # define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER |
1874 | # define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER |
1875 | # define CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER |
1876 | # define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER |
1877 | # define CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER |
1878 | #endif |
1879 | |
1880 | // Separate std::pair specialization |
1881 | #if defined(CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER) |
1882 | #include <utility> |
1883 | namespace Catch { |
1884 | template<typename T1, typename T2> |
1885 | struct StringMaker<std::pair<T1, T2> > { |
1886 | static std::string convert(const std::pair<T1, T2>& pair) { |
1887 | ReusableStringStream rss; |
1888 | rss << "{ " |
1889 | << ::Catch::Detail::stringify(pair.first) |
1890 | << ", " |
1891 | << ::Catch::Detail::stringify(pair.second) |
1892 | << " }" ; |
1893 | return rss.str(); |
1894 | } |
1895 | }; |
1896 | } |
1897 | #endif // CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER |
1898 | |
1899 | #if defined(CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_OPTIONAL) |
1900 | #include <optional> |
1901 | namespace Catch { |
1902 | template<typename T> |
1903 | struct StringMaker<std::optional<T> > { |
1904 | static std::string convert(const std::optional<T>& optional) { |
1905 | ReusableStringStream rss; |
1906 | if (optional.has_value()) { |
1907 | rss << ::Catch::Detail::stringify(*optional); |
1908 | } else { |
1909 | rss << "{ }" ; |
1910 | } |
1911 | return rss.str(); |
1912 | } |
1913 | }; |
1914 | } |
1915 | #endif // CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER |
1916 | |
1917 | // Separate std::tuple specialization |
1918 | #if defined(CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER) |
1919 | #include <tuple> |
1920 | namespace Catch { |
1921 | namespace Detail { |
1922 | template< |
1923 | typename Tuple, |
1924 | std::size_t N = 0, |
1925 | bool = (N < std::tuple_size<Tuple>::value) |
1926 | > |
1927 | struct TupleElementPrinter { |
1928 | static void print(const Tuple& tuple, std::ostream& os) { |
1929 | os << (N ? ", " : " " ) |
1930 | << ::Catch::Detail::stringify(std::get<N>(tuple)); |
1931 | TupleElementPrinter<Tuple, N + 1>::print(tuple, os); |
1932 | } |
1933 | }; |
1934 | |
1935 | template< |
1936 | typename Tuple, |
1937 | std::size_t N |
1938 | > |
1939 | struct TupleElementPrinter<Tuple, N, false> { |
1940 | static void print(const Tuple&, std::ostream&) {} |
1941 | }; |
1942 | |
1943 | } |
1944 | |
1945 | template<typename ...Types> |
1946 | struct StringMaker<std::tuple<Types...>> { |
1947 | static std::string convert(const std::tuple<Types...>& tuple) { |
1948 | ReusableStringStream rss; |
1949 | rss << '{'; |
1950 | Detail::TupleElementPrinter<std::tuple<Types...>>::print(tuple, rss.get()); |
1951 | rss << " }" ; |
1952 | return rss.str(); |
1953 | } |
1954 | }; |
1955 | } |
1956 | #endif // CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER |
1957 | |
1958 | #if defined(CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_VARIANT) |
1959 | #include <variant> |
1960 | namespace Catch { |
1961 | template<> |
1962 | struct StringMaker<std::monostate> { |
1963 | static std::string convert(const std::monostate&) { |
1964 | return "{ }" ; |
1965 | } |
1966 | }; |
1967 | |
1968 | template<typename... Elements> |
1969 | struct StringMaker<std::variant<Elements...>> { |
1970 | static std::string convert(const std::variant<Elements...>& variant) { |
1971 | if (variant.valueless_by_exception()) { |
1972 | return "{valueless variant}" ; |
1973 | } else { |
1974 | return std::visit( |
1975 | [](const auto& value) { |
1976 | return ::Catch::Detail::stringify(value); |
1977 | }, |
1978 | variant |
1979 | ); |
1980 | } |
1981 | } |
1982 | }; |
1983 | } |
1984 | #endif // CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER |
1985 | |
1986 | namespace Catch { |
1987 | // Import begin/ end from std here |
1988 | using std::begin; |
1989 | using std::end; |
1990 | |
1991 | namespace detail { |
1992 | template <typename...> |
1993 | struct void_type { |
1994 | using type = void; |
1995 | }; |
1996 | |
1997 | template <typename T, typename = void> |
1998 | struct is_range_impl : std::false_type { |
1999 | }; |
2000 | |
2001 | template <typename T> |
2002 | struct is_range_impl<T, typename void_type<decltype(begin(std::declval<T>()))>::type> : std::true_type { |
2003 | }; |
2004 | } // namespace detail |
2005 | |
2006 | template <typename T> |
2007 | struct is_range : detail::is_range_impl<T> { |
2008 | }; |
2009 | |
2010 | #if defined(_MANAGED) // Managed types are never ranges |
2011 | template <typename T> |
2012 | struct is_range<T^> { |
2013 | static const bool value = false; |
2014 | }; |
2015 | #endif |
2016 | |
2017 | template<typename Range> |
2018 | std::string rangeToString( Range const& range ) { |
2019 | return ::Catch::Detail::rangeToString( begin( range ), end( range ) ); |
2020 | } |
2021 | |
2022 | // Handle vector<bool> specially |
2023 | template<typename Allocator> |
2024 | std::string rangeToString( std::vector<bool, Allocator> const& v ) { |
2025 | ReusableStringStream ; |
2026 | rss << "{ " ; |
2027 | bool first = true; |
2028 | for( bool b : v ) { |
2029 | if( first ) |
2030 | first = false; |
2031 | else |
2032 | rss << ", " ; |
2033 | rss << ::Catch::Detail::stringify( b ); |
2034 | } |
2035 | rss << " }" ; |
2036 | return rss.str(); |
2037 | } |
2038 | |
2039 | template<typename R> |
2040 | struct StringMaker<R, typename std::enable_if<is_range<R>::value && !::Catch::Detail::IsStreamInsertable<R>::value>::type> { |
2041 | static std::string convert( R const& range ) { |
2042 | return rangeToString( range ); |
2043 | } |
2044 | }; |
2045 | |
2046 | template <typename T, int SZ> |
2047 | struct StringMaker<T[SZ]> { |
2048 | static std::string convert(T const(&arr)[SZ]) { |
2049 | return rangeToString(arr); |
2050 | } |
2051 | }; |
2052 | |
2053 | } // namespace Catch |
2054 | |
2055 | // Separate std::chrono::duration specialization |
2056 | #if defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) |
2057 | #include <ctime> |
2058 | #include <ratio> |
2059 | #include <chrono> |
2060 | |
2061 | namespace Catch { |
2062 | |
2063 | template <class Ratio> |
2064 | struct ratio_string { |
2065 | static std::string symbol(); |
2066 | }; |
2067 | |
2068 | template <class Ratio> |
2069 | std::string ratio_string<Ratio>::symbol() { |
2070 | Catch::ReusableStringStream rss; |
2071 | rss << '[' << Ratio::num << '/' |
2072 | << Ratio::den << ']'; |
2073 | return rss.str(); |
2074 | } |
2075 | template <> |
2076 | struct ratio_string<std::atto> { |
2077 | static std::string symbol(); |
2078 | }; |
2079 | template <> |
2080 | struct ratio_string<std::femto> { |
2081 | static std::string symbol(); |
2082 | }; |
2083 | template <> |
2084 | struct ratio_string<std::pico> { |
2085 | static std::string symbol(); |
2086 | }; |
2087 | template <> |
2088 | struct ratio_string<std::nano> { |
2089 | static std::string symbol(); |
2090 | }; |
2091 | template <> |
2092 | struct ratio_string<std::micro> { |
2093 | static std::string symbol(); |
2094 | }; |
2095 | template <> |
2096 | struct ratio_string<std::milli> { |
2097 | static std::string symbol(); |
2098 | }; |
2099 | |
2100 | //////////// |
2101 | // std::chrono::duration specializations |
2102 | template<typename Value, typename Ratio> |
2103 | struct StringMaker<std::chrono::duration<Value, Ratio>> { |
2104 | static std::string convert(std::chrono::duration<Value, Ratio> const& duration) { |
2105 | ReusableStringStream rss; |
2106 | rss << duration.count() << ' ' << ratio_string<Ratio>::symbol() << 's'; |
2107 | return rss.str(); |
2108 | } |
2109 | }; |
2110 | template<typename Value> |
2111 | struct StringMaker<std::chrono::duration<Value, std::ratio<1>>> { |
2112 | static std::string convert(std::chrono::duration<Value, std::ratio<1>> const& duration) { |
2113 | ReusableStringStream rss; |
2114 | rss << duration.count() << " s" ; |
2115 | return rss.str(); |
2116 | } |
2117 | }; |
2118 | template<typename Value> |
2119 | struct StringMaker<std::chrono::duration<Value, std::ratio<60>>> { |
2120 | static std::string convert(std::chrono::duration<Value, std::ratio<60>> const& duration) { |
2121 | ReusableStringStream rss; |
2122 | rss << duration.count() << " m" ; |
2123 | return rss.str(); |
2124 | } |
2125 | }; |
2126 | template<typename Value> |
2127 | struct StringMaker<std::chrono::duration<Value, std::ratio<3600>>> { |
2128 | static std::string convert(std::chrono::duration<Value, std::ratio<3600>> const& duration) { |
2129 | ReusableStringStream rss; |
2130 | rss << duration.count() << " h" ; |
2131 | return rss.str(); |
2132 | } |
2133 | }; |
2134 | |
2135 | //////////// |
2136 | // std::chrono::time_point specialization |
2137 | // Generic time_point cannot be specialized, only std::chrono::time_point<system_clock> |
2138 | template<typename Clock, typename Duration> |
2139 | struct StringMaker<std::chrono::time_point<Clock, Duration>> { |
2140 | static std::string convert(std::chrono::time_point<Clock, Duration> const& time_point) { |
2141 | return ::Catch::Detail::stringify(time_point.time_since_epoch()) + " since epoch" ; |
2142 | } |
2143 | }; |
2144 | // std::chrono::time_point<system_clock> specialization |
2145 | template<typename Duration> |
2146 | struct StringMaker<std::chrono::time_point<std::chrono::system_clock, Duration>> { |
2147 | static std::string convert(std::chrono::time_point<std::chrono::system_clock, Duration> const& time_point) { |
2148 | auto converted = std::chrono::system_clock::to_time_t(time_point); |
2149 | |
2150 | #ifdef _MSC_VER |
2151 | std::tm timeInfo = {}; |
2152 | gmtime_s(&timeInfo, &converted); |
2153 | #else |
2154 | std::tm* timeInfo = std::gmtime(&converted); |
2155 | #endif |
2156 | |
2157 | auto const timeStampSize = sizeof("2017-01-16T17:06:45Z" ); |
2158 | char timeStamp[timeStampSize]; |
2159 | const char * const fmt = "%Y-%m-%dT%H:%M:%SZ" ; |
2160 | |
2161 | #ifdef _MSC_VER |
2162 | std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); |
2163 | #else |
2164 | std::strftime(timeStamp, timeStampSize, fmt, timeInfo); |
2165 | #endif |
2166 | return std::string(timeStamp); |
2167 | } |
2168 | }; |
2169 | } |
2170 | #endif // CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER |
2171 | |
2172 | #define INTERNAL_CATCH_REGISTER_ENUM( enumName, ... ) \ |
2173 | namespace Catch { \ |
2174 | template<> struct StringMaker<enumName> { \ |
2175 | static std::string convert( enumName value ) { \ |
2176 | static const auto& enumInfo = ::Catch::getMutableRegistryHub().getMutableEnumValuesRegistry().registerEnum( #enumName, #__VA_ARGS__, { __VA_ARGS__ } ); \ |
2177 | return static_cast<std::string>(enumInfo.lookup( static_cast<int>( value ) )); \ |
2178 | } \ |
2179 | }; \ |
2180 | } |
2181 | |
2182 | #define CATCH_REGISTER_ENUM( enumName, ... ) INTERNAL_CATCH_REGISTER_ENUM( enumName, __VA_ARGS__ ) |
2183 | |
2184 | #ifdef _MSC_VER |
2185 | #pragma warning(pop) |
2186 | #endif |
2187 | |
2188 | // end catch_tostring.h |
2189 | #include <iosfwd> |
2190 | |
2191 | #ifdef _MSC_VER |
2192 | #pragma warning(push) |
2193 | #pragma warning(disable:4389) // '==' : signed/unsigned mismatch |
2194 | #pragma warning(disable:4018) // more "signed/unsigned mismatch" |
2195 | #pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform) |
2196 | #pragma warning(disable:4180) // qualifier applied to function type has no meaning |
2197 | #pragma warning(disable:4800) // Forcing result to true or false |
2198 | #endif |
2199 | |
2200 | namespace Catch { |
2201 | |
2202 | struct ITransientExpression { |
2203 | auto isBinaryExpression() const -> bool { return m_isBinaryExpression; } |
2204 | auto getResult() const -> bool { return m_result; } |
2205 | virtual void streamReconstructedExpression( std::ostream &os ) const = 0; |
2206 | |
2207 | ITransientExpression( bool isBinaryExpression, bool result ) |
2208 | : m_isBinaryExpression( isBinaryExpression ), |
2209 | m_result( result ) |
2210 | {} |
2211 | |
2212 | // We don't actually need a virtual destructor, but many static analysers |
2213 | // complain if it's not here :-( |
2214 | virtual ~ITransientExpression(); |
2215 | |
2216 | bool m_isBinaryExpression; |
2217 | bool m_result; |
2218 | |
2219 | }; |
2220 | |
2221 | void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ); |
2222 | |
2223 | template<typename LhsT, typename RhsT> |
2224 | class BinaryExpr : public ITransientExpression { |
2225 | LhsT m_lhs; |
2226 | StringRef m_op; |
2227 | RhsT m_rhs; |
2228 | |
2229 | void streamReconstructedExpression( std::ostream &os ) const override { |
2230 | formatReconstructedExpression |
2231 | ( os, Catch::Detail::stringify( m_lhs ), m_op, Catch::Detail::stringify( m_rhs ) ); |
2232 | } |
2233 | |
2234 | public: |
2235 | BinaryExpr( bool comparisonResult, LhsT lhs, StringRef op, RhsT rhs ) |
2236 | : ITransientExpression{ true, comparisonResult }, |
2237 | m_lhs( lhs ), |
2238 | m_op( op ), |
2239 | m_rhs( rhs ) |
2240 | {} |
2241 | |
2242 | template<typename T> |
2243 | auto operator && ( T ) const -> BinaryExpr<LhsT, RhsT const&> const { |
2244 | static_assert(always_false<T>::value, |
2245 | "chained comparisons are not supported inside assertions, " |
2246 | "wrap the expression inside parentheses, or decompose it" ); |
2247 | } |
2248 | |
2249 | template<typename T> |
2250 | auto operator || ( T ) const -> BinaryExpr<LhsT, RhsT const&> const { |
2251 | static_assert(always_false<T>::value, |
2252 | "chained comparisons are not supported inside assertions, " |
2253 | "wrap the expression inside parentheses, or decompose it" ); |
2254 | } |
2255 | |
2256 | template<typename T> |
2257 | auto operator == ( T ) const -> BinaryExpr<LhsT, RhsT const&> const { |
2258 | static_assert(always_false<T>::value, |
2259 | "chained comparisons are not supported inside assertions, " |
2260 | "wrap the expression inside parentheses, or decompose it" ); |
2261 | } |
2262 | |
2263 | template<typename T> |
2264 | auto operator != ( T ) const -> BinaryExpr<LhsT, RhsT const&> const { |
2265 | static_assert(always_false<T>::value, |
2266 | "chained comparisons are not supported inside assertions, " |
2267 | "wrap the expression inside parentheses, or decompose it" ); |
2268 | } |
2269 | |
2270 | template<typename T> |
2271 | auto operator > ( T ) const -> BinaryExpr<LhsT, RhsT const&> const { |
2272 | static_assert(always_false<T>::value, |
2273 | "chained comparisons are not supported inside assertions, " |
2274 | "wrap the expression inside parentheses, or decompose it" ); |
2275 | } |
2276 | |
2277 | template<typename T> |
2278 | auto operator < ( T ) const -> BinaryExpr<LhsT, RhsT const&> const { |
2279 | static_assert(always_false<T>::value, |
2280 | "chained comparisons are not supported inside assertions, " |
2281 | "wrap the expression inside parentheses, or decompose it" ); |
2282 | } |
2283 | |
2284 | template<typename T> |
2285 | auto operator >= ( T ) const -> BinaryExpr<LhsT, RhsT const&> const { |
2286 | static_assert(always_false<T>::value, |
2287 | "chained comparisons are not supported inside assertions, " |
2288 | "wrap the expression inside parentheses, or decompose it" ); |
2289 | } |
2290 | |
2291 | template<typename T> |
2292 | auto operator <= ( T ) const -> BinaryExpr<LhsT, RhsT const&> const { |
2293 | static_assert(always_false<T>::value, |
2294 | "chained comparisons are not supported inside assertions, " |
2295 | "wrap the expression inside parentheses, or decompose it" ); |
2296 | } |
2297 | }; |
2298 | |
2299 | template<typename LhsT> |
2300 | class UnaryExpr : public ITransientExpression { |
2301 | LhsT m_lhs; |
2302 | |
2303 | void streamReconstructedExpression( std::ostream &os ) const override { |
2304 | os << Catch::Detail::stringify( m_lhs ); |
2305 | } |
2306 | |
2307 | public: |
2308 | explicit UnaryExpr( LhsT lhs ) |
2309 | : ITransientExpression{ false, static_cast<bool>(lhs) }, |
2310 | m_lhs( lhs ) |
2311 | {} |
2312 | }; |
2313 | |
2314 | // Specialised comparison functions to handle equality comparisons between ints and pointers (NULL deduces as an int) |
2315 | template<typename LhsT, typename RhsT> |
2316 | auto compareEqual( LhsT const& lhs, RhsT const& rhs ) -> bool { return static_cast<bool>(lhs == rhs); } |
2317 | template<typename T> |
2318 | auto compareEqual( T* const& lhs, int rhs ) -> bool { return lhs == reinterpret_cast<void const*>( rhs ); } |
2319 | template<typename T> |
2320 | auto compareEqual( T* const& lhs, long rhs ) -> bool { return lhs == reinterpret_cast<void const*>( rhs ); } |
2321 | template<typename T> |
2322 | auto compareEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) == rhs; } |
2323 | template<typename T> |
2324 | auto compareEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) == rhs; } |
2325 | |
2326 | template<typename LhsT, typename RhsT> |
2327 | auto compareNotEqual( LhsT const& lhs, RhsT&& rhs ) -> bool { return static_cast<bool>(lhs != rhs); } |
2328 | template<typename T> |
2329 | auto compareNotEqual( T* const& lhs, int rhs ) -> bool { return lhs != reinterpret_cast<void const*>( rhs ); } |
2330 | template<typename T> |
2331 | auto compareNotEqual( T* const& lhs, long rhs ) -> bool { return lhs != reinterpret_cast<void const*>( rhs ); } |
2332 | template<typename T> |
2333 | auto compareNotEqual( int lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) != rhs; } |
2334 | template<typename T> |
2335 | auto compareNotEqual( long lhs, T* const& rhs ) -> bool { return reinterpret_cast<void const*>( lhs ) != rhs; } |
2336 | |
2337 | template<typename LhsT> |
2338 | class ExprLhs { |
2339 | LhsT m_lhs; |
2340 | public: |
2341 | explicit ExprLhs( LhsT lhs ) : m_lhs( lhs ) {} |
2342 | |
2343 | template<typename RhsT> |
2344 | auto operator == ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { |
2345 | return { compareEqual( m_lhs, rhs ), m_lhs, "==" , rhs }; |
2346 | } |
2347 | auto operator == ( bool rhs ) -> BinaryExpr<LhsT, bool> const { |
2348 | return { m_lhs == rhs, m_lhs, "==" , rhs }; |
2349 | } |
2350 | |
2351 | template<typename RhsT> |
2352 | auto operator != ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { |
2353 | return { compareNotEqual( m_lhs, rhs ), m_lhs, "!=" , rhs }; |
2354 | } |
2355 | auto operator != ( bool rhs ) -> BinaryExpr<LhsT, bool> const { |
2356 | return { m_lhs != rhs, m_lhs, "!=" , rhs }; |
2357 | } |
2358 | |
2359 | template<typename RhsT> |
2360 | auto operator > ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { |
2361 | return { static_cast<bool>(m_lhs > rhs), m_lhs, ">" , rhs }; |
2362 | } |
2363 | template<typename RhsT> |
2364 | auto operator < ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { |
2365 | return { static_cast<bool>(m_lhs < rhs), m_lhs, "<" , rhs }; |
2366 | } |
2367 | template<typename RhsT> |
2368 | auto operator >= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { |
2369 | return { static_cast<bool>(m_lhs >= rhs), m_lhs, ">=" , rhs }; |
2370 | } |
2371 | template<typename RhsT> |
2372 | auto operator <= ( RhsT const& rhs ) -> BinaryExpr<LhsT, RhsT const&> const { |
2373 | return { static_cast<bool>(m_lhs <= rhs), m_lhs, "<=" , rhs }; |
2374 | } |
2375 | template <typename RhsT> |
2376 | auto operator | (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const { |
2377 | return { static_cast<bool>(m_lhs | rhs), m_lhs, "|" , rhs }; |
2378 | } |
2379 | template <typename RhsT> |
2380 | auto operator & (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const { |
2381 | return { static_cast<bool>(m_lhs & rhs), m_lhs, "&" , rhs }; |
2382 | } |
2383 | template <typename RhsT> |
2384 | auto operator ^ (RhsT const& rhs) -> BinaryExpr<LhsT, RhsT const&> const { |
2385 | return { static_cast<bool>(m_lhs ^ rhs), m_lhs, "^" , rhs }; |
2386 | } |
2387 | |
2388 | template<typename RhsT> |
2389 | auto operator && ( RhsT const& ) -> BinaryExpr<LhsT, RhsT const&> const { |
2390 | static_assert(always_false<RhsT>::value, |
2391 | "operator&& is not supported inside assertions, " |
2392 | "wrap the expression inside parentheses, or decompose it" ); |
2393 | } |
2394 | |
2395 | template<typename RhsT> |
2396 | auto operator || ( RhsT const& ) -> BinaryExpr<LhsT, RhsT const&> const { |
2397 | static_assert(always_false<RhsT>::value, |
2398 | "operator|| is not supported inside assertions, " |
2399 | "wrap the expression inside parentheses, or decompose it" ); |
2400 | } |
2401 | |
2402 | auto makeUnaryExpr() const -> UnaryExpr<LhsT> { |
2403 | return UnaryExpr<LhsT>{ m_lhs }; |
2404 | } |
2405 | }; |
2406 | |
2407 | void handleExpression( ITransientExpression const& expr ); |
2408 | |
2409 | template<typename T> |
2410 | void handleExpression( ExprLhs<T> const& expr ) { |
2411 | handleExpression( expr.makeUnaryExpr() ); |
2412 | } |
2413 | |
2414 | struct Decomposer { |
2415 | template<typename T> |
2416 | auto operator <= ( T const& lhs ) -> ExprLhs<T const&> { |
2417 | return ExprLhs<T const&>{ lhs }; |
2418 | } |
2419 | |
2420 | auto operator <=( bool value ) -> ExprLhs<bool> { |
2421 | return ExprLhs<bool>{ value }; |
2422 | } |
2423 | }; |
2424 | |
2425 | } // end namespace Catch |
2426 | |
2427 | #ifdef _MSC_VER |
2428 | #pragma warning(pop) |
2429 | #endif |
2430 | |
2431 | // end catch_decomposer.h |
2432 | // start catch_interfaces_capture.h |
2433 | |
2434 | #include <string> |
2435 | #include <chrono> |
2436 | |
2437 | namespace Catch { |
2438 | |
2439 | class AssertionResult; |
2440 | struct AssertionInfo; |
2441 | struct SectionInfo; |
2442 | struct SectionEndInfo; |
2443 | struct MessageInfo; |
2444 | struct MessageBuilder; |
2445 | struct Counts; |
2446 | struct AssertionReaction; |
2447 | struct SourceLineInfo; |
2448 | |
2449 | struct ITransientExpression; |
2450 | struct IGeneratorTracker; |
2451 | |
2452 | #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) |
2453 | struct BenchmarkInfo; |
2454 | template <typename Duration = std::chrono::duration<double, std::nano>> |
2455 | struct BenchmarkStats; |
2456 | #endif // CATCH_CONFIG_ENABLE_BENCHMARKING |
2457 | |
2458 | struct IResultCapture { |
2459 | |
2460 | virtual ~IResultCapture(); |
2461 | |
2462 | virtual bool sectionStarted( SectionInfo const& sectionInfo, |
2463 | Counts& assertions ) = 0; |
2464 | virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; |
2465 | virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; |
2466 | |
2467 | virtual auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0; |
2468 | |
2469 | #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) |
2470 | virtual void benchmarkPreparing( std::string const& name ) = 0; |
2471 | virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0; |
2472 | virtual void benchmarkEnded( BenchmarkStats<> const& stats ) = 0; |
2473 | virtual void benchmarkFailed( std::string const& error ) = 0; |
2474 | #endif // CATCH_CONFIG_ENABLE_BENCHMARKING |
2475 | |
2476 | virtual void pushScopedMessage( MessageInfo const& message ) = 0; |
2477 | virtual void popScopedMessage( MessageInfo const& message ) = 0; |
2478 | |
2479 | virtual void emplaceUnscopedMessage( MessageBuilder const& builder ) = 0; |
2480 | |
2481 | virtual void handleFatalErrorCondition( StringRef message ) = 0; |
2482 | |
2483 | virtual void handleExpr |
2484 | ( AssertionInfo const& info, |
2485 | ITransientExpression const& expr, |
2486 | AssertionReaction& reaction ) = 0; |
2487 | virtual void handleMessage |
2488 | ( AssertionInfo const& info, |
2489 | ResultWas::OfType resultType, |
2490 | StringRef const& message, |
2491 | AssertionReaction& reaction ) = 0; |
2492 | virtual void handleUnexpectedExceptionNotThrown |
2493 | ( AssertionInfo const& info, |
2494 | AssertionReaction& reaction ) = 0; |
2495 | virtual void handleUnexpectedInflightException |
2496 | ( AssertionInfo const& info, |
2497 | std::string const& message, |
2498 | AssertionReaction& reaction ) = 0; |
2499 | virtual void handleIncomplete |
2500 | ( AssertionInfo const& info ) = 0; |
2501 | virtual void handleNonExpr |
2502 | ( AssertionInfo const &info, |
2503 | ResultWas::OfType resultType, |
2504 | AssertionReaction &reaction ) = 0; |
2505 | |
2506 | virtual bool lastAssertionPassed() = 0; |
2507 | virtual void assertionPassed() = 0; |
2508 | |
2509 | // Deprecated, do not use: |
2510 | virtual std::string getCurrentTestName() const = 0; |
2511 | virtual const AssertionResult* getLastResult() const = 0; |
2512 | virtual void exceptionEarlyReported() = 0; |
2513 | }; |
2514 | |
2515 | IResultCapture& getResultCapture(); |
2516 | } |
2517 | |
2518 | // end catch_interfaces_capture.h |
2519 | namespace Catch { |
2520 | |
2521 | struct TestFailureException{}; |
2522 | struct AssertionResultData; |
2523 | struct IResultCapture; |
2524 | class RunContext; |
2525 | |
2526 | class LazyExpression { |
2527 | friend class AssertionHandler; |
2528 | friend struct AssertionStats; |
2529 | friend class RunContext; |
2530 | |
2531 | ITransientExpression const* m_transientExpression = nullptr; |
2532 | bool m_isNegated; |
2533 | public: |
2534 | LazyExpression( bool isNegated ); |
2535 | LazyExpression( LazyExpression const& other ); |
2536 | LazyExpression& operator = ( LazyExpression const& ) = delete; |
2537 | |
2538 | explicit operator bool() const; |
2539 | |
2540 | friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&; |
2541 | }; |
2542 | |
2543 | struct AssertionReaction { |
2544 | bool shouldDebugBreak = false; |
2545 | bool shouldThrow = false; |
2546 | }; |
2547 | |
2548 | class AssertionHandler { |
2549 | AssertionInfo m_assertionInfo; |
2550 | AssertionReaction m_reaction; |
2551 | bool m_completed = false; |
2552 | IResultCapture& m_resultCapture; |
2553 | |
2554 | public: |
2555 | AssertionHandler |
2556 | ( StringRef const& macroName, |
2557 | SourceLineInfo const& lineInfo, |
2558 | StringRef capturedExpression, |
2559 | ResultDisposition::Flags resultDisposition ); |
2560 | ~AssertionHandler() { |
2561 | if ( !m_completed ) { |
2562 | m_resultCapture.handleIncomplete( m_assertionInfo ); |
2563 | } |
2564 | } |
2565 | |
2566 | template<typename T> |
2567 | void handleExpr( ExprLhs<T> const& expr ) { |
2568 | handleExpr( expr.makeUnaryExpr() ); |
2569 | } |
2570 | void handleExpr( ITransientExpression const& expr ); |
2571 | |
2572 | void handleMessage(ResultWas::OfType resultType, StringRef const& message); |
2573 | |
2574 | void handleExceptionThrownAsExpected(); |
2575 | void handleUnexpectedExceptionNotThrown(); |
2576 | void handleExceptionNotThrownAsExpected(); |
2577 | void handleThrowingCallSkipped(); |
2578 | void handleUnexpectedInflightException(); |
2579 | |
2580 | void complete(); |
2581 | void setCompleted(); |
2582 | |
2583 | // query |
2584 | auto allowThrows() const -> bool; |
2585 | }; |
2586 | |
2587 | void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef const& matcherString ); |
2588 | |
2589 | } // namespace Catch |
2590 | |
2591 | // end catch_assertionhandler.h |
2592 | // start catch_message.h |
2593 | |
2594 | #include <string> |
2595 | #include <vector> |
2596 | |
2597 | namespace Catch { |
2598 | |
2599 | struct MessageInfo { |
2600 | MessageInfo( StringRef const& _macroName, |
2601 | SourceLineInfo const& _lineInfo, |
2602 | ResultWas::OfType _type ); |
2603 | |
2604 | StringRef macroName; |
2605 | std::string message; |
2606 | SourceLineInfo lineInfo; |
2607 | ResultWas::OfType type; |
2608 | unsigned int sequence; |
2609 | |
2610 | bool operator == ( MessageInfo const& other ) const; |
2611 | bool operator < ( MessageInfo const& other ) const; |
2612 | private: |
2613 | static unsigned int globalCount; |
2614 | }; |
2615 | |
2616 | struct MessageStream { |
2617 | |
2618 | template<typename T> |
2619 | MessageStream& operator << ( T const& value ) { |
2620 | m_stream << value; |
2621 | return *this; |
2622 | } |
2623 | |
2624 | ReusableStringStream m_stream; |
2625 | }; |
2626 | |
2627 | struct MessageBuilder : MessageStream { |
2628 | MessageBuilder( StringRef const& macroName, |
2629 | SourceLineInfo const& lineInfo, |
2630 | ResultWas::OfType type ); |
2631 | |
2632 | template<typename T> |
2633 | MessageBuilder& operator << ( T const& value ) { |
2634 | m_stream << value; |
2635 | return *this; |
2636 | } |
2637 | |
2638 | MessageInfo m_info; |
2639 | }; |
2640 | |
2641 | class ScopedMessage { |
2642 | public: |
2643 | explicit ScopedMessage( MessageBuilder const& builder ); |
2644 | ScopedMessage( ScopedMessage& duplicate ) = delete; |
2645 | ScopedMessage( ScopedMessage&& old ); |
2646 | ~ScopedMessage(); |
2647 | |
2648 | MessageInfo m_info; |
2649 | bool m_moved; |
2650 | }; |
2651 | |
2652 | class Capturer { |
2653 | std::vector<MessageInfo> m_messages; |
2654 | IResultCapture& m_resultCapture = getResultCapture(); |
2655 | size_t m_captured = 0; |
2656 | public: |
2657 | Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ); |
2658 | ~Capturer(); |
2659 | |
2660 | void captureValue( size_t index, std::string const& value ); |
2661 | |
2662 | template<typename T> |
2663 | void captureValues( size_t index, T const& value ) { |
2664 | captureValue( index, Catch::Detail::stringify( value ) ); |
2665 | } |
2666 | |
2667 | template<typename T, typename... Ts> |
2668 | void captureValues( size_t index, T const& value, Ts const&... values ) { |
2669 | captureValue( index, Catch::Detail::stringify(value) ); |
2670 | captureValues( index+1, values... ); |
2671 | } |
2672 | }; |
2673 | |
2674 | } // end namespace Catch |
2675 | |
2676 | // end catch_message.h |
2677 | #if !defined(CATCH_CONFIG_DISABLE) |
2678 | |
2679 | #if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION) |
2680 | #define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__ |
2681 | #else |
2682 | #define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION" |
2683 | #endif |
2684 | |
2685 | #if defined(CATCH_CONFIG_FAST_COMPILE) || defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) |
2686 | |
2687 | /////////////////////////////////////////////////////////////////////////////// |
2688 | // Another way to speed-up compilation is to omit local try-catch for REQUIRE* |
2689 | // macros. |
2690 | #define INTERNAL_CATCH_TRY |
2691 | #define INTERNAL_CATCH_CATCH( capturer ) |
2692 | |
2693 | #else // CATCH_CONFIG_FAST_COMPILE |
2694 | |
2695 | #define INTERNAL_CATCH_TRY try |
2696 | #define INTERNAL_CATCH_CATCH( handler ) catch(...) { handler.handleUnexpectedInflightException(); } |
2697 | |
2698 | #endif |
2699 | |
2700 | #define INTERNAL_CATCH_REACT( handler ) handler.complete(); |
2701 | |
2702 | /////////////////////////////////////////////////////////////////////////////// |
2703 | #define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \ |
2704 | do { \ |
2705 | CATCH_INTERNAL_IGNORE_BUT_WARN(__VA_ARGS__); \ |
2706 | Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ |
2707 | INTERNAL_CATCH_TRY { \ |
2708 | CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ |
2709 | CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ |
2710 | catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); \ |
2711 | CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ |
2712 | } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ |
2713 | INTERNAL_CATCH_REACT( catchAssertionHandler ) \ |
2714 | } while( (void)0, (false) && static_cast<bool>( !!(__VA_ARGS__) ) ) |
2715 | |
2716 | /////////////////////////////////////////////////////////////////////////////// |
2717 | #define INTERNAL_CATCH_IF( macroName, resultDisposition, ... ) \ |
2718 | INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \ |
2719 | if( Catch::getResultCapture().lastAssertionPassed() ) |
2720 | |
2721 | /////////////////////////////////////////////////////////////////////////////// |
2722 | #define INTERNAL_CATCH_ELSE( macroName, resultDisposition, ... ) \ |
2723 | INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \ |
2724 | if( !Catch::getResultCapture().lastAssertionPassed() ) |
2725 | |
2726 | /////////////////////////////////////////////////////////////////////////////// |
2727 | #define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \ |
2728 | do { \ |
2729 | Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ |
2730 | try { \ |
2731 | static_cast<void>(__VA_ARGS__); \ |
2732 | catchAssertionHandler.handleExceptionNotThrownAsExpected(); \ |
2733 | } \ |
2734 | catch( ... ) { \ |
2735 | catchAssertionHandler.handleUnexpectedInflightException(); \ |
2736 | } \ |
2737 | INTERNAL_CATCH_REACT( catchAssertionHandler ) \ |
2738 | } while( false ) |
2739 | |
2740 | /////////////////////////////////////////////////////////////////////////////// |
2741 | #define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \ |
2742 | do { \ |
2743 | Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition); \ |
2744 | if( catchAssertionHandler.allowThrows() ) \ |
2745 | try { \ |
2746 | static_cast<void>(__VA_ARGS__); \ |
2747 | catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ |
2748 | } \ |
2749 | catch( ... ) { \ |
2750 | catchAssertionHandler.handleExceptionThrownAsExpected(); \ |
2751 | } \ |
2752 | else \ |
2753 | catchAssertionHandler.handleThrowingCallSkipped(); \ |
2754 | INTERNAL_CATCH_REACT( catchAssertionHandler ) \ |
2755 | } while( false ) |
2756 | |
2757 | /////////////////////////////////////////////////////////////////////////////// |
2758 | #define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \ |
2759 | do { \ |
2760 | Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \ |
2761 | if( catchAssertionHandler.allowThrows() ) \ |
2762 | try { \ |
2763 | static_cast<void>(expr); \ |
2764 | catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ |
2765 | } \ |
2766 | catch( exceptionType const& ) { \ |
2767 | catchAssertionHandler.handleExceptionThrownAsExpected(); \ |
2768 | } \ |
2769 | catch( ... ) { \ |
2770 | catchAssertionHandler.handleUnexpectedInflightException(); \ |
2771 | } \ |
2772 | else \ |
2773 | catchAssertionHandler.handleThrowingCallSkipped(); \ |
2774 | INTERNAL_CATCH_REACT( catchAssertionHandler ) \ |
2775 | } while( false ) |
2776 | |
2777 | /////////////////////////////////////////////////////////////////////////////// |
2778 | #define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \ |
2779 | do { \ |
2780 | Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::StringRef(), resultDisposition ); \ |
2781 | catchAssertionHandler.handleMessage( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \ |
2782 | INTERNAL_CATCH_REACT( catchAssertionHandler ) \ |
2783 | } while( false ) |
2784 | |
2785 | /////////////////////////////////////////////////////////////////////////////// |
2786 | #define INTERNAL_CATCH_CAPTURE( varName, macroName, ... ) \ |
2787 | auto varName = Catch::Capturer( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info, #__VA_ARGS__ ); \ |
2788 | varName.captureValues( 0, __VA_ARGS__ ) |
2789 | |
2790 | /////////////////////////////////////////////////////////////////////////////// |
2791 | #define INTERNAL_CATCH_INFO( macroName, log ) \ |
2792 | Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log ); |
2793 | |
2794 | /////////////////////////////////////////////////////////////////////////////// |
2795 | #define INTERNAL_CATCH_UNSCOPED_INFO( macroName, log ) \ |
2796 | Catch::getResultCapture().emplaceUnscopedMessage( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log ) |
2797 | |
2798 | /////////////////////////////////////////////////////////////////////////////// |
2799 | // Although this is matcher-based, it can be used with just a string |
2800 | #define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \ |
2801 | do { \ |
2802 | Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ |
2803 | if( catchAssertionHandler.allowThrows() ) \ |
2804 | try { \ |
2805 | static_cast<void>(__VA_ARGS__); \ |
2806 | catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ |
2807 | } \ |
2808 | catch( ... ) { \ |
2809 | Catch::handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher##_catch_sr ); \ |
2810 | } \ |
2811 | else \ |
2812 | catchAssertionHandler.handleThrowingCallSkipped(); \ |
2813 | INTERNAL_CATCH_REACT( catchAssertionHandler ) \ |
2814 | } while( false ) |
2815 | |
2816 | #endif // CATCH_CONFIG_DISABLE |
2817 | |
2818 | // end catch_capture.hpp |
2819 | // start catch_section.h |
2820 | |
2821 | // start catch_section_info.h |
2822 | |
2823 | // start catch_totals.h |
2824 | |
2825 | #include <cstddef> |
2826 | |
2827 | namespace Catch { |
2828 | |
2829 | struct Counts { |
2830 | Counts operator - ( Counts const& other ) const; |
2831 | Counts& operator += ( Counts const& other ); |
2832 | |
2833 | std::size_t total() const; |
2834 | bool allPassed() const; |
2835 | bool allOk() const; |
2836 | |
2837 | std::size_t passed = 0; |
2838 | std::size_t failed = 0; |
2839 | std::size_t failedButOk = 0; |
2840 | }; |
2841 | |
2842 | struct Totals { |
2843 | |
2844 | Totals operator - ( Totals const& other ) const; |
2845 | Totals& operator += ( Totals const& other ); |
2846 | |
2847 | Totals delta( Totals const& prevTotals ) const; |
2848 | |
2849 | int error = 0; |
2850 | Counts assertions; |
2851 | Counts testCases; |
2852 | }; |
2853 | } |
2854 | |
2855 | // end catch_totals.h |
2856 | #include <string> |
2857 | |
2858 | namespace Catch { |
2859 | |
2860 | struct SectionInfo { |
2861 | SectionInfo |
2862 | ( SourceLineInfo const& _lineInfo, |
2863 | std::string const& _name ); |
2864 | |
2865 | // Deprecated |
2866 | SectionInfo |
2867 | ( SourceLineInfo const& _lineInfo, |
2868 | std::string const& _name, |
2869 | std::string const& ) : SectionInfo( _lineInfo, _name ) {} |
2870 | |
2871 | std::string name; |
2872 | std::string description; // !Deprecated: this will always be empty |
2873 | SourceLineInfo lineInfo; |
2874 | }; |
2875 | |
2876 | struct SectionEndInfo { |
2877 | SectionInfo sectionInfo; |
2878 | Counts prevAssertions; |
2879 | double durationInSeconds; |
2880 | }; |
2881 | |
2882 | } // end namespace Catch |
2883 | |
2884 | // end catch_section_info.h |
2885 | // start catch_timer.h |
2886 | |
2887 | #include <cstdint> |
2888 | |
2889 | namespace Catch { |
2890 | |
2891 | auto getCurrentNanosecondsSinceEpoch() -> uint64_t; |
2892 | auto getEstimatedClockResolution() -> uint64_t; |
2893 | |
2894 | class Timer { |
2895 | uint64_t m_nanoseconds = 0; |
2896 | public: |
2897 | void start(); |
2898 | auto getElapsedNanoseconds() const -> uint64_t; |
2899 | auto getElapsedMicroseconds() const -> uint64_t; |
2900 | auto getElapsedMilliseconds() const -> unsigned int; |
2901 | auto getElapsedSeconds() const -> double; |
2902 | }; |
2903 | |
2904 | } // namespace Catch |
2905 | |
2906 | // end catch_timer.h |
2907 | #include <string> |
2908 | |
2909 | namespace Catch { |
2910 | |
2911 | class Section : NonCopyable { |
2912 | public: |
2913 | Section( SectionInfo const& info ); |
2914 | ~Section(); |
2915 | |
2916 | // This indicates whether the section should be executed or not |
2917 | explicit operator bool() const; |
2918 | |
2919 | private: |
2920 | SectionInfo m_info; |
2921 | |
2922 | std::string m_name; |
2923 | Counts m_assertions; |
2924 | bool m_sectionIncluded; |
2925 | Timer m_timer; |
2926 | }; |
2927 | |
2928 | } // end namespace Catch |
2929 | |
2930 | #define INTERNAL_CATCH_SECTION( ... ) \ |
2931 | CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ |
2932 | CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ |
2933 | if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \ |
2934 | CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION |
2935 | |
2936 | #define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \ |
2937 | CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ |
2938 | CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ |
2939 | if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, (Catch::ReusableStringStream() << __VA_ARGS__).str() ) ) \ |
2940 | CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION |
2941 | |
2942 | // end catch_section.h |
2943 | // start catch_interfaces_exception.h |
2944 | |
2945 | // start catch_interfaces_registry_hub.h |
2946 | |
2947 | #include <string> |
2948 | #include <memory> |
2949 | |
2950 | namespace Catch { |
2951 | |
2952 | class TestCase; |
2953 | struct ITestCaseRegistry; |
2954 | struct IExceptionTranslatorRegistry; |
2955 | struct IExceptionTranslator; |
2956 | struct IReporterRegistry; |
2957 | struct IReporterFactory; |
2958 | struct ITagAliasRegistry; |
2959 | struct IMutableEnumValuesRegistry; |
2960 | |
2961 | class StartupExceptionRegistry; |
2962 | |
2963 | using IReporterFactoryPtr = std::shared_ptr<IReporterFactory>; |
2964 | |
2965 | struct IRegistryHub { |
2966 | virtual ~IRegistryHub(); |
2967 | |
2968 | virtual IReporterRegistry const& getReporterRegistry() const = 0; |
2969 | virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; |
2970 | virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0; |
2971 | virtual IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const = 0; |
2972 | |
2973 | virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0; |
2974 | }; |
2975 | |
2976 | struct IMutableRegistryHub { |
2977 | virtual ~IMutableRegistryHub(); |
2978 | virtual void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) = 0; |
2979 | virtual void registerListener( IReporterFactoryPtr const& factory ) = 0; |
2980 | virtual void registerTest( TestCase const& testInfo ) = 0; |
2981 | virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; |
2982 | virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0; |
2983 | virtual void registerStartupException() noexcept = 0; |
2984 | virtual IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() = 0; |
2985 | }; |
2986 | |
2987 | IRegistryHub const& getRegistryHub(); |
2988 | IMutableRegistryHub& getMutableRegistryHub(); |
2989 | void cleanUp(); |
2990 | std::string translateActiveException(); |
2991 | |
2992 | } |
2993 | |
2994 | // end catch_interfaces_registry_hub.h |
2995 | #if defined(CATCH_CONFIG_DISABLE) |
2996 | #define INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( translatorName, signature) \ |
2997 | static std::string translatorName( signature ) |
2998 | #endif |
2999 | |
3000 | #include <exception> |
3001 | #include <string> |
3002 | #include <vector> |
3003 | |
3004 | namespace Catch { |
3005 | using exceptionTranslateFunction = std::string(*)(); |
3006 | |
3007 | struct IExceptionTranslator; |
3008 | using ExceptionTranslators = std::vector<std::unique_ptr<IExceptionTranslator const>>; |
3009 | |
3010 | struct IExceptionTranslator { |
3011 | virtual ~IExceptionTranslator(); |
3012 | virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0; |
3013 | }; |
3014 | |
3015 | struct IExceptionTranslatorRegistry { |
3016 | virtual ~IExceptionTranslatorRegistry(); |
3017 | |
3018 | virtual std::string translateActiveException() const = 0; |
3019 | }; |
3020 | |
3021 | class ExceptionTranslatorRegistrar { |
3022 | template<typename T> |
3023 | class ExceptionTranslator : public IExceptionTranslator { |
3024 | public: |
3025 | |
3026 | ExceptionTranslator( std::string(*translateFunction)( T& ) ) |
3027 | : m_translateFunction( translateFunction ) |
3028 | {} |
3029 | |
3030 | std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const override { |
3031 | #if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) |
3032 | return "" ; |
3033 | #else |
3034 | try { |
3035 | if( it == itEnd ) |
3036 | std::rethrow_exception(std::current_exception()); |
3037 | else |
3038 | return (*it)->translate( it+1, itEnd ); |
3039 | } |
3040 | catch( T& ex ) { |
3041 | return m_translateFunction( ex ); |
3042 | } |
3043 | #endif |
3044 | } |
3045 | |
3046 | protected: |
3047 | std::string(*m_translateFunction)( T& ); |
3048 | }; |
3049 | |
3050 | public: |
3051 | template<typename T> |
3052 | ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) { |
3053 | getMutableRegistryHub().registerTranslator |
3054 | ( new ExceptionTranslator<T>( translateFunction ) ); |
3055 | } |
3056 | }; |
3057 | } |
3058 | |
3059 | /////////////////////////////////////////////////////////////////////////////// |
3060 | #define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \ |
3061 | static std::string translatorName( signature ); \ |
3062 | CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ |
3063 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ |
3064 | namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); } \ |
3065 | CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ |
3066 | static std::string translatorName( signature ) |
3067 | |
3068 | #define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) |
3069 | |
3070 | // end catch_interfaces_exception.h |
3071 | // start catch_approx.h |
3072 | |
3073 | #include <type_traits> |
3074 | |
3075 | namespace Catch { |
3076 | namespace Detail { |
3077 | |
3078 | class Approx { |
3079 | private: |
3080 | bool equalityComparisonImpl(double other) const; |
3081 | // Validates the new margin (margin >= 0) |
3082 | // out-of-line to avoid including stdexcept in the header |
3083 | void setMargin(double margin); |
3084 | // Validates the new epsilon (0 < epsilon < 1) |
3085 | // out-of-line to avoid including stdexcept in the header |
3086 | void setEpsilon(double epsilon); |
3087 | |
3088 | public: |
3089 | explicit Approx ( double value ); |
3090 | |
3091 | static Approx custom(); |
3092 | |
3093 | Approx operator-() const; |
3094 | |
3095 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
3096 | Approx operator()( T const& value ) const { |
3097 | Approx approx( static_cast<double>(value) ); |
3098 | approx.m_epsilon = m_epsilon; |
3099 | approx.m_margin = m_margin; |
3100 | approx.m_scale = m_scale; |
3101 | return approx; |
3102 | } |
3103 | |
3104 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
3105 | explicit Approx( T const& value ): Approx(static_cast<double>(value)) |
3106 | {} |
3107 | |
3108 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
3109 | friend bool operator == ( const T& lhs, Approx const& rhs ) { |
3110 | auto lhs_v = static_cast<double>(lhs); |
3111 | return rhs.equalityComparisonImpl(lhs_v); |
3112 | } |
3113 | |
3114 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
3115 | friend bool operator == ( Approx const& lhs, const T& rhs ) { |
3116 | return operator==( rhs, lhs ); |
3117 | } |
3118 | |
3119 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
3120 | friend bool operator != ( T const& lhs, Approx const& rhs ) { |
3121 | return !operator==( lhs, rhs ); |
3122 | } |
3123 | |
3124 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
3125 | friend bool operator != ( Approx const& lhs, T const& rhs ) { |
3126 | return !operator==( rhs, lhs ); |
3127 | } |
3128 | |
3129 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
3130 | friend bool operator <= ( T const& lhs, Approx const& rhs ) { |
3131 | return static_cast<double>(lhs) < rhs.m_value || lhs == rhs; |
3132 | } |
3133 | |
3134 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
3135 | friend bool operator <= ( Approx const& lhs, T const& rhs ) { |
3136 | return lhs.m_value < static_cast<double>(rhs) || lhs == rhs; |
3137 | } |
3138 | |
3139 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
3140 | friend bool operator >= ( T const& lhs, Approx const& rhs ) { |
3141 | return static_cast<double>(lhs) > rhs.m_value || lhs == rhs; |
3142 | } |
3143 | |
3144 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
3145 | friend bool operator >= ( Approx const& lhs, T const& rhs ) { |
3146 | return lhs.m_value > static_cast<double>(rhs) || lhs == rhs; |
3147 | } |
3148 | |
3149 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
3150 | Approx& epsilon( T const& newEpsilon ) { |
3151 | double epsilonAsDouble = static_cast<double>(newEpsilon); |
3152 | setEpsilon(epsilonAsDouble); |
3153 | return *this; |
3154 | } |
3155 | |
3156 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
3157 | Approx& margin( T const& newMargin ) { |
3158 | double marginAsDouble = static_cast<double>(newMargin); |
3159 | setMargin(marginAsDouble); |
3160 | return *this; |
3161 | } |
3162 | |
3163 | template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
3164 | Approx& scale( T const& newScale ) { |
3165 | m_scale = static_cast<double>(newScale); |
3166 | return *this; |
3167 | } |
3168 | |
3169 | std::string toString() const; |
3170 | |
3171 | private: |
3172 | double m_epsilon; |
3173 | double m_margin; |
3174 | double m_scale; |
3175 | double m_value; |
3176 | }; |
3177 | } // end namespace Detail |
3178 | |
3179 | namespace literals { |
3180 | Detail::Approx operator "" _a(long double val); |
3181 | Detail::Approx operator "" _a(unsigned long long val); |
3182 | } // end namespace literals |
3183 | |
3184 | template<> |
3185 | struct StringMaker<Catch::Detail::Approx> { |
3186 | static std::string convert(Catch::Detail::Approx const& value); |
3187 | }; |
3188 | |
3189 | } // end namespace Catch |
3190 | |
3191 | // end catch_approx.h |
3192 | // start catch_string_manip.h |
3193 | |
3194 | #include <string> |
3195 | #include <iosfwd> |
3196 | #include <vector> |
3197 | |
3198 | namespace Catch { |
3199 | |
3200 | bool startsWith( std::string const& s, std::string const& prefix ); |
3201 | bool startsWith( std::string const& s, char prefix ); |
3202 | bool endsWith( std::string const& s, std::string const& suffix ); |
3203 | bool endsWith( std::string const& s, char suffix ); |
3204 | bool contains( std::string const& s, std::string const& infix ); |
3205 | void toLowerInPlace( std::string& s ); |
3206 | std::string toLower( std::string const& s ); |
3207 | //! Returns a new string without whitespace at the start/end |
3208 | std::string trim( std::string const& str ); |
3209 | //! Returns a substring of the original ref without whitespace. Beware lifetimes! |
3210 | StringRef trim(StringRef ref); |
3211 | |
3212 | // !!! Be aware, returns refs into original string - make sure original string outlives them |
3213 | std::vector<StringRef> splitStringRef( StringRef str, char delimiter ); |
3214 | bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); |
3215 | |
3216 | struct pluralise { |
3217 | pluralise( std::size_t count, std::string const& label ); |
3218 | |
3219 | friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ); |
3220 | |
3221 | std::size_t m_count; |
3222 | std::string m_label; |
3223 | }; |
3224 | } |
3225 | |
3226 | // end catch_string_manip.h |
3227 | #ifndef CATCH_CONFIG_DISABLE_MATCHERS |
3228 | // start catch_capture_matchers.h |
3229 | |
3230 | // start catch_matchers.h |
3231 | |
3232 | #include <string> |
3233 | #include <vector> |
3234 | |
3235 | namespace Catch { |
3236 | namespace Matchers { |
3237 | namespace Impl { |
3238 | |
3239 | template<typename ArgT> struct MatchAllOf; |
3240 | template<typename ArgT> struct MatchAnyOf; |
3241 | template<typename ArgT> struct MatchNotOf; |
3242 | |
3243 | class MatcherUntypedBase { |
3244 | public: |
3245 | MatcherUntypedBase() = default; |
3246 | MatcherUntypedBase ( MatcherUntypedBase const& ) = default; |
3247 | MatcherUntypedBase& operator = ( MatcherUntypedBase const& ) = delete; |
3248 | std::string toString() const; |
3249 | |
3250 | protected: |
3251 | virtual ~MatcherUntypedBase(); |
3252 | virtual std::string describe() const = 0; |
3253 | mutable std::string m_cachedToString; |
3254 | }; |
3255 | |
3256 | #ifdef __clang__ |
3257 | # pragma clang diagnostic push |
3258 | # pragma clang diagnostic ignored "-Wnon-virtual-dtor" |
3259 | #endif |
3260 | |
3261 | template<typename ObjectT> |
3262 | struct MatcherMethod { |
3263 | virtual bool match( ObjectT const& arg ) const = 0; |
3264 | }; |
3265 | |
3266 | #if defined(__OBJC__) |
3267 | // Hack to fix Catch GH issue #1661. Could use id for generic Object support. |
3268 | // use of const for Object pointers is very uncommon and under ARC it causes some kind of signature mismatch that breaks compilation |
3269 | template<> |
3270 | struct MatcherMethod<NSString*> { |
3271 | virtual bool match( NSString* arg ) const = 0; |
3272 | }; |
3273 | #endif |
3274 | |
3275 | #ifdef __clang__ |
3276 | # pragma clang diagnostic pop |
3277 | #endif |
3278 | |
3279 | template<typename T> |
3280 | struct MatcherBase : MatcherUntypedBase, MatcherMethod<T> { |
3281 | |
3282 | MatchAllOf<T> operator && ( MatcherBase const& other ) const; |
3283 | MatchAnyOf<T> operator || ( MatcherBase const& other ) const; |
3284 | MatchNotOf<T> operator ! () const; |
3285 | }; |
3286 | |
3287 | template<typename ArgT> |
3288 | struct MatchAllOf : MatcherBase<ArgT> { |
3289 | bool match( ArgT const& arg ) const override { |
3290 | for( auto matcher : m_matchers ) { |
3291 | if (!matcher->match(arg)) |
3292 | return false; |
3293 | } |
3294 | return true; |
3295 | } |
3296 | std::string describe() const override { |
3297 | std::string description; |
3298 | description.reserve( 4 + m_matchers.size()*32 ); |
3299 | description += "( " ; |
3300 | bool first = true; |
3301 | for( auto matcher : m_matchers ) { |
3302 | if( first ) |
3303 | first = false; |
3304 | else |
3305 | description += " and " ; |
3306 | description += matcher->toString(); |
3307 | } |
3308 | description += " )" ; |
3309 | return description; |
3310 | } |
3311 | |
3312 | MatchAllOf<ArgT> operator && ( MatcherBase<ArgT> const& other ) { |
3313 | auto copy(*this); |
3314 | copy.m_matchers.push_back( &other ); |
3315 | return copy; |
3316 | } |
3317 | |
3318 | std::vector<MatcherBase<ArgT> const*> m_matchers; |
3319 | }; |
3320 | template<typename ArgT> |
3321 | struct MatchAnyOf : MatcherBase<ArgT> { |
3322 | |
3323 | bool match( ArgT const& arg ) const override { |
3324 | for( auto matcher : m_matchers ) { |
3325 | if (matcher->match(arg)) |
3326 | return true; |
3327 | } |
3328 | return false; |
3329 | } |
3330 | std::string describe() const override { |
3331 | std::string description; |
3332 | description.reserve( 4 + m_matchers.size()*32 ); |
3333 | description += "( " ; |
3334 | bool first = true; |
3335 | for( auto matcher : m_matchers ) { |
3336 | if( first ) |
3337 | first = false; |
3338 | else |
3339 | description += " or " ; |
3340 | description += matcher->toString(); |
3341 | } |
3342 | description += " )" ; |
3343 | return description; |
3344 | } |
3345 | |
3346 | MatchAnyOf<ArgT> operator || ( MatcherBase<ArgT> const& other ) { |
3347 | auto copy(*this); |
3348 | copy.m_matchers.push_back( &other ); |
3349 | return copy; |
3350 | } |
3351 | |
3352 | std::vector<MatcherBase<ArgT> const*> m_matchers; |
3353 | }; |
3354 | |
3355 | template<typename ArgT> |
3356 | struct MatchNotOf : MatcherBase<ArgT> { |
3357 | |
3358 | MatchNotOf( MatcherBase<ArgT> const& underlyingMatcher ) : m_underlyingMatcher( underlyingMatcher ) {} |
3359 | |
3360 | bool match( ArgT const& arg ) const override { |
3361 | return !m_underlyingMatcher.match( arg ); |
3362 | } |
3363 | |
3364 | std::string describe() const override { |
3365 | return "not " + m_underlyingMatcher.toString(); |
3366 | } |
3367 | MatcherBase<ArgT> const& m_underlyingMatcher; |
3368 | }; |
3369 | |
3370 | template<typename T> |
3371 | MatchAllOf<T> MatcherBase<T>::operator && ( MatcherBase const& other ) const { |
3372 | return MatchAllOf<T>() && *this && other; |
3373 | } |
3374 | template<typename T> |
3375 | MatchAnyOf<T> MatcherBase<T>::operator || ( MatcherBase const& other ) const { |
3376 | return MatchAnyOf<T>() || *this || other; |
3377 | } |
3378 | template<typename T> |
3379 | MatchNotOf<T> MatcherBase<T>::operator ! () const { |
3380 | return MatchNotOf<T>( *this ); |
3381 | } |
3382 | |
3383 | } // namespace Impl |
3384 | |
3385 | } // namespace Matchers |
3386 | |
3387 | using namespace Matchers; |
3388 | using Matchers::Impl::MatcherBase; |
3389 | |
3390 | } // namespace Catch |
3391 | |
3392 | // end catch_matchers.h |
3393 | // start catch_matchers_exception.hpp |
3394 | |
3395 | namespace Catch { |
3396 | namespace Matchers { |
3397 | namespace Exception { |
3398 | |
3399 | class ExceptionMessageMatcher : public MatcherBase<std::exception> { |
3400 | std::string m_message; |
3401 | public: |
3402 | |
3403 | ExceptionMessageMatcher(std::string const& message): |
3404 | m_message(message) |
3405 | {} |
3406 | |
3407 | bool match(std::exception const& ex) const override; |
3408 | |
3409 | std::string describe() const override; |
3410 | }; |
3411 | |
3412 | } // namespace Exception |
3413 | |
3414 | Exception::ExceptionMessageMatcher Message(std::string const& message); |
3415 | |
3416 | } // namespace Matchers |
3417 | } // namespace Catch |
3418 | |
3419 | // end catch_matchers_exception.hpp |
3420 | // start catch_matchers_floating.h |
3421 | |
3422 | namespace Catch { |
3423 | namespace Matchers { |
3424 | |
3425 | namespace Floating { |
3426 | |
3427 | enum class FloatingPointKind : uint8_t; |
3428 | |
3429 | struct WithinAbsMatcher : MatcherBase<double> { |
3430 | WithinAbsMatcher(double target, double margin); |
3431 | bool match(double const& matchee) const override; |
3432 | std::string describe() const override; |
3433 | private: |
3434 | double m_target; |
3435 | double m_margin; |
3436 | }; |
3437 | |
3438 | struct WithinUlpsMatcher : MatcherBase<double> { |
3439 | WithinUlpsMatcher(double target, uint64_t ulps, FloatingPointKind baseType); |
3440 | bool match(double const& matchee) const override; |
3441 | std::string describe() const override; |
3442 | private: |
3443 | double m_target; |
3444 | uint64_t m_ulps; |
3445 | FloatingPointKind m_type; |
3446 | }; |
3447 | |
3448 | // Given IEEE-754 format for floats and doubles, we can assume |
3449 | // that float -> double promotion is lossless. Given this, we can |
3450 | // assume that if we do the standard relative comparison of |
3451 | // |lhs - rhs| <= epsilon * max(fabs(lhs), fabs(rhs)), then we get |
3452 | // the same result if we do this for floats, as if we do this for |
3453 | // doubles that were promoted from floats. |
3454 | struct WithinRelMatcher : MatcherBase<double> { |
3455 | WithinRelMatcher(double target, double epsilon); |
3456 | bool match(double const& matchee) const override; |
3457 | std::string describe() const override; |
3458 | private: |
3459 | double m_target; |
3460 | double m_epsilon; |
3461 | }; |
3462 | |
3463 | } // namespace Floating |
3464 | |
3465 | // The following functions create the actual matcher objects. |
3466 | // This allows the types to be inferred |
3467 | Floating::WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff); |
3468 | Floating::WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff); |
3469 | Floating::WithinAbsMatcher WithinAbs(double target, double margin); |
3470 | Floating::WithinRelMatcher WithinRel(double target, double eps); |
3471 | // defaults epsilon to 100*numeric_limits<double>::epsilon() |
3472 | Floating::WithinRelMatcher WithinRel(double target); |
3473 | Floating::WithinRelMatcher WithinRel(float target, float eps); |
3474 | // defaults epsilon to 100*numeric_limits<float>::epsilon() |
3475 | Floating::WithinRelMatcher WithinRel(float target); |
3476 | |
3477 | } // namespace Matchers |
3478 | } // namespace Catch |
3479 | |
3480 | // end catch_matchers_floating.h |
3481 | // start catch_matchers_generic.hpp |
3482 | |
3483 | #include <functional> |
3484 | #include <string> |
3485 | |
3486 | namespace Catch { |
3487 | namespace Matchers { |
3488 | namespace Generic { |
3489 | |
3490 | namespace Detail { |
3491 | std::string finalizeDescription(const std::string& desc); |
3492 | } |
3493 | |
3494 | template <typename T> |
3495 | class PredicateMatcher : public MatcherBase<T> { |
3496 | std::function<bool(T const&)> m_predicate; |
3497 | std::string m_description; |
3498 | public: |
3499 | |
3500 | PredicateMatcher(std::function<bool(T const&)> const& elem, std::string const& descr) |
3501 | :m_predicate(std::move(elem)), |
3502 | m_description(Detail::finalizeDescription(descr)) |
3503 | {} |
3504 | |
3505 | bool match( T const& item ) const override { |
3506 | return m_predicate(item); |
3507 | } |
3508 | |
3509 | std::string describe() const override { |
3510 | return m_description; |
3511 | } |
3512 | }; |
3513 | |
3514 | } // namespace Generic |
3515 | |
3516 | // The following functions create the actual matcher objects. |
3517 | // The user has to explicitly specify type to the function, because |
3518 | // inferring std::function<bool(T const&)> is hard (but possible) and |
3519 | // requires a lot of TMP. |
3520 | template<typename T> |
3521 | Generic::PredicateMatcher<T> Predicate(std::function<bool(T const&)> const& predicate, std::string const& description = "" ) { |
3522 | return Generic::PredicateMatcher<T>(predicate, description); |
3523 | } |
3524 | |
3525 | } // namespace Matchers |
3526 | } // namespace Catch |
3527 | |
3528 | // end catch_matchers_generic.hpp |
3529 | // start catch_matchers_string.h |
3530 | |
3531 | #include <string> |
3532 | |
3533 | namespace Catch { |
3534 | namespace Matchers { |
3535 | |
3536 | namespace StdString { |
3537 | |
3538 | struct CasedString |
3539 | { |
3540 | CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ); |
3541 | std::string adjustString( std::string const& str ) const; |
3542 | std::string caseSensitivitySuffix() const; |
3543 | |
3544 | CaseSensitive::Choice m_caseSensitivity; |
3545 | std::string m_str; |
3546 | }; |
3547 | |
3548 | struct StringMatcherBase : MatcherBase<std::string> { |
3549 | StringMatcherBase( std::string const& operation, CasedString const& comparator ); |
3550 | std::string describe() const override; |
3551 | |
3552 | CasedString m_comparator; |
3553 | std::string m_operation; |
3554 | }; |
3555 | |
3556 | struct EqualsMatcher : StringMatcherBase { |
3557 | EqualsMatcher( CasedString const& comparator ); |
3558 | bool match( std::string const& source ) const override; |
3559 | }; |
3560 | struct ContainsMatcher : StringMatcherBase { |
3561 | ContainsMatcher( CasedString const& comparator ); |
3562 | bool match( std::string const& source ) const override; |
3563 | }; |
3564 | struct StartsWithMatcher : StringMatcherBase { |
3565 | StartsWithMatcher( CasedString const& comparator ); |
3566 | bool match( std::string const& source ) const override; |
3567 | }; |
3568 | struct EndsWithMatcher : StringMatcherBase { |
3569 | EndsWithMatcher( CasedString const& comparator ); |
3570 | bool match( std::string const& source ) const override; |
3571 | }; |
3572 | |
3573 | struct RegexMatcher : MatcherBase<std::string> { |
3574 | RegexMatcher( std::string regex, CaseSensitive::Choice caseSensitivity ); |
3575 | bool match( std::string const& matchee ) const override; |
3576 | std::string describe() const override; |
3577 | |
3578 | private: |
3579 | std::string m_regex; |
3580 | CaseSensitive::Choice m_caseSensitivity; |
3581 | }; |
3582 | |
3583 | } // namespace StdString |
3584 | |
3585 | // The following functions create the actual matcher objects. |
3586 | // This allows the types to be inferred |
3587 | |
3588 | StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); |
3589 | StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); |
3590 | StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); |
3591 | StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); |
3592 | StdString::RegexMatcher Matches( std::string const& regex, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ); |
3593 | |
3594 | } // namespace Matchers |
3595 | } // namespace Catch |
3596 | |
3597 | // end catch_matchers_string.h |
3598 | // start catch_matchers_vector.h |
3599 | |
3600 | #include <algorithm> |
3601 | |
3602 | namespace Catch { |
3603 | namespace Matchers { |
3604 | |
3605 | namespace Vector { |
3606 | template<typename T, typename Alloc> |
3607 | struct ContainsElementMatcher : MatcherBase<std::vector<T, Alloc>> { |
3608 | |
3609 | ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {} |
3610 | |
3611 | bool match(std::vector<T, Alloc> const &v) const override { |
3612 | for (auto const& el : v) { |
3613 | if (el == m_comparator) { |
3614 | return true; |
3615 | } |
3616 | } |
3617 | return false; |
3618 | } |
3619 | |
3620 | std::string describe() const override { |
3621 | return "Contains: " + ::Catch::Detail::stringify( m_comparator ); |
3622 | } |
3623 | |
3624 | T const& m_comparator; |
3625 | }; |
3626 | |
3627 | template<typename T, typename AllocComp, typename AllocMatch> |
3628 | struct ContainsMatcher : MatcherBase<std::vector<T, AllocMatch>> { |
3629 | |
3630 | ContainsMatcher(std::vector<T, AllocComp> const &comparator) : m_comparator( comparator ) {} |
3631 | |
3632 | bool match(std::vector<T, AllocMatch> const &v) const override { |
3633 | // !TBD: see note in EqualsMatcher |
3634 | if (m_comparator.size() > v.size()) |
3635 | return false; |
3636 | for (auto const& comparator : m_comparator) { |
3637 | auto present = false; |
3638 | for (const auto& el : v) { |
3639 | if (el == comparator) { |
3640 | present = true; |
3641 | break; |
3642 | } |
3643 | } |
3644 | if (!present) { |
3645 | return false; |
3646 | } |
3647 | } |
3648 | return true; |
3649 | } |
3650 | std::string describe() const override { |
3651 | return "Contains: " + ::Catch::Detail::stringify( m_comparator ); |
3652 | } |
3653 | |
3654 | std::vector<T, AllocComp> const& m_comparator; |
3655 | }; |
3656 | |
3657 | template<typename T, typename AllocComp, typename AllocMatch> |
3658 | struct EqualsMatcher : MatcherBase<std::vector<T, AllocMatch>> { |
3659 | |
3660 | EqualsMatcher(std::vector<T, AllocComp> const &comparator) : m_comparator( comparator ) {} |
3661 | |
3662 | bool match(std::vector<T, AllocMatch> const &v) const override { |
3663 | // !TBD: This currently works if all elements can be compared using != |
3664 | // - a more general approach would be via a compare template that defaults |
3665 | // to using !=. but could be specialised for, e.g. std::vector<T, Alloc> etc |
3666 | // - then just call that directly |
3667 | if (m_comparator.size() != v.size()) |
3668 | return false; |
3669 | for (std::size_t i = 0; i < v.size(); ++i) |
3670 | if (m_comparator[i] != v[i]) |
3671 | return false; |
3672 | return true; |
3673 | } |
3674 | std::string describe() const override { |
3675 | return "Equals: " + ::Catch::Detail::stringify( m_comparator ); |
3676 | } |
3677 | std::vector<T, AllocComp> const& m_comparator; |
3678 | }; |
3679 | |
3680 | template<typename T, typename AllocComp, typename AllocMatch> |
3681 | struct ApproxMatcher : MatcherBase<std::vector<T, AllocMatch>> { |
3682 | |
3683 | ApproxMatcher(std::vector<T, AllocComp> const& comparator) : m_comparator( comparator ) {} |
3684 | |
3685 | bool match(std::vector<T, AllocMatch> const &v) const override { |
3686 | if (m_comparator.size() != v.size()) |
3687 | return false; |
3688 | for (std::size_t i = 0; i < v.size(); ++i) |
3689 | if (m_comparator[i] != approx(v[i])) |
3690 | return false; |
3691 | return true; |
3692 | } |
3693 | std::string describe() const override { |
3694 | return "is approx: " + ::Catch::Detail::stringify( m_comparator ); |
3695 | } |
3696 | template <typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
3697 | ApproxMatcher& epsilon( T const& newEpsilon ) { |
3698 | approx.epsilon(newEpsilon); |
3699 | return *this; |
3700 | } |
3701 | template <typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
3702 | ApproxMatcher& margin( T const& newMargin ) { |
3703 | approx.margin(newMargin); |
3704 | return *this; |
3705 | } |
3706 | template <typename = typename std::enable_if<std::is_constructible<double, T>::value>::type> |
3707 | ApproxMatcher& scale( T const& newScale ) { |
3708 | approx.scale(newScale); |
3709 | return *this; |
3710 | } |
3711 | |
3712 | std::vector<T, AllocComp> const& m_comparator; |
3713 | mutable Catch::Detail::Approx approx = Catch::Detail::Approx::custom(); |
3714 | }; |
3715 | |
3716 | template<typename T, typename AllocComp, typename AllocMatch> |
3717 | struct UnorderedEqualsMatcher : MatcherBase<std::vector<T, AllocMatch>> { |
3718 | UnorderedEqualsMatcher(std::vector<T, AllocComp> const& target) : m_target(target) {} |
3719 | bool match(std::vector<T, AllocMatch> const& vec) const override { |
3720 | if (m_target.size() != vec.size()) { |
3721 | return false; |
3722 | } |
3723 | return std::is_permutation(m_target.begin(), m_target.end(), vec.begin()); |
3724 | } |
3725 | |
3726 | std::string describe() const override { |
3727 | return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target); |
3728 | } |
3729 | private: |
3730 | std::vector<T, AllocComp> const& m_target; |
3731 | }; |
3732 | |
3733 | } // namespace Vector |
3734 | |
3735 | // The following functions create the actual matcher objects. |
3736 | // This allows the types to be inferred |
3737 | |
3738 | template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp> |
3739 | Vector::ContainsMatcher<T, AllocComp, AllocMatch> Contains( std::vector<T, AllocComp> const& comparator ) { |
3740 | return Vector::ContainsMatcher<T, AllocComp, AllocMatch>( comparator ); |
3741 | } |
3742 | |
3743 | template<typename T, typename Alloc = std::allocator<T>> |
3744 | Vector::ContainsElementMatcher<T, Alloc> VectorContains( T const& comparator ) { |
3745 | return Vector::ContainsElementMatcher<T, Alloc>( comparator ); |
3746 | } |
3747 | |
3748 | template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp> |
3749 | Vector::EqualsMatcher<T, AllocComp, AllocMatch> Equals( std::vector<T, AllocComp> const& comparator ) { |
3750 | return Vector::EqualsMatcher<T, AllocComp, AllocMatch>( comparator ); |
3751 | } |
3752 | |
3753 | template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp> |
3754 | Vector::ApproxMatcher<T, AllocComp, AllocMatch> Approx( std::vector<T, AllocComp> const& comparator ) { |
3755 | return Vector::ApproxMatcher<T, AllocComp, AllocMatch>( comparator ); |
3756 | } |
3757 | |
3758 | template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp> |
3759 | Vector::UnorderedEqualsMatcher<T, AllocComp, AllocMatch> UnorderedEquals(std::vector<T, AllocComp> const& target) { |
3760 | return Vector::UnorderedEqualsMatcher<T, AllocComp, AllocMatch>( target ); |
3761 | } |
3762 | |
3763 | } // namespace Matchers |
3764 | } // namespace Catch |
3765 | |
3766 | // end catch_matchers_vector.h |
3767 | namespace Catch { |
3768 | |
3769 | template<typename ArgT, typename MatcherT> |
3770 | class MatchExpr : public ITransientExpression { |
3771 | ArgT const& m_arg; |
3772 | MatcherT m_matcher; |
3773 | StringRef m_matcherString; |
3774 | public: |
3775 | MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef const& matcherString ) |
3776 | : ITransientExpression{ true, matcher.match( arg ) }, |
3777 | m_arg( arg ), |
3778 | m_matcher( matcher ), |
3779 | m_matcherString( matcherString ) |
3780 | {} |
3781 | |
3782 | void streamReconstructedExpression( std::ostream &os ) const override { |
3783 | auto matcherAsString = m_matcher.toString(); |
3784 | os << Catch::Detail::stringify( m_arg ) << ' '; |
3785 | if( matcherAsString == Detail::unprintableString ) |
3786 | os << m_matcherString; |
3787 | else |
3788 | os << matcherAsString; |
3789 | } |
3790 | }; |
3791 | |
3792 | using StringMatcher = Matchers::Impl::MatcherBase<std::string>; |
3793 | |
3794 | void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString ); |
3795 | |
3796 | template<typename ArgT, typename MatcherT> |
3797 | auto makeMatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef const& matcherString ) -> MatchExpr<ArgT, MatcherT> { |
3798 | return MatchExpr<ArgT, MatcherT>( arg, matcher, matcherString ); |
3799 | } |
3800 | |
3801 | } // namespace Catch |
3802 | |
3803 | /////////////////////////////////////////////////////////////////////////////// |
3804 | #define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \ |
3805 | do { \ |
3806 | Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ |
3807 | INTERNAL_CATCH_TRY { \ |
3808 | catchAssertionHandler.handleExpr( Catch::makeMatchExpr( arg, matcher, #matcher##_catch_sr ) ); \ |
3809 | } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ |
3810 | INTERNAL_CATCH_REACT( catchAssertionHandler ) \ |
3811 | } while( false ) |
3812 | |
3813 | /////////////////////////////////////////////////////////////////////////////// |
3814 | #define INTERNAL_CATCH_THROWS_MATCHES( macroName, exceptionType, resultDisposition, matcher, ... ) \ |
3815 | do { \ |
3816 | Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(exceptionType) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \ |
3817 | if( catchAssertionHandler.allowThrows() ) \ |
3818 | try { \ |
3819 | static_cast<void>(__VA_ARGS__ ); \ |
3820 | catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \ |
3821 | } \ |
3822 | catch( exceptionType const& ex ) { \ |
3823 | catchAssertionHandler.handleExpr( Catch::makeMatchExpr( ex, matcher, #matcher##_catch_sr ) ); \ |
3824 | } \ |
3825 | catch( ... ) { \ |
3826 | catchAssertionHandler.handleUnexpectedInflightException(); \ |
3827 | } \ |
3828 | else \ |
3829 | catchAssertionHandler.handleThrowingCallSkipped(); \ |
3830 | INTERNAL_CATCH_REACT( catchAssertionHandler ) \ |
3831 | } while( false ) |
3832 | |
3833 | // end catch_capture_matchers.h |
3834 | #endif |
3835 | // start catch_generators.hpp |
3836 | |
3837 | // start catch_interfaces_generatortracker.h |
3838 | |
3839 | |
3840 | #include <memory> |
3841 | |
3842 | namespace Catch { |
3843 | |
3844 | namespace Generators { |
3845 | class GeneratorUntypedBase { |
3846 | public: |
3847 | GeneratorUntypedBase() = default; |
3848 | virtual ~GeneratorUntypedBase(); |
3849 | // Attempts to move the generator to the next element |
3850 | // |
3851 | // Returns true iff the move succeeded (and a valid element |
3852 | // can be retrieved). |
3853 | virtual bool next() = 0; |
3854 | }; |
3855 | using GeneratorBasePtr = std::unique_ptr<GeneratorUntypedBase>; |
3856 | |
3857 | } // namespace Generators |
3858 | |
3859 | struct IGeneratorTracker { |
3860 | virtual ~IGeneratorTracker(); |
3861 | virtual auto hasGenerator() const -> bool = 0; |
3862 | virtual auto getGenerator() const -> Generators::GeneratorBasePtr const& = 0; |
3863 | virtual void setGenerator( Generators::GeneratorBasePtr&& generator ) = 0; |
3864 | }; |
3865 | |
3866 | } // namespace Catch |
3867 | |
3868 | // end catch_interfaces_generatortracker.h |
3869 | // start catch_enforce.h |
3870 | |
3871 | #include <exception> |
3872 | |
3873 | namespace Catch { |
3874 | #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) |
3875 | template <typename Ex> |
3876 | [[noreturn]] |
3877 | void throw_exception(Ex const& e) { |
3878 | throw e; |
3879 | } |
3880 | #else // ^^ Exceptions are enabled // Exceptions are disabled vv |
3881 | [[noreturn]] |
3882 | void throw_exception(std::exception const& e); |
3883 | #endif |
3884 | |
3885 | [[noreturn]] |
3886 | void throw_logic_error(std::string const& msg); |
3887 | [[noreturn]] |
3888 | void throw_domain_error(std::string const& msg); |
3889 | [[noreturn]] |
3890 | void throw_runtime_error(std::string const& msg); |
3891 | |
3892 | } // namespace Catch; |
3893 | |
3894 | #define CATCH_MAKE_MSG(...) \ |
3895 | (Catch::ReusableStringStream() << __VA_ARGS__).str() |
3896 | |
3897 | #define CATCH_INTERNAL_ERROR(...) \ |
3898 | Catch::throw_logic_error(CATCH_MAKE_MSG( CATCH_INTERNAL_LINEINFO << ": Internal Catch2 error: " << __VA_ARGS__)) |
3899 | |
3900 | #define CATCH_ERROR(...) \ |
3901 | Catch::throw_domain_error(CATCH_MAKE_MSG( __VA_ARGS__ )) |
3902 | |
3903 | #define CATCH_RUNTIME_ERROR(...) \ |
3904 | Catch::throw_runtime_error(CATCH_MAKE_MSG( __VA_ARGS__ )) |
3905 | |
3906 | #define CATCH_ENFORCE( condition, ... ) \ |
3907 | do{ if( !(condition) ) CATCH_ERROR( __VA_ARGS__ ); } while(false) |
3908 | |
3909 | // end catch_enforce.h |
3910 | #include <memory> |
3911 | #include <vector> |
3912 | #include <cassert> |
3913 | |
3914 | #include <utility> |
3915 | #include <exception> |
3916 | |
3917 | namespace Catch { |
3918 | |
3919 | class GeneratorException : public std::exception { |
3920 | const char* const m_msg = "" ; |
3921 | |
3922 | public: |
3923 | GeneratorException(const char* msg): |
3924 | m_msg(msg) |
3925 | {} |
3926 | |
3927 | const char* what() const noexcept override final; |
3928 | }; |
3929 | |
3930 | namespace Generators { |
3931 | |
3932 | // !TBD move this into its own location? |
3933 | namespace pf{ |
3934 | template<typename T, typename... Args> |
3935 | std::unique_ptr<T> make_unique( Args&&... args ) { |
3936 | return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); |
3937 | } |
3938 | } |
3939 | |
3940 | template<typename T> |
3941 | struct IGenerator : GeneratorUntypedBase { |
3942 | virtual ~IGenerator() = default; |
3943 | |
3944 | // Returns the current element of the generator |
3945 | // |
3946 | // \Precondition The generator is either freshly constructed, |
3947 | // or the last call to `next()` returned true |
3948 | virtual T const& get() const = 0; |
3949 | using type = T; |
3950 | }; |
3951 | |
3952 | template<typename T> |
3953 | class SingleValueGenerator final : public IGenerator<T> { |
3954 | T m_value; |
3955 | public: |
3956 | SingleValueGenerator(T&& value) : m_value(std::move(value)) {} |
3957 | |
3958 | T const& get() const override { |
3959 | return m_value; |
3960 | } |
3961 | bool next() override { |
3962 | return false; |
3963 | } |
3964 | }; |
3965 | |
3966 | template<typename T> |
3967 | class FixedValuesGenerator final : public IGenerator<T> { |
3968 | static_assert(!std::is_same<T, bool>::value, |
3969 | "FixedValuesGenerator does not support bools because of std::vector<bool>" |
3970 | "specialization, use SingleValue Generator instead." ); |
3971 | std::vector<T> m_values; |
3972 | size_t m_idx = 0; |
3973 | public: |
3974 | FixedValuesGenerator( std::initializer_list<T> values ) : m_values( values ) {} |
3975 | |
3976 | T const& get() const override { |
3977 | return m_values[m_idx]; |
3978 | } |
3979 | bool next() override { |
3980 | ++m_idx; |
3981 | return m_idx < m_values.size(); |
3982 | } |
3983 | }; |
3984 | |
3985 | template <typename T> |
3986 | class GeneratorWrapper final { |
3987 | std::unique_ptr<IGenerator<T>> m_generator; |
3988 | public: |
3989 | GeneratorWrapper(std::unique_ptr<IGenerator<T>> generator): |
3990 | m_generator(std::move(generator)) |
3991 | {} |
3992 | T const& get() const { |
3993 | return m_generator->get(); |
3994 | } |
3995 | bool next() { |
3996 | return m_generator->next(); |
3997 | } |
3998 | }; |
3999 | |
4000 | template <typename T> |
4001 | GeneratorWrapper<T> value(T&& value) { |
4002 | return GeneratorWrapper<T>(pf::make_unique<SingleValueGenerator<T>>(std::forward<T>(value))); |
4003 | } |
4004 | template <typename T> |
4005 | GeneratorWrapper<T> values(std::initializer_list<T> values) { |
4006 | return GeneratorWrapper<T>(pf::make_unique<FixedValuesGenerator<T>>(values)); |
4007 | } |
4008 | |
4009 | template<typename T> |
4010 | class Generators : public IGenerator<T> { |
4011 | std::vector<GeneratorWrapper<T>> m_generators; |
4012 | size_t m_current = 0; |
4013 | |
4014 | void populate(GeneratorWrapper<T>&& generator) { |
4015 | m_generators.emplace_back(std::move(generator)); |
4016 | } |
4017 | void populate(T&& val) { |
4018 | m_generators.emplace_back(value(std::forward<T>(val))); |
4019 | } |
4020 | template<typename U> |
4021 | void populate(U&& val) { |
4022 | populate(T(std::forward<U>(val))); |
4023 | } |
4024 | template<typename U, typename... Gs> |
4025 | void populate(U&& valueOrGenerator, Gs &&... moreGenerators) { |
4026 | populate(std::forward<U>(valueOrGenerator)); |
4027 | populate(std::forward<Gs>(moreGenerators)...); |
4028 | } |
4029 | |
4030 | public: |
4031 | template <typename... Gs> |
4032 | Generators(Gs &&... moreGenerators) { |
4033 | m_generators.reserve(sizeof...(Gs)); |
4034 | populate(std::forward<Gs>(moreGenerators)...); |
4035 | } |
4036 | |
4037 | T const& get() const override { |
4038 | return m_generators[m_current].get(); |
4039 | } |
4040 | |
4041 | bool next() override { |
4042 | if (m_current >= m_generators.size()) { |
4043 | return false; |
4044 | } |
4045 | const bool current_status = m_generators[m_current].next(); |
4046 | if (!current_status) { |
4047 | ++m_current; |
4048 | } |
4049 | return m_current < m_generators.size(); |
4050 | } |
4051 | }; |
4052 | |
4053 | template<typename... Ts> |
4054 | GeneratorWrapper<std::tuple<Ts...>> table( std::initializer_list<std::tuple<typename std::decay<Ts>::type...>> tuples ) { |
4055 | return values<std::tuple<Ts...>>( tuples ); |
4056 | } |
4057 | |
4058 | // Tag type to signal that a generator sequence should convert arguments to a specific type |
4059 | template <typename T> |
4060 | struct as {}; |
4061 | |
4062 | template<typename T, typename... Gs> |
4063 | auto makeGenerators( GeneratorWrapper<T>&& generator, Gs &&... moreGenerators ) -> Generators<T> { |
4064 | return Generators<T>(std::move(generator), std::forward<Gs>(moreGenerators)...); |
4065 | } |
4066 | template<typename T> |
4067 | auto makeGenerators( GeneratorWrapper<T>&& generator ) -> Generators<T> { |
4068 | return Generators<T>(std::move(generator)); |
4069 | } |
4070 | template<typename T, typename... Gs> |
4071 | auto makeGenerators( T&& val, Gs &&... moreGenerators ) -> Generators<T> { |
4072 | return makeGenerators( value( std::forward<T>( val ) ), std::forward<Gs>( moreGenerators )... ); |
4073 | } |
4074 | template<typename T, typename U, typename... Gs> |
4075 | auto makeGenerators( as<T>, U&& val, Gs &&... moreGenerators ) -> Generators<T> { |
4076 | return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... ); |
4077 | } |
4078 | |
4079 | auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker&; |
4080 | |
4081 | template<typename L> |
4082 | // Note: The type after -> is weird, because VS2015 cannot parse |
4083 | // the expression used in the typedef inside, when it is in |
4084 | // return type. Yeah. |
4085 | auto generate( StringRef generatorName, SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>().get()) { |
4086 | using UnderlyingType = typename decltype(generatorExpression())::type; |
4087 | |
4088 | IGeneratorTracker& tracker = acquireGeneratorTracker( generatorName, lineInfo ); |
4089 | if (!tracker.hasGenerator()) { |
4090 | tracker.setGenerator(pf::make_unique<Generators<UnderlyingType>>(generatorExpression())); |
4091 | } |
4092 | |
4093 | auto const& generator = static_cast<IGenerator<UnderlyingType> const&>( *tracker.getGenerator() ); |
4094 | return generator.get(); |
4095 | } |
4096 | |
4097 | } // namespace Generators |
4098 | } // namespace Catch |
4099 | |
4100 | #define GENERATE( ... ) \ |
4101 | Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \ |
4102 | CATCH_INTERNAL_LINEINFO, \ |
4103 | [ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace) |
4104 | #define GENERATE_COPY( ... ) \ |
4105 | Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \ |
4106 | CATCH_INTERNAL_LINEINFO, \ |
4107 | [=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace) |
4108 | #define GENERATE_REF( ... ) \ |
4109 | Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \ |
4110 | CATCH_INTERNAL_LINEINFO, \ |
4111 | [&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace) |
4112 | |
4113 | // end catch_generators.hpp |
4114 | // start catch_generators_generic.hpp |
4115 | |
4116 | namespace Catch { |
4117 | namespace Generators { |
4118 | |
4119 | template <typename T> |
4120 | class TakeGenerator : public IGenerator<T> { |
4121 | GeneratorWrapper<T> m_generator; |
4122 | size_t m_returned = 0; |
4123 | size_t m_target; |
4124 | public: |
4125 | TakeGenerator(size_t target, GeneratorWrapper<T>&& generator): |
4126 | m_generator(std::move(generator)), |
4127 | m_target(target) |
4128 | { |
4129 | assert(target != 0 && "Empty generators are not allowed" ); |
4130 | } |
4131 | T const& get() const override { |
4132 | return m_generator.get(); |
4133 | } |
4134 | bool next() override { |
4135 | ++m_returned; |
4136 | if (m_returned >= m_target) { |
4137 | return false; |
4138 | } |
4139 | |
4140 | const auto success = m_generator.next(); |
4141 | // If the underlying generator does not contain enough values |
4142 | // then we cut short as well |
4143 | if (!success) { |
4144 | m_returned = m_target; |
4145 | } |
4146 | return success; |
4147 | } |
4148 | }; |
4149 | |
4150 | template <typename T> |
4151 | GeneratorWrapper<T> take(size_t target, GeneratorWrapper<T>&& generator) { |
4152 | return GeneratorWrapper<T>(pf::make_unique<TakeGenerator<T>>(target, std::move(generator))); |
4153 | } |
4154 | |
4155 | template <typename T, typename Predicate> |
4156 | class FilterGenerator : public IGenerator<T> { |
4157 | GeneratorWrapper<T> m_generator; |
4158 | Predicate m_predicate; |
4159 | public: |
4160 | template <typename P = Predicate> |
4161 | FilterGenerator(P&& pred, GeneratorWrapper<T>&& generator): |
4162 | m_generator(std::move(generator)), |
4163 | m_predicate(std::forward<P>(pred)) |
4164 | { |
4165 | if (!m_predicate(m_generator.get())) { |
4166 | // It might happen that there are no values that pass the |
4167 | // filter. In that case we throw an exception. |
4168 | auto has_initial_value = nextImpl(); |
4169 | if (!has_initial_value) { |
4170 | Catch::throw_exception(GeneratorException("No valid value found in filtered generator" )); |
4171 | } |
4172 | } |
4173 | } |
4174 | |
4175 | T const& get() const override { |
4176 | return m_generator.get(); |
4177 | } |
4178 | |
4179 | bool next() override { |
4180 | return nextImpl(); |
4181 | } |
4182 | |
4183 | private: |
4184 | bool nextImpl() { |
4185 | bool success = m_generator.next(); |
4186 | if (!success) { |
4187 | return false; |
4188 | } |
4189 | while (!m_predicate(m_generator.get()) && (success = m_generator.next()) == true); |
4190 | return success; |
4191 | } |
4192 | }; |
4193 | |
4194 | template <typename T, typename Predicate> |
4195 | GeneratorWrapper<T> filter(Predicate&& pred, GeneratorWrapper<T>&& generator) { |
4196 | return GeneratorWrapper<T>(std::unique_ptr<IGenerator<T>>(pf::make_unique<FilterGenerator<T, Predicate>>(std::forward<Predicate>(pred), std::move(generator)))); |
4197 | } |
4198 | |
4199 | template <typename T> |
4200 | class RepeatGenerator : public IGenerator<T> { |
4201 | static_assert(!std::is_same<T, bool>::value, |
4202 | "RepeatGenerator currently does not support bools" |
4203 | "because of std::vector<bool> specialization" ); |
4204 | GeneratorWrapper<T> m_generator; |
4205 | mutable std::vector<T> m_returned; |
4206 | size_t m_target_repeats; |
4207 | size_t m_current_repeat = 0; |
4208 | size_t m_repeat_index = 0; |
4209 | public: |
4210 | RepeatGenerator(size_t repeats, GeneratorWrapper<T>&& generator): |
4211 | m_generator(std::move(generator)), |
4212 | m_target_repeats(repeats) |
4213 | { |
4214 | assert(m_target_repeats > 0 && "Repeat generator must repeat at least once" ); |
4215 | } |
4216 | |
4217 | T const& get() const override { |
4218 | if (m_current_repeat == 0) { |
4219 | m_returned.push_back(m_generator.get()); |
4220 | return m_returned.back(); |
4221 | } |
4222 | return m_returned[m_repeat_index]; |
4223 | } |
4224 | |
4225 | bool next() override { |
4226 | // There are 2 basic cases: |
4227 | // 1) We are still reading the generator |
4228 | // 2) We are reading our own cache |
4229 | |
4230 | // In the first case, we need to poke the underlying generator. |
4231 | // If it happily moves, we are left in that state, otherwise it is time to start reading from our cache |
4232 | if (m_current_repeat == 0) { |
4233 | const auto success = m_generator.next(); |
4234 | if (!success) { |
4235 | ++m_current_repeat; |
4236 | } |
4237 | return m_current_repeat < m_target_repeats; |
4238 | } |
4239 | |
4240 | // In the second case, we need to move indices forward and check that we haven't run up against the end |
4241 | ++m_repeat_index; |
4242 | if (m_repeat_index == m_returned.size()) { |
4243 | m_repeat_index = 0; |
4244 | ++m_current_repeat; |
4245 | } |
4246 | return m_current_repeat < m_target_repeats; |
4247 | } |
4248 | }; |
4249 | |
4250 | template <typename T> |
4251 | GeneratorWrapper<T> repeat(size_t repeats, GeneratorWrapper<T>&& generator) { |
4252 | return GeneratorWrapper<T>(pf::make_unique<RepeatGenerator<T>>(repeats, std::move(generator))); |
4253 | } |
4254 | |
4255 | template <typename T, typename U, typename Func> |
4256 | class MapGenerator : public IGenerator<T> { |
4257 | // TBD: provide static assert for mapping function, for friendly error message |
4258 | GeneratorWrapper<U> m_generator; |
4259 | Func m_function; |
4260 | // To avoid returning dangling reference, we have to save the values |
4261 | T m_cache; |
4262 | public: |
4263 | template <typename F2 = Func> |
4264 | MapGenerator(F2&& function, GeneratorWrapper<U>&& generator) : |
4265 | m_generator(std::move(generator)), |
4266 | m_function(std::forward<F2>(function)), |
4267 | m_cache(m_function(m_generator.get())) |
4268 | {} |
4269 | |
4270 | T const& get() const override { |
4271 | return m_cache; |
4272 | } |
4273 | bool next() override { |
4274 | const auto success = m_generator.next(); |
4275 | if (success) { |
4276 | m_cache = m_function(m_generator.get()); |
4277 | } |
4278 | return success; |
4279 | } |
4280 | }; |
4281 | |
4282 | template <typename Func, typename U, typename T = FunctionReturnType<Func, U>> |
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, typename U, typename Func> |
4290 | GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) { |
4291 | return GeneratorWrapper<T>( |
4292 | pf::make_unique<MapGenerator<T, U, Func>>(std::forward<Func>(function), std::move(generator)) |
4293 | ); |
4294 | } |
4295 | |
4296 | template <typename T> |
4297 | class ChunkGenerator final : public IGenerator<std::vector<T>> { |
4298 | std::vector<T> m_chunk; |
4299 | size_t m_chunk_size; |
4300 | GeneratorWrapper<T> m_generator; |
4301 | bool m_used_up = false; |
4302 | public: |
4303 | ChunkGenerator(size_t size, GeneratorWrapper<T> generator) : |
4304 | m_chunk_size(size), m_generator(std::move(generator)) |
4305 | { |
4306 | m_chunk.reserve(m_chunk_size); |
4307 | if (m_chunk_size != 0) { |
4308 | m_chunk.push_back(m_generator.get()); |
4309 | for (size_t i = 1; i < m_chunk_size; ++i) { |
4310 | if (!m_generator.next()) { |
4311 | Catch::throw_exception(GeneratorException("Not enough values to initialize the first chunk" )); |
4312 | } |
4313 | m_chunk.push_back(m_generator.get()); |
4314 | } |
4315 | } |
4316 | } |
4317 | std::vector<T> const& get() const override { |
4318 | return m_chunk; |
4319 | } |
4320 | bool next() override { |
4321 | m_chunk.clear(); |
4322 | for (size_t idx = 0; idx < m_chunk_size; ++idx) { |
4323 | if (!m_generator.next()) { |
4324 | return false; |
4325 | } |
4326 | m_chunk.push_back(m_generator.get()); |
4327 | } |
4328 | return true; |
4329 | } |
4330 | }; |
4331 | |
4332 | template <typename T> |
4333 | GeneratorWrapper<std::vector<T>> chunk(size_t size, GeneratorWrapper<T>&& generator) { |
4334 | return GeneratorWrapper<std::vector<T>>( |
4335 | pf::make_unique<ChunkGenerator<T>>(size, std::move(generator)) |
4336 | ); |
4337 | } |
4338 | |
4339 | } // namespace Generators |
4340 | } // namespace Catch |
4341 | |
4342 | // end catch_generators_generic.hpp |
4343 | // start catch_generators_specific.hpp |
4344 | |
4345 | // start catch_context.h |
4346 | |
4347 | #include <memory> |
4348 | |
4349 | namespace Catch { |
4350 | |
4351 | struct IResultCapture; |
4352 | struct IRunner; |
4353 | struct IConfig; |
4354 | struct IMutableContext; |
4355 | |
4356 | using IConfigPtr = std::shared_ptr<IConfig const>; |
4357 | |
4358 | struct IContext |
4359 | { |
4360 | virtual ~IContext(); |
4361 | |
4362 | virtual IResultCapture* getResultCapture() = 0; |
4363 | virtual IRunner* getRunner() = 0; |
4364 | virtual IConfigPtr const& getConfig() const = 0; |
4365 | }; |
4366 | |
4367 | struct IMutableContext : IContext |
4368 | { |
4369 | virtual ~IMutableContext(); |
4370 | virtual void setResultCapture( IResultCapture* resultCapture ) = 0; |
4371 | virtual void setRunner( IRunner* runner ) = 0; |
4372 | virtual void setConfig( IConfigPtr const& config ) = 0; |
4373 | |
4374 | private: |
4375 | static IMutableContext *currentContext; |
4376 | friend IMutableContext& getCurrentMutableContext(); |
4377 | friend void cleanUpContext(); |
4378 | static void createContext(); |
4379 | }; |
4380 | |
4381 | inline IMutableContext& getCurrentMutableContext() |
4382 | { |
4383 | if( !IMutableContext::currentContext ) |
4384 | IMutableContext::createContext(); |
4385 | // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn) |
4386 | return *IMutableContext::currentContext; |
4387 | } |
4388 | |
4389 | inline IContext& getCurrentContext() |
4390 | { |
4391 | return getCurrentMutableContext(); |
4392 | } |
4393 | |
4394 | void cleanUpContext(); |
4395 | |
4396 | class SimplePcg32; |
4397 | SimplePcg32& rng(); |
4398 | } |
4399 | |
4400 | // end catch_context.h |
4401 | // start catch_interfaces_config.h |
4402 | |
4403 | // start catch_option.hpp |
4404 | |
4405 | namespace Catch { |
4406 | |
4407 | // An optional type |
4408 | template<typename T> |
4409 | class Option { |
4410 | public: |
4411 | Option() : nullableValue( nullptr ) {} |
4412 | Option( T const& _value ) |
4413 | : nullableValue( new( storage ) T( _value ) ) |
4414 | {} |
4415 | Option( Option const& _other ) |
4416 | : nullableValue( _other ? new( storage ) T( *_other ) : nullptr ) |
4417 | {} |
4418 | |
4419 | ~Option() { |
4420 | reset(); |
4421 | } |
4422 | |
4423 | Option& operator= ( Option const& _other ) { |
4424 | if( &_other != this ) { |
4425 | reset(); |
4426 | if( _other ) |
4427 | nullableValue = new( storage ) T( *_other ); |
4428 | } |
4429 | return *this; |
4430 | } |
4431 | Option& operator = ( T const& _value ) { |
4432 | reset(); |
4433 | nullableValue = new( storage ) T( _value ); |
4434 | return *this; |
4435 | } |
4436 | |
4437 | void reset() { |
4438 | if( nullableValue ) |
4439 | nullableValue->~T(); |
4440 | nullableValue = nullptr; |
4441 | } |
4442 | |
4443 | T& operator*() { return *nullableValue; } |
4444 | T const& operator*() const { return *nullableValue; } |
4445 | T* operator->() { return nullableValue; } |
4446 | const T* operator->() const { return nullableValue; } |
4447 | |
4448 | T valueOr( T const& defaultValue ) const { |
4449 | return nullableValue ? *nullableValue : defaultValue; |
4450 | } |
4451 | |
4452 | bool some() const { return nullableValue != nullptr; } |
4453 | bool none() const { return nullableValue == nullptr; } |
4454 | |
4455 | bool operator !() const { return nullableValue == nullptr; } |
4456 | explicit operator bool() const { |
4457 | return some(); |
4458 | } |
4459 | |
4460 | private: |
4461 | T *nullableValue; |
4462 | alignas(alignof(T)) char storage[sizeof(T)]; |
4463 | }; |
4464 | |
4465 | } // end namespace Catch |
4466 | |
4467 | // end catch_option.hpp |
4468 | #include <chrono> |
4469 | #include <iosfwd> |
4470 | #include <string> |
4471 | #include <vector> |
4472 | #include <memory> |
4473 | |
4474 | namespace Catch { |
4475 | |
4476 | enum class Verbosity { |
4477 | Quiet = 0, |
4478 | Normal, |
4479 | High |
4480 | }; |
4481 | |
4482 | struct WarnAbout { enum What { |
4483 | Nothing = 0x00, |
4484 | NoAssertions = 0x01, |
4485 | NoTests = 0x02 |
4486 | }; }; |
4487 | |
4488 | struct ShowDurations { enum OrNot { |
4489 | DefaultForReporter, |
4490 | Always, |
4491 | Never |
4492 | }; }; |
4493 | struct RunTests { enum InWhatOrder { |
4494 | InDeclarationOrder, |
4495 | InLexicographicalOrder, |
4496 | InRandomOrder |
4497 | }; }; |
4498 | struct UseColour { enum YesOrNo { |
4499 | Auto, |
4500 | Yes, |
4501 | No |
4502 | }; }; |
4503 | struct WaitForKeypress { enum When { |
4504 | Never, |
4505 | BeforeStart = 1, |
4506 | BeforeExit = 2, |
4507 | BeforeStartAndExit = BeforeStart | BeforeExit |
4508 | }; }; |
4509 | |
4510 | class TestSpec; |
4511 | |
4512 | struct IConfig : NonCopyable { |
4513 | |
4514 | virtual ~IConfig(); |
4515 | |
4516 | virtual bool allowThrows() const = 0; |
4517 | virtual std::ostream& stream() const = 0; |
4518 | virtual std::string name() const = 0; |
4519 | virtual bool includeSuccessfulResults() const = 0; |
4520 | virtual bool shouldDebugBreak() const = 0; |
4521 | virtual bool warnAboutMissingAssertions() const = 0; |
4522 | virtual bool warnAboutNoTests() const = 0; |
4523 | virtual int abortAfter() const = 0; |
4524 | virtual bool showInvisibles() const = 0; |
4525 | virtual ShowDurations::OrNot showDurations() const = 0; |
4526 | virtual double minDuration() const = 0; |
4527 | virtual TestSpec const& testSpec() const = 0; |
4528 | virtual bool hasTestFilters() const = 0; |
4529 | virtual std::vector<std::string> const& getTestsOrTags() const = 0; |
4530 | virtual RunTests::InWhatOrder runOrder() const = 0; |
4531 | virtual unsigned int rngSeed() const = 0; |
4532 | virtual UseColour::YesOrNo useColour() const = 0; |
4533 | virtual std::vector<std::string> const& getSectionsToRun() const = 0; |
4534 | virtual Verbosity verbosity() const = 0; |
4535 | |
4536 | virtual bool benchmarkNoAnalysis() const = 0; |
4537 | virtual int benchmarkSamples() const = 0; |
4538 | virtual double benchmarkConfidenceInterval() const = 0; |
4539 | virtual unsigned int benchmarkResamples() const = 0; |
4540 | virtual std::chrono::milliseconds benchmarkWarmupTime() const = 0; |
4541 | }; |
4542 | |
4543 | using IConfigPtr = std::shared_ptr<IConfig const>; |
4544 | } |
4545 | |
4546 | // end catch_interfaces_config.h |
4547 | // start catch_random_number_generator.h |
4548 | |
4549 | #include <cstdint> |
4550 | |
4551 | namespace Catch { |
4552 | |
4553 | // This is a simple implementation of C++11 Uniform Random Number |
4554 | // Generator. It does not provide all operators, because Catch2 |
4555 | // does not use it, but it should behave as expected inside stdlib's |
4556 | // distributions. |
4557 | // The implementation is based on the PCG family (http://pcg-random.org) |
4558 | class SimplePcg32 { |
4559 | using state_type = std::uint64_t; |
4560 | public: |
4561 | using result_type = std::uint32_t; |
4562 | static constexpr result_type (min)() { |
4563 | return 0; |
4564 | } |
4565 | static constexpr result_type (max)() { |
4566 | return static_cast<result_type>(-1); |
4567 | } |
4568 | |
4569 | // Provide some default initial state for the default constructor |
4570 | SimplePcg32():SimplePcg32(0xed743cc4U) {} |
4571 | |
4572 | explicit SimplePcg32(result_type seed_); |
4573 | |
4574 | void seed(result_type seed_); |
4575 | void discard(uint64_t skip); |
4576 | |
4577 | result_type operator()(); |
4578 | |
4579 | private: |
4580 | friend bool operator==(SimplePcg32 const& lhs, SimplePcg32 const& rhs); |
4581 | friend bool operator!=(SimplePcg32 const& lhs, SimplePcg32 const& rhs); |
4582 | |
4583 | // In theory we also need operator<< and operator>> |
4584 | // In practice we do not use them, so we will skip them for now |
4585 | |
4586 | std::uint64_t m_state; |
4587 | // This part of the state determines which "stream" of the numbers |
4588 | // is chosen -- we take it as a constant for Catch2, so we only |
4589 | // need to deal with seeding the main state. |
4590 | // Picked by reading 8 bytes from `/dev/random` :-) |
4591 | static const std::uint64_t s_inc = (0x13ed0cc53f939476ULL << 1ULL) | 1ULL; |
4592 | }; |
4593 | |
4594 | } // end namespace Catch |
4595 | |
4596 | // end catch_random_number_generator.h |
4597 | #include <random> |
4598 | |
4599 | namespace Catch { |
4600 | namespace Generators { |
4601 | |
4602 | template <typename Float> |
4603 | class RandomFloatingGenerator final : public IGenerator<Float> { |
4604 | Catch::SimplePcg32& m_rng; |
4605 | std::uniform_real_distribution<Float> m_dist; |
4606 | Float m_current_number; |
4607 | public: |
4608 | |
4609 | RandomFloatingGenerator(Float a, Float b): |
4610 | m_rng(rng()), |
4611 | m_dist(a, b) { |
4612 | static_cast<void>(next()); |
4613 | } |
4614 | |
4615 | Float const& get() const override { |
4616 | return m_current_number; |
4617 | } |
4618 | bool next() override { |
4619 | m_current_number = m_dist(m_rng); |
4620 | return true; |
4621 | } |
4622 | }; |
4623 | |
4624 | template <typename Integer> |
4625 | class RandomIntegerGenerator final : public IGenerator<Integer> { |
4626 | Catch::SimplePcg32& m_rng; |
4627 | std::uniform_int_distribution<Integer> m_dist; |
4628 | Integer m_current_number; |
4629 | public: |
4630 | |
4631 | RandomIntegerGenerator(Integer a, Integer b): |
4632 | m_rng(rng()), |
4633 | m_dist(a, b) { |
4634 | static_cast<void>(next()); |
4635 | } |
4636 | |
4637 | Integer const& get() const override { |
4638 | return m_current_number; |
4639 | } |
4640 | bool next() override { |
4641 | m_current_number = m_dist(m_rng); |
4642 | return true; |
4643 | } |
4644 | }; |
4645 | |
4646 | // TODO: Ideally this would be also constrained against the various char types, |
4647 | // but I don't expect users to run into that in practice. |
4648 | template <typename T> |
4649 | typename std::enable_if<std::is_integral<T>::value && !std::is_same<T, bool>::value, |
4650 | GeneratorWrapper<T>>::type |
4651 | random(T a, T b) { |
4652 | return GeneratorWrapper<T>( |
4653 | pf::make_unique<RandomIntegerGenerator<T>>(a, b) |
4654 | ); |
4655 | } |
4656 | |
4657 | template <typename T> |
4658 | typename std::enable_if<std::is_floating_point<T>::value, |
4659 | GeneratorWrapper<T>>::type |
4660 | random(T a, T b) { |
4661 | return GeneratorWrapper<T>( |
4662 | pf::make_unique<RandomFloatingGenerator<T>>(a, b) |
4663 | ); |
4664 | } |
4665 | |
4666 | template <typename T> |
4667 | class RangeGenerator final : public IGenerator<T> { |
4668 | T m_current; |
4669 | T m_end; |
4670 | T m_step; |
4671 | bool m_positive; |
4672 | |
4673 | public: |
4674 | RangeGenerator(T const& start, T const& end, T const& step): |
4675 | m_current(start), |
4676 | m_end(end), |
4677 | m_step(step), |
4678 | m_positive(m_step > T(0)) |
4679 | { |
4680 | assert(m_current != m_end && "Range start and end cannot be equal" ); |
4681 | assert(m_step != T(0) && "Step size cannot be zero" ); |
4682 | assert(((m_positive && m_current <= m_end) || (!m_positive && m_current >= m_end)) && "Step moves away from end" ); |
4683 | } |
4684 | |
4685 | RangeGenerator(T const& start, T const& end): |
4686 | RangeGenerator(start, end, (start < end) ? T(1) : T(-1)) |
4687 | {} |
4688 | |
4689 | T const& get() const override { |
4690 | return m_current; |
4691 | } |
4692 | |
4693 | bool next() override { |
4694 | m_current += m_step; |
4695 | return (m_positive) ? (m_current < m_end) : (m_current > m_end); |
4696 | } |
4697 | }; |
4698 | |
4699 | template <typename T> |
4700 | GeneratorWrapper<T> range(T const& start, T const& end, T const& step) { |
4701 | static_assert(std::is_arithmetic<T>::value && !std::is_same<T, bool>::value, "Type must be numeric" ); |
4702 | return GeneratorWrapper<T>(pf::make_unique<RangeGenerator<T>>(start, end, step)); |
4703 | } |
4704 | |
4705 | template <typename T> |
4706 | GeneratorWrapper<T> range(T const& start, T const& end) { |
4707 | static_assert(std::is_integral<T>::value && !std::is_same<T, bool>::value, "Type must be an integer" ); |
4708 | return GeneratorWrapper<T>(pf::make_unique<RangeGenerator<T>>(start, end)); |
4709 | } |
4710 | |
4711 | template <typename T> |
4712 | class IteratorGenerator final : public IGenerator<T> { |
4713 | static_assert(!std::is_same<T, bool>::value, |
4714 | "IteratorGenerator currently does not support bools" |
4715 | "because of std::vector<bool> specialization" ); |
4716 | |
4717 | std::vector<T> m_elems; |
4718 | size_t m_current = 0; |
4719 | public: |
4720 | template <typename InputIterator, typename InputSentinel> |
4721 | IteratorGenerator(InputIterator first, InputSentinel last):m_elems(first, last) { |
4722 | if (m_elems.empty()) { |
4723 | Catch::throw_exception(GeneratorException("IteratorGenerator received no valid values" )); |
4724 | } |
4725 | } |
4726 | |
4727 | T const& get() const override { |
4728 | return m_elems[m_current]; |
4729 | } |
4730 | |
4731 | bool next() override { |
4732 | ++m_current; |
4733 | return m_current != m_elems.size(); |
4734 | } |
4735 | }; |
4736 | |
4737 | template <typename InputIterator, |
4738 | typename InputSentinel, |
4739 | typename ResultType = typename std::iterator_traits<InputIterator>::value_type> |
4740 | GeneratorWrapper<ResultType> from_range(InputIterator from, InputSentinel to) { |
4741 | return GeneratorWrapper<ResultType>(pf::make_unique<IteratorGenerator<ResultType>>(from, to)); |
4742 | } |
4743 | |
4744 | template <typename Container, |
4745 | typename ResultType = typename Container::value_type> |
4746 | GeneratorWrapper<ResultType> from_range(Container const& cnt) { |
4747 | return GeneratorWrapper<ResultType>(pf::make_unique<IteratorGenerator<ResultType>>(cnt.begin(), cnt.end())); |
4748 | } |
4749 | |
4750 | } // namespace Generators |
4751 | } // namespace Catch |
4752 | |
4753 | // end catch_generators_specific.hpp |
4754 | |
4755 | // These files are included here so the single_include script doesn't put them |
4756 | // in the conditionally compiled sections |
4757 | // start catch_test_case_info.h |
4758 | |
4759 | #include <string> |
4760 | #include <vector> |
4761 | #include <memory> |
4762 | |
4763 | #ifdef __clang__ |
4764 | #pragma clang diagnostic push |
4765 | #pragma clang diagnostic ignored "-Wpadded" |
4766 | #endif |
4767 | |
4768 | namespace Catch { |
4769 | |
4770 | struct ITestInvoker; |
4771 | |
4772 | struct TestCaseInfo { |
4773 | enum SpecialProperties{ |
4774 | None = 0, |
4775 | IsHidden = 1 << 1, |
4776 | ShouldFail = 1 << 2, |
4777 | MayFail = 1 << 3, |
4778 | Throws = 1 << 4, |
4779 | NonPortable = 1 << 5, |
4780 | Benchmark = 1 << 6 |
4781 | }; |
4782 | |
4783 | TestCaseInfo( std::string const& _name, |
4784 | std::string const& _className, |
4785 | std::string const& _description, |
4786 | std::vector<std::string> const& _tags, |
4787 | SourceLineInfo const& _lineInfo ); |
4788 | |
4789 | friend void setTags( TestCaseInfo& testCaseInfo, std::vector<std::string> tags ); |
4790 | |
4791 | bool isHidden() const; |
4792 | bool throws() const; |
4793 | bool okToFail() const; |
4794 | bool expectedToFail() const; |
4795 | |
4796 | std::string tagsAsString() const; |
4797 | |
4798 | std::string name; |
4799 | std::string className; |
4800 | std::string description; |
4801 | std::vector<std::string> tags; |
4802 | std::vector<std::string> lcaseTags; |
4803 | SourceLineInfo lineInfo; |
4804 | SpecialProperties properties; |
4805 | }; |
4806 | |
4807 | class TestCase : public TestCaseInfo { |
4808 | public: |
4809 | |
4810 | TestCase( ITestInvoker* testCase, TestCaseInfo&& info ); |
4811 | |
4812 | TestCase withName( std::string const& _newName ) const; |
4813 | |
4814 | void invoke() const; |
4815 | |
4816 | TestCaseInfo const& getTestCaseInfo() const; |
4817 | |
4818 | bool operator == ( TestCase const& other ) const; |
4819 | bool operator < ( TestCase const& other ) const; |
4820 | |
4821 | private: |
4822 | std::shared_ptr<ITestInvoker> test; |
4823 | }; |
4824 | |
4825 | TestCase makeTestCase( ITestInvoker* testCase, |
4826 | std::string const& className, |
4827 | NameAndTags const& nameAndTags, |
4828 | SourceLineInfo const& lineInfo ); |
4829 | } |
4830 | |
4831 | #ifdef __clang__ |
4832 | #pragma clang diagnostic pop |
4833 | #endif |
4834 | |
4835 | // end catch_test_case_info.h |
4836 | // start catch_interfaces_runner.h |
4837 | |
4838 | namespace Catch { |
4839 | |
4840 | struct IRunner { |
4841 | virtual ~IRunner(); |
4842 | virtual bool aborting() const = 0; |
4843 | }; |
4844 | } |
4845 | |
4846 | // end catch_interfaces_runner.h |
4847 | |
4848 | #ifdef __OBJC__ |
4849 | // start catch_objc.hpp |
4850 | |
4851 | #import <objc/runtime.h> |
4852 | |
4853 | #include <string> |
4854 | |
4855 | // NB. Any general catch headers included here must be included |
4856 | // in catch.hpp first to make sure they are included by the single |
4857 | // header for non obj-usage |
4858 | |
4859 | /////////////////////////////////////////////////////////////////////////////// |
4860 | // This protocol is really only here for (self) documenting purposes, since |
4861 | // all its methods are optional. |
4862 | @protocol OcFixture |
4863 | |
4864 | @optional |
4865 | |
4866 | -(void) setUp; |
4867 | -(void) tearDown; |
4868 | |
4869 | @end |
4870 | |
4871 | namespace Catch { |
4872 | |
4873 | class OcMethod : public ITestInvoker { |
4874 | |
4875 | public: |
4876 | OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {} |
4877 | |
4878 | virtual void invoke() const { |
4879 | id obj = [[m_cls alloc] init]; |
4880 | |
4881 | performOptionalSelector( obj, @selector(setUp) ); |
4882 | performOptionalSelector( obj, m_sel ); |
4883 | performOptionalSelector( obj, @selector(tearDown) ); |
4884 | |
4885 | arcSafeRelease( obj ); |
4886 | } |
4887 | private: |
4888 | virtual ~OcMethod() {} |
4889 | |
4890 | Class m_cls; |
4891 | SEL m_sel; |
4892 | }; |
4893 | |
4894 | namespace Detail{ |
4895 | |
4896 | inline std::string getAnnotation( Class cls, |
4897 | std::string const& annotationName, |
4898 | std::string const& testCaseName ) { |
4899 | NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s" , annotationName.c_str(), testCaseName.c_str()]; |
4900 | SEL sel = NSSelectorFromString( selStr ); |
4901 | arcSafeRelease( selStr ); |
4902 | id value = performOptionalSelector( cls, sel ); |
4903 | if( value ) |
4904 | return [(NSString*)value UTF8String]; |
4905 | return "" ; |
4906 | } |
4907 | } |
4908 | |
4909 | inline std::size_t registerTestMethods() { |
4910 | std::size_t noTestMethods = 0; |
4911 | int noClasses = objc_getClassList( nullptr, 0 ); |
4912 | |
4913 | Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); |
4914 | objc_getClassList( classes, noClasses ); |
4915 | |
4916 | for( int c = 0; c < noClasses; c++ ) { |
4917 | Class cls = classes[c]; |
4918 | { |
4919 | u_int count; |
4920 | Method* methods = class_copyMethodList( cls, &count ); |
4921 | for( u_int m = 0; m < count ; m++ ) { |
4922 | SEL selector = method_getName(methods[m]); |
4923 | std::string methodName = sel_getName(selector); |
4924 | if( startsWith( methodName, "Catch_TestCase_" ) ) { |
4925 | std::string testCaseName = methodName.substr( 15 ); |
4926 | std::string name = Detail::getAnnotation( cls, "Name" , testCaseName ); |
4927 | std::string desc = Detail::getAnnotation( cls, "Description" , testCaseName ); |
4928 | const char* className = class_getName( cls ); |
4929 | |
4930 | getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, NameAndTags( name.c_str(), desc.c_str() ), SourceLineInfo("" ,0) ) ); |
4931 | noTestMethods++; |
4932 | } |
4933 | } |
4934 | free(methods); |
4935 | } |
4936 | } |
4937 | return noTestMethods; |
4938 | } |
4939 | |
4940 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) |
4941 | |
4942 | namespace Matchers { |
4943 | namespace Impl { |
4944 | namespace NSStringMatchers { |
4945 | |
4946 | struct StringHolder : MatcherBase<NSString*>{ |
4947 | StringHolder( NSString* substr ) : m_substr( [substr copy] ){} |
4948 | StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){} |
4949 | StringHolder() { |
4950 | arcSafeRelease( m_substr ); |
4951 | } |
4952 | |
4953 | bool match( NSString* str ) const override { |
4954 | return false; |
4955 | } |
4956 | |
4957 | NSString* CATCH_ARC_STRONG m_substr; |
4958 | }; |
4959 | |
4960 | struct Equals : StringHolder { |
4961 | Equals( NSString* substr ) : StringHolder( substr ){} |
4962 | |
4963 | bool match( NSString* str ) const override { |
4964 | return (str != nil || m_substr == nil ) && |
4965 | [str isEqualToString:m_substr]; |
4966 | } |
4967 | |
4968 | std::string describe() const override { |
4969 | return "equals string: " + Catch::Detail::stringify( m_substr ); |
4970 | } |
4971 | }; |
4972 | |
4973 | struct Contains : StringHolder { |
4974 | Contains( NSString* substr ) : StringHolder( substr ){} |
4975 | |
4976 | bool match( NSString* str ) const override { |
4977 | return (str != nil || m_substr == nil ) && |
4978 | [str rangeOfString:m_substr].location != NSNotFound; |
4979 | } |
4980 | |
4981 | std::string describe() const override { |
4982 | return "contains string: " + Catch::Detail::stringify( m_substr ); |
4983 | } |
4984 | }; |
4985 | |
4986 | struct StartsWith : StringHolder { |
4987 | StartsWith( NSString* substr ) : StringHolder( substr ){} |
4988 | |
4989 | bool match( NSString* str ) const override { |
4990 | return (str != nil || m_substr == nil ) && |
4991 | [str rangeOfString:m_substr].location == 0; |
4992 | } |
4993 | |
4994 | std::string describe() const override { |
4995 | return "starts with: " + Catch::Detail::stringify( m_substr ); |
4996 | } |
4997 | }; |
4998 | struct EndsWith : StringHolder { |
4999 | EndsWith( NSString* substr ) : StringHolder( substr ){} |
5000 | |
5001 | bool match( NSString* str ) const override { |
5002 | return (str != nil || m_substr == nil ) && |
5003 | [str rangeOfString:m_substr].location == [str length] - [m_substr length]; |
5004 | } |
5005 | |
5006 | std::string describe() const override { |
5007 | return "ends with: " + Catch::Detail::stringify( m_substr ); |
5008 | } |
5009 | }; |
5010 | |
5011 | } // namespace NSStringMatchers |
5012 | } // namespace Impl |
5013 | |
5014 | inline Impl::NSStringMatchers::Equals |
5015 | Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); } |
5016 | |
5017 | inline Impl::NSStringMatchers::Contains |
5018 | Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); } |
5019 | |
5020 | inline Impl::NSStringMatchers::StartsWith |
5021 | StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); } |
5022 | |
5023 | inline Impl::NSStringMatchers::EndsWith |
5024 | EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); } |
5025 | |
5026 | } // namespace Matchers |
5027 | |
5028 | using namespace Matchers; |
5029 | |
5030 | #endif // CATCH_CONFIG_DISABLE_MATCHERS |
5031 | |
5032 | } // namespace Catch |
5033 | |
5034 | /////////////////////////////////////////////////////////////////////////////// |
5035 | #define OC_MAKE_UNIQUE_NAME( root, uniqueSuffix ) root##uniqueSuffix |
5036 | #define OC_TEST_CASE2( name, desc, uniqueSuffix ) \ |
5037 | +(NSString*) OC_MAKE_UNIQUE_NAME( Catch_Name_test_, uniqueSuffix ) \ |
5038 | { \ |
5039 | return @ name; \ |
5040 | } \ |
5041 | +(NSString*) OC_MAKE_UNIQUE_NAME( Catch_Description_test_, uniqueSuffix ) \ |
5042 | { \ |
5043 | return @ desc; \ |
5044 | } \ |
5045 | -(void) OC_MAKE_UNIQUE_NAME( Catch_TestCase_test_, uniqueSuffix ) |
5046 | |
5047 | #define OC_TEST_CASE( name, desc ) OC_TEST_CASE2( name, desc, __LINE__ ) |
5048 | |
5049 | // end catch_objc.hpp |
5050 | #endif |
5051 | |
5052 | // Benchmarking needs the externally-facing parts of reporters to work |
5053 | #if defined(CATCH_CONFIG_EXTERNAL_INTERFACES) || defined(CATCH_CONFIG_ENABLE_BENCHMARKING) |
5054 | // start catch_external_interfaces.h |
5055 | |
5056 | // start catch_reporter_bases.hpp |
5057 | |
5058 | // start catch_interfaces_reporter.h |
5059 | |
5060 | // start catch_config.hpp |
5061 | |
5062 | // start catch_test_spec_parser.h |
5063 | |
5064 | #ifdef __clang__ |
5065 | #pragma clang diagnostic push |
5066 | #pragma clang diagnostic ignored "-Wpadded" |
5067 | #endif |
5068 | |
5069 | // start catch_test_spec.h |
5070 | |
5071 | #ifdef __clang__ |
5072 | #pragma clang diagnostic push |
5073 | #pragma clang diagnostic ignored "-Wpadded" |
5074 | #endif |
5075 | |
5076 | // start catch_wildcard_pattern.h |
5077 | |
5078 | namespace Catch |
5079 | { |
5080 | class WildcardPattern { |
5081 | enum WildcardPosition { |
5082 | NoWildcard = 0, |
5083 | WildcardAtStart = 1, |
5084 | WildcardAtEnd = 2, |
5085 | WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd |
5086 | }; |
5087 | |
5088 | public: |
5089 | |
5090 | WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity ); |
5091 | virtual ~WildcardPattern() = default; |
5092 | virtual bool matches( std::string const& str ) const; |
5093 | |
5094 | private: |
5095 | std::string normaliseString( std::string const& str ) const; |
5096 | CaseSensitive::Choice m_caseSensitivity; |
5097 | WildcardPosition m_wildcard = NoWildcard; |
5098 | std::string m_pattern; |
5099 | }; |
5100 | } |
5101 | |
5102 | // end catch_wildcard_pattern.h |
5103 | #include <string> |
5104 | #include <vector> |
5105 | #include <memory> |
5106 | |
5107 | namespace Catch { |
5108 | |
5109 | struct IConfig; |
5110 | |
5111 | class TestSpec { |
5112 | class Pattern { |
5113 | public: |
5114 | explicit Pattern( std::string const& name ); |
5115 | virtual ~Pattern(); |
5116 | virtual bool matches( TestCaseInfo const& testCase ) const = 0; |
5117 | std::string const& name() const; |
5118 | private: |
5119 | std::string const m_name; |
5120 | }; |
5121 | using PatternPtr = std::shared_ptr<Pattern>; |
5122 | |
5123 | class NamePattern : public Pattern { |
5124 | public: |
5125 | explicit NamePattern( std::string const& name, std::string const& filterString ); |
5126 | bool matches( TestCaseInfo const& testCase ) const override; |
5127 | private: |
5128 | WildcardPattern m_wildcardPattern; |
5129 | }; |
5130 | |
5131 | class TagPattern : public Pattern { |
5132 | public: |
5133 | explicit TagPattern( std::string const& tag, std::string const& filterString ); |
5134 | bool matches( TestCaseInfo const& testCase ) const override; |
5135 | private: |
5136 | std::string m_tag; |
5137 | }; |
5138 | |
5139 | class ExcludedPattern : public Pattern { |
5140 | public: |
5141 | explicit ExcludedPattern( PatternPtr const& underlyingPattern ); |
5142 | bool matches( TestCaseInfo const& testCase ) const override; |
5143 | private: |
5144 | PatternPtr m_underlyingPattern; |
5145 | }; |
5146 | |
5147 | struct Filter { |
5148 | std::vector<PatternPtr> m_patterns; |
5149 | |
5150 | bool matches( TestCaseInfo const& testCase ) const; |
5151 | std::string name() const; |
5152 | }; |
5153 | |
5154 | public: |
5155 | struct FilterMatch { |
5156 | std::string name; |
5157 | std::vector<TestCase const*> tests; |
5158 | }; |
5159 | using Matches = std::vector<FilterMatch>; |
5160 | using vectorStrings = std::vector<std::string>; |
5161 | |
5162 | bool hasFilters() const; |
5163 | bool matches( TestCaseInfo const& testCase ) const; |
5164 | Matches matchesByFilter( std::vector<TestCase> const& testCases, IConfig const& config ) const; |
5165 | const vectorStrings & getInvalidArgs() const; |
5166 | |
5167 | private: |
5168 | std::vector<Filter> m_filters; |
5169 | std::vector<std::string> m_invalidArgs; |
5170 | friend class TestSpecParser; |
5171 | }; |
5172 | } |
5173 | |
5174 | #ifdef __clang__ |
5175 | #pragma clang diagnostic pop |
5176 | #endif |
5177 | |
5178 | // end catch_test_spec.h |
5179 | // start catch_interfaces_tag_alias_registry.h |
5180 | |
5181 | #include <string> |
5182 | |
5183 | namespace Catch { |
5184 | |
5185 | struct TagAlias; |
5186 | |
5187 | struct ITagAliasRegistry { |
5188 | virtual ~ITagAliasRegistry(); |
5189 | // Nullptr if not present |
5190 | virtual TagAlias const* find( std::string const& alias ) const = 0; |
5191 | virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0; |
5192 | |
5193 | static ITagAliasRegistry const& get(); |
5194 | }; |
5195 | |
5196 | } // end namespace Catch |
5197 | |
5198 | // end catch_interfaces_tag_alias_registry.h |
5199 | namespace Catch { |
5200 | |
5201 | class TestSpecParser { |
5202 | enum Mode{ None, Name, QuotedName, Tag, EscapedName }; |
5203 | Mode m_mode = None; |
5204 | Mode lastMode = None; |
5205 | bool m_exclusion = false; |
5206 | std::size_t m_pos = 0; |
5207 | std::size_t m_realPatternPos = 0; |
5208 | std::string m_arg; |
5209 | std::string m_substring; |
5210 | std::string m_patternName; |
5211 | std::vector<std::size_t> m_escapeChars; |
5212 | TestSpec::Filter m_currentFilter; |
5213 | TestSpec m_testSpec; |
5214 | ITagAliasRegistry const* m_tagAliases = nullptr; |
5215 | |
5216 | public: |
5217 | TestSpecParser( ITagAliasRegistry const& tagAliases ); |
5218 | |
5219 | TestSpecParser& parse( std::string const& arg ); |
5220 | TestSpec testSpec(); |
5221 | |
5222 | private: |
5223 | bool visitChar( char c ); |
5224 | void startNewMode( Mode mode ); |
5225 | bool processNoneChar( char c ); |
5226 | void processNameChar( char c ); |
5227 | bool processOtherChar( char c ); |
5228 | void endMode(); |
5229 | void escape(); |
5230 | bool isControlChar( char c ) const; |
5231 | void saveLastMode(); |
5232 | void revertBackToLastMode(); |
5233 | void addFilter(); |
5234 | bool separate(); |
5235 | |
5236 | // Handles common preprocessing of the pattern for name/tag patterns |
5237 | std::string preprocessPattern(); |
5238 | // Adds the current pattern as a test name |
5239 | void addNamePattern(); |
5240 | // Adds the current pattern as a tag |
5241 | void addTagPattern(); |
5242 | |
5243 | inline void addCharToPattern(char c) { |
5244 | m_substring += c; |
5245 | m_patternName += c; |
5246 | m_realPatternPos++; |
5247 | } |
5248 | |
5249 | }; |
5250 | TestSpec parseTestSpec( std::string const& arg ); |
5251 | |
5252 | } // namespace Catch |
5253 | |
5254 | #ifdef __clang__ |
5255 | #pragma clang diagnostic pop |
5256 | #endif |
5257 | |
5258 | // end catch_test_spec_parser.h |
5259 | // Libstdc++ doesn't like incomplete classes for unique_ptr |
5260 | |
5261 | #include <memory> |
5262 | #include <vector> |
5263 | #include <string> |
5264 | |
5265 | #ifndef CATCH_CONFIG_CONSOLE_WIDTH |
5266 | #define CATCH_CONFIG_CONSOLE_WIDTH 80 |
5267 | #endif |
5268 | |
5269 | namespace Catch { |
5270 | |
5271 | struct IStream; |
5272 | |
5273 | struct ConfigData { |
5274 | bool listTests = false; |
5275 | bool listTags = false; |
5276 | bool listReporters = false; |
5277 | bool listTestNamesOnly = false; |
5278 | |
5279 | bool showSuccessfulTests = false; |
5280 | bool shouldDebugBreak = false; |
5281 | bool noThrow = false; |
5282 | bool showHelp = false; |
5283 | bool showInvisibles = false; |
5284 | bool filenamesAsTags = false; |
5285 | bool libIdentify = false; |
5286 | |
5287 | int abortAfter = -1; |
5288 | unsigned int rngSeed = 0; |
5289 | |
5290 | bool benchmarkNoAnalysis = false; |
5291 | unsigned int benchmarkSamples = 100; |
5292 | double benchmarkConfidenceInterval = 0.95; |
5293 | unsigned int benchmarkResamples = 100000; |
5294 | std::chrono::milliseconds::rep benchmarkWarmupTime = 100; |
5295 | |
5296 | Verbosity verbosity = Verbosity::Normal; |
5297 | WarnAbout::What warnings = WarnAbout::Nothing; |
5298 | ShowDurations::OrNot showDurations = ShowDurations::DefaultForReporter; |
5299 | double minDuration = -1; |
5300 | RunTests::InWhatOrder runOrder = RunTests::InDeclarationOrder; |
5301 | UseColour::YesOrNo useColour = UseColour::Auto; |
5302 | WaitForKeypress::When waitForKeypress = WaitForKeypress::Never; |
5303 | |
5304 | std::string outputFilename; |
5305 | std::string name; |
5306 | std::string processName; |
5307 | #ifndef CATCH_CONFIG_DEFAULT_REPORTER |
5308 | #define CATCH_CONFIG_DEFAULT_REPORTER "console" |
5309 | #endif |
5310 | std::string reporterName = CATCH_CONFIG_DEFAULT_REPORTER; |
5311 | #undef CATCH_CONFIG_DEFAULT_REPORTER |
5312 | |
5313 | std::vector<std::string> testsOrTags; |
5314 | std::vector<std::string> sectionsToRun; |
5315 | }; |
5316 | |
5317 | class Config : public IConfig { |
5318 | public: |
5319 | |
5320 | Config() = default; |
5321 | Config( ConfigData const& data ); |
5322 | virtual ~Config() = default; |
5323 | |
5324 | std::string const& getFilename() const; |
5325 | |
5326 | bool listTests() const; |
5327 | bool listTestNamesOnly() const; |
5328 | bool listTags() const; |
5329 | bool listReporters() const; |
5330 | |
5331 | std::string getProcessName() const; |
5332 | std::string const& getReporterName() const; |
5333 | |
5334 | std::vector<std::string> const& getTestsOrTags() const override; |
5335 | std::vector<std::string> const& getSectionsToRun() const override; |
5336 | |
5337 | TestSpec const& testSpec() const override; |
5338 | bool hasTestFilters() const override; |
5339 | |
5340 | bool showHelp() const; |
5341 | |
5342 | // IConfig interface |
5343 | bool allowThrows() const override; |
5344 | std::ostream& stream() const override; |
5345 | std::string name() const override; |
5346 | bool includeSuccessfulResults() const override; |
5347 | bool warnAboutMissingAssertions() const override; |
5348 | bool warnAboutNoTests() const override; |
5349 | ShowDurations::OrNot showDurations() const override; |
5350 | double minDuration() const override; |
5351 | RunTests::InWhatOrder runOrder() const override; |
5352 | unsigned int rngSeed() const override; |
5353 | UseColour::YesOrNo useColour() const override; |
5354 | bool shouldDebugBreak() const override; |
5355 | int abortAfter() const override; |
5356 | bool showInvisibles() const override; |
5357 | Verbosity verbosity() const override; |
5358 | bool benchmarkNoAnalysis() const override; |
5359 | int benchmarkSamples() const override; |
5360 | double benchmarkConfidenceInterval() const override; |
5361 | unsigned int benchmarkResamples() const override; |
5362 | std::chrono::milliseconds benchmarkWarmupTime() const override; |
5363 | |
5364 | private: |
5365 | |
5366 | IStream const* openStream(); |
5367 | ConfigData m_data; |
5368 | |
5369 | std::unique_ptr<IStream const> m_stream; |
5370 | TestSpec m_testSpec; |
5371 | bool m_hasTestFilters = false; |
5372 | }; |
5373 | |
5374 | } // end namespace Catch |
5375 | |
5376 | // end catch_config.hpp |
5377 | // start catch_assertionresult.h |
5378 | |
5379 | #include <string> |
5380 | |
5381 | namespace Catch { |
5382 | |
5383 | struct AssertionResultData |
5384 | { |
5385 | AssertionResultData() = delete; |
5386 | |
5387 | AssertionResultData( ResultWas::OfType _resultType, LazyExpression const& _lazyExpression ); |
5388 | |
5389 | std::string message; |
5390 | mutable std::string reconstructedExpression; |
5391 | LazyExpression lazyExpression; |
5392 | ResultWas::OfType resultType; |
5393 | |
5394 | std::string reconstructExpression() const; |
5395 | }; |
5396 | |
5397 | class AssertionResult { |
5398 | public: |
5399 | AssertionResult() = delete; |
5400 | AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); |
5401 | |
5402 | bool isOk() const; |
5403 | bool succeeded() const; |
5404 | ResultWas::OfType getResultType() const; |
5405 | bool hasExpression() const; |
5406 | bool hasMessage() const; |
5407 | std::string getExpression() const; |
5408 | std::string getExpressionInMacro() const; |
5409 | bool hasExpandedExpression() const; |
5410 | std::string getExpandedExpression() const; |
5411 | std::string getMessage() const; |
5412 | SourceLineInfo getSourceInfo() const; |
5413 | StringRef getTestMacroName() const; |
5414 | |
5415 | //protected: |
5416 | AssertionInfo m_info; |
5417 | AssertionResultData m_resultData; |
5418 | }; |
5419 | |
5420 | } // end namespace Catch |
5421 | |
5422 | // end catch_assertionresult.h |
5423 | #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) |
5424 | // start catch_estimate.hpp |
5425 | |
5426 | // Statistics estimates |
5427 | |
5428 | |
5429 | namespace Catch { |
5430 | namespace Benchmark { |
5431 | template <typename Duration> |
5432 | struct Estimate { |
5433 | Duration point; |
5434 | Duration lower_bound; |
5435 | Duration upper_bound; |
5436 | double confidence_interval; |
5437 | |
5438 | template <typename Duration2> |
5439 | operator Estimate<Duration2>() const { |
5440 | return { point, lower_bound, upper_bound, confidence_interval }; |
5441 | } |
5442 | }; |
5443 | } // namespace Benchmark |
5444 | } // namespace Catch |
5445 | |
5446 | // end catch_estimate.hpp |
5447 | // start catch_outlier_classification.hpp |
5448 | |
5449 | // Outlier information |
5450 | |
5451 | namespace Catch { |
5452 | namespace Benchmark { |
5453 | struct OutlierClassification { |
5454 | int samples_seen = 0; |
5455 | int low_severe = 0; // more than 3 times IQR below Q1 |
5456 | int low_mild = 0; // 1.5 to 3 times IQR below Q1 |
5457 | int high_mild = 0; // 1.5 to 3 times IQR above Q3 |
5458 | int high_severe = 0; // more than 3 times IQR above Q3 |
5459 | |
5460 | int total() const { |
5461 | return low_severe + low_mild + high_mild + high_severe; |
5462 | } |
5463 | }; |
5464 | } // namespace Benchmark |
5465 | } // namespace Catch |
5466 | |
5467 | // end catch_outlier_classification.hpp |
5468 | |
5469 | #include <iterator> |
5470 | #endif // CATCH_CONFIG_ENABLE_BENCHMARKING |
5471 | |
5472 | #include <string> |
5473 | #include <iosfwd> |
5474 | #include <map> |
5475 | #include <set> |
5476 | #include <memory> |
5477 | #include <algorithm> |
5478 | |
5479 | namespace Catch { |
5480 | |
5481 | struct ReporterConfig { |
5482 | explicit ReporterConfig( IConfigPtr const& _fullConfig ); |
5483 | |
5484 | ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream ); |
5485 | |
5486 | std::ostream& stream() const; |
5487 | IConfigPtr fullConfig() const; |
5488 | |
5489 | private: |
5490 | std::ostream* m_stream; |
5491 | IConfigPtr m_fullConfig; |
5492 | }; |
5493 | |
5494 | struct ReporterPreferences { |
5495 | bool shouldRedirectStdOut = false; |
5496 | bool shouldReportAllAssertions = false; |
5497 | }; |
5498 | |
5499 | template<typename T> |
5500 | struct LazyStat : Option<T> { |
5501 | LazyStat& operator=( T const& _value ) { |
5502 | Option<T>::operator=( _value ); |
5503 | used = false; |
5504 | return *this; |
5505 | } |
5506 | void reset() { |
5507 | Option<T>::reset(); |
5508 | used = false; |
5509 | } |
5510 | bool used = false; |
5511 | }; |
5512 | |
5513 | struct TestRunInfo { |
5514 | TestRunInfo( std::string const& _name ); |
5515 | std::string name; |
5516 | }; |
5517 | struct GroupInfo { |
5518 | GroupInfo( std::string const& _name, |
5519 | std::size_t _groupIndex, |
5520 | std::size_t _groupsCount ); |
5521 | |
5522 | std::string name; |
5523 | std::size_t groupIndex; |
5524 | std::size_t groupsCounts; |
5525 | }; |
5526 | |
5527 | struct AssertionStats { |
5528 | AssertionStats( AssertionResult const& _assertionResult, |
5529 | std::vector<MessageInfo> const& _infoMessages, |
5530 | Totals const& _totals ); |
5531 | |
5532 | AssertionStats( AssertionStats const& ) = default; |
5533 | AssertionStats( AssertionStats && ) = default; |
5534 | AssertionStats& operator = ( AssertionStats const& ) = delete; |
5535 | AssertionStats& operator = ( AssertionStats && ) = delete; |
5536 | virtual ~AssertionStats(); |
5537 | |
5538 | AssertionResult assertionResult; |
5539 | std::vector<MessageInfo> infoMessages; |
5540 | Totals totals; |
5541 | }; |
5542 | |
5543 | struct SectionStats { |
5544 | SectionStats( SectionInfo const& _sectionInfo, |
5545 | Counts const& _assertions, |
5546 | double _durationInSeconds, |
5547 | bool _missingAssertions ); |
5548 | SectionStats( SectionStats const& ) = default; |
5549 | SectionStats( SectionStats && ) = default; |
5550 | SectionStats& operator = ( SectionStats const& ) = default; |
5551 | SectionStats& operator = ( SectionStats && ) = default; |
5552 | virtual ~SectionStats(); |
5553 | |
5554 | SectionInfo sectionInfo; |
5555 | Counts assertions; |
5556 | double durationInSeconds; |
5557 | bool missingAssertions; |
5558 | }; |
5559 | |
5560 | struct TestCaseStats { |
5561 | TestCaseStats( TestCaseInfo const& _testInfo, |
5562 | Totals const& _totals, |
5563 | std::string const& _stdOut, |
5564 | std::string const& _stdErr, |
5565 | bool _aborting ); |
5566 | |
5567 | TestCaseStats( TestCaseStats const& ) = default; |
5568 | TestCaseStats( TestCaseStats && ) = default; |
5569 | TestCaseStats& operator = ( TestCaseStats const& ) = default; |
5570 | TestCaseStats& operator = ( TestCaseStats && ) = default; |
5571 | virtual ~TestCaseStats(); |
5572 | |
5573 | TestCaseInfo testInfo; |
5574 | Totals totals; |
5575 | std::string stdOut; |
5576 | std::string stdErr; |
5577 | bool aborting; |
5578 | }; |
5579 | |
5580 | struct TestGroupStats { |
5581 | TestGroupStats( GroupInfo const& _groupInfo, |
5582 | Totals const& _totals, |
5583 | bool _aborting ); |
5584 | TestGroupStats( GroupInfo const& _groupInfo ); |
5585 | |
5586 | TestGroupStats( TestGroupStats const& ) = default; |
5587 | TestGroupStats( TestGroupStats && ) = default; |
5588 | TestGroupStats& operator = ( TestGroupStats const& ) = default; |
5589 | TestGroupStats& operator = ( TestGroupStats && ) = default; |
5590 | virtual ~TestGroupStats(); |
5591 | |
5592 | GroupInfo groupInfo; |
5593 | Totals totals; |
5594 | bool aborting; |
5595 | }; |
5596 | |
5597 | struct TestRunStats { |
5598 | TestRunStats( TestRunInfo const& _runInfo, |
5599 | Totals const& _totals, |
5600 | bool _aborting ); |
5601 | |
5602 | TestRunStats( TestRunStats const& ) = default; |
5603 | TestRunStats( TestRunStats && ) = default; |
5604 | TestRunStats& operator = ( TestRunStats const& ) = default; |
5605 | TestRunStats& operator = ( TestRunStats && ) = default; |
5606 | virtual ~TestRunStats(); |
5607 | |
5608 | TestRunInfo runInfo; |
5609 | Totals totals; |
5610 | bool aborting; |
5611 | }; |
5612 | |
5613 | #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) |
5614 | struct BenchmarkInfo { |
5615 | std::string name; |
5616 | double estimatedDuration; |
5617 | int iterations; |
5618 | int samples; |
5619 | unsigned int resamples; |
5620 | double clockResolution; |
5621 | double clockCost; |
5622 | }; |
5623 | |
5624 | template <class Duration> |
5625 | struct BenchmarkStats { |
5626 | BenchmarkInfo info; |
5627 | |
5628 | std::vector<Duration> samples; |
5629 | Benchmark::Estimate<Duration> mean; |
5630 | Benchmark::Estimate<Duration> standardDeviation; |
5631 | Benchmark::OutlierClassification outliers; |
5632 | double outlierVariance; |
5633 | |
5634 | template <typename Duration2> |
5635 | operator BenchmarkStats<Duration2>() const { |
5636 | std::vector<Duration2> samples2; |
5637 | samples2.reserve(samples.size()); |
5638 | std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](Duration d) { return Duration2(d); }); |
5639 | return { |
5640 | info, |
5641 | std::move(samples2), |
5642 | mean, |
5643 | standardDeviation, |
5644 | outliers, |
5645 | outlierVariance, |
5646 | }; |
5647 | } |
5648 | }; |
5649 | #endif // CATCH_CONFIG_ENABLE_BENCHMARKING |
5650 | |
5651 | struct IStreamingReporter { |
5652 | virtual ~IStreamingReporter() = default; |
5653 | |
5654 | // Implementing class must also provide the following static methods: |
5655 | // static std::string getDescription(); |
5656 | // static std::set<Verbosity> getSupportedVerbosities() |
5657 | |
5658 | virtual ReporterPreferences getPreferences() const = 0; |
5659 | |
5660 | virtual void noMatchingTestCases( std::string const& spec ) = 0; |
5661 | |
5662 | virtual void reportInvalidArguments(std::string const&) {} |
5663 | |
5664 | virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; |
5665 | virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0; |
5666 | |
5667 | virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; |
5668 | virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; |
5669 | |
5670 | #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) |
5671 | virtual void benchmarkPreparing( std::string const& ) {} |
5672 | virtual void benchmarkStarting( BenchmarkInfo const& ) {} |
5673 | virtual void benchmarkEnded( BenchmarkStats<> const& ) {} |
5674 | virtual void benchmarkFailed( std::string const& ) {} |
5675 | #endif // CATCH_CONFIG_ENABLE_BENCHMARKING |
5676 | |
5677 | virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; |
5678 | |
5679 | // The return value indicates if the messages buffer should be cleared: |
5680 | virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; |
5681 | |
5682 | virtual void sectionEnded( SectionStats const& sectionStats ) = 0; |
5683 | virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; |
5684 | virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; |
5685 | virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; |
5686 | |
5687 | virtual void skipTest( TestCaseInfo const& testInfo ) = 0; |
5688 | |
5689 | // Default empty implementation provided |
5690 | virtual void fatalErrorEncountered( StringRef name ); |
5691 | |
5692 | virtual bool isMulti() const; |
5693 | }; |
5694 | using IStreamingReporterPtr = std::unique_ptr<IStreamingReporter>; |
5695 | |
5696 | struct IReporterFactory { |
5697 | virtual ~IReporterFactory(); |
5698 | virtual IStreamingReporterPtr create( ReporterConfig const& config ) const = 0; |
5699 | virtual std::string getDescription() const = 0; |
5700 | }; |
5701 | using IReporterFactoryPtr = std::shared_ptr<IReporterFactory>; |
5702 | |
5703 | struct IReporterRegistry { |
5704 | using FactoryMap = std::map<std::string, IReporterFactoryPtr>; |
5705 | using Listeners = std::vector<IReporterFactoryPtr>; |
5706 | |
5707 | virtual ~IReporterRegistry(); |
5708 | virtual IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const = 0; |
5709 | virtual FactoryMap const& getFactories() const = 0; |
5710 | virtual Listeners const& getListeners() const = 0; |
5711 | }; |
5712 | |
5713 | } // end namespace Catch |
5714 | |
5715 | // end catch_interfaces_reporter.h |
5716 | #include <algorithm> |
5717 | #include <cstring> |
5718 | #include <cfloat> |
5719 | #include <cstdio> |
5720 | #include <cassert> |
5721 | #include <memory> |
5722 | #include <ostream> |
5723 | |
5724 | namespace Catch { |
5725 | void prepareExpandedExpression(AssertionResult& result); |
5726 | |
5727 | // Returns double formatted as %.3f (format expected on output) |
5728 | std::string getFormattedDuration( double duration ); |
5729 | |
5730 | //! Should the reporter show |
5731 | bool shouldShowDuration( IConfig const& config, double duration ); |
5732 | |
5733 | std::string serializeFilters( std::vector<std::string> const& container ); |
5734 | |
5735 | template<typename DerivedT> |
5736 | struct StreamingReporterBase : IStreamingReporter { |
5737 | |
5738 | StreamingReporterBase( ReporterConfig const& _config ) |
5739 | : m_config( _config.fullConfig() ), |
5740 | stream( _config.stream() ) |
5741 | { |
5742 | m_reporterPrefs.shouldRedirectStdOut = false; |
5743 | if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) ) |
5744 | CATCH_ERROR( "Verbosity level not supported by this reporter" ); |
5745 | } |
5746 | |
5747 | ReporterPreferences getPreferences() const override { |
5748 | return m_reporterPrefs; |
5749 | } |
5750 | |
5751 | static std::set<Verbosity> getSupportedVerbosities() { |
5752 | return { Verbosity::Normal }; |
5753 | } |
5754 | |
5755 | ~StreamingReporterBase() override = default; |
5756 | |
5757 | void noMatchingTestCases(std::string const&) override {} |
5758 | |
5759 | void reportInvalidArguments(std::string const&) override {} |
5760 | |
5761 | void testRunStarting(TestRunInfo const& _testRunInfo) override { |
5762 | currentTestRunInfo = _testRunInfo; |
5763 | } |
5764 | |
5765 | void testGroupStarting(GroupInfo const& _groupInfo) override { |
5766 | currentGroupInfo = _groupInfo; |
5767 | } |
5768 | |
5769 | void testCaseStarting(TestCaseInfo const& _testInfo) override { |
5770 | currentTestCaseInfo = _testInfo; |
5771 | } |
5772 | void sectionStarting(SectionInfo const& _sectionInfo) override { |
5773 | m_sectionStack.push_back(_sectionInfo); |
5774 | } |
5775 | |
5776 | void sectionEnded(SectionStats const& /* _sectionStats */) override { |
5777 | m_sectionStack.pop_back(); |
5778 | } |
5779 | void testCaseEnded(TestCaseStats const& /* _testCaseStats */) override { |
5780 | currentTestCaseInfo.reset(); |
5781 | } |
5782 | void testGroupEnded(TestGroupStats const& /* _testGroupStats */) override { |
5783 | currentGroupInfo.reset(); |
5784 | } |
5785 | void testRunEnded(TestRunStats const& /* _testRunStats */) override { |
5786 | currentTestCaseInfo.reset(); |
5787 | currentGroupInfo.reset(); |
5788 | currentTestRunInfo.reset(); |
5789 | } |
5790 | |
5791 | void skipTest(TestCaseInfo const&) override { |
5792 | // Don't do anything with this by default. |
5793 | // It can optionally be overridden in the derived class. |
5794 | } |
5795 | |
5796 | IConfigPtr m_config; |
5797 | std::ostream& stream; |
5798 | |
5799 | LazyStat<TestRunInfo> currentTestRunInfo; |
5800 | LazyStat<GroupInfo> currentGroupInfo; |
5801 | LazyStat<TestCaseInfo> currentTestCaseInfo; |
5802 | |
5803 | std::vector<SectionInfo> m_sectionStack; |
5804 | ReporterPreferences m_reporterPrefs; |
5805 | }; |
5806 | |
5807 | template<typename DerivedT> |
5808 | struct CumulativeReporterBase : IStreamingReporter { |
5809 | template<typename T, typename ChildNodeT> |
5810 | struct Node { |
5811 | explicit Node( T const& _value ) : value( _value ) {} |
5812 | virtual ~Node() {} |
5813 | |
5814 | using ChildNodes = std::vector<std::shared_ptr<ChildNodeT>>; |
5815 | T value; |
5816 | ChildNodes children; |
5817 | }; |
5818 | struct SectionNode { |
5819 | explicit SectionNode(SectionStats const& _stats) : stats(_stats) {} |
5820 | virtual ~SectionNode() = default; |
5821 | |
5822 | bool operator == (SectionNode const& other) const { |
5823 | return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo; |
5824 | } |
5825 | bool operator == (std::shared_ptr<SectionNode> const& other) const { |
5826 | return operator==(*other); |
5827 | } |
5828 | |
5829 | SectionStats stats; |
5830 | using ChildSections = std::vector<std::shared_ptr<SectionNode>>; |
5831 | using Assertions = std::vector<AssertionStats>; |
5832 | ChildSections childSections; |
5833 | Assertions assertions; |
5834 | std::string stdOut; |
5835 | std::string stdErr; |
5836 | }; |
5837 | |
5838 | struct BySectionInfo { |
5839 | BySectionInfo( SectionInfo const& other ) : m_other( other ) {} |
5840 | BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} |
5841 | bool operator() (std::shared_ptr<SectionNode> const& node) const { |
5842 | return ((node->stats.sectionInfo.name == m_other.name) && |
5843 | (node->stats.sectionInfo.lineInfo == m_other.lineInfo)); |
5844 | } |
5845 | void operator=(BySectionInfo const&) = delete; |
5846 | |
5847 | private: |
5848 | SectionInfo const& m_other; |
5849 | }; |
5850 | |
5851 | using TestCaseNode = Node<TestCaseStats, SectionNode>; |
5852 | using TestGroupNode = Node<TestGroupStats, TestCaseNode>; |
5853 | using TestRunNode = Node<TestRunStats, TestGroupNode>; |
5854 | |
5855 | CumulativeReporterBase( ReporterConfig const& _config ) |
5856 | : m_config( _config.fullConfig() ), |
5857 | stream( _config.stream() ) |
5858 | { |
5859 | m_reporterPrefs.shouldRedirectStdOut = false; |
5860 | if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) ) |
5861 | CATCH_ERROR( "Verbosity level not supported by this reporter" ); |
5862 | } |
5863 | ~CumulativeReporterBase() override = default; |
5864 | |
5865 | ReporterPreferences getPreferences() const override { |
5866 | return m_reporterPrefs; |
5867 | } |
5868 | |
5869 | static std::set<Verbosity> getSupportedVerbosities() { |
5870 | return { Verbosity::Normal }; |
5871 | } |
5872 | |
5873 | void testRunStarting( TestRunInfo const& ) override {} |
5874 | void testGroupStarting( GroupInfo const& ) override {} |
5875 | |
5876 | void testCaseStarting( TestCaseInfo const& ) override {} |
5877 | |
5878 | void sectionStarting( SectionInfo const& sectionInfo ) override { |
5879 | SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); |
5880 | std::shared_ptr<SectionNode> node; |
5881 | if( m_sectionStack.empty() ) { |
5882 | if( !m_rootSection ) |
5883 | m_rootSection = std::make_shared<SectionNode>( incompleteStats ); |
5884 | node = m_rootSection; |
5885 | } |
5886 | else { |
5887 | SectionNode& parentNode = *m_sectionStack.back(); |
5888 | auto it = |
5889 | std::find_if( parentNode.childSections.begin(), |
5890 | parentNode.childSections.end(), |
5891 | BySectionInfo( sectionInfo ) ); |
5892 | if( it == parentNode.childSections.end() ) { |
5893 | node = std::make_shared<SectionNode>( incompleteStats ); |
5894 | parentNode.childSections.push_back( node ); |
5895 | } |
5896 | else |
5897 | node = *it; |
5898 | } |
5899 | m_sectionStack.push_back( node ); |
5900 | m_deepestSection = std::move(node); |
5901 | } |
5902 | |
5903 | void assertionStarting(AssertionInfo const&) override {} |
5904 | |
5905 | bool assertionEnded(AssertionStats const& assertionStats) override { |
5906 | assert(!m_sectionStack.empty()); |
5907 | // AssertionResult holds a pointer to a temporary DecomposedExpression, |
5908 | // which getExpandedExpression() calls to build the expression string. |
5909 | // Our section stack copy of the assertionResult will likely outlive the |
5910 | // temporary, so it must be expanded or discarded now to avoid calling |
5911 | // a destroyed object later. |
5912 | prepareExpandedExpression(const_cast<AssertionResult&>( assertionStats.assertionResult ) ); |
5913 | SectionNode& sectionNode = *m_sectionStack.back(); |
5914 | sectionNode.assertions.push_back(assertionStats); |
5915 | return true; |
5916 | } |
5917 | void sectionEnded(SectionStats const& sectionStats) override { |
5918 | assert(!m_sectionStack.empty()); |
5919 | SectionNode& node = *m_sectionStack.back(); |
5920 | node.stats = sectionStats; |
5921 | m_sectionStack.pop_back(); |
5922 | } |
5923 | void testCaseEnded(TestCaseStats const& testCaseStats) override { |
5924 | auto node = std::make_shared<TestCaseNode>(testCaseStats); |
5925 | assert(m_sectionStack.size() == 0); |
5926 | node->children.push_back(m_rootSection); |
5927 | m_testCases.push_back(node); |
5928 | m_rootSection.reset(); |
5929 | |
5930 | assert(m_deepestSection); |
5931 | m_deepestSection->stdOut = testCaseStats.stdOut; |
5932 | m_deepestSection->stdErr = testCaseStats.stdErr; |
5933 | } |
5934 | void testGroupEnded(TestGroupStats const& testGroupStats) override { |
5935 | auto node = std::make_shared<TestGroupNode>(testGroupStats); |
5936 | node->children.swap(m_testCases); |
5937 | m_testGroups.push_back(node); |
5938 | } |
5939 | void testRunEnded(TestRunStats const& testRunStats) override { |
5940 | auto node = std::make_shared<TestRunNode>(testRunStats); |
5941 | node->children.swap(m_testGroups); |
5942 | m_testRuns.push_back(node); |
5943 | testRunEndedCumulative(); |
5944 | } |
5945 | virtual void testRunEndedCumulative() = 0; |
5946 | |
5947 | void skipTest(TestCaseInfo const&) override {} |
5948 | |
5949 | IConfigPtr m_config; |
5950 | std::ostream& stream; |
5951 | std::vector<AssertionStats> m_assertions; |
5952 | std::vector<std::vector<std::shared_ptr<SectionNode>>> m_sections; |
5953 | std::vector<std::shared_ptr<TestCaseNode>> m_testCases; |
5954 | std::vector<std::shared_ptr<TestGroupNode>> m_testGroups; |
5955 | |
5956 | std::vector<std::shared_ptr<TestRunNode>> m_testRuns; |
5957 | |
5958 | std::shared_ptr<SectionNode> m_rootSection; |
5959 | std::shared_ptr<SectionNode> m_deepestSection; |
5960 | std::vector<std::shared_ptr<SectionNode>> m_sectionStack; |
5961 | ReporterPreferences m_reporterPrefs; |
5962 | }; |
5963 | |
5964 | template<char C> |
5965 | char const* getLineOfChars() { |
5966 | static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; |
5967 | if( !*line ) { |
5968 | std::memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); |
5969 | line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; |
5970 | } |
5971 | return line; |
5972 | } |
5973 | |
5974 | struct TestEventListenerBase : StreamingReporterBase<TestEventListenerBase> { |
5975 | TestEventListenerBase( ReporterConfig const& _config ); |
5976 | |
5977 | static std::set<Verbosity> getSupportedVerbosities(); |
5978 | |
5979 | void assertionStarting(AssertionInfo const&) override; |
5980 | bool assertionEnded(AssertionStats const&) override; |
5981 | }; |
5982 | |
5983 | } // end namespace Catch |
5984 | |
5985 | // end catch_reporter_bases.hpp |
5986 | // start catch_console_colour.h |
5987 | |
5988 | namespace Catch { |
5989 | |
5990 | struct Colour { |
5991 | enum Code { |
5992 | None = 0, |
5993 | |
5994 | White, |
5995 | Red, |
5996 | Green, |
5997 | Blue, |
5998 | Cyan, |
5999 | Yellow, |
6000 | Grey, |
6001 | |
6002 | Bright = 0x10, |
6003 | |
6004 | BrightRed = Bright | Red, |
6005 | BrightGreen = Bright | Green, |
6006 | LightGrey = Bright | Grey, |
6007 | BrightWhite = Bright | White, |
6008 | BrightYellow = Bright | Yellow, |
6009 | |
6010 | // By intention |
6011 | FileName = LightGrey, |
6012 | Warning = BrightYellow, |
6013 | ResultError = BrightRed, |
6014 | ResultSuccess = BrightGreen, |
6015 | ResultExpectedFailure = Warning, |
6016 | |
6017 | Error = BrightRed, |
6018 | Success = Green, |
6019 | |
6020 | OriginalExpression = Cyan, |
6021 | ReconstructedExpression = BrightYellow, |
6022 | |
6023 | SecondaryText = LightGrey, |
6024 | Headers = White |
6025 | }; |
6026 | |
6027 | // Use constructed object for RAII guard |
6028 | Colour( Code _colourCode ); |
6029 | Colour( Colour&& other ) noexcept; |
6030 | Colour& operator=( Colour&& other ) noexcept; |
6031 | ~Colour(); |
6032 | |
6033 | // Use static method for one-shot changes |
6034 | static void use( Code _colourCode ); |
6035 | |
6036 | private: |
6037 | bool m_moved = false; |
6038 | }; |
6039 | |
6040 | std::ostream& operator << ( std::ostream& os, Colour const& ); |
6041 | |
6042 | } // end namespace Catch |
6043 | |
6044 | // end catch_console_colour.h |
6045 | // start catch_reporter_registrars.hpp |
6046 | |
6047 | |
6048 | namespace Catch { |
6049 | |
6050 | template<typename T> |
6051 | class ReporterRegistrar { |
6052 | |
6053 | class ReporterFactory : public IReporterFactory { |
6054 | |
6055 | IStreamingReporterPtr create( ReporterConfig const& config ) const override { |
6056 | return std::unique_ptr<T>( new T( config ) ); |
6057 | } |
6058 | |
6059 | std::string getDescription() const override { |
6060 | return T::getDescription(); |
6061 | } |
6062 | }; |
6063 | |
6064 | public: |
6065 | |
6066 | explicit ReporterRegistrar( std::string const& name ) { |
6067 | getMutableRegistryHub().registerReporter( name, std::make_shared<ReporterFactory>() ); |
6068 | } |
6069 | }; |
6070 | |
6071 | template<typename T> |
6072 | class ListenerRegistrar { |
6073 | |
6074 | class ListenerFactory : public IReporterFactory { |
6075 | |
6076 | IStreamingReporterPtr create( ReporterConfig const& config ) const override { |
6077 | return std::unique_ptr<T>( new T( config ) ); |
6078 | } |
6079 | std::string getDescription() const override { |
6080 | return std::string(); |
6081 | } |
6082 | }; |
6083 | |
6084 | public: |
6085 | |
6086 | ListenerRegistrar() { |
6087 | getMutableRegistryHub().registerListener( std::make_shared<ListenerFactory>() ); |
6088 | } |
6089 | }; |
6090 | } |
6091 | |
6092 | #if !defined(CATCH_CONFIG_DISABLE) |
6093 | |
6094 | #define CATCH_REGISTER_REPORTER( name, reporterType ) \ |
6095 | CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ |
6096 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ |
6097 | namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); } \ |
6098 | CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION |
6099 | |
6100 | #define CATCH_REGISTER_LISTENER( listenerType ) \ |
6101 | CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ |
6102 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ |
6103 | namespace{ Catch::ListenerRegistrar<listenerType> catch_internal_RegistrarFor##listenerType; } \ |
6104 | CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION |
6105 | #else // CATCH_CONFIG_DISABLE |
6106 | |
6107 | #define CATCH_REGISTER_REPORTER(name, reporterType) |
6108 | #define CATCH_REGISTER_LISTENER(listenerType) |
6109 | |
6110 | #endif // CATCH_CONFIG_DISABLE |
6111 | |
6112 | // end catch_reporter_registrars.hpp |
6113 | // Allow users to base their work off existing reporters |
6114 | // start catch_reporter_compact.h |
6115 | |
6116 | namespace Catch { |
6117 | |
6118 | struct CompactReporter : StreamingReporterBase<CompactReporter> { |
6119 | |
6120 | using StreamingReporterBase::StreamingReporterBase; |
6121 | |
6122 | ~CompactReporter() override; |
6123 | |
6124 | static std::string getDescription(); |
6125 | |
6126 | void noMatchingTestCases(std::string const& spec) override; |
6127 | |
6128 | void assertionStarting(AssertionInfo const&) override; |
6129 | |
6130 | bool assertionEnded(AssertionStats const& _assertionStats) override; |
6131 | |
6132 | void sectionEnded(SectionStats const& _sectionStats) override; |
6133 | |
6134 | void testRunEnded(TestRunStats const& _testRunStats) override; |
6135 | |
6136 | }; |
6137 | |
6138 | } // end namespace Catch |
6139 | |
6140 | // end catch_reporter_compact.h |
6141 | // start catch_reporter_console.h |
6142 | |
6143 | #if defined(_MSC_VER) |
6144 | #pragma warning(push) |
6145 | #pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch |
6146 | // Note that 4062 (not all labels are handled |
6147 | // and default is missing) is enabled |
6148 | #endif |
6149 | |
6150 | namespace Catch { |
6151 | // Fwd decls |
6152 | struct SummaryColumn; |
6153 | class TablePrinter; |
6154 | |
6155 | struct ConsoleReporter : StreamingReporterBase<ConsoleReporter> { |
6156 | std::unique_ptr<TablePrinter> m_tablePrinter; |
6157 | |
6158 | ConsoleReporter(ReporterConfig const& config); |
6159 | ~ConsoleReporter() override; |
6160 | static std::string getDescription(); |
6161 | |
6162 | void noMatchingTestCases(std::string const& spec) override; |
6163 | |
6164 | void reportInvalidArguments(std::string const&arg) override; |
6165 | |
6166 | void assertionStarting(AssertionInfo const&) override; |
6167 | |
6168 | bool assertionEnded(AssertionStats const& _assertionStats) override; |
6169 | |
6170 | void sectionStarting(SectionInfo const& _sectionInfo) override; |
6171 | void sectionEnded(SectionStats const& _sectionStats) override; |
6172 | |
6173 | #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) |
6174 | void benchmarkPreparing(std::string const& name) override; |
6175 | void benchmarkStarting(BenchmarkInfo const& info) override; |
6176 | void benchmarkEnded(BenchmarkStats<> const& stats) override; |
6177 | void benchmarkFailed(std::string const& error) override; |
6178 | #endif // CATCH_CONFIG_ENABLE_BENCHMARKING |
6179 | |
6180 | void testCaseEnded(TestCaseStats const& _testCaseStats) override; |
6181 | void testGroupEnded(TestGroupStats const& _testGroupStats) override; |
6182 | void testRunEnded(TestRunStats const& _testRunStats) override; |
6183 | void testRunStarting(TestRunInfo const& _testRunInfo) override; |
6184 | private: |
6185 | |
6186 | void lazyPrint(); |
6187 | |
6188 | void lazyPrintWithoutClosingBenchmarkTable(); |
6189 | void lazyPrintRunInfo(); |
6190 | void lazyPrintGroupInfo(); |
6191 | void printTestCaseAndSectionHeader(); |
6192 | |
6193 | void printClosedHeader(std::string const& _name); |
6194 | void printOpenHeader(std::string const& _name); |
6195 | |
6196 | // if string has a : in first line will set indent to follow it on |
6197 | // subsequent lines |
6198 | void printHeaderString(std::string const& _string, std::size_t indent = 0); |
6199 | |
6200 | void printTotals(Totals const& totals); |
6201 | void printSummaryRow(std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row); |
6202 | |
6203 | void printTotalsDivider(Totals const& totals); |
6204 | void printSummaryDivider(); |
6205 | void printTestFilters(); |
6206 | |
6207 | private: |
6208 | bool m_headerPrinted = false; |
6209 | }; |
6210 | |
6211 | } // end namespace Catch |
6212 | |
6213 | #if defined(_MSC_VER) |
6214 | #pragma warning(pop) |
6215 | #endif |
6216 | |
6217 | // end catch_reporter_console.h |
6218 | // start catch_reporter_junit.h |
6219 | |
6220 | // start catch_xmlwriter.h |
6221 | |
6222 | #include <vector> |
6223 | |
6224 | namespace Catch { |
6225 | enum class XmlFormatting { |
6226 | None = 0x00, |
6227 | Indent = 0x01, |
6228 | Newline = 0x02, |
6229 | }; |
6230 | |
6231 | XmlFormatting operator | (XmlFormatting lhs, XmlFormatting rhs); |
6232 | XmlFormatting operator & (XmlFormatting lhs, XmlFormatting rhs); |
6233 | |
6234 | class XmlEncode { |
6235 | public: |
6236 | enum ForWhat { ForTextNodes, ForAttributes }; |
6237 | |
6238 | XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ); |
6239 | |
6240 | void encodeTo( std::ostream& os ) const; |
6241 | |
6242 | friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ); |
6243 | |
6244 | private: |
6245 | std::string m_str; |
6246 | ForWhat m_forWhat; |
6247 | }; |
6248 | |
6249 | class XmlWriter { |
6250 | public: |
6251 | |
6252 | class ScopedElement { |
6253 | public: |
6254 | ScopedElement( XmlWriter* writer, XmlFormatting fmt ); |
6255 | |
6256 | ScopedElement( ScopedElement&& other ) noexcept; |
6257 | ScopedElement& operator=( ScopedElement&& other ) noexcept; |
6258 | |
6259 | ~ScopedElement(); |
6260 | |
6261 | ScopedElement& writeText( std::string const& text, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent ); |
6262 | |
6263 | template<typename T> |
6264 | ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { |
6265 | m_writer->writeAttribute( name, attribute ); |
6266 | return *this; |
6267 | } |
6268 | |
6269 | private: |
6270 | mutable XmlWriter* m_writer = nullptr; |
6271 | XmlFormatting m_fmt; |
6272 | }; |
6273 | |
6274 | XmlWriter( std::ostream& os = Catch::cout() ); |
6275 | ~XmlWriter(); |
6276 | |
6277 | XmlWriter( XmlWriter const& ) = delete; |
6278 | XmlWriter& operator=( XmlWriter const& ) = delete; |
6279 | |
6280 | XmlWriter& startElement( std::string const& name, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent); |
6281 | |
6282 | ScopedElement scopedElement( std::string const& name, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent); |
6283 | |
6284 | XmlWriter& endElement(XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent); |
6285 | |
6286 | XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ); |
6287 | |
6288 | XmlWriter& writeAttribute( std::string const& name, bool attribute ); |
6289 | |
6290 | template<typename T> |
6291 | XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { |
6292 | ReusableStringStream rss; |
6293 | rss << attribute; |
6294 | return writeAttribute( name, rss.str() ); |
6295 | } |
6296 | |
6297 | XmlWriter& writeText( std::string const& text, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent); |
6298 | |
6299 | XmlWriter& writeComment(std::string const& text, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent); |
6300 | |
6301 | void writeStylesheetRef( std::string const& url ); |
6302 | |
6303 | XmlWriter& writeBlankLine(); |
6304 | |
6305 | void ensureTagClosed(); |
6306 | |
6307 | private: |
6308 | |
6309 | void applyFormatting(XmlFormatting fmt); |
6310 | |
6311 | void writeDeclaration(); |
6312 | |
6313 | void newlineIfNecessary(); |
6314 | |
6315 | bool m_tagIsOpen = false; |
6316 | bool m_needsNewline = false; |
6317 | std::vector<std::string> m_tags; |
6318 | std::string m_indent; |
6319 | std::ostream& m_os; |
6320 | }; |
6321 | |
6322 | } |
6323 | |
6324 | // end catch_xmlwriter.h |
6325 | namespace Catch { |
6326 | |
6327 | class JunitReporter : public CumulativeReporterBase<JunitReporter> { |
6328 | public: |
6329 | JunitReporter(ReporterConfig const& _config); |
6330 | |
6331 | ~JunitReporter() override; |
6332 | |
6333 | static std::string getDescription(); |
6334 | |
6335 | void noMatchingTestCases(std::string const& /*spec*/) override; |
6336 | |
6337 | void testRunStarting(TestRunInfo const& runInfo) override; |
6338 | |
6339 | void testGroupStarting(GroupInfo const& groupInfo) override; |
6340 | |
6341 | void testCaseStarting(TestCaseInfo const& testCaseInfo) override; |
6342 | bool assertionEnded(AssertionStats const& assertionStats) override; |
6343 | |
6344 | void testCaseEnded(TestCaseStats const& testCaseStats) override; |
6345 | |
6346 | void testGroupEnded(TestGroupStats const& testGroupStats) override; |
6347 | |
6348 | void testRunEndedCumulative() override; |
6349 | |
6350 | void writeGroup(TestGroupNode const& groupNode, double suiteTime); |
6351 | |
6352 | void writeTestCase(TestCaseNode const& testCaseNode); |
6353 | |
6354 | void writeSection( std::string const& className, |
6355 | std::string const& rootName, |
6356 | SectionNode const& sectionNode, |
6357 | bool testOkToFail ); |
6358 | |
6359 | void writeAssertions(SectionNode const& sectionNode); |
6360 | void writeAssertion(AssertionStats const& stats); |
6361 | |
6362 | XmlWriter xml; |
6363 | Timer suiteTimer; |
6364 | std::string stdOutForSuite; |
6365 | std::string stdErrForSuite; |
6366 | unsigned int unexpectedExceptions = 0; |
6367 | bool m_okToFail = false; |
6368 | }; |
6369 | |
6370 | } // end namespace Catch |
6371 | |
6372 | // end catch_reporter_junit.h |
6373 | // start catch_reporter_xml.h |
6374 | |
6375 | namespace Catch { |
6376 | class XmlReporter : public StreamingReporterBase<XmlReporter> { |
6377 | public: |
6378 | XmlReporter(ReporterConfig const& _config); |
6379 | |
6380 | ~XmlReporter() override; |
6381 | |
6382 | static std::string getDescription(); |
6383 | |
6384 | virtual std::string getStylesheetRef() const; |
6385 | |
6386 | void writeSourceInfo(SourceLineInfo const& sourceInfo); |
6387 | |
6388 | public: // StreamingReporterBase |
6389 | |
6390 | void noMatchingTestCases(std::string const& s) override; |
6391 | |
6392 | void testRunStarting(TestRunInfo const& testInfo) override; |
6393 | |
6394 | void testGroupStarting(GroupInfo const& groupInfo) override; |
6395 | |
6396 | void testCaseStarting(TestCaseInfo const& testInfo) override; |
6397 | |
6398 | void sectionStarting(SectionInfo const& sectionInfo) override; |
6399 | |
6400 | void assertionStarting(AssertionInfo const&) override; |
6401 | |
6402 | bool assertionEnded(AssertionStats const& assertionStats) override; |
6403 | |
6404 | void sectionEnded(SectionStats const& sectionStats) override; |
6405 | |
6406 | void testCaseEnded(TestCaseStats const& testCaseStats) override; |
6407 | |
6408 | void testGroupEnded(TestGroupStats const& testGroupStats) override; |
6409 | |
6410 | void testRunEnded(TestRunStats const& testRunStats) override; |
6411 | |
6412 | #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) |
6413 | void benchmarkPreparing(std::string const& name) override; |
6414 | void benchmarkStarting(BenchmarkInfo const&) override; |
6415 | void benchmarkEnded(BenchmarkStats<> const&) override; |
6416 | void benchmarkFailed(std::string const&) override; |
6417 | #endif // CATCH_CONFIG_ENABLE_BENCHMARKING |
6418 | |
6419 | private: |
6420 | Timer m_testCaseTimer; |
6421 | XmlWriter m_xml; |
6422 | int m_sectionDepth = 0; |
6423 | }; |
6424 | |
6425 | } // end namespace Catch |
6426 | |
6427 | // end catch_reporter_xml.h |
6428 | |
6429 | // end catch_external_interfaces.h |
6430 | #endif |
6431 | |
6432 | #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) |
6433 | // start catch_benchmarking_all.hpp |
6434 | |
6435 | // A proxy header that includes all of the benchmarking headers to allow |
6436 | // concise include of the benchmarking features. You should prefer the |
6437 | // individual includes in standard use. |
6438 | |
6439 | // start catch_benchmark.hpp |
6440 | |
6441 | // Benchmark |
6442 | |
6443 | // start catch_chronometer.hpp |
6444 | |
6445 | // User-facing chronometer |
6446 | |
6447 | |
6448 | // start catch_clock.hpp |
6449 | |
6450 | // Clocks |
6451 | |
6452 | |
6453 | #include <chrono> |
6454 | #include <ratio> |
6455 | |
6456 | namespace Catch { |
6457 | namespace Benchmark { |
6458 | template <typename Clock> |
6459 | using ClockDuration = typename Clock::duration; |
6460 | template <typename Clock> |
6461 | using FloatDuration = std::chrono::duration<double, typename Clock::period>; |
6462 | |
6463 | template <typename Clock> |
6464 | using TimePoint = typename Clock::time_point; |
6465 | |
6466 | using default_clock = std::chrono::steady_clock; |
6467 | |
6468 | template <typename Clock> |
6469 | struct now { |
6470 | TimePoint<Clock> operator()() const { |
6471 | return Clock::now(); |
6472 | } |
6473 | }; |
6474 | |
6475 | using fp_seconds = std::chrono::duration<double, std::ratio<1>>; |
6476 | } // namespace Benchmark |
6477 | } // namespace Catch |
6478 | |
6479 | // end catch_clock.hpp |
6480 | // start catch_optimizer.hpp |
6481 | |
6482 | // Hinting the optimizer |
6483 | |
6484 | |
6485 | #if defined(_MSC_VER) |
6486 | # include <atomic> // atomic_thread_fence |
6487 | #endif |
6488 | |
6489 | namespace Catch { |
6490 | namespace Benchmark { |
6491 | #if defined(__GNUC__) || defined(__clang__) |
6492 | template <typename T> |
6493 | inline void keep_memory(T* p) { |
6494 | asm volatile("" : : "g" (p) : "memory" ); |
6495 | } |
6496 | inline void keep_memory() { |
6497 | asm volatile("" : : : "memory" ); |
6498 | } |
6499 | |
6500 | namespace Detail { |
6501 | inline void optimizer_barrier() { keep_memory(); } |
6502 | } // namespace Detail |
6503 | #elif defined(_MSC_VER) |
6504 | |
6505 | #pragma optimize("", off) |
6506 | template <typename T> |
6507 | inline void keep_memory(T* p) { |
6508 | // thanks @milleniumbug |
6509 | *reinterpret_cast<char volatile*>(p) = *reinterpret_cast<char const volatile*>(p); |
6510 | } |
6511 | // TODO equivalent keep_memory() |
6512 | #pragma optimize("", on) |
6513 | |
6514 | namespace Detail { |
6515 | inline void optimizer_barrier() { |
6516 | std::atomic_thread_fence(std::memory_order_seq_cst); |
6517 | } |
6518 | } // namespace Detail |
6519 | |
6520 | #endif |
6521 | |
6522 | template <typename T> |
6523 | inline void deoptimize_value(T&& x) { |
6524 | keep_memory(&x); |
6525 | } |
6526 | |
6527 | template <typename Fn, typename... Args> |
6528 | inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> typename std::enable_if<!std::is_same<void, decltype(fn(args...))>::value>::type { |
6529 | deoptimize_value(std::forward<Fn>(fn) (std::forward<Args...>(args...))); |
6530 | } |
6531 | |
6532 | template <typename Fn, typename... Args> |
6533 | inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> typename std::enable_if<std::is_same<void, decltype(fn(args...))>::value>::type { |
6534 | std::forward<Fn>(fn) (std::forward<Args...>(args...)); |
6535 | } |
6536 | } // namespace Benchmark |
6537 | } // namespace Catch |
6538 | |
6539 | // end catch_optimizer.hpp |
6540 | // start catch_complete_invoke.hpp |
6541 | |
6542 | // Invoke with a special case for void |
6543 | |
6544 | |
6545 | #include <type_traits> |
6546 | #include <utility> |
6547 | |
6548 | namespace Catch { |
6549 | namespace Benchmark { |
6550 | namespace Detail { |
6551 | template <typename T> |
6552 | struct CompleteType { using type = T; }; |
6553 | template <> |
6554 | struct CompleteType<void> { struct type {}; }; |
6555 | |
6556 | template <typename T> |
6557 | using CompleteType_t = typename CompleteType<T>::type; |
6558 | |
6559 | template <typename Result> |
6560 | struct CompleteInvoker { |
6561 | template <typename Fun, typename... Args> |
6562 | static Result invoke(Fun&& fun, Args&&... args) { |
6563 | return std::forward<Fun>(fun)(std::forward<Args>(args)...); |
6564 | } |
6565 | }; |
6566 | template <> |
6567 | struct CompleteInvoker<void> { |
6568 | template <typename Fun, typename... Args> |
6569 | static CompleteType_t<void> invoke(Fun&& fun, Args&&... args) { |
6570 | std::forward<Fun>(fun)(std::forward<Args>(args)...); |
6571 | return {}; |
6572 | } |
6573 | }; |
6574 | |
6575 | // invoke and not return void :( |
6576 | template <typename Fun, typename... Args> |
6577 | CompleteType_t<FunctionReturnType<Fun, Args...>> complete_invoke(Fun&& fun, Args&&... args) { |
6578 | return CompleteInvoker<FunctionReturnType<Fun, Args...>>::invoke(std::forward<Fun>(fun), std::forward<Args>(args)...); |
6579 | } |
6580 | |
6581 | const std::string benchmarkErrorMsg = "a benchmark failed to run successfully" ; |
6582 | } // namespace Detail |
6583 | |
6584 | template <typename Fun> |
6585 | Detail::CompleteType_t<FunctionReturnType<Fun>> user_code(Fun&& fun) { |
6586 | CATCH_TRY{ |
6587 | return Detail::complete_invoke(std::forward<Fun>(fun)); |
6588 | } CATCH_CATCH_ALL{ |
6589 | getResultCapture().benchmarkFailed(translateActiveException()); |
6590 | CATCH_RUNTIME_ERROR(Detail::benchmarkErrorMsg); |
6591 | } |
6592 | } |
6593 | } // namespace Benchmark |
6594 | } // namespace Catch |
6595 | |
6596 | // end catch_complete_invoke.hpp |
6597 | namespace Catch { |
6598 | namespace Benchmark { |
6599 | namespace Detail { |
6600 | struct ChronometerConcept { |
6601 | virtual void start() = 0; |
6602 | virtual void finish() = 0; |
6603 | virtual ~ChronometerConcept() = default; |
6604 | }; |
6605 | template <typename Clock> |
6606 | struct ChronometerModel final : public ChronometerConcept { |
6607 | void start() override { started = Clock::now(); } |
6608 | void finish() override { finished = Clock::now(); } |
6609 | |
6610 | ClockDuration<Clock> elapsed() const { return finished - started; } |
6611 | |
6612 | TimePoint<Clock> started; |
6613 | TimePoint<Clock> finished; |
6614 | }; |
6615 | } // namespace Detail |
6616 | |
6617 | struct Chronometer { |
6618 | public: |
6619 | template <typename Fun> |
6620 | void measure(Fun&& fun) { measure(std::forward<Fun>(fun), is_callable<Fun(int)>()); } |
6621 | |
6622 | int runs() const { return k; } |
6623 | |
6624 | Chronometer(Detail::ChronometerConcept& meter, int k) |
6625 | : impl(&meter) |
6626 | , k(k) {} |
6627 | |
6628 | private: |
6629 | template <typename Fun> |
6630 | void measure(Fun&& fun, std::false_type) { |
6631 | measure([&fun](int) { return fun(); }, std::true_type()); |
6632 | } |
6633 | |
6634 | template <typename Fun> |
6635 | void measure(Fun&& fun, std::true_type) { |
6636 | Detail::optimizer_barrier(); |
6637 | impl->start(); |
6638 | for (int i = 0; i < k; ++i) invoke_deoptimized(fun, i); |
6639 | impl->finish(); |
6640 | Detail::optimizer_barrier(); |
6641 | } |
6642 | |
6643 | Detail::ChronometerConcept* impl; |
6644 | int k; |
6645 | }; |
6646 | } // namespace Benchmark |
6647 | } // namespace Catch |
6648 | |
6649 | // end catch_chronometer.hpp |
6650 | // start catch_environment.hpp |
6651 | |
6652 | // Environment information |
6653 | |
6654 | |
6655 | namespace Catch { |
6656 | namespace Benchmark { |
6657 | template <typename Duration> |
6658 | struct EnvironmentEstimate { |
6659 | Duration mean; |
6660 | OutlierClassification outliers; |
6661 | |
6662 | template <typename Duration2> |
6663 | operator EnvironmentEstimate<Duration2>() const { |
6664 | return { mean, outliers }; |
6665 | } |
6666 | }; |
6667 | template <typename Clock> |
6668 | struct Environment { |
6669 | using clock_type = Clock; |
6670 | EnvironmentEstimate<FloatDuration<Clock>> clock_resolution; |
6671 | EnvironmentEstimate<FloatDuration<Clock>> clock_cost; |
6672 | }; |
6673 | } // namespace Benchmark |
6674 | } // namespace Catch |
6675 | |
6676 | // end catch_environment.hpp |
6677 | // start catch_execution_plan.hpp |
6678 | |
6679 | // Execution plan |
6680 | |
6681 | |
6682 | // start catch_benchmark_function.hpp |
6683 | |
6684 | // Dumb std::function implementation for consistent call overhead |
6685 | |
6686 | |
6687 | #include <cassert> |
6688 | #include <type_traits> |
6689 | #include <utility> |
6690 | #include <memory> |
6691 | |
6692 | namespace Catch { |
6693 | namespace Benchmark { |
6694 | namespace Detail { |
6695 | template <typename T> |
6696 | using Decay = typename std::decay<T>::type; |
6697 | template <typename T, typename U> |
6698 | struct is_related |
6699 | : std::is_same<Decay<T>, Decay<U>> {}; |
6700 | |
6701 | /// We need to reinvent std::function because every piece of code that might add overhead |
6702 | /// in a measurement context needs to have consistent performance characteristics so that we |
6703 | /// can account for it in the measurement. |
6704 | /// Implementations of std::function with optimizations that aren't always applicable, like |
6705 | /// small buffer optimizations, are not uncommon. |
6706 | /// This is effectively an implementation of std::function without any such optimizations; |
6707 | /// it may be slow, but it is consistently slow. |
6708 | struct BenchmarkFunction { |
6709 | private: |
6710 | struct callable { |
6711 | virtual void call(Chronometer meter) const = 0; |
6712 | virtual callable* clone() const = 0; |
6713 | virtual ~callable() = default; |
6714 | }; |
6715 | template <typename Fun> |
6716 | struct model : public callable { |
6717 | model(Fun&& fun) : fun(std::move(fun)) {} |
6718 | model(Fun const& fun) : fun(fun) {} |
6719 | |
6720 | model<Fun>* clone() const override { return new model<Fun>(*this); } |
6721 | |
6722 | void call(Chronometer meter) const override { |
6723 | call(meter, is_callable<Fun(Chronometer)>()); |
6724 | } |
6725 | void call(Chronometer meter, std::true_type) const { |
6726 | fun(meter); |
6727 | } |
6728 | void call(Chronometer meter, std::false_type) const { |
6729 | meter.measure(fun); |
6730 | } |
6731 | |
6732 | Fun fun; |
6733 | }; |
6734 | |
6735 | struct do_nothing { void operator()() const {} }; |
6736 | |
6737 | template <typename T> |
6738 | BenchmarkFunction(model<T>* c) : f(c) {} |
6739 | |
6740 | public: |
6741 | BenchmarkFunction() |
6742 | : f(new model<do_nothing>{ {} }) {} |
6743 | |
6744 | template <typename Fun, |
6745 | typename std::enable_if<!is_related<Fun, BenchmarkFunction>::value, int>::type = 0> |
6746 | BenchmarkFunction(Fun&& fun) |
6747 | : f(new model<typename std::decay<Fun>::type>(std::forward<Fun>(fun))) {} |
6748 | |
6749 | BenchmarkFunction(BenchmarkFunction&& that) |
6750 | : f(std::move(that.f)) {} |
6751 | |
6752 | BenchmarkFunction(BenchmarkFunction const& that) |
6753 | : f(that.f->clone()) {} |
6754 | |
6755 | BenchmarkFunction& operator=(BenchmarkFunction&& that) { |
6756 | f = std::move(that.f); |
6757 | return *this; |
6758 | } |
6759 | |
6760 | BenchmarkFunction& operator=(BenchmarkFunction const& that) { |
6761 | f.reset(that.f->clone()); |
6762 | return *this; |
6763 | } |
6764 | |
6765 | void operator()(Chronometer meter) const { f->call(meter); } |
6766 | |
6767 | private: |
6768 | std::unique_ptr<callable> f; |
6769 | }; |
6770 | } // namespace Detail |
6771 | } // namespace Benchmark |
6772 | } // namespace Catch |
6773 | |
6774 | // end catch_benchmark_function.hpp |
6775 | // start catch_repeat.hpp |
6776 | |
6777 | // repeat algorithm |
6778 | |
6779 | |
6780 | #include <type_traits> |
6781 | #include <utility> |
6782 | |
6783 | namespace Catch { |
6784 | namespace Benchmark { |
6785 | namespace Detail { |
6786 | template <typename Fun> |
6787 | struct repeater { |
6788 | void operator()(int k) const { |
6789 | for (int i = 0; i < k; ++i) { |
6790 | fun(); |
6791 | } |
6792 | } |
6793 | Fun fun; |
6794 | }; |
6795 | template <typename Fun> |
6796 | repeater<typename std::decay<Fun>::type> repeat(Fun&& fun) { |
6797 | return { std::forward<Fun>(fun) }; |
6798 | } |
6799 | } // namespace Detail |
6800 | } // namespace Benchmark |
6801 | } // namespace Catch |
6802 | |
6803 | // end catch_repeat.hpp |
6804 | // start catch_run_for_at_least.hpp |
6805 | |
6806 | // Run a function for a minimum amount of time |
6807 | |
6808 | |
6809 | // start catch_measure.hpp |
6810 | |
6811 | // Measure |
6812 | |
6813 | |
6814 | // start catch_timing.hpp |
6815 | |
6816 | // Timing |
6817 | |
6818 | |
6819 | #include <tuple> |
6820 | #include <type_traits> |
6821 | |
6822 | namespace Catch { |
6823 | namespace Benchmark { |
6824 | template <typename Duration, typename Result> |
6825 | struct Timing { |
6826 | Duration elapsed; |
6827 | Result result; |
6828 | int iterations; |
6829 | }; |
6830 | template <typename Clock, typename Func, typename... Args> |
6831 | using TimingOf = Timing<ClockDuration<Clock>, Detail::CompleteType_t<FunctionReturnType<Func, Args...>>>; |
6832 | } // namespace Benchmark |
6833 | } // namespace Catch |
6834 | |
6835 | // end catch_timing.hpp |
6836 | #include <utility> |
6837 | |
6838 | namespace Catch { |
6839 | namespace Benchmark { |
6840 | namespace Detail { |
6841 | template <typename Clock, typename Fun, typename... Args> |
6842 | TimingOf<Clock, Fun, Args...> measure(Fun&& fun, Args&&... args) { |
6843 | auto start = Clock::now(); |
6844 | auto&& r = Detail::complete_invoke(fun, std::forward<Args>(args)...); |
6845 | auto end = Clock::now(); |
6846 | auto delta = end - start; |
6847 | return { delta, std::forward<decltype(r)>(r), 1 }; |
6848 | } |
6849 | } // namespace Detail |
6850 | } // namespace Benchmark |
6851 | } // namespace Catch |
6852 | |
6853 | // end catch_measure.hpp |
6854 | #include <utility> |
6855 | #include <type_traits> |
6856 | |
6857 | namespace Catch { |
6858 | namespace Benchmark { |
6859 | namespace Detail { |
6860 | template <typename Clock, typename Fun> |
6861 | TimingOf<Clock, Fun, int> measure_one(Fun&& fun, int iters, std::false_type) { |
6862 | return Detail::measure<Clock>(fun, iters); |
6863 | } |
6864 | template <typename Clock, typename Fun> |
6865 | TimingOf<Clock, Fun, Chronometer> measure_one(Fun&& fun, int iters, std::true_type) { |
6866 | Detail::ChronometerModel<Clock> meter; |
6867 | auto&& result = Detail::complete_invoke(fun, Chronometer(meter, iters)); |
6868 | |
6869 | return { meter.elapsed(), std::move(result), iters }; |
6870 | } |
6871 | |
6872 | template <typename Clock, typename Fun> |
6873 | using run_for_at_least_argument_t = typename std::conditional<is_callable<Fun(Chronometer)>::value, Chronometer, int>::type; |
6874 | |
6875 | struct optimized_away_error : std::exception { |
6876 | const char* what() const noexcept override { |
6877 | return "could not measure benchmark, maybe it was optimized away" ; |
6878 | } |
6879 | }; |
6880 | |
6881 | template <typename Clock, typename Fun> |
6882 | TimingOf<Clock, Fun, run_for_at_least_argument_t<Clock, Fun>> run_for_at_least(ClockDuration<Clock> how_long, int seed, Fun&& fun) { |
6883 | auto iters = seed; |
6884 | while (iters < (1 << 30)) { |
6885 | auto&& Timing = measure_one<Clock>(fun, iters, is_callable<Fun(Chronometer)>()); |
6886 | |
6887 | if (Timing.elapsed >= how_long) { |
6888 | return { Timing.elapsed, std::move(Timing.result), iters }; |
6889 | } |
6890 | iters *= 2; |
6891 | } |
6892 | Catch::throw_exception(optimized_away_error{}); |
6893 | } |
6894 | } // namespace Detail |
6895 | } // namespace Benchmark |
6896 | } // namespace Catch |
6897 | |
6898 | // end catch_run_for_at_least.hpp |
6899 | #include <algorithm> |
6900 | #include <iterator> |
6901 | |
6902 | namespace Catch { |
6903 | namespace Benchmark { |
6904 | template <typename Duration> |
6905 | struct ExecutionPlan { |
6906 | int iterations_per_sample; |
6907 | Duration estimated_duration; |
6908 | Detail::BenchmarkFunction benchmark; |
6909 | Duration warmup_time; |
6910 | int warmup_iterations; |
6911 | |
6912 | template <typename Duration2> |
6913 | operator ExecutionPlan<Duration2>() const { |
6914 | return { iterations_per_sample, estimated_duration, benchmark, warmup_time, warmup_iterations }; |
6915 | } |
6916 | |
6917 | template <typename Clock> |
6918 | std::vector<FloatDuration<Clock>> run(const IConfig &cfg, Environment<FloatDuration<Clock>> env) const { |
6919 | // warmup a bit |
6920 | Detail::run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(warmup_time), warmup_iterations, Detail::repeat(now<Clock>{})); |
6921 | |
6922 | std::vector<FloatDuration<Clock>> times; |
6923 | times.reserve(cfg.benchmarkSamples()); |
6924 | std::generate_n(std::back_inserter(times), cfg.benchmarkSamples(), [this, env] { |
6925 | Detail::ChronometerModel<Clock> model; |
6926 | this->benchmark(Chronometer(model, iterations_per_sample)); |
6927 | auto sample_time = model.elapsed() - env.clock_cost.mean; |
6928 | if (sample_time < FloatDuration<Clock>::zero()) sample_time = FloatDuration<Clock>::zero(); |
6929 | return sample_time / iterations_per_sample; |
6930 | }); |
6931 | return times; |
6932 | } |
6933 | }; |
6934 | } // namespace Benchmark |
6935 | } // namespace Catch |
6936 | |
6937 | // end catch_execution_plan.hpp |
6938 | // start catch_estimate_clock.hpp |
6939 | |
6940 | // Environment measurement |
6941 | |
6942 | |
6943 | // start catch_stats.hpp |
6944 | |
6945 | // Statistical analysis tools |
6946 | |
6947 | |
6948 | #include <algorithm> |
6949 | #include <functional> |
6950 | #include <vector> |
6951 | #include <iterator> |
6952 | #include <numeric> |
6953 | #include <tuple> |
6954 | #include <cmath> |
6955 | #include <utility> |
6956 | #include <cstddef> |
6957 | #include <random> |
6958 | |
6959 | namespace Catch { |
6960 | namespace Benchmark { |
6961 | namespace Detail { |
6962 | using sample = std::vector<double>; |
6963 | |
6964 | double weighted_average_quantile(int k, int q, std::vector<double>::iterator first, std::vector<double>::iterator last); |
6965 | |
6966 | template <typename Iterator> |
6967 | OutlierClassification classify_outliers(Iterator first, Iterator last) { |
6968 | std::vector<double> copy(first, last); |
6969 | |
6970 | auto q1 = weighted_average_quantile(1, 4, copy.begin(), copy.end()); |
6971 | auto q3 = weighted_average_quantile(3, 4, copy.begin(), copy.end()); |
6972 | auto iqr = q3 - q1; |
6973 | auto los = q1 - (iqr * 3.); |
6974 | auto lom = q1 - (iqr * 1.5); |
6975 | auto him = q3 + (iqr * 1.5); |
6976 | auto his = q3 + (iqr * 3.); |
6977 | |
6978 | OutlierClassification o; |
6979 | for (; first != last; ++first) { |
6980 | auto&& t = *first; |
6981 | if (t < los) ++o.low_severe; |
6982 | else if (t < lom) ++o.low_mild; |
6983 | else if (t > his) ++o.high_severe; |
6984 | else if (t > him) ++o.high_mild; |
6985 | ++o.samples_seen; |
6986 | } |
6987 | return o; |
6988 | } |
6989 | |
6990 | template <typename Iterator> |
6991 | double mean(Iterator first, Iterator last) { |
6992 | auto count = last - first; |
6993 | double sum = std::accumulate(first, last, 0.); |
6994 | return sum / count; |
6995 | } |
6996 | |
6997 | template <typename URng, typename Iterator, typename Estimator> |
6998 | sample resample(URng& rng, int resamples, Iterator first, Iterator last, Estimator& estimator) { |
6999 | auto n = last - first; |
7000 | std::uniform_int_distribution<decltype(n)> dist(0, n - 1); |
7001 | |
7002 | sample out; |
7003 | out.reserve(resamples); |
7004 | std::generate_n(std::back_inserter(out), resamples, [n, first, &estimator, &dist, &rng] { |
7005 | std::vector<double> resampled; |
7006 | resampled.reserve(n); |
7007 | std::generate_n(std::back_inserter(resampled), n, [first, &dist, &rng] { return first[dist(rng)]; }); |
7008 | return estimator(resampled.begin(), resampled.end()); |
7009 | }); |
7010 | std::sort(out.begin(), out.end()); |
7011 | return out; |
7012 | } |
7013 | |
7014 | template <typename Estimator, typename Iterator> |
7015 | sample jackknife(Estimator&& estimator, Iterator first, Iterator last) { |
7016 | auto n = last - first; |
7017 | auto second = std::next(first); |
7018 | sample results; |
7019 | results.reserve(n); |
7020 | |
7021 | for (auto it = first; it != last; ++it) { |
7022 | std::iter_swap(it, first); |
7023 | results.push_back(estimator(second, last)); |
7024 | } |
7025 | |
7026 | return results; |
7027 | } |
7028 | |
7029 | inline double normal_cdf(double x) { |
7030 | return std::erfc(-x / std::sqrt(2.0)) / 2.0; |
7031 | } |
7032 | |
7033 | double erfc_inv(double x); |
7034 | |
7035 | double normal_quantile(double p); |
7036 | |
7037 | template <typename Iterator, typename Estimator> |
7038 | Estimate<double> bootstrap(double confidence_level, Iterator first, Iterator last, sample const& resample, Estimator&& estimator) { |
7039 | auto n_samples = last - first; |
7040 | |
7041 | double point = estimator(first, last); |
7042 | // Degenerate case with a single sample |
7043 | if (n_samples == 1) return { point, point, point, confidence_level }; |
7044 | |
7045 | sample jack = jackknife(estimator, first, last); |
7046 | double jack_mean = mean(jack.begin(), jack.end()); |
7047 | double sum_squares, sum_cubes; |
7048 | 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> { |
7049 | auto d = jack_mean - x; |
7050 | auto d2 = d * d; |
7051 | auto d3 = d2 * d; |
7052 | return { sqcb.first + d2, sqcb.second + d3 }; |
7053 | }); |
7054 | |
7055 | double accel = sum_cubes / (6 * std::pow(sum_squares, 1.5)); |
7056 | int n = static_cast<int>(resample.size()); |
7057 | double prob_n = std::count_if(resample.begin(), resample.end(), [point](double x) { return x < point; }) / (double)n; |
7058 | // degenerate case with uniform samples |
7059 | if (prob_n == 0) return { point, point, point, confidence_level }; |
7060 | |
7061 | double bias = normal_quantile(prob_n); |
7062 | double z1 = normal_quantile((1. - confidence_level) / 2.); |
7063 | |
7064 | auto cumn = [n](double x) -> int { |
7065 | return std::lround(normal_cdf(x) * n); }; |
7066 | auto a = [bias, accel](double b) { return bias + b / (1. - accel * b); }; |
7067 | double b1 = bias + z1; |
7068 | double b2 = bias - z1; |
7069 | double a1 = a(b1); |
7070 | double a2 = a(b2); |
7071 | auto lo = (std::max)(cumn(a1), 0); |
7072 | auto hi = (std::min)(cumn(a2), n - 1); |
7073 | |
7074 | return { point, resample[lo], resample[hi], confidence_level }; |
7075 | } |
7076 | |
7077 | double outlier_variance(Estimate<double> mean, Estimate<double> stddev, int n); |
7078 | |
7079 | struct bootstrap_analysis { |
7080 | Estimate<double> mean; |
7081 | Estimate<double> standard_deviation; |
7082 | double outlier_variance; |
7083 | }; |
7084 | |
7085 | bootstrap_analysis analyse_samples(double confidence_level, int n_resamples, std::vector<double>::iterator first, std::vector<double>::iterator last); |
7086 | } // namespace Detail |
7087 | } // namespace Benchmark |
7088 | } // namespace Catch |
7089 | |
7090 | // end catch_stats.hpp |
7091 | #include <algorithm> |
7092 | #include <iterator> |
7093 | #include <tuple> |
7094 | #include <vector> |
7095 | #include <cmath> |
7096 | |
7097 | namespace Catch { |
7098 | namespace Benchmark { |
7099 | namespace Detail { |
7100 | template <typename Clock> |
7101 | std::vector<double> resolution(int k) { |
7102 | std::vector<TimePoint<Clock>> times; |
7103 | times.reserve(k + 1); |
7104 | std::generate_n(std::back_inserter(times), k + 1, now<Clock>{}); |
7105 | |
7106 | std::vector<double> deltas; |
7107 | deltas.reserve(k); |
7108 | std::transform(std::next(times.begin()), times.end(), times.begin(), |
7109 | std::back_inserter(deltas), |
7110 | [](TimePoint<Clock> a, TimePoint<Clock> b) { return static_cast<double>((a - b).count()); }); |
7111 | |
7112 | return deltas; |
7113 | } |
7114 | |
7115 | const auto warmup_iterations = 10000; |
7116 | const auto warmup_time = std::chrono::milliseconds(100); |
7117 | const auto minimum_ticks = 1000; |
7118 | const auto warmup_seed = 10000; |
7119 | const auto clock_resolution_estimation_time = std::chrono::milliseconds(500); |
7120 | const auto clock_cost_estimation_time_limit = std::chrono::seconds(1); |
7121 | const auto clock_cost_estimation_tick_limit = 100000; |
7122 | const auto clock_cost_estimation_time = std::chrono::milliseconds(10); |
7123 | const auto clock_cost_estimation_iterations = 10000; |
7124 | |
7125 | template <typename Clock> |
7126 | int warmup() { |
7127 | return run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(warmup_time), warmup_seed, &resolution<Clock>) |
7128 | .iterations; |
7129 | } |
7130 | template <typename Clock> |
7131 | EnvironmentEstimate<FloatDuration<Clock>> estimate_clock_resolution(int iterations) { |
7132 | auto r = run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(clock_resolution_estimation_time), iterations, &resolution<Clock>) |
7133 | .result; |
7134 | return { |
7135 | FloatDuration<Clock>(mean(r.begin(), r.end())), |
7136 | classify_outliers(r.begin(), r.end()), |
7137 | }; |
7138 | } |
7139 | template <typename Clock> |
7140 | EnvironmentEstimate<FloatDuration<Clock>> estimate_clock_cost(FloatDuration<Clock> resolution) { |
7141 | auto time_limit = (std::min)( |
7142 | resolution * clock_cost_estimation_tick_limit, |
7143 | FloatDuration<Clock>(clock_cost_estimation_time_limit)); |
7144 | auto time_clock = [](int k) { |
7145 | return Detail::measure<Clock>([k] { |
7146 | for (int i = 0; i < k; ++i) { |
7147 | volatile auto ignored = Clock::now(); |
7148 | (void)ignored; |
7149 | } |
7150 | }).elapsed; |
7151 | }; |
7152 | time_clock(1); |
7153 | int iters = clock_cost_estimation_iterations; |
7154 | auto&& r = run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(clock_cost_estimation_time), iters, time_clock); |
7155 | std::vector<double> times; |
7156 | int nsamples = static_cast<int>(std::ceil(time_limit / r.elapsed)); |
7157 | times.reserve(nsamples); |
7158 | std::generate_n(std::back_inserter(times), nsamples, [time_clock, &r] { |
7159 | return static_cast<double>((time_clock(r.iterations) / r.iterations).count()); |
7160 | }); |
7161 | return { |
7162 | FloatDuration<Clock>(mean(times.begin(), times.end())), |
7163 | classify_outliers(times.begin(), times.end()), |
7164 | }; |
7165 | } |
7166 | |
7167 | template <typename Clock> |
7168 | Environment<FloatDuration<Clock>> measure_environment() { |
7169 | static Environment<FloatDuration<Clock>>* env = nullptr; |
7170 | if (env) { |
7171 | return *env; |
7172 | } |
7173 | |
7174 | auto iters = Detail::warmup<Clock>(); |
7175 | auto resolution = Detail::estimate_clock_resolution<Clock>(iters); |
7176 | auto cost = Detail::estimate_clock_cost<Clock>(resolution.mean); |
7177 | |
7178 | env = new Environment<FloatDuration<Clock>>{ resolution, cost }; |
7179 | return *env; |
7180 | } |
7181 | } // namespace Detail |
7182 | } // namespace Benchmark |
7183 | } // namespace Catch |
7184 | |
7185 | // end catch_estimate_clock.hpp |
7186 | // start catch_analyse.hpp |
7187 | |
7188 | // Run and analyse one benchmark |
7189 | |
7190 | |
7191 | // start catch_sample_analysis.hpp |
7192 | |
7193 | // Benchmark results |
7194 | |
7195 | |
7196 | #include <algorithm> |
7197 | #include <vector> |
7198 | #include <string> |
7199 | #include <iterator> |
7200 | |
7201 | namespace Catch { |
7202 | namespace Benchmark { |
7203 | template <typename Duration> |
7204 | struct SampleAnalysis { |
7205 | std::vector<Duration> samples; |
7206 | Estimate<Duration> mean; |
7207 | Estimate<Duration> standard_deviation; |
7208 | OutlierClassification outliers; |
7209 | double outlier_variance; |
7210 | |
7211 | template <typename Duration2> |
7212 | operator SampleAnalysis<Duration2>() const { |
7213 | std::vector<Duration2> samples2; |
7214 | samples2.reserve(samples.size()); |
7215 | std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](Duration d) { return Duration2(d); }); |
7216 | return { |
7217 | std::move(samples2), |
7218 | mean, |
7219 | standard_deviation, |
7220 | outliers, |
7221 | outlier_variance, |
7222 | }; |
7223 | } |
7224 | }; |
7225 | } // namespace Benchmark |
7226 | } // namespace Catch |
7227 | |
7228 | // end catch_sample_analysis.hpp |
7229 | #include <algorithm> |
7230 | #include <iterator> |
7231 | #include <vector> |
7232 | |
7233 | namespace Catch { |
7234 | namespace Benchmark { |
7235 | namespace Detail { |
7236 | template <typename Duration, typename Iterator> |
7237 | SampleAnalysis<Duration> analyse(const IConfig &cfg, Environment<Duration>, Iterator first, Iterator last) { |
7238 | if (!cfg.benchmarkNoAnalysis()) { |
7239 | std::vector<double> samples; |
7240 | samples.reserve(last - first); |
7241 | std::transform(first, last, std::back_inserter(samples), [](Duration d) { return d.count(); }); |
7242 | |
7243 | auto analysis = Catch::Benchmark::Detail::analyse_samples(cfg.benchmarkConfidenceInterval(), cfg.benchmarkResamples(), samples.begin(), samples.end()); |
7244 | auto outliers = Catch::Benchmark::Detail::classify_outliers(samples.begin(), samples.end()); |
7245 | |
7246 | auto wrap_estimate = [](Estimate<double> e) { |
7247 | return Estimate<Duration> { |
7248 | Duration(e.point), |
7249 | Duration(e.lower_bound), |
7250 | Duration(e.upper_bound), |
7251 | e.confidence_interval, |
7252 | }; |
7253 | }; |
7254 | std::vector<Duration> samples2; |
7255 | samples2.reserve(samples.size()); |
7256 | std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](double d) { return Duration(d); }); |
7257 | return { |
7258 | std::move(samples2), |
7259 | wrap_estimate(analysis.mean), |
7260 | wrap_estimate(analysis.standard_deviation), |
7261 | outliers, |
7262 | analysis.outlier_variance, |
7263 | }; |
7264 | } else { |
7265 | std::vector<Duration> samples; |
7266 | samples.reserve(last - first); |
7267 | |
7268 | Duration mean = Duration(0); |
7269 | int i = 0; |
7270 | for (auto it = first; it < last; ++it, ++i) { |
7271 | samples.push_back(Duration(*it)); |
7272 | mean += Duration(*it); |
7273 | } |
7274 | mean /= i; |
7275 | |
7276 | return { |
7277 | std::move(samples), |
7278 | Estimate<Duration>{mean, mean, mean, 0.0}, |
7279 | Estimate<Duration>{Duration(0), Duration(0), Duration(0), 0.0}, |
7280 | OutlierClassification{}, |
7281 | 0.0 |
7282 | }; |
7283 | } |
7284 | } |
7285 | } // namespace Detail |
7286 | } // namespace Benchmark |
7287 | } // namespace Catch |
7288 | |
7289 | // end catch_analyse.hpp |
7290 | #include <algorithm> |
7291 | #include <functional> |
7292 | #include <string> |
7293 | #include <vector> |
7294 | #include <cmath> |
7295 | |
7296 | namespace Catch { |
7297 | namespace Benchmark { |
7298 | struct Benchmark { |
7299 | Benchmark(std::string &&name) |
7300 | : name(std::move(name)) {} |
7301 | |
7302 | template <class FUN> |
7303 | Benchmark(std::string &&name, FUN &&func) |
7304 | : fun(std::move(func)), name(std::move(name)) {} |
7305 | |
7306 | template <typename Clock> |
7307 | ExecutionPlan<FloatDuration<Clock>> prepare(const IConfig &cfg, Environment<FloatDuration<Clock>> env) const { |
7308 | auto min_time = env.clock_resolution.mean * Detail::minimum_ticks; |
7309 | auto run_time = std::max(min_time, std::chrono::duration_cast<decltype(min_time)>(cfg.benchmarkWarmupTime())); |
7310 | auto&& test = Detail::run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(run_time), 1, fun); |
7311 | int new_iters = static_cast<int>(std::ceil(min_time * test.iterations / test.elapsed)); |
7312 | return { new_iters, test.elapsed / test.iterations * new_iters * cfg.benchmarkSamples(), fun, std::chrono::duration_cast<FloatDuration<Clock>>(cfg.benchmarkWarmupTime()), Detail::warmup_iterations }; |
7313 | } |
7314 | |
7315 | template <typename Clock = default_clock> |
7316 | void run() { |
7317 | IConfigPtr cfg = getCurrentContext().getConfig(); |
7318 | |
7319 | auto env = Detail::measure_environment<Clock>(); |
7320 | |
7321 | getResultCapture().benchmarkPreparing(name); |
7322 | CATCH_TRY{ |
7323 | auto plan = user_code([&] { |
7324 | return prepare<Clock>(*cfg, env); |
7325 | }); |
7326 | |
7327 | BenchmarkInfo info { |
7328 | name, |
7329 | plan.estimated_duration.count(), |
7330 | plan.iterations_per_sample, |
7331 | cfg->benchmarkSamples(), |
7332 | cfg->benchmarkResamples(), |
7333 | env.clock_resolution.mean.count(), |
7334 | env.clock_cost.mean.count() |
7335 | }; |
7336 | |
7337 | getResultCapture().benchmarkStarting(info); |
7338 | |
7339 | auto samples = user_code([&] { |
7340 | return plan.template run<Clock>(*cfg, env); |
7341 | }); |
7342 | |
7343 | auto analysis = Detail::analyse(*cfg, env, samples.begin(), samples.end()); |
7344 | BenchmarkStats<FloatDuration<Clock>> stats{ info, analysis.samples, analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance }; |
7345 | getResultCapture().benchmarkEnded(stats); |
7346 | |
7347 | } CATCH_CATCH_ALL{ |
7348 | if (translateActiveException() != Detail::benchmarkErrorMsg) // benchmark errors have been reported, otherwise rethrow. |
7349 | std::rethrow_exception(std::current_exception()); |
7350 | } |
7351 | } |
7352 | |
7353 | // sets lambda to be used in fun *and* executes benchmark! |
7354 | template <typename Fun, |
7355 | typename std::enable_if<!Detail::is_related<Fun, Benchmark>::value, int>::type = 0> |
7356 | Benchmark & operator=(Fun func) { |
7357 | fun = Detail::BenchmarkFunction(func); |
7358 | run(); |
7359 | return *this; |
7360 | } |
7361 | |
7362 | explicit operator bool() { |
7363 | return true; |
7364 | } |
7365 | |
7366 | private: |
7367 | Detail::BenchmarkFunction fun; |
7368 | std::string name; |
7369 | }; |
7370 | } |
7371 | } // namespace Catch |
7372 | |
7373 | #define INTERNAL_CATCH_GET_1_ARG(arg1, arg2, ...) arg1 |
7374 | #define INTERNAL_CATCH_GET_2_ARG(arg1, arg2, ...) arg2 |
7375 | |
7376 | #define INTERNAL_CATCH_BENCHMARK(BenchmarkName, name, benchmarkIndex)\ |
7377 | if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \ |
7378 | BenchmarkName = [&](int benchmarkIndex) |
7379 | |
7380 | #define INTERNAL_CATCH_BENCHMARK_ADVANCED(BenchmarkName, name)\ |
7381 | if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \ |
7382 | BenchmarkName = [&] |
7383 | |
7384 | // end catch_benchmark.hpp |
7385 | // start catch_constructor.hpp |
7386 | |
7387 | // Constructor and destructor helpers |
7388 | |
7389 | |
7390 | #include <type_traits> |
7391 | |
7392 | namespace Catch { |
7393 | namespace Benchmark { |
7394 | namespace Detail { |
7395 | template <typename T, bool Destruct> |
7396 | struct ObjectStorage |
7397 | { |
7398 | using TStorage = typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type; |
7399 | |
7400 | ObjectStorage() : data() {} |
7401 | |
7402 | ObjectStorage(const ObjectStorage& other) |
7403 | { |
7404 | new(&data) T(other.stored_object()); |
7405 | } |
7406 | |
7407 | ObjectStorage(ObjectStorage&& other) |
7408 | { |
7409 | new(&data) T(std::move(other.stored_object())); |
7410 | } |
7411 | |
7412 | ~ObjectStorage() { destruct_on_exit<T>(); } |
7413 | |
7414 | template <typename... Args> |
7415 | void construct(Args&&... args) |
7416 | { |
7417 | new (&data) T(std::forward<Args>(args)...); |
7418 | } |
7419 | |
7420 | template <bool AllowManualDestruction = !Destruct> |
7421 | typename std::enable_if<AllowManualDestruction>::type destruct() |
7422 | { |
7423 | stored_object().~T(); |
7424 | } |
7425 | |
7426 | private: |
7427 | // If this is a constructor benchmark, destruct the underlying object |
7428 | template <typename U> |
7429 | void destruct_on_exit(typename std::enable_if<Destruct, U>::type* = 0) { destruct<true>(); } |
7430 | // Otherwise, don't |
7431 | template <typename U> |
7432 | void destruct_on_exit(typename std::enable_if<!Destruct, U>::type* = 0) { } |
7433 | |
7434 | T& stored_object() { |
7435 | return *static_cast<T*>(static_cast<void*>(&data)); |
7436 | } |
7437 | |
7438 | T const& stored_object() const { |
7439 | return *static_cast<T*>(static_cast<void*>(&data)); |
7440 | } |
7441 | |
7442 | TStorage data; |
7443 | }; |
7444 | } |
7445 | |
7446 | template <typename T> |
7447 | using storage_for = Detail::ObjectStorage<T, true>; |
7448 | |
7449 | template <typename T> |
7450 | using destructable_object = Detail::ObjectStorage<T, false>; |
7451 | } |
7452 | } |
7453 | |
7454 | // end catch_constructor.hpp |
7455 | // end catch_benchmarking_all.hpp |
7456 | #endif |
7457 | |
7458 | #endif // ! CATCH_CONFIG_IMPL_ONLY |
7459 | |
7460 | #ifdef CATCH_IMPL |
7461 | // start catch_impl.hpp |
7462 | |
7463 | #ifdef __clang__ |
7464 | #pragma clang diagnostic push |
7465 | #pragma clang diagnostic ignored "-Wweak-vtables" |
7466 | #endif |
7467 | |
7468 | // Keep these here for external reporters |
7469 | // start catch_test_case_tracker.h |
7470 | |
7471 | #include <string> |
7472 | #include <vector> |
7473 | #include <memory> |
7474 | |
7475 | namespace Catch { |
7476 | namespace TestCaseTracking { |
7477 | |
7478 | struct NameAndLocation { |
7479 | std::string name; |
7480 | SourceLineInfo location; |
7481 | |
7482 | NameAndLocation( std::string const& _name, SourceLineInfo const& _location ); |
7483 | friend bool operator==(NameAndLocation const& lhs, NameAndLocation const& rhs) { |
7484 | return lhs.name == rhs.name |
7485 | && lhs.location == rhs.location; |
7486 | } |
7487 | }; |
7488 | |
7489 | class ITracker; |
7490 | |
7491 | using ITrackerPtr = std::shared_ptr<ITracker>; |
7492 | |
7493 | class ITracker { |
7494 | NameAndLocation m_nameAndLocation; |
7495 | |
7496 | public: |
7497 | ITracker(NameAndLocation const& nameAndLoc) : |
7498 | m_nameAndLocation(nameAndLoc) |
7499 | {} |
7500 | |
7501 | // static queries |
7502 | NameAndLocation const& nameAndLocation() const { |
7503 | return m_nameAndLocation; |
7504 | } |
7505 | |
7506 | virtual ~ITracker(); |
7507 | |
7508 | // dynamic queries |
7509 | virtual bool isComplete() const = 0; // Successfully completed or failed |
7510 | virtual bool isSuccessfullyCompleted() const = 0; |
7511 | virtual bool isOpen() const = 0; // Started but not complete |
7512 | virtual bool hasChildren() const = 0; |
7513 | virtual bool hasStarted() const = 0; |
7514 | |
7515 | virtual ITracker& parent() = 0; |
7516 | |
7517 | // actions |
7518 | virtual void close() = 0; // Successfully complete |
7519 | virtual void fail() = 0; |
7520 | virtual void markAsNeedingAnotherRun() = 0; |
7521 | |
7522 | virtual void addChild( ITrackerPtr const& child ) = 0; |
7523 | virtual ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) = 0; |
7524 | virtual void openChild() = 0; |
7525 | |
7526 | // Debug/ checking |
7527 | virtual bool isSectionTracker() const = 0; |
7528 | virtual bool isGeneratorTracker() const = 0; |
7529 | }; |
7530 | |
7531 | class TrackerContext { |
7532 | |
7533 | enum RunState { |
7534 | NotStarted, |
7535 | Executing, |
7536 | CompletedCycle |
7537 | }; |
7538 | |
7539 | ITrackerPtr m_rootTracker; |
7540 | ITracker* m_currentTracker = nullptr; |
7541 | RunState m_runState = NotStarted; |
7542 | |
7543 | public: |
7544 | |
7545 | ITracker& startRun(); |
7546 | void endRun(); |
7547 | |
7548 | void startCycle(); |
7549 | void completeCycle(); |
7550 | |
7551 | bool completedCycle() const; |
7552 | ITracker& currentTracker(); |
7553 | void setCurrentTracker( ITracker* tracker ); |
7554 | }; |
7555 | |
7556 | class TrackerBase : public ITracker { |
7557 | protected: |
7558 | enum CycleState { |
7559 | NotStarted, |
7560 | Executing, |
7561 | ExecutingChildren, |
7562 | NeedsAnotherRun, |
7563 | CompletedSuccessfully, |
7564 | Failed |
7565 | }; |
7566 | |
7567 | using Children = std::vector<ITrackerPtr>; |
7568 | TrackerContext& m_ctx; |
7569 | ITracker* m_parent; |
7570 | Children m_children; |
7571 | CycleState m_runState = NotStarted; |
7572 | |
7573 | public: |
7574 | TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); |
7575 | |
7576 | bool isComplete() const override; |
7577 | bool isSuccessfullyCompleted() const override; |
7578 | bool isOpen() const override; |
7579 | bool hasChildren() const override; |
7580 | bool hasStarted() const override { |
7581 | return m_runState != NotStarted; |
7582 | } |
7583 | |
7584 | void addChild( ITrackerPtr const& child ) override; |
7585 | |
7586 | ITrackerPtr findChild( NameAndLocation const& nameAndLocation ) override; |
7587 | ITracker& parent() override; |
7588 | |
7589 | void openChild() override; |
7590 | |
7591 | bool isSectionTracker() const override; |
7592 | bool isGeneratorTracker() const override; |
7593 | |
7594 | void open(); |
7595 | |
7596 | void close() override; |
7597 | void fail() override; |
7598 | void markAsNeedingAnotherRun() override; |
7599 | |
7600 | private: |
7601 | void moveToParent(); |
7602 | void moveToThis(); |
7603 | }; |
7604 | |
7605 | class SectionTracker : public TrackerBase { |
7606 | std::vector<std::string> m_filters; |
7607 | std::string m_trimmed_name; |
7608 | public: |
7609 | SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); |
7610 | |
7611 | bool isSectionTracker() const override; |
7612 | |
7613 | bool isComplete() const override; |
7614 | |
7615 | static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ); |
7616 | |
7617 | void tryOpen(); |
7618 | |
7619 | void addInitialFilters( std::vector<std::string> const& filters ); |
7620 | void addNextFilters( std::vector<std::string> const& filters ); |
7621 | //! Returns filters active in this tracker |
7622 | std::vector<std::string> const& getFilters() const; |
7623 | //! Returns whitespace-trimmed name of the tracked section |
7624 | std::string const& trimmedName() const; |
7625 | }; |
7626 | |
7627 | } // namespace TestCaseTracking |
7628 | |
7629 | using TestCaseTracking::ITracker; |
7630 | using TestCaseTracking::TrackerContext; |
7631 | using TestCaseTracking::SectionTracker; |
7632 | |
7633 | } // namespace Catch |
7634 | |
7635 | // end catch_test_case_tracker.h |
7636 | |
7637 | // start catch_leak_detector.h |
7638 | |
7639 | namespace Catch { |
7640 | |
7641 | struct LeakDetector { |
7642 | LeakDetector(); |
7643 | ~LeakDetector(); |
7644 | }; |
7645 | |
7646 | } |
7647 | // end catch_leak_detector.h |
7648 | // Cpp files will be included in the single-header file here |
7649 | // start catch_stats.cpp |
7650 | |
7651 | // Statistical analysis tools |
7652 | |
7653 | #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) |
7654 | |
7655 | #include <cassert> |
7656 | #include <random> |
7657 | |
7658 | #if defined(CATCH_CONFIG_USE_ASYNC) |
7659 | #include <future> |
7660 | #endif |
7661 | |
7662 | namespace { |
7663 | double erf_inv(double x) { |
7664 | // Code accompanying the article "Approximating the erfinv function" in GPU Computing Gems, Volume 2 |
7665 | double w, p; |
7666 | |
7667 | w = -log((1.0 - x) * (1.0 + x)); |
7668 | |
7669 | if (w < 6.250000) { |
7670 | w = w - 3.125000; |
7671 | p = -3.6444120640178196996e-21; |
7672 | p = -1.685059138182016589e-19 + p * w; |
7673 | p = 1.2858480715256400167e-18 + p * w; |
7674 | p = 1.115787767802518096e-17 + p * w; |
7675 | p = -1.333171662854620906e-16 + p * w; |
7676 | p = 2.0972767875968561637e-17 + p * w; |
7677 | p = 6.6376381343583238325e-15 + p * w; |
7678 | p = -4.0545662729752068639e-14 + p * w; |
7679 | p = -8.1519341976054721522e-14 + p * w; |
7680 | p = 2.6335093153082322977e-12 + p * w; |
7681 | p = -1.2975133253453532498e-11 + p * w; |
7682 | p = -5.4154120542946279317e-11 + p * w; |
7683 | p = 1.051212273321532285e-09 + p * w; |
7684 | p = -4.1126339803469836976e-09 + p * w; |
7685 | p = -2.9070369957882005086e-08 + p * w; |
7686 | p = 4.2347877827932403518e-07 + p * w; |
7687 | p = -1.3654692000834678645e-06 + p * w; |
7688 | p = -1.3882523362786468719e-05 + p * w; |
7689 | p = 0.0001867342080340571352 + p * w; |
7690 | p = -0.00074070253416626697512 + p * w; |
7691 | p = -0.0060336708714301490533 + p * w; |
7692 | p = 0.24015818242558961693 + p * w; |
7693 | p = 1.6536545626831027356 + p * w; |
7694 | } else if (w < 16.000000) { |
7695 | w = sqrt(w) - 3.250000; |
7696 | p = 2.2137376921775787049e-09; |
7697 | p = 9.0756561938885390979e-08 + p * w; |
7698 | p = -2.7517406297064545428e-07 + p * w; |
7699 | p = 1.8239629214389227755e-08 + p * w; |
7700 | p = 1.5027403968909827627e-06 + p * w; |
7701 | p = -4.013867526981545969e-06 + p * w; |
7702 | p = 2.9234449089955446044e-06 + p * w; |
7703 | p = 1.2475304481671778723e-05 + p * w; |
7704 | p = -4.7318229009055733981e-05 + p * w; |
7705 | p = 6.8284851459573175448e-05 + p * w; |
7706 | p = 2.4031110387097893999e-05 + p * w; |
7707 | p = -0.0003550375203628474796 + p * w; |
7708 | p = 0.00095328937973738049703 + p * w; |
7709 | p = -0.0016882755560235047313 + p * w; |
7710 | p = 0.0024914420961078508066 + p * w; |
7711 | p = -0.0037512085075692412107 + p * w; |
7712 | p = 0.005370914553590063617 + p * w; |
7713 | p = 1.0052589676941592334 + p * w; |
7714 | p = 3.0838856104922207635 + p * w; |
7715 | } else { |
7716 | w = sqrt(w) - 5.000000; |
7717 | p = -2.7109920616438573243e-11; |
7718 | p = -2.5556418169965252055e-10 + p * w; |
7719 | p = 1.5076572693500548083e-09 + p * w; |
7720 | p = -3.7894654401267369937e-09 + p * w; |
7721 | p = 7.6157012080783393804e-09 + p * w; |
7722 | p = -1.4960026627149240478e-08 + p * w; |
7723 | p = 2.9147953450901080826e-08 + p * w; |
7724 | p = -6.7711997758452339498e-08 + p * w; |
7725 | p = 2.2900482228026654717e-07 + p * w; |
7726 | p = -9.9298272942317002539e-07 + p * w; |
7727 | p = 4.5260625972231537039e-06 + p * w; |
7728 | p = -1.9681778105531670567e-05 + p * w; |
7729 | p = 7.5995277030017761139e-05 + p * w; |
7730 | p = -0.00021503011930044477347 + p * w; |
7731 | p = -0.00013871931833623122026 + p * w; |
7732 | p = 1.0103004648645343977 + p * w; |
7733 | p = 4.8499064014085844221 + p * w; |
7734 | } |
7735 | return p * x; |
7736 | } |
7737 | |
7738 | double standard_deviation(std::vector<double>::iterator first, std::vector<double>::iterator last) { |
7739 | auto m = Catch::Benchmark::Detail::mean(first, last); |
7740 | double variance = std::accumulate(first, last, 0., [m](double a, double b) { |
7741 | double diff = b - m; |
7742 | return a + diff * diff; |
7743 | }) / (last - first); |
7744 | return std::sqrt(variance); |
7745 | } |
7746 | |
7747 | } |
7748 | |
7749 | namespace Catch { |
7750 | namespace Benchmark { |
7751 | namespace Detail { |
7752 | |
7753 | double weighted_average_quantile(int k, int q, std::vector<double>::iterator first, std::vector<double>::iterator last) { |
7754 | auto count = last - first; |
7755 | double idx = (count - 1) * k / static_cast<double>(q); |
7756 | int j = static_cast<int>(idx); |
7757 | double g = idx - j; |
7758 | std::nth_element(first, first + j, last); |
7759 | auto xj = first[j]; |
7760 | if (g == 0) return xj; |
7761 | |
7762 | auto xj1 = *std::min_element(first + (j + 1), last); |
7763 | return xj + g * (xj1 - xj); |
7764 | } |
7765 | |
7766 | double erfc_inv(double x) { |
7767 | return erf_inv(1.0 - x); |
7768 | } |
7769 | |
7770 | double normal_quantile(double p) { |
7771 | static const double ROOT_TWO = std::sqrt(2.0); |
7772 | |
7773 | double result = 0.0; |
7774 | assert(p >= 0 && p <= 1); |
7775 | if (p < 0 || p > 1) { |
7776 | return result; |
7777 | } |
7778 | |
7779 | result = -erfc_inv(2.0 * p); |
7780 | // result *= normal distribution standard deviation (1.0) * sqrt(2) |
7781 | result *= /*sd * */ ROOT_TWO; |
7782 | // result += normal disttribution mean (0) |
7783 | return result; |
7784 | } |
7785 | |
7786 | double outlier_variance(Estimate<double> mean, Estimate<double> stddev, int n) { |
7787 | double sb = stddev.point; |
7788 | double mn = mean.point / n; |
7789 | double mg_min = mn / 2.; |
7790 | double sg = (std::min)(mg_min / 4., sb / std::sqrt(n)); |
7791 | double sg2 = sg * sg; |
7792 | double sb2 = sb * sb; |
7793 | |
7794 | auto c_max = [n, mn, sb2, sg2](double x) -> double { |
7795 | double k = mn - x; |
7796 | double d = k * k; |
7797 | double nd = n * d; |
7798 | double k0 = -n * nd; |
7799 | double k1 = sb2 - n * sg2 + nd; |
7800 | double det = k1 * k1 - 4 * sg2 * k0; |
7801 | return (int)(-2. * k0 / (k1 + std::sqrt(det))); |
7802 | }; |
7803 | |
7804 | auto var_out = [n, sb2, sg2](double c) { |
7805 | double nc = n - c; |
7806 | return (nc / n) * (sb2 - nc * sg2); |
7807 | }; |
7808 | |
7809 | return (std::min)(var_out(1), var_out((std::min)(c_max(0.), c_max(mg_min)))) / sb2; |
7810 | } |
7811 | |
7812 | bootstrap_analysis analyse_samples(double confidence_level, int n_resamples, std::vector<double>::iterator first, std::vector<double>::iterator last) { |
7813 | CATCH_INTERNAL_START_WARNINGS_SUPPRESSION |
7814 | CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS |
7815 | static std::random_device entropy; |
7816 | CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION |
7817 | |
7818 | auto n = static_cast<int>(last - first); // seriously, one can't use integral types without hell in C++ |
7819 | |
7820 | auto mean = &Detail::mean<std::vector<double>::iterator>; |
7821 | auto stddev = &standard_deviation; |
7822 | |
7823 | #if defined(CATCH_CONFIG_USE_ASYNC) |
7824 | auto Estimate = [=](double(*f)(std::vector<double>::iterator, std::vector<double>::iterator)) { |
7825 | auto seed = entropy(); |
7826 | return std::async(std::launch::async, [=] { |
7827 | std::mt19937 rng(seed); |
7828 | auto resampled = resample(rng, n_resamples, first, last, f); |
7829 | return bootstrap(confidence_level, first, last, resampled, f); |
7830 | }); |
7831 | }; |
7832 | |
7833 | auto mean_future = Estimate(mean); |
7834 | auto stddev_future = Estimate(stddev); |
7835 | |
7836 | auto mean_estimate = mean_future.get(); |
7837 | auto stddev_estimate = stddev_future.get(); |
7838 | #else |
7839 | auto Estimate = [=](double(*f)(std::vector<double>::iterator, std::vector<double>::iterator)) { |
7840 | auto seed = entropy(); |
7841 | std::mt19937 rng(seed); |
7842 | auto resampled = resample(rng, n_resamples, first, last, f); |
7843 | return bootstrap(confidence_level, first, last, resampled, f); |
7844 | }; |
7845 | |
7846 | auto mean_estimate = Estimate(mean); |
7847 | auto stddev_estimate = Estimate(stddev); |
7848 | #endif // CATCH_USE_ASYNC |
7849 | |
7850 | double outlier_variance = Detail::outlier_variance(mean_estimate, stddev_estimate, n); |
7851 | |
7852 | return { mean_estimate, stddev_estimate, outlier_variance }; |
7853 | } |
7854 | } // namespace Detail |
7855 | } // namespace Benchmark |
7856 | } // namespace Catch |
7857 | |
7858 | #endif // CATCH_CONFIG_ENABLE_BENCHMARKING |
7859 | // end catch_stats.cpp |
7860 | // start catch_approx.cpp |
7861 | |
7862 | #include <cmath> |
7863 | #include <limits> |
7864 | |
7865 | namespace { |
7866 | |
7867 | // Performs equivalent check of std::fabs(lhs - rhs) <= margin |
7868 | // But without the subtraction to allow for INFINITY in comparison |
7869 | bool marginComparison(double lhs, double rhs, double margin) { |
7870 | return (lhs + margin >= rhs) && (rhs + margin >= lhs); |
7871 | } |
7872 | |
7873 | } |
7874 | |
7875 | namespace Catch { |
7876 | namespace Detail { |
7877 | |
7878 | Approx::Approx ( double value ) |
7879 | : m_epsilon( std::numeric_limits<float>::epsilon()*100 ), |
7880 | m_margin( 0.0 ), |
7881 | m_scale( 0.0 ), |
7882 | m_value( value ) |
7883 | {} |
7884 | |
7885 | Approx Approx::custom() { |
7886 | return Approx( 0 ); |
7887 | } |
7888 | |
7889 | Approx Approx::operator-() const { |
7890 | auto temp(*this); |
7891 | temp.m_value = -temp.m_value; |
7892 | return temp; |
7893 | } |
7894 | |
7895 | std::string Approx::toString() const { |
7896 | ReusableStringStream rss; |
7897 | rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )" ; |
7898 | return rss.str(); |
7899 | } |
7900 | |
7901 | bool Approx::equalityComparisonImpl(const double other) const { |
7902 | // First try with fixed margin, then compute margin based on epsilon, scale and Approx's value |
7903 | // Thanks to Richard Harris for his help refining the scaled margin value |
7904 | return marginComparison(m_value, other, m_margin) |
7905 | || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(std::isinf(m_value)? 0 : m_value))); |
7906 | } |
7907 | |
7908 | void Approx::setMargin(double newMargin) { |
7909 | CATCH_ENFORCE(newMargin >= 0, |
7910 | "Invalid Approx::margin: " << newMargin << '.' |
7911 | << " Approx::Margin has to be non-negative." ); |
7912 | m_margin = newMargin; |
7913 | } |
7914 | |
7915 | void Approx::setEpsilon(double newEpsilon) { |
7916 | CATCH_ENFORCE(newEpsilon >= 0 && newEpsilon <= 1.0, |
7917 | "Invalid Approx::epsilon: " << newEpsilon << '.' |
7918 | << " Approx::epsilon has to be in [0, 1]" ); |
7919 | m_epsilon = newEpsilon; |
7920 | } |
7921 | |
7922 | } // end namespace Detail |
7923 | |
7924 | namespace literals { |
7925 | Detail::Approx operator "" _a(long double val) { |
7926 | return Detail::Approx(val); |
7927 | } |
7928 | Detail::Approx operator "" _a(unsigned long long val) { |
7929 | return Detail::Approx(val); |
7930 | } |
7931 | } // end namespace literals |
7932 | |
7933 | std::string StringMaker<Catch::Detail::Approx>::convert(Catch::Detail::Approx const& value) { |
7934 | return value.toString(); |
7935 | } |
7936 | |
7937 | } // end namespace Catch |
7938 | // end catch_approx.cpp |
7939 | // start catch_assertionhandler.cpp |
7940 | |
7941 | // start catch_debugger.h |
7942 | |
7943 | namespace Catch { |
7944 | bool isDebuggerActive(); |
7945 | } |
7946 | |
7947 | #ifdef CATCH_PLATFORM_MAC |
7948 | |
7949 | #if defined(__i386__) || defined(__x86_64__) |
7950 | #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */ |
7951 | #elif defined(__aarch64__) |
7952 | #define CATCH_TRAP() __asm__(".inst 0xd4200000") |
7953 | #endif |
7954 | |
7955 | #elif defined(CATCH_PLATFORM_IPHONE) |
7956 | |
7957 | // use inline assembler |
7958 | #if defined(__i386__) || defined(__x86_64__) |
7959 | #define CATCH_TRAP() __asm__("int $3") |
7960 | #elif defined(__aarch64__) |
7961 | #define CATCH_TRAP() __asm__(".inst 0xd4200000") |
7962 | #elif defined(__arm__) && !defined(__thumb__) |
7963 | #define CATCH_TRAP() __asm__(".inst 0xe7f001f0") |
7964 | #elif defined(__arm__) && defined(__thumb__) |
7965 | #define CATCH_TRAP() __asm__(".inst 0xde01") |
7966 | #endif |
7967 | |
7968 | #elif defined(CATCH_PLATFORM_LINUX) |
7969 | // If we can use inline assembler, do it because this allows us to break |
7970 | // directly at the location of the failing check instead of breaking inside |
7971 | // raise() called from it, i.e. one stack frame below. |
7972 | #if defined(__GNUC__) && (defined(__i386) || defined(__x86_64)) |
7973 | #define CATCH_TRAP() asm volatile ("int $3") /* NOLINT */ |
7974 | #else // Fall back to the generic way. |
7975 | #include <signal.h> |
7976 | |
7977 | #define CATCH_TRAP() raise(SIGTRAP) |
7978 | #endif |
7979 | #elif defined(_MSC_VER) |
7980 | #define CATCH_TRAP() __debugbreak() |
7981 | #elif defined(__MINGW32__) |
7982 | extern "C" __declspec(dllimport) void __stdcall DebugBreak(); |
7983 | #define CATCH_TRAP() DebugBreak() |
7984 | #endif |
7985 | |
7986 | #ifndef CATCH_BREAK_INTO_DEBUGGER |
7987 | #ifdef CATCH_TRAP |
7988 | #define CATCH_BREAK_INTO_DEBUGGER() []{ if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } }() |
7989 | #else |
7990 | #define CATCH_BREAK_INTO_DEBUGGER() []{}() |
7991 | #endif |
7992 | #endif |
7993 | |
7994 | // end catch_debugger.h |
7995 | // start catch_run_context.h |
7996 | |
7997 | // start catch_fatal_condition.h |
7998 | |
7999 | #include <cassert> |
8000 | |
8001 | namespace Catch { |
8002 | |
8003 | // Wrapper for platform-specific fatal error (signals/SEH) handlers |
8004 | // |
8005 | // Tries to be cooperative with other handlers, and not step over |
8006 | // other handlers. This means that unknown structured exceptions |
8007 | // are passed on, previous signal handlers are called, and so on. |
8008 | // |
8009 | // Can only be instantiated once, and assumes that once a signal |
8010 | // is caught, the binary will end up terminating. Thus, there |
8011 | class FatalConditionHandler { |
8012 | bool m_started = false; |
8013 | |
8014 | // Install/disengage implementation for specific platform. |
8015 | // Should be if-defed to work on current platform, can assume |
8016 | // engage-disengage 1:1 pairing. |
8017 | void engage_platform(); |
8018 | void disengage_platform(); |
8019 | public: |
8020 | // Should also have platform-specific implementations as needed |
8021 | FatalConditionHandler(); |
8022 | ~FatalConditionHandler(); |
8023 | |
8024 | void engage() { |
8025 | assert(!m_started && "Handler cannot be installed twice." ); |
8026 | m_started = true; |
8027 | engage_platform(); |
8028 | } |
8029 | |
8030 | void disengage() { |
8031 | assert(m_started && "Handler cannot be uninstalled without being installed first" ); |
8032 | m_started = false; |
8033 | disengage_platform(); |
8034 | } |
8035 | }; |
8036 | |
8037 | //! Simple RAII guard for (dis)engaging the FatalConditionHandler |
8038 | class FatalConditionHandlerGuard { |
8039 | FatalConditionHandler* m_handler; |
8040 | public: |
8041 | FatalConditionHandlerGuard(FatalConditionHandler* handler): |
8042 | m_handler(handler) { |
8043 | m_handler->engage(); |
8044 | } |
8045 | ~FatalConditionHandlerGuard() { |
8046 | m_handler->disengage(); |
8047 | } |
8048 | }; |
8049 | |
8050 | } // end namespace Catch |
8051 | |
8052 | // end catch_fatal_condition.h |
8053 | #include <string> |
8054 | |
8055 | namespace Catch { |
8056 | |
8057 | struct IMutableContext; |
8058 | |
8059 | /////////////////////////////////////////////////////////////////////////// |
8060 | |
8061 | class RunContext : public IResultCapture, public IRunner { |
8062 | |
8063 | public: |
8064 | RunContext( RunContext const& ) = delete; |
8065 | RunContext& operator =( RunContext const& ) = delete; |
8066 | |
8067 | explicit RunContext( IConfigPtr const& _config, IStreamingReporterPtr&& reporter ); |
8068 | |
8069 | ~RunContext() override; |
8070 | |
8071 | void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ); |
8072 | void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ); |
8073 | |
8074 | Totals runTest(TestCase const& testCase); |
8075 | |
8076 | IConfigPtr config() const; |
8077 | IStreamingReporter& reporter() const; |
8078 | |
8079 | public: // IResultCapture |
8080 | |
8081 | // Assertion handlers |
8082 | void handleExpr |
8083 | ( AssertionInfo const& info, |
8084 | ITransientExpression const& expr, |
8085 | AssertionReaction& reaction ) override; |
8086 | void handleMessage |
8087 | ( AssertionInfo const& info, |
8088 | ResultWas::OfType resultType, |
8089 | StringRef const& message, |
8090 | AssertionReaction& reaction ) override; |
8091 | void handleUnexpectedExceptionNotThrown |
8092 | ( AssertionInfo const& info, |
8093 | AssertionReaction& reaction ) override; |
8094 | void handleUnexpectedInflightException |
8095 | ( AssertionInfo const& info, |
8096 | std::string const& message, |
8097 | AssertionReaction& reaction ) override; |
8098 | void handleIncomplete |
8099 | ( AssertionInfo const& info ) override; |
8100 | void handleNonExpr |
8101 | ( AssertionInfo const &info, |
8102 | ResultWas::OfType resultType, |
8103 | AssertionReaction &reaction ) override; |
8104 | |
8105 | bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) override; |
8106 | |
8107 | void sectionEnded( SectionEndInfo const& endInfo ) override; |
8108 | void sectionEndedEarly( SectionEndInfo const& endInfo ) override; |
8109 | |
8110 | auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override; |
8111 | |
8112 | #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) |
8113 | void benchmarkPreparing( std::string const& name ) override; |
8114 | void benchmarkStarting( BenchmarkInfo const& info ) override; |
8115 | void benchmarkEnded( BenchmarkStats<> const& stats ) override; |
8116 | void benchmarkFailed( std::string const& error ) override; |
8117 | #endif // CATCH_CONFIG_ENABLE_BENCHMARKING |
8118 | |
8119 | void pushScopedMessage( MessageInfo const& message ) override; |
8120 | void popScopedMessage( MessageInfo const& message ) override; |
8121 | |
8122 | void emplaceUnscopedMessage( MessageBuilder const& builder ) override; |
8123 | |
8124 | std::string getCurrentTestName() const override; |
8125 | |
8126 | const AssertionResult* getLastResult() const override; |
8127 | |
8128 | void exceptionEarlyReported() override; |
8129 | |
8130 | void handleFatalErrorCondition( StringRef message ) override; |
8131 | |
8132 | bool lastAssertionPassed() override; |
8133 | |
8134 | void assertionPassed() override; |
8135 | |
8136 | public: |
8137 | // !TBD We need to do this another way! |
8138 | bool aborting() const final; |
8139 | |
8140 | private: |
8141 | |
8142 | void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ); |
8143 | void invokeActiveTestCase(); |
8144 | |
8145 | void resetAssertionInfo(); |
8146 | bool testForMissingAssertions( Counts& assertions ); |
8147 | |
8148 | void assertionEnded( AssertionResult const& result ); |
8149 | void reportExpr |
8150 | ( AssertionInfo const &info, |
8151 | ResultWas::OfType resultType, |
8152 | ITransientExpression const *expr, |
8153 | bool negated ); |
8154 | |
8155 | void populateReaction( AssertionReaction& reaction ); |
8156 | |
8157 | private: |
8158 | |
8159 | void handleUnfinishedSections(); |
8160 | |
8161 | TestRunInfo m_runInfo; |
8162 | IMutableContext& m_context; |
8163 | TestCase const* m_activeTestCase = nullptr; |
8164 | ITracker* m_testCaseTracker = nullptr; |
8165 | Option<AssertionResult> m_lastResult; |
8166 | |
8167 | IConfigPtr m_config; |
8168 | Totals m_totals; |
8169 | IStreamingReporterPtr m_reporter; |
8170 | std::vector<MessageInfo> m_messages; |
8171 | std::vector<ScopedMessage> m_messageScopes; /* Keeps owners of so-called unscoped messages. */ |
8172 | AssertionInfo m_lastAssertionInfo; |
8173 | std::vector<SectionEndInfo> m_unfinishedSections; |
8174 | std::vector<ITracker*> m_activeSections; |
8175 | TrackerContext m_trackerContext; |
8176 | FatalConditionHandler m_fatalConditionhandler; |
8177 | bool m_lastAssertionPassed = false; |
8178 | bool m_shouldReportUnexpected = true; |
8179 | bool m_includeSuccessfulResults; |
8180 | }; |
8181 | |
8182 | void seedRng(IConfig const& config); |
8183 | unsigned int rngSeed(); |
8184 | } // end namespace Catch |
8185 | |
8186 | // end catch_run_context.h |
8187 | namespace Catch { |
8188 | |
8189 | namespace { |
8190 | auto operator <<( std::ostream& os, ITransientExpression const& expr ) -> std::ostream& { |
8191 | expr.streamReconstructedExpression( os ); |
8192 | return os; |
8193 | } |
8194 | } |
8195 | |
8196 | LazyExpression::LazyExpression( bool isNegated ) |
8197 | : m_isNegated( isNegated ) |
8198 | {} |
8199 | |
8200 | LazyExpression::LazyExpression( LazyExpression const& other ) : m_isNegated( other.m_isNegated ) {} |
8201 | |
8202 | LazyExpression::operator bool() const { |
8203 | return m_transientExpression != nullptr; |
8204 | } |
8205 | |
8206 | auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream& { |
8207 | if( lazyExpr.m_isNegated ) |
8208 | os << "!" ; |
8209 | |
8210 | if( lazyExpr ) { |
8211 | if( lazyExpr.m_isNegated && lazyExpr.m_transientExpression->isBinaryExpression() ) |
8212 | os << "(" << *lazyExpr.m_transientExpression << ")" ; |
8213 | else |
8214 | os << *lazyExpr.m_transientExpression; |
8215 | } |
8216 | else { |
8217 | os << "{** error - unchecked empty expression requested **}" ; |
8218 | } |
8219 | return os; |
8220 | } |
8221 | |
8222 | AssertionHandler::AssertionHandler |
8223 | ( StringRef const& macroName, |
8224 | SourceLineInfo const& lineInfo, |
8225 | StringRef capturedExpression, |
8226 | ResultDisposition::Flags resultDisposition ) |
8227 | : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition }, |
8228 | m_resultCapture( getResultCapture() ) |
8229 | {} |
8230 | |
8231 | void AssertionHandler::handleExpr( ITransientExpression const& expr ) { |
8232 | m_resultCapture.handleExpr( m_assertionInfo, expr, m_reaction ); |
8233 | } |
8234 | void AssertionHandler::handleMessage(ResultWas::OfType resultType, StringRef const& message) { |
8235 | m_resultCapture.handleMessage( m_assertionInfo, resultType, message, m_reaction ); |
8236 | } |
8237 | |
8238 | auto AssertionHandler::allowThrows() const -> bool { |
8239 | return getCurrentContext().getConfig()->allowThrows(); |
8240 | } |
8241 | |
8242 | void AssertionHandler::complete() { |
8243 | setCompleted(); |
8244 | if( m_reaction.shouldDebugBreak ) { |
8245 | |
8246 | // If you find your debugger stopping you here then go one level up on the |
8247 | // call-stack for the code that caused it (typically a failed assertion) |
8248 | |
8249 | // (To go back to the test and change execution, jump over the throw, next) |
8250 | CATCH_BREAK_INTO_DEBUGGER(); |
8251 | } |
8252 | if (m_reaction.shouldThrow) { |
8253 | #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) |
8254 | throw Catch::TestFailureException(); |
8255 | #else |
8256 | CATCH_ERROR( "Test failure requires aborting test!" ); |
8257 | #endif |
8258 | } |
8259 | } |
8260 | void AssertionHandler::setCompleted() { |
8261 | m_completed = true; |
8262 | } |
8263 | |
8264 | void AssertionHandler::handleUnexpectedInflightException() { |
8265 | m_resultCapture.handleUnexpectedInflightException( m_assertionInfo, Catch::translateActiveException(), m_reaction ); |
8266 | } |
8267 | |
8268 | void AssertionHandler::handleExceptionThrownAsExpected() { |
8269 | m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); |
8270 | } |
8271 | void AssertionHandler::handleExceptionNotThrownAsExpected() { |
8272 | m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); |
8273 | } |
8274 | |
8275 | void AssertionHandler::handleUnexpectedExceptionNotThrown() { |
8276 | m_resultCapture.handleUnexpectedExceptionNotThrown( m_assertionInfo, m_reaction ); |
8277 | } |
8278 | |
8279 | void AssertionHandler::handleThrowingCallSkipped() { |
8280 | m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction); |
8281 | } |
8282 | |
8283 | // This is the overload that takes a string and infers the Equals matcher from it |
8284 | // The more general overload, that takes any string matcher, is in catch_capture_matchers.cpp |
8285 | void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef const& matcherString ) { |
8286 | handleExceptionMatchExpr( handler, Matchers::Equals( str ), matcherString ); |
8287 | } |
8288 | |
8289 | } // namespace Catch |
8290 | // end catch_assertionhandler.cpp |
8291 | // start catch_assertionresult.cpp |
8292 | |
8293 | namespace Catch { |
8294 | AssertionResultData::AssertionResultData(ResultWas::OfType _resultType, LazyExpression const & _lazyExpression): |
8295 | lazyExpression(_lazyExpression), |
8296 | resultType(_resultType) {} |
8297 | |
8298 | std::string AssertionResultData::reconstructExpression() const { |
8299 | |
8300 | if( reconstructedExpression.empty() ) { |
8301 | if( lazyExpression ) { |
8302 | ReusableStringStream rss; |
8303 | rss << lazyExpression; |
8304 | reconstructedExpression = rss.str(); |
8305 | } |
8306 | } |
8307 | return reconstructedExpression; |
8308 | } |
8309 | |
8310 | AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) |
8311 | : m_info( info ), |
8312 | m_resultData( data ) |
8313 | {} |
8314 | |
8315 | // Result was a success |
8316 | bool AssertionResult::succeeded() const { |
8317 | return Catch::isOk( m_resultData.resultType ); |
8318 | } |
8319 | |
8320 | // Result was a success, or failure is suppressed |
8321 | bool AssertionResult::isOk() const { |
8322 | return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition ); |
8323 | } |
8324 | |
8325 | ResultWas::OfType AssertionResult::getResultType() const { |
8326 | return m_resultData.resultType; |
8327 | } |
8328 | |
8329 | bool AssertionResult::hasExpression() const { |
8330 | return !m_info.capturedExpression.empty(); |
8331 | } |
8332 | |
8333 | bool AssertionResult::hasMessage() const { |
8334 | return !m_resultData.message.empty(); |
8335 | } |
8336 | |
8337 | std::string AssertionResult::getExpression() const { |
8338 | // Possibly overallocating by 3 characters should be basically free |
8339 | std::string expr; expr.reserve(m_info.capturedExpression.size() + 3); |
8340 | if (isFalseTest(m_info.resultDisposition)) { |
8341 | expr += "!(" ; |
8342 | } |
8343 | expr += m_info.capturedExpression; |
8344 | if (isFalseTest(m_info.resultDisposition)) { |
8345 | expr += ')'; |
8346 | } |
8347 | return expr; |
8348 | } |
8349 | |
8350 | std::string AssertionResult::getExpressionInMacro() const { |
8351 | std::string expr; |
8352 | if( m_info.macroName.empty() ) |
8353 | expr = static_cast<std::string>(m_info.capturedExpression); |
8354 | else { |
8355 | expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 ); |
8356 | expr += m_info.macroName; |
8357 | expr += "( " ; |
8358 | expr += m_info.capturedExpression; |
8359 | expr += " )" ; |
8360 | } |
8361 | return expr; |
8362 | } |
8363 | |
8364 | bool AssertionResult::hasExpandedExpression() const { |
8365 | return hasExpression() && getExpandedExpression() != getExpression(); |
8366 | } |
8367 | |
8368 | std::string AssertionResult::getExpandedExpression() const { |
8369 | std::string expr = m_resultData.reconstructExpression(); |
8370 | return expr.empty() |
8371 | ? getExpression() |
8372 | : expr; |
8373 | } |
8374 | |
8375 | std::string AssertionResult::getMessage() const { |
8376 | return m_resultData.message; |
8377 | } |
8378 | SourceLineInfo AssertionResult::getSourceInfo() const { |
8379 | return m_info.lineInfo; |
8380 | } |
8381 | |
8382 | StringRef AssertionResult::getTestMacroName() const { |
8383 | return m_info.macroName; |
8384 | } |
8385 | |
8386 | } // end namespace Catch |
8387 | // end catch_assertionresult.cpp |
8388 | // start catch_capture_matchers.cpp |
8389 | |
8390 | namespace Catch { |
8391 | |
8392 | using StringMatcher = Matchers::Impl::MatcherBase<std::string>; |
8393 | |
8394 | // This is the general overload that takes a any string matcher |
8395 | // There is another overload, in catch_assertionhandler.h/.cpp, that only takes a string and infers |
8396 | // the Equals matcher (so the header does not mention matchers) |
8397 | void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString ) { |
8398 | std::string exceptionMessage = Catch::translateActiveException(); |
8399 | MatchExpr<std::string, StringMatcher const&> expr( exceptionMessage, matcher, matcherString ); |
8400 | handler.handleExpr( expr ); |
8401 | } |
8402 | |
8403 | } // namespace Catch |
8404 | // end catch_capture_matchers.cpp |
8405 | // start catch_commandline.cpp |
8406 | |
8407 | // start catch_commandline.h |
8408 | |
8409 | // start catch_clara.h |
8410 | |
8411 | // Use Catch's value for console width (store Clara's off to the side, if present) |
8412 | #ifdef CLARA_CONFIG_CONSOLE_WIDTH |
8413 | #define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH |
8414 | #undef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH |
8415 | #endif |
8416 | #define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH-1 |
8417 | |
8418 | #ifdef __clang__ |
8419 | #pragma clang diagnostic push |
8420 | #pragma clang diagnostic ignored "-Wweak-vtables" |
8421 | #pragma clang diagnostic ignored "-Wexit-time-destructors" |
8422 | #pragma clang diagnostic ignored "-Wshadow" |
8423 | #endif |
8424 | |
8425 | // start clara.hpp |
8426 | // Copyright 2017 Two Blue Cubes Ltd. All rights reserved. |
8427 | // |
8428 | // Distributed under the Boost Software License, Version 1.0. (See accompanying |
8429 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
8430 | // |
8431 | // See https://github.com/philsquared/Clara for more details |
8432 | |
8433 | // Clara v1.1.5 |
8434 | |
8435 | |
8436 | #ifndef CATCH_CLARA_CONFIG_CONSOLE_WIDTH |
8437 | #define CATCH_CLARA_CONFIG_CONSOLE_WIDTH 80 |
8438 | #endif |
8439 | |
8440 | #ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH |
8441 | #define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CLARA_CONFIG_CONSOLE_WIDTH |
8442 | #endif |
8443 | |
8444 | #ifndef CLARA_CONFIG_OPTIONAL_TYPE |
8445 | #ifdef __has_include |
8446 | #if __has_include(<optional>) && __cplusplus >= 201703L |
8447 | #include <optional> |
8448 | #define CLARA_CONFIG_OPTIONAL_TYPE std::optional |
8449 | #endif |
8450 | #endif |
8451 | #endif |
8452 | |
8453 | // ----------- #included from clara_textflow.hpp ----------- |
8454 | |
8455 | // TextFlowCpp |
8456 | // |
8457 | // A single-header library for wrapping and laying out basic text, by Phil Nash |
8458 | // |
8459 | // Distributed under the Boost Software License, Version 1.0. (See accompanying |
8460 | // file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
8461 | // |
8462 | // This project is hosted at https://github.com/philsquared/textflowcpp |
8463 | |
8464 | |
8465 | #include <cassert> |
8466 | #include <ostream> |
8467 | #include <sstream> |
8468 | #include <vector> |
8469 | |
8470 | #ifndef CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH |
8471 | #define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH 80 |
8472 | #endif |
8473 | |
8474 | namespace Catch { |
8475 | namespace clara { |
8476 | namespace TextFlow { |
8477 | |
8478 | inline auto isWhitespace(char c) -> bool { |
8479 | static std::string chars = " \t\n\r" ; |
8480 | return chars.find(c) != std::string::npos; |
8481 | } |
8482 | inline auto isBreakableBefore(char c) -> bool { |
8483 | static std::string chars = "[({<|" ; |
8484 | return chars.find(c) != std::string::npos; |
8485 | } |
8486 | inline auto isBreakableAfter(char c) -> bool { |
8487 | static std::string chars = "])}>.,:;*+-=&/\\" ; |
8488 | return chars.find(c) != std::string::npos; |
8489 | } |
8490 | |
8491 | class Columns; |
8492 | |
8493 | class Column { |
8494 | std::vector<std::string> m_strings; |
8495 | size_t m_width = CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH; |
8496 | size_t m_indent = 0; |
8497 | size_t m_initialIndent = std::string::npos; |
8498 | |
8499 | public: |
8500 | class iterator { |
8501 | friend Column; |
8502 | |
8503 | Column const& m_column; |
8504 | size_t m_stringIndex = 0; |
8505 | size_t m_pos = 0; |
8506 | |
8507 | size_t m_len = 0; |
8508 | size_t m_end = 0; |
8509 | bool m_suffix = false; |
8510 | |
8511 | iterator(Column const& column, size_t stringIndex) |
8512 | : m_column(column), |
8513 | m_stringIndex(stringIndex) {} |
8514 | |
8515 | auto line() const -> std::string const& { return m_column.m_strings[m_stringIndex]; } |
8516 | |
8517 | auto isBoundary(size_t at) const -> bool { |
8518 | assert(at > 0); |
8519 | assert(at <= line().size()); |
8520 | |
8521 | return at == line().size() || |
8522 | (isWhitespace(line()[at]) && !isWhitespace(line()[at - 1])) || |
8523 | isBreakableBefore(line()[at]) || |
8524 | isBreakableAfter(line()[at - 1]); |
8525 | } |
8526 | |
8527 | void calcLength() { |
8528 | assert(m_stringIndex < m_column.m_strings.size()); |
8529 | |
8530 | m_suffix = false; |
8531 | auto width = m_column.m_width - indent(); |
8532 | m_end = m_pos; |
8533 | if (line()[m_pos] == '\n') { |
8534 | ++m_end; |
8535 | } |
8536 | while (m_end < line().size() && line()[m_end] != '\n') |
8537 | ++m_end; |
8538 | |
8539 | if (m_end < m_pos + width) { |
8540 | m_len = m_end - m_pos; |
8541 | } else { |
8542 | size_t len = width; |
8543 | while (len > 0 && !isBoundary(m_pos + len)) |
8544 | --len; |
8545 | while (len > 0 && isWhitespace(line()[m_pos + len - 1])) |
8546 | --len; |
8547 | |
8548 | if (len > 0) { |
8549 | m_len = len; |
8550 | } else { |
8551 | m_suffix = true; |
8552 | m_len = width - 1; |
8553 | } |
8554 | } |
8555 | } |
8556 | |
8557 | auto indent() const -> size_t { |
8558 | auto initial = m_pos == 0 && m_stringIndex == 0 ? m_column.m_initialIndent : std::string::npos; |
8559 | return initial == std::string::npos ? m_column.m_indent : initial; |
8560 | } |
8561 | |
8562 | auto addIndentAndSuffix(std::string const &plain) const -> std::string { |
8563 | return std::string(indent(), ' ') + (m_suffix ? plain + "-" : plain); |
8564 | } |
8565 | |
8566 | public: |
8567 | using difference_type = std::ptrdiff_t; |
8568 | using value_type = std::string; |
8569 | using pointer = value_type * ; |
8570 | using reference = value_type & ; |
8571 | using iterator_category = std::forward_iterator_tag; |
8572 | |
8573 | explicit iterator(Column const& column) : m_column(column) { |
8574 | assert(m_column.m_width > m_column.m_indent); |
8575 | assert(m_column.m_initialIndent == std::string::npos || m_column.m_width > m_column.m_initialIndent); |
8576 | calcLength(); |
8577 | if (m_len == 0) |
8578 | m_stringIndex++; // Empty string |
8579 | } |
8580 | |
8581 | auto operator *() const -> std::string { |
8582 | assert(m_stringIndex < m_column.m_strings.size()); |
8583 | assert(m_pos <= m_end); |
8584 | return addIndentAndSuffix(line().substr(m_pos, m_len)); |
8585 | } |
8586 | |
8587 | auto operator ++() -> iterator& { |
8588 | m_pos += m_len; |
8589 | if (m_pos < line().size() && line()[m_pos] == '\n') |
8590 | m_pos += 1; |
8591 | else |
8592 | while (m_pos < line().size() && isWhitespace(line()[m_pos])) |
8593 | ++m_pos; |
8594 | |
8595 | if (m_pos == line().size()) { |
8596 | m_pos = 0; |
8597 | ++m_stringIndex; |
8598 | } |
8599 | if (m_stringIndex < m_column.m_strings.size()) |
8600 | calcLength(); |
8601 | return *this; |
8602 | } |
8603 | auto operator ++(int) -> iterator { |
8604 | iterator prev(*this); |
8605 | operator++(); |
8606 | return prev; |
8607 | } |
8608 | |
8609 | auto operator ==(iterator const& other) const -> bool { |
8610 | return |
8611 | m_pos == other.m_pos && |
8612 | m_stringIndex == other.m_stringIndex && |
8613 | &m_column == &other.m_column; |
8614 | } |
8615 | auto operator !=(iterator const& other) const -> bool { |
8616 | return !operator==(other); |
8617 | } |
8618 | }; |
8619 | using const_iterator = iterator; |
8620 | |
8621 | explicit Column(std::string const& text) { m_strings.push_back(text); } |
8622 | |
8623 | auto width(size_t newWidth) -> Column& { |
8624 | assert(newWidth > 0); |
8625 | m_width = newWidth; |
8626 | return *this; |
8627 | } |
8628 | auto indent(size_t newIndent) -> Column& { |
8629 | m_indent = newIndent; |
8630 | return *this; |
8631 | } |
8632 | auto initialIndent(size_t newIndent) -> Column& { |
8633 | m_initialIndent = newIndent; |
8634 | return *this; |
8635 | } |
8636 | |
8637 | auto width() const -> size_t { return m_width; } |
8638 | auto begin() const -> iterator { return iterator(*this); } |
8639 | auto end() const -> iterator { return { *this, m_strings.size() }; } |
8640 | |
8641 | inline friend std::ostream& operator << (std::ostream& os, Column const& col) { |
8642 | bool first = true; |
8643 | for (auto line : col) { |
8644 | if (first) |
8645 | first = false; |
8646 | else |
8647 | os << "\n" ; |
8648 | os << line; |
8649 | } |
8650 | return os; |
8651 | } |
8652 | |
8653 | auto operator + (Column const& other)->Columns; |
8654 | |
8655 | auto toString() const -> std::string { |
8656 | std::ostringstream oss; |
8657 | oss << *this; |
8658 | return oss.str(); |
8659 | } |
8660 | }; |
8661 | |
8662 | class Spacer : public Column { |
8663 | |
8664 | public: |
8665 | explicit Spacer(size_t spaceWidth) : Column("" ) { |
8666 | width(spaceWidth); |
8667 | } |
8668 | }; |
8669 | |
8670 | class Columns { |
8671 | std::vector<Column> m_columns; |
8672 | |
8673 | public: |
8674 | |
8675 | class iterator { |
8676 | friend Columns; |
8677 | struct EndTag {}; |
8678 | |
8679 | std::vector<Column> const& m_columns; |
8680 | std::vector<Column::iterator> m_iterators; |
8681 | size_t m_activeIterators; |
8682 | |
8683 | iterator(Columns const& columns, EndTag) |
8684 | : m_columns(columns.m_columns), |
8685 | m_activeIterators(0) { |
8686 | m_iterators.reserve(m_columns.size()); |
8687 | |
8688 | for (auto const& col : m_columns) |
8689 | m_iterators.push_back(col.end()); |
8690 | } |
8691 | |
8692 | public: |
8693 | using difference_type = std::ptrdiff_t; |
8694 | using value_type = std::string; |
8695 | using pointer = value_type * ; |
8696 | using reference = value_type & ; |
8697 | using iterator_category = std::forward_iterator_tag; |
8698 | |
8699 | explicit iterator(Columns const& columns) |
8700 | : m_columns(columns.m_columns), |
8701 | m_activeIterators(m_columns.size()) { |
8702 | m_iterators.reserve(m_columns.size()); |
8703 | |
8704 | for (auto const& col : m_columns) |
8705 | m_iterators.push_back(col.begin()); |
8706 | } |
8707 | |
8708 | auto operator ==(iterator const& other) const -> bool { |
8709 | return m_iterators == other.m_iterators; |
8710 | } |
8711 | auto operator !=(iterator const& other) const -> bool { |
8712 | return m_iterators != other.m_iterators; |
8713 | } |
8714 | auto operator *() const -> std::string { |
8715 | std::string row, padding; |
8716 | |
8717 | for (size_t i = 0; i < m_columns.size(); ++i) { |
8718 | auto width = m_columns[i].width(); |
8719 | if (m_iterators[i] != m_columns[i].end()) { |
8720 | std::string col = *m_iterators[i]; |
8721 | row += padding + col; |
8722 | if (col.size() < width) |
8723 | padding = std::string(width - col.size(), ' '); |
8724 | else |
8725 | padding = "" ; |
8726 | } else { |
8727 | padding += std::string(width, ' '); |
8728 | } |
8729 | } |
8730 | return row; |
8731 | } |
8732 | auto operator ++() -> iterator& { |
8733 | for (size_t i = 0; i < m_columns.size(); ++i) { |
8734 | if (m_iterators[i] != m_columns[i].end()) |
8735 | ++m_iterators[i]; |
8736 | } |
8737 | return *this; |
8738 | } |
8739 | auto operator ++(int) -> iterator { |
8740 | iterator prev(*this); |
8741 | operator++(); |
8742 | return prev; |
8743 | } |
8744 | }; |
8745 | using const_iterator = iterator; |
8746 | |
8747 | auto begin() const -> iterator { return iterator(*this); } |
8748 | auto end() const -> iterator { return { *this, iterator::EndTag() }; } |
8749 | |
8750 | auto operator += (Column const& col) -> Columns& { |
8751 | m_columns.push_back(col); |
8752 | return *this; |
8753 | } |
8754 | auto operator + (Column const& col) -> Columns { |
8755 | Columns combined = *this; |
8756 | combined += col; |
8757 | return combined; |
8758 | } |
8759 | |
8760 | inline friend std::ostream& operator << (std::ostream& os, Columns const& cols) { |
8761 | |
8762 | bool first = true; |
8763 | for (auto line : cols) { |
8764 | if (first) |
8765 | first = false; |
8766 | else |
8767 | os << "\n" ; |
8768 | os << line; |
8769 | } |
8770 | return os; |
8771 | } |
8772 | |
8773 | auto toString() const -> std::string { |
8774 | std::ostringstream oss; |
8775 | oss << *this; |
8776 | return oss.str(); |
8777 | } |
8778 | }; |
8779 | |
8780 | inline auto Column::operator + (Column const& other) -> Columns { |
8781 | Columns cols; |
8782 | cols += *this; |
8783 | cols += other; |
8784 | return cols; |
8785 | } |
8786 | } |
8787 | |
8788 | } |
8789 | } |
8790 | |
8791 | // ----------- end of #include from clara_textflow.hpp ----------- |
8792 | // ........... back in clara.hpp |
8793 | |
8794 | #include <cctype> |
8795 | #include <string> |
8796 | #include <memory> |
8797 | #include <set> |
8798 | #include <algorithm> |
8799 | |
8800 | #if !defined(CATCH_PLATFORM_WINDOWS) && ( defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) ) |
8801 | #define CATCH_PLATFORM_WINDOWS |
8802 | #endif |
8803 | |
8804 | namespace Catch { namespace clara { |
8805 | namespace detail { |
8806 | |
8807 | // Traits for extracting arg and return type of lambdas (for single argument lambdas) |
8808 | template<typename L> |
8809 | struct UnaryLambdaTraits : UnaryLambdaTraits<decltype( &L::operator() )> {}; |
8810 | |
8811 | template<typename ClassT, typename ReturnT, typename... Args> |
8812 | struct UnaryLambdaTraits<ReturnT( ClassT::* )( Args... ) const> { |
8813 | static const bool isValid = false; |
8814 | }; |
8815 | |
8816 | template<typename ClassT, typename ReturnT, typename ArgT> |
8817 | struct UnaryLambdaTraits<ReturnT( ClassT::* )( ArgT ) const> { |
8818 | static const bool isValid = true; |
8819 | using ArgType = typename std::remove_const<typename std::remove_reference<ArgT>::type>::type; |
8820 | using ReturnType = ReturnT; |
8821 | }; |
8822 | |
8823 | class TokenStream; |
8824 | |
8825 | // Transport for raw args (copied from main args, or supplied via init list for testing) |
8826 | class Args { |
8827 | friend TokenStream; |
8828 | std::string m_exeName; |
8829 | std::vector<std::string> m_args; |
8830 | |
8831 | public: |
8832 | Args( int argc, char const* const* argv ) |
8833 | : m_exeName(argv[0]), |
8834 | m_args(argv + 1, argv + argc) {} |
8835 | |
8836 | Args( std::initializer_list<std::string> args ) |
8837 | : m_exeName( *args.begin() ), |
8838 | m_args( args.begin()+1, args.end() ) |
8839 | {} |
8840 | |
8841 | auto exeName() const -> std::string { |
8842 | return m_exeName; |
8843 | } |
8844 | }; |
8845 | |
8846 | // Wraps a token coming from a token stream. These may not directly correspond to strings as a single string |
8847 | // may encode an option + its argument if the : or = form is used |
8848 | enum class TokenType { |
8849 | Option, Argument |
8850 | }; |
8851 | struct Token { |
8852 | TokenType type; |
8853 | std::string token; |
8854 | }; |
8855 | |
8856 | inline auto isOptPrefix( char c ) -> bool { |
8857 | return c == '-' |
8858 | #ifdef CATCH_PLATFORM_WINDOWS |
8859 | || c == '/' |
8860 | #endif |
8861 | ; |
8862 | } |
8863 | |
8864 | // Abstracts iterators into args as a stream of tokens, with option arguments uniformly handled |
8865 | class TokenStream { |
8866 | using Iterator = std::vector<std::string>::const_iterator; |
8867 | Iterator it; |
8868 | Iterator itEnd; |
8869 | std::vector<Token> m_tokenBuffer; |
8870 | |
8871 | void loadBuffer() { |
8872 | m_tokenBuffer.resize( 0 ); |
8873 | |
8874 | // Skip any empty strings |
8875 | while( it != itEnd && it->empty() ) |
8876 | ++it; |
8877 | |
8878 | if( it != itEnd ) { |
8879 | auto const &next = *it; |
8880 | if( isOptPrefix( next[0] ) ) { |
8881 | auto delimiterPos = next.find_first_of( " :=" ); |
8882 | if( delimiterPos != std::string::npos ) { |
8883 | m_tokenBuffer.push_back( { TokenType::Option, next.substr( 0, delimiterPos ) } ); |
8884 | m_tokenBuffer.push_back( { TokenType::Argument, next.substr( delimiterPos + 1 ) } ); |
8885 | } else { |
8886 | if( next[1] != '-' && next.size() > 2 ) { |
8887 | std::string opt = "- " ; |
8888 | for( size_t i = 1; i < next.size(); ++i ) { |
8889 | opt[1] = next[i]; |
8890 | m_tokenBuffer.push_back( { TokenType::Option, opt } ); |
8891 | } |
8892 | } else { |
8893 | m_tokenBuffer.push_back( { TokenType::Option, next } ); |
8894 | } |
8895 | } |
8896 | } else { |
8897 | m_tokenBuffer.push_back( { TokenType::Argument, next } ); |
8898 | } |
8899 | } |
8900 | } |
8901 | |
8902 | public: |
8903 | explicit TokenStream( Args const &args ) : TokenStream( args.m_args.begin(), args.m_args.end() ) {} |
8904 | |
8905 | TokenStream( Iterator it, Iterator itEnd ) : it( it ), itEnd( itEnd ) { |
8906 | loadBuffer(); |
8907 | } |
8908 | |
8909 | explicit operator bool() const { |
8910 | return !m_tokenBuffer.empty() || it != itEnd; |
8911 | } |
8912 | |
8913 | auto count() const -> size_t { return m_tokenBuffer.size() + (itEnd - it); } |
8914 | |
8915 | auto operator*() const -> Token { |
8916 | assert( !m_tokenBuffer.empty() ); |
8917 | return m_tokenBuffer.front(); |
8918 | } |
8919 | |
8920 | auto operator->() const -> Token const * { |
8921 | assert( !m_tokenBuffer.empty() ); |
8922 | return &m_tokenBuffer.front(); |
8923 | } |
8924 | |
8925 | auto operator++() -> TokenStream & { |
8926 | if( m_tokenBuffer.size() >= 2 ) { |
8927 | m_tokenBuffer.erase( m_tokenBuffer.begin() ); |
8928 | } else { |
8929 | if( it != itEnd ) |
8930 | ++it; |
8931 | loadBuffer(); |
8932 | } |
8933 | return *this; |
8934 | } |
8935 | }; |
8936 | |
8937 | class ResultBase { |
8938 | public: |
8939 | enum Type { |
8940 | Ok, LogicError, RuntimeError |
8941 | }; |
8942 | |
8943 | protected: |
8944 | ResultBase( Type type ) : m_type( type ) {} |
8945 | virtual ~ResultBase() = default; |
8946 | |
8947 | virtual void enforceOk() const = 0; |
8948 | |
8949 | Type m_type; |
8950 | }; |
8951 | |
8952 | template<typename T> |
8953 | class ResultValueBase : public ResultBase { |
8954 | public: |
8955 | auto value() const -> T const & { |
8956 | enforceOk(); |
8957 | return m_value; |
8958 | } |
8959 | |
8960 | protected: |
8961 | ResultValueBase( Type type ) : ResultBase( type ) {} |
8962 | |
8963 | ResultValueBase( ResultValueBase const &other ) : ResultBase( other ) { |
8964 | if( m_type == ResultBase::Ok ) |
8965 | new( &m_value ) T( other.m_value ); |
8966 | } |
8967 | |
8968 | ResultValueBase( Type, T const &value ) : ResultBase( Ok ) { |
8969 | new( &m_value ) T( value ); |
8970 | } |
8971 | |
8972 | auto operator=( ResultValueBase const &other ) -> ResultValueBase & { |
8973 | if( m_type == ResultBase::Ok ) |
8974 | m_value.~T(); |
8975 | ResultBase::operator=(other); |
8976 | if( m_type == ResultBase::Ok ) |
8977 | new( &m_value ) T( other.m_value ); |
8978 | return *this; |
8979 | } |
8980 | |
8981 | ~ResultValueBase() override { |
8982 | if( m_type == Ok ) |
8983 | m_value.~T(); |
8984 | } |
8985 | |
8986 | union { |
8987 | T m_value; |
8988 | }; |
8989 | }; |
8990 | |
8991 | template<> |
8992 | class ResultValueBase<void> : public ResultBase { |
8993 | protected: |
8994 | using ResultBase::ResultBase; |
8995 | }; |
8996 | |
8997 | template<typename T = void> |
8998 | class BasicResult : public ResultValueBase<T> { |
8999 | public: |
9000 | template<typename U> |
9001 | explicit BasicResult( BasicResult<U> const &other ) |
9002 | : ResultValueBase<T>( other.type() ), |
9003 | m_errorMessage( other.errorMessage() ) |
9004 | { |
9005 | assert( type() != ResultBase::Ok ); |
9006 | } |
9007 | |
9008 | template<typename U> |
9009 | static auto ok( U const &value ) -> BasicResult { return { ResultBase::Ok, value }; } |
9010 | static auto ok() -> BasicResult { return { ResultBase::Ok }; } |
9011 | static auto logicError( std::string const &message ) -> BasicResult { return { ResultBase::LogicError, message }; } |
9012 | static auto runtimeError( std::string const &message ) -> BasicResult { return { ResultBase::RuntimeError, message }; } |
9013 | |
9014 | explicit operator bool() const { return m_type == ResultBase::Ok; } |
9015 | auto type() const -> ResultBase::Type { return m_type; } |
9016 | auto errorMessage() const -> std::string { return m_errorMessage; } |
9017 | |
9018 | protected: |
9019 | void enforceOk() const override { |
9020 | |
9021 | // Errors shouldn't reach this point, but if they do |
9022 | // the actual error message will be in m_errorMessage |
9023 | assert( m_type != ResultBase::LogicError ); |
9024 | assert( m_type != ResultBase::RuntimeError ); |
9025 | if( m_type != ResultBase::Ok ) |
9026 | std::abort(); |
9027 | } |
9028 | |
9029 | std::string m_errorMessage; // Only populated if resultType is an error |
9030 | |
9031 | BasicResult( ResultBase::Type type, std::string const &message ) |
9032 | : ResultValueBase<T>(type), |
9033 | m_errorMessage(message) |
9034 | { |
9035 | assert( m_type != ResultBase::Ok ); |
9036 | } |
9037 | |
9038 | using ResultValueBase<T>::ResultValueBase; |
9039 | using ResultBase::m_type; |
9040 | }; |
9041 | |
9042 | enum class ParseResultType { |
9043 | Matched, NoMatch, ShortCircuitAll, ShortCircuitSame |
9044 | }; |
9045 | |
9046 | class ParseState { |
9047 | public: |
9048 | |
9049 | ParseState( ParseResultType type, TokenStream const &remainingTokens ) |
9050 | : m_type(type), |
9051 | m_remainingTokens( remainingTokens ) |
9052 | {} |
9053 | |
9054 | auto type() const -> ParseResultType { return m_type; } |
9055 | auto remainingTokens() const -> TokenStream { return m_remainingTokens; } |
9056 | |
9057 | private: |
9058 | ParseResultType m_type; |
9059 | TokenStream m_remainingTokens; |
9060 | }; |
9061 | |
9062 | using Result = BasicResult<void>; |
9063 | using ParserResult = BasicResult<ParseResultType>; |
9064 | using InternalParseResult = BasicResult<ParseState>; |
9065 | |
9066 | struct HelpColumns { |
9067 | std::string left; |
9068 | std::string right; |
9069 | }; |
9070 | |
9071 | template<typename T> |
9072 | inline auto convertInto( std::string const &source, T& target ) -> ParserResult { |
9073 | std::stringstream ss; |
9074 | ss << source; |
9075 | ss >> target; |
9076 | if( ss.fail() ) |
9077 | return ParserResult::runtimeError( "Unable to convert '" + source + "' to destination type" ); |
9078 | else |
9079 | return ParserResult::ok( ParseResultType::Matched ); |
9080 | } |
9081 | inline auto convertInto( std::string const &source, std::string& target ) -> ParserResult { |
9082 | target = source; |
9083 | return ParserResult::ok( ParseResultType::Matched ); |
9084 | } |
9085 | inline auto convertInto( std::string const &source, bool &target ) -> ParserResult { |
9086 | std::string srcLC = source; |
9087 | std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( unsigned char c ) { return static_cast<char>( std::tolower(c) ); } ); |
9088 | if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on" ) |
9089 | target = true; |
9090 | else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off" ) |
9091 | target = false; |
9092 | else |
9093 | return ParserResult::runtimeError( "Expected a boolean value but did not recognise: '" + source + "'" ); |
9094 | return ParserResult::ok( ParseResultType::Matched ); |
9095 | } |
9096 | #ifdef CLARA_CONFIG_OPTIONAL_TYPE |
9097 | template<typename T> |
9098 | inline auto convertInto( std::string const &source, CLARA_CONFIG_OPTIONAL_TYPE<T>& target ) -> ParserResult { |
9099 | T temp; |
9100 | auto result = convertInto( source, temp ); |
9101 | if( result ) |
9102 | target = std::move(temp); |
9103 | return result; |
9104 | } |
9105 | #endif // CLARA_CONFIG_OPTIONAL_TYPE |
9106 | |
9107 | struct NonCopyable { |
9108 | NonCopyable() = default; |
9109 | NonCopyable( NonCopyable const & ) = delete; |
9110 | NonCopyable( NonCopyable && ) = delete; |
9111 | NonCopyable &operator=( NonCopyable const & ) = delete; |
9112 | NonCopyable &operator=( NonCopyable && ) = delete; |
9113 | }; |
9114 | |
9115 | struct BoundRef : NonCopyable { |
9116 | virtual ~BoundRef() = default; |
9117 | virtual auto isContainer() const -> bool { return false; } |
9118 | virtual auto isFlag() const -> bool { return false; } |
9119 | }; |
9120 | struct BoundValueRefBase : BoundRef { |
9121 | virtual auto setValue( std::string const &arg ) -> ParserResult = 0; |
9122 | }; |
9123 | struct BoundFlagRefBase : BoundRef { |
9124 | virtual auto setFlag( bool flag ) -> ParserResult = 0; |
9125 | virtual auto isFlag() const -> bool { return true; } |
9126 | }; |
9127 | |
9128 | template<typename T> |
9129 | struct BoundValueRef : BoundValueRefBase { |
9130 | T &m_ref; |
9131 | |
9132 | explicit BoundValueRef( T &ref ) : m_ref( ref ) {} |
9133 | |
9134 | auto setValue( std::string const &arg ) -> ParserResult override { |
9135 | return convertInto( arg, m_ref ); |
9136 | } |
9137 | }; |
9138 | |
9139 | template<typename T> |
9140 | struct BoundValueRef<std::vector<T>> : BoundValueRefBase { |
9141 | std::vector<T> &m_ref; |
9142 | |
9143 | explicit BoundValueRef( std::vector<T> &ref ) : m_ref( ref ) {} |
9144 | |
9145 | auto isContainer() const -> bool override { return true; } |
9146 | |
9147 | auto setValue( std::string const &arg ) -> ParserResult override { |
9148 | T temp; |
9149 | auto result = convertInto( arg, temp ); |
9150 | if( result ) |
9151 | m_ref.push_back( temp ); |
9152 | return result; |
9153 | } |
9154 | }; |
9155 | |
9156 | struct BoundFlagRef : BoundFlagRefBase { |
9157 | bool &m_ref; |
9158 | |
9159 | explicit BoundFlagRef( bool &ref ) : m_ref( ref ) {} |
9160 | |
9161 | auto setFlag( bool flag ) -> ParserResult override { |
9162 | m_ref = flag; |
9163 | return ParserResult::ok( ParseResultType::Matched ); |
9164 | } |
9165 | }; |
9166 | |
9167 | template<typename ReturnType> |
9168 | struct LambdaInvoker { |
9169 | static_assert( std::is_same<ReturnType, ParserResult>::value, "Lambda must return void or clara::ParserResult" ); |
9170 | |
9171 | template<typename L, typename ArgType> |
9172 | static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult { |
9173 | return lambda( arg ); |
9174 | } |
9175 | }; |
9176 | |
9177 | template<> |
9178 | struct LambdaInvoker<void> { |
9179 | template<typename L, typename ArgType> |
9180 | static auto invoke( L const &lambda, ArgType const &arg ) -> ParserResult { |
9181 | lambda( arg ); |
9182 | return ParserResult::ok( ParseResultType::Matched ); |
9183 | } |
9184 | }; |
9185 | |
9186 | template<typename ArgType, typename L> |
9187 | inline auto invokeLambda( L const &lambda, std::string const &arg ) -> ParserResult { |
9188 | ArgType temp{}; |
9189 | auto result = convertInto( arg, temp ); |
9190 | return !result |
9191 | ? result |
9192 | : LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( lambda, temp ); |
9193 | } |
9194 | |
9195 | template<typename L> |
9196 | struct BoundLambda : BoundValueRefBase { |
9197 | L m_lambda; |
9198 | |
9199 | static_assert( UnaryLambdaTraits<L>::isValid, "Supplied lambda must take exactly one argument" ); |
9200 | explicit BoundLambda( L const &lambda ) : m_lambda( lambda ) {} |
9201 | |
9202 | auto setValue( std::string const &arg ) -> ParserResult override { |
9203 | return invokeLambda<typename UnaryLambdaTraits<L>::ArgType>( m_lambda, arg ); |
9204 | } |
9205 | }; |
9206 | |
9207 | template<typename L> |
9208 | struct BoundFlagLambda : BoundFlagRefBase { |
9209 | L m_lambda; |
9210 | |
9211 | static_assert( UnaryLambdaTraits<L>::isValid, "Supplied lambda must take exactly one argument" ); |
9212 | static_assert( std::is_same<typename UnaryLambdaTraits<L>::ArgType, bool>::value, "flags must be boolean" ); |
9213 | |
9214 | explicit BoundFlagLambda( L const &lambda ) : m_lambda( lambda ) {} |
9215 | |
9216 | auto setFlag( bool flag ) -> ParserResult override { |
9217 | return LambdaInvoker<typename UnaryLambdaTraits<L>::ReturnType>::invoke( m_lambda, flag ); |
9218 | } |
9219 | }; |
9220 | |
9221 | enum class Optionality { Optional, Required }; |
9222 | |
9223 | struct Parser; |
9224 | |
9225 | class ParserBase { |
9226 | public: |
9227 | virtual ~ParserBase() = default; |
9228 | virtual auto validate() const -> Result { return Result::ok(); } |
9229 | virtual auto parse( std::string const& exeName, TokenStream const &tokens) const -> InternalParseResult = 0; |
9230 | virtual auto cardinality() const -> size_t { return 1; } |
9231 | |
9232 | auto parse( Args const &args ) const -> InternalParseResult { |
9233 | return parse( args.exeName(), TokenStream( args ) ); |
9234 | } |
9235 | }; |
9236 | |
9237 | template<typename DerivedT> |
9238 | class ComposableParserImpl : public ParserBase { |
9239 | public: |
9240 | template<typename T> |
9241 | auto operator|( T const &other ) const -> Parser; |
9242 | |
9243 | template<typename T> |
9244 | auto operator+( T const &other ) const -> Parser; |
9245 | }; |
9246 | |
9247 | // Common code and state for Args and Opts |
9248 | template<typename DerivedT> |
9249 | class ParserRefImpl : public ComposableParserImpl<DerivedT> { |
9250 | protected: |
9251 | Optionality m_optionality = Optionality::Optional; |
9252 | std::shared_ptr<BoundRef> m_ref; |
9253 | std::string m_hint; |
9254 | std::string m_description; |
9255 | |
9256 | explicit ParserRefImpl( std::shared_ptr<BoundRef> const &ref ) : m_ref( ref ) {} |
9257 | |
9258 | public: |
9259 | template<typename T> |
9260 | ParserRefImpl( T &ref, std::string const &hint ) |
9261 | : m_ref( std::make_shared<BoundValueRef<T>>( ref ) ), |
9262 | m_hint( hint ) |
9263 | {} |
9264 | |
9265 | template<typename LambdaT> |
9266 | ParserRefImpl( LambdaT const &ref, std::string const &hint ) |
9267 | : m_ref( std::make_shared<BoundLambda<LambdaT>>( ref ) ), |
9268 | m_hint(hint) |
9269 | {} |
9270 | |
9271 | auto operator()( std::string const &description ) -> DerivedT & { |
9272 | m_description = description; |
9273 | return static_cast<DerivedT &>( *this ); |
9274 | } |
9275 | |
9276 | auto optional() -> DerivedT & { |
9277 | m_optionality = Optionality::Optional; |
9278 | return static_cast<DerivedT &>( *this ); |
9279 | }; |
9280 | |
9281 | auto required() -> DerivedT & { |
9282 | m_optionality = Optionality::Required; |
9283 | return static_cast<DerivedT &>( *this ); |
9284 | }; |
9285 | |
9286 | auto isOptional() const -> bool { |
9287 | return m_optionality == Optionality::Optional; |
9288 | } |
9289 | |
9290 | auto cardinality() const -> size_t override { |
9291 | if( m_ref->isContainer() ) |
9292 | return 0; |
9293 | else |
9294 | return 1; |
9295 | } |
9296 | |
9297 | auto hint() const -> std::string { return m_hint; } |
9298 | }; |
9299 | |
9300 | class ExeName : public ComposableParserImpl<ExeName> { |
9301 | std::shared_ptr<std::string> m_name; |
9302 | std::shared_ptr<BoundValueRefBase> m_ref; |
9303 | |
9304 | template<typename LambdaT> |
9305 | static auto makeRef(LambdaT const &lambda) -> std::shared_ptr<BoundValueRefBase> { |
9306 | return std::make_shared<BoundLambda<LambdaT>>( lambda) ; |
9307 | } |
9308 | |
9309 | public: |
9310 | ExeName() : m_name( std::make_shared<std::string>( "<executable>" ) ) {} |
9311 | |
9312 | explicit ExeName( std::string &ref ) : ExeName() { |
9313 | m_ref = std::make_shared<BoundValueRef<std::string>>( ref ); |
9314 | } |
9315 | |
9316 | template<typename LambdaT> |
9317 | explicit ExeName( LambdaT const& lambda ) : ExeName() { |
9318 | m_ref = std::make_shared<BoundLambda<LambdaT>>( lambda ); |
9319 | } |
9320 | |
9321 | // The exe name is not parsed out of the normal tokens, but is handled specially |
9322 | auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override { |
9323 | return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) ); |
9324 | } |
9325 | |
9326 | auto name() const -> std::string { return *m_name; } |
9327 | auto set( std::string const& newName ) -> ParserResult { |
9328 | |
9329 | auto lastSlash = newName.find_last_of( "\\/" ); |
9330 | auto filename = ( lastSlash == std::string::npos ) |
9331 | ? newName |
9332 | : newName.substr( lastSlash+1 ); |
9333 | |
9334 | *m_name = filename; |
9335 | if( m_ref ) |
9336 | return m_ref->setValue( filename ); |
9337 | else |
9338 | return ParserResult::ok( ParseResultType::Matched ); |
9339 | } |
9340 | }; |
9341 | |
9342 | class Arg : public ParserRefImpl<Arg> { |
9343 | public: |
9344 | using ParserRefImpl::ParserRefImpl; |
9345 | |
9346 | auto parse( std::string const &, TokenStream const &tokens ) const -> InternalParseResult override { |
9347 | auto validationResult = validate(); |
9348 | if( !validationResult ) |
9349 | return InternalParseResult( validationResult ); |
9350 | |
9351 | auto remainingTokens = tokens; |
9352 | auto const &token = *remainingTokens; |
9353 | if( token.type != TokenType::Argument ) |
9354 | return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) ); |
9355 | |
9356 | assert( !m_ref->isFlag() ); |
9357 | auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() ); |
9358 | |
9359 | auto result = valueRef->setValue( remainingTokens->token ); |
9360 | if( !result ) |
9361 | return InternalParseResult( result ); |
9362 | else |
9363 | return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) ); |
9364 | } |
9365 | }; |
9366 | |
9367 | inline auto normaliseOpt( std::string const &optName ) -> std::string { |
9368 | #ifdef CATCH_PLATFORM_WINDOWS |
9369 | if( optName[0] == '/' ) |
9370 | return "-" + optName.substr( 1 ); |
9371 | else |
9372 | #endif |
9373 | return optName; |
9374 | } |
9375 | |
9376 | class Opt : public ParserRefImpl<Opt> { |
9377 | protected: |
9378 | std::vector<std::string> m_optNames; |
9379 | |
9380 | public: |
9381 | template<typename LambdaT> |
9382 | explicit Opt( LambdaT const &ref ) : ParserRefImpl( std::make_shared<BoundFlagLambda<LambdaT>>( ref ) ) {} |
9383 | |
9384 | explicit Opt( bool &ref ) : ParserRefImpl( std::make_shared<BoundFlagRef>( ref ) ) {} |
9385 | |
9386 | template<typename LambdaT> |
9387 | Opt( LambdaT const &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {} |
9388 | |
9389 | template<typename T> |
9390 | Opt( T &ref, std::string const &hint ) : ParserRefImpl( ref, hint ) {} |
9391 | |
9392 | auto operator[]( std::string const &optName ) -> Opt & { |
9393 | m_optNames.push_back( optName ); |
9394 | return *this; |
9395 | } |
9396 | |
9397 | auto getHelpColumns() const -> std::vector<HelpColumns> { |
9398 | std::ostringstream oss; |
9399 | bool first = true; |
9400 | for( auto const &opt : m_optNames ) { |
9401 | if (first) |
9402 | first = false; |
9403 | else |
9404 | oss << ", " ; |
9405 | oss << opt; |
9406 | } |
9407 | if( !m_hint.empty() ) |
9408 | oss << " <" << m_hint << ">" ; |
9409 | return { { oss.str(), m_description } }; |
9410 | } |
9411 | |
9412 | auto isMatch( std::string const &optToken ) const -> bool { |
9413 | auto normalisedToken = normaliseOpt( optToken ); |
9414 | for( auto const &name : m_optNames ) { |
9415 | if( normaliseOpt( name ) == normalisedToken ) |
9416 | return true; |
9417 | } |
9418 | return false; |
9419 | } |
9420 | |
9421 | using ParserBase::parse; |
9422 | |
9423 | auto parse( std::string const&, TokenStream const &tokens ) const -> InternalParseResult override { |
9424 | auto validationResult = validate(); |
9425 | if( !validationResult ) |
9426 | return InternalParseResult( validationResult ); |
9427 | |
9428 | auto remainingTokens = tokens; |
9429 | if( remainingTokens && remainingTokens->type == TokenType::Option ) { |
9430 | auto const &token = *remainingTokens; |
9431 | if( isMatch(token.token ) ) { |
9432 | if( m_ref->isFlag() ) { |
9433 | auto flagRef = static_cast<detail::BoundFlagRefBase*>( m_ref.get() ); |
9434 | auto result = flagRef->setFlag( true ); |
9435 | if( !result ) |
9436 | return InternalParseResult( result ); |
9437 | if( result.value() == ParseResultType::ShortCircuitAll ) |
9438 | return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) ); |
9439 | } else { |
9440 | auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() ); |
9441 | ++remainingTokens; |
9442 | if( !remainingTokens ) |
9443 | return InternalParseResult::runtimeError( "Expected argument following " + token.token ); |
9444 | auto const &argToken = *remainingTokens; |
9445 | if( argToken.type != TokenType::Argument ) |
9446 | return InternalParseResult::runtimeError( "Expected argument following " + token.token ); |
9447 | auto result = valueRef->setValue( argToken.token ); |
9448 | if( !result ) |
9449 | return InternalParseResult( result ); |
9450 | if( result.value() == ParseResultType::ShortCircuitAll ) |
9451 | return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) ); |
9452 | } |
9453 | return InternalParseResult::ok( ParseState( ParseResultType::Matched, ++remainingTokens ) ); |
9454 | } |
9455 | } |
9456 | return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) ); |
9457 | } |
9458 | |
9459 | auto validate() const -> Result override { |
9460 | if( m_optNames.empty() ) |
9461 | return Result::logicError( "No options supplied to Opt" ); |
9462 | for( auto const &name : m_optNames ) { |
9463 | if( name.empty() ) |
9464 | return Result::logicError( "Option name cannot be empty" ); |
9465 | #ifdef CATCH_PLATFORM_WINDOWS |
9466 | if( name[0] != '-' && name[0] != '/' ) |
9467 | return Result::logicError( "Option name must begin with '-' or '/'" ); |
9468 | #else |
9469 | if( name[0] != '-' ) |
9470 | return Result::logicError( "Option name must begin with '-'" ); |
9471 | #endif |
9472 | } |
9473 | return ParserRefImpl::validate(); |
9474 | } |
9475 | }; |
9476 | |
9477 | struct Help : Opt { |
9478 | Help( bool &showHelpFlag ) |
9479 | : Opt([&]( bool flag ) { |
9480 | showHelpFlag = flag; |
9481 | return ParserResult::ok( ParseResultType::ShortCircuitAll ); |
9482 | }) |
9483 | { |
9484 | static_cast<Opt &>( *this ) |
9485 | ("display usage information" ) |
9486 | ["-?" ]["-h" ]["--help" ] |
9487 | .optional(); |
9488 | } |
9489 | }; |
9490 | |
9491 | struct Parser : ParserBase { |
9492 | |
9493 | mutable ExeName m_exeName; |
9494 | std::vector<Opt> m_options; |
9495 | std::vector<Arg> m_args; |
9496 | |
9497 | auto operator|=( ExeName const &exeName ) -> Parser & { |
9498 | m_exeName = exeName; |
9499 | return *this; |
9500 | } |
9501 | |
9502 | auto operator|=( Arg const &arg ) -> Parser & { |
9503 | m_args.push_back(arg); |
9504 | return *this; |
9505 | } |
9506 | |
9507 | auto operator|=( Opt const &opt ) -> Parser & { |
9508 | m_options.push_back(opt); |
9509 | return *this; |
9510 | } |
9511 | |
9512 | auto operator|=( Parser const &other ) -> Parser & { |
9513 | m_options.insert(m_options.end(), other.m_options.begin(), other.m_options.end()); |
9514 | m_args.insert(m_args.end(), other.m_args.begin(), other.m_args.end()); |
9515 | return *this; |
9516 | } |
9517 | |
9518 | template<typename T> |
9519 | auto operator|( T const &other ) const -> Parser { |
9520 | return Parser( *this ) |= other; |
9521 | } |
9522 | |
9523 | // Forward deprecated interface with '+' instead of '|' |
9524 | template<typename T> |
9525 | auto operator+=( T const &other ) -> Parser & { return operator|=( other ); } |
9526 | template<typename T> |
9527 | auto operator+( T const &other ) const -> Parser { return operator|( other ); } |
9528 | |
9529 | auto getHelpColumns() const -> std::vector<HelpColumns> { |
9530 | std::vector<HelpColumns> cols; |
9531 | for (auto const &o : m_options) { |
9532 | auto childCols = o.getHelpColumns(); |
9533 | cols.insert( cols.end(), childCols.begin(), childCols.end() ); |
9534 | } |
9535 | return cols; |
9536 | } |
9537 | |
9538 | void writeToStream( std::ostream &os ) const { |
9539 | if (!m_exeName.name().empty()) { |
9540 | os << "usage:\n" << " " << m_exeName.name() << " " ; |
9541 | bool required = true, first = true; |
9542 | for( auto const &arg : m_args ) { |
9543 | if (first) |
9544 | first = false; |
9545 | else |
9546 | os << " " ; |
9547 | if( arg.isOptional() && required ) { |
9548 | os << "[" ; |
9549 | required = false; |
9550 | } |
9551 | os << "<" << arg.hint() << ">" ; |
9552 | if( arg.cardinality() == 0 ) |
9553 | os << " ... " ; |
9554 | } |
9555 | if( !required ) |
9556 | os << "]" ; |
9557 | if( !m_options.empty() ) |
9558 | os << " options" ; |
9559 | os << "\n\nwhere options are:" << std::endl; |
9560 | } |
9561 | |
9562 | auto rows = getHelpColumns(); |
9563 | size_t consoleWidth = CATCH_CLARA_CONFIG_CONSOLE_WIDTH; |
9564 | size_t optWidth = 0; |
9565 | for( auto const &cols : rows ) |
9566 | optWidth = (std::max)(optWidth, cols.left.size() + 2); |
9567 | |
9568 | optWidth = (std::min)(optWidth, consoleWidth/2); |
9569 | |
9570 | for( auto const &cols : rows ) { |
9571 | auto row = |
9572 | TextFlow::Column( cols.left ).width( optWidth ).indent( 2 ) + |
9573 | TextFlow::Spacer(4) + |
9574 | TextFlow::Column( cols.right ).width( consoleWidth - 7 - optWidth ); |
9575 | os << row << std::endl; |
9576 | } |
9577 | } |
9578 | |
9579 | friend auto operator<<( std::ostream &os, Parser const &parser ) -> std::ostream& { |
9580 | parser.writeToStream( os ); |
9581 | return os; |
9582 | } |
9583 | |
9584 | auto validate() const -> Result override { |
9585 | for( auto const &opt : m_options ) { |
9586 | auto result = opt.validate(); |
9587 | if( !result ) |
9588 | return result; |
9589 | } |
9590 | for( auto const &arg : m_args ) { |
9591 | auto result = arg.validate(); |
9592 | if( !result ) |
9593 | return result; |
9594 | } |
9595 | return Result::ok(); |
9596 | } |
9597 | |
9598 | using ParserBase::parse; |
9599 | |
9600 | auto parse( std::string const& exeName, TokenStream const &tokens ) const -> InternalParseResult override { |
9601 | |
9602 | struct ParserInfo { |
9603 | ParserBase const* parser = nullptr; |
9604 | size_t count = 0; |
9605 | }; |
9606 | const size_t totalParsers = m_options.size() + m_args.size(); |
9607 | assert( totalParsers < 512 ); |
9608 | // ParserInfo parseInfos[totalParsers]; // <-- this is what we really want to do |
9609 | ParserInfo parseInfos[512]; |
9610 | |
9611 | { |
9612 | size_t i = 0; |
9613 | for (auto const &opt : m_options) parseInfos[i++].parser = &opt; |
9614 | for (auto const &arg : m_args) parseInfos[i++].parser = &arg; |
9615 | } |
9616 | |
9617 | m_exeName.set( exeName ); |
9618 | |
9619 | auto result = InternalParseResult::ok( ParseState( ParseResultType::NoMatch, tokens ) ); |
9620 | while( result.value().remainingTokens() ) { |
9621 | bool tokenParsed = false; |
9622 | |
9623 | for( size_t i = 0; i < totalParsers; ++i ) { |
9624 | auto& parseInfo = parseInfos[i]; |
9625 | if( parseInfo.parser->cardinality() == 0 || parseInfo.count < parseInfo.parser->cardinality() ) { |
9626 | result = parseInfo.parser->parse(exeName, result.value().remainingTokens()); |
9627 | if (!result) |
9628 | return result; |
9629 | if (result.value().type() != ParseResultType::NoMatch) { |
9630 | tokenParsed = true; |
9631 | ++parseInfo.count; |
9632 | break; |
9633 | } |
9634 | } |
9635 | } |
9636 | |
9637 | if( result.value().type() == ParseResultType::ShortCircuitAll ) |
9638 | return result; |
9639 | if( !tokenParsed ) |
9640 | return InternalParseResult::runtimeError( "Unrecognised token: " + result.value().remainingTokens()->token ); |
9641 | } |
9642 | // !TBD Check missing required options |
9643 | return result; |
9644 | } |
9645 | }; |
9646 | |
9647 | template<typename DerivedT> |
9648 | template<typename T> |
9649 | auto ComposableParserImpl<DerivedT>::operator|( T const &other ) const -> Parser { |
9650 | return Parser() | static_cast<DerivedT const &>( *this ) | other; |
9651 | } |
9652 | } // namespace detail |
9653 | |
9654 | // A Combined parser |
9655 | using detail::Parser; |
9656 | |
9657 | // A parser for options |
9658 | using detail::Opt; |
9659 | |
9660 | // A parser for arguments |
9661 | using detail::Arg; |
9662 | |
9663 | // Wrapper for argc, argv from main() |
9664 | using detail::Args; |
9665 | |
9666 | // Specifies the name of the executable |
9667 | using detail::ExeName; |
9668 | |
9669 | // Convenience wrapper for option parser that specifies the help option |
9670 | using detail::Help; |
9671 | |
9672 | // enum of result types from a parse |
9673 | using detail::ParseResultType; |
9674 | |
9675 | // Result type for parser operation |
9676 | using detail::ParserResult; |
9677 | |
9678 | }} // namespace Catch::clara |
9679 | |
9680 | // end clara.hpp |
9681 | #ifdef __clang__ |
9682 | #pragma clang diagnostic pop |
9683 | #endif |
9684 | |
9685 | // Restore Clara's value for console width, if present |
9686 | #ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH |
9687 | #define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH |
9688 | #undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH |
9689 | #endif |
9690 | |
9691 | // end catch_clara.h |
9692 | namespace Catch { |
9693 | |
9694 | clara::Parser makeCommandLineParser( ConfigData& config ); |
9695 | |
9696 | } // end namespace Catch |
9697 | |
9698 | // end catch_commandline.h |
9699 | #include <fstream> |
9700 | #include <ctime> |
9701 | |
9702 | namespace Catch { |
9703 | |
9704 | clara::Parser makeCommandLineParser( ConfigData& config ) { |
9705 | |
9706 | using namespace clara; |
9707 | |
9708 | auto const setWarning = [&]( std::string const& warning ) { |
9709 | auto warningSet = [&]() { |
9710 | if( warning == "NoAssertions" ) |
9711 | return WarnAbout::NoAssertions; |
9712 | |
9713 | if ( warning == "NoTests" ) |
9714 | return WarnAbout::NoTests; |
9715 | |
9716 | return WarnAbout::Nothing; |
9717 | }(); |
9718 | |
9719 | if (warningSet == WarnAbout::Nothing) |
9720 | return ParserResult::runtimeError( "Unrecognised warning: '" + warning + "'" ); |
9721 | config.warnings = static_cast<WarnAbout::What>( config.warnings | warningSet ); |
9722 | return ParserResult::ok( ParseResultType::Matched ); |
9723 | }; |
9724 | auto const loadTestNamesFromFile = [&]( std::string const& filename ) { |
9725 | std::ifstream f( filename.c_str() ); |
9726 | if( !f.is_open() ) |
9727 | return ParserResult::runtimeError( "Unable to load input file: '" + filename + "'" ); |
9728 | |
9729 | std::string line; |
9730 | while( std::getline( f, line ) ) { |
9731 | line = trim(line); |
9732 | if( !line.empty() && !startsWith( line, '#' ) ) { |
9733 | if( !startsWith( line, '"' ) ) |
9734 | line = '"' + line + '"'; |
9735 | config.testsOrTags.push_back( line ); |
9736 | config.testsOrTags.emplace_back( "," ); |
9737 | } |
9738 | } |
9739 | //Remove comma in the end |
9740 | if(!config.testsOrTags.empty()) |
9741 | config.testsOrTags.erase( config.testsOrTags.end()-1 ); |
9742 | |
9743 | return ParserResult::ok( ParseResultType::Matched ); |
9744 | }; |
9745 | auto const setTestOrder = [&]( std::string const& order ) { |
9746 | if( startsWith( "declared" , order ) ) |
9747 | config.runOrder = RunTests::InDeclarationOrder; |
9748 | else if( startsWith( "lexical" , order ) ) |
9749 | config.runOrder = RunTests::InLexicographicalOrder; |
9750 | else if( startsWith( "random" , order ) ) |
9751 | config.runOrder = RunTests::InRandomOrder; |
9752 | else |
9753 | return clara::ParserResult::runtimeError( "Unrecognised ordering: '" + order + "'" ); |
9754 | return ParserResult::ok( ParseResultType::Matched ); |
9755 | }; |
9756 | auto const setRngSeed = [&]( std::string const& seed ) { |
9757 | if( seed != "time" ) |
9758 | return clara::detail::convertInto( seed, config.rngSeed ); |
9759 | config.rngSeed = static_cast<unsigned int>( std::time(nullptr) ); |
9760 | return ParserResult::ok( ParseResultType::Matched ); |
9761 | }; |
9762 | auto const setColourUsage = [&]( std::string const& useColour ) { |
9763 | auto mode = toLower( useColour ); |
9764 | |
9765 | if( mode == "yes" ) |
9766 | config.useColour = UseColour::Yes; |
9767 | else if( mode == "no" ) |
9768 | config.useColour = UseColour::No; |
9769 | else if( mode == "auto" ) |
9770 | config.useColour = UseColour::Auto; |
9771 | else |
9772 | return ParserResult::runtimeError( "colour mode must be one of: auto, yes or no. '" + useColour + "' not recognised" ); |
9773 | return ParserResult::ok( ParseResultType::Matched ); |
9774 | }; |
9775 | auto const setWaitForKeypress = [&]( std::string const& keypress ) { |
9776 | auto keypressLc = toLower( keypress ); |
9777 | if (keypressLc == "never" ) |
9778 | config.waitForKeypress = WaitForKeypress::Never; |
9779 | else if( keypressLc == "start" ) |
9780 | config.waitForKeypress = WaitForKeypress::BeforeStart; |
9781 | else if( keypressLc == "exit" ) |
9782 | config.waitForKeypress = WaitForKeypress::BeforeExit; |
9783 | else if( keypressLc == "both" ) |
9784 | config.waitForKeypress = WaitForKeypress::BeforeStartAndExit; |
9785 | else |
9786 | return ParserResult::runtimeError( "keypress argument must be one of: never, start, exit or both. '" + keypress + "' not recognised" ); |
9787 | return ParserResult::ok( ParseResultType::Matched ); |
9788 | }; |
9789 | auto const setVerbosity = [&]( std::string const& verbosity ) { |
9790 | auto lcVerbosity = toLower( verbosity ); |
9791 | if( lcVerbosity == "quiet" ) |
9792 | config.verbosity = Verbosity::Quiet; |
9793 | else if( lcVerbosity == "normal" ) |
9794 | config.verbosity = Verbosity::Normal; |
9795 | else if( lcVerbosity == "high" ) |
9796 | config.verbosity = Verbosity::High; |
9797 | else |
9798 | return ParserResult::runtimeError( "Unrecognised verbosity, '" + verbosity + "'" ); |
9799 | return ParserResult::ok( ParseResultType::Matched ); |
9800 | }; |
9801 | auto const setReporter = [&]( std::string const& reporter ) { |
9802 | IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); |
9803 | |
9804 | auto lcReporter = toLower( reporter ); |
9805 | auto result = factories.find( lcReporter ); |
9806 | |
9807 | if( factories.end() != result ) |
9808 | config.reporterName = lcReporter; |
9809 | else |
9810 | return ParserResult::runtimeError( "Unrecognized reporter, '" + reporter + "'. Check available with --list-reporters" ); |
9811 | return ParserResult::ok( ParseResultType::Matched ); |
9812 | }; |
9813 | |
9814 | auto cli |
9815 | = ExeName( config.processName ) |
9816 | | Help( config.showHelp ) |
9817 | | Opt( config.listTests ) |
9818 | ["-l" ]["--list-tests" ] |
9819 | ( "list all/matching test cases" ) |
9820 | | Opt( config.listTags ) |
9821 | ["-t" ]["--list-tags" ] |
9822 | ( "list all/matching tags" ) |
9823 | | Opt( config.showSuccessfulTests ) |
9824 | ["-s" ]["--success" ] |
9825 | ( "include successful tests in output" ) |
9826 | | Opt( config.shouldDebugBreak ) |
9827 | ["-b" ]["--break" ] |
9828 | ( "break into debugger on failure" ) |
9829 | | Opt( config.noThrow ) |
9830 | ["-e" ]["--nothrow" ] |
9831 | ( "skip exception tests" ) |
9832 | | Opt( config.showInvisibles ) |
9833 | ["-i" ]["--invisibles" ] |
9834 | ( "show invisibles (tabs, newlines)" ) |
9835 | | Opt( config.outputFilename, "filename" ) |
9836 | ["-o" ]["--out" ] |
9837 | ( "output filename" ) |
9838 | | Opt( setReporter, "name" ) |
9839 | ["-r" ]["--reporter" ] |
9840 | ( "reporter to use (defaults to console)" ) |
9841 | | Opt( config.name, "name" ) |
9842 | ["-n" ]["--name" ] |
9843 | ( "suite name" ) |
9844 | | Opt( [&]( bool ){ config.abortAfter = 1; } ) |
9845 | ["-a" ]["--abort" ] |
9846 | ( "abort at first failure" ) |
9847 | | Opt( [&]( int x ){ config.abortAfter = x; }, "no. failures" ) |
9848 | ["-x" ]["--abortx" ] |
9849 | ( "abort after x failures" ) |
9850 | | Opt( setWarning, "warning name" ) |
9851 | ["-w" ]["--warn" ] |
9852 | ( "enable warnings" ) |
9853 | | Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" ) |
9854 | ["-d" ]["--durations" ] |
9855 | ( "show test durations" ) |
9856 | | Opt( config.minDuration, "seconds" ) |
9857 | ["-D" ]["--min-duration" ] |
9858 | ( "show test durations for tests taking at least the given number of seconds" ) |
9859 | | Opt( loadTestNamesFromFile, "filename" ) |
9860 | ["-f" ]["--input-file" ] |
9861 | ( "load test names to run from a file" ) |
9862 | | Opt( config.filenamesAsTags ) |
9863 | ["-#" ]["--filenames-as-tags" ] |
9864 | ( "adds a tag for the filename" ) |
9865 | | Opt( config.sectionsToRun, "section name" ) |
9866 | ["-c" ]["--section" ] |
9867 | ( "specify section to run" ) |
9868 | | Opt( setVerbosity, "quiet|normal|high" ) |
9869 | ["-v" ]["--verbosity" ] |
9870 | ( "set output verbosity" ) |
9871 | | Opt( config.listTestNamesOnly ) |
9872 | ["--list-test-names-only" ] |
9873 | ( "list all/matching test cases names only" ) |
9874 | | Opt( config.listReporters ) |
9875 | ["--list-reporters" ] |
9876 | ( "list all reporters" ) |
9877 | | Opt( setTestOrder, "decl|lex|rand" ) |
9878 | ["--order" ] |
9879 | ( "test case order (defaults to decl)" ) |
9880 | | Opt( setRngSeed, "'time'|number" ) |
9881 | ["--rng-seed" ] |
9882 | ( "set a specific seed for random numbers" ) |
9883 | | Opt( setColourUsage, "yes|no" ) |
9884 | ["--use-colour" ] |
9885 | ( "should output be colourised" ) |
9886 | | Opt( config.libIdentify ) |
9887 | ["--libidentify" ] |
9888 | ( "report name and version according to libidentify standard" ) |
9889 | | Opt( setWaitForKeypress, "never|start|exit|both" ) |
9890 | ["--wait-for-keypress" ] |
9891 | ( "waits for a keypress before exiting" ) |
9892 | | Opt( config.benchmarkSamples, "samples" ) |
9893 | ["--benchmark-samples" ] |
9894 | ( "number of samples to collect (default: 100)" ) |
9895 | | Opt( config.benchmarkResamples, "resamples" ) |
9896 | ["--benchmark-resamples" ] |
9897 | ( "number of resamples for the bootstrap (default: 100000)" ) |
9898 | | Opt( config.benchmarkConfidenceInterval, "confidence interval" ) |
9899 | ["--benchmark-confidence-interval" ] |
9900 | ( "confidence interval for the bootstrap (between 0 and 1, default: 0.95)" ) |
9901 | | Opt( config.benchmarkNoAnalysis ) |
9902 | ["--benchmark-no-analysis" ] |
9903 | ( "perform only measurements; do not perform any analysis" ) |
9904 | | Opt( config.benchmarkWarmupTime, "benchmarkWarmupTime" ) |
9905 | ["--benchmark-warmup-time" ] |
9906 | ( "amount of time in milliseconds spent on warming up each test (default: 100)" ) |
9907 | | Arg( config.testsOrTags, "test name|pattern|tags" ) |
9908 | ( "which test or tests to use" ); |
9909 | |
9910 | return cli; |
9911 | } |
9912 | |
9913 | } // end namespace Catch |
9914 | // end catch_commandline.cpp |
9915 | // start catch_common.cpp |
9916 | |
9917 | #include <cstring> |
9918 | #include <ostream> |
9919 | |
9920 | namespace Catch { |
9921 | |
9922 | bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const noexcept { |
9923 | return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0); |
9924 | } |
9925 | bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const noexcept { |
9926 | // We can assume that the same file will usually have the same pointer. |
9927 | // Thus, if the pointers are the same, there is no point in calling the strcmp |
9928 | return line < other.line || ( line == other.line && file != other.file && (std::strcmp(file, other.file) < 0)); |
9929 | } |
9930 | |
9931 | std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { |
9932 | #ifndef __GNUG__ |
9933 | os << info.file << '(' << info.line << ')'; |
9934 | #else |
9935 | os << info.file << ':' << info.line; |
9936 | #endif |
9937 | return os; |
9938 | } |
9939 | |
9940 | std::string StreamEndStop::operator+() const { |
9941 | return std::string(); |
9942 | } |
9943 | |
9944 | NonCopyable::NonCopyable() = default; |
9945 | NonCopyable::~NonCopyable() = default; |
9946 | |
9947 | } |
9948 | // end catch_common.cpp |
9949 | // start catch_config.cpp |
9950 | |
9951 | namespace Catch { |
9952 | |
9953 | Config::Config( ConfigData const& data ) |
9954 | : m_data( data ), |
9955 | m_stream( openStream() ) |
9956 | { |
9957 | // We need to trim filter specs to avoid trouble with superfluous |
9958 | // whitespace (esp. important for bdd macros, as those are manually |
9959 | // aligned with whitespace). |
9960 | |
9961 | for (auto& elem : m_data.testsOrTags) { |
9962 | elem = trim(elem); |
9963 | } |
9964 | for (auto& elem : m_data.sectionsToRun) { |
9965 | elem = trim(elem); |
9966 | } |
9967 | |
9968 | TestSpecParser parser(ITagAliasRegistry::get()); |
9969 | if (!m_data.testsOrTags.empty()) { |
9970 | m_hasTestFilters = true; |
9971 | for (auto const& testOrTags : m_data.testsOrTags) { |
9972 | parser.parse(testOrTags); |
9973 | } |
9974 | } |
9975 | m_testSpec = parser.testSpec(); |
9976 | } |
9977 | |
9978 | std::string const& Config::getFilename() const { |
9979 | return m_data.outputFilename ; |
9980 | } |
9981 | |
9982 | bool Config::listTests() const { return m_data.listTests; } |
9983 | bool Config::listTestNamesOnly() const { return m_data.listTestNamesOnly; } |
9984 | bool Config::listTags() const { return m_data.listTags; } |
9985 | bool Config::listReporters() const { return m_data.listReporters; } |
9986 | |
9987 | std::string Config::getProcessName() const { return m_data.processName; } |
9988 | std::string const& Config::getReporterName() const { return m_data.reporterName; } |
9989 | |
9990 | std::vector<std::string> const& Config::getTestsOrTags() const { return m_data.testsOrTags; } |
9991 | std::vector<std::string> const& Config::getSectionsToRun() const { return m_data.sectionsToRun; } |
9992 | |
9993 | TestSpec const& Config::testSpec() const { return m_testSpec; } |
9994 | bool Config::hasTestFilters() const { return m_hasTestFilters; } |
9995 | |
9996 | bool Config::showHelp() const { return m_data.showHelp; } |
9997 | |
9998 | // IConfig interface |
9999 | bool Config::allowThrows() const { return !m_data.noThrow; } |
10000 | std::ostream& Config::stream() const { return m_stream->stream(); } |
10001 | std::string Config::name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } |
10002 | bool Config::includeSuccessfulResults() const { return m_data.showSuccessfulTests; } |
10003 | bool Config::warnAboutMissingAssertions() const { return !!(m_data.warnings & WarnAbout::NoAssertions); } |
10004 | bool Config::warnAboutNoTests() const { return !!(m_data.warnings & WarnAbout::NoTests); } |
10005 | ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; } |
10006 | double Config::minDuration() const { return m_data.minDuration; } |
10007 | RunTests::InWhatOrder Config::runOrder() const { return m_data.runOrder; } |
10008 | unsigned int Config::rngSeed() const { return m_data.rngSeed; } |
10009 | UseColour::YesOrNo Config::useColour() const { return m_data.useColour; } |
10010 | bool Config::shouldDebugBreak() const { return m_data.shouldDebugBreak; } |
10011 | int Config::abortAfter() const { return m_data.abortAfter; } |
10012 | bool Config::showInvisibles() const { return m_data.showInvisibles; } |
10013 | Verbosity Config::verbosity() const { return m_data.verbosity; } |
10014 | |
10015 | bool Config::benchmarkNoAnalysis() const { return m_data.benchmarkNoAnalysis; } |
10016 | int Config::benchmarkSamples() const { return m_data.benchmarkSamples; } |
10017 | double Config::benchmarkConfidenceInterval() const { return m_data.benchmarkConfidenceInterval; } |
10018 | unsigned int Config::benchmarkResamples() const { return m_data.benchmarkResamples; } |
10019 | std::chrono::milliseconds Config::benchmarkWarmupTime() const { return std::chrono::milliseconds(m_data.benchmarkWarmupTime); } |
10020 | |
10021 | IStream const* Config::openStream() { |
10022 | return Catch::makeStream(m_data.outputFilename); |
10023 | } |
10024 | |
10025 | } // end namespace Catch |
10026 | // end catch_config.cpp |
10027 | // start catch_console_colour.cpp |
10028 | |
10029 | #if defined(__clang__) |
10030 | # pragma clang diagnostic push |
10031 | # pragma clang diagnostic ignored "-Wexit-time-destructors" |
10032 | #endif |
10033 | |
10034 | // start catch_errno_guard.h |
10035 | |
10036 | namespace Catch { |
10037 | |
10038 | class ErrnoGuard { |
10039 | public: |
10040 | ErrnoGuard(); |
10041 | ~ErrnoGuard(); |
10042 | private: |
10043 | int m_oldErrno; |
10044 | }; |
10045 | |
10046 | } |
10047 | |
10048 | // end catch_errno_guard.h |
10049 | // start catch_windows_h_proxy.h |
10050 | |
10051 | |
10052 | #if defined(CATCH_PLATFORM_WINDOWS) |
10053 | |
10054 | #if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX) |
10055 | # define CATCH_DEFINED_NOMINMAX |
10056 | # define NOMINMAX |
10057 | #endif |
10058 | #if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN) |
10059 | # define CATCH_DEFINED_WIN32_LEAN_AND_MEAN |
10060 | # define WIN32_LEAN_AND_MEAN |
10061 | #endif |
10062 | |
10063 | #ifdef __AFXDLL |
10064 | #include <AfxWin.h> |
10065 | #else |
10066 | #include <windows.h> |
10067 | #endif |
10068 | |
10069 | #ifdef CATCH_DEFINED_NOMINMAX |
10070 | # undef NOMINMAX |
10071 | #endif |
10072 | #ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN |
10073 | # undef WIN32_LEAN_AND_MEAN |
10074 | #endif |
10075 | |
10076 | #endif // defined(CATCH_PLATFORM_WINDOWS) |
10077 | |
10078 | // end catch_windows_h_proxy.h |
10079 | #include <sstream> |
10080 | |
10081 | namespace Catch { |
10082 | namespace { |
10083 | |
10084 | struct IColourImpl { |
10085 | virtual ~IColourImpl() = default; |
10086 | virtual void use( Colour::Code _colourCode ) = 0; |
10087 | }; |
10088 | |
10089 | struct NoColourImpl : IColourImpl { |
10090 | void use( Colour::Code ) override {} |
10091 | |
10092 | static IColourImpl* instance() { |
10093 | static NoColourImpl s_instance; |
10094 | return &s_instance; |
10095 | } |
10096 | }; |
10097 | |
10098 | } // anon namespace |
10099 | } // namespace Catch |
10100 | |
10101 | #if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI ) |
10102 | # ifdef CATCH_PLATFORM_WINDOWS |
10103 | # define CATCH_CONFIG_COLOUR_WINDOWS |
10104 | # else |
10105 | # define CATCH_CONFIG_COLOUR_ANSI |
10106 | # endif |
10107 | #endif |
10108 | |
10109 | #if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) ///////////////////////////////////////// |
10110 | |
10111 | namespace Catch { |
10112 | namespace { |
10113 | |
10114 | class Win32ColourImpl : public IColourImpl { |
10115 | public: |
10116 | Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) |
10117 | { |
10118 | CONSOLE_SCREEN_BUFFER_INFO csbiInfo; |
10119 | GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); |
10120 | originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY ); |
10121 | originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY ); |
10122 | } |
10123 | |
10124 | void use( Colour::Code _colourCode ) override { |
10125 | switch( _colourCode ) { |
10126 | case Colour::None: return setTextAttribute( originalForegroundAttributes ); |
10127 | case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); |
10128 | case Colour::Red: return setTextAttribute( FOREGROUND_RED ); |
10129 | case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); |
10130 | case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE ); |
10131 | case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN ); |
10132 | case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN ); |
10133 | case Colour::Grey: return setTextAttribute( 0 ); |
10134 | |
10135 | case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY ); |
10136 | case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED ); |
10137 | case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); |
10138 | case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); |
10139 | case Colour::BrightYellow: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN ); |
10140 | |
10141 | case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" ); |
10142 | |
10143 | default: |
10144 | CATCH_ERROR( "Unknown colour requested" ); |
10145 | } |
10146 | } |
10147 | |
10148 | private: |
10149 | void setTextAttribute( WORD _textAttribute ) { |
10150 | SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes ); |
10151 | } |
10152 | HANDLE stdoutHandle; |
10153 | WORD originalForegroundAttributes; |
10154 | WORD originalBackgroundAttributes; |
10155 | }; |
10156 | |
10157 | IColourImpl* platformColourInstance() { |
10158 | static Win32ColourImpl s_instance; |
10159 | |
10160 | IConfigPtr config = getCurrentContext().getConfig(); |
10161 | UseColour::YesOrNo colourMode = config |
10162 | ? config->useColour() |
10163 | : UseColour::Auto; |
10164 | if( colourMode == UseColour::Auto ) |
10165 | colourMode = UseColour::Yes; |
10166 | return colourMode == UseColour::Yes |
10167 | ? &s_instance |
10168 | : NoColourImpl::instance(); |
10169 | } |
10170 | |
10171 | } // end anon namespace |
10172 | } // end namespace Catch |
10173 | |
10174 | #elif defined( CATCH_CONFIG_COLOUR_ANSI ) ////////////////////////////////////// |
10175 | |
10176 | #include <unistd.h> |
10177 | |
10178 | namespace Catch { |
10179 | namespace { |
10180 | |
10181 | // use POSIX/ ANSI console terminal codes |
10182 | // Thanks to Adam Strzelecki for original contribution |
10183 | // (http://github.com/nanoant) |
10184 | // https://github.com/philsquared/Catch/pull/131 |
10185 | class PosixColourImpl : public IColourImpl { |
10186 | public: |
10187 | void use( Colour::Code _colourCode ) override { |
10188 | switch( _colourCode ) { |
10189 | case Colour::None: |
10190 | case Colour::White: return setColour( "[0m" ); |
10191 | case Colour::Red: return setColour( "[0;31m" ); |
10192 | case Colour::Green: return setColour( "[0;32m" ); |
10193 | case Colour::Blue: return setColour( "[0;34m" ); |
10194 | case Colour::Cyan: return setColour( "[0;36m" ); |
10195 | case Colour::Yellow: return setColour( "[0;33m" ); |
10196 | case Colour::Grey: return setColour( "[1;30m" ); |
10197 | |
10198 | case Colour::LightGrey: return setColour( "[0;37m" ); |
10199 | case Colour::BrightRed: return setColour( "[1;31m" ); |
10200 | case Colour::BrightGreen: return setColour( "[1;32m" ); |
10201 | case Colour::BrightWhite: return setColour( "[1;37m" ); |
10202 | case Colour::BrightYellow: return setColour( "[1;33m" ); |
10203 | |
10204 | case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" ); |
10205 | default: CATCH_INTERNAL_ERROR( "Unknown colour requested" ); |
10206 | } |
10207 | } |
10208 | static IColourImpl* instance() { |
10209 | static PosixColourImpl s_instance; |
10210 | return &s_instance; |
10211 | } |
10212 | |
10213 | private: |
10214 | void setColour( const char* _escapeCode ) { |
10215 | getCurrentContext().getConfig()->stream() |
10216 | << '\033' << _escapeCode; |
10217 | } |
10218 | }; |
10219 | |
10220 | bool useColourOnPlatform() { |
10221 | return |
10222 | #if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE) |
10223 | !isDebuggerActive() && |
10224 | #endif |
10225 | #if !(defined(__DJGPP__) && defined(__STRICT_ANSI__)) |
10226 | isatty(STDOUT_FILENO) |
10227 | #else |
10228 | false |
10229 | #endif |
10230 | ; |
10231 | } |
10232 | IColourImpl* platformColourInstance() { |
10233 | ErrnoGuard guard; |
10234 | IConfigPtr config = getCurrentContext().getConfig(); |
10235 | UseColour::YesOrNo colourMode = config |
10236 | ? config->useColour() |
10237 | : UseColour::Auto; |
10238 | if( colourMode == UseColour::Auto ) |
10239 | colourMode = useColourOnPlatform() |
10240 | ? UseColour::Yes |
10241 | : UseColour::No; |
10242 | return colourMode == UseColour::Yes |
10243 | ? PosixColourImpl::instance() |
10244 | : NoColourImpl::instance(); |
10245 | } |
10246 | |
10247 | } // end anon namespace |
10248 | } // end namespace Catch |
10249 | |
10250 | #else // not Windows or ANSI /////////////////////////////////////////////// |
10251 | |
10252 | namespace Catch { |
10253 | |
10254 | static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); } |
10255 | |
10256 | } // end namespace Catch |
10257 | |
10258 | #endif // Windows/ ANSI/ None |
10259 | |
10260 | namespace Catch { |
10261 | |
10262 | Colour::Colour( Code _colourCode ) { use( _colourCode ); } |
10263 | Colour::Colour( Colour&& other ) noexcept { |
10264 | m_moved = other.m_moved; |
10265 | other.m_moved = true; |
10266 | } |
10267 | Colour& Colour::operator=( Colour&& other ) noexcept { |
10268 | m_moved = other.m_moved; |
10269 | other.m_moved = true; |
10270 | return *this; |
10271 | } |
10272 | |
10273 | Colour::~Colour(){ if( !m_moved ) use( None ); } |
10274 | |
10275 | void Colour::use( Code _colourCode ) { |
10276 | static IColourImpl* impl = platformColourInstance(); |
10277 | // Strictly speaking, this cannot possibly happen. |
10278 | // However, under some conditions it does happen (see #1626), |
10279 | // and this change is small enough that we can let practicality |
10280 | // triumph over purity in this case. |
10281 | if (impl != nullptr) { |
10282 | impl->use( _colourCode ); |
10283 | } |
10284 | } |
10285 | |
10286 | std::ostream& operator << ( std::ostream& os, Colour const& ) { |
10287 | return os; |
10288 | } |
10289 | |
10290 | } // end namespace Catch |
10291 | |
10292 | #if defined(__clang__) |
10293 | # pragma clang diagnostic pop |
10294 | #endif |
10295 | |
10296 | // end catch_console_colour.cpp |
10297 | // start catch_context.cpp |
10298 | |
10299 | namespace Catch { |
10300 | |
10301 | class Context : public IMutableContext, NonCopyable { |
10302 | |
10303 | public: // IContext |
10304 | IResultCapture* getResultCapture() override { |
10305 | return m_resultCapture; |
10306 | } |
10307 | IRunner* getRunner() override { |
10308 | return m_runner; |
10309 | } |
10310 | |
10311 | IConfigPtr const& getConfig() const override { |
10312 | return m_config; |
10313 | } |
10314 | |
10315 | ~Context() override; |
10316 | |
10317 | public: // IMutableContext |
10318 | void setResultCapture( IResultCapture* resultCapture ) override { |
10319 | m_resultCapture = resultCapture; |
10320 | } |
10321 | void setRunner( IRunner* runner ) override { |
10322 | m_runner = runner; |
10323 | } |
10324 | void setConfig( IConfigPtr const& config ) override { |
10325 | m_config = config; |
10326 | } |
10327 | |
10328 | friend IMutableContext& getCurrentMutableContext(); |
10329 | |
10330 | private: |
10331 | IConfigPtr m_config; |
10332 | IRunner* m_runner = nullptr; |
10333 | IResultCapture* m_resultCapture = nullptr; |
10334 | }; |
10335 | |
10336 | IMutableContext *IMutableContext::currentContext = nullptr; |
10337 | |
10338 | void IMutableContext::createContext() |
10339 | { |
10340 | currentContext = new Context(); |
10341 | } |
10342 | |
10343 | void cleanUpContext() { |
10344 | delete IMutableContext::currentContext; |
10345 | IMutableContext::currentContext = nullptr; |
10346 | } |
10347 | IContext::~IContext() = default; |
10348 | IMutableContext::~IMutableContext() = default; |
10349 | Context::~Context() = default; |
10350 | |
10351 | SimplePcg32& rng() { |
10352 | static SimplePcg32 s_rng; |
10353 | return s_rng; |
10354 | } |
10355 | |
10356 | } |
10357 | // end catch_context.cpp |
10358 | // start catch_debug_console.cpp |
10359 | |
10360 | // start catch_debug_console.h |
10361 | |
10362 | #include <string> |
10363 | |
10364 | namespace Catch { |
10365 | void writeToDebugConsole( std::string const& text ); |
10366 | } |
10367 | |
10368 | // end catch_debug_console.h |
10369 | #if defined(CATCH_CONFIG_ANDROID_LOGWRITE) |
10370 | #include <android/log.h> |
10371 | |
10372 | namespace Catch { |
10373 | void writeToDebugConsole( std::string const& text ) { |
10374 | __android_log_write( ANDROID_LOG_DEBUG, "Catch" , text.c_str() ); |
10375 | } |
10376 | } |
10377 | |
10378 | #elif defined(CATCH_PLATFORM_WINDOWS) |
10379 | |
10380 | namespace Catch { |
10381 | void writeToDebugConsole( std::string const& text ) { |
10382 | ::OutputDebugStringA( text.c_str() ); |
10383 | } |
10384 | } |
10385 | |
10386 | #else |
10387 | |
10388 | namespace Catch { |
10389 | void writeToDebugConsole( std::string const& text ) { |
10390 | // !TBD: Need a version for Mac/ XCode and other IDEs |
10391 | Catch::cout() << text; |
10392 | } |
10393 | } |
10394 | |
10395 | #endif // Platform |
10396 | // end catch_debug_console.cpp |
10397 | // start catch_debugger.cpp |
10398 | |
10399 | #if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE) |
10400 | |
10401 | # include <cassert> |
10402 | # include <sys/types.h> |
10403 | # include <unistd.h> |
10404 | # include <cstddef> |
10405 | # include <ostream> |
10406 | |
10407 | #ifdef __apple_build_version__ |
10408 | // These headers will only compile with AppleClang (XCode) |
10409 | // For other compilers (Clang, GCC, ... ) we need to exclude them |
10410 | # include <sys/sysctl.h> |
10411 | #endif |
10412 | |
10413 | namespace Catch { |
10414 | #ifdef __apple_build_version__ |
10415 | // The following function is taken directly from the following technical note: |
10416 | // https://developer.apple.com/library/archive/qa/qa1361/_index.html |
10417 | |
10418 | // Returns true if the current process is being debugged (either |
10419 | // running under the debugger or has a debugger attached post facto). |
10420 | bool isDebuggerActive(){ |
10421 | int mib[4]; |
10422 | struct kinfo_proc info; |
10423 | std::size_t size; |
10424 | |
10425 | // Initialize the flags so that, if sysctl fails for some bizarre |
10426 | // reason, we get a predictable result. |
10427 | |
10428 | info.kp_proc.p_flag = 0; |
10429 | |
10430 | // Initialize mib, which tells sysctl the info we want, in this case |
10431 | // we're looking for information about a specific process ID. |
10432 | |
10433 | mib[0] = CTL_KERN; |
10434 | mib[1] = KERN_PROC; |
10435 | mib[2] = KERN_PROC_PID; |
10436 | mib[3] = getpid(); |
10437 | |
10438 | // Call sysctl. |
10439 | |
10440 | size = sizeof(info); |
10441 | if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, nullptr, 0) != 0 ) { |
10442 | Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; |
10443 | return false; |
10444 | } |
10445 | |
10446 | // We're being debugged if the P_TRACED flag is set. |
10447 | |
10448 | return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); |
10449 | } |
10450 | #else |
10451 | bool isDebuggerActive() { |
10452 | // We need to find another way to determine this for non-appleclang compilers on macOS |
10453 | return false; |
10454 | } |
10455 | #endif |
10456 | } // namespace Catch |
10457 | |
10458 | #elif defined(CATCH_PLATFORM_LINUX) |
10459 | #include <fstream> |
10460 | #include <string> |
10461 | |
10462 | namespace Catch{ |
10463 | // The standard POSIX way of detecting a debugger is to attempt to |
10464 | // ptrace() the process, but this needs to be done from a child and not |
10465 | // this process itself to still allow attaching to this process later |
10466 | // if wanted, so is rather heavy. Under Linux we have the PID of the |
10467 | // "debugger" (which doesn't need to be gdb, of course, it could also |
10468 | // be strace, for example) in /proc/$PID/status, so just get it from |
10469 | // there instead. |
10470 | bool isDebuggerActive(){ |
10471 | // Libstdc++ has a bug, where std::ifstream sets errno to 0 |
10472 | // This way our users can properly assert over errno values |
10473 | ErrnoGuard guard; |
10474 | std::ifstream in("/proc/self/status" ); |
10475 | for( std::string line; std::getline(in, line); ) { |
10476 | static const int PREFIX_LEN = 11; |
10477 | if( line.compare(0, PREFIX_LEN, "TracerPid:\t" ) == 0 ) { |
10478 | // We're traced if the PID is not 0 and no other PID starts |
10479 | // with 0 digit, so it's enough to check for just a single |
10480 | // character. |
10481 | return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0'; |
10482 | } |
10483 | } |
10484 | |
10485 | return false; |
10486 | } |
10487 | } // namespace Catch |
10488 | #elif defined(_MSC_VER) |
10489 | extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); |
10490 | namespace Catch { |
10491 | bool isDebuggerActive() { |
10492 | return IsDebuggerPresent() != 0; |
10493 | } |
10494 | } |
10495 | #elif defined(__MINGW32__) |
10496 | extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); |
10497 | namespace Catch { |
10498 | bool isDebuggerActive() { |
10499 | return IsDebuggerPresent() != 0; |
10500 | } |
10501 | } |
10502 | #else |
10503 | namespace Catch { |
10504 | bool isDebuggerActive() { return false; } |
10505 | } |
10506 | #endif // Platform |
10507 | // end catch_debugger.cpp |
10508 | // start catch_decomposer.cpp |
10509 | |
10510 | namespace Catch { |
10511 | |
10512 | ITransientExpression::~ITransientExpression() = default; |
10513 | |
10514 | void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ) { |
10515 | if( lhs.size() + rhs.size() < 40 && |
10516 | lhs.find('\n') == std::string::npos && |
10517 | rhs.find('\n') == std::string::npos ) |
10518 | os << lhs << " " << op << " " << rhs; |
10519 | else |
10520 | os << lhs << "\n" << op << "\n" << rhs; |
10521 | } |
10522 | } |
10523 | // end catch_decomposer.cpp |
10524 | // start catch_enforce.cpp |
10525 | |
10526 | #include <stdexcept> |
10527 | |
10528 | namespace Catch { |
10529 | #if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER) |
10530 | [[noreturn]] |
10531 | void throw_exception(std::exception const& e) { |
10532 | Catch::cerr() << "Catch will terminate because it needed to throw an exception.\n" |
10533 | << "The message was: " << e.what() << '\n'; |
10534 | std::terminate(); |
10535 | } |
10536 | #endif |
10537 | |
10538 | [[noreturn]] |
10539 | void throw_logic_error(std::string const& msg) { |
10540 | throw_exception(std::logic_error(msg)); |
10541 | } |
10542 | |
10543 | [[noreturn]] |
10544 | void throw_domain_error(std::string const& msg) { |
10545 | throw_exception(std::domain_error(msg)); |
10546 | } |
10547 | |
10548 | [[noreturn]] |
10549 | void throw_runtime_error(std::string const& msg) { |
10550 | throw_exception(std::runtime_error(msg)); |
10551 | } |
10552 | |
10553 | } // namespace Catch; |
10554 | // end catch_enforce.cpp |
10555 | // start catch_enum_values_registry.cpp |
10556 | // start catch_enum_values_registry.h |
10557 | |
10558 | #include <vector> |
10559 | #include <memory> |
10560 | |
10561 | namespace Catch { |
10562 | |
10563 | namespace Detail { |
10564 | |
10565 | std::unique_ptr<EnumInfo> makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ); |
10566 | |
10567 | class EnumValuesRegistry : public IMutableEnumValuesRegistry { |
10568 | |
10569 | std::vector<std::unique_ptr<EnumInfo>> m_enumInfos; |
10570 | |
10571 | EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::vector<int> const& values) override; |
10572 | }; |
10573 | |
10574 | std::vector<StringRef> parseEnums( StringRef enums ); |
10575 | |
10576 | } // Detail |
10577 | |
10578 | } // Catch |
10579 | |
10580 | // end catch_enum_values_registry.h |
10581 | |
10582 | #include <map> |
10583 | #include <cassert> |
10584 | |
10585 | namespace Catch { |
10586 | |
10587 | IMutableEnumValuesRegistry::~IMutableEnumValuesRegistry() {} |
10588 | |
10589 | namespace Detail { |
10590 | |
10591 | namespace { |
10592 | // Extracts the actual name part of an enum instance |
10593 | // In other words, it returns the Blue part of Bikeshed::Colour::Blue |
10594 | StringRef extractInstanceName(StringRef enumInstance) { |
10595 | // Find last occurrence of ":" |
10596 | size_t name_start = enumInstance.size(); |
10597 | while (name_start > 0 && enumInstance[name_start - 1] != ':') { |
10598 | --name_start; |
10599 | } |
10600 | return enumInstance.substr(name_start, enumInstance.size() - name_start); |
10601 | } |
10602 | } |
10603 | |
10604 | std::vector<StringRef> parseEnums( StringRef enums ) { |
10605 | auto enumValues = splitStringRef( enums, ',' ); |
10606 | std::vector<StringRef> parsed; |
10607 | parsed.reserve( enumValues.size() ); |
10608 | for( auto const& enumValue : enumValues ) { |
10609 | parsed.push_back(trim(extractInstanceName(enumValue))); |
10610 | } |
10611 | return parsed; |
10612 | } |
10613 | |
10614 | EnumInfo::~EnumInfo() {} |
10615 | |
10616 | StringRef EnumInfo::lookup( int value ) const { |
10617 | for( auto const& valueToName : m_values ) { |
10618 | if( valueToName.first == value ) |
10619 | return valueToName.second; |
10620 | } |
10621 | return "{** unexpected enum value **}"_sr ; |
10622 | } |
10623 | |
10624 | std::unique_ptr<EnumInfo> makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ) { |
10625 | std::unique_ptr<EnumInfo> enumInfo( new EnumInfo ); |
10626 | enumInfo->m_name = enumName; |
10627 | enumInfo->m_values.reserve( values.size() ); |
10628 | |
10629 | const auto valueNames = Catch::Detail::parseEnums( allValueNames ); |
10630 | assert( valueNames.size() == values.size() ); |
10631 | std::size_t i = 0; |
10632 | for( auto value : values ) |
10633 | enumInfo->m_values.emplace_back(value, valueNames[i++]); |
10634 | |
10635 | return enumInfo; |
10636 | } |
10637 | |
10638 | EnumInfo const& EnumValuesRegistry::registerEnum( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ) { |
10639 | m_enumInfos.push_back(makeEnumInfo(enumName, allValueNames, values)); |
10640 | return *m_enumInfos.back(); |
10641 | } |
10642 | |
10643 | } // Detail |
10644 | } // Catch |
10645 | |
10646 | // end catch_enum_values_registry.cpp |
10647 | // start catch_errno_guard.cpp |
10648 | |
10649 | #include <cerrno> |
10650 | |
10651 | namespace Catch { |
10652 | ErrnoGuard::ErrnoGuard():m_oldErrno(errno){} |
10653 | ErrnoGuard::~ErrnoGuard() { errno = m_oldErrno; } |
10654 | } |
10655 | // end catch_errno_guard.cpp |
10656 | // start catch_exception_translator_registry.cpp |
10657 | |
10658 | // start catch_exception_translator_registry.h |
10659 | |
10660 | #include <vector> |
10661 | #include <string> |
10662 | #include <memory> |
10663 | |
10664 | namespace Catch { |
10665 | |
10666 | class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { |
10667 | public: |
10668 | ~ExceptionTranslatorRegistry(); |
10669 | virtual void registerTranslator( const IExceptionTranslator* translator ); |
10670 | std::string translateActiveException() const override; |
10671 | std::string tryTranslators() const; |
10672 | |
10673 | private: |
10674 | std::vector<std::unique_ptr<IExceptionTranslator const>> m_translators; |
10675 | }; |
10676 | } |
10677 | |
10678 | // end catch_exception_translator_registry.h |
10679 | #ifdef __OBJC__ |
10680 | #import "Foundation/Foundation.h" |
10681 | #endif |
10682 | |
10683 | namespace Catch { |
10684 | |
10685 | ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() { |
10686 | } |
10687 | |
10688 | void ExceptionTranslatorRegistry::registerTranslator( const IExceptionTranslator* translator ) { |
10689 | m_translators.push_back( std::unique_ptr<const IExceptionTranslator>( translator ) ); |
10690 | } |
10691 | |
10692 | #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) |
10693 | std::string ExceptionTranslatorRegistry::translateActiveException() const { |
10694 | try { |
10695 | #ifdef __OBJC__ |
10696 | // In Objective-C try objective-c exceptions first |
10697 | @try { |
10698 | return tryTranslators(); |
10699 | } |
10700 | @catch (NSException *exception) { |
10701 | return Catch::Detail::stringify( [exception description] ); |
10702 | } |
10703 | #else |
10704 | // Compiling a mixed mode project with MSVC means that CLR |
10705 | // exceptions will be caught in (...) as well. However, these |
10706 | // do not fill-in std::current_exception and thus lead to crash |
10707 | // when attempting rethrow. |
10708 | // /EHa switch also causes structured exceptions to be caught |
10709 | // here, but they fill-in current_exception properly, so |
10710 | // at worst the output should be a little weird, instead of |
10711 | // causing a crash. |
10712 | if (std::current_exception() == nullptr) { |
10713 | return "Non C++ exception. Possibly a CLR exception." ; |
10714 | } |
10715 | return tryTranslators(); |
10716 | #endif |
10717 | } |
10718 | catch( TestFailureException& ) { |
10719 | std::rethrow_exception(std::current_exception()); |
10720 | } |
10721 | catch( std::exception& ex ) { |
10722 | return ex.what(); |
10723 | } |
10724 | catch( std::string& msg ) { |
10725 | return msg; |
10726 | } |
10727 | catch( const char* msg ) { |
10728 | return msg; |
10729 | } |
10730 | catch(...) { |
10731 | return "Unknown exception" ; |
10732 | } |
10733 | } |
10734 | |
10735 | std::string ExceptionTranslatorRegistry::tryTranslators() const { |
10736 | if (m_translators.empty()) { |
10737 | std::rethrow_exception(std::current_exception()); |
10738 | } else { |
10739 | return m_translators[0]->translate(m_translators.begin() + 1, m_translators.end()); |
10740 | } |
10741 | } |
10742 | |
10743 | #else // ^^ Exceptions are enabled // Exceptions are disabled vv |
10744 | std::string ExceptionTranslatorRegistry::translateActiveException() const { |
10745 | CATCH_INTERNAL_ERROR("Attempted to translate active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!" ); |
10746 | } |
10747 | |
10748 | std::string ExceptionTranslatorRegistry::tryTranslators() const { |
10749 | CATCH_INTERNAL_ERROR("Attempted to use exception translators under CATCH_CONFIG_DISABLE_EXCEPTIONS!" ); |
10750 | } |
10751 | #endif |
10752 | |
10753 | } |
10754 | // end catch_exception_translator_registry.cpp |
10755 | // start catch_fatal_condition.cpp |
10756 | |
10757 | #include <algorithm> |
10758 | |
10759 | #if !defined( CATCH_CONFIG_WINDOWS_SEH ) && !defined( CATCH_CONFIG_POSIX_SIGNALS ) |
10760 | |
10761 | namespace Catch { |
10762 | |
10763 | // If neither SEH nor signal handling is required, the handler impls |
10764 | // do not have to do anything, and can be empty. |
10765 | void FatalConditionHandler::engage_platform() {} |
10766 | void FatalConditionHandler::disengage_platform() {} |
10767 | FatalConditionHandler::FatalConditionHandler() = default; |
10768 | FatalConditionHandler::~FatalConditionHandler() = default; |
10769 | |
10770 | } // end namespace Catch |
10771 | |
10772 | #endif // !CATCH_CONFIG_WINDOWS_SEH && !CATCH_CONFIG_POSIX_SIGNALS |
10773 | |
10774 | #if defined( CATCH_CONFIG_WINDOWS_SEH ) && defined( CATCH_CONFIG_POSIX_SIGNALS ) |
10775 | #error "Inconsistent configuration: Windows' SEH handling and POSIX signals cannot be enabled at the same time" |
10776 | #endif // CATCH_CONFIG_WINDOWS_SEH && CATCH_CONFIG_POSIX_SIGNALS |
10777 | |
10778 | #if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS ) |
10779 | |
10780 | namespace { |
10781 | //! Signals fatal error message to the run context |
10782 | void reportFatal( char const * const message ) { |
10783 | Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message ); |
10784 | } |
10785 | |
10786 | //! Minimal size Catch2 needs for its own fatal error handling. |
10787 | //! Picked anecdotally, so it might not be sufficient on all |
10788 | //! platforms, and for all configurations. |
10789 | constexpr std::size_t minStackSizeForErrors = 32 * 1024; |
10790 | } // end unnamed namespace |
10791 | |
10792 | #endif // CATCH_CONFIG_WINDOWS_SEH || CATCH_CONFIG_POSIX_SIGNALS |
10793 | |
10794 | #if defined( CATCH_CONFIG_WINDOWS_SEH ) |
10795 | |
10796 | namespace Catch { |
10797 | |
10798 | struct SignalDefs { DWORD id; const char* name; }; |
10799 | |
10800 | // There is no 1-1 mapping between signals and windows exceptions. |
10801 | // Windows can easily distinguish between SO and SigSegV, |
10802 | // but SigInt, SigTerm, etc are handled differently. |
10803 | static SignalDefs signalDefs[] = { |
10804 | { static_cast<DWORD>(EXCEPTION_ILLEGAL_INSTRUCTION), "SIGILL - Illegal instruction signal" }, |
10805 | { static_cast<DWORD>(EXCEPTION_STACK_OVERFLOW), "SIGSEGV - Stack overflow" }, |
10806 | { static_cast<DWORD>(EXCEPTION_ACCESS_VIOLATION), "SIGSEGV - Segmentation violation signal" }, |
10807 | { static_cast<DWORD>(EXCEPTION_INT_DIVIDE_BY_ZERO), "Divide by zero error" }, |
10808 | }; |
10809 | |
10810 | static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) { |
10811 | for (auto const& def : signalDefs) { |
10812 | if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) { |
10813 | reportFatal(def.name); |
10814 | } |
10815 | } |
10816 | // If its not an exception we care about, pass it along. |
10817 | // This stops us from eating debugger breaks etc. |
10818 | return EXCEPTION_CONTINUE_SEARCH; |
10819 | } |
10820 | |
10821 | // Since we do not support multiple instantiations, we put these |
10822 | // into global variables and rely on cleaning them up in outlined |
10823 | // constructors/destructors |
10824 | static PVOID exceptionHandlerHandle = nullptr; |
10825 | |
10826 | // For MSVC, we reserve part of the stack memory for handling |
10827 | // memory overflow structured exception. |
10828 | FatalConditionHandler::FatalConditionHandler() { |
10829 | ULONG guaranteeSize = static_cast<ULONG>(minStackSizeForErrors); |
10830 | if (!SetThreadStackGuarantee(&guaranteeSize)) { |
10831 | // We do not want to fully error out, because needing |
10832 | // the stack reserve should be rare enough anyway. |
10833 | Catch::cerr() |
10834 | << "Failed to reserve piece of stack." |
10835 | << " Stack overflows will not be reported successfully." ; |
10836 | } |
10837 | } |
10838 | |
10839 | // We do not attempt to unset the stack guarantee, because |
10840 | // Windows does not support lowering the stack size guarantee. |
10841 | FatalConditionHandler::~FatalConditionHandler() = default; |
10842 | |
10843 | void FatalConditionHandler::engage_platform() { |
10844 | // Register as first handler in current chain |
10845 | exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException); |
10846 | if (!exceptionHandlerHandle) { |
10847 | CATCH_RUNTIME_ERROR("Could not register vectored exception handler" ); |
10848 | } |
10849 | } |
10850 | |
10851 | void FatalConditionHandler::disengage_platform() { |
10852 | if (!RemoveVectoredExceptionHandler(exceptionHandlerHandle)) { |
10853 | CATCH_RUNTIME_ERROR("Could not unregister vectored exception handler" ); |
10854 | } |
10855 | exceptionHandlerHandle = nullptr; |
10856 | } |
10857 | |
10858 | } // end namespace Catch |
10859 | |
10860 | #endif // CATCH_CONFIG_WINDOWS_SEH |
10861 | |
10862 | #if defined( CATCH_CONFIG_POSIX_SIGNALS ) |
10863 | |
10864 | #include <signal.h> |
10865 | |
10866 | namespace Catch { |
10867 | |
10868 | struct SignalDefs { |
10869 | int id; |
10870 | const char* name; |
10871 | }; |
10872 | |
10873 | static SignalDefs signalDefs[] = { |
10874 | { SIGINT, "SIGINT - Terminal interrupt signal" }, |
10875 | { SIGILL, "SIGILL - Illegal instruction signal" }, |
10876 | { SIGFPE, "SIGFPE - Floating point error signal" }, |
10877 | { SIGSEGV, "SIGSEGV - Segmentation violation signal" }, |
10878 | { SIGTERM, "SIGTERM - Termination request signal" }, |
10879 | { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } |
10880 | }; |
10881 | |
10882 | // Older GCCs trigger -Wmissing-field-initializers for T foo = {} |
10883 | // which is zero initialization, but not explicit. We want to avoid |
10884 | // that. |
10885 | #if defined(__GNUC__) |
10886 | # pragma GCC diagnostic push |
10887 | # pragma GCC diagnostic ignored "-Wmissing-field-initializers" |
10888 | #endif |
10889 | |
10890 | static char* altStackMem = nullptr; |
10891 | static std::size_t altStackSize = 0; |
10892 | static stack_t oldSigStack{}; |
10893 | static struct sigaction oldSigActions[sizeof(signalDefs) / sizeof(SignalDefs)]{}; |
10894 | |
10895 | static void restorePreviousSignalHandlers() { |
10896 | // We set signal handlers back to the previous ones. Hopefully |
10897 | // nobody overwrote them in the meantime, and doesn't expect |
10898 | // their signal handlers to live past ours given that they |
10899 | // installed them after ours.. |
10900 | for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) { |
10901 | sigaction(signalDefs[i].id, &oldSigActions[i], nullptr); |
10902 | } |
10903 | // Return the old stack |
10904 | sigaltstack(&oldSigStack, nullptr); |
10905 | } |
10906 | |
10907 | static void handleSignal( int sig ) { |
10908 | char const * name = "<unknown signal>" ; |
10909 | for (auto const& def : signalDefs) { |
10910 | if (sig == def.id) { |
10911 | name = def.name; |
10912 | break; |
10913 | } |
10914 | } |
10915 | // We need to restore previous signal handlers and let them do |
10916 | // their thing, so that the users can have the debugger break |
10917 | // when a signal is raised, and so on. |
10918 | restorePreviousSignalHandlers(); |
10919 | reportFatal( name ); |
10920 | raise( sig ); |
10921 | } |
10922 | |
10923 | FatalConditionHandler::FatalConditionHandler() { |
10924 | assert(!altStackMem && "Cannot initialize POSIX signal handler when one already exists" ); |
10925 | if (altStackSize == 0) { |
10926 | altStackSize = std::max(static_cast<size_t>(SIGSTKSZ), minStackSizeForErrors); |
10927 | } |
10928 | altStackMem = new char[altStackSize](); |
10929 | } |
10930 | |
10931 | FatalConditionHandler::~FatalConditionHandler() { |
10932 | delete[] altStackMem; |
10933 | // We signal that another instance can be constructed by zeroing |
10934 | // out the pointer. |
10935 | altStackMem = nullptr; |
10936 | } |
10937 | |
10938 | void FatalConditionHandler::engage_platform() { |
10939 | stack_t sigStack; |
10940 | sigStack.ss_sp = altStackMem; |
10941 | sigStack.ss_size = altStackSize; |
10942 | sigStack.ss_flags = 0; |
10943 | sigaltstack(&sigStack, &oldSigStack); |
10944 | struct sigaction sa = { }; |
10945 | |
10946 | sa.sa_handler = handleSignal; |
10947 | sa.sa_flags = SA_ONSTACK; |
10948 | for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) { |
10949 | sigaction(signalDefs[i].id, &sa, &oldSigActions[i]); |
10950 | } |
10951 | } |
10952 | |
10953 | #if defined(__GNUC__) |
10954 | # pragma GCC diagnostic pop |
10955 | #endif |
10956 | |
10957 | void FatalConditionHandler::disengage_platform() { |
10958 | restorePreviousSignalHandlers(); |
10959 | } |
10960 | |
10961 | } // end namespace Catch |
10962 | |
10963 | #endif // CATCH_CONFIG_POSIX_SIGNALS |
10964 | // end catch_fatal_condition.cpp |
10965 | // start catch_generators.cpp |
10966 | |
10967 | #include <limits> |
10968 | #include <set> |
10969 | |
10970 | namespace Catch { |
10971 | |
10972 | IGeneratorTracker::~IGeneratorTracker() {} |
10973 | |
10974 | const char* GeneratorException::what() const noexcept { |
10975 | return m_msg; |
10976 | } |
10977 | |
10978 | namespace Generators { |
10979 | |
10980 | GeneratorUntypedBase::~GeneratorUntypedBase() {} |
10981 | |
10982 | auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { |
10983 | return getResultCapture().acquireGeneratorTracker( generatorName, lineInfo ); |
10984 | } |
10985 | |
10986 | } // namespace Generators |
10987 | } // namespace Catch |
10988 | // end catch_generators.cpp |
10989 | // start catch_interfaces_capture.cpp |
10990 | |
10991 | namespace Catch { |
10992 | IResultCapture::~IResultCapture() = default; |
10993 | } |
10994 | // end catch_interfaces_capture.cpp |
10995 | // start catch_interfaces_config.cpp |
10996 | |
10997 | namespace Catch { |
10998 | IConfig::~IConfig() = default; |
10999 | } |
11000 | // end catch_interfaces_config.cpp |
11001 | // start catch_interfaces_exception.cpp |
11002 | |
11003 | namespace Catch { |
11004 | IExceptionTranslator::~IExceptionTranslator() = default; |
11005 | IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() = default; |
11006 | } |
11007 | // end catch_interfaces_exception.cpp |
11008 | // start catch_interfaces_registry_hub.cpp |
11009 | |
11010 | namespace Catch { |
11011 | IRegistryHub::~IRegistryHub() = default; |
11012 | IMutableRegistryHub::~IMutableRegistryHub() = default; |
11013 | } |
11014 | // end catch_interfaces_registry_hub.cpp |
11015 | // start catch_interfaces_reporter.cpp |
11016 | |
11017 | // start catch_reporter_listening.h |
11018 | |
11019 | namespace Catch { |
11020 | |
11021 | class ListeningReporter : public IStreamingReporter { |
11022 | using Reporters = std::vector<IStreamingReporterPtr>; |
11023 | Reporters m_listeners; |
11024 | IStreamingReporterPtr m_reporter = nullptr; |
11025 | ReporterPreferences m_preferences; |
11026 | |
11027 | public: |
11028 | ListeningReporter(); |
11029 | |
11030 | void addListener( IStreamingReporterPtr&& listener ); |
11031 | void addReporter( IStreamingReporterPtr&& reporter ); |
11032 | |
11033 | public: // IStreamingReporter |
11034 | |
11035 | ReporterPreferences getPreferences() const override; |
11036 | |
11037 | void noMatchingTestCases( std::string const& spec ) override; |
11038 | |
11039 | void reportInvalidArguments(std::string const&arg) override; |
11040 | |
11041 | static std::set<Verbosity> getSupportedVerbosities(); |
11042 | |
11043 | #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) |
11044 | void benchmarkPreparing(std::string const& name) override; |
11045 | void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) override; |
11046 | void benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) override; |
11047 | void benchmarkFailed(std::string const&) override; |
11048 | #endif // CATCH_CONFIG_ENABLE_BENCHMARKING |
11049 | |
11050 | void testRunStarting( TestRunInfo const& testRunInfo ) override; |
11051 | void testGroupStarting( GroupInfo const& groupInfo ) override; |
11052 | void testCaseStarting( TestCaseInfo const& testInfo ) override; |
11053 | void sectionStarting( SectionInfo const& sectionInfo ) override; |
11054 | void assertionStarting( AssertionInfo const& assertionInfo ) override; |
11055 | |
11056 | // The return value indicates if the messages buffer should be cleared: |
11057 | bool assertionEnded( AssertionStats const& assertionStats ) override; |
11058 | void sectionEnded( SectionStats const& sectionStats ) override; |
11059 | void testCaseEnded( TestCaseStats const& testCaseStats ) override; |
11060 | void testGroupEnded( TestGroupStats const& testGroupStats ) override; |
11061 | void testRunEnded( TestRunStats const& testRunStats ) override; |
11062 | |
11063 | void skipTest( TestCaseInfo const& testInfo ) override; |
11064 | bool isMulti() const override; |
11065 | |
11066 | }; |
11067 | |
11068 | } // end namespace Catch |
11069 | |
11070 | // end catch_reporter_listening.h |
11071 | namespace Catch { |
11072 | |
11073 | ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig ) |
11074 | : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} |
11075 | |
11076 | ReporterConfig::ReporterConfig( IConfigPtr const& _fullConfig, std::ostream& _stream ) |
11077 | : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} |
11078 | |
11079 | std::ostream& ReporterConfig::stream() const { return *m_stream; } |
11080 | IConfigPtr ReporterConfig::fullConfig() const { return m_fullConfig; } |
11081 | |
11082 | TestRunInfo::TestRunInfo( std::string const& _name ) : name( _name ) {} |
11083 | |
11084 | GroupInfo::GroupInfo( std::string const& _name, |
11085 | std::size_t _groupIndex, |
11086 | std::size_t _groupsCount ) |
11087 | : name( _name ), |
11088 | groupIndex( _groupIndex ), |
11089 | groupsCounts( _groupsCount ) |
11090 | {} |
11091 | |
11092 | AssertionStats::AssertionStats( AssertionResult const& _assertionResult, |
11093 | std::vector<MessageInfo> const& _infoMessages, |
11094 | Totals const& _totals ) |
11095 | : assertionResult( _assertionResult ), |
11096 | infoMessages( _infoMessages ), |
11097 | totals( _totals ) |
11098 | { |
11099 | assertionResult.m_resultData.lazyExpression.m_transientExpression = _assertionResult.m_resultData.lazyExpression.m_transientExpression; |
11100 | |
11101 | if( assertionResult.hasMessage() ) { |
11102 | // Copy message into messages list. |
11103 | // !TBD This should have been done earlier, somewhere |
11104 | MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); |
11105 | builder << assertionResult.getMessage(); |
11106 | builder.m_info.message = builder.m_stream.str(); |
11107 | |
11108 | infoMessages.push_back( builder.m_info ); |
11109 | } |
11110 | } |
11111 | |
11112 | AssertionStats::~AssertionStats() = default; |
11113 | |
11114 | SectionStats::SectionStats( SectionInfo const& _sectionInfo, |
11115 | Counts const& _assertions, |
11116 | double _durationInSeconds, |
11117 | bool _missingAssertions ) |
11118 | : sectionInfo( _sectionInfo ), |
11119 | assertions( _assertions ), |
11120 | durationInSeconds( _durationInSeconds ), |
11121 | missingAssertions( _missingAssertions ) |
11122 | {} |
11123 | |
11124 | SectionStats::~SectionStats() = default; |
11125 | |
11126 | TestCaseStats::TestCaseStats( TestCaseInfo const& _testInfo, |
11127 | Totals const& _totals, |
11128 | std::string const& _stdOut, |
11129 | std::string const& _stdErr, |
11130 | bool _aborting ) |
11131 | : testInfo( _testInfo ), |
11132 | totals( _totals ), |
11133 | stdOut( _stdOut ), |
11134 | stdErr( _stdErr ), |
11135 | aborting( _aborting ) |
11136 | {} |
11137 | |
11138 | TestCaseStats::~TestCaseStats() = default; |
11139 | |
11140 | TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo, |
11141 | Totals const& _totals, |
11142 | bool _aborting ) |
11143 | : groupInfo( _groupInfo ), |
11144 | totals( _totals ), |
11145 | aborting( _aborting ) |
11146 | {} |
11147 | |
11148 | TestGroupStats::TestGroupStats( GroupInfo const& _groupInfo ) |
11149 | : groupInfo( _groupInfo ), |
11150 | aborting( false ) |
11151 | {} |
11152 | |
11153 | TestGroupStats::~TestGroupStats() = default; |
11154 | |
11155 | TestRunStats::TestRunStats( TestRunInfo const& _runInfo, |
11156 | Totals const& _totals, |
11157 | bool _aborting ) |
11158 | : runInfo( _runInfo ), |
11159 | totals( _totals ), |
11160 | aborting( _aborting ) |
11161 | {} |
11162 | |
11163 | TestRunStats::~TestRunStats() = default; |
11164 | |
11165 | void IStreamingReporter::fatalErrorEncountered( StringRef ) {} |
11166 | bool IStreamingReporter::isMulti() const { return false; } |
11167 | |
11168 | IReporterFactory::~IReporterFactory() = default; |
11169 | IReporterRegistry::~IReporterRegistry() = default; |
11170 | |
11171 | } // end namespace Catch |
11172 | // end catch_interfaces_reporter.cpp |
11173 | // start catch_interfaces_runner.cpp |
11174 | |
11175 | namespace Catch { |
11176 | IRunner::~IRunner() = default; |
11177 | } |
11178 | // end catch_interfaces_runner.cpp |
11179 | // start catch_interfaces_testcase.cpp |
11180 | |
11181 | namespace Catch { |
11182 | ITestInvoker::~ITestInvoker() = default; |
11183 | ITestCaseRegistry::~ITestCaseRegistry() = default; |
11184 | } |
11185 | // end catch_interfaces_testcase.cpp |
11186 | // start catch_leak_detector.cpp |
11187 | |
11188 | #ifdef CATCH_CONFIG_WINDOWS_CRTDBG |
11189 | #include <crtdbg.h> |
11190 | |
11191 | namespace Catch { |
11192 | |
11193 | LeakDetector::LeakDetector() { |
11194 | int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); |
11195 | flag |= _CRTDBG_LEAK_CHECK_DF; |
11196 | flag |= _CRTDBG_ALLOC_MEM_DF; |
11197 | _CrtSetDbgFlag(flag); |
11198 | _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG); |
11199 | _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); |
11200 | // Change this to leaking allocation's number to break there |
11201 | _CrtSetBreakAlloc(-1); |
11202 | } |
11203 | } |
11204 | |
11205 | #else |
11206 | |
11207 | Catch::LeakDetector::LeakDetector() {} |
11208 | |
11209 | #endif |
11210 | |
11211 | Catch::LeakDetector::~LeakDetector() { |
11212 | Catch::cleanUp(); |
11213 | } |
11214 | // end catch_leak_detector.cpp |
11215 | // start catch_list.cpp |
11216 | |
11217 | // start catch_list.h |
11218 | |
11219 | #include <set> |
11220 | |
11221 | namespace Catch { |
11222 | |
11223 | std::size_t listTests( Config const& config ); |
11224 | |
11225 | std::size_t listTestsNamesOnly( Config const& config ); |
11226 | |
11227 | struct TagInfo { |
11228 | void add( std::string const& spelling ); |
11229 | std::string all() const; |
11230 | |
11231 | std::set<std::string> spellings; |
11232 | std::size_t count = 0; |
11233 | }; |
11234 | |
11235 | std::size_t listTags( Config const& config ); |
11236 | |
11237 | std::size_t listReporters(); |
11238 | |
11239 | Option<std::size_t> list( std::shared_ptr<Config> const& config ); |
11240 | |
11241 | } // end namespace Catch |
11242 | |
11243 | // end catch_list.h |
11244 | // start catch_text.h |
11245 | |
11246 | namespace Catch { |
11247 | using namespace clara::TextFlow; |
11248 | } |
11249 | |
11250 | // end catch_text.h |
11251 | #include <limits> |
11252 | #include <algorithm> |
11253 | #include <iomanip> |
11254 | |
11255 | namespace Catch { |
11256 | |
11257 | std::size_t listTests( Config const& config ) { |
11258 | TestSpec const& testSpec = config.testSpec(); |
11259 | if( config.hasTestFilters() ) |
11260 | Catch::cout() << "Matching test cases:\n" ; |
11261 | else { |
11262 | Catch::cout() << "All available test cases:\n" ; |
11263 | } |
11264 | |
11265 | auto matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); |
11266 | for( auto const& testCaseInfo : matchedTestCases ) { |
11267 | Colour::Code colour = testCaseInfo.isHidden() |
11268 | ? Colour::SecondaryText |
11269 | : Colour::None; |
11270 | Colour colourGuard( colour ); |
11271 | |
11272 | Catch::cout() << Column( testCaseInfo.name ).initialIndent( 2 ).indent( 4 ) << "\n" ; |
11273 | if( config.verbosity() >= Verbosity::High ) { |
11274 | Catch::cout() << Column( Catch::Detail::stringify( testCaseInfo.lineInfo ) ).indent(4) << std::endl; |
11275 | std::string description = testCaseInfo.description; |
11276 | if( description.empty() ) |
11277 | description = "(NO DESCRIPTION)" ; |
11278 | Catch::cout() << Column( description ).indent(4) << std::endl; |
11279 | } |
11280 | if( !testCaseInfo.tags.empty() ) |
11281 | Catch::cout() << Column( testCaseInfo.tagsAsString() ).indent( 6 ) << "\n" ; |
11282 | } |
11283 | |
11284 | if( !config.hasTestFilters() ) |
11285 | Catch::cout() << pluralise( matchedTestCases.size(), "test case" ) << '\n' << std::endl; |
11286 | else |
11287 | Catch::cout() << pluralise( matchedTestCases.size(), "matching test case" ) << '\n' << std::endl; |
11288 | return matchedTestCases.size(); |
11289 | } |
11290 | |
11291 | std::size_t listTestsNamesOnly( Config const& config ) { |
11292 | TestSpec const& testSpec = config.testSpec(); |
11293 | std::size_t matchedTests = 0; |
11294 | std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); |
11295 | for( auto const& testCaseInfo : matchedTestCases ) { |
11296 | matchedTests++; |
11297 | if( startsWith( testCaseInfo.name, '#' ) ) |
11298 | Catch::cout() << '"' << testCaseInfo.name << '"'; |
11299 | else |
11300 | Catch::cout() << testCaseInfo.name; |
11301 | if ( config.verbosity() >= Verbosity::High ) |
11302 | Catch::cout() << "\t@" << testCaseInfo.lineInfo; |
11303 | Catch::cout() << std::endl; |
11304 | } |
11305 | return matchedTests; |
11306 | } |
11307 | |
11308 | void TagInfo::add( std::string const& spelling ) { |
11309 | ++count; |
11310 | spellings.insert( spelling ); |
11311 | } |
11312 | |
11313 | std::string TagInfo::all() const { |
11314 | size_t size = 0; |
11315 | for (auto const& spelling : spellings) { |
11316 | // Add 2 for the brackes |
11317 | size += spelling.size() + 2; |
11318 | } |
11319 | |
11320 | std::string out; out.reserve(size); |
11321 | for (auto const& spelling : spellings) { |
11322 | out += '['; |
11323 | out += spelling; |
11324 | out += ']'; |
11325 | } |
11326 | return out; |
11327 | } |
11328 | |
11329 | std::size_t listTags( Config const& config ) { |
11330 | TestSpec const& testSpec = config.testSpec(); |
11331 | if( config.hasTestFilters() ) |
11332 | Catch::cout() << "Tags for matching test cases:\n" ; |
11333 | else { |
11334 | Catch::cout() << "All available tags:\n" ; |
11335 | } |
11336 | |
11337 | std::map<std::string, TagInfo> tagCounts; |
11338 | |
11339 | std::vector<TestCase> matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); |
11340 | for( auto const& testCase : matchedTestCases ) { |
11341 | for( auto const& tagName : testCase.getTestCaseInfo().tags ) { |
11342 | std::string lcaseTagName = toLower( tagName ); |
11343 | auto countIt = tagCounts.find( lcaseTagName ); |
11344 | if( countIt == tagCounts.end() ) |
11345 | countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; |
11346 | countIt->second.add( tagName ); |
11347 | } |
11348 | } |
11349 | |
11350 | for( auto const& tagCount : tagCounts ) { |
11351 | ReusableStringStream rss; |
11352 | rss << " " << std::setw(2) << tagCount.second.count << " " ; |
11353 | auto str = rss.str(); |
11354 | auto wrapper = Column( tagCount.second.all() ) |
11355 | .initialIndent( 0 ) |
11356 | .indent( str.size() ) |
11357 | .width( CATCH_CONFIG_CONSOLE_WIDTH-10 ); |
11358 | Catch::cout() << str << wrapper << '\n'; |
11359 | } |
11360 | Catch::cout() << pluralise( tagCounts.size(), "tag" ) << '\n' << std::endl; |
11361 | return tagCounts.size(); |
11362 | } |
11363 | |
11364 | std::size_t listReporters() { |
11365 | Catch::cout() << "Available reporters:\n" ; |
11366 | IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); |
11367 | std::size_t maxNameLen = 0; |
11368 | for( auto const& factoryKvp : factories ) |
11369 | maxNameLen = (std::max)( maxNameLen, factoryKvp.first.size() ); |
11370 | |
11371 | for( auto const& factoryKvp : factories ) { |
11372 | Catch::cout() |
11373 | << Column( factoryKvp.first + ":" ) |
11374 | .indent(2) |
11375 | .width( 5+maxNameLen ) |
11376 | + Column( factoryKvp.second->getDescription() ) |
11377 | .initialIndent(0) |
11378 | .indent(2) |
11379 | .width( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) |
11380 | << "\n" ; |
11381 | } |
11382 | Catch::cout() << std::endl; |
11383 | return factories.size(); |
11384 | } |
11385 | |
11386 | Option<std::size_t> list( std::shared_ptr<Config> const& config ) { |
11387 | Option<std::size_t> listedCount; |
11388 | getCurrentMutableContext().setConfig( config ); |
11389 | if( config->listTests() ) |
11390 | listedCount = listedCount.valueOr(0) + listTests( *config ); |
11391 | if( config->listTestNamesOnly() ) |
11392 | listedCount = listedCount.valueOr(0) + listTestsNamesOnly( *config ); |
11393 | if( config->listTags() ) |
11394 | listedCount = listedCount.valueOr(0) + listTags( *config ); |
11395 | if( config->listReporters() ) |
11396 | listedCount = listedCount.valueOr(0) + listReporters(); |
11397 | return listedCount; |
11398 | } |
11399 | |
11400 | } // end namespace Catch |
11401 | // end catch_list.cpp |
11402 | // start catch_matchers.cpp |
11403 | |
11404 | namespace Catch { |
11405 | namespace Matchers { |
11406 | namespace Impl { |
11407 | |
11408 | std::string MatcherUntypedBase::toString() const { |
11409 | if( m_cachedToString.empty() ) |
11410 | m_cachedToString = describe(); |
11411 | return m_cachedToString; |
11412 | } |
11413 | |
11414 | MatcherUntypedBase::~MatcherUntypedBase() = default; |
11415 | |
11416 | } // namespace Impl |
11417 | } // namespace Matchers |
11418 | |
11419 | using namespace Matchers; |
11420 | using Matchers::Impl::MatcherBase; |
11421 | |
11422 | } // namespace Catch |
11423 | // end catch_matchers.cpp |
11424 | // start catch_matchers_exception.cpp |
11425 | |
11426 | namespace Catch { |
11427 | namespace Matchers { |
11428 | namespace Exception { |
11429 | |
11430 | bool ExceptionMessageMatcher::match(std::exception const& ex) const { |
11431 | return ex.what() == m_message; |
11432 | } |
11433 | |
11434 | std::string ExceptionMessageMatcher::describe() const { |
11435 | return "exception message matches \"" + m_message + "\"" ; |
11436 | } |
11437 | |
11438 | } |
11439 | Exception::ExceptionMessageMatcher Message(std::string const& message) { |
11440 | return Exception::ExceptionMessageMatcher(message); |
11441 | } |
11442 | |
11443 | // namespace Exception |
11444 | } // namespace Matchers |
11445 | } // namespace Catch |
11446 | // end catch_matchers_exception.cpp |
11447 | // start catch_matchers_floating.cpp |
11448 | |
11449 | // start catch_polyfills.hpp |
11450 | |
11451 | namespace Catch { |
11452 | bool isnan(float f); |
11453 | bool isnan(double d); |
11454 | } |
11455 | |
11456 | // end catch_polyfills.hpp |
11457 | // start catch_to_string.hpp |
11458 | |
11459 | #include <string> |
11460 | |
11461 | namespace Catch { |
11462 | template <typename T> |
11463 | std::string to_string(T const& t) { |
11464 | #if defined(CATCH_CONFIG_CPP11_TO_STRING) |
11465 | return std::to_string(t); |
11466 | #else |
11467 | ReusableStringStream rss; |
11468 | rss << t; |
11469 | return rss.str(); |
11470 | #endif |
11471 | } |
11472 | } // end namespace Catch |
11473 | |
11474 | // end catch_to_string.hpp |
11475 | #include <algorithm> |
11476 | #include <cmath> |
11477 | #include <cstdlib> |
11478 | #include <cstdint> |
11479 | #include <cstring> |
11480 | #include <sstream> |
11481 | #include <type_traits> |
11482 | #include <iomanip> |
11483 | #include <limits> |
11484 | |
11485 | namespace Catch { |
11486 | namespace { |
11487 | |
11488 | int32_t convert(float f) { |
11489 | static_assert(sizeof(float) == sizeof(int32_t), "Important ULP matcher assumption violated" ); |
11490 | int32_t i; |
11491 | std::memcpy(&i, &f, sizeof(f)); |
11492 | return i; |
11493 | } |
11494 | |
11495 | int64_t convert(double d) { |
11496 | static_assert(sizeof(double) == sizeof(int64_t), "Important ULP matcher assumption violated" ); |
11497 | int64_t i; |
11498 | std::memcpy(&i, &d, sizeof(d)); |
11499 | return i; |
11500 | } |
11501 | |
11502 | template <typename FP> |
11503 | bool almostEqualUlps(FP lhs, FP rhs, uint64_t maxUlpDiff) { |
11504 | // Comparison with NaN should always be false. |
11505 | // This way we can rule it out before getting into the ugly details |
11506 | if (Catch::isnan(lhs) || Catch::isnan(rhs)) { |
11507 | return false; |
11508 | } |
11509 | |
11510 | auto lc = convert(lhs); |
11511 | auto rc = convert(rhs); |
11512 | |
11513 | if ((lc < 0) != (rc < 0)) { |
11514 | // Potentially we can have +0 and -0 |
11515 | return lhs == rhs; |
11516 | } |
11517 | |
11518 | // static cast as a workaround for IBM XLC |
11519 | auto ulpDiff = std::abs(static_cast<FP>(lc - rc)); |
11520 | return static_cast<uint64_t>(ulpDiff) <= maxUlpDiff; |
11521 | } |
11522 | |
11523 | #if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) |
11524 | |
11525 | float nextafter(float x, float y) { |
11526 | return ::nextafterf(x, y); |
11527 | } |
11528 | |
11529 | double nextafter(double x, double y) { |
11530 | return ::nextafter(x, y); |
11531 | } |
11532 | |
11533 | #endif // ^^^ CATCH_CONFIG_GLOBAL_NEXTAFTER ^^^ |
11534 | |
11535 | template <typename FP> |
11536 | FP step(FP start, FP direction, uint64_t steps) { |
11537 | for (uint64_t i = 0; i < steps; ++i) { |
11538 | #if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) |
11539 | start = Catch::nextafter(start, direction); |
11540 | #else |
11541 | start = std::nextafter(start, direction); |
11542 | #endif |
11543 | } |
11544 | return start; |
11545 | } |
11546 | |
11547 | // Performs equivalent check of std::fabs(lhs - rhs) <= margin |
11548 | // But without the subtraction to allow for INFINITY in comparison |
11549 | bool marginComparison(double lhs, double rhs, double margin) { |
11550 | return (lhs + margin >= rhs) && (rhs + margin >= lhs); |
11551 | } |
11552 | |
11553 | template <typename FloatingPoint> |
11554 | void write(std::ostream& out, FloatingPoint num) { |
11555 | out << std::scientific |
11556 | << std::setprecision(std::numeric_limits<FloatingPoint>::max_digits10 - 1) |
11557 | << num; |
11558 | } |
11559 | |
11560 | } // end anonymous namespace |
11561 | |
11562 | namespace Matchers { |
11563 | namespace Floating { |
11564 | |
11565 | enum class FloatingPointKind : uint8_t { |
11566 | Float, |
11567 | Double |
11568 | }; |
11569 | |
11570 | WithinAbsMatcher::WithinAbsMatcher(double target, double margin) |
11571 | :m_target{ target }, m_margin{ margin } { |
11572 | CATCH_ENFORCE(margin >= 0, "Invalid margin: " << margin << '.' |
11573 | << " Margin has to be non-negative." ); |
11574 | } |
11575 | |
11576 | // Performs equivalent check of std::fabs(lhs - rhs) <= margin |
11577 | // But without the subtraction to allow for INFINITY in comparison |
11578 | bool WithinAbsMatcher::match(double const& matchee) const { |
11579 | return (matchee + m_margin >= m_target) && (m_target + m_margin >= matchee); |
11580 | } |
11581 | |
11582 | std::string WithinAbsMatcher::describe() const { |
11583 | return "is within " + ::Catch::Detail::stringify(m_margin) + " of " + ::Catch::Detail::stringify(m_target); |
11584 | } |
11585 | |
11586 | WithinUlpsMatcher::WithinUlpsMatcher(double target, uint64_t ulps, FloatingPointKind baseType) |
11587 | :m_target{ target }, m_ulps{ ulps }, m_type{ baseType } { |
11588 | CATCH_ENFORCE(m_type == FloatingPointKind::Double |
11589 | || m_ulps < (std::numeric_limits<uint32_t>::max)(), |
11590 | "Provided ULP is impossibly large for a float comparison." ); |
11591 | } |
11592 | |
11593 | #if defined(__clang__) |
11594 | #pragma clang diagnostic push |
11595 | // Clang <3.5 reports on the default branch in the switch below |
11596 | #pragma clang diagnostic ignored "-Wunreachable-code" |
11597 | #endif |
11598 | |
11599 | bool WithinUlpsMatcher::match(double const& matchee) const { |
11600 | switch (m_type) { |
11601 | case FloatingPointKind::Float: |
11602 | return almostEqualUlps<float>(static_cast<float>(matchee), static_cast<float>(m_target), m_ulps); |
11603 | case FloatingPointKind::Double: |
11604 | return almostEqualUlps<double>(matchee, m_target, m_ulps); |
11605 | default: |
11606 | CATCH_INTERNAL_ERROR( "Unknown FloatingPointKind value" ); |
11607 | } |
11608 | } |
11609 | |
11610 | #if defined(__clang__) |
11611 | #pragma clang diagnostic pop |
11612 | #endif |
11613 | |
11614 | std::string WithinUlpsMatcher::describe() const { |
11615 | std::stringstream ret; |
11616 | |
11617 | ret << "is within " << m_ulps << " ULPs of " ; |
11618 | |
11619 | if (m_type == FloatingPointKind::Float) { |
11620 | write(ret, static_cast<float>(m_target)); |
11621 | ret << 'f'; |
11622 | } else { |
11623 | write(ret, m_target); |
11624 | } |
11625 | |
11626 | ret << " ([" ; |
11627 | if (m_type == FloatingPointKind::Double) { |
11628 | write(ret, step(m_target, static_cast<double>(-INFINITY), m_ulps)); |
11629 | ret << ", " ; |
11630 | write(ret, step(m_target, static_cast<double>( INFINITY), m_ulps)); |
11631 | } else { |
11632 | // We have to cast INFINITY to float because of MinGW, see #1782 |
11633 | write(ret, step(static_cast<float>(m_target), static_cast<float>(-INFINITY), m_ulps)); |
11634 | ret << ", " ; |
11635 | write(ret, step(static_cast<float>(m_target), static_cast<float>( INFINITY), m_ulps)); |
11636 | } |
11637 | ret << "])" ; |
11638 | |
11639 | return ret.str(); |
11640 | } |
11641 | |
11642 | WithinRelMatcher::WithinRelMatcher(double target, double epsilon): |
11643 | m_target(target), |
11644 | m_epsilon(epsilon){ |
11645 | CATCH_ENFORCE(m_epsilon >= 0., "Relative comparison with epsilon < 0 does not make sense." ); |
11646 | CATCH_ENFORCE(m_epsilon < 1., "Relative comparison with epsilon >= 1 does not make sense." ); |
11647 | } |
11648 | |
11649 | bool WithinRelMatcher::match(double const& matchee) const { |
11650 | const auto relMargin = m_epsilon * (std::max)(std::fabs(matchee), std::fabs(m_target)); |
11651 | return marginComparison(matchee, m_target, |
11652 | std::isinf(relMargin)? 0 : relMargin); |
11653 | } |
11654 | |
11655 | std::string WithinRelMatcher::describe() const { |
11656 | Catch::ReusableStringStream sstr; |
11657 | sstr << "and " << m_target << " are within " << m_epsilon * 100. << "% of each other" ; |
11658 | return sstr.str(); |
11659 | } |
11660 | |
11661 | }// namespace Floating |
11662 | |
11663 | Floating::WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff) { |
11664 | return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Double); |
11665 | } |
11666 | |
11667 | Floating::WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff) { |
11668 | return Floating::WithinUlpsMatcher(target, maxUlpDiff, Floating::FloatingPointKind::Float); |
11669 | } |
11670 | |
11671 | Floating::WithinAbsMatcher WithinAbs(double target, double margin) { |
11672 | return Floating::WithinAbsMatcher(target, margin); |
11673 | } |
11674 | |
11675 | Floating::WithinRelMatcher WithinRel(double target, double eps) { |
11676 | return Floating::WithinRelMatcher(target, eps); |
11677 | } |
11678 | |
11679 | Floating::WithinRelMatcher WithinRel(double target) { |
11680 | return Floating::WithinRelMatcher(target, std::numeric_limits<double>::epsilon() * 100); |
11681 | } |
11682 | |
11683 | Floating::WithinRelMatcher WithinRel(float target, float eps) { |
11684 | return Floating::WithinRelMatcher(target, eps); |
11685 | } |
11686 | |
11687 | Floating::WithinRelMatcher WithinRel(float target) { |
11688 | return Floating::WithinRelMatcher(target, std::numeric_limits<float>::epsilon() * 100); |
11689 | } |
11690 | |
11691 | } // namespace Matchers |
11692 | } // namespace Catch |
11693 | // end catch_matchers_floating.cpp |
11694 | // start catch_matchers_generic.cpp |
11695 | |
11696 | std::string Catch::Matchers::Generic::Detail::finalizeDescription(const std::string& desc) { |
11697 | if (desc.empty()) { |
11698 | return "matches undescribed predicate" ; |
11699 | } else { |
11700 | return "matches predicate: \"" + desc + '"'; |
11701 | } |
11702 | } |
11703 | // end catch_matchers_generic.cpp |
11704 | // start catch_matchers_string.cpp |
11705 | |
11706 | #include <regex> |
11707 | |
11708 | namespace Catch { |
11709 | namespace Matchers { |
11710 | |
11711 | namespace StdString { |
11712 | |
11713 | CasedString::CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ) |
11714 | : m_caseSensitivity( caseSensitivity ), |
11715 | m_str( adjustString( str ) ) |
11716 | {} |
11717 | std::string CasedString::adjustString( std::string const& str ) const { |
11718 | return m_caseSensitivity == CaseSensitive::No |
11719 | ? toLower( str ) |
11720 | : str; |
11721 | } |
11722 | std::string CasedString::caseSensitivitySuffix() const { |
11723 | return m_caseSensitivity == CaseSensitive::No |
11724 | ? " (case insensitive)" |
11725 | : std::string(); |
11726 | } |
11727 | |
11728 | StringMatcherBase::StringMatcherBase( std::string const& operation, CasedString const& comparator ) |
11729 | : m_comparator( comparator ), |
11730 | m_operation( operation ) { |
11731 | } |
11732 | |
11733 | std::string StringMatcherBase::describe() const { |
11734 | std::string description; |
11735 | description.reserve(5 + m_operation.size() + m_comparator.m_str.size() + |
11736 | m_comparator.caseSensitivitySuffix().size()); |
11737 | description += m_operation; |
11738 | description += ": \"" ; |
11739 | description += m_comparator.m_str; |
11740 | description += "\"" ; |
11741 | description += m_comparator.caseSensitivitySuffix(); |
11742 | return description; |
11743 | } |
11744 | |
11745 | EqualsMatcher::EqualsMatcher( CasedString const& comparator ) : StringMatcherBase( "equals" , comparator ) {} |
11746 | |
11747 | bool EqualsMatcher::match( std::string const& source ) const { |
11748 | return m_comparator.adjustString( source ) == m_comparator.m_str; |
11749 | } |
11750 | |
11751 | ContainsMatcher::ContainsMatcher( CasedString const& comparator ) : StringMatcherBase( "contains" , comparator ) {} |
11752 | |
11753 | bool ContainsMatcher::match( std::string const& source ) const { |
11754 | return contains( m_comparator.adjustString( source ), m_comparator.m_str ); |
11755 | } |
11756 | |
11757 | StartsWithMatcher::StartsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "starts with" , comparator ) {} |
11758 | |
11759 | bool StartsWithMatcher::match( std::string const& source ) const { |
11760 | return startsWith( m_comparator.adjustString( source ), m_comparator.m_str ); |
11761 | } |
11762 | |
11763 | EndsWithMatcher::EndsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "ends with" , comparator ) {} |
11764 | |
11765 | bool EndsWithMatcher::match( std::string const& source ) const { |
11766 | return endsWith( m_comparator.adjustString( source ), m_comparator.m_str ); |
11767 | } |
11768 | |
11769 | RegexMatcher::RegexMatcher(std::string regex, CaseSensitive::Choice caseSensitivity): m_regex(std::move(regex)), m_caseSensitivity(caseSensitivity) {} |
11770 | |
11771 | bool RegexMatcher::match(std::string const& matchee) const { |
11772 | auto flags = std::regex::ECMAScript; // ECMAScript is the default syntax option anyway |
11773 | if (m_caseSensitivity == CaseSensitive::Choice::No) { |
11774 | flags |= std::regex::icase; |
11775 | } |
11776 | auto reg = std::regex(m_regex, flags); |
11777 | return std::regex_match(matchee, reg); |
11778 | } |
11779 | |
11780 | std::string RegexMatcher::describe() const { |
11781 | return "matches " + ::Catch::Detail::stringify(m_regex) + ((m_caseSensitivity == CaseSensitive::Choice::Yes)? " case sensitively" : " case insensitively" ); |
11782 | } |
11783 | |
11784 | } // namespace StdString |
11785 | |
11786 | StdString::EqualsMatcher Equals( std::string const& str, CaseSensitive::Choice caseSensitivity ) { |
11787 | return StdString::EqualsMatcher( StdString::CasedString( str, caseSensitivity) ); |
11788 | } |
11789 | StdString::ContainsMatcher Contains( std::string const& str, CaseSensitive::Choice caseSensitivity ) { |
11790 | return StdString::ContainsMatcher( StdString::CasedString( str, caseSensitivity) ); |
11791 | } |
11792 | StdString::EndsWithMatcher EndsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) { |
11793 | return StdString::EndsWithMatcher( StdString::CasedString( str, caseSensitivity) ); |
11794 | } |
11795 | StdString::StartsWithMatcher StartsWith( std::string const& str, CaseSensitive::Choice caseSensitivity ) { |
11796 | return StdString::StartsWithMatcher( StdString::CasedString( str, caseSensitivity) ); |
11797 | } |
11798 | |
11799 | StdString::RegexMatcher Matches(std::string const& regex, CaseSensitive::Choice caseSensitivity) { |
11800 | return StdString::RegexMatcher(regex, caseSensitivity); |
11801 | } |
11802 | |
11803 | } // namespace Matchers |
11804 | } // namespace Catch |
11805 | // end catch_matchers_string.cpp |
11806 | // start catch_message.cpp |
11807 | |
11808 | // start catch_uncaught_exceptions.h |
11809 | |
11810 | namespace Catch { |
11811 | bool uncaught_exceptions(); |
11812 | } // end namespace Catch |
11813 | |
11814 | // end catch_uncaught_exceptions.h |
11815 | #include <cassert> |
11816 | #include <stack> |
11817 | |
11818 | namespace Catch { |
11819 | |
11820 | MessageInfo::MessageInfo( StringRef const& _macroName, |
11821 | SourceLineInfo const& _lineInfo, |
11822 | ResultWas::OfType _type ) |
11823 | : macroName( _macroName ), |
11824 | lineInfo( _lineInfo ), |
11825 | type( _type ), |
11826 | sequence( ++globalCount ) |
11827 | {} |
11828 | |
11829 | bool MessageInfo::operator==( MessageInfo const& other ) const { |
11830 | return sequence == other.sequence; |
11831 | } |
11832 | |
11833 | bool MessageInfo::operator<( MessageInfo const& other ) const { |
11834 | return sequence < other.sequence; |
11835 | } |
11836 | |
11837 | // This may need protecting if threading support is added |
11838 | unsigned int MessageInfo::globalCount = 0; |
11839 | |
11840 | //////////////////////////////////////////////////////////////////////////// |
11841 | |
11842 | Catch::MessageBuilder::MessageBuilder( StringRef const& macroName, |
11843 | SourceLineInfo const& lineInfo, |
11844 | ResultWas::OfType type ) |
11845 | :m_info(macroName, lineInfo, type) {} |
11846 | |
11847 | //////////////////////////////////////////////////////////////////////////// |
11848 | |
11849 | ScopedMessage::ScopedMessage( MessageBuilder const& builder ) |
11850 | : m_info( builder.m_info ), m_moved() |
11851 | { |
11852 | m_info.message = builder.m_stream.str(); |
11853 | getResultCapture().pushScopedMessage( m_info ); |
11854 | } |
11855 | |
11856 | ScopedMessage::ScopedMessage( ScopedMessage&& old ) |
11857 | : m_info( old.m_info ), m_moved() |
11858 | { |
11859 | old.m_moved = true; |
11860 | } |
11861 | |
11862 | ScopedMessage::~ScopedMessage() { |
11863 | if ( !uncaught_exceptions() && !m_moved ){ |
11864 | getResultCapture().popScopedMessage(m_info); |
11865 | } |
11866 | } |
11867 | |
11868 | Capturer::Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ) { |
11869 | auto trimmed = [&] (size_t start, size_t end) { |
11870 | while (names[start] == ',' || isspace(static_cast<unsigned char>(names[start]))) { |
11871 | ++start; |
11872 | } |
11873 | while (names[end] == ',' || isspace(static_cast<unsigned char>(names[end]))) { |
11874 | --end; |
11875 | } |
11876 | return names.substr(start, end - start + 1); |
11877 | }; |
11878 | auto skipq = [&] (size_t start, char quote) { |
11879 | for (auto i = start + 1; i < names.size() ; ++i) { |
11880 | if (names[i] == quote) |
11881 | return i; |
11882 | if (names[i] == '\\') |
11883 | ++i; |
11884 | } |
11885 | CATCH_INTERNAL_ERROR("CAPTURE parsing encountered unmatched quote" ); |
11886 | }; |
11887 | |
11888 | size_t start = 0; |
11889 | std::stack<char> openings; |
11890 | for (size_t pos = 0; pos < names.size(); ++pos) { |
11891 | char c = names[pos]; |
11892 | switch (c) { |
11893 | case '[': |
11894 | case '{': |
11895 | case '(': |
11896 | // It is basically impossible to disambiguate between |
11897 | // comparison and start of template args in this context |
11898 | // case '<': |
11899 | openings.push(c); |
11900 | break; |
11901 | case ']': |
11902 | case '}': |
11903 | case ')': |
11904 | // case '>': |
11905 | openings.pop(); |
11906 | break; |
11907 | case '"': |
11908 | case '\'': |
11909 | pos = skipq(pos, c); |
11910 | break; |
11911 | case ',': |
11912 | if (start != pos && openings.empty()) { |
11913 | m_messages.emplace_back(macroName, lineInfo, resultType); |
11914 | m_messages.back().message = static_cast<std::string>(trimmed(start, pos)); |
11915 | m_messages.back().message += " := " ; |
11916 | start = pos; |
11917 | } |
11918 | } |
11919 | } |
11920 | assert(openings.empty() && "Mismatched openings" ); |
11921 | m_messages.emplace_back(macroName, lineInfo, resultType); |
11922 | m_messages.back().message = static_cast<std::string>(trimmed(start, names.size() - 1)); |
11923 | m_messages.back().message += " := " ; |
11924 | } |
11925 | Capturer::~Capturer() { |
11926 | if ( !uncaught_exceptions() ){ |
11927 | assert( m_captured == m_messages.size() ); |
11928 | for( size_t i = 0; i < m_captured; ++i ) |
11929 | m_resultCapture.popScopedMessage( m_messages[i] ); |
11930 | } |
11931 | } |
11932 | |
11933 | void Capturer::captureValue( size_t index, std::string const& value ) { |
11934 | assert( index < m_messages.size() ); |
11935 | m_messages[index].message += value; |
11936 | m_resultCapture.pushScopedMessage( m_messages[index] ); |
11937 | m_captured++; |
11938 | } |
11939 | |
11940 | } // end namespace Catch |
11941 | // end catch_message.cpp |
11942 | // start catch_output_redirect.cpp |
11943 | |
11944 | // start catch_output_redirect.h |
11945 | #ifndef TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H |
11946 | #define TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H |
11947 | |
11948 | #include <cstdio> |
11949 | #include <iosfwd> |
11950 | #include <string> |
11951 | |
11952 | namespace Catch { |
11953 | |
11954 | class RedirectedStream { |
11955 | std::ostream& m_originalStream; |
11956 | std::ostream& m_redirectionStream; |
11957 | std::streambuf* m_prevBuf; |
11958 | |
11959 | public: |
11960 | RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream ); |
11961 | ~RedirectedStream(); |
11962 | }; |
11963 | |
11964 | class RedirectedStdOut { |
11965 | ReusableStringStream m_rss; |
11966 | RedirectedStream m_cout; |
11967 | public: |
11968 | RedirectedStdOut(); |
11969 | auto str() const -> std::string; |
11970 | }; |
11971 | |
11972 | // StdErr has two constituent streams in C++, std::cerr and std::clog |
11973 | // This means that we need to redirect 2 streams into 1 to keep proper |
11974 | // order of writes |
11975 | class RedirectedStdErr { |
11976 | ReusableStringStream m_rss; |
11977 | RedirectedStream m_cerr; |
11978 | RedirectedStream m_clog; |
11979 | public: |
11980 | RedirectedStdErr(); |
11981 | auto str() const -> std::string; |
11982 | }; |
11983 | |
11984 | class RedirectedStreams { |
11985 | public: |
11986 | RedirectedStreams(RedirectedStreams const&) = delete; |
11987 | RedirectedStreams& operator=(RedirectedStreams const&) = delete; |
11988 | RedirectedStreams(RedirectedStreams&&) = delete; |
11989 | RedirectedStreams& operator=(RedirectedStreams&&) = delete; |
11990 | |
11991 | RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr); |
11992 | ~RedirectedStreams(); |
11993 | private: |
11994 | std::string& m_redirectedCout; |
11995 | std::string& m_redirectedCerr; |
11996 | RedirectedStdOut m_redirectedStdOut; |
11997 | RedirectedStdErr m_redirectedStdErr; |
11998 | }; |
11999 | |
12000 | #if defined(CATCH_CONFIG_NEW_CAPTURE) |
12001 | |
12002 | // Windows's implementation of std::tmpfile is terrible (it tries |
12003 | // to create a file inside system folder, thus requiring elevated |
12004 | // privileges for the binary), so we have to use tmpnam(_s) and |
12005 | // create the file ourselves there. |
12006 | class TempFile { |
12007 | public: |
12008 | TempFile(TempFile const&) = delete; |
12009 | TempFile& operator=(TempFile const&) = delete; |
12010 | TempFile(TempFile&&) = delete; |
12011 | TempFile& operator=(TempFile&&) = delete; |
12012 | |
12013 | TempFile(); |
12014 | ~TempFile(); |
12015 | |
12016 | std::FILE* getFile(); |
12017 | std::string getContents(); |
12018 | |
12019 | private: |
12020 | std::FILE* m_file = nullptr; |
12021 | #if defined(_MSC_VER) |
12022 | char m_buffer[L_tmpnam] = { 0 }; |
12023 | #endif |
12024 | }; |
12025 | |
12026 | class OutputRedirect { |
12027 | public: |
12028 | OutputRedirect(OutputRedirect const&) = delete; |
12029 | OutputRedirect& operator=(OutputRedirect const&) = delete; |
12030 | OutputRedirect(OutputRedirect&&) = delete; |
12031 | OutputRedirect& operator=(OutputRedirect&&) = delete; |
12032 | |
12033 | OutputRedirect(std::string& stdout_dest, std::string& stderr_dest); |
12034 | ~OutputRedirect(); |
12035 | |
12036 | private: |
12037 | int m_originalStdout = -1; |
12038 | int m_originalStderr = -1; |
12039 | TempFile m_stdoutFile; |
12040 | TempFile m_stderrFile; |
12041 | std::string& m_stdoutDest; |
12042 | std::string& m_stderrDest; |
12043 | }; |
12044 | |
12045 | #endif |
12046 | |
12047 | } // end namespace Catch |
12048 | |
12049 | #endif // TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H |
12050 | // end catch_output_redirect.h |
12051 | #include <cstdio> |
12052 | #include <cstring> |
12053 | #include <fstream> |
12054 | #include <sstream> |
12055 | #include <stdexcept> |
12056 | |
12057 | #if defined(CATCH_CONFIG_NEW_CAPTURE) |
12058 | #if defined(_MSC_VER) |
12059 | #include <io.h> //_dup and _dup2 |
12060 | #define dup _dup |
12061 | #define dup2 _dup2 |
12062 | #define fileno _fileno |
12063 | #else |
12064 | #include <unistd.h> // dup and dup2 |
12065 | #endif |
12066 | #endif |
12067 | |
12068 | namespace Catch { |
12069 | |
12070 | RedirectedStream::RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream ) |
12071 | : m_originalStream( originalStream ), |
12072 | m_redirectionStream( redirectionStream ), |
12073 | m_prevBuf( m_originalStream.rdbuf() ) |
12074 | { |
12075 | m_originalStream.rdbuf( m_redirectionStream.rdbuf() ); |
12076 | } |
12077 | |
12078 | RedirectedStream::~RedirectedStream() { |
12079 | m_originalStream.rdbuf( m_prevBuf ); |
12080 | } |
12081 | |
12082 | RedirectedStdOut::RedirectedStdOut() : m_cout( Catch::cout(), m_rss.get() ) {} |
12083 | auto RedirectedStdOut::str() const -> std::string { return m_rss.str(); } |
12084 | |
12085 | RedirectedStdErr::RedirectedStdErr() |
12086 | : m_cerr( Catch::cerr(), m_rss.get() ), |
12087 | m_clog( Catch::clog(), m_rss.get() ) |
12088 | {} |
12089 | auto RedirectedStdErr::str() const -> std::string { return m_rss.str(); } |
12090 | |
12091 | RedirectedStreams::RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr) |
12092 | : m_redirectedCout(redirectedCout), |
12093 | m_redirectedCerr(redirectedCerr) |
12094 | {} |
12095 | |
12096 | RedirectedStreams::~RedirectedStreams() { |
12097 | m_redirectedCout += m_redirectedStdOut.str(); |
12098 | m_redirectedCerr += m_redirectedStdErr.str(); |
12099 | } |
12100 | |
12101 | #if defined(CATCH_CONFIG_NEW_CAPTURE) |
12102 | |
12103 | #if defined(_MSC_VER) |
12104 | TempFile::TempFile() { |
12105 | if (tmpnam_s(m_buffer)) { |
12106 | CATCH_RUNTIME_ERROR("Could not get a temp filename" ); |
12107 | } |
12108 | if (fopen_s(&m_file, m_buffer, "w+" )) { |
12109 | char buffer[100]; |
12110 | if (strerror_s(buffer, errno)) { |
12111 | CATCH_RUNTIME_ERROR("Could not translate errno to a string" ); |
12112 | } |
12113 | CATCH_RUNTIME_ERROR("Could not open the temp file: '" << m_buffer << "' because: " << buffer); |
12114 | } |
12115 | } |
12116 | #else |
12117 | TempFile::TempFile() { |
12118 | m_file = std::tmpfile(); |
12119 | if (!m_file) { |
12120 | CATCH_RUNTIME_ERROR("Could not create a temp file." ); |
12121 | } |
12122 | } |
12123 | |
12124 | #endif |
12125 | |
12126 | TempFile::~TempFile() { |
12127 | // TBD: What to do about errors here? |
12128 | std::fclose(m_file); |
12129 | // We manually create the file on Windows only, on Linux |
12130 | // it will be autodeleted |
12131 | #if defined(_MSC_VER) |
12132 | std::remove(m_buffer); |
12133 | #endif |
12134 | } |
12135 | |
12136 | FILE* TempFile::getFile() { |
12137 | return m_file; |
12138 | } |
12139 | |
12140 | std::string TempFile::getContents() { |
12141 | std::stringstream sstr; |
12142 | char buffer[100] = {}; |
12143 | std::rewind(m_file); |
12144 | while (std::fgets(buffer, sizeof(buffer), m_file)) { |
12145 | sstr << buffer; |
12146 | } |
12147 | return sstr.str(); |
12148 | } |
12149 | |
12150 | OutputRedirect::OutputRedirect(std::string& stdout_dest, std::string& stderr_dest) : |
12151 | m_originalStdout(dup(1)), |
12152 | m_originalStderr(dup(2)), |
12153 | m_stdoutDest(stdout_dest), |
12154 | m_stderrDest(stderr_dest) { |
12155 | dup2(fileno(m_stdoutFile.getFile()), 1); |
12156 | dup2(fileno(m_stderrFile.getFile()), 2); |
12157 | } |
12158 | |
12159 | OutputRedirect::~OutputRedirect() { |
12160 | Catch::cout() << std::flush; |
12161 | fflush(stdout); |
12162 | // Since we support overriding these streams, we flush cerr |
12163 | // even though std::cerr is unbuffered |
12164 | Catch::cerr() << std::flush; |
12165 | Catch::clog() << std::flush; |
12166 | fflush(stderr); |
12167 | |
12168 | dup2(m_originalStdout, 1); |
12169 | dup2(m_originalStderr, 2); |
12170 | |
12171 | m_stdoutDest += m_stdoutFile.getContents(); |
12172 | m_stderrDest += m_stderrFile.getContents(); |
12173 | } |
12174 | |
12175 | #endif // CATCH_CONFIG_NEW_CAPTURE |
12176 | |
12177 | } // namespace Catch |
12178 | |
12179 | #if defined(CATCH_CONFIG_NEW_CAPTURE) |
12180 | #if defined(_MSC_VER) |
12181 | #undef dup |
12182 | #undef dup2 |
12183 | #undef fileno |
12184 | #endif |
12185 | #endif |
12186 | // end catch_output_redirect.cpp |
12187 | // start catch_polyfills.cpp |
12188 | |
12189 | #include <cmath> |
12190 | |
12191 | namespace Catch { |
12192 | |
12193 | #if !defined(CATCH_CONFIG_POLYFILL_ISNAN) |
12194 | bool isnan(float f) { |
12195 | return std::isnan(f); |
12196 | } |
12197 | bool isnan(double d) { |
12198 | return std::isnan(d); |
12199 | } |
12200 | #else |
12201 | // For now we only use this for embarcadero |
12202 | bool isnan(float f) { |
12203 | return std::_isnan(f); |
12204 | } |
12205 | bool isnan(double d) { |
12206 | return std::_isnan(d); |
12207 | } |
12208 | #endif |
12209 | |
12210 | } // end namespace Catch |
12211 | // end catch_polyfills.cpp |
12212 | // start catch_random_number_generator.cpp |
12213 | |
12214 | namespace Catch { |
12215 | |
12216 | namespace { |
12217 | |
12218 | #if defined(_MSC_VER) |
12219 | #pragma warning(push) |
12220 | #pragma warning(disable:4146) // we negate uint32 during the rotate |
12221 | #endif |
12222 | // Safe rotr implementation thanks to John Regehr |
12223 | uint32_t rotate_right(uint32_t val, uint32_t count) { |
12224 | const uint32_t mask = 31; |
12225 | count &= mask; |
12226 | return (val >> count) | (val << (-count & mask)); |
12227 | } |
12228 | |
12229 | #if defined(_MSC_VER) |
12230 | #pragma warning(pop) |
12231 | #endif |
12232 | |
12233 | } |
12234 | |
12235 | SimplePcg32::SimplePcg32(result_type seed_) { |
12236 | seed(seed_); |
12237 | } |
12238 | |
12239 | void SimplePcg32::seed(result_type seed_) { |
12240 | m_state = 0; |
12241 | (*this)(); |
12242 | m_state += seed_; |
12243 | (*this)(); |
12244 | } |
12245 | |
12246 | void SimplePcg32::discard(uint64_t skip) { |
12247 | // We could implement this to run in O(log n) steps, but this |
12248 | // should suffice for our use case. |
12249 | for (uint64_t s = 0; s < skip; ++s) { |
12250 | static_cast<void>((*this)()); |
12251 | } |
12252 | } |
12253 | |
12254 | SimplePcg32::result_type SimplePcg32::operator()() { |
12255 | // prepare the output value |
12256 | const uint32_t xorshifted = static_cast<uint32_t>(((m_state >> 18u) ^ m_state) >> 27u); |
12257 | const auto output = rotate_right(xorshifted, m_state >> 59u); |
12258 | |
12259 | // advance state |
12260 | m_state = m_state * 6364136223846793005ULL + s_inc; |
12261 | |
12262 | return output; |
12263 | } |
12264 | |
12265 | bool operator==(SimplePcg32 const& lhs, SimplePcg32 const& rhs) { |
12266 | return lhs.m_state == rhs.m_state; |
12267 | } |
12268 | |
12269 | bool operator!=(SimplePcg32 const& lhs, SimplePcg32 const& rhs) { |
12270 | return lhs.m_state != rhs.m_state; |
12271 | } |
12272 | } |
12273 | // end catch_random_number_generator.cpp |
12274 | // start catch_registry_hub.cpp |
12275 | |
12276 | // start catch_test_case_registry_impl.h |
12277 | |
12278 | #include <vector> |
12279 | #include <set> |
12280 | #include <algorithm> |
12281 | #include <ios> |
12282 | |
12283 | namespace Catch { |
12284 | |
12285 | class TestCase; |
12286 | struct IConfig; |
12287 | |
12288 | std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ); |
12289 | |
12290 | bool isThrowSafe( TestCase const& testCase, IConfig const& config ); |
12291 | bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); |
12292 | |
12293 | void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions ); |
12294 | |
12295 | std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ); |
12296 | std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ); |
12297 | |
12298 | class TestRegistry : public ITestCaseRegistry { |
12299 | public: |
12300 | virtual ~TestRegistry() = default; |
12301 | |
12302 | virtual void registerTest( TestCase const& testCase ); |
12303 | |
12304 | std::vector<TestCase> const& getAllTests() const override; |
12305 | std::vector<TestCase> const& getAllTestsSorted( IConfig const& config ) const override; |
12306 | |
12307 | private: |
12308 | std::vector<TestCase> m_functions; |
12309 | mutable RunTests::InWhatOrder m_currentSortOrder = RunTests::InDeclarationOrder; |
12310 | mutable std::vector<TestCase> m_sortedFunctions; |
12311 | std::size_t m_unnamedCount = 0; |
12312 | std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised |
12313 | }; |
12314 | |
12315 | /////////////////////////////////////////////////////////////////////////// |
12316 | |
12317 | class TestInvokerAsFunction : public ITestInvoker { |
12318 | void(*m_testAsFunction)(); |
12319 | public: |
12320 | TestInvokerAsFunction( void(*testAsFunction)() ) noexcept; |
12321 | |
12322 | void invoke() const override; |
12323 | }; |
12324 | |
12325 | std::string extractClassName( StringRef const& classOrQualifiedMethodName ); |
12326 | |
12327 | /////////////////////////////////////////////////////////////////////////// |
12328 | |
12329 | } // end namespace Catch |
12330 | |
12331 | // end catch_test_case_registry_impl.h |
12332 | // start catch_reporter_registry.h |
12333 | |
12334 | #include <map> |
12335 | |
12336 | namespace Catch { |
12337 | |
12338 | class ReporterRegistry : public IReporterRegistry { |
12339 | |
12340 | public: |
12341 | |
12342 | ~ReporterRegistry() override; |
12343 | |
12344 | IStreamingReporterPtr create( std::string const& name, IConfigPtr const& config ) const override; |
12345 | |
12346 | void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ); |
12347 | void registerListener( IReporterFactoryPtr const& factory ); |
12348 | |
12349 | FactoryMap const& getFactories() const override; |
12350 | Listeners const& getListeners() const override; |
12351 | |
12352 | private: |
12353 | FactoryMap m_factories; |
12354 | Listeners m_listeners; |
12355 | }; |
12356 | } |
12357 | |
12358 | // end catch_reporter_registry.h |
12359 | // start catch_tag_alias_registry.h |
12360 | |
12361 | // start catch_tag_alias.h |
12362 | |
12363 | #include <string> |
12364 | |
12365 | namespace Catch { |
12366 | |
12367 | struct TagAlias { |
12368 | TagAlias(std::string const& _tag, SourceLineInfo _lineInfo); |
12369 | |
12370 | std::string tag; |
12371 | SourceLineInfo lineInfo; |
12372 | }; |
12373 | |
12374 | } // end namespace Catch |
12375 | |
12376 | // end catch_tag_alias.h |
12377 | #include <map> |
12378 | |
12379 | namespace Catch { |
12380 | |
12381 | class TagAliasRegistry : public ITagAliasRegistry { |
12382 | public: |
12383 | ~TagAliasRegistry() override; |
12384 | TagAlias const* find( std::string const& alias ) const override; |
12385 | std::string expandAliases( std::string const& unexpandedTestSpec ) const override; |
12386 | void add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ); |
12387 | |
12388 | private: |
12389 | std::map<std::string, TagAlias> m_registry; |
12390 | }; |
12391 | |
12392 | } // end namespace Catch |
12393 | |
12394 | // end catch_tag_alias_registry.h |
12395 | // start catch_startup_exception_registry.h |
12396 | |
12397 | #include <vector> |
12398 | #include <exception> |
12399 | |
12400 | namespace Catch { |
12401 | |
12402 | class StartupExceptionRegistry { |
12403 | #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) |
12404 | public: |
12405 | void add(std::exception_ptr const& exception) noexcept; |
12406 | std::vector<std::exception_ptr> const& getExceptions() const noexcept; |
12407 | private: |
12408 | std::vector<std::exception_ptr> m_exceptions; |
12409 | #endif |
12410 | }; |
12411 | |
12412 | } // end namespace Catch |
12413 | |
12414 | // end catch_startup_exception_registry.h |
12415 | // start catch_singletons.hpp |
12416 | |
12417 | namespace Catch { |
12418 | |
12419 | struct ISingleton { |
12420 | virtual ~ISingleton(); |
12421 | }; |
12422 | |
12423 | void addSingleton( ISingleton* singleton ); |
12424 | void cleanupSingletons(); |
12425 | |
12426 | template<typename SingletonImplT, typename InterfaceT = SingletonImplT, typename MutableInterfaceT = InterfaceT> |
12427 | class Singleton : SingletonImplT, public ISingleton { |
12428 | |
12429 | static auto getInternal() -> Singleton* { |
12430 | static Singleton* s_instance = nullptr; |
12431 | if( !s_instance ) { |
12432 | s_instance = new Singleton; |
12433 | addSingleton( s_instance ); |
12434 | } |
12435 | return s_instance; |
12436 | } |
12437 | |
12438 | public: |
12439 | static auto get() -> InterfaceT const& { |
12440 | return *getInternal(); |
12441 | } |
12442 | static auto getMutable() -> MutableInterfaceT& { |
12443 | return *getInternal(); |
12444 | } |
12445 | }; |
12446 | |
12447 | } // namespace Catch |
12448 | |
12449 | // end catch_singletons.hpp |
12450 | namespace Catch { |
12451 | |
12452 | namespace { |
12453 | |
12454 | class RegistryHub : public IRegistryHub, public IMutableRegistryHub, |
12455 | private NonCopyable { |
12456 | |
12457 | public: // IRegistryHub |
12458 | RegistryHub() = default; |
12459 | IReporterRegistry const& getReporterRegistry() const override { |
12460 | return m_reporterRegistry; |
12461 | } |
12462 | ITestCaseRegistry const& getTestCaseRegistry() const override { |
12463 | return m_testCaseRegistry; |
12464 | } |
12465 | IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const override { |
12466 | return m_exceptionTranslatorRegistry; |
12467 | } |
12468 | ITagAliasRegistry const& getTagAliasRegistry() const override { |
12469 | return m_tagAliasRegistry; |
12470 | } |
12471 | StartupExceptionRegistry const& getStartupExceptionRegistry() const override { |
12472 | return m_exceptionRegistry; |
12473 | } |
12474 | |
12475 | public: // IMutableRegistryHub |
12476 | void registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) override { |
12477 | m_reporterRegistry.registerReporter( name, factory ); |
12478 | } |
12479 | void registerListener( IReporterFactoryPtr const& factory ) override { |
12480 | m_reporterRegistry.registerListener( factory ); |
12481 | } |
12482 | void registerTest( TestCase const& testInfo ) override { |
12483 | m_testCaseRegistry.registerTest( testInfo ); |
12484 | } |
12485 | void registerTranslator( const IExceptionTranslator* translator ) override { |
12486 | m_exceptionTranslatorRegistry.registerTranslator( translator ); |
12487 | } |
12488 | void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) override { |
12489 | m_tagAliasRegistry.add( alias, tag, lineInfo ); |
12490 | } |
12491 | void registerStartupException() noexcept override { |
12492 | #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) |
12493 | m_exceptionRegistry.add(std::current_exception()); |
12494 | #else |
12495 | CATCH_INTERNAL_ERROR("Attempted to register active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!" ); |
12496 | #endif |
12497 | } |
12498 | IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() override { |
12499 | return m_enumValuesRegistry; |
12500 | } |
12501 | |
12502 | private: |
12503 | TestRegistry m_testCaseRegistry; |
12504 | ReporterRegistry m_reporterRegistry; |
12505 | ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; |
12506 | TagAliasRegistry m_tagAliasRegistry; |
12507 | StartupExceptionRegistry m_exceptionRegistry; |
12508 | Detail::EnumValuesRegistry m_enumValuesRegistry; |
12509 | }; |
12510 | } |
12511 | |
12512 | using RegistryHubSingleton = Singleton<RegistryHub, IRegistryHub, IMutableRegistryHub>; |
12513 | |
12514 | IRegistryHub const& getRegistryHub() { |
12515 | return RegistryHubSingleton::get(); |
12516 | } |
12517 | IMutableRegistryHub& getMutableRegistryHub() { |
12518 | return RegistryHubSingleton::getMutable(); |
12519 | } |
12520 | void cleanUp() { |
12521 | cleanupSingletons(); |
12522 | cleanUpContext(); |
12523 | } |
12524 | std::string translateActiveException() { |
12525 | return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); |
12526 | } |
12527 | |
12528 | } // end namespace Catch |
12529 | // end catch_registry_hub.cpp |
12530 | // start catch_reporter_registry.cpp |
12531 | |
12532 | namespace Catch { |
12533 | |
12534 | ReporterRegistry::~ReporterRegistry() = default; |
12535 | |
12536 | IStreamingReporterPtr ReporterRegistry::create( std::string const& name, IConfigPtr const& config ) const { |
12537 | auto it = m_factories.find( name ); |
12538 | if( it == m_factories.end() ) |
12539 | return nullptr; |
12540 | return it->second->create( ReporterConfig( config ) ); |
12541 | } |
12542 | |
12543 | void ReporterRegistry::registerReporter( std::string const& name, IReporterFactoryPtr const& factory ) { |
12544 | m_factories.emplace(name, factory); |
12545 | } |
12546 | void ReporterRegistry::registerListener( IReporterFactoryPtr const& factory ) { |
12547 | m_listeners.push_back( factory ); |
12548 | } |
12549 | |
12550 | IReporterRegistry::FactoryMap const& ReporterRegistry::getFactories() const { |
12551 | return m_factories; |
12552 | } |
12553 | IReporterRegistry::Listeners const& ReporterRegistry::getListeners() const { |
12554 | return m_listeners; |
12555 | } |
12556 | |
12557 | } |
12558 | // end catch_reporter_registry.cpp |
12559 | // start catch_result_type.cpp |
12560 | |
12561 | namespace Catch { |
12562 | |
12563 | bool isOk( ResultWas::OfType resultType ) { |
12564 | return ( resultType & ResultWas::FailureBit ) == 0; |
12565 | } |
12566 | bool isJustInfo( int flags ) { |
12567 | return flags == ResultWas::Info; |
12568 | } |
12569 | |
12570 | ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { |
12571 | return static_cast<ResultDisposition::Flags>( static_cast<int>( lhs ) | static_cast<int>( rhs ) ); |
12572 | } |
12573 | |
12574 | bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } |
12575 | bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } |
12576 | |
12577 | } // end namespace Catch |
12578 | // end catch_result_type.cpp |
12579 | // start catch_run_context.cpp |
12580 | |
12581 | #include <cassert> |
12582 | #include <algorithm> |
12583 | #include <sstream> |
12584 | |
12585 | namespace Catch { |
12586 | |
12587 | namespace Generators { |
12588 | struct GeneratorTracker : TestCaseTracking::TrackerBase, IGeneratorTracker { |
12589 | GeneratorBasePtr m_generator; |
12590 | |
12591 | GeneratorTracker( TestCaseTracking::NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) |
12592 | : TrackerBase( nameAndLocation, ctx, parent ) |
12593 | {} |
12594 | ~GeneratorTracker(); |
12595 | |
12596 | static GeneratorTracker& acquire( TrackerContext& ctx, TestCaseTracking::NameAndLocation const& nameAndLocation ) { |
12597 | std::shared_ptr<GeneratorTracker> tracker; |
12598 | |
12599 | ITracker& currentTracker = ctx.currentTracker(); |
12600 | // Under specific circumstances, the generator we want |
12601 | // to acquire is also the current tracker. If this is |
12602 | // the case, we have to avoid looking through current |
12603 | // tracker's children, and instead return the current |
12604 | // tracker. |
12605 | // A case where this check is important is e.g. |
12606 | // for (int i = 0; i < 5; ++i) { |
12607 | // int n = GENERATE(1, 2); |
12608 | // } |
12609 | // |
12610 | // without it, the code above creates 5 nested generators. |
12611 | if (currentTracker.nameAndLocation() == nameAndLocation) { |
12612 | auto thisTracker = currentTracker.parent().findChild(nameAndLocation); |
12613 | assert(thisTracker); |
12614 | assert(thisTracker->isGeneratorTracker()); |
12615 | tracker = std::static_pointer_cast<GeneratorTracker>(thisTracker); |
12616 | } else if ( TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { |
12617 | assert( childTracker ); |
12618 | assert( childTracker->isGeneratorTracker() ); |
12619 | tracker = std::static_pointer_cast<GeneratorTracker>( childTracker ); |
12620 | } else { |
12621 | tracker = std::make_shared<GeneratorTracker>( nameAndLocation, ctx, ¤tTracker ); |
12622 | currentTracker.addChild( tracker ); |
12623 | } |
12624 | |
12625 | if( !tracker->isComplete() ) { |
12626 | tracker->open(); |
12627 | } |
12628 | |
12629 | return *tracker; |
12630 | } |
12631 | |
12632 | // TrackerBase interface |
12633 | bool isGeneratorTracker() const override { return true; } |
12634 | auto hasGenerator() const -> bool override { |
12635 | return !!m_generator; |
12636 | } |
12637 | void close() override { |
12638 | TrackerBase::close(); |
12639 | // If a generator has a child (it is followed by a section) |
12640 | // and none of its children have started, then we must wait |
12641 | // until later to start consuming its values. |
12642 | // This catches cases where `GENERATE` is placed between two |
12643 | // `SECTION`s. |
12644 | // **The check for m_children.empty cannot be removed**. |
12645 | // doing so would break `GENERATE` _not_ followed by `SECTION`s. |
12646 | const bool should_wait_for_child = [&]() { |
12647 | // No children -> nobody to wait for |
12648 | if ( m_children.empty() ) { |
12649 | return false; |
12650 | } |
12651 | // If at least one child started executing, don't wait |
12652 | if ( std::find_if( |
12653 | m_children.begin(), |
12654 | m_children.end(), |
12655 | []( TestCaseTracking::ITrackerPtr tracker ) { |
12656 | return tracker->hasStarted(); |
12657 | } ) != m_children.end() ) { |
12658 | return false; |
12659 | } |
12660 | |
12661 | // No children have started. We need to check if they _can_ |
12662 | // start, and thus we should wait for them, or they cannot |
12663 | // start (due to filters), and we shouldn't wait for them |
12664 | auto* parent = m_parent; |
12665 | // This is safe: there is always at least one section |
12666 | // tracker in a test case tracking tree |
12667 | while ( !parent->isSectionTracker() ) { |
12668 | parent = &( parent->parent() ); |
12669 | } |
12670 | assert( parent && |
12671 | "Missing root (test case) level section" ); |
12672 | |
12673 | auto const& parentSection = |
12674 | static_cast<SectionTracker&>( *parent ); |
12675 | auto const& filters = parentSection.getFilters(); |
12676 | // No filters -> no restrictions on running sections |
12677 | if ( filters.empty() ) { |
12678 | return true; |
12679 | } |
12680 | |
12681 | for ( auto const& child : m_children ) { |
12682 | if ( child->isSectionTracker() && |
12683 | std::find( filters.begin(), |
12684 | filters.end(), |
12685 | static_cast<SectionTracker&>( *child ) |
12686 | .trimmedName() ) != |
12687 | filters.end() ) { |
12688 | return true; |
12689 | } |
12690 | } |
12691 | return false; |
12692 | }(); |
12693 | |
12694 | // This check is a bit tricky, because m_generator->next() |
12695 | // has a side-effect, where it consumes generator's current |
12696 | // value, but we do not want to invoke the side-effect if |
12697 | // this generator is still waiting for any child to start. |
12698 | if ( should_wait_for_child || |
12699 | ( m_runState == CompletedSuccessfully && |
12700 | m_generator->next() ) ) { |
12701 | m_children.clear(); |
12702 | m_runState = Executing; |
12703 | } |
12704 | } |
12705 | |
12706 | // IGeneratorTracker interface |
12707 | auto getGenerator() const -> GeneratorBasePtr const& override { |
12708 | return m_generator; |
12709 | } |
12710 | void setGenerator( GeneratorBasePtr&& generator ) override { |
12711 | m_generator = std::move( generator ); |
12712 | } |
12713 | }; |
12714 | GeneratorTracker::~GeneratorTracker() {} |
12715 | } |
12716 | |
12717 | RunContext::RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter) |
12718 | : m_runInfo(_config->name()), |
12719 | m_context(getCurrentMutableContext()), |
12720 | m_config(_config), |
12721 | m_reporter(std::move(reporter)), |
12722 | m_lastAssertionInfo{ StringRef(), SourceLineInfo("" ,0), StringRef(), ResultDisposition::Normal }, |
12723 | m_includeSuccessfulResults( m_config->includeSuccessfulResults() || m_reporter->getPreferences().shouldReportAllAssertions ) |
12724 | { |
12725 | m_context.setRunner(this); |
12726 | m_context.setConfig(m_config); |
12727 | m_context.setResultCapture(this); |
12728 | m_reporter->testRunStarting(m_runInfo); |
12729 | } |
12730 | |
12731 | RunContext::~RunContext() { |
12732 | m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, aborting())); |
12733 | } |
12734 | |
12735 | void RunContext::testGroupStarting(std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount) { |
12736 | m_reporter->testGroupStarting(GroupInfo(testSpec, groupIndex, groupsCount)); |
12737 | } |
12738 | |
12739 | void RunContext::testGroupEnded(std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount) { |
12740 | m_reporter->testGroupEnded(TestGroupStats(GroupInfo(testSpec, groupIndex, groupsCount), totals, aborting())); |
12741 | } |
12742 | |
12743 | Totals RunContext::runTest(TestCase const& testCase) { |
12744 | Totals prevTotals = m_totals; |
12745 | |
12746 | std::string redirectedCout; |
12747 | std::string redirectedCerr; |
12748 | |
12749 | auto const& testInfo = testCase.getTestCaseInfo(); |
12750 | |
12751 | m_reporter->testCaseStarting(testInfo); |
12752 | |
12753 | m_activeTestCase = &testCase; |
12754 | |
12755 | ITracker& rootTracker = m_trackerContext.startRun(); |
12756 | assert(rootTracker.isSectionTracker()); |
12757 | static_cast<SectionTracker&>(rootTracker).addInitialFilters(m_config->getSectionsToRun()); |
12758 | do { |
12759 | m_trackerContext.startCycle(); |
12760 | m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(testInfo.name, testInfo.lineInfo)); |
12761 | runCurrentTest(redirectedCout, redirectedCerr); |
12762 | } while (!m_testCaseTracker->isSuccessfullyCompleted() && !aborting()); |
12763 | |
12764 | Totals deltaTotals = m_totals.delta(prevTotals); |
12765 | if (testInfo.expectedToFail() && deltaTotals.testCases.passed > 0) { |
12766 | deltaTotals.assertions.failed++; |
12767 | deltaTotals.testCases.passed--; |
12768 | deltaTotals.testCases.failed++; |
12769 | } |
12770 | m_totals.testCases += deltaTotals.testCases; |
12771 | m_reporter->testCaseEnded(TestCaseStats(testInfo, |
12772 | deltaTotals, |
12773 | redirectedCout, |
12774 | redirectedCerr, |
12775 | aborting())); |
12776 | |
12777 | m_activeTestCase = nullptr; |
12778 | m_testCaseTracker = nullptr; |
12779 | |
12780 | return deltaTotals; |
12781 | } |
12782 | |
12783 | IConfigPtr RunContext::config() const { |
12784 | return m_config; |
12785 | } |
12786 | |
12787 | IStreamingReporter& RunContext::reporter() const { |
12788 | return *m_reporter; |
12789 | } |
12790 | |
12791 | void RunContext::assertionEnded(AssertionResult const & result) { |
12792 | if (result.getResultType() == ResultWas::Ok) { |
12793 | m_totals.assertions.passed++; |
12794 | m_lastAssertionPassed = true; |
12795 | } else if (!result.isOk()) { |
12796 | m_lastAssertionPassed = false; |
12797 | if( m_activeTestCase->getTestCaseInfo().okToFail() ) |
12798 | m_totals.assertions.failedButOk++; |
12799 | else |
12800 | m_totals.assertions.failed++; |
12801 | } |
12802 | else { |
12803 | m_lastAssertionPassed = true; |
12804 | } |
12805 | |
12806 | // We have no use for the return value (whether messages should be cleared), because messages were made scoped |
12807 | // and should be let to clear themselves out. |
12808 | static_cast<void>(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals))); |
12809 | |
12810 | if (result.getResultType() != ResultWas::Warning) |
12811 | m_messageScopes.clear(); |
12812 | |
12813 | // Reset working state |
12814 | resetAssertionInfo(); |
12815 | m_lastResult = result; |
12816 | } |
12817 | void RunContext::resetAssertionInfo() { |
12818 | m_lastAssertionInfo.macroName = StringRef(); |
12819 | m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"_sr ; |
12820 | } |
12821 | |
12822 | bool RunContext::sectionStarted(SectionInfo const & sectionInfo, Counts & assertions) { |
12823 | ITracker& sectionTracker = SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocation(sectionInfo.name, sectionInfo.lineInfo)); |
12824 | if (!sectionTracker.isOpen()) |
12825 | return false; |
12826 | m_activeSections.push_back(§ionTracker); |
12827 | |
12828 | m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; |
12829 | |
12830 | m_reporter->sectionStarting(sectionInfo); |
12831 | |
12832 | assertions = m_totals.assertions; |
12833 | |
12834 | return true; |
12835 | } |
12836 | auto RunContext::acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { |
12837 | using namespace Generators; |
12838 | GeneratorTracker& tracker = GeneratorTracker::acquire(m_trackerContext, |
12839 | TestCaseTracking::NameAndLocation( static_cast<std::string>(generatorName), lineInfo ) ); |
12840 | m_lastAssertionInfo.lineInfo = lineInfo; |
12841 | return tracker; |
12842 | } |
12843 | |
12844 | bool RunContext::testForMissingAssertions(Counts& assertions) { |
12845 | if (assertions.total() != 0) |
12846 | return false; |
12847 | if (!m_config->warnAboutMissingAssertions()) |
12848 | return false; |
12849 | if (m_trackerContext.currentTracker().hasChildren()) |
12850 | return false; |
12851 | m_totals.assertions.failed++; |
12852 | assertions.failed++; |
12853 | return true; |
12854 | } |
12855 | |
12856 | void RunContext::sectionEnded(SectionEndInfo const & endInfo) { |
12857 | Counts assertions = m_totals.assertions - endInfo.prevAssertions; |
12858 | bool missingAssertions = testForMissingAssertions(assertions); |
12859 | |
12860 | if (!m_activeSections.empty()) { |
12861 | m_activeSections.back()->close(); |
12862 | m_activeSections.pop_back(); |
12863 | } |
12864 | |
12865 | m_reporter->sectionEnded(SectionStats(endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions)); |
12866 | m_messages.clear(); |
12867 | m_messageScopes.clear(); |
12868 | } |
12869 | |
12870 | void RunContext::sectionEndedEarly(SectionEndInfo const & endInfo) { |
12871 | if (m_unfinishedSections.empty()) |
12872 | m_activeSections.back()->fail(); |
12873 | else |
12874 | m_activeSections.back()->close(); |
12875 | m_activeSections.pop_back(); |
12876 | |
12877 | m_unfinishedSections.push_back(endInfo); |
12878 | } |
12879 | |
12880 | #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) |
12881 | void RunContext::benchmarkPreparing(std::string const& name) { |
12882 | m_reporter->benchmarkPreparing(name); |
12883 | } |
12884 | void RunContext::benchmarkStarting( BenchmarkInfo const& info ) { |
12885 | m_reporter->benchmarkStarting( info ); |
12886 | } |
12887 | void RunContext::benchmarkEnded( BenchmarkStats<> const& stats ) { |
12888 | m_reporter->benchmarkEnded( stats ); |
12889 | } |
12890 | void RunContext::benchmarkFailed(std::string const & error) { |
12891 | m_reporter->benchmarkFailed(error); |
12892 | } |
12893 | #endif // CATCH_CONFIG_ENABLE_BENCHMARKING |
12894 | |
12895 | void RunContext::pushScopedMessage(MessageInfo const & message) { |
12896 | m_messages.push_back(message); |
12897 | } |
12898 | |
12899 | void RunContext::popScopedMessage(MessageInfo const & message) { |
12900 | m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end()); |
12901 | } |
12902 | |
12903 | void RunContext::emplaceUnscopedMessage( MessageBuilder const& builder ) { |
12904 | m_messageScopes.emplace_back( builder ); |
12905 | } |
12906 | |
12907 | std::string RunContext::getCurrentTestName() const { |
12908 | return m_activeTestCase |
12909 | ? m_activeTestCase->getTestCaseInfo().name |
12910 | : std::string(); |
12911 | } |
12912 | |
12913 | const AssertionResult * RunContext::getLastResult() const { |
12914 | return &(*m_lastResult); |
12915 | } |
12916 | |
12917 | void RunContext::exceptionEarlyReported() { |
12918 | m_shouldReportUnexpected = false; |
12919 | } |
12920 | |
12921 | void RunContext::handleFatalErrorCondition( StringRef message ) { |
12922 | // First notify reporter that bad things happened |
12923 | m_reporter->fatalErrorEncountered(message); |
12924 | |
12925 | // Don't rebuild the result -- the stringification itself can cause more fatal errors |
12926 | // Instead, fake a result data. |
12927 | AssertionResultData tempResult( ResultWas::FatalErrorCondition, { false } ); |
12928 | tempResult.message = static_cast<std::string>(message); |
12929 | AssertionResult result(m_lastAssertionInfo, tempResult); |
12930 | |
12931 | assertionEnded(result); |
12932 | |
12933 | handleUnfinishedSections(); |
12934 | |
12935 | // Recreate section for test case (as we will lose the one that was in scope) |
12936 | auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); |
12937 | SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name); |
12938 | |
12939 | Counts assertions; |
12940 | assertions.failed = 1; |
12941 | SectionStats testCaseSectionStats(testCaseSection, assertions, 0, false); |
12942 | m_reporter->sectionEnded(testCaseSectionStats); |
12943 | |
12944 | auto const& testInfo = m_activeTestCase->getTestCaseInfo(); |
12945 | |
12946 | Totals deltaTotals; |
12947 | deltaTotals.testCases.failed = 1; |
12948 | deltaTotals.assertions.failed = 1; |
12949 | m_reporter->testCaseEnded(TestCaseStats(testInfo, |
12950 | deltaTotals, |
12951 | std::string(), |
12952 | std::string(), |
12953 | false)); |
12954 | m_totals.testCases.failed++; |
12955 | testGroupEnded(std::string(), m_totals, 1, 1); |
12956 | m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, false)); |
12957 | } |
12958 | |
12959 | bool RunContext::lastAssertionPassed() { |
12960 | return m_lastAssertionPassed; |
12961 | } |
12962 | |
12963 | void RunContext::assertionPassed() { |
12964 | m_lastAssertionPassed = true; |
12965 | ++m_totals.assertions.passed; |
12966 | resetAssertionInfo(); |
12967 | m_messageScopes.clear(); |
12968 | } |
12969 | |
12970 | bool RunContext::aborting() const { |
12971 | return m_totals.assertions.failed >= static_cast<std::size_t>(m_config->abortAfter()); |
12972 | } |
12973 | |
12974 | void RunContext::runCurrentTest(std::string & redirectedCout, std::string & redirectedCerr) { |
12975 | auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); |
12976 | SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name); |
12977 | m_reporter->sectionStarting(testCaseSection); |
12978 | Counts prevAssertions = m_totals.assertions; |
12979 | double duration = 0; |
12980 | m_shouldReportUnexpected = true; |
12981 | m_lastAssertionInfo = { "TEST_CASE"_sr , testCaseInfo.lineInfo, StringRef(), ResultDisposition::Normal }; |
12982 | |
12983 | seedRng(*m_config); |
12984 | |
12985 | Timer timer; |
12986 | CATCH_TRY { |
12987 | if (m_reporter->getPreferences().shouldRedirectStdOut) { |
12988 | #if !defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) |
12989 | RedirectedStreams redirectedStreams(redirectedCout, redirectedCerr); |
12990 | |
12991 | timer.start(); |
12992 | invokeActiveTestCase(); |
12993 | #else |
12994 | OutputRedirect r(redirectedCout, redirectedCerr); |
12995 | timer.start(); |
12996 | invokeActiveTestCase(); |
12997 | #endif |
12998 | } else { |
12999 | timer.start(); |
13000 | invokeActiveTestCase(); |
13001 | } |
13002 | duration = timer.getElapsedSeconds(); |
13003 | } CATCH_CATCH_ANON (TestFailureException&) { |
13004 | // This just means the test was aborted due to failure |
13005 | } CATCH_CATCH_ALL { |
13006 | // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions |
13007 | // are reported without translation at the point of origin. |
13008 | if( m_shouldReportUnexpected ) { |
13009 | AssertionReaction dummyReaction; |
13010 | handleUnexpectedInflightException( m_lastAssertionInfo, translateActiveException(), dummyReaction ); |
13011 | } |
13012 | } |
13013 | Counts assertions = m_totals.assertions - prevAssertions; |
13014 | bool missingAssertions = testForMissingAssertions(assertions); |
13015 | |
13016 | m_testCaseTracker->close(); |
13017 | handleUnfinishedSections(); |
13018 | m_messages.clear(); |
13019 | m_messageScopes.clear(); |
13020 | |
13021 | SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions); |
13022 | m_reporter->sectionEnded(testCaseSectionStats); |
13023 | } |
13024 | |
13025 | void RunContext::invokeActiveTestCase() { |
13026 | FatalConditionHandlerGuard _(&m_fatalConditionhandler); |
13027 | m_activeTestCase->invoke(); |
13028 | } |
13029 | |
13030 | void RunContext::handleUnfinishedSections() { |
13031 | // If sections ended prematurely due to an exception we stored their |
13032 | // infos here so we can tear them down outside the unwind process. |
13033 | for (auto it = m_unfinishedSections.rbegin(), |
13034 | itEnd = m_unfinishedSections.rend(); |
13035 | it != itEnd; |
13036 | ++it) |
13037 | sectionEnded(*it); |
13038 | m_unfinishedSections.clear(); |
13039 | } |
13040 | |
13041 | void RunContext::handleExpr( |
13042 | AssertionInfo const& info, |
13043 | ITransientExpression const& expr, |
13044 | AssertionReaction& reaction |
13045 | ) { |
13046 | m_reporter->assertionStarting( info ); |
13047 | |
13048 | bool negated = isFalseTest( info.resultDisposition ); |
13049 | bool result = expr.getResult() != negated; |
13050 | |
13051 | if( result ) { |
13052 | if (!m_includeSuccessfulResults) { |
13053 | assertionPassed(); |
13054 | } |
13055 | else { |
13056 | reportExpr(info, ResultWas::Ok, &expr, negated); |
13057 | } |
13058 | } |
13059 | else { |
13060 | reportExpr(info, ResultWas::ExpressionFailed, &expr, negated ); |
13061 | populateReaction( reaction ); |
13062 | } |
13063 | } |
13064 | void RunContext::reportExpr( |
13065 | AssertionInfo const &info, |
13066 | ResultWas::OfType resultType, |
13067 | ITransientExpression const *expr, |
13068 | bool negated ) { |
13069 | |
13070 | m_lastAssertionInfo = info; |
13071 | AssertionResultData data( resultType, LazyExpression( negated ) ); |
13072 | |
13073 | AssertionResult assertionResult{ info, data }; |
13074 | assertionResult.m_resultData.lazyExpression.m_transientExpression = expr; |
13075 | |
13076 | assertionEnded( assertionResult ); |
13077 | } |
13078 | |
13079 | void RunContext::handleMessage( |
13080 | AssertionInfo const& info, |
13081 | ResultWas::OfType resultType, |
13082 | StringRef const& message, |
13083 | AssertionReaction& reaction |
13084 | ) { |
13085 | m_reporter->assertionStarting( info ); |
13086 | |
13087 | m_lastAssertionInfo = info; |
13088 | |
13089 | AssertionResultData data( resultType, LazyExpression( false ) ); |
13090 | data.message = static_cast<std::string>(message); |
13091 | AssertionResult assertionResult{ m_lastAssertionInfo, data }; |
13092 | assertionEnded( assertionResult ); |
13093 | if( !assertionResult.isOk() ) |
13094 | populateReaction( reaction ); |
13095 | } |
13096 | void RunContext::handleUnexpectedExceptionNotThrown( |
13097 | AssertionInfo const& info, |
13098 | AssertionReaction& reaction |
13099 | ) { |
13100 | handleNonExpr(info, Catch::ResultWas::DidntThrowException, reaction); |
13101 | } |
13102 | |
13103 | void RunContext::handleUnexpectedInflightException( |
13104 | AssertionInfo const& info, |
13105 | std::string const& message, |
13106 | AssertionReaction& reaction |
13107 | ) { |
13108 | m_lastAssertionInfo = info; |
13109 | |
13110 | AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); |
13111 | data.message = message; |
13112 | AssertionResult assertionResult{ info, data }; |
13113 | assertionEnded( assertionResult ); |
13114 | populateReaction( reaction ); |
13115 | } |
13116 | |
13117 | void RunContext::populateReaction( AssertionReaction& reaction ) { |
13118 | reaction.shouldDebugBreak = m_config->shouldDebugBreak(); |
13119 | reaction.shouldThrow = aborting() || (m_lastAssertionInfo.resultDisposition & ResultDisposition::Normal); |
13120 | } |
13121 | |
13122 | void RunContext::handleIncomplete( |
13123 | AssertionInfo const& info |
13124 | ) { |
13125 | m_lastAssertionInfo = info; |
13126 | |
13127 | AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) ); |
13128 | data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE" ; |
13129 | AssertionResult assertionResult{ info, data }; |
13130 | assertionEnded( assertionResult ); |
13131 | } |
13132 | void RunContext::handleNonExpr( |
13133 | AssertionInfo const &info, |
13134 | ResultWas::OfType resultType, |
13135 | AssertionReaction &reaction |
13136 | ) { |
13137 | m_lastAssertionInfo = info; |
13138 | |
13139 | AssertionResultData data( resultType, LazyExpression( false ) ); |
13140 | AssertionResult assertionResult{ info, data }; |
13141 | assertionEnded( assertionResult ); |
13142 | |
13143 | if( !assertionResult.isOk() ) |
13144 | populateReaction( reaction ); |
13145 | } |
13146 | |
13147 | IResultCapture& getResultCapture() { |
13148 | if (auto* capture = getCurrentContext().getResultCapture()) |
13149 | return *capture; |
13150 | else |
13151 | CATCH_INTERNAL_ERROR("No result capture instance" ); |
13152 | } |
13153 | |
13154 | void seedRng(IConfig const& config) { |
13155 | if (config.rngSeed() != 0) { |
13156 | std::srand(config.rngSeed()); |
13157 | rng().seed(config.rngSeed()); |
13158 | } |
13159 | } |
13160 | |
13161 | unsigned int rngSeed() { |
13162 | return getCurrentContext().getConfig()->rngSeed(); |
13163 | } |
13164 | |
13165 | } |
13166 | // end catch_run_context.cpp |
13167 | // start catch_section.cpp |
13168 | |
13169 | namespace Catch { |
13170 | |
13171 | Section::Section( SectionInfo const& info ) |
13172 | : m_info( info ), |
13173 | m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) ) |
13174 | { |
13175 | m_timer.start(); |
13176 | } |
13177 | |
13178 | Section::~Section() { |
13179 | if( m_sectionIncluded ) { |
13180 | SectionEndInfo endInfo{ m_info, m_assertions, m_timer.getElapsedSeconds() }; |
13181 | if( uncaught_exceptions() ) |
13182 | getResultCapture().sectionEndedEarly( endInfo ); |
13183 | else |
13184 | getResultCapture().sectionEnded( endInfo ); |
13185 | } |
13186 | } |
13187 | |
13188 | // This indicates whether the section should be executed or not |
13189 | Section::operator bool() const { |
13190 | return m_sectionIncluded; |
13191 | } |
13192 | |
13193 | } // end namespace Catch |
13194 | // end catch_section.cpp |
13195 | // start catch_section_info.cpp |
13196 | |
13197 | namespace Catch { |
13198 | |
13199 | SectionInfo::SectionInfo |
13200 | ( SourceLineInfo const& _lineInfo, |
13201 | std::string const& _name ) |
13202 | : name( _name ), |
13203 | lineInfo( _lineInfo ) |
13204 | {} |
13205 | |
13206 | } // end namespace Catch |
13207 | // end catch_section_info.cpp |
13208 | // start catch_session.cpp |
13209 | |
13210 | // start catch_session.h |
13211 | |
13212 | #include <memory> |
13213 | |
13214 | namespace Catch { |
13215 | |
13216 | class Session : NonCopyable { |
13217 | public: |
13218 | |
13219 | Session(); |
13220 | ~Session() override; |
13221 | |
13222 | void showHelp() const; |
13223 | void libIdentify(); |
13224 | |
13225 | int applyCommandLine( int argc, char const * const * argv ); |
13226 | #if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE) |
13227 | int applyCommandLine( int argc, wchar_t const * const * argv ); |
13228 | #endif |
13229 | |
13230 | void useConfigData( ConfigData const& configData ); |
13231 | |
13232 | template<typename CharT> |
13233 | int run(int argc, CharT const * const argv[]) { |
13234 | if (m_startupExceptions) |
13235 | return 1; |
13236 | int returnCode = applyCommandLine(argc, argv); |
13237 | if (returnCode == 0) |
13238 | returnCode = run(); |
13239 | return returnCode; |
13240 | } |
13241 | |
13242 | int run(); |
13243 | |
13244 | clara::Parser const& cli() const; |
13245 | void cli( clara::Parser const& newParser ); |
13246 | ConfigData& configData(); |
13247 | Config& config(); |
13248 | private: |
13249 | int runInternal(); |
13250 | |
13251 | clara::Parser m_cli; |
13252 | ConfigData m_configData; |
13253 | std::shared_ptr<Config> m_config; |
13254 | bool m_startupExceptions = false; |
13255 | }; |
13256 | |
13257 | } // end namespace Catch |
13258 | |
13259 | // end catch_session.h |
13260 | // start catch_version.h |
13261 | |
13262 | #include <iosfwd> |
13263 | |
13264 | namespace Catch { |
13265 | |
13266 | // Versioning information |
13267 | struct Version { |
13268 | Version( Version const& ) = delete; |
13269 | Version& operator=( Version const& ) = delete; |
13270 | Version( unsigned int _majorVersion, |
13271 | unsigned int _minorVersion, |
13272 | unsigned int _patchNumber, |
13273 | char const * const _branchName, |
13274 | unsigned int _buildNumber ); |
13275 | |
13276 | unsigned int const majorVersion; |
13277 | unsigned int const minorVersion; |
13278 | unsigned int const patchNumber; |
13279 | |
13280 | // buildNumber is only used if branchName is not null |
13281 | char const * const branchName; |
13282 | unsigned int const buildNumber; |
13283 | |
13284 | friend std::ostream& operator << ( std::ostream& os, Version const& version ); |
13285 | }; |
13286 | |
13287 | Version const& libraryVersion(); |
13288 | } |
13289 | |
13290 | // end catch_version.h |
13291 | #include <cstdlib> |
13292 | #include <iomanip> |
13293 | #include <set> |
13294 | #include <iterator> |
13295 | |
13296 | namespace Catch { |
13297 | |
13298 | namespace { |
13299 | const int MaxExitCode = 255; |
13300 | |
13301 | IStreamingReporterPtr createReporter(std::string const& reporterName, IConfigPtr const& config) { |
13302 | auto reporter = Catch::getRegistryHub().getReporterRegistry().create(reporterName, config); |
13303 | CATCH_ENFORCE(reporter, "No reporter registered with name: '" << reporterName << "'" ); |
13304 | |
13305 | return reporter; |
13306 | } |
13307 | |
13308 | IStreamingReporterPtr makeReporter(std::shared_ptr<Config> const& config) { |
13309 | if (Catch::getRegistryHub().getReporterRegistry().getListeners().empty()) { |
13310 | return createReporter(config->getReporterName(), config); |
13311 | } |
13312 | |
13313 | // On older platforms, returning std::unique_ptr<ListeningReporter> |
13314 | // when the return type is std::unique_ptr<IStreamingReporter> |
13315 | // doesn't compile without a std::move call. However, this causes |
13316 | // a warning on newer platforms. Thus, we have to work around |
13317 | // it a bit and downcast the pointer manually. |
13318 | auto ret = std::unique_ptr<IStreamingReporter>(new ListeningReporter); |
13319 | auto& multi = static_cast<ListeningReporter&>(*ret); |
13320 | auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners(); |
13321 | for (auto const& listener : listeners) { |
13322 | multi.addListener(listener->create(Catch::ReporterConfig(config))); |
13323 | } |
13324 | multi.addReporter(createReporter(config->getReporterName(), config)); |
13325 | return ret; |
13326 | } |
13327 | |
13328 | class TestGroup { |
13329 | public: |
13330 | explicit TestGroup(std::shared_ptr<Config> const& config) |
13331 | : m_config{config} |
13332 | , m_context{config, makeReporter(config)} |
13333 | { |
13334 | auto const& allTestCases = getAllTestCasesSorted(*m_config); |
13335 | m_matches = m_config->testSpec().matchesByFilter(allTestCases, *m_config); |
13336 | auto const& invalidArgs = m_config->testSpec().getInvalidArgs(); |
13337 | |
13338 | if (m_matches.empty() && invalidArgs.empty()) { |
13339 | for (auto const& test : allTestCases) |
13340 | if (!test.isHidden()) |
13341 | m_tests.emplace(&test); |
13342 | } else { |
13343 | for (auto const& match : m_matches) |
13344 | m_tests.insert(match.tests.begin(), match.tests.end()); |
13345 | } |
13346 | } |
13347 | |
13348 | Totals execute() { |
13349 | auto const& invalidArgs = m_config->testSpec().getInvalidArgs(); |
13350 | Totals totals; |
13351 | m_context.testGroupStarting(m_config->name(), 1, 1); |
13352 | for (auto const& testCase : m_tests) { |
13353 | if (!m_context.aborting()) |
13354 | totals += m_context.runTest(*testCase); |
13355 | else |
13356 | m_context.reporter().skipTest(*testCase); |
13357 | } |
13358 | |
13359 | for (auto const& match : m_matches) { |
13360 | if (match.tests.empty()) { |
13361 | m_context.reporter().noMatchingTestCases(match.name); |
13362 | totals.error = -1; |
13363 | } |
13364 | } |
13365 | |
13366 | if (!invalidArgs.empty()) { |
13367 | for (auto const& invalidArg: invalidArgs) |
13368 | m_context.reporter().reportInvalidArguments(invalidArg); |
13369 | } |
13370 | |
13371 | m_context.testGroupEnded(m_config->name(), totals, 1, 1); |
13372 | return totals; |
13373 | } |
13374 | |
13375 | private: |
13376 | using Tests = std::set<TestCase const*>; |
13377 | |
13378 | std::shared_ptr<Config> m_config; |
13379 | RunContext m_context; |
13380 | Tests m_tests; |
13381 | TestSpec::Matches m_matches; |
13382 | }; |
13383 | |
13384 | void applyFilenamesAsTags(Catch::IConfig const& config) { |
13385 | auto& tests = const_cast<std::vector<TestCase>&>(getAllTestCasesSorted(config)); |
13386 | for (auto& testCase : tests) { |
13387 | auto tags = testCase.tags; |
13388 | |
13389 | std::string filename = testCase.lineInfo.file; |
13390 | auto lastSlash = filename.find_last_of("\\/" ); |
13391 | if (lastSlash != std::string::npos) { |
13392 | filename.erase(0, lastSlash); |
13393 | filename[0] = '#'; |
13394 | } |
13395 | |
13396 | auto lastDot = filename.find_last_of('.'); |
13397 | if (lastDot != std::string::npos) { |
13398 | filename.erase(lastDot); |
13399 | } |
13400 | |
13401 | tags.push_back(std::move(filename)); |
13402 | setTags(testCase, tags); |
13403 | } |
13404 | } |
13405 | |
13406 | } // anon namespace |
13407 | |
13408 | Session::Session() { |
13409 | static bool alreadyInstantiated = false; |
13410 | if( alreadyInstantiated ) { |
13411 | CATCH_TRY { CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); } |
13412 | CATCH_CATCH_ALL { getMutableRegistryHub().registerStartupException(); } |
13413 | } |
13414 | |
13415 | // There cannot be exceptions at startup in no-exception mode. |
13416 | #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) |
13417 | const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions(); |
13418 | if ( !exceptions.empty() ) { |
13419 | config(); |
13420 | getCurrentMutableContext().setConfig(m_config); |
13421 | |
13422 | m_startupExceptions = true; |
13423 | Colour colourGuard( Colour::Red ); |
13424 | Catch::cerr() << "Errors occurred during startup!" << '\n'; |
13425 | // iterate over all exceptions and notify user |
13426 | for ( const auto& ex_ptr : exceptions ) { |
13427 | try { |
13428 | std::rethrow_exception(ex_ptr); |
13429 | } catch ( std::exception const& ex ) { |
13430 | Catch::cerr() << Column( ex.what() ).indent(2) << '\n'; |
13431 | } |
13432 | } |
13433 | } |
13434 | #endif |
13435 | |
13436 | alreadyInstantiated = true; |
13437 | m_cli = makeCommandLineParser( m_configData ); |
13438 | } |
13439 | Session::~Session() { |
13440 | Catch::cleanUp(); |
13441 | } |
13442 | |
13443 | void Session::showHelp() const { |
13444 | Catch::cout() |
13445 | << "\nCatch v" << libraryVersion() << "\n" |
13446 | << m_cli << std::endl |
13447 | << "For more detailed usage please see the project docs\n" << std::endl; |
13448 | } |
13449 | void Session::libIdentify() { |
13450 | Catch::cout() |
13451 | << std::left << std::setw(16) << "description: " << "A Catch2 test executable\n" |
13452 | << std::left << std::setw(16) << "category: " << "testframework\n" |
13453 | << std::left << std::setw(16) << "framework: " << "Catch Test\n" |
13454 | << std::left << std::setw(16) << "version: " << libraryVersion() << std::endl; |
13455 | } |
13456 | |
13457 | int Session::applyCommandLine( int argc, char const * const * argv ) { |
13458 | if( m_startupExceptions ) |
13459 | return 1; |
13460 | |
13461 | auto result = m_cli.parse( clara::Args( argc, argv ) ); |
13462 | if( !result ) { |
13463 | config(); |
13464 | getCurrentMutableContext().setConfig(m_config); |
13465 | Catch::cerr() |
13466 | << Colour( Colour::Red ) |
13467 | << "\nError(s) in input:\n" |
13468 | << Column( result.errorMessage() ).indent( 2 ) |
13469 | << "\n\n" ; |
13470 | Catch::cerr() << "Run with -? for usage\n" << std::endl; |
13471 | return MaxExitCode; |
13472 | } |
13473 | |
13474 | if( m_configData.showHelp ) |
13475 | showHelp(); |
13476 | if( m_configData.libIdentify ) |
13477 | libIdentify(); |
13478 | m_config.reset(); |
13479 | return 0; |
13480 | } |
13481 | |
13482 | #if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE) |
13483 | int Session::applyCommandLine( int argc, wchar_t const * const * argv ) { |
13484 | |
13485 | char **utf8Argv = new char *[ argc ]; |
13486 | |
13487 | for ( int i = 0; i < argc; ++i ) { |
13488 | int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, nullptr, 0, nullptr, nullptr ); |
13489 | |
13490 | utf8Argv[ i ] = new char[ bufSize ]; |
13491 | |
13492 | WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, nullptr, nullptr ); |
13493 | } |
13494 | |
13495 | int returnCode = applyCommandLine( argc, utf8Argv ); |
13496 | |
13497 | for ( int i = 0; i < argc; ++i ) |
13498 | delete [] utf8Argv[ i ]; |
13499 | |
13500 | delete [] utf8Argv; |
13501 | |
13502 | return returnCode; |
13503 | } |
13504 | #endif |
13505 | |
13506 | void Session::useConfigData( ConfigData const& configData ) { |
13507 | m_configData = configData; |
13508 | m_config.reset(); |
13509 | } |
13510 | |
13511 | int Session::run() { |
13512 | if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) { |
13513 | Catch::cout() << "...waiting for enter/ return before starting" << std::endl; |
13514 | static_cast<void>(std::getchar()); |
13515 | } |
13516 | int exitCode = runInternal(); |
13517 | if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) { |
13518 | Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << std::endl; |
13519 | static_cast<void>(std::getchar()); |
13520 | } |
13521 | return exitCode; |
13522 | } |
13523 | |
13524 | clara::Parser const& Session::cli() const { |
13525 | return m_cli; |
13526 | } |
13527 | void Session::cli( clara::Parser const& newParser ) { |
13528 | m_cli = newParser; |
13529 | } |
13530 | ConfigData& Session::configData() { |
13531 | return m_configData; |
13532 | } |
13533 | Config& Session::config() { |
13534 | if( !m_config ) |
13535 | m_config = std::make_shared<Config>( m_configData ); |
13536 | return *m_config; |
13537 | } |
13538 | |
13539 | int Session::runInternal() { |
13540 | if( m_startupExceptions ) |
13541 | return 1; |
13542 | |
13543 | if (m_configData.showHelp || m_configData.libIdentify) { |
13544 | return 0; |
13545 | } |
13546 | |
13547 | CATCH_TRY { |
13548 | config(); // Force config to be constructed |
13549 | |
13550 | seedRng( *m_config ); |
13551 | |
13552 | if( m_configData.filenamesAsTags ) |
13553 | applyFilenamesAsTags( *m_config ); |
13554 | |
13555 | // Handle list request |
13556 | if( Option<std::size_t> listed = list( m_config ) ) |
13557 | return static_cast<int>( *listed ); |
13558 | |
13559 | TestGroup tests { m_config }; |
13560 | auto const totals = tests.execute(); |
13561 | |
13562 | if( m_config->warnAboutNoTests() && totals.error == -1 ) |
13563 | return 2; |
13564 | |
13565 | // Note that on unices only the lower 8 bits are usually used, clamping |
13566 | // the return value to 255 prevents false negative when some multiple |
13567 | // of 256 tests has failed |
13568 | return (std::min) (MaxExitCode, (std::max) (totals.error, static_cast<int>(totals.assertions.failed))); |
13569 | } |
13570 | #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) |
13571 | catch( std::exception& ex ) { |
13572 | Catch::cerr() << ex.what() << std::endl; |
13573 | return MaxExitCode; |
13574 | } |
13575 | #endif |
13576 | } |
13577 | |
13578 | } // end namespace Catch |
13579 | // end catch_session.cpp |
13580 | // start catch_singletons.cpp |
13581 | |
13582 | #include <vector> |
13583 | |
13584 | namespace Catch { |
13585 | |
13586 | namespace { |
13587 | static auto getSingletons() -> std::vector<ISingleton*>*& { |
13588 | static std::vector<ISingleton*>* g_singletons = nullptr; |
13589 | if( !g_singletons ) |
13590 | g_singletons = new std::vector<ISingleton*>(); |
13591 | return g_singletons; |
13592 | } |
13593 | } |
13594 | |
13595 | ISingleton::~ISingleton() {} |
13596 | |
13597 | void addSingleton(ISingleton* singleton ) { |
13598 | getSingletons()->push_back( singleton ); |
13599 | } |
13600 | void cleanupSingletons() { |
13601 | auto& singletons = getSingletons(); |
13602 | for( auto singleton : *singletons ) |
13603 | delete singleton; |
13604 | delete singletons; |
13605 | singletons = nullptr; |
13606 | } |
13607 | |
13608 | } // namespace Catch |
13609 | // end catch_singletons.cpp |
13610 | // start catch_startup_exception_registry.cpp |
13611 | |
13612 | #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) |
13613 | namespace Catch { |
13614 | void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept { |
13615 | CATCH_TRY { |
13616 | m_exceptions.push_back(exception); |
13617 | } CATCH_CATCH_ALL { |
13618 | // If we run out of memory during start-up there's really not a lot more we can do about it |
13619 | std::terminate(); |
13620 | } |
13621 | } |
13622 | |
13623 | std::vector<std::exception_ptr> const& StartupExceptionRegistry::getExceptions() const noexcept { |
13624 | return m_exceptions; |
13625 | } |
13626 | |
13627 | } // end namespace Catch |
13628 | #endif |
13629 | // end catch_startup_exception_registry.cpp |
13630 | // start catch_stream.cpp |
13631 | |
13632 | #include <cstdio> |
13633 | #include <iostream> |
13634 | #include <fstream> |
13635 | #include <sstream> |
13636 | #include <vector> |
13637 | #include <memory> |
13638 | |
13639 | namespace Catch { |
13640 | |
13641 | Catch::IStream::~IStream() = default; |
13642 | |
13643 | namespace Detail { namespace { |
13644 | template<typename WriterF, std::size_t bufferSize=256> |
13645 | class StreamBufImpl : public std::streambuf { |
13646 | char data[bufferSize]; |
13647 | WriterF m_writer; |
13648 | |
13649 | public: |
13650 | StreamBufImpl() { |
13651 | setp( data, data + sizeof(data) ); |
13652 | } |
13653 | |
13654 | ~StreamBufImpl() noexcept { |
13655 | StreamBufImpl::sync(); |
13656 | } |
13657 | |
13658 | private: |
13659 | int overflow( int c ) override { |
13660 | sync(); |
13661 | |
13662 | if( c != EOF ) { |
13663 | if( pbase() == epptr() ) |
13664 | m_writer( std::string( 1, static_cast<char>( c ) ) ); |
13665 | else |
13666 | sputc( static_cast<char>( c ) ); |
13667 | } |
13668 | return 0; |
13669 | } |
13670 | |
13671 | int sync() override { |
13672 | if( pbase() != pptr() ) { |
13673 | m_writer( std::string( pbase(), static_cast<std::string::size_type>( pptr() - pbase() ) ) ); |
13674 | setp( pbase(), epptr() ); |
13675 | } |
13676 | return 0; |
13677 | } |
13678 | }; |
13679 | |
13680 | /////////////////////////////////////////////////////////////////////////// |
13681 | |
13682 | struct OutputDebugWriter { |
13683 | |
13684 | void operator()( std::string const&str ) { |
13685 | writeToDebugConsole( str ); |
13686 | } |
13687 | }; |
13688 | |
13689 | /////////////////////////////////////////////////////////////////////////// |
13690 | |
13691 | class FileStream : public IStream { |
13692 | mutable std::ofstream m_ofs; |
13693 | public: |
13694 | FileStream( StringRef filename ) { |
13695 | m_ofs.open( filename.c_str() ); |
13696 | CATCH_ENFORCE( !m_ofs.fail(), "Unable to open file: '" << filename << "'" ); |
13697 | } |
13698 | ~FileStream() override = default; |
13699 | public: // IStream |
13700 | std::ostream& stream() const override { |
13701 | return m_ofs; |
13702 | } |
13703 | }; |
13704 | |
13705 | /////////////////////////////////////////////////////////////////////////// |
13706 | |
13707 | class CoutStream : public IStream { |
13708 | mutable std::ostream m_os; |
13709 | public: |
13710 | // Store the streambuf from cout up-front because |
13711 | // cout may get redirected when running tests |
13712 | CoutStream() : m_os( Catch::cout().rdbuf() ) {} |
13713 | ~CoutStream() override = default; |
13714 | |
13715 | public: // IStream |
13716 | std::ostream& stream() const override { return m_os; } |
13717 | }; |
13718 | |
13719 | /////////////////////////////////////////////////////////////////////////// |
13720 | |
13721 | class DebugOutStream : public IStream { |
13722 | std::unique_ptr<StreamBufImpl<OutputDebugWriter>> m_streamBuf; |
13723 | mutable std::ostream m_os; |
13724 | public: |
13725 | DebugOutStream() |
13726 | : m_streamBuf( new StreamBufImpl<OutputDebugWriter>() ), |
13727 | m_os( m_streamBuf.get() ) |
13728 | {} |
13729 | |
13730 | ~DebugOutStream() override = default; |
13731 | |
13732 | public: // IStream |
13733 | std::ostream& stream() const override { return m_os; } |
13734 | }; |
13735 | |
13736 | }} // namespace anon::detail |
13737 | |
13738 | /////////////////////////////////////////////////////////////////////////// |
13739 | |
13740 | auto makeStream( StringRef const &filename ) -> IStream const* { |
13741 | if( filename.empty() ) |
13742 | return new Detail::CoutStream(); |
13743 | else if( filename[0] == '%' ) { |
13744 | if( filename == "%debug" ) |
13745 | return new Detail::DebugOutStream(); |
13746 | else |
13747 | CATCH_ERROR( "Unrecognised stream: '" << filename << "'" ); |
13748 | } |
13749 | else |
13750 | return new Detail::FileStream( filename ); |
13751 | } |
13752 | |
13753 | // This class encapsulates the idea of a pool of ostringstreams that can be reused. |
13754 | struct StringStreams { |
13755 | std::vector<std::unique_ptr<std::ostringstream>> m_streams; |
13756 | std::vector<std::size_t> m_unused; |
13757 | std::ostringstream m_referenceStream; // Used for copy state/ flags from |
13758 | |
13759 | auto add() -> std::size_t { |
13760 | if( m_unused.empty() ) { |
13761 | m_streams.push_back( std::unique_ptr<std::ostringstream>( new std::ostringstream ) ); |
13762 | return m_streams.size()-1; |
13763 | } |
13764 | else { |
13765 | auto index = m_unused.back(); |
13766 | m_unused.pop_back(); |
13767 | return index; |
13768 | } |
13769 | } |
13770 | |
13771 | void release( std::size_t index ) { |
13772 | m_streams[index]->copyfmt( m_referenceStream ); // Restore initial flags and other state |
13773 | m_unused.push_back(index); |
13774 | } |
13775 | }; |
13776 | |
13777 | ReusableStringStream::ReusableStringStream() |
13778 | : m_index( Singleton<StringStreams>::getMutable().add() ), |
13779 | m_oss( Singleton<StringStreams>::getMutable().m_streams[m_index].get() ) |
13780 | {} |
13781 | |
13782 | ReusableStringStream::~ReusableStringStream() { |
13783 | static_cast<std::ostringstream*>( m_oss )->str("" ); |
13784 | m_oss->clear(); |
13785 | Singleton<StringStreams>::getMutable().release( m_index ); |
13786 | } |
13787 | |
13788 | auto ReusableStringStream::str() const -> std::string { |
13789 | return static_cast<std::ostringstream*>( m_oss )->str(); |
13790 | } |
13791 | |
13792 | /////////////////////////////////////////////////////////////////////////// |
13793 | |
13794 | #ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions |
13795 | std::ostream& cout() { return std::cout; } |
13796 | std::ostream& cerr() { return std::cerr; } |
13797 | std::ostream& clog() { return std::clog; } |
13798 | #endif |
13799 | } |
13800 | // end catch_stream.cpp |
13801 | // start catch_string_manip.cpp |
13802 | |
13803 | #include <algorithm> |
13804 | #include <ostream> |
13805 | #include <cstring> |
13806 | #include <cctype> |
13807 | #include <vector> |
13808 | |
13809 | namespace Catch { |
13810 | |
13811 | namespace { |
13812 | char toLowerCh(char c) { |
13813 | return static_cast<char>( std::tolower( static_cast<unsigned char>(c) ) ); |
13814 | } |
13815 | } |
13816 | |
13817 | bool startsWith( std::string const& s, std::string const& prefix ) { |
13818 | return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin()); |
13819 | } |
13820 | bool startsWith( std::string const& s, char prefix ) { |
13821 | return !s.empty() && s[0] == prefix; |
13822 | } |
13823 | bool endsWith( std::string const& s, std::string const& suffix ) { |
13824 | return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin()); |
13825 | } |
13826 | bool endsWith( std::string const& s, char suffix ) { |
13827 | return !s.empty() && s[s.size()-1] == suffix; |
13828 | } |
13829 | bool contains( std::string const& s, std::string const& infix ) { |
13830 | return s.find( infix ) != std::string::npos; |
13831 | } |
13832 | void toLowerInPlace( std::string& s ) { |
13833 | std::transform( s.begin(), s.end(), s.begin(), toLowerCh ); |
13834 | } |
13835 | std::string toLower( std::string const& s ) { |
13836 | std::string lc = s; |
13837 | toLowerInPlace( lc ); |
13838 | return lc; |
13839 | } |
13840 | std::string trim( std::string const& str ) { |
13841 | static char const* whitespaceChars = "\n\r\t " ; |
13842 | std::string::size_type start = str.find_first_not_of( whitespaceChars ); |
13843 | std::string::size_type end = str.find_last_not_of( whitespaceChars ); |
13844 | |
13845 | return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string(); |
13846 | } |
13847 | |
13848 | StringRef trim(StringRef ref) { |
13849 | const auto is_ws = [](char c) { |
13850 | return c == ' ' || c == '\t' || c == '\n' || c == '\r'; |
13851 | }; |
13852 | size_t real_begin = 0; |
13853 | while (real_begin < ref.size() && is_ws(ref[real_begin])) { ++real_begin; } |
13854 | size_t real_end = ref.size(); |
13855 | while (real_end > real_begin && is_ws(ref[real_end - 1])) { --real_end; } |
13856 | |
13857 | return ref.substr(real_begin, real_end - real_begin); |
13858 | } |
13859 | |
13860 | bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { |
13861 | bool replaced = false; |
13862 | std::size_t i = str.find( replaceThis ); |
13863 | while( i != std::string::npos ) { |
13864 | replaced = true; |
13865 | str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() ); |
13866 | if( i < str.size()-withThis.size() ) |
13867 | i = str.find( replaceThis, i+withThis.size() ); |
13868 | else |
13869 | i = std::string::npos; |
13870 | } |
13871 | return replaced; |
13872 | } |
13873 | |
13874 | std::vector<StringRef> splitStringRef( StringRef str, char delimiter ) { |
13875 | std::vector<StringRef> subStrings; |
13876 | std::size_t start = 0; |
13877 | for(std::size_t pos = 0; pos < str.size(); ++pos ) { |
13878 | if( str[pos] == delimiter ) { |
13879 | if( pos - start > 1 ) |
13880 | subStrings.push_back( str.substr( start, pos-start ) ); |
13881 | start = pos+1; |
13882 | } |
13883 | } |
13884 | if( start < str.size() ) |
13885 | subStrings.push_back( str.substr( start, str.size()-start ) ); |
13886 | return subStrings; |
13887 | } |
13888 | |
13889 | pluralise::pluralise( std::size_t count, std::string const& label ) |
13890 | : m_count( count ), |
13891 | m_label( label ) |
13892 | {} |
13893 | |
13894 | std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { |
13895 | os << pluraliser.m_count << ' ' << pluraliser.m_label; |
13896 | if( pluraliser.m_count != 1 ) |
13897 | os << 's'; |
13898 | return os; |
13899 | } |
13900 | |
13901 | } |
13902 | // end catch_string_manip.cpp |
13903 | // start catch_stringref.cpp |
13904 | |
13905 | #include <algorithm> |
13906 | #include <ostream> |
13907 | #include <cstring> |
13908 | #include <cstdint> |
13909 | |
13910 | namespace Catch { |
13911 | StringRef::StringRef( char const* rawChars ) noexcept |
13912 | : StringRef( rawChars, static_cast<StringRef::size_type>(std::strlen(rawChars) ) ) |
13913 | {} |
13914 | |
13915 | auto StringRef::c_str() const -> char const* { |
13916 | CATCH_ENFORCE(isNullTerminated(), "Called StringRef::c_str() on a non-null-terminated instance" ); |
13917 | return m_start; |
13918 | } |
13919 | auto StringRef::data() const noexcept -> char const* { |
13920 | return m_start; |
13921 | } |
13922 | |
13923 | auto StringRef::substr( size_type start, size_type size ) const noexcept -> StringRef { |
13924 | if (start < m_size) { |
13925 | return StringRef(m_start + start, (std::min)(m_size - start, size)); |
13926 | } else { |
13927 | return StringRef(); |
13928 | } |
13929 | } |
13930 | auto StringRef::operator == ( StringRef const& other ) const noexcept -> bool { |
13931 | return m_size == other.m_size |
13932 | && (std::memcmp( m_start, other.m_start, m_size ) == 0); |
13933 | } |
13934 | |
13935 | auto operator << ( std::ostream& os, StringRef const& str ) -> std::ostream& { |
13936 | return os.write(str.data(), str.size()); |
13937 | } |
13938 | |
13939 | auto operator+=( std::string& lhs, StringRef const& rhs ) -> std::string& { |
13940 | lhs.append(rhs.data(), rhs.size()); |
13941 | return lhs; |
13942 | } |
13943 | |
13944 | } // namespace Catch |
13945 | // end catch_stringref.cpp |
13946 | // start catch_tag_alias.cpp |
13947 | |
13948 | namespace Catch { |
13949 | TagAlias::TagAlias(std::string const & _tag, SourceLineInfo _lineInfo): tag(_tag), lineInfo(_lineInfo) {} |
13950 | } |
13951 | // end catch_tag_alias.cpp |
13952 | // start catch_tag_alias_autoregistrar.cpp |
13953 | |
13954 | namespace Catch { |
13955 | |
13956 | RegistrarForTagAliases::RegistrarForTagAliases(char const* alias, char const* tag, SourceLineInfo const& lineInfo) { |
13957 | CATCH_TRY { |
13958 | getMutableRegistryHub().registerTagAlias(alias, tag, lineInfo); |
13959 | } CATCH_CATCH_ALL { |
13960 | // Do not throw when constructing global objects, instead register the exception to be processed later |
13961 | getMutableRegistryHub().registerStartupException(); |
13962 | } |
13963 | } |
13964 | |
13965 | } |
13966 | // end catch_tag_alias_autoregistrar.cpp |
13967 | // start catch_tag_alias_registry.cpp |
13968 | |
13969 | #include <sstream> |
13970 | |
13971 | namespace Catch { |
13972 | |
13973 | TagAliasRegistry::~TagAliasRegistry() {} |
13974 | |
13975 | TagAlias const* TagAliasRegistry::find( std::string const& alias ) const { |
13976 | auto it = m_registry.find( alias ); |
13977 | if( it != m_registry.end() ) |
13978 | return &(it->second); |
13979 | else |
13980 | return nullptr; |
13981 | } |
13982 | |
13983 | std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { |
13984 | std::string expandedTestSpec = unexpandedTestSpec; |
13985 | for( auto const& registryKvp : m_registry ) { |
13986 | std::size_t pos = expandedTestSpec.find( registryKvp.first ); |
13987 | if( pos != std::string::npos ) { |
13988 | expandedTestSpec = expandedTestSpec.substr( 0, pos ) + |
13989 | registryKvp.second.tag + |
13990 | expandedTestSpec.substr( pos + registryKvp.first.size() ); |
13991 | } |
13992 | } |
13993 | return expandedTestSpec; |
13994 | } |
13995 | |
13996 | void TagAliasRegistry::add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) { |
13997 | CATCH_ENFORCE( startsWith(alias, "[@" ) && endsWith(alias, ']'), |
13998 | "error: tag alias, '" << alias << "' is not of the form [@alias name].\n" << lineInfo ); |
13999 | |
14000 | CATCH_ENFORCE( m_registry.insert(std::make_pair(alias, TagAlias(tag, lineInfo))).second, |
14001 | "error: tag alias, '" << alias << "' already registered.\n" |
14002 | << "\tFirst seen at: " << find(alias)->lineInfo << "\n" |
14003 | << "\tRedefined at: " << lineInfo ); |
14004 | } |
14005 | |
14006 | ITagAliasRegistry::~ITagAliasRegistry() {} |
14007 | |
14008 | ITagAliasRegistry const& ITagAliasRegistry::get() { |
14009 | return getRegistryHub().getTagAliasRegistry(); |
14010 | } |
14011 | |
14012 | } // end namespace Catch |
14013 | // end catch_tag_alias_registry.cpp |
14014 | // start catch_test_case_info.cpp |
14015 | |
14016 | #include <cctype> |
14017 | #include <exception> |
14018 | #include <algorithm> |
14019 | #include <sstream> |
14020 | |
14021 | namespace Catch { |
14022 | |
14023 | namespace { |
14024 | TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { |
14025 | if( startsWith( tag, '.' ) || |
14026 | tag == "!hide" ) |
14027 | return TestCaseInfo::IsHidden; |
14028 | else if( tag == "!throws" ) |
14029 | return TestCaseInfo::Throws; |
14030 | else if( tag == "!shouldfail" ) |
14031 | return TestCaseInfo::ShouldFail; |
14032 | else if( tag == "!mayfail" ) |
14033 | return TestCaseInfo::MayFail; |
14034 | else if( tag == "!nonportable" ) |
14035 | return TestCaseInfo::NonPortable; |
14036 | else if( tag == "!benchmark" ) |
14037 | return static_cast<TestCaseInfo::SpecialProperties>( TestCaseInfo::Benchmark | TestCaseInfo::IsHidden ); |
14038 | else |
14039 | return TestCaseInfo::None; |
14040 | } |
14041 | bool isReservedTag( std::string const& tag ) { |
14042 | return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( static_cast<unsigned char>(tag[0]) ); |
14043 | } |
14044 | void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { |
14045 | CATCH_ENFORCE( !isReservedTag(tag), |
14046 | "Tag name: [" << tag << "] is not allowed.\n" |
14047 | << "Tag names starting with non alphanumeric characters are reserved\n" |
14048 | << _lineInfo ); |
14049 | } |
14050 | } |
14051 | |
14052 | TestCase makeTestCase( ITestInvoker* _testCase, |
14053 | std::string const& _className, |
14054 | NameAndTags const& nameAndTags, |
14055 | SourceLineInfo const& _lineInfo ) |
14056 | { |
14057 | bool isHidden = false; |
14058 | |
14059 | // Parse out tags |
14060 | std::vector<std::string> tags; |
14061 | std::string desc, tag; |
14062 | bool inTag = false; |
14063 | for (char c : nameAndTags.tags) { |
14064 | if( !inTag ) { |
14065 | if( c == '[' ) |
14066 | inTag = true; |
14067 | else |
14068 | desc += c; |
14069 | } |
14070 | else { |
14071 | if( c == ']' ) { |
14072 | TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag ); |
14073 | if( ( prop & TestCaseInfo::IsHidden ) != 0 ) |
14074 | isHidden = true; |
14075 | else if( prop == TestCaseInfo::None ) |
14076 | enforceNotReservedTag( tag, _lineInfo ); |
14077 | |
14078 | // Merged hide tags like `[.approvals]` should be added as |
14079 | // `[.][approvals]`. The `[.]` is added at later point, so |
14080 | // we only strip the prefix |
14081 | if (startsWith(tag, '.') && tag.size() > 1) { |
14082 | tag.erase(0, 1); |
14083 | } |
14084 | tags.push_back( tag ); |
14085 | tag.clear(); |
14086 | inTag = false; |
14087 | } |
14088 | else |
14089 | tag += c; |
14090 | } |
14091 | } |
14092 | if( isHidden ) { |
14093 | // Add all "hidden" tags to make them behave identically |
14094 | tags.insert( tags.end(), { "." , "!hide" } ); |
14095 | } |
14096 | |
14097 | TestCaseInfo info( static_cast<std::string>(nameAndTags.name), _className, desc, tags, _lineInfo ); |
14098 | return TestCase( _testCase, std::move(info) ); |
14099 | } |
14100 | |
14101 | void setTags( TestCaseInfo& testCaseInfo, std::vector<std::string> tags ) { |
14102 | std::sort(begin(tags), end(tags)); |
14103 | tags.erase(std::unique(begin(tags), end(tags)), end(tags)); |
14104 | testCaseInfo.lcaseTags.clear(); |
14105 | |
14106 | for( auto const& tag : tags ) { |
14107 | std::string lcaseTag = toLower( tag ); |
14108 | testCaseInfo.properties = static_cast<TestCaseInfo::SpecialProperties>( testCaseInfo.properties | parseSpecialTag( lcaseTag ) ); |
14109 | testCaseInfo.lcaseTags.push_back( lcaseTag ); |
14110 | } |
14111 | testCaseInfo.tags = std::move(tags); |
14112 | } |
14113 | |
14114 | TestCaseInfo::TestCaseInfo( std::string const& _name, |
14115 | std::string const& _className, |
14116 | std::string const& _description, |
14117 | std::vector<std::string> const& _tags, |
14118 | SourceLineInfo const& _lineInfo ) |
14119 | : name( _name ), |
14120 | className( _className ), |
14121 | description( _description ), |
14122 | lineInfo( _lineInfo ), |
14123 | properties( None ) |
14124 | { |
14125 | setTags( *this, _tags ); |
14126 | } |
14127 | |
14128 | bool TestCaseInfo::isHidden() const { |
14129 | return ( properties & IsHidden ) != 0; |
14130 | } |
14131 | bool TestCaseInfo::throws() const { |
14132 | return ( properties & Throws ) != 0; |
14133 | } |
14134 | bool TestCaseInfo::okToFail() const { |
14135 | return ( properties & (ShouldFail | MayFail ) ) != 0; |
14136 | } |
14137 | bool TestCaseInfo::expectedToFail() const { |
14138 | return ( properties & (ShouldFail ) ) != 0; |
14139 | } |
14140 | |
14141 | std::string TestCaseInfo::tagsAsString() const { |
14142 | std::string ret; |
14143 | // '[' and ']' per tag |
14144 | std::size_t full_size = 2 * tags.size(); |
14145 | for (const auto& tag : tags) { |
14146 | full_size += tag.size(); |
14147 | } |
14148 | ret.reserve(full_size); |
14149 | for (const auto& tag : tags) { |
14150 | ret.push_back('['); |
14151 | ret.append(tag); |
14152 | ret.push_back(']'); |
14153 | } |
14154 | |
14155 | return ret; |
14156 | } |
14157 | |
14158 | TestCase::TestCase( ITestInvoker* testCase, TestCaseInfo&& info ) : TestCaseInfo( std::move(info) ), test( testCase ) {} |
14159 | |
14160 | TestCase TestCase::withName( std::string const& _newName ) const { |
14161 | TestCase other( *this ); |
14162 | other.name = _newName; |
14163 | return other; |
14164 | } |
14165 | |
14166 | void TestCase::invoke() const { |
14167 | test->invoke(); |
14168 | } |
14169 | |
14170 | bool TestCase::operator == ( TestCase const& other ) const { |
14171 | return test.get() == other.test.get() && |
14172 | name == other.name && |
14173 | className == other.className; |
14174 | } |
14175 | |
14176 | bool TestCase::operator < ( TestCase const& other ) const { |
14177 | return name < other.name; |
14178 | } |
14179 | |
14180 | TestCaseInfo const& TestCase::getTestCaseInfo() const |
14181 | { |
14182 | return *this; |
14183 | } |
14184 | |
14185 | } // end namespace Catch |
14186 | // end catch_test_case_info.cpp |
14187 | // start catch_test_case_registry_impl.cpp |
14188 | |
14189 | #include <algorithm> |
14190 | #include <sstream> |
14191 | |
14192 | namespace Catch { |
14193 | |
14194 | namespace { |
14195 | struct TestHasher { |
14196 | using hash_t = uint64_t; |
14197 | |
14198 | explicit TestHasher( hash_t hashSuffix ): |
14199 | m_hashSuffix{ hashSuffix } {} |
14200 | |
14201 | uint32_t operator()( TestCase const& t ) const { |
14202 | // FNV-1a hash with multiplication fold. |
14203 | const hash_t prime = 1099511628211u; |
14204 | hash_t hash = 14695981039346656037u; |
14205 | for ( const char c : t.name ) { |
14206 | hash ^= c; |
14207 | hash *= prime; |
14208 | } |
14209 | hash ^= m_hashSuffix; |
14210 | hash *= prime; |
14211 | const uint32_t low{ static_cast<uint32_t>( hash ) }; |
14212 | const uint32_t high{ static_cast<uint32_t>( hash >> 32 ) }; |
14213 | return low * high; |
14214 | } |
14215 | |
14216 | private: |
14217 | hash_t m_hashSuffix; |
14218 | }; |
14219 | } // end unnamed namespace |
14220 | |
14221 | std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ) { |
14222 | switch( config.runOrder() ) { |
14223 | case RunTests::InDeclarationOrder: |
14224 | // already in declaration order |
14225 | break; |
14226 | |
14227 | case RunTests::InLexicographicalOrder: { |
14228 | std::vector<TestCase> sorted = unsortedTestCases; |
14229 | std::sort( sorted.begin(), sorted.end() ); |
14230 | return sorted; |
14231 | } |
14232 | |
14233 | case RunTests::InRandomOrder: { |
14234 | seedRng( config ); |
14235 | TestHasher h{ config.rngSeed() }; |
14236 | |
14237 | using hashedTest = std::pair<TestHasher::hash_t, TestCase const*>; |
14238 | std::vector<hashedTest> indexed_tests; |
14239 | indexed_tests.reserve( unsortedTestCases.size() ); |
14240 | |
14241 | for (auto const& testCase : unsortedTestCases) { |
14242 | indexed_tests.emplace_back(h(testCase), &testCase); |
14243 | } |
14244 | |
14245 | std::sort(indexed_tests.begin(), indexed_tests.end(), |
14246 | [](hashedTest const& lhs, hashedTest const& rhs) { |
14247 | if (lhs.first == rhs.first) { |
14248 | return lhs.second->name < rhs.second->name; |
14249 | } |
14250 | return lhs.first < rhs.first; |
14251 | }); |
14252 | |
14253 | std::vector<TestCase> sorted; |
14254 | sorted.reserve( indexed_tests.size() ); |
14255 | |
14256 | for (auto const& hashed : indexed_tests) { |
14257 | sorted.emplace_back(*hashed.second); |
14258 | } |
14259 | |
14260 | return sorted; |
14261 | } |
14262 | } |
14263 | return unsortedTestCases; |
14264 | } |
14265 | |
14266 | bool isThrowSafe( TestCase const& testCase, IConfig const& config ) { |
14267 | return !testCase.throws() || config.allowThrows(); |
14268 | } |
14269 | |
14270 | bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) { |
14271 | return testSpec.matches( testCase ) && isThrowSafe( testCase, config ); |
14272 | } |
14273 | |
14274 | void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions ) { |
14275 | std::set<TestCase> seenFunctions; |
14276 | for( auto const& function : functions ) { |
14277 | auto prev = seenFunctions.insert( function ); |
14278 | CATCH_ENFORCE( prev.second, |
14279 | "error: TEST_CASE( \"" << function.name << "\" ) already defined.\n" |
14280 | << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" |
14281 | << "\tRedefined at " << function.getTestCaseInfo().lineInfo ); |
14282 | } |
14283 | } |
14284 | |
14285 | std::vector<TestCase> filterTests( std::vector<TestCase> const& testCases, TestSpec const& testSpec, IConfig const& config ) { |
14286 | std::vector<TestCase> filtered; |
14287 | filtered.reserve( testCases.size() ); |
14288 | for (auto const& testCase : testCases) { |
14289 | if ((!testSpec.hasFilters() && !testCase.isHidden()) || |
14290 | (testSpec.hasFilters() && matchTest(testCase, testSpec, config))) { |
14291 | filtered.push_back(testCase); |
14292 | } |
14293 | } |
14294 | return filtered; |
14295 | } |
14296 | std::vector<TestCase> const& getAllTestCasesSorted( IConfig const& config ) { |
14297 | return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config ); |
14298 | } |
14299 | |
14300 | void TestRegistry::registerTest( TestCase const& testCase ) { |
14301 | std::string name = testCase.getTestCaseInfo().name; |
14302 | if( name.empty() ) { |
14303 | ReusableStringStream rss; |
14304 | rss << "Anonymous test case " << ++m_unnamedCount; |
14305 | return registerTest( testCase.withName( rss.str() ) ); |
14306 | } |
14307 | m_functions.push_back( testCase ); |
14308 | } |
14309 | |
14310 | std::vector<TestCase> const& TestRegistry::getAllTests() const { |
14311 | return m_functions; |
14312 | } |
14313 | std::vector<TestCase> const& TestRegistry::getAllTestsSorted( IConfig const& config ) const { |
14314 | if( m_sortedFunctions.empty() ) |
14315 | enforceNoDuplicateTestCases( m_functions ); |
14316 | |
14317 | if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) { |
14318 | m_sortedFunctions = sortTests( config, m_functions ); |
14319 | m_currentSortOrder = config.runOrder(); |
14320 | } |
14321 | return m_sortedFunctions; |
14322 | } |
14323 | |
14324 | /////////////////////////////////////////////////////////////////////////// |
14325 | TestInvokerAsFunction::TestInvokerAsFunction( void(*testAsFunction)() ) noexcept : m_testAsFunction( testAsFunction ) {} |
14326 | |
14327 | void TestInvokerAsFunction::invoke() const { |
14328 | m_testAsFunction(); |
14329 | } |
14330 | |
14331 | std::string extractClassName( StringRef const& classOrQualifiedMethodName ) { |
14332 | std::string className(classOrQualifiedMethodName); |
14333 | if( startsWith( className, '&' ) ) |
14334 | { |
14335 | std::size_t lastColons = className.rfind( "::" ); |
14336 | std::size_t penultimateColons = className.rfind( "::" , lastColons-1 ); |
14337 | if( penultimateColons == std::string::npos ) |
14338 | penultimateColons = 1; |
14339 | className = className.substr( penultimateColons, lastColons-penultimateColons ); |
14340 | } |
14341 | return className; |
14342 | } |
14343 | |
14344 | } // end namespace Catch |
14345 | // end catch_test_case_registry_impl.cpp |
14346 | // start catch_test_case_tracker.cpp |
14347 | |
14348 | #include <algorithm> |
14349 | #include <cassert> |
14350 | #include <stdexcept> |
14351 | #include <memory> |
14352 | #include <sstream> |
14353 | |
14354 | #if defined(__clang__) |
14355 | # pragma clang diagnostic push |
14356 | # pragma clang diagnostic ignored "-Wexit-time-destructors" |
14357 | #endif |
14358 | |
14359 | namespace Catch { |
14360 | namespace TestCaseTracking { |
14361 | |
14362 | NameAndLocation::NameAndLocation( std::string const& _name, SourceLineInfo const& _location ) |
14363 | : name( _name ), |
14364 | location( _location ) |
14365 | {} |
14366 | |
14367 | ITracker::~ITracker() = default; |
14368 | |
14369 | ITracker& TrackerContext::startRun() { |
14370 | m_rootTracker = std::make_shared<SectionTracker>( NameAndLocation( "{root}" , CATCH_INTERNAL_LINEINFO ), *this, nullptr ); |
14371 | m_currentTracker = nullptr; |
14372 | m_runState = Executing; |
14373 | return *m_rootTracker; |
14374 | } |
14375 | |
14376 | void TrackerContext::endRun() { |
14377 | m_rootTracker.reset(); |
14378 | m_currentTracker = nullptr; |
14379 | m_runState = NotStarted; |
14380 | } |
14381 | |
14382 | void TrackerContext::startCycle() { |
14383 | m_currentTracker = m_rootTracker.get(); |
14384 | m_runState = Executing; |
14385 | } |
14386 | void TrackerContext::completeCycle() { |
14387 | m_runState = CompletedCycle; |
14388 | } |
14389 | |
14390 | bool TrackerContext::completedCycle() const { |
14391 | return m_runState == CompletedCycle; |
14392 | } |
14393 | ITracker& TrackerContext::currentTracker() { |
14394 | return *m_currentTracker; |
14395 | } |
14396 | void TrackerContext::setCurrentTracker( ITracker* tracker ) { |
14397 | m_currentTracker = tracker; |
14398 | } |
14399 | |
14400 | TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ): |
14401 | ITracker(nameAndLocation), |
14402 | m_ctx( ctx ), |
14403 | m_parent( parent ) |
14404 | {} |
14405 | |
14406 | bool TrackerBase::isComplete() const { |
14407 | return m_runState == CompletedSuccessfully || m_runState == Failed; |
14408 | } |
14409 | bool TrackerBase::isSuccessfullyCompleted() const { |
14410 | return m_runState == CompletedSuccessfully; |
14411 | } |
14412 | bool TrackerBase::isOpen() const { |
14413 | return m_runState != NotStarted && !isComplete(); |
14414 | } |
14415 | bool TrackerBase::hasChildren() const { |
14416 | return !m_children.empty(); |
14417 | } |
14418 | |
14419 | void TrackerBase::addChild( ITrackerPtr const& child ) { |
14420 | m_children.push_back( child ); |
14421 | } |
14422 | |
14423 | ITrackerPtr TrackerBase::findChild( NameAndLocation const& nameAndLocation ) { |
14424 | auto it = std::find_if( m_children.begin(), m_children.end(), |
14425 | [&nameAndLocation]( ITrackerPtr const& tracker ){ |
14426 | return |
14427 | tracker->nameAndLocation().location == nameAndLocation.location && |
14428 | tracker->nameAndLocation().name == nameAndLocation.name; |
14429 | } ); |
14430 | return( it != m_children.end() ) |
14431 | ? *it |
14432 | : nullptr; |
14433 | } |
14434 | ITracker& TrackerBase::parent() { |
14435 | assert( m_parent ); // Should always be non-null except for root |
14436 | return *m_parent; |
14437 | } |
14438 | |
14439 | void TrackerBase::openChild() { |
14440 | if( m_runState != ExecutingChildren ) { |
14441 | m_runState = ExecutingChildren; |
14442 | if( m_parent ) |
14443 | m_parent->openChild(); |
14444 | } |
14445 | } |
14446 | |
14447 | bool TrackerBase::isSectionTracker() const { return false; } |
14448 | bool TrackerBase::isGeneratorTracker() const { return false; } |
14449 | |
14450 | void TrackerBase::open() { |
14451 | m_runState = Executing; |
14452 | moveToThis(); |
14453 | if( m_parent ) |
14454 | m_parent->openChild(); |
14455 | } |
14456 | |
14457 | void TrackerBase::close() { |
14458 | |
14459 | // Close any still open children (e.g. generators) |
14460 | while( &m_ctx.currentTracker() != this ) |
14461 | m_ctx.currentTracker().close(); |
14462 | |
14463 | switch( m_runState ) { |
14464 | case NeedsAnotherRun: |
14465 | break; |
14466 | |
14467 | case Executing: |
14468 | m_runState = CompletedSuccessfully; |
14469 | break; |
14470 | case ExecutingChildren: |
14471 | if( std::all_of(m_children.begin(), m_children.end(), [](ITrackerPtr const& t){ return t->isComplete(); }) ) |
14472 | m_runState = CompletedSuccessfully; |
14473 | break; |
14474 | |
14475 | case NotStarted: |
14476 | case CompletedSuccessfully: |
14477 | case Failed: |
14478 | CATCH_INTERNAL_ERROR( "Illogical state: " << m_runState ); |
14479 | |
14480 | default: |
14481 | CATCH_INTERNAL_ERROR( "Unknown state: " << m_runState ); |
14482 | } |
14483 | moveToParent(); |
14484 | m_ctx.completeCycle(); |
14485 | } |
14486 | void TrackerBase::fail() { |
14487 | m_runState = Failed; |
14488 | if( m_parent ) |
14489 | m_parent->markAsNeedingAnotherRun(); |
14490 | moveToParent(); |
14491 | m_ctx.completeCycle(); |
14492 | } |
14493 | void TrackerBase::markAsNeedingAnotherRun() { |
14494 | m_runState = NeedsAnotherRun; |
14495 | } |
14496 | |
14497 | void TrackerBase::moveToParent() { |
14498 | assert( m_parent ); |
14499 | m_ctx.setCurrentTracker( m_parent ); |
14500 | } |
14501 | void TrackerBase::moveToThis() { |
14502 | m_ctx.setCurrentTracker( this ); |
14503 | } |
14504 | |
14505 | SectionTracker::SectionTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) |
14506 | : TrackerBase( nameAndLocation, ctx, parent ), |
14507 | m_trimmed_name(trim(nameAndLocation.name)) |
14508 | { |
14509 | if( parent ) { |
14510 | while( !parent->isSectionTracker() ) |
14511 | parent = &parent->parent(); |
14512 | |
14513 | SectionTracker& parentSection = static_cast<SectionTracker&>( *parent ); |
14514 | addNextFilters( parentSection.m_filters ); |
14515 | } |
14516 | } |
14517 | |
14518 | bool SectionTracker::isComplete() const { |
14519 | bool complete = true; |
14520 | |
14521 | if (m_filters.empty() |
14522 | || m_filters[0] == "" |
14523 | || std::find(m_filters.begin(), m_filters.end(), m_trimmed_name) != m_filters.end()) { |
14524 | complete = TrackerBase::isComplete(); |
14525 | } |
14526 | return complete; |
14527 | } |
14528 | |
14529 | bool SectionTracker::isSectionTracker() const { return true; } |
14530 | |
14531 | SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) { |
14532 | std::shared_ptr<SectionTracker> section; |
14533 | |
14534 | ITracker& currentTracker = ctx.currentTracker(); |
14535 | if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { |
14536 | assert( childTracker ); |
14537 | assert( childTracker->isSectionTracker() ); |
14538 | section = std::static_pointer_cast<SectionTracker>( childTracker ); |
14539 | } |
14540 | else { |
14541 | section = std::make_shared<SectionTracker>( nameAndLocation, ctx, ¤tTracker ); |
14542 | currentTracker.addChild( section ); |
14543 | } |
14544 | if( !ctx.completedCycle() ) |
14545 | section->tryOpen(); |
14546 | return *section; |
14547 | } |
14548 | |
14549 | void SectionTracker::tryOpen() { |
14550 | if( !isComplete() ) |
14551 | open(); |
14552 | } |
14553 | |
14554 | void SectionTracker::addInitialFilters( std::vector<std::string> const& filters ) { |
14555 | if( !filters.empty() ) { |
14556 | m_filters.reserve( m_filters.size() + filters.size() + 2 ); |
14557 | m_filters.emplace_back("" ); // Root - should never be consulted |
14558 | m_filters.emplace_back("" ); // Test Case - not a section filter |
14559 | m_filters.insert( m_filters.end(), filters.begin(), filters.end() ); |
14560 | } |
14561 | } |
14562 | void SectionTracker::addNextFilters( std::vector<std::string> const& filters ) { |
14563 | if( filters.size() > 1 ) |
14564 | m_filters.insert( m_filters.end(), filters.begin()+1, filters.end() ); |
14565 | } |
14566 | |
14567 | std::vector<std::string> const& SectionTracker::getFilters() const { |
14568 | return m_filters; |
14569 | } |
14570 | |
14571 | std::string const& SectionTracker::trimmedName() const { |
14572 | return m_trimmed_name; |
14573 | } |
14574 | |
14575 | } // namespace TestCaseTracking |
14576 | |
14577 | using TestCaseTracking::ITracker; |
14578 | using TestCaseTracking::TrackerContext; |
14579 | using TestCaseTracking::SectionTracker; |
14580 | |
14581 | } // namespace Catch |
14582 | |
14583 | #if defined(__clang__) |
14584 | # pragma clang diagnostic pop |
14585 | #endif |
14586 | // end catch_test_case_tracker.cpp |
14587 | // start catch_test_registry.cpp |
14588 | |
14589 | namespace Catch { |
14590 | |
14591 | auto makeTestInvoker( void(*testAsFunction)() ) noexcept -> ITestInvoker* { |
14592 | return new(std::nothrow) TestInvokerAsFunction( testAsFunction ); |
14593 | } |
14594 | |
14595 | NameAndTags::NameAndTags( StringRef const& name_ , StringRef const& tags_ ) noexcept : name( name_ ), tags( tags_ ) {} |
14596 | |
14597 | AutoReg::AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept { |
14598 | CATCH_TRY { |
14599 | getMutableRegistryHub() |
14600 | .registerTest( |
14601 | makeTestCase( |
14602 | invoker, |
14603 | extractClassName( classOrMethod ), |
14604 | nameAndTags, |
14605 | lineInfo)); |
14606 | } CATCH_CATCH_ALL { |
14607 | // Do not throw when constructing global objects, instead register the exception to be processed later |
14608 | getMutableRegistryHub().registerStartupException(); |
14609 | } |
14610 | } |
14611 | |
14612 | AutoReg::~AutoReg() = default; |
14613 | } |
14614 | // end catch_test_registry.cpp |
14615 | // start catch_test_spec.cpp |
14616 | |
14617 | #include <algorithm> |
14618 | #include <string> |
14619 | #include <vector> |
14620 | #include <memory> |
14621 | |
14622 | namespace Catch { |
14623 | |
14624 | TestSpec::Pattern::Pattern( std::string const& name ) |
14625 | : m_name( name ) |
14626 | {} |
14627 | |
14628 | TestSpec::Pattern::~Pattern() = default; |
14629 | |
14630 | std::string const& TestSpec::Pattern::name() const { |
14631 | return m_name; |
14632 | } |
14633 | |
14634 | TestSpec::NamePattern::NamePattern( std::string const& name, std::string const& filterString ) |
14635 | : Pattern( filterString ) |
14636 | , m_wildcardPattern( toLower( name ), CaseSensitive::No ) |
14637 | {} |
14638 | |
14639 | bool TestSpec::NamePattern::matches( TestCaseInfo const& testCase ) const { |
14640 | return m_wildcardPattern.matches( testCase.name ); |
14641 | } |
14642 | |
14643 | TestSpec::TagPattern::TagPattern( std::string const& tag, std::string const& filterString ) |
14644 | : Pattern( filterString ) |
14645 | , m_tag( toLower( tag ) ) |
14646 | {} |
14647 | |
14648 | bool TestSpec::TagPattern::matches( TestCaseInfo const& testCase ) const { |
14649 | return std::find(begin(testCase.lcaseTags), |
14650 | end(testCase.lcaseTags), |
14651 | m_tag) != end(testCase.lcaseTags); |
14652 | } |
14653 | |
14654 | TestSpec::ExcludedPattern::ExcludedPattern( PatternPtr const& underlyingPattern ) |
14655 | : Pattern( underlyingPattern->name() ) |
14656 | , m_underlyingPattern( underlyingPattern ) |
14657 | {} |
14658 | |
14659 | bool TestSpec::ExcludedPattern::matches( TestCaseInfo const& testCase ) const { |
14660 | return !m_underlyingPattern->matches( testCase ); |
14661 | } |
14662 | |
14663 | bool TestSpec::Filter::matches( TestCaseInfo const& testCase ) const { |
14664 | return std::all_of( m_patterns.begin(), m_patterns.end(), [&]( PatternPtr const& p ){ return p->matches( testCase ); } ); |
14665 | } |
14666 | |
14667 | std::string TestSpec::Filter::name() const { |
14668 | std::string name; |
14669 | for( auto const& p : m_patterns ) |
14670 | name += p->name(); |
14671 | return name; |
14672 | } |
14673 | |
14674 | bool TestSpec::hasFilters() const { |
14675 | return !m_filters.empty(); |
14676 | } |
14677 | |
14678 | bool TestSpec::matches( TestCaseInfo const& testCase ) const { |
14679 | return std::any_of( m_filters.begin(), m_filters.end(), [&]( Filter const& f ){ return f.matches( testCase ); } ); |
14680 | } |
14681 | |
14682 | TestSpec::Matches TestSpec::matchesByFilter( std::vector<TestCase> const& testCases, IConfig const& config ) const |
14683 | { |
14684 | Matches matches( m_filters.size() ); |
14685 | std::transform( m_filters.begin(), m_filters.end(), matches.begin(), [&]( Filter const& filter ){ |
14686 | std::vector<TestCase const*> currentMatches; |
14687 | for( auto const& test : testCases ) |
14688 | if( isThrowSafe( test, config ) && filter.matches( test ) ) |
14689 | currentMatches.emplace_back( &test ); |
14690 | return FilterMatch{ filter.name(), currentMatches }; |
14691 | } ); |
14692 | return matches; |
14693 | } |
14694 | |
14695 | const TestSpec::vectorStrings& TestSpec::getInvalidArgs() const{ |
14696 | return (m_invalidArgs); |
14697 | } |
14698 | |
14699 | } |
14700 | // end catch_test_spec.cpp |
14701 | // start catch_test_spec_parser.cpp |
14702 | |
14703 | namespace Catch { |
14704 | |
14705 | TestSpecParser::TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {} |
14706 | |
14707 | TestSpecParser& TestSpecParser::parse( std::string const& arg ) { |
14708 | m_mode = None; |
14709 | m_exclusion = false; |
14710 | m_arg = m_tagAliases->expandAliases( arg ); |
14711 | m_escapeChars.clear(); |
14712 | m_substring.reserve(m_arg.size()); |
14713 | m_patternName.reserve(m_arg.size()); |
14714 | m_realPatternPos = 0; |
14715 | |
14716 | for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) |
14717 | //if visitChar fails |
14718 | if( !visitChar( m_arg[m_pos] ) ){ |
14719 | m_testSpec.m_invalidArgs.push_back(arg); |
14720 | break; |
14721 | } |
14722 | endMode(); |
14723 | return *this; |
14724 | } |
14725 | TestSpec TestSpecParser::testSpec() { |
14726 | addFilter(); |
14727 | return m_testSpec; |
14728 | } |
14729 | bool TestSpecParser::visitChar( char c ) { |
14730 | if( (m_mode != EscapedName) && (c == '\\') ) { |
14731 | escape(); |
14732 | addCharToPattern(c); |
14733 | return true; |
14734 | }else if((m_mode != EscapedName) && (c == ',') ) { |
14735 | return separate(); |
14736 | } |
14737 | |
14738 | switch( m_mode ) { |
14739 | case None: |
14740 | if( processNoneChar( c ) ) |
14741 | return true; |
14742 | break; |
14743 | case Name: |
14744 | processNameChar( c ); |
14745 | break; |
14746 | case EscapedName: |
14747 | endMode(); |
14748 | addCharToPattern(c); |
14749 | return true; |
14750 | default: |
14751 | case Tag: |
14752 | case QuotedName: |
14753 | if( processOtherChar( c ) ) |
14754 | return true; |
14755 | break; |
14756 | } |
14757 | |
14758 | m_substring += c; |
14759 | if( !isControlChar( c ) ) { |
14760 | m_patternName += c; |
14761 | m_realPatternPos++; |
14762 | } |
14763 | return true; |
14764 | } |
14765 | // Two of the processing methods return true to signal the caller to return |
14766 | // without adding the given character to the current pattern strings |
14767 | bool TestSpecParser::processNoneChar( char c ) { |
14768 | switch( c ) { |
14769 | case ' ': |
14770 | return true; |
14771 | case '~': |
14772 | m_exclusion = true; |
14773 | return false; |
14774 | case '[': |
14775 | startNewMode( Tag ); |
14776 | return false; |
14777 | case '"': |
14778 | startNewMode( QuotedName ); |
14779 | return false; |
14780 | default: |
14781 | startNewMode( Name ); |
14782 | return false; |
14783 | } |
14784 | } |
14785 | void TestSpecParser::processNameChar( char c ) { |
14786 | if( c == '[' ) { |
14787 | if( m_substring == "exclude:" ) |
14788 | m_exclusion = true; |
14789 | else |
14790 | endMode(); |
14791 | startNewMode( Tag ); |
14792 | } |
14793 | } |
14794 | bool TestSpecParser::processOtherChar( char c ) { |
14795 | if( !isControlChar( c ) ) |
14796 | return false; |
14797 | m_substring += c; |
14798 | endMode(); |
14799 | return true; |
14800 | } |
14801 | void TestSpecParser::startNewMode( Mode mode ) { |
14802 | m_mode = mode; |
14803 | } |
14804 | void TestSpecParser::endMode() { |
14805 | switch( m_mode ) { |
14806 | case Name: |
14807 | case QuotedName: |
14808 | return addNamePattern(); |
14809 | case Tag: |
14810 | return addTagPattern(); |
14811 | case EscapedName: |
14812 | revertBackToLastMode(); |
14813 | return; |
14814 | case None: |
14815 | default: |
14816 | return startNewMode( None ); |
14817 | } |
14818 | } |
14819 | void TestSpecParser::escape() { |
14820 | saveLastMode(); |
14821 | m_mode = EscapedName; |
14822 | m_escapeChars.push_back(m_realPatternPos); |
14823 | } |
14824 | bool TestSpecParser::isControlChar( char c ) const { |
14825 | switch( m_mode ) { |
14826 | default: |
14827 | return false; |
14828 | case None: |
14829 | return c == '~'; |
14830 | case Name: |
14831 | return c == '['; |
14832 | case EscapedName: |
14833 | return true; |
14834 | case QuotedName: |
14835 | return c == '"'; |
14836 | case Tag: |
14837 | return c == '[' || c == ']'; |
14838 | } |
14839 | } |
14840 | |
14841 | void TestSpecParser::addFilter() { |
14842 | if( !m_currentFilter.m_patterns.empty() ) { |
14843 | m_testSpec.m_filters.push_back( m_currentFilter ); |
14844 | m_currentFilter = TestSpec::Filter(); |
14845 | } |
14846 | } |
14847 | |
14848 | void TestSpecParser::saveLastMode() { |
14849 | lastMode = m_mode; |
14850 | } |
14851 | |
14852 | void TestSpecParser::revertBackToLastMode() { |
14853 | m_mode = lastMode; |
14854 | } |
14855 | |
14856 | bool TestSpecParser::separate() { |
14857 | if( (m_mode==QuotedName) || (m_mode==Tag) ){ |
14858 | //invalid argument, signal failure to previous scope. |
14859 | m_mode = None; |
14860 | m_pos = m_arg.size(); |
14861 | m_substring.clear(); |
14862 | m_patternName.clear(); |
14863 | m_realPatternPos = 0; |
14864 | return false; |
14865 | } |
14866 | endMode(); |
14867 | addFilter(); |
14868 | return true; //success |
14869 | } |
14870 | |
14871 | std::string TestSpecParser::preprocessPattern() { |
14872 | std::string token = m_patternName; |
14873 | for (std::size_t i = 0; i < m_escapeChars.size(); ++i) |
14874 | token = token.substr(0, m_escapeChars[i] - i) + token.substr(m_escapeChars[i] - i + 1); |
14875 | m_escapeChars.clear(); |
14876 | if (startsWith(token, "exclude:" )) { |
14877 | m_exclusion = true; |
14878 | token = token.substr(8); |
14879 | } |
14880 | |
14881 | m_patternName.clear(); |
14882 | m_realPatternPos = 0; |
14883 | |
14884 | return token; |
14885 | } |
14886 | |
14887 | void TestSpecParser::addNamePattern() { |
14888 | auto token = preprocessPattern(); |
14889 | |
14890 | if (!token.empty()) { |
14891 | TestSpec::PatternPtr pattern = std::make_shared<TestSpec::NamePattern>(token, m_substring); |
14892 | if (m_exclusion) |
14893 | pattern = std::make_shared<TestSpec::ExcludedPattern>(pattern); |
14894 | m_currentFilter.m_patterns.push_back(pattern); |
14895 | } |
14896 | m_substring.clear(); |
14897 | m_exclusion = false; |
14898 | m_mode = None; |
14899 | } |
14900 | |
14901 | void TestSpecParser::addTagPattern() { |
14902 | auto token = preprocessPattern(); |
14903 | |
14904 | if (!token.empty()) { |
14905 | // If the tag pattern is the "hide and tag" shorthand (e.g. [.foo]) |
14906 | // we have to create a separate hide tag and shorten the real one |
14907 | if (token.size() > 1 && token[0] == '.') { |
14908 | token.erase(token.begin()); |
14909 | TestSpec::PatternPtr pattern = std::make_shared<TestSpec::TagPattern>("." , m_substring); |
14910 | if (m_exclusion) { |
14911 | pattern = std::make_shared<TestSpec::ExcludedPattern>(pattern); |
14912 | } |
14913 | m_currentFilter.m_patterns.push_back(pattern); |
14914 | } |
14915 | |
14916 | TestSpec::PatternPtr pattern = std::make_shared<TestSpec::TagPattern>(token, m_substring); |
14917 | |
14918 | if (m_exclusion) { |
14919 | pattern = std::make_shared<TestSpec::ExcludedPattern>(pattern); |
14920 | } |
14921 | m_currentFilter.m_patterns.push_back(pattern); |
14922 | } |
14923 | m_substring.clear(); |
14924 | m_exclusion = false; |
14925 | m_mode = None; |
14926 | } |
14927 | |
14928 | TestSpec parseTestSpec( std::string const& arg ) { |
14929 | return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); |
14930 | } |
14931 | |
14932 | } // namespace Catch |
14933 | // end catch_test_spec_parser.cpp |
14934 | // start catch_timer.cpp |
14935 | |
14936 | #include <chrono> |
14937 | |
14938 | static const uint64_t nanosecondsInSecond = 1000000000; |
14939 | |
14940 | namespace Catch { |
14941 | |
14942 | auto getCurrentNanosecondsSinceEpoch() -> uint64_t { |
14943 | return std::chrono::duration_cast<std::chrono::nanoseconds>( std::chrono::high_resolution_clock::now().time_since_epoch() ).count(); |
14944 | } |
14945 | |
14946 | namespace { |
14947 | auto estimateClockResolution() -> uint64_t { |
14948 | uint64_t sum = 0; |
14949 | static const uint64_t iterations = 1000000; |
14950 | |
14951 | auto startTime = getCurrentNanosecondsSinceEpoch(); |
14952 | |
14953 | for( std::size_t i = 0; i < iterations; ++i ) { |
14954 | |
14955 | uint64_t ticks; |
14956 | uint64_t baseTicks = getCurrentNanosecondsSinceEpoch(); |
14957 | do { |
14958 | ticks = getCurrentNanosecondsSinceEpoch(); |
14959 | } while( ticks == baseTicks ); |
14960 | |
14961 | auto delta = ticks - baseTicks; |
14962 | sum += delta; |
14963 | |
14964 | // If we have been calibrating for over 3 seconds -- the clock |
14965 | // is terrible and we should move on. |
14966 | // TBD: How to signal that the measured resolution is probably wrong? |
14967 | if (ticks > startTime + 3 * nanosecondsInSecond) { |
14968 | return sum / ( i + 1u ); |
14969 | } |
14970 | } |
14971 | |
14972 | // We're just taking the mean, here. To do better we could take the std. dev and exclude outliers |
14973 | // - and potentially do more iterations if there's a high variance. |
14974 | return sum/iterations; |
14975 | } |
14976 | } |
14977 | auto getEstimatedClockResolution() -> uint64_t { |
14978 | static auto s_resolution = estimateClockResolution(); |
14979 | return s_resolution; |
14980 | } |
14981 | |
14982 | void Timer::start() { |
14983 | m_nanoseconds = getCurrentNanosecondsSinceEpoch(); |
14984 | } |
14985 | auto Timer::getElapsedNanoseconds() const -> uint64_t { |
14986 | return getCurrentNanosecondsSinceEpoch() - m_nanoseconds; |
14987 | } |
14988 | auto Timer::getElapsedMicroseconds() const -> uint64_t { |
14989 | return getElapsedNanoseconds()/1000; |
14990 | } |
14991 | auto Timer::getElapsedMilliseconds() const -> unsigned int { |
14992 | return static_cast<unsigned int>(getElapsedMicroseconds()/1000); |
14993 | } |
14994 | auto Timer::getElapsedSeconds() const -> double { |
14995 | return getElapsedMicroseconds()/1000000.0; |
14996 | } |
14997 | |
14998 | } // namespace Catch |
14999 | // end catch_timer.cpp |
15000 | // start catch_tostring.cpp |
15001 | |
15002 | #if defined(__clang__) |
15003 | # pragma clang diagnostic push |
15004 | # pragma clang diagnostic ignored "-Wexit-time-destructors" |
15005 | # pragma clang diagnostic ignored "-Wglobal-constructors" |
15006 | #endif |
15007 | |
15008 | // Enable specific decls locally |
15009 | #if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) |
15010 | #define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER |
15011 | #endif |
15012 | |
15013 | #include <cmath> |
15014 | #include <iomanip> |
15015 | |
15016 | namespace Catch { |
15017 | |
15018 | namespace Detail { |
15019 | |
15020 | const std::string unprintableString = "{?}" ; |
15021 | |
15022 | namespace { |
15023 | const int hexThreshold = 255; |
15024 | |
15025 | struct Endianness { |
15026 | enum Arch { Big, Little }; |
15027 | |
15028 | static Arch which() { |
15029 | int one = 1; |
15030 | // If the lowest byte we read is non-zero, we can assume |
15031 | // that little endian format is used. |
15032 | auto value = *reinterpret_cast<char*>(&one); |
15033 | return value ? Little : Big; |
15034 | } |
15035 | }; |
15036 | } |
15037 | |
15038 | std::string rawMemoryToString( const void *object, std::size_t size ) { |
15039 | // Reverse order for little endian architectures |
15040 | int i = 0, end = static_cast<int>( size ), inc = 1; |
15041 | if( Endianness::which() == Endianness::Little ) { |
15042 | i = end-1; |
15043 | end = inc = -1; |
15044 | } |
15045 | |
15046 | unsigned char const *bytes = static_cast<unsigned char const *>(object); |
15047 | ReusableStringStream rss; |
15048 | rss << "0x" << std::setfill('0') << std::hex; |
15049 | for( ; i != end; i += inc ) |
15050 | rss << std::setw(2) << static_cast<unsigned>(bytes[i]); |
15051 | return rss.str(); |
15052 | } |
15053 | } |
15054 | |
15055 | template<typename T> |
15056 | std::string fpToString( T value, int precision ) { |
15057 | if (Catch::isnan(value)) { |
15058 | return "nan" ; |
15059 | } |
15060 | |
15061 | ReusableStringStream rss; |
15062 | rss << std::setprecision( precision ) |
15063 | << std::fixed |
15064 | << value; |
15065 | std::string d = rss.str(); |
15066 | std::size_t i = d.find_last_not_of( '0' ); |
15067 | if( i != std::string::npos && i != d.size()-1 ) { |
15068 | if( d[i] == '.' ) |
15069 | i++; |
15070 | d = d.substr( 0, i+1 ); |
15071 | } |
15072 | return d; |
15073 | } |
15074 | |
15075 | //// ======================================================= //// |
15076 | // |
15077 | // Out-of-line defs for full specialization of StringMaker |
15078 | // |
15079 | //// ======================================================= //// |
15080 | |
15081 | std::string StringMaker<std::string>::convert(const std::string& str) { |
15082 | if (!getCurrentContext().getConfig()->showInvisibles()) { |
15083 | return '"' + str + '"'; |
15084 | } |
15085 | |
15086 | std::string s("\"" ); |
15087 | for (char c : str) { |
15088 | switch (c) { |
15089 | case '\n': |
15090 | s.append("\\n" ); |
15091 | break; |
15092 | case '\t': |
15093 | s.append("\\t" ); |
15094 | break; |
15095 | default: |
15096 | s.push_back(c); |
15097 | break; |
15098 | } |
15099 | } |
15100 | s.append("\"" ); |
15101 | return s; |
15102 | } |
15103 | |
15104 | #ifdef CATCH_CONFIG_CPP17_STRING_VIEW |
15105 | std::string StringMaker<std::string_view>::convert(std::string_view str) { |
15106 | return ::Catch::Detail::stringify(std::string{ str }); |
15107 | } |
15108 | #endif |
15109 | |
15110 | std::string StringMaker<char const*>::convert(char const* str) { |
15111 | if (str) { |
15112 | return ::Catch::Detail::stringify(std::string{ str }); |
15113 | } else { |
15114 | return{ "{null string}" }; |
15115 | } |
15116 | } |
15117 | std::string StringMaker<char*>::convert(char* str) { |
15118 | if (str) { |
15119 | return ::Catch::Detail::stringify(std::string{ str }); |
15120 | } else { |
15121 | return{ "{null string}" }; |
15122 | } |
15123 | } |
15124 | |
15125 | #ifdef CATCH_CONFIG_WCHAR |
15126 | std::string StringMaker<std::wstring>::convert(const std::wstring& wstr) { |
15127 | std::string s; |
15128 | s.reserve(wstr.size()); |
15129 | for (auto c : wstr) { |
15130 | s += (c <= 0xff) ? static_cast<char>(c) : '?'; |
15131 | } |
15132 | return ::Catch::Detail::stringify(s); |
15133 | } |
15134 | |
15135 | # ifdef CATCH_CONFIG_CPP17_STRING_VIEW |
15136 | std::string StringMaker<std::wstring_view>::convert(std::wstring_view str) { |
15137 | return StringMaker<std::wstring>::convert(std::wstring(str)); |
15138 | } |
15139 | # endif |
15140 | |
15141 | std::string StringMaker<wchar_t const*>::convert(wchar_t const * str) { |
15142 | if (str) { |
15143 | return ::Catch::Detail::stringify(std::wstring{ str }); |
15144 | } else { |
15145 | return{ "{null string}" }; |
15146 | } |
15147 | } |
15148 | std::string StringMaker<wchar_t *>::convert(wchar_t * str) { |
15149 | if (str) { |
15150 | return ::Catch::Detail::stringify(std::wstring{ str }); |
15151 | } else { |
15152 | return{ "{null string}" }; |
15153 | } |
15154 | } |
15155 | #endif |
15156 | |
15157 | #if defined(CATCH_CONFIG_CPP17_BYTE) |
15158 | #include <cstddef> |
15159 | std::string StringMaker<std::byte>::convert(std::byte value) { |
15160 | return ::Catch::Detail::stringify(std::to_integer<unsigned long long>(value)); |
15161 | } |
15162 | #endif // defined(CATCH_CONFIG_CPP17_BYTE) |
15163 | |
15164 | std::string StringMaker<int>::convert(int value) { |
15165 | return ::Catch::Detail::stringify(static_cast<long long>(value)); |
15166 | } |
15167 | std::string StringMaker<long>::convert(long value) { |
15168 | return ::Catch::Detail::stringify(static_cast<long long>(value)); |
15169 | } |
15170 | std::string StringMaker<long long>::convert(long long value) { |
15171 | ReusableStringStream rss; |
15172 | rss << value; |
15173 | if (value > Detail::hexThreshold) { |
15174 | rss << " (0x" << std::hex << value << ')'; |
15175 | } |
15176 | return rss.str(); |
15177 | } |
15178 | |
15179 | std::string StringMaker<unsigned int>::convert(unsigned int value) { |
15180 | return ::Catch::Detail::stringify(static_cast<unsigned long long>(value)); |
15181 | } |
15182 | std::string StringMaker<unsigned long>::convert(unsigned long value) { |
15183 | return ::Catch::Detail::stringify(static_cast<unsigned long long>(value)); |
15184 | } |
15185 | std::string StringMaker<unsigned long long>::convert(unsigned long long value) { |
15186 | ReusableStringStream rss; |
15187 | rss << value; |
15188 | if (value > Detail::hexThreshold) { |
15189 | rss << " (0x" << std::hex << value << ')'; |
15190 | } |
15191 | return rss.str(); |
15192 | } |
15193 | |
15194 | std::string StringMaker<bool>::convert(bool b) { |
15195 | return b ? "true" : "false" ; |
15196 | } |
15197 | |
15198 | std::string StringMaker<signed char>::convert(signed char value) { |
15199 | if (value == '\r') { |
15200 | return "'\\r'" ; |
15201 | } else if (value == '\f') { |
15202 | return "'\\f'" ; |
15203 | } else if (value == '\n') { |
15204 | return "'\\n'" ; |
15205 | } else if (value == '\t') { |
15206 | return "'\\t'" ; |
15207 | } else if ('\0' <= value && value < ' ') { |
15208 | return ::Catch::Detail::stringify(static_cast<unsigned int>(value)); |
15209 | } else { |
15210 | char chstr[] = "' '" ; |
15211 | chstr[1] = value; |
15212 | return chstr; |
15213 | } |
15214 | } |
15215 | std::string StringMaker<char>::convert(char c) { |
15216 | return ::Catch::Detail::stringify(static_cast<signed char>(c)); |
15217 | } |
15218 | std::string StringMaker<unsigned char>::convert(unsigned char c) { |
15219 | return ::Catch::Detail::stringify(static_cast<char>(c)); |
15220 | } |
15221 | |
15222 | std::string StringMaker<std::nullptr_t>::convert(std::nullptr_t) { |
15223 | return "nullptr" ; |
15224 | } |
15225 | |
15226 | int StringMaker<float>::precision = 5; |
15227 | |
15228 | std::string StringMaker<float>::convert(float value) { |
15229 | return fpToString(value, precision) + 'f'; |
15230 | } |
15231 | |
15232 | int StringMaker<double>::precision = 10; |
15233 | |
15234 | std::string StringMaker<double>::convert(double value) { |
15235 | return fpToString(value, precision); |
15236 | } |
15237 | |
15238 | std::string ratio_string<std::atto>::symbol() { return "a" ; } |
15239 | std::string ratio_string<std::femto>::symbol() { return "f" ; } |
15240 | std::string ratio_string<std::pico>::symbol() { return "p" ; } |
15241 | std::string ratio_string<std::nano>::symbol() { return "n" ; } |
15242 | std::string ratio_string<std::micro>::symbol() { return "u" ; } |
15243 | std::string ratio_string<std::milli>::symbol() { return "m" ; } |
15244 | |
15245 | } // end namespace Catch |
15246 | |
15247 | #if defined(__clang__) |
15248 | # pragma clang diagnostic pop |
15249 | #endif |
15250 | |
15251 | // end catch_tostring.cpp |
15252 | // start catch_totals.cpp |
15253 | |
15254 | namespace Catch { |
15255 | |
15256 | Counts Counts::operator - ( Counts const& other ) const { |
15257 | Counts diff; |
15258 | diff.passed = passed - other.passed; |
15259 | diff.failed = failed - other.failed; |
15260 | diff.failedButOk = failedButOk - other.failedButOk; |
15261 | return diff; |
15262 | } |
15263 | |
15264 | Counts& Counts::operator += ( Counts const& other ) { |
15265 | passed += other.passed; |
15266 | failed += other.failed; |
15267 | failedButOk += other.failedButOk; |
15268 | return *this; |
15269 | } |
15270 | |
15271 | std::size_t Counts::total() const { |
15272 | return passed + failed + failedButOk; |
15273 | } |
15274 | bool Counts::allPassed() const { |
15275 | return failed == 0 && failedButOk == 0; |
15276 | } |
15277 | bool Counts::allOk() const { |
15278 | return failed == 0; |
15279 | } |
15280 | |
15281 | Totals Totals::operator - ( Totals const& other ) const { |
15282 | Totals diff; |
15283 | diff.assertions = assertions - other.assertions; |
15284 | diff.testCases = testCases - other.testCases; |
15285 | return diff; |
15286 | } |
15287 | |
15288 | Totals& Totals::operator += ( Totals const& other ) { |
15289 | assertions += other.assertions; |
15290 | testCases += other.testCases; |
15291 | return *this; |
15292 | } |
15293 | |
15294 | Totals Totals::delta( Totals const& prevTotals ) const { |
15295 | Totals diff = *this - prevTotals; |
15296 | if( diff.assertions.failed > 0 ) |
15297 | ++diff.testCases.failed; |
15298 | else if( diff.assertions.failedButOk > 0 ) |
15299 | ++diff.testCases.failedButOk; |
15300 | else |
15301 | ++diff.testCases.passed; |
15302 | return diff; |
15303 | } |
15304 | |
15305 | } |
15306 | // end catch_totals.cpp |
15307 | // start catch_uncaught_exceptions.cpp |
15308 | |
15309 | // start catch_config_uncaught_exceptions.hpp |
15310 | |
15311 | // Copyright Catch2 Authors |
15312 | // Distributed under the Boost Software License, Version 1.0. |
15313 | // (See accompanying file LICENSE_1_0.txt or copy at |
15314 | // https://www.boost.org/LICENSE_1_0.txt) |
15315 | |
15316 | // SPDX-License-Identifier: BSL-1.0 |
15317 | |
15318 | #ifndef CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP |
15319 | #define CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP |
15320 | |
15321 | #if defined(_MSC_VER) |
15322 | # if _MSC_VER >= 1900 // Visual Studio 2015 or newer |
15323 | # define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS |
15324 | # endif |
15325 | #endif |
15326 | |
15327 | #include <exception> |
15328 | |
15329 | #if defined(__cpp_lib_uncaught_exceptions) \ |
15330 | && !defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) |
15331 | |
15332 | # define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS |
15333 | #endif // __cpp_lib_uncaught_exceptions |
15334 | |
15335 | #if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) \ |
15336 | && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) \ |
15337 | && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) |
15338 | |
15339 | # define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS |
15340 | #endif |
15341 | |
15342 | #endif // CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP |
15343 | // end catch_config_uncaught_exceptions.hpp |
15344 | #include <exception> |
15345 | |
15346 | namespace Catch { |
15347 | bool uncaught_exceptions() { |
15348 | #if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) |
15349 | return false; |
15350 | #elif defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) |
15351 | return std::uncaught_exceptions() > 0; |
15352 | #else |
15353 | return std::uncaught_exception(); |
15354 | #endif |
15355 | } |
15356 | } // end namespace Catch |
15357 | // end catch_uncaught_exceptions.cpp |
15358 | // start catch_version.cpp |
15359 | |
15360 | #include <ostream> |
15361 | |
15362 | namespace Catch { |
15363 | |
15364 | Version::Version |
15365 | ( unsigned int _majorVersion, |
15366 | unsigned int _minorVersion, |
15367 | unsigned int _patchNumber, |
15368 | char const * const _branchName, |
15369 | unsigned int _buildNumber ) |
15370 | : majorVersion( _majorVersion ), |
15371 | minorVersion( _minorVersion ), |
15372 | patchNumber( _patchNumber ), |
15373 | branchName( _branchName ), |
15374 | buildNumber( _buildNumber ) |
15375 | {} |
15376 | |
15377 | std::ostream& operator << ( std::ostream& os, Version const& version ) { |
15378 | os << version.majorVersion << '.' |
15379 | << version.minorVersion << '.' |
15380 | << version.patchNumber; |
15381 | // branchName is never null -> 0th char is \0 if it is empty |
15382 | if (version.branchName[0]) { |
15383 | os << '-' << version.branchName |
15384 | << '.' << version.buildNumber; |
15385 | } |
15386 | return os; |
15387 | } |
15388 | |
15389 | Version const& libraryVersion() { |
15390 | static Version version( 2, 13, 8, "" , 0 ); |
15391 | return version; |
15392 | } |
15393 | |
15394 | } |
15395 | // end catch_version.cpp |
15396 | // start catch_wildcard_pattern.cpp |
15397 | |
15398 | namespace Catch { |
15399 | |
15400 | WildcardPattern::WildcardPattern( std::string const& pattern, |
15401 | CaseSensitive::Choice caseSensitivity ) |
15402 | : m_caseSensitivity( caseSensitivity ), |
15403 | m_pattern( normaliseString( pattern ) ) |
15404 | { |
15405 | if( startsWith( m_pattern, '*' ) ) { |
15406 | m_pattern = m_pattern.substr( 1 ); |
15407 | m_wildcard = WildcardAtStart; |
15408 | } |
15409 | if( endsWith( m_pattern, '*' ) ) { |
15410 | m_pattern = m_pattern.substr( 0, m_pattern.size()-1 ); |
15411 | m_wildcard = static_cast<WildcardPosition>( m_wildcard | WildcardAtEnd ); |
15412 | } |
15413 | } |
15414 | |
15415 | bool WildcardPattern::matches( std::string const& str ) const { |
15416 | switch( m_wildcard ) { |
15417 | case NoWildcard: |
15418 | return m_pattern == normaliseString( str ); |
15419 | case WildcardAtStart: |
15420 | return endsWith( normaliseString( str ), m_pattern ); |
15421 | case WildcardAtEnd: |
15422 | return startsWith( normaliseString( str ), m_pattern ); |
15423 | case WildcardAtBothEnds: |
15424 | return contains( normaliseString( str ), m_pattern ); |
15425 | default: |
15426 | CATCH_INTERNAL_ERROR( "Unknown enum" ); |
15427 | } |
15428 | } |
15429 | |
15430 | std::string WildcardPattern::normaliseString( std::string const& str ) const { |
15431 | return trim( m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str ); |
15432 | } |
15433 | } |
15434 | // end catch_wildcard_pattern.cpp |
15435 | // start catch_xmlwriter.cpp |
15436 | |
15437 | #include <iomanip> |
15438 | #include <type_traits> |
15439 | |
15440 | namespace Catch { |
15441 | |
15442 | namespace { |
15443 | |
15444 | size_t trailingBytes(unsigned char c) { |
15445 | if ((c & 0xE0) == 0xC0) { |
15446 | return 2; |
15447 | } |
15448 | if ((c & 0xF0) == 0xE0) { |
15449 | return 3; |
15450 | } |
15451 | if ((c & 0xF8) == 0xF0) { |
15452 | return 4; |
15453 | } |
15454 | CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered" ); |
15455 | } |
15456 | |
15457 | uint32_t headerValue(unsigned char c) { |
15458 | if ((c & 0xE0) == 0xC0) { |
15459 | return c & 0x1F; |
15460 | } |
15461 | if ((c & 0xF0) == 0xE0) { |
15462 | return c & 0x0F; |
15463 | } |
15464 | if ((c & 0xF8) == 0xF0) { |
15465 | return c & 0x07; |
15466 | } |
15467 | CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered" ); |
15468 | } |
15469 | |
15470 | void hexEscapeChar(std::ostream& os, unsigned char c) { |
15471 | std::ios_base::fmtflags f(os.flags()); |
15472 | os << "\\x" |
15473 | << std::uppercase << std::hex << std::setfill('0') << std::setw(2) |
15474 | << static_cast<int>(c); |
15475 | os.flags(f); |
15476 | } |
15477 | |
15478 | bool shouldNewline(XmlFormatting fmt) { |
15479 | return !!(static_cast<std::underlying_type<XmlFormatting>::type>(fmt & XmlFormatting::Newline)); |
15480 | } |
15481 | |
15482 | bool shouldIndent(XmlFormatting fmt) { |
15483 | return !!(static_cast<std::underlying_type<XmlFormatting>::type>(fmt & XmlFormatting::Indent)); |
15484 | } |
15485 | |
15486 | } // anonymous namespace |
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 | XmlFormatting operator & (XmlFormatting lhs, XmlFormatting rhs) { |
15496 | return static_cast<XmlFormatting>( |
15497 | static_cast<std::underlying_type<XmlFormatting>::type>(lhs) & |
15498 | static_cast<std::underlying_type<XmlFormatting>::type>(rhs) |
15499 | ); |
15500 | } |
15501 | |
15502 | XmlEncode::XmlEncode( std::string const& str, ForWhat forWhat ) |
15503 | : m_str( str ), |
15504 | m_forWhat( forWhat ) |
15505 | {} |
15506 | |
15507 | void XmlEncode::encodeTo( std::ostream& os ) const { |
15508 | // Apostrophe escaping not necessary if we always use " to write attributes |
15509 | // (see: http://www.w3.org/TR/xml/#syntax) |
15510 | |
15511 | for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) { |
15512 | unsigned char c = m_str[idx]; |
15513 | switch (c) { |
15514 | case '<': os << "<" ; break; |
15515 | case '&': os << "&" ; break; |
15516 | |
15517 | case '>': |
15518 | // See: http://www.w3.org/TR/xml/#syntax |
15519 | if (idx > 2 && m_str[idx - 1] == ']' && m_str[idx - 2] == ']') |
15520 | os << ">" ; |
15521 | else |
15522 | os << c; |
15523 | break; |
15524 | |
15525 | case '\"': |
15526 | if (m_forWhat == ForAttributes) |
15527 | os << """ ; |
15528 | else |
15529 | os << c; |
15530 | break; |
15531 | |
15532 | default: |
15533 | // Check for control characters and invalid utf-8 |
15534 | |
15535 | // Escape control characters in standard ascii |
15536 | // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0 |
15537 | if (c < 0x09 || (c > 0x0D && c < 0x20) || c == 0x7F) { |
15538 | hexEscapeChar(os, c); |
15539 | break; |
15540 | } |
15541 | |
15542 | // Plain ASCII: Write it to stream |
15543 | if (c < 0x7F) { |
15544 | os << c; |
15545 | break; |
15546 | } |
15547 | |
15548 | // UTF-8 territory |
15549 | // Check if the encoding is valid and if it is not, hex escape bytes. |
15550 | // Important: We do not check the exact decoded values for validity, only the encoding format |
15551 | // First check that this bytes is a valid lead byte: |
15552 | // This means that it is not encoded as 1111 1XXX |
15553 | // Or as 10XX XXXX |
15554 | if (c < 0xC0 || |
15555 | c >= 0xF8) { |
15556 | hexEscapeChar(os, c); |
15557 | break; |
15558 | } |
15559 | |
15560 | auto encBytes = trailingBytes(c); |
15561 | // Are there enough bytes left to avoid accessing out-of-bounds memory? |
15562 | if (idx + encBytes - 1 >= m_str.size()) { |
15563 | hexEscapeChar(os, c); |
15564 | break; |
15565 | } |
15566 | // The header is valid, check data |
15567 | // The next encBytes bytes must together be a valid utf-8 |
15568 | // This means: bitpattern 10XX XXXX and the extracted value is sane (ish) |
15569 | bool valid = true; |
15570 | uint32_t value = headerValue(c); |
15571 | for (std::size_t n = 1; n < encBytes; ++n) { |
15572 | unsigned char nc = m_str[idx + n]; |
15573 | valid &= ((nc & 0xC0) == 0x80); |
15574 | value = (value << 6) | (nc & 0x3F); |
15575 | } |
15576 | |
15577 | if ( |
15578 | // Wrong bit pattern of following bytes |
15579 | (!valid) || |
15580 | // Overlong encodings |
15581 | (value < 0x80) || |
15582 | (0x80 <= value && value < 0x800 && encBytes > 2) || |
15583 | (0x800 < value && value < 0x10000 && encBytes > 3) || |
15584 | // Encoded value out of range |
15585 | (value >= 0x110000) |
15586 | ) { |
15587 | hexEscapeChar(os, c); |
15588 | break; |
15589 | } |
15590 | |
15591 | // If we got here, this is in fact a valid(ish) utf-8 sequence |
15592 | for (std::size_t n = 0; n < encBytes; ++n) { |
15593 | os << m_str[idx + n]; |
15594 | } |
15595 | idx += encBytes - 1; |
15596 | break; |
15597 | } |
15598 | } |
15599 | } |
15600 | |
15601 | std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { |
15602 | xmlEncode.encodeTo( os ); |
15603 | return os; |
15604 | } |
15605 | |
15606 | XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer, XmlFormatting fmt ) |
15607 | : m_writer( writer ), |
15608 | m_fmt(fmt) |
15609 | {} |
15610 | |
15611 | XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) noexcept |
15612 | : m_writer( other.m_writer ), |
15613 | m_fmt(other.m_fmt) |
15614 | { |
15615 | other.m_writer = nullptr; |
15616 | other.m_fmt = XmlFormatting::None; |
15617 | } |
15618 | XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) noexcept { |
15619 | if ( m_writer ) { |
15620 | m_writer->endElement(); |
15621 | } |
15622 | m_writer = other.m_writer; |
15623 | other.m_writer = nullptr; |
15624 | m_fmt = other.m_fmt; |
15625 | other.m_fmt = XmlFormatting::None; |
15626 | return *this; |
15627 | } |
15628 | |
15629 | XmlWriter::ScopedElement::~ScopedElement() { |
15630 | if (m_writer) { |
15631 | m_writer->endElement(m_fmt); |
15632 | } |
15633 | } |
15634 | |
15635 | XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, XmlFormatting fmt ) { |
15636 | m_writer->writeText( text, fmt ); |
15637 | return *this; |
15638 | } |
15639 | |
15640 | XmlWriter::XmlWriter( std::ostream& os ) : m_os( os ) |
15641 | { |
15642 | writeDeclaration(); |
15643 | } |
15644 | |
15645 | XmlWriter::~XmlWriter() { |
15646 | while (!m_tags.empty()) { |
15647 | endElement(); |
15648 | } |
15649 | newlineIfNecessary(); |
15650 | } |
15651 | |
15652 | XmlWriter& XmlWriter::startElement( std::string const& name, XmlFormatting fmt ) { |
15653 | ensureTagClosed(); |
15654 | newlineIfNecessary(); |
15655 | if (shouldIndent(fmt)) { |
15656 | m_os << m_indent; |
15657 | m_indent += " " ; |
15658 | } |
15659 | m_os << '<' << name; |
15660 | m_tags.push_back( name ); |
15661 | m_tagIsOpen = true; |
15662 | applyFormatting(fmt); |
15663 | return *this; |
15664 | } |
15665 | |
15666 | XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name, XmlFormatting fmt ) { |
15667 | ScopedElement scoped( this, fmt ); |
15668 | startElement( name, fmt ); |
15669 | return scoped; |
15670 | } |
15671 | |
15672 | XmlWriter& XmlWriter::endElement(XmlFormatting fmt) { |
15673 | m_indent = m_indent.substr(0, m_indent.size() - 2); |
15674 | |
15675 | if( m_tagIsOpen ) { |
15676 | m_os << "/>" ; |
15677 | m_tagIsOpen = false; |
15678 | } else { |
15679 | newlineIfNecessary(); |
15680 | if (shouldIndent(fmt)) { |
15681 | m_os << m_indent; |
15682 | } |
15683 | m_os << "</" << m_tags.back() << ">" ; |
15684 | } |
15685 | m_os << std::flush; |
15686 | applyFormatting(fmt); |
15687 | m_tags.pop_back(); |
15688 | return *this; |
15689 | } |
15690 | |
15691 | XmlWriter& XmlWriter::writeAttribute( std::string const& name, std::string const& attribute ) { |
15692 | if( !name.empty() && !attribute.empty() ) |
15693 | m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"'; |
15694 | return *this; |
15695 | } |
15696 | |
15697 | XmlWriter& XmlWriter::writeAttribute( std::string const& name, bool attribute ) { |
15698 | m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"'; |
15699 | return *this; |
15700 | } |
15701 | |
15702 | XmlWriter& XmlWriter::writeText( std::string const& text, XmlFormatting fmt) { |
15703 | if( !text.empty() ){ |
15704 | bool tagWasOpen = m_tagIsOpen; |
15705 | ensureTagClosed(); |
15706 | if (tagWasOpen && shouldIndent(fmt)) { |
15707 | m_os << m_indent; |
15708 | } |
15709 | m_os << XmlEncode( text ); |
15710 | applyFormatting(fmt); |
15711 | } |
15712 | return *this; |
15713 | } |
15714 | |
15715 | XmlWriter& XmlWriter::writeComment( std::string const& text, XmlFormatting fmt) { |
15716 | ensureTagClosed(); |
15717 | if (shouldIndent(fmt)) { |
15718 | m_os << m_indent; |
15719 | } |
15720 | m_os << "<!--" << text << "-->" ; |
15721 | applyFormatting(fmt); |
15722 | return *this; |
15723 | } |
15724 | |
15725 | void XmlWriter::writeStylesheetRef( std::string const& url ) { |
15726 | m_os << "<?xml-stylesheet type=\"text/xsl\" href=\"" << url << "\"?>\n" ; |
15727 | } |
15728 | |
15729 | XmlWriter& XmlWriter::writeBlankLine() { |
15730 | ensureTagClosed(); |
15731 | m_os << '\n'; |
15732 | return *this; |
15733 | } |
15734 | |
15735 | void XmlWriter::ensureTagClosed() { |
15736 | if( m_tagIsOpen ) { |
15737 | m_os << '>' << std::flush; |
15738 | newlineIfNecessary(); |
15739 | m_tagIsOpen = false; |
15740 | } |
15741 | } |
15742 | |
15743 | void XmlWriter::applyFormatting(XmlFormatting fmt) { |
15744 | m_needsNewline = shouldNewline(fmt); |
15745 | } |
15746 | |
15747 | void XmlWriter::writeDeclaration() { |
15748 | m_os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ; |
15749 | } |
15750 | |
15751 | void XmlWriter::newlineIfNecessary() { |
15752 | if( m_needsNewline ) { |
15753 | m_os << std::endl; |
15754 | m_needsNewline = false; |
15755 | } |
15756 | } |
15757 | } |
15758 | // end catch_xmlwriter.cpp |
15759 | // start catch_reporter_bases.cpp |
15760 | |
15761 | #include <cstring> |
15762 | #include <cfloat> |
15763 | #include <cstdio> |
15764 | #include <cassert> |
15765 | #include <memory> |
15766 | |
15767 | namespace Catch { |
15768 | void prepareExpandedExpression(AssertionResult& result) { |
15769 | result.getExpandedExpression(); |
15770 | } |
15771 | |
15772 | // Because formatting using c++ streams is stateful, drop down to C is required |
15773 | // Alternatively we could use stringstream, but its performance is... not good. |
15774 | std::string getFormattedDuration( double duration ) { |
15775 | // Max exponent + 1 is required to represent the whole part |
15776 | // + 1 for decimal point |
15777 | // + 3 for the 3 decimal places |
15778 | // + 1 for null terminator |
15779 | const std::size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1; |
15780 | char buffer[maxDoubleSize]; |
15781 | |
15782 | // Save previous errno, to prevent sprintf from overwriting it |
15783 | ErrnoGuard guard; |
15784 | #ifdef _MSC_VER |
15785 | sprintf_s(buffer, "%.3f" , duration); |
15786 | #else |
15787 | std::sprintf(buffer, "%.3f" , duration); |
15788 | #endif |
15789 | return std::string(buffer); |
15790 | } |
15791 | |
15792 | bool shouldShowDuration( IConfig const& config, double duration ) { |
15793 | if ( config.showDurations() == ShowDurations::Always ) { |
15794 | return true; |
15795 | } |
15796 | if ( config.showDurations() == ShowDurations::Never ) { |
15797 | return false; |
15798 | } |
15799 | const double min = config.minDuration(); |
15800 | return min >= 0 && duration >= min; |
15801 | } |
15802 | |
15803 | std::string serializeFilters( std::vector<std::string> const& container ) { |
15804 | ReusableStringStream oss; |
15805 | bool first = true; |
15806 | for (auto&& filter : container) |
15807 | { |
15808 | if (!first) |
15809 | oss << ' '; |
15810 | else |
15811 | first = false; |
15812 | |
15813 | oss << filter; |
15814 | } |
15815 | return oss.str(); |
15816 | } |
15817 | |
15818 | TestEventListenerBase::TestEventListenerBase(ReporterConfig const & _config) |
15819 | :StreamingReporterBase(_config) {} |
15820 | |
15821 | std::set<Verbosity> TestEventListenerBase::getSupportedVerbosities() { |
15822 | return { Verbosity::Quiet, Verbosity::Normal, Verbosity::High }; |
15823 | } |
15824 | |
15825 | void TestEventListenerBase::assertionStarting(AssertionInfo const &) {} |
15826 | |
15827 | bool TestEventListenerBase::assertionEnded(AssertionStats const &) { |
15828 | return false; |
15829 | } |
15830 | |
15831 | } // end namespace Catch |
15832 | // end catch_reporter_bases.cpp |
15833 | // start catch_reporter_compact.cpp |
15834 | |
15835 | namespace { |
15836 | |
15837 | #ifdef CATCH_PLATFORM_MAC |
15838 | const char* failedString() { return "FAILED" ; } |
15839 | const char* passedString() { return "PASSED" ; } |
15840 | #else |
15841 | const char* failedString() { return "failed" ; } |
15842 | const char* passedString() { return "passed" ; } |
15843 | #endif |
15844 | |
15845 | // Colour::LightGrey |
15846 | Catch::Colour::Code dimColour() { return Catch::Colour::FileName; } |
15847 | |
15848 | std::string bothOrAll( std::size_t count ) { |
15849 | return count == 1 ? std::string() : |
15850 | count == 2 ? "both " : "all " ; |
15851 | } |
15852 | |
15853 | } // anon namespace |
15854 | |
15855 | namespace Catch { |
15856 | namespace { |
15857 | // Colour, message variants: |
15858 | // - white: No tests ran. |
15859 | // - red: Failed [both/all] N test cases, failed [both/all] M assertions. |
15860 | // - white: Passed [both/all] N test cases (no assertions). |
15861 | // - red: Failed N tests cases, failed M assertions. |
15862 | // - green: Passed [both/all] N tests cases with M assertions. |
15863 | void printTotals(std::ostream& out, const Totals& totals) { |
15864 | if (totals.testCases.total() == 0) { |
15865 | out << "No tests ran." ; |
15866 | } else if (totals.testCases.failed == totals.testCases.total()) { |
15867 | Colour colour(Colour::ResultError); |
15868 | const std::string qualify_assertions_failed = |
15869 | totals.assertions.failed == totals.assertions.total() ? |
15870 | bothOrAll(totals.assertions.failed) : std::string(); |
15871 | out << |
15872 | "Failed " << bothOrAll(totals.testCases.failed) |
15873 | << pluralise(totals.testCases.failed, "test case" ) << ", " |
15874 | "failed " << qualify_assertions_failed << |
15875 | pluralise(totals.assertions.failed, "assertion" ) << '.'; |
15876 | } else if (totals.assertions.total() == 0) { |
15877 | out << |
15878 | "Passed " << bothOrAll(totals.testCases.total()) |
15879 | << pluralise(totals.testCases.total(), "test case" ) |
15880 | << " (no assertions)." ; |
15881 | } else if (totals.assertions.failed) { |
15882 | Colour colour(Colour::ResultError); |
15883 | out << |
15884 | "Failed " << pluralise(totals.testCases.failed, "test case" ) << ", " |
15885 | "failed " << pluralise(totals.assertions.failed, "assertion" ) << '.'; |
15886 | } else { |
15887 | Colour colour(Colour::ResultSuccess); |
15888 | out << |
15889 | "Passed " << bothOrAll(totals.testCases.passed) |
15890 | << pluralise(totals.testCases.passed, "test case" ) << |
15891 | " with " << pluralise(totals.assertions.passed, "assertion" ) << '.'; |
15892 | } |
15893 | } |
15894 | |
15895 | // Implementation of CompactReporter formatting |
15896 | class AssertionPrinter { |
15897 | public: |
15898 | AssertionPrinter& operator= (AssertionPrinter const&) = delete; |
15899 | AssertionPrinter(AssertionPrinter const&) = delete; |
15900 | AssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages) |
15901 | : stream(_stream) |
15902 | , result(_stats.assertionResult) |
15903 | , messages(_stats.infoMessages) |
15904 | , itMessage(_stats.infoMessages.begin()) |
15905 | , printInfoMessages(_printInfoMessages) {} |
15906 | |
15907 | void print() { |
15908 | printSourceInfo(); |
15909 | |
15910 | itMessage = messages.begin(); |
15911 | |
15912 | switch (result.getResultType()) { |
15913 | case ResultWas::Ok: |
15914 | printResultType(Colour::ResultSuccess, passedString()); |
15915 | printOriginalExpression(); |
15916 | printReconstructedExpression(); |
15917 | if (!result.hasExpression()) |
15918 | printRemainingMessages(Colour::None); |
15919 | else |
15920 | printRemainingMessages(); |
15921 | break; |
15922 | case ResultWas::ExpressionFailed: |
15923 | if (result.isOk()) |
15924 | printResultType(Colour::ResultSuccess, failedString() + std::string(" - but was ok" )); |
15925 | else |
15926 | printResultType(Colour::Error, failedString()); |
15927 | printOriginalExpression(); |
15928 | printReconstructedExpression(); |
15929 | printRemainingMessages(); |
15930 | break; |
15931 | case ResultWas::ThrewException: |
15932 | printResultType(Colour::Error, failedString()); |
15933 | printIssue("unexpected exception with message:" ); |
15934 | printMessage(); |
15935 | printExpressionWas(); |
15936 | printRemainingMessages(); |
15937 | break; |
15938 | case ResultWas::FatalErrorCondition: |
15939 | printResultType(Colour::Error, failedString()); |
15940 | printIssue("fatal error condition with message:" ); |
15941 | printMessage(); |
15942 | printExpressionWas(); |
15943 | printRemainingMessages(); |
15944 | break; |
15945 | case ResultWas::DidntThrowException: |
15946 | printResultType(Colour::Error, failedString()); |
15947 | printIssue("expected exception, got none" ); |
15948 | printExpressionWas(); |
15949 | printRemainingMessages(); |
15950 | break; |
15951 | case ResultWas::Info: |
15952 | printResultType(Colour::None, "info" ); |
15953 | printMessage(); |
15954 | printRemainingMessages(); |
15955 | break; |
15956 | case ResultWas::Warning: |
15957 | printResultType(Colour::None, "warning" ); |
15958 | printMessage(); |
15959 | printRemainingMessages(); |
15960 | break; |
15961 | case ResultWas::ExplicitFailure: |
15962 | printResultType(Colour::Error, failedString()); |
15963 | printIssue("explicitly" ); |
15964 | printRemainingMessages(Colour::None); |
15965 | break; |
15966 | // These cases are here to prevent compiler warnings |
15967 | case ResultWas::Unknown: |
15968 | case ResultWas::FailureBit: |
15969 | case ResultWas::Exception: |
15970 | printResultType(Colour::Error, "** internal error **" ); |
15971 | break; |
15972 | } |
15973 | } |
15974 | |
15975 | private: |
15976 | void printSourceInfo() const { |
15977 | Colour colourGuard(Colour::FileName); |
15978 | stream << result.getSourceInfo() << ':'; |
15979 | } |
15980 | |
15981 | void printResultType(Colour::Code colour, std::string const& passOrFail) const { |
15982 | if (!passOrFail.empty()) { |
15983 | { |
15984 | Colour colourGuard(colour); |
15985 | stream << ' ' << passOrFail; |
15986 | } |
15987 | stream << ':'; |
15988 | } |
15989 | } |
15990 | |
15991 | void printIssue(std::string const& issue) const { |
15992 | stream << ' ' << issue; |
15993 | } |
15994 | |
15995 | void printExpressionWas() { |
15996 | if (result.hasExpression()) { |
15997 | stream << ';'; |
15998 | { |
15999 | Colour colour(dimColour()); |
16000 | stream << " expression was:" ; |
16001 | } |
16002 | printOriginalExpression(); |
16003 | } |
16004 | } |
16005 | |
16006 | void printOriginalExpression() const { |
16007 | if (result.hasExpression()) { |
16008 | stream << ' ' << result.getExpression(); |
16009 | } |
16010 | } |
16011 | |
16012 | void printReconstructedExpression() const { |
16013 | if (result.hasExpandedExpression()) { |
16014 | { |
16015 | Colour colour(dimColour()); |
16016 | stream << " for: " ; |
16017 | } |
16018 | stream << result.getExpandedExpression(); |
16019 | } |
16020 | } |
16021 | |
16022 | void printMessage() { |
16023 | if (itMessage != messages.end()) { |
16024 | stream << " '" << itMessage->message << '\''; |
16025 | ++itMessage; |
16026 | } |
16027 | } |
16028 | |
16029 | void printRemainingMessages(Colour::Code colour = dimColour()) { |
16030 | if (itMessage == messages.end()) |
16031 | return; |
16032 | |
16033 | const auto itEnd = messages.cend(); |
16034 | const auto N = static_cast<std::size_t>(std::distance(itMessage, itEnd)); |
16035 | |
16036 | { |
16037 | Colour colourGuard(colour); |
16038 | stream << " with " << pluralise(N, "message" ) << ':'; |
16039 | } |
16040 | |
16041 | while (itMessage != itEnd) { |
16042 | // If this assertion is a warning ignore any INFO messages |
16043 | if (printInfoMessages || itMessage->type != ResultWas::Info) { |
16044 | printMessage(); |
16045 | if (itMessage != itEnd) { |
16046 | Colour colourGuard(dimColour()); |
16047 | stream << " and" ; |
16048 | } |
16049 | continue; |
16050 | } |
16051 | ++itMessage; |
16052 | } |
16053 | } |
16054 | |
16055 | private: |
16056 | std::ostream& stream; |
16057 | AssertionResult const& result; |
16058 | std::vector<MessageInfo> messages; |
16059 | std::vector<MessageInfo>::const_iterator itMessage; |
16060 | bool printInfoMessages; |
16061 | }; |
16062 | |
16063 | } // anon namespace |
16064 | |
16065 | std::string CompactReporter::getDescription() { |
16066 | return "Reports test results on a single line, suitable for IDEs" ; |
16067 | } |
16068 | |
16069 | void CompactReporter::noMatchingTestCases( std::string const& spec ) { |
16070 | stream << "No test cases matched '" << spec << '\'' << std::endl; |
16071 | } |
16072 | |
16073 | void CompactReporter::assertionStarting( AssertionInfo const& ) {} |
16074 | |
16075 | bool CompactReporter::assertionEnded( AssertionStats const& _assertionStats ) { |
16076 | AssertionResult const& result = _assertionStats.assertionResult; |
16077 | |
16078 | bool printInfoMessages = true; |
16079 | |
16080 | // Drop out if result was successful and we're not printing those |
16081 | if( !m_config->includeSuccessfulResults() && result.isOk() ) { |
16082 | if( result.getResultType() != ResultWas::Warning ) |
16083 | return false; |
16084 | printInfoMessages = false; |
16085 | } |
16086 | |
16087 | AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); |
16088 | printer.print(); |
16089 | |
16090 | stream << std::endl; |
16091 | return true; |
16092 | } |
16093 | |
16094 | void CompactReporter::sectionEnded(SectionStats const& _sectionStats) { |
16095 | double dur = _sectionStats.durationInSeconds; |
16096 | if ( shouldShowDuration( *m_config, dur ) ) { |
16097 | stream << getFormattedDuration( dur ) << " s: " << _sectionStats.sectionInfo.name << std::endl; |
16098 | } |
16099 | } |
16100 | |
16101 | void CompactReporter::testRunEnded( TestRunStats const& _testRunStats ) { |
16102 | printTotals( stream, _testRunStats.totals ); |
16103 | stream << '\n' << std::endl; |
16104 | StreamingReporterBase::testRunEnded( _testRunStats ); |
16105 | } |
16106 | |
16107 | CompactReporter::~CompactReporter() {} |
16108 | |
16109 | CATCH_REGISTER_REPORTER( "compact" , CompactReporter ) |
16110 | |
16111 | } // end namespace Catch |
16112 | // end catch_reporter_compact.cpp |
16113 | // start catch_reporter_console.cpp |
16114 | |
16115 | #include <cfloat> |
16116 | #include <cstdio> |
16117 | |
16118 | #if defined(_MSC_VER) |
16119 | #pragma warning(push) |
16120 | #pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch |
16121 | // Note that 4062 (not all labels are handled and default is missing) is enabled |
16122 | #endif |
16123 | |
16124 | #if defined(__clang__) |
16125 | # pragma clang diagnostic push |
16126 | // For simplicity, benchmarking-only helpers are always enabled |
16127 | # pragma clang diagnostic ignored "-Wunused-function" |
16128 | #endif |
16129 | |
16130 | namespace Catch { |
16131 | |
16132 | namespace { |
16133 | |
16134 | // Formatter impl for ConsoleReporter |
16135 | class ConsoleAssertionPrinter { |
16136 | public: |
16137 | ConsoleAssertionPrinter& operator= (ConsoleAssertionPrinter const&) = delete; |
16138 | ConsoleAssertionPrinter(ConsoleAssertionPrinter const&) = delete; |
16139 | ConsoleAssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages) |
16140 | : stream(_stream), |
16141 | stats(_stats), |
16142 | result(_stats.assertionResult), |
16143 | colour(Colour::None), |
16144 | message(result.getMessage()), |
16145 | messages(_stats.infoMessages), |
16146 | printInfoMessages(_printInfoMessages) { |
16147 | switch (result.getResultType()) { |
16148 | case ResultWas::Ok: |
16149 | colour = Colour::Success; |
16150 | passOrFail = "PASSED" ; |
16151 | //if( result.hasMessage() ) |
16152 | if (_stats.infoMessages.size() == 1) |
16153 | messageLabel = "with message" ; |
16154 | if (_stats.infoMessages.size() > 1) |
16155 | messageLabel = "with messages" ; |
16156 | break; |
16157 | case ResultWas::ExpressionFailed: |
16158 | if (result.isOk()) { |
16159 | colour = Colour::Success; |
16160 | passOrFail = "FAILED - but was ok" ; |
16161 | } else { |
16162 | colour = Colour::Error; |
16163 | passOrFail = "FAILED" ; |
16164 | } |
16165 | if (_stats.infoMessages.size() == 1) |
16166 | messageLabel = "with message" ; |
16167 | if (_stats.infoMessages.size() > 1) |
16168 | messageLabel = "with messages" ; |
16169 | break; |
16170 | case ResultWas::ThrewException: |
16171 | colour = Colour::Error; |
16172 | passOrFail = "FAILED" ; |
16173 | messageLabel = "due to unexpected exception with " ; |
16174 | if (_stats.infoMessages.size() == 1) |
16175 | messageLabel += "message" ; |
16176 | if (_stats.infoMessages.size() > 1) |
16177 | messageLabel += "messages" ; |
16178 | break; |
16179 | case ResultWas::FatalErrorCondition: |
16180 | colour = Colour::Error; |
16181 | passOrFail = "FAILED" ; |
16182 | messageLabel = "due to a fatal error condition" ; |
16183 | break; |
16184 | case ResultWas::DidntThrowException: |
16185 | colour = Colour::Error; |
16186 | passOrFail = "FAILED" ; |
16187 | messageLabel = "because no exception was thrown where one was expected" ; |
16188 | break; |
16189 | case ResultWas::Info: |
16190 | messageLabel = "info" ; |
16191 | break; |
16192 | case ResultWas::Warning: |
16193 | messageLabel = "warning" ; |
16194 | break; |
16195 | case ResultWas::ExplicitFailure: |
16196 | passOrFail = "FAILED" ; |
16197 | colour = Colour::Error; |
16198 | if (_stats.infoMessages.size() == 1) |
16199 | messageLabel = "explicitly with message" ; |
16200 | if (_stats.infoMessages.size() > 1) |
16201 | messageLabel = "explicitly with messages" ; |
16202 | break; |
16203 | // These cases are here to prevent compiler warnings |
16204 | case ResultWas::Unknown: |
16205 | case ResultWas::FailureBit: |
16206 | case ResultWas::Exception: |
16207 | passOrFail = "** internal error **" ; |
16208 | colour = Colour::Error; |
16209 | break; |
16210 | } |
16211 | } |
16212 | |
16213 | void print() const { |
16214 | printSourceInfo(); |
16215 | if (stats.totals.assertions.total() > 0) { |
16216 | printResultType(); |
16217 | printOriginalExpression(); |
16218 | printReconstructedExpression(); |
16219 | } else { |
16220 | stream << '\n'; |
16221 | } |
16222 | printMessage(); |
16223 | } |
16224 | |
16225 | private: |
16226 | void printResultType() const { |
16227 | if (!passOrFail.empty()) { |
16228 | Colour colourGuard(colour); |
16229 | stream << passOrFail << ":\n" ; |
16230 | } |
16231 | } |
16232 | void printOriginalExpression() const { |
16233 | if (result.hasExpression()) { |
16234 | Colour colourGuard(Colour::OriginalExpression); |
16235 | stream << " " ; |
16236 | stream << result.getExpressionInMacro(); |
16237 | stream << '\n'; |
16238 | } |
16239 | } |
16240 | void printReconstructedExpression() const { |
16241 | if (result.hasExpandedExpression()) { |
16242 | stream << "with expansion:\n" ; |
16243 | Colour colourGuard(Colour::ReconstructedExpression); |
16244 | stream << Column(result.getExpandedExpression()).indent(2) << '\n'; |
16245 | } |
16246 | } |
16247 | void printMessage() const { |
16248 | if (!messageLabel.empty()) |
16249 | stream << messageLabel << ':' << '\n'; |
16250 | for (auto const& msg : messages) { |
16251 | // If this assertion is a warning ignore any INFO messages |
16252 | if (printInfoMessages || msg.type != ResultWas::Info) |
16253 | stream << Column(msg.message).indent(2) << '\n'; |
16254 | } |
16255 | } |
16256 | void printSourceInfo() const { |
16257 | Colour colourGuard(Colour::FileName); |
16258 | stream << result.getSourceInfo() << ": " ; |
16259 | } |
16260 | |
16261 | std::ostream& stream; |
16262 | AssertionStats const& stats; |
16263 | AssertionResult const& result; |
16264 | Colour::Code colour; |
16265 | std::string passOrFail; |
16266 | std::string messageLabel; |
16267 | std::string message; |
16268 | std::vector<MessageInfo> messages; |
16269 | bool printInfoMessages; |
16270 | }; |
16271 | |
16272 | std::size_t makeRatio(std::size_t number, std::size_t total) { |
16273 | std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number / total : 0; |
16274 | return (ratio == 0 && number > 0) ? 1 : ratio; |
16275 | } |
16276 | |
16277 | std::size_t& findMax(std::size_t& i, std::size_t& j, std::size_t& k) { |
16278 | if (i > j && i > k) |
16279 | return i; |
16280 | else if (j > k) |
16281 | return j; |
16282 | else |
16283 | return k; |
16284 | } |
16285 | |
16286 | struct ColumnInfo { |
16287 | enum Justification { Left, Right }; |
16288 | std::string name; |
16289 | int width; |
16290 | Justification justification; |
16291 | }; |
16292 | struct ColumnBreak {}; |
16293 | struct RowBreak {}; |
16294 | |
16295 | class Duration { |
16296 | enum class Unit { |
16297 | Auto, |
16298 | Nanoseconds, |
16299 | Microseconds, |
16300 | Milliseconds, |
16301 | Seconds, |
16302 | Minutes |
16303 | }; |
16304 | static const uint64_t s_nanosecondsInAMicrosecond = 1000; |
16305 | static const uint64_t s_nanosecondsInAMillisecond = 1000 * s_nanosecondsInAMicrosecond; |
16306 | static const uint64_t s_nanosecondsInASecond = 1000 * s_nanosecondsInAMillisecond; |
16307 | static const uint64_t s_nanosecondsInAMinute = 60 * s_nanosecondsInASecond; |
16308 | |
16309 | double m_inNanoseconds; |
16310 | Unit m_units; |
16311 | |
16312 | public: |
16313 | explicit Duration(double inNanoseconds, Unit units = Unit::Auto) |
16314 | : m_inNanoseconds(inNanoseconds), |
16315 | m_units(units) { |
16316 | if (m_units == Unit::Auto) { |
16317 | if (m_inNanoseconds < s_nanosecondsInAMicrosecond) |
16318 | m_units = Unit::Nanoseconds; |
16319 | else if (m_inNanoseconds < s_nanosecondsInAMillisecond) |
16320 | m_units = Unit::Microseconds; |
16321 | else if (m_inNanoseconds < s_nanosecondsInASecond) |
16322 | m_units = Unit::Milliseconds; |
16323 | else if (m_inNanoseconds < s_nanosecondsInAMinute) |
16324 | m_units = Unit::Seconds; |
16325 | else |
16326 | m_units = Unit::Minutes; |
16327 | } |
16328 | |
16329 | } |
16330 | |
16331 | auto value() const -> double { |
16332 | switch (m_units) { |
16333 | case Unit::Microseconds: |
16334 | return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMicrosecond); |
16335 | case Unit::Milliseconds: |
16336 | return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMillisecond); |
16337 | case Unit::Seconds: |
16338 | return m_inNanoseconds / static_cast<double>(s_nanosecondsInASecond); |
16339 | case Unit::Minutes: |
16340 | return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMinute); |
16341 | default: |
16342 | return m_inNanoseconds; |
16343 | } |
16344 | } |
16345 | auto unitsAsString() const -> std::string { |
16346 | switch (m_units) { |
16347 | case Unit::Nanoseconds: |
16348 | return "ns" ; |
16349 | case Unit::Microseconds: |
16350 | return "us" ; |
16351 | case Unit::Milliseconds: |
16352 | return "ms" ; |
16353 | case Unit::Seconds: |
16354 | return "s" ; |
16355 | case Unit::Minutes: |
16356 | return "m" ; |
16357 | default: |
16358 | return "** internal error **" ; |
16359 | } |
16360 | |
16361 | } |
16362 | friend auto operator << (std::ostream& os, Duration const& duration) -> std::ostream& { |
16363 | return os << duration.value() << ' ' << duration.unitsAsString(); |
16364 | } |
16365 | }; |
16366 | } // end anon namespace |
16367 | |
16368 | class TablePrinter { |
16369 | std::ostream& m_os; |
16370 | std::vector<ColumnInfo> m_columnInfos; |
16371 | std::ostringstream m_oss; |
16372 | int m_currentColumn = -1; |
16373 | bool m_isOpen = false; |
16374 | |
16375 | public: |
16376 | TablePrinter( std::ostream& os, std::vector<ColumnInfo> columnInfos ) |
16377 | : m_os( os ), |
16378 | m_columnInfos( std::move( columnInfos ) ) {} |
16379 | |
16380 | auto columnInfos() const -> std::vector<ColumnInfo> const& { |
16381 | return m_columnInfos; |
16382 | } |
16383 | |
16384 | void open() { |
16385 | if (!m_isOpen) { |
16386 | m_isOpen = true; |
16387 | *this << RowBreak(); |
16388 | |
16389 | Columns headerCols; |
16390 | Spacer spacer(2); |
16391 | for (auto const& info : m_columnInfos) { |
16392 | headerCols += Column(info.name).width(static_cast<std::size_t>(info.width - 2)); |
16393 | headerCols += spacer; |
16394 | } |
16395 | m_os << headerCols << '\n'; |
16396 | |
16397 | m_os << Catch::getLineOfChars<'-'>() << '\n'; |
16398 | } |
16399 | } |
16400 | void close() { |
16401 | if (m_isOpen) { |
16402 | *this << RowBreak(); |
16403 | m_os << std::endl; |
16404 | m_isOpen = false; |
16405 | } |
16406 | } |
16407 | |
16408 | template<typename T> |
16409 | friend TablePrinter& operator << (TablePrinter& tp, T const& value) { |
16410 | tp.m_oss << value; |
16411 | return tp; |
16412 | } |
16413 | |
16414 | friend TablePrinter& operator << (TablePrinter& tp, ColumnBreak) { |
16415 | auto colStr = tp.m_oss.str(); |
16416 | const auto strSize = colStr.size(); |
16417 | tp.m_oss.str("" ); |
16418 | tp.open(); |
16419 | if (tp.m_currentColumn == static_cast<int>(tp.m_columnInfos.size() - 1)) { |
16420 | tp.m_currentColumn = -1; |
16421 | tp.m_os << '\n'; |
16422 | } |
16423 | tp.m_currentColumn++; |
16424 | |
16425 | auto colInfo = tp.m_columnInfos[tp.m_currentColumn]; |
16426 | auto padding = (strSize + 1 < static_cast<std::size_t>(colInfo.width)) |
16427 | ? std::string(colInfo.width - (strSize + 1), ' ') |
16428 | : std::string(); |
16429 | if (colInfo.justification == ColumnInfo::Left) |
16430 | tp.m_os << colStr << padding << ' '; |
16431 | else |
16432 | tp.m_os << padding << colStr << ' '; |
16433 | return tp; |
16434 | } |
16435 | |
16436 | friend TablePrinter& operator << (TablePrinter& tp, RowBreak) { |
16437 | if (tp.m_currentColumn > 0) { |
16438 | tp.m_os << '\n'; |
16439 | tp.m_currentColumn = -1; |
16440 | } |
16441 | return tp; |
16442 | } |
16443 | }; |
16444 | |
16445 | ConsoleReporter::ConsoleReporter(ReporterConfig const& config) |
16446 | : StreamingReporterBase(config), |
16447 | m_tablePrinter(new TablePrinter(config.stream(), |
16448 | [&config]() -> std::vector<ColumnInfo> { |
16449 | if (config.fullConfig()->benchmarkNoAnalysis()) |
16450 | { |
16451 | return{ |
16452 | { "benchmark name" , CATCH_CONFIG_CONSOLE_WIDTH - 43, ColumnInfo::Left }, |
16453 | { " samples" , 14, ColumnInfo::Right }, |
16454 | { " iterations" , 14, ColumnInfo::Right }, |
16455 | { " mean" , 14, ColumnInfo::Right } |
16456 | }; |
16457 | } |
16458 | else |
16459 | { |
16460 | return{ |
16461 | { "benchmark name" , CATCH_CONFIG_CONSOLE_WIDTH - 43, ColumnInfo::Left }, |
16462 | { "samples mean std dev" , 14, ColumnInfo::Right }, |
16463 | { "iterations low mean low std dev" , 14, ColumnInfo::Right }, |
16464 | { "estimated high mean high std dev" , 14, ColumnInfo::Right } |
16465 | }; |
16466 | } |
16467 | }())) {} |
16468 | ConsoleReporter::~ConsoleReporter() = default; |
16469 | |
16470 | std::string ConsoleReporter::getDescription() { |
16471 | return "Reports test results as plain lines of text" ; |
16472 | } |
16473 | |
16474 | void ConsoleReporter::noMatchingTestCases(std::string const& spec) { |
16475 | stream << "No test cases matched '" << spec << '\'' << std::endl; |
16476 | } |
16477 | |
16478 | void ConsoleReporter::reportInvalidArguments(std::string const&arg){ |
16479 | stream << "Invalid Filter: " << arg << std::endl; |
16480 | } |
16481 | |
16482 | void ConsoleReporter::assertionStarting(AssertionInfo const&) {} |
16483 | |
16484 | bool ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) { |
16485 | AssertionResult const& result = _assertionStats.assertionResult; |
16486 | |
16487 | bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); |
16488 | |
16489 | // Drop out if result was successful but we're not printing them. |
16490 | if (!includeResults && result.getResultType() != ResultWas::Warning) |
16491 | return false; |
16492 | |
16493 | lazyPrint(); |
16494 | |
16495 | ConsoleAssertionPrinter printer(stream, _assertionStats, includeResults); |
16496 | printer.print(); |
16497 | stream << std::endl; |
16498 | return true; |
16499 | } |
16500 | |
16501 | void ConsoleReporter::sectionStarting(SectionInfo const& _sectionInfo) { |
16502 | m_tablePrinter->close(); |
16503 | m_headerPrinted = false; |
16504 | StreamingReporterBase::sectionStarting(_sectionInfo); |
16505 | } |
16506 | void ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) { |
16507 | m_tablePrinter->close(); |
16508 | if (_sectionStats.missingAssertions) { |
16509 | lazyPrint(); |
16510 | Colour colour(Colour::ResultError); |
16511 | if (m_sectionStack.size() > 1) |
16512 | stream << "\nNo assertions in section" ; |
16513 | else |
16514 | stream << "\nNo assertions in test case" ; |
16515 | stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; |
16516 | } |
16517 | double dur = _sectionStats.durationInSeconds; |
16518 | if (shouldShowDuration(*m_config, dur)) { |
16519 | stream << getFormattedDuration(dur) << " s: " << _sectionStats.sectionInfo.name << std::endl; |
16520 | } |
16521 | if (m_headerPrinted) { |
16522 | m_headerPrinted = false; |
16523 | } |
16524 | StreamingReporterBase::sectionEnded(_sectionStats); |
16525 | } |
16526 | |
16527 | #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) |
16528 | void ConsoleReporter::benchmarkPreparing(std::string const& name) { |
16529 | lazyPrintWithoutClosingBenchmarkTable(); |
16530 | |
16531 | auto nameCol = Column(name).width(static_cast<std::size_t>(m_tablePrinter->columnInfos()[0].width - 2)); |
16532 | |
16533 | bool firstLine = true; |
16534 | for (auto line : nameCol) { |
16535 | if (!firstLine) |
16536 | (*m_tablePrinter) << ColumnBreak() << ColumnBreak() << ColumnBreak(); |
16537 | else |
16538 | firstLine = false; |
16539 | |
16540 | (*m_tablePrinter) << line << ColumnBreak(); |
16541 | } |
16542 | } |
16543 | |
16544 | void ConsoleReporter::benchmarkStarting(BenchmarkInfo const& info) { |
16545 | (*m_tablePrinter) << info.samples << ColumnBreak() |
16546 | << info.iterations << ColumnBreak(); |
16547 | if (!m_config->benchmarkNoAnalysis()) |
16548 | (*m_tablePrinter) << Duration(info.estimatedDuration) << ColumnBreak(); |
16549 | } |
16550 | void ConsoleReporter::benchmarkEnded(BenchmarkStats<> const& stats) { |
16551 | if (m_config->benchmarkNoAnalysis()) |
16552 | { |
16553 | (*m_tablePrinter) << Duration(stats.mean.point.count()) << ColumnBreak(); |
16554 | } |
16555 | else |
16556 | { |
16557 | (*m_tablePrinter) << ColumnBreak() |
16558 | << Duration(stats.mean.point.count()) << ColumnBreak() |
16559 | << Duration(stats.mean.lower_bound.count()) << ColumnBreak() |
16560 | << Duration(stats.mean.upper_bound.count()) << ColumnBreak() << ColumnBreak() |
16561 | << Duration(stats.standardDeviation.point.count()) << ColumnBreak() |
16562 | << Duration(stats.standardDeviation.lower_bound.count()) << ColumnBreak() |
16563 | << Duration(stats.standardDeviation.upper_bound.count()) << ColumnBreak() << ColumnBreak() << ColumnBreak() << ColumnBreak() << ColumnBreak(); |
16564 | } |
16565 | } |
16566 | |
16567 | void ConsoleReporter::benchmarkFailed(std::string const& error) { |
16568 | Colour colour(Colour::Red); |
16569 | (*m_tablePrinter) |
16570 | << "Benchmark failed (" << error << ')' |
16571 | << ColumnBreak() << RowBreak(); |
16572 | } |
16573 | #endif // CATCH_CONFIG_ENABLE_BENCHMARKING |
16574 | |
16575 | void ConsoleReporter::testCaseEnded(TestCaseStats const& _testCaseStats) { |
16576 | m_tablePrinter->close(); |
16577 | StreamingReporterBase::testCaseEnded(_testCaseStats); |
16578 | m_headerPrinted = false; |
16579 | } |
16580 | void ConsoleReporter::testGroupEnded(TestGroupStats const& _testGroupStats) { |
16581 | if (currentGroupInfo.used) { |
16582 | printSummaryDivider(); |
16583 | stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n" ; |
16584 | printTotals(_testGroupStats.totals); |
16585 | stream << '\n' << std::endl; |
16586 | } |
16587 | StreamingReporterBase::testGroupEnded(_testGroupStats); |
16588 | } |
16589 | void ConsoleReporter::testRunEnded(TestRunStats const& _testRunStats) { |
16590 | printTotalsDivider(_testRunStats.totals); |
16591 | printTotals(_testRunStats.totals); |
16592 | stream << std::endl; |
16593 | StreamingReporterBase::testRunEnded(_testRunStats); |
16594 | } |
16595 | void ConsoleReporter::testRunStarting(TestRunInfo const& _testInfo) { |
16596 | StreamingReporterBase::testRunStarting(_testInfo); |
16597 | printTestFilters(); |
16598 | } |
16599 | |
16600 | void ConsoleReporter::lazyPrint() { |
16601 | |
16602 | m_tablePrinter->close(); |
16603 | lazyPrintWithoutClosingBenchmarkTable(); |
16604 | } |
16605 | |
16606 | void ConsoleReporter::lazyPrintWithoutClosingBenchmarkTable() { |
16607 | |
16608 | if (!currentTestRunInfo.used) |
16609 | lazyPrintRunInfo(); |
16610 | if (!currentGroupInfo.used) |
16611 | lazyPrintGroupInfo(); |
16612 | |
16613 | if (!m_headerPrinted) { |
16614 | printTestCaseAndSectionHeader(); |
16615 | m_headerPrinted = true; |
16616 | } |
16617 | } |
16618 | void ConsoleReporter::lazyPrintRunInfo() { |
16619 | stream << '\n' << getLineOfChars<'~'>() << '\n'; |
16620 | Colour colour(Colour::SecondaryText); |
16621 | stream << currentTestRunInfo->name |
16622 | << " is a Catch v" << libraryVersion() << " host application.\n" |
16623 | << "Run with -? for options\n\n" ; |
16624 | |
16625 | if (m_config->rngSeed() != 0) |
16626 | stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n" ; |
16627 | |
16628 | currentTestRunInfo.used = true; |
16629 | } |
16630 | void ConsoleReporter::lazyPrintGroupInfo() { |
16631 | if (!currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1) { |
16632 | printClosedHeader("Group: " + currentGroupInfo->name); |
16633 | currentGroupInfo.used = true; |
16634 | } |
16635 | } |
16636 | void ConsoleReporter::printTestCaseAndSectionHeader() { |
16637 | assert(!m_sectionStack.empty()); |
16638 | printOpenHeader(currentTestCaseInfo->name); |
16639 | |
16640 | if (m_sectionStack.size() > 1) { |
16641 | Colour colourGuard(Colour::Headers); |
16642 | |
16643 | auto |
16644 | it = m_sectionStack.begin() + 1, // Skip first section (test case) |
16645 | itEnd = m_sectionStack.end(); |
16646 | for (; it != itEnd; ++it) |
16647 | printHeaderString(it->name, 2); |
16648 | } |
16649 | |
16650 | SourceLineInfo lineInfo = m_sectionStack.back().lineInfo; |
16651 | |
16652 | stream << getLineOfChars<'-'>() << '\n'; |
16653 | Colour colourGuard(Colour::FileName); |
16654 | stream << lineInfo << '\n'; |
16655 | stream << getLineOfChars<'.'>() << '\n' << std::endl; |
16656 | } |
16657 | |
16658 | void ConsoleReporter::printClosedHeader(std::string const& _name) { |
16659 | printOpenHeader(_name); |
16660 | stream << getLineOfChars<'.'>() << '\n'; |
16661 | } |
16662 | void ConsoleReporter::printOpenHeader(std::string const& _name) { |
16663 | stream << getLineOfChars<'-'>() << '\n'; |
16664 | { |
16665 | Colour colourGuard(Colour::Headers); |
16666 | printHeaderString(_name); |
16667 | } |
16668 | } |
16669 | |
16670 | // if string has a : in first line will set indent to follow it on |
16671 | // subsequent lines |
16672 | void ConsoleReporter::printHeaderString(std::string const& _string, std::size_t indent) { |
16673 | std::size_t i = _string.find(": " ); |
16674 | if (i != std::string::npos) |
16675 | i += 2; |
16676 | else |
16677 | i = 0; |
16678 | stream << Column(_string).indent(indent + i).initialIndent(indent) << '\n'; |
16679 | } |
16680 | |
16681 | struct SummaryColumn { |
16682 | |
16683 | SummaryColumn( std::string _label, Colour::Code _colour ) |
16684 | : label( std::move( _label ) ), |
16685 | colour( _colour ) {} |
16686 | SummaryColumn addRow( std::size_t count ) { |
16687 | ReusableStringStream rss; |
16688 | rss << count; |
16689 | std::string row = rss.str(); |
16690 | for (auto& oldRow : rows) { |
16691 | while (oldRow.size() < row.size()) |
16692 | oldRow = ' ' + oldRow; |
16693 | while (oldRow.size() > row.size()) |
16694 | row = ' ' + row; |
16695 | } |
16696 | rows.push_back(row); |
16697 | return *this; |
16698 | } |
16699 | |
16700 | std::string label; |
16701 | Colour::Code colour; |
16702 | std::vector<std::string> rows; |
16703 | |
16704 | }; |
16705 | |
16706 | void ConsoleReporter::printTotals( Totals const& totals ) { |
16707 | if (totals.testCases.total() == 0) { |
16708 | stream << Colour(Colour::Warning) << "No tests ran\n" ; |
16709 | } else if (totals.assertions.total() > 0 && totals.testCases.allPassed()) { |
16710 | stream << Colour(Colour::ResultSuccess) << "All tests passed" ; |
16711 | stream << " (" |
16712 | << pluralise(totals.assertions.passed, "assertion" ) << " in " |
16713 | << pluralise(totals.testCases.passed, "test case" ) << ')' |
16714 | << '\n'; |
16715 | } else { |
16716 | |
16717 | std::vector<SummaryColumn> columns; |
16718 | columns.push_back(SummaryColumn("" , Colour::None) |
16719 | .addRow(totals.testCases.total()) |
16720 | .addRow(totals.assertions.total())); |
16721 | columns.push_back(SummaryColumn("passed" , Colour::Success) |
16722 | .addRow(totals.testCases.passed) |
16723 | .addRow(totals.assertions.passed)); |
16724 | columns.push_back(SummaryColumn("failed" , Colour::ResultError) |
16725 | .addRow(totals.testCases.failed) |
16726 | .addRow(totals.assertions.failed)); |
16727 | columns.push_back(SummaryColumn("failed as expected" , Colour::ResultExpectedFailure) |
16728 | .addRow(totals.testCases.failedButOk) |
16729 | .addRow(totals.assertions.failedButOk)); |
16730 | |
16731 | printSummaryRow("test cases" , columns, 0); |
16732 | printSummaryRow("assertions" , columns, 1); |
16733 | } |
16734 | } |
16735 | void ConsoleReporter::printSummaryRow(std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row) { |
16736 | for (auto col : cols) { |
16737 | std::string value = col.rows[row]; |
16738 | if (col.label.empty()) { |
16739 | stream << label << ": " ; |
16740 | if (value != "0" ) |
16741 | stream << value; |
16742 | else |
16743 | stream << Colour(Colour::Warning) << "- none -" ; |
16744 | } else if (value != "0" ) { |
16745 | stream << Colour(Colour::LightGrey) << " | " ; |
16746 | stream << Colour(col.colour) |
16747 | << value << ' ' << col.label; |
16748 | } |
16749 | } |
16750 | stream << '\n'; |
16751 | } |
16752 | |
16753 | void ConsoleReporter::printTotalsDivider(Totals const& totals) { |
16754 | if (totals.testCases.total() > 0) { |
16755 | std::size_t failedRatio = makeRatio(totals.testCases.failed, totals.testCases.total()); |
16756 | std::size_t failedButOkRatio = makeRatio(totals.testCases.failedButOk, totals.testCases.total()); |
16757 | std::size_t passedRatio = makeRatio(totals.testCases.passed, totals.testCases.total()); |
16758 | while (failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH - 1) |
16759 | findMax(failedRatio, failedButOkRatio, passedRatio)++; |
16760 | while (failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH - 1) |
16761 | findMax(failedRatio, failedButOkRatio, passedRatio)--; |
16762 | |
16763 | stream << Colour(Colour::Error) << std::string(failedRatio, '='); |
16764 | stream << Colour(Colour::ResultExpectedFailure) << std::string(failedButOkRatio, '='); |
16765 | if (totals.testCases.allPassed()) |
16766 | stream << Colour(Colour::ResultSuccess) << std::string(passedRatio, '='); |
16767 | else |
16768 | stream << Colour(Colour::Success) << std::string(passedRatio, '='); |
16769 | } else { |
16770 | stream << Colour(Colour::Warning) << std::string(CATCH_CONFIG_CONSOLE_WIDTH - 1, '='); |
16771 | } |
16772 | stream << '\n'; |
16773 | } |
16774 | void ConsoleReporter::printSummaryDivider() { |
16775 | stream << getLineOfChars<'-'>() << '\n'; |
16776 | } |
16777 | |
16778 | void ConsoleReporter::printTestFilters() { |
16779 | if (m_config->testSpec().hasFilters()) { |
16780 | Colour guard(Colour::BrightYellow); |
16781 | stream << "Filters: " << serializeFilters(m_config->getTestsOrTags()) << '\n'; |
16782 | } |
16783 | } |
16784 | |
16785 | CATCH_REGISTER_REPORTER("console" , ConsoleReporter) |
16786 | |
16787 | } // end namespace Catch |
16788 | |
16789 | #if defined(_MSC_VER) |
16790 | #pragma warning(pop) |
16791 | #endif |
16792 | |
16793 | #if defined(__clang__) |
16794 | # pragma clang diagnostic pop |
16795 | #endif |
16796 | // end catch_reporter_console.cpp |
16797 | // start catch_reporter_junit.cpp |
16798 | |
16799 | #include <cassert> |
16800 | #include <sstream> |
16801 | #include <ctime> |
16802 | #include <algorithm> |
16803 | #include <iomanip> |
16804 | |
16805 | namespace Catch { |
16806 | |
16807 | namespace { |
16808 | std::string getCurrentTimestamp() { |
16809 | // Beware, this is not reentrant because of backward compatibility issues |
16810 | // Also, UTC only, again because of backward compatibility (%z is C++11) |
16811 | time_t rawtime; |
16812 | std::time(&rawtime); |
16813 | auto const timeStampSize = sizeof("2017-01-16T17:06:45Z" ); |
16814 | |
16815 | #ifdef _MSC_VER |
16816 | std::tm timeInfo = {}; |
16817 | gmtime_s(&timeInfo, &rawtime); |
16818 | #else |
16819 | std::tm* timeInfo; |
16820 | timeInfo = std::gmtime(&rawtime); |
16821 | #endif |
16822 | |
16823 | char timeStamp[timeStampSize]; |
16824 | const char * const fmt = "%Y-%m-%dT%H:%M:%SZ" ; |
16825 | |
16826 | #ifdef _MSC_VER |
16827 | std::strftime(timeStamp, timeStampSize, fmt, &timeInfo); |
16828 | #else |
16829 | std::strftime(timeStamp, timeStampSize, fmt, timeInfo); |
16830 | #endif |
16831 | return std::string(timeStamp, timeStampSize-1); |
16832 | } |
16833 | |
16834 | std::string fileNameTag(const std::vector<std::string> &tags) { |
16835 | auto it = std::find_if(begin(tags), |
16836 | end(tags), |
16837 | [] (std::string const& tag) {return tag.front() == '#'; }); |
16838 | if (it != tags.end()) |
16839 | return it->substr(1); |
16840 | return std::string(); |
16841 | } |
16842 | |
16843 | // Formats the duration in seconds to 3 decimal places. |
16844 | // This is done because some genius defined Maven Surefire schema |
16845 | // in a way that only accepts 3 decimal places, and tools like |
16846 | // Jenkins use that schema for validation JUnit reporter output. |
16847 | std::string formatDuration( double seconds ) { |
16848 | ReusableStringStream rss; |
16849 | rss << std::fixed << std::setprecision( 3 ) << seconds; |
16850 | return rss.str(); |
16851 | } |
16852 | |
16853 | } // anonymous namespace |
16854 | |
16855 | JunitReporter::JunitReporter( ReporterConfig const& _config ) |
16856 | : CumulativeReporterBase( _config ), |
16857 | xml( _config.stream() ) |
16858 | { |
16859 | m_reporterPrefs.shouldRedirectStdOut = true; |
16860 | m_reporterPrefs.shouldReportAllAssertions = true; |
16861 | } |
16862 | |
16863 | JunitReporter::~JunitReporter() {} |
16864 | |
16865 | std::string JunitReporter::getDescription() { |
16866 | return "Reports test results in an XML format that looks like Ant's junitreport target" ; |
16867 | } |
16868 | |
16869 | void JunitReporter::noMatchingTestCases( std::string const& /*spec*/ ) {} |
16870 | |
16871 | void JunitReporter::testRunStarting( TestRunInfo const& runInfo ) { |
16872 | CumulativeReporterBase::testRunStarting( runInfo ); |
16873 | xml.startElement( "testsuites" ); |
16874 | } |
16875 | |
16876 | void JunitReporter::testGroupStarting( GroupInfo const& groupInfo ) { |
16877 | suiteTimer.start(); |
16878 | stdOutForSuite.clear(); |
16879 | stdErrForSuite.clear(); |
16880 | unexpectedExceptions = 0; |
16881 | CumulativeReporterBase::testGroupStarting( groupInfo ); |
16882 | } |
16883 | |
16884 | void JunitReporter::testCaseStarting( TestCaseInfo const& testCaseInfo ) { |
16885 | m_okToFail = testCaseInfo.okToFail(); |
16886 | } |
16887 | |
16888 | bool JunitReporter::assertionEnded( AssertionStats const& assertionStats ) { |
16889 | if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail ) |
16890 | unexpectedExceptions++; |
16891 | return CumulativeReporterBase::assertionEnded( assertionStats ); |
16892 | } |
16893 | |
16894 | void JunitReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { |
16895 | stdOutForSuite += testCaseStats.stdOut; |
16896 | stdErrForSuite += testCaseStats.stdErr; |
16897 | CumulativeReporterBase::testCaseEnded( testCaseStats ); |
16898 | } |
16899 | |
16900 | void JunitReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { |
16901 | double suiteTime = suiteTimer.getElapsedSeconds(); |
16902 | CumulativeReporterBase::testGroupEnded( testGroupStats ); |
16903 | writeGroup( *m_testGroups.back(), suiteTime ); |
16904 | } |
16905 | |
16906 | void JunitReporter::testRunEndedCumulative() { |
16907 | xml.endElement(); |
16908 | } |
16909 | |
16910 | void JunitReporter::writeGroup( TestGroupNode const& groupNode, double suiteTime ) { |
16911 | XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); |
16912 | |
16913 | TestGroupStats const& stats = groupNode.value; |
16914 | xml.writeAttribute( "name" , stats.groupInfo.name ); |
16915 | xml.writeAttribute( "errors" , unexpectedExceptions ); |
16916 | xml.writeAttribute( "failures" , stats.totals.assertions.failed-unexpectedExceptions ); |
16917 | xml.writeAttribute( "tests" , stats.totals.assertions.total() ); |
16918 | xml.writeAttribute( "hostname" , "tbd" ); // !TBD |
16919 | if( m_config->showDurations() == ShowDurations::Never ) |
16920 | xml.writeAttribute( "time" , "" ); |
16921 | else |
16922 | xml.writeAttribute( "time" , formatDuration( suiteTime ) ); |
16923 | xml.writeAttribute( "timestamp" , getCurrentTimestamp() ); |
16924 | |
16925 | // Write properties if there are any |
16926 | if (m_config->hasTestFilters() || m_config->rngSeed() != 0) { |
16927 | auto properties = xml.scopedElement("properties" ); |
16928 | if (m_config->hasTestFilters()) { |
16929 | xml.scopedElement("property" ) |
16930 | .writeAttribute("name" , "filters" ) |
16931 | .writeAttribute("value" , serializeFilters(m_config->getTestsOrTags())); |
16932 | } |
16933 | if (m_config->rngSeed() != 0) { |
16934 | xml.scopedElement("property" ) |
16935 | .writeAttribute("name" , "random-seed" ) |
16936 | .writeAttribute("value" , m_config->rngSeed()); |
16937 | } |
16938 | } |
16939 | |
16940 | // Write test cases |
16941 | for( auto const& child : groupNode.children ) |
16942 | writeTestCase( *child ); |
16943 | |
16944 | xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite ), XmlFormatting::Newline ); |
16945 | xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite ), XmlFormatting::Newline ); |
16946 | } |
16947 | |
16948 | void JunitReporter::writeTestCase( TestCaseNode const& testCaseNode ) { |
16949 | TestCaseStats const& stats = testCaseNode.value; |
16950 | |
16951 | // All test cases have exactly one section - which represents the |
16952 | // test case itself. That section may have 0-n nested sections |
16953 | assert( testCaseNode.children.size() == 1 ); |
16954 | SectionNode const& rootSection = *testCaseNode.children.front(); |
16955 | |
16956 | std::string className = stats.testInfo.className; |
16957 | |
16958 | if( className.empty() ) { |
16959 | className = fileNameTag(stats.testInfo.tags); |
16960 | if ( className.empty() ) |
16961 | className = "global" ; |
16962 | } |
16963 | |
16964 | if ( !m_config->name().empty() ) |
16965 | className = m_config->name() + "." + className; |
16966 | |
16967 | writeSection( className, "" , rootSection, stats.testInfo.okToFail() ); |
16968 | } |
16969 | |
16970 | void JunitReporter::writeSection( std::string const& className, |
16971 | std::string const& rootName, |
16972 | SectionNode const& sectionNode, |
16973 | bool testOkToFail) { |
16974 | std::string name = trim( sectionNode.stats.sectionInfo.name ); |
16975 | if( !rootName.empty() ) |
16976 | name = rootName + '/' + name; |
16977 | |
16978 | if( !sectionNode.assertions.empty() || |
16979 | !sectionNode.stdOut.empty() || |
16980 | !sectionNode.stdErr.empty() ) { |
16981 | XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); |
16982 | if( className.empty() ) { |
16983 | xml.writeAttribute( "classname" , name ); |
16984 | xml.writeAttribute( "name" , "root" ); |
16985 | } |
16986 | else { |
16987 | xml.writeAttribute( "classname" , className ); |
16988 | xml.writeAttribute( "name" , name ); |
16989 | } |
16990 | xml.writeAttribute( "time" , formatDuration( sectionNode.stats.durationInSeconds ) ); |
16991 | // This is not ideal, but it should be enough to mimic gtest's |
16992 | // junit output. |
16993 | // Ideally the JUnit reporter would also handle `skipTest` |
16994 | // events and write those out appropriately. |
16995 | xml.writeAttribute( "status" , "run" ); |
16996 | |
16997 | if (sectionNode.stats.assertions.failedButOk) { |
16998 | xml.scopedElement("skipped" ) |
16999 | .writeAttribute("message" , "TEST_CASE tagged with !mayfail" ); |
17000 | } |
17001 | |
17002 | writeAssertions( sectionNode ); |
17003 | |
17004 | if( !sectionNode.stdOut.empty() ) |
17005 | xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), XmlFormatting::Newline ); |
17006 | if( !sectionNode.stdErr.empty() ) |
17007 | xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), XmlFormatting::Newline ); |
17008 | } |
17009 | for( auto const& childNode : sectionNode.childSections ) |
17010 | if( className.empty() ) |
17011 | writeSection( name, "" , *childNode, testOkToFail ); |
17012 | else |
17013 | writeSection( className, name, *childNode, testOkToFail ); |
17014 | } |
17015 | |
17016 | void JunitReporter::writeAssertions( SectionNode const& sectionNode ) { |
17017 | for( auto const& assertion : sectionNode.assertions ) |
17018 | writeAssertion( assertion ); |
17019 | } |
17020 | |
17021 | void JunitReporter::writeAssertion( AssertionStats const& stats ) { |
17022 | AssertionResult const& result = stats.assertionResult; |
17023 | if( !result.isOk() ) { |
17024 | std::string elementName; |
17025 | switch( result.getResultType() ) { |
17026 | case ResultWas::ThrewException: |
17027 | case ResultWas::FatalErrorCondition: |
17028 | elementName = "error" ; |
17029 | break; |
17030 | case ResultWas::ExplicitFailure: |
17031 | case ResultWas::ExpressionFailed: |
17032 | case ResultWas::DidntThrowException: |
17033 | elementName = "failure" ; |
17034 | break; |
17035 | |
17036 | // We should never see these here: |
17037 | case ResultWas::Info: |
17038 | case ResultWas::Warning: |
17039 | case ResultWas::Ok: |
17040 | case ResultWas::Unknown: |
17041 | case ResultWas::FailureBit: |
17042 | case ResultWas::Exception: |
17043 | elementName = "internalError" ; |
17044 | break; |
17045 | } |
17046 | |
17047 | XmlWriter::ScopedElement e = xml.scopedElement( elementName ); |
17048 | |
17049 | xml.writeAttribute( "message" , result.getExpression() ); |
17050 | xml.writeAttribute( "type" , result.getTestMacroName() ); |
17051 | |
17052 | ReusableStringStream rss; |
17053 | if (stats.totals.assertions.total() > 0) { |
17054 | rss << "FAILED" << ":\n" ; |
17055 | if (result.hasExpression()) { |
17056 | rss << " " ; |
17057 | rss << result.getExpressionInMacro(); |
17058 | rss << '\n'; |
17059 | } |
17060 | if (result.hasExpandedExpression()) { |
17061 | rss << "with expansion:\n" ; |
17062 | rss << Column(result.getExpandedExpression()).indent(2) << '\n'; |
17063 | } |
17064 | } else { |
17065 | rss << '\n'; |
17066 | } |
17067 | |
17068 | if( !result.getMessage().empty() ) |
17069 | rss << result.getMessage() << '\n'; |
17070 | for( auto const& msg : stats.infoMessages ) |
17071 | if( msg.type == ResultWas::Info ) |
17072 | rss << msg.message << '\n'; |
17073 | |
17074 | rss << "at " << result.getSourceInfo(); |
17075 | xml.writeText( rss.str(), XmlFormatting::Newline ); |
17076 | } |
17077 | } |
17078 | |
17079 | CATCH_REGISTER_REPORTER( "junit" , JunitReporter ) |
17080 | |
17081 | } // end namespace Catch |
17082 | // end catch_reporter_junit.cpp |
17083 | // start catch_reporter_listening.cpp |
17084 | |
17085 | #include <cassert> |
17086 | |
17087 | namespace Catch { |
17088 | |
17089 | ListeningReporter::ListeningReporter() { |
17090 | // We will assume that listeners will always want all assertions |
17091 | m_preferences.shouldReportAllAssertions = true; |
17092 | } |
17093 | |
17094 | void ListeningReporter::addListener( IStreamingReporterPtr&& listener ) { |
17095 | m_listeners.push_back( std::move( listener ) ); |
17096 | } |
17097 | |
17098 | void ListeningReporter::addReporter(IStreamingReporterPtr&& reporter) { |
17099 | assert(!m_reporter && "Listening reporter can wrap only 1 real reporter" ); |
17100 | m_reporter = std::move( reporter ); |
17101 | m_preferences.shouldRedirectStdOut = m_reporter->getPreferences().shouldRedirectStdOut; |
17102 | } |
17103 | |
17104 | ReporterPreferences ListeningReporter::getPreferences() const { |
17105 | return m_preferences; |
17106 | } |
17107 | |
17108 | std::set<Verbosity> ListeningReporter::getSupportedVerbosities() { |
17109 | return std::set<Verbosity>{ }; |
17110 | } |
17111 | |
17112 | void ListeningReporter::noMatchingTestCases( std::string const& spec ) { |
17113 | for ( auto const& listener : m_listeners ) { |
17114 | listener->noMatchingTestCases( spec ); |
17115 | } |
17116 | m_reporter->noMatchingTestCases( spec ); |
17117 | } |
17118 | |
17119 | void ListeningReporter::reportInvalidArguments(std::string const&arg){ |
17120 | for ( auto const& listener : m_listeners ) { |
17121 | listener->reportInvalidArguments( arg ); |
17122 | } |
17123 | m_reporter->reportInvalidArguments( arg ); |
17124 | } |
17125 | |
17126 | #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) |
17127 | void ListeningReporter::benchmarkPreparing( std::string const& name ) { |
17128 | for (auto const& listener : m_listeners) { |
17129 | listener->benchmarkPreparing(name); |
17130 | } |
17131 | m_reporter->benchmarkPreparing(name); |
17132 | } |
17133 | void ListeningReporter::benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) { |
17134 | for ( auto const& listener : m_listeners ) { |
17135 | listener->benchmarkStarting( benchmarkInfo ); |
17136 | } |
17137 | m_reporter->benchmarkStarting( benchmarkInfo ); |
17138 | } |
17139 | void ListeningReporter::benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) { |
17140 | for ( auto const& listener : m_listeners ) { |
17141 | listener->benchmarkEnded( benchmarkStats ); |
17142 | } |
17143 | m_reporter->benchmarkEnded( benchmarkStats ); |
17144 | } |
17145 | |
17146 | void ListeningReporter::benchmarkFailed( std::string const& error ) { |
17147 | for (auto const& listener : m_listeners) { |
17148 | listener->benchmarkFailed(error); |
17149 | } |
17150 | m_reporter->benchmarkFailed(error); |
17151 | } |
17152 | #endif // CATCH_CONFIG_ENABLE_BENCHMARKING |
17153 | |
17154 | void ListeningReporter::testRunStarting( TestRunInfo const& testRunInfo ) { |
17155 | for ( auto const& listener : m_listeners ) { |
17156 | listener->testRunStarting( testRunInfo ); |
17157 | } |
17158 | m_reporter->testRunStarting( testRunInfo ); |
17159 | } |
17160 | |
17161 | void ListeningReporter::testGroupStarting( GroupInfo const& groupInfo ) { |
17162 | for ( auto const& listener : m_listeners ) { |
17163 | listener->testGroupStarting( groupInfo ); |
17164 | } |
17165 | m_reporter->testGroupStarting( groupInfo ); |
17166 | } |
17167 | |
17168 | void ListeningReporter::testCaseStarting( TestCaseInfo const& testInfo ) { |
17169 | for ( auto const& listener : m_listeners ) { |
17170 | listener->testCaseStarting( testInfo ); |
17171 | } |
17172 | m_reporter->testCaseStarting( testInfo ); |
17173 | } |
17174 | |
17175 | void ListeningReporter::sectionStarting( SectionInfo const& sectionInfo ) { |
17176 | for ( auto const& listener : m_listeners ) { |
17177 | listener->sectionStarting( sectionInfo ); |
17178 | } |
17179 | m_reporter->sectionStarting( sectionInfo ); |
17180 | } |
17181 | |
17182 | void ListeningReporter::assertionStarting( AssertionInfo const& assertionInfo ) { |
17183 | for ( auto const& listener : m_listeners ) { |
17184 | listener->assertionStarting( assertionInfo ); |
17185 | } |
17186 | m_reporter->assertionStarting( assertionInfo ); |
17187 | } |
17188 | |
17189 | // The return value indicates if the messages buffer should be cleared: |
17190 | bool ListeningReporter::assertionEnded( AssertionStats const& assertionStats ) { |
17191 | for( auto const& listener : m_listeners ) { |
17192 | static_cast<void>( listener->assertionEnded( assertionStats ) ); |
17193 | } |
17194 | return m_reporter->assertionEnded( assertionStats ); |
17195 | } |
17196 | |
17197 | void ListeningReporter::sectionEnded( SectionStats const& sectionStats ) { |
17198 | for ( auto const& listener : m_listeners ) { |
17199 | listener->sectionEnded( sectionStats ); |
17200 | } |
17201 | m_reporter->sectionEnded( sectionStats ); |
17202 | } |
17203 | |
17204 | void ListeningReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { |
17205 | for ( auto const& listener : m_listeners ) { |
17206 | listener->testCaseEnded( testCaseStats ); |
17207 | } |
17208 | m_reporter->testCaseEnded( testCaseStats ); |
17209 | } |
17210 | |
17211 | void ListeningReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { |
17212 | for ( auto const& listener : m_listeners ) { |
17213 | listener->testGroupEnded( testGroupStats ); |
17214 | } |
17215 | m_reporter->testGroupEnded( testGroupStats ); |
17216 | } |
17217 | |
17218 | void ListeningReporter::testRunEnded( TestRunStats const& testRunStats ) { |
17219 | for ( auto const& listener : m_listeners ) { |
17220 | listener->testRunEnded( testRunStats ); |
17221 | } |
17222 | m_reporter->testRunEnded( testRunStats ); |
17223 | } |
17224 | |
17225 | void ListeningReporter::skipTest( TestCaseInfo const& testInfo ) { |
17226 | for ( auto const& listener : m_listeners ) { |
17227 | listener->skipTest( testInfo ); |
17228 | } |
17229 | m_reporter->skipTest( testInfo ); |
17230 | } |
17231 | |
17232 | bool ListeningReporter::isMulti() const { |
17233 | return true; |
17234 | } |
17235 | |
17236 | } // end namespace Catch |
17237 | // end catch_reporter_listening.cpp |
17238 | // start catch_reporter_xml.cpp |
17239 | |
17240 | #if defined(_MSC_VER) |
17241 | #pragma warning(push) |
17242 | #pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch |
17243 | // Note that 4062 (not all labels are handled |
17244 | // and default is missing) is enabled |
17245 | #endif |
17246 | |
17247 | namespace Catch { |
17248 | XmlReporter::XmlReporter( ReporterConfig const& _config ) |
17249 | : StreamingReporterBase( _config ), |
17250 | m_xml(_config.stream()) |
17251 | { |
17252 | m_reporterPrefs.shouldRedirectStdOut = true; |
17253 | m_reporterPrefs.shouldReportAllAssertions = true; |
17254 | } |
17255 | |
17256 | XmlReporter::~XmlReporter() = default; |
17257 | |
17258 | std::string XmlReporter::getDescription() { |
17259 | return "Reports test results as an XML document" ; |
17260 | } |
17261 | |
17262 | std::string XmlReporter::getStylesheetRef() const { |
17263 | return std::string(); |
17264 | } |
17265 | |
17266 | void XmlReporter::writeSourceInfo( SourceLineInfo const& sourceInfo ) { |
17267 | m_xml |
17268 | .writeAttribute( "filename" , sourceInfo.file ) |
17269 | .writeAttribute( "line" , sourceInfo.line ); |
17270 | } |
17271 | |
17272 | void XmlReporter::noMatchingTestCases( std::string const& s ) { |
17273 | StreamingReporterBase::noMatchingTestCases( s ); |
17274 | } |
17275 | |
17276 | void XmlReporter::testRunStarting( TestRunInfo const& testInfo ) { |
17277 | StreamingReporterBase::testRunStarting( testInfo ); |
17278 | std::string stylesheetRef = getStylesheetRef(); |
17279 | if( !stylesheetRef.empty() ) |
17280 | m_xml.writeStylesheetRef( stylesheetRef ); |
17281 | m_xml.startElement( "Catch" ); |
17282 | if( !m_config->name().empty() ) |
17283 | m_xml.writeAttribute( "name" , m_config->name() ); |
17284 | if (m_config->testSpec().hasFilters()) |
17285 | m_xml.writeAttribute( "filters" , serializeFilters( m_config->getTestsOrTags() ) ); |
17286 | if( m_config->rngSeed() != 0 ) |
17287 | m_xml.scopedElement( "Randomness" ) |
17288 | .writeAttribute( "seed" , m_config->rngSeed() ); |
17289 | } |
17290 | |
17291 | void XmlReporter::testGroupStarting( GroupInfo const& groupInfo ) { |
17292 | StreamingReporterBase::testGroupStarting( groupInfo ); |
17293 | m_xml.startElement( "Group" ) |
17294 | .writeAttribute( "name" , groupInfo.name ); |
17295 | } |
17296 | |
17297 | void XmlReporter::testCaseStarting( TestCaseInfo const& testInfo ) { |
17298 | StreamingReporterBase::testCaseStarting(testInfo); |
17299 | m_xml.startElement( "TestCase" ) |
17300 | .writeAttribute( "name" , trim( testInfo.name ) ) |
17301 | .writeAttribute( "description" , testInfo.description ) |
17302 | .writeAttribute( "tags" , testInfo.tagsAsString() ); |
17303 | |
17304 | writeSourceInfo( testInfo.lineInfo ); |
17305 | |
17306 | if ( m_config->showDurations() == ShowDurations::Always ) |
17307 | m_testCaseTimer.start(); |
17308 | m_xml.ensureTagClosed(); |
17309 | } |
17310 | |
17311 | void XmlReporter::sectionStarting( SectionInfo const& sectionInfo ) { |
17312 | StreamingReporterBase::sectionStarting( sectionInfo ); |
17313 | if( m_sectionDepth++ > 0 ) { |
17314 | m_xml.startElement( "Section" ) |
17315 | .writeAttribute( "name" , trim( sectionInfo.name ) ); |
17316 | writeSourceInfo( sectionInfo.lineInfo ); |
17317 | m_xml.ensureTagClosed(); |
17318 | } |
17319 | } |
17320 | |
17321 | void XmlReporter::assertionStarting( AssertionInfo const& ) { } |
17322 | |
17323 | bool XmlReporter::assertionEnded( AssertionStats const& assertionStats ) { |
17324 | |
17325 | AssertionResult const& result = assertionStats.assertionResult; |
17326 | |
17327 | bool includeResults = m_config->includeSuccessfulResults() || !result.isOk(); |
17328 | |
17329 | if( includeResults || result.getResultType() == ResultWas::Warning ) { |
17330 | // Print any info messages in <Info> tags. |
17331 | for( auto const& msg : assertionStats.infoMessages ) { |
17332 | if( msg.type == ResultWas::Info && includeResults ) { |
17333 | m_xml.scopedElement( "Info" ) |
17334 | .writeText( msg.message ); |
17335 | } else if ( msg.type == ResultWas::Warning ) { |
17336 | m_xml.scopedElement( "Warning" ) |
17337 | .writeText( msg.message ); |
17338 | } |
17339 | } |
17340 | } |
17341 | |
17342 | // Drop out if result was successful but we're not printing them. |
17343 | if( !includeResults && result.getResultType() != ResultWas::Warning ) |
17344 | return true; |
17345 | |
17346 | // Print the expression if there is one. |
17347 | if( result.hasExpression() ) { |
17348 | m_xml.startElement( "Expression" ) |
17349 | .writeAttribute( "success" , result.succeeded() ) |
17350 | .writeAttribute( "type" , result.getTestMacroName() ); |
17351 | |
17352 | writeSourceInfo( result.getSourceInfo() ); |
17353 | |
17354 | m_xml.scopedElement( "Original" ) |
17355 | .writeText( result.getExpression() ); |
17356 | m_xml.scopedElement( "Expanded" ) |
17357 | .writeText( result.getExpandedExpression() ); |
17358 | } |
17359 | |
17360 | // And... Print a result applicable to each result type. |
17361 | switch( result.getResultType() ) { |
17362 | case ResultWas::ThrewException: |
17363 | m_xml.startElement( "Exception" ); |
17364 | writeSourceInfo( result.getSourceInfo() ); |
17365 | m_xml.writeText( result.getMessage() ); |
17366 | m_xml.endElement(); |
17367 | break; |
17368 | case ResultWas::FatalErrorCondition: |
17369 | m_xml.startElement( "FatalErrorCondition" ); |
17370 | writeSourceInfo( result.getSourceInfo() ); |
17371 | m_xml.writeText( result.getMessage() ); |
17372 | m_xml.endElement(); |
17373 | break; |
17374 | case ResultWas::Info: |
17375 | m_xml.scopedElement( "Info" ) |
17376 | .writeText( result.getMessage() ); |
17377 | break; |
17378 | case ResultWas::Warning: |
17379 | // Warning will already have been written |
17380 | break; |
17381 | case ResultWas::ExplicitFailure: |
17382 | m_xml.startElement( "Failure" ); |
17383 | writeSourceInfo( result.getSourceInfo() ); |
17384 | m_xml.writeText( result.getMessage() ); |
17385 | m_xml.endElement(); |
17386 | break; |
17387 | default: |
17388 | break; |
17389 | } |
17390 | |
17391 | if( result.hasExpression() ) |
17392 | m_xml.endElement(); |
17393 | |
17394 | return true; |
17395 | } |
17396 | |
17397 | void XmlReporter::sectionEnded( SectionStats const& sectionStats ) { |
17398 | StreamingReporterBase::sectionEnded( sectionStats ); |
17399 | if( --m_sectionDepth > 0 ) { |
17400 | XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); |
17401 | e.writeAttribute( "successes" , sectionStats.assertions.passed ); |
17402 | e.writeAttribute( "failures" , sectionStats.assertions.failed ); |
17403 | e.writeAttribute( "expectedFailures" , sectionStats.assertions.failedButOk ); |
17404 | |
17405 | if ( m_config->showDurations() == ShowDurations::Always ) |
17406 | e.writeAttribute( "durationInSeconds" , sectionStats.durationInSeconds ); |
17407 | |
17408 | m_xml.endElement(); |
17409 | } |
17410 | } |
17411 | |
17412 | void XmlReporter::testCaseEnded( TestCaseStats const& testCaseStats ) { |
17413 | StreamingReporterBase::testCaseEnded( testCaseStats ); |
17414 | XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); |
17415 | e.writeAttribute( "success" , testCaseStats.totals.assertions.allOk() ); |
17416 | |
17417 | if ( m_config->showDurations() == ShowDurations::Always ) |
17418 | e.writeAttribute( "durationInSeconds" , m_testCaseTimer.getElapsedSeconds() ); |
17419 | |
17420 | if( !testCaseStats.stdOut.empty() ) |
17421 | m_xml.scopedElement( "StdOut" ).writeText( trim( testCaseStats.stdOut ), XmlFormatting::Newline ); |
17422 | if( !testCaseStats.stdErr.empty() ) |
17423 | m_xml.scopedElement( "StdErr" ).writeText( trim( testCaseStats.stdErr ), XmlFormatting::Newline ); |
17424 | |
17425 | m_xml.endElement(); |
17426 | } |
17427 | |
17428 | void XmlReporter::testGroupEnded( TestGroupStats const& testGroupStats ) { |
17429 | StreamingReporterBase::testGroupEnded( testGroupStats ); |
17430 | // TODO: Check testGroupStats.aborting and act accordingly. |
17431 | m_xml.scopedElement( "OverallResults" ) |
17432 | .writeAttribute( "successes" , testGroupStats.totals.assertions.passed ) |
17433 | .writeAttribute( "failures" , testGroupStats.totals.assertions.failed ) |
17434 | .writeAttribute( "expectedFailures" , testGroupStats.totals.assertions.failedButOk ); |
17435 | m_xml.scopedElement( "OverallResultsCases" ) |
17436 | .writeAttribute( "successes" , testGroupStats.totals.testCases.passed ) |
17437 | .writeAttribute( "failures" , testGroupStats.totals.testCases.failed ) |
17438 | .writeAttribute( "expectedFailures" , testGroupStats.totals.testCases.failedButOk ); |
17439 | m_xml.endElement(); |
17440 | } |
17441 | |
17442 | void XmlReporter::testRunEnded( TestRunStats const& testRunStats ) { |
17443 | StreamingReporterBase::testRunEnded( testRunStats ); |
17444 | m_xml.scopedElement( "OverallResults" ) |
17445 | .writeAttribute( "successes" , testRunStats.totals.assertions.passed ) |
17446 | .writeAttribute( "failures" , testRunStats.totals.assertions.failed ) |
17447 | .writeAttribute( "expectedFailures" , testRunStats.totals.assertions.failedButOk ); |
17448 | m_xml.scopedElement( "OverallResultsCases" ) |
17449 | .writeAttribute( "successes" , testRunStats.totals.testCases.passed ) |
17450 | .writeAttribute( "failures" , testRunStats.totals.testCases.failed ) |
17451 | .writeAttribute( "expectedFailures" , testRunStats.totals.testCases.failedButOk ); |
17452 | m_xml.endElement(); |
17453 | } |
17454 | |
17455 | #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) |
17456 | void XmlReporter::benchmarkPreparing(std::string const& name) { |
17457 | m_xml.startElement("BenchmarkResults" ) |
17458 | .writeAttribute("name" , name); |
17459 | } |
17460 | |
17461 | void XmlReporter::benchmarkStarting(BenchmarkInfo const &info) { |
17462 | m_xml.writeAttribute("samples" , info.samples) |
17463 | .writeAttribute("resamples" , info.resamples) |
17464 | .writeAttribute("iterations" , info.iterations) |
17465 | .writeAttribute("clockResolution" , info.clockResolution) |
17466 | .writeAttribute("estimatedDuration" , info.estimatedDuration) |
17467 | .writeComment("All values in nano seconds" ); |
17468 | } |
17469 | |
17470 | void XmlReporter::benchmarkEnded(BenchmarkStats<> const& benchmarkStats) { |
17471 | m_xml.startElement("mean" ) |
17472 | .writeAttribute("value" , benchmarkStats.mean.point.count()) |
17473 | .writeAttribute("lowerBound" , benchmarkStats.mean.lower_bound.count()) |
17474 | .writeAttribute("upperBound" , benchmarkStats.mean.upper_bound.count()) |
17475 | .writeAttribute("ci" , benchmarkStats.mean.confidence_interval); |
17476 | m_xml.endElement(); |
17477 | m_xml.startElement("standardDeviation" ) |
17478 | .writeAttribute("value" , benchmarkStats.standardDeviation.point.count()) |
17479 | .writeAttribute("lowerBound" , benchmarkStats.standardDeviation.lower_bound.count()) |
17480 | .writeAttribute("upperBound" , benchmarkStats.standardDeviation.upper_bound.count()) |
17481 | .writeAttribute("ci" , benchmarkStats.standardDeviation.confidence_interval); |
17482 | m_xml.endElement(); |
17483 | m_xml.startElement("outliers" ) |
17484 | .writeAttribute("variance" , benchmarkStats.outlierVariance) |
17485 | .writeAttribute("lowMild" , benchmarkStats.outliers.low_mild) |
17486 | .writeAttribute("lowSevere" , benchmarkStats.outliers.low_severe) |
17487 | .writeAttribute("highMild" , benchmarkStats.outliers.high_mild) |
17488 | .writeAttribute("highSevere" , benchmarkStats.outliers.high_severe); |
17489 | m_xml.endElement(); |
17490 | m_xml.endElement(); |
17491 | } |
17492 | |
17493 | void XmlReporter::benchmarkFailed(std::string const &error) { |
17494 | m_xml.scopedElement("failed" ). |
17495 | writeAttribute("message" , error); |
17496 | m_xml.endElement(); |
17497 | } |
17498 | #endif // CATCH_CONFIG_ENABLE_BENCHMARKING |
17499 | |
17500 | CATCH_REGISTER_REPORTER( "xml" , XmlReporter ) |
17501 | |
17502 | } // end namespace Catch |
17503 | |
17504 | #if defined(_MSC_VER) |
17505 | #pragma warning(pop) |
17506 | #endif |
17507 | // end catch_reporter_xml.cpp |
17508 | |
17509 | namespace Catch { |
17510 | LeakDetector leakDetector; |
17511 | } |
17512 | |
17513 | #ifdef __clang__ |
17514 | #pragma clang diagnostic pop |
17515 | #endif |
17516 | |
17517 | // end catch_impl.hpp |
17518 | #endif |
17519 | |
17520 | #ifdef CATCH_CONFIG_MAIN |
17521 | // start catch_default_main.hpp |
17522 | |
17523 | #ifndef __OBJC__ |
17524 | |
17525 | #if defined(CATCH_CONFIG_WCHAR) && defined(CATCH_PLATFORM_WINDOWS) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN) |
17526 | // Standard C/C++ Win32 Unicode wmain entry point |
17527 | extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) { |
17528 | #else |
17529 | // Standard C/C++ main entry point |
17530 | int main (int argc, char * argv[]) { |
17531 | #endif |
17532 | |
17533 | return Catch::Session().run( argc, argv ); |
17534 | } |
17535 | |
17536 | #else // __OBJC__ |
17537 | |
17538 | // Objective-C entry point |
17539 | int main (int argc, char * const argv[]) { |
17540 | #if !CATCH_ARC_ENABLED |
17541 | NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; |
17542 | #endif |
17543 | |
17544 | Catch::registerTestMethods(); |
17545 | int result = Catch::Session().run( argc, (char**)argv ); |
17546 | |
17547 | #if !CATCH_ARC_ENABLED |
17548 | [pool drain]; |
17549 | #endif |
17550 | |
17551 | return result; |
17552 | } |
17553 | |
17554 | #endif // __OBJC__ |
17555 | |
17556 | // end catch_default_main.hpp |
17557 | #endif |
17558 | |
17559 | #if !defined(CATCH_CONFIG_IMPL_ONLY) |
17560 | |
17561 | #ifdef CLARA_CONFIG_MAIN_NOT_DEFINED |
17562 | # undef CLARA_CONFIG_MAIN |
17563 | #endif |
17564 | |
17565 | #if !defined(CATCH_CONFIG_DISABLE) |
17566 | ////// |
17567 | // If this config identifier is defined then all CATCH macros are prefixed with CATCH_ |
17568 | #ifdef CATCH_CONFIG_PREFIX_ALL |
17569 | |
17570 | #define CATCH_REQUIRE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ ) |
17571 | #define CATCH_REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) |
17572 | |
17573 | #define CATCH_REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ ) |
17574 | #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) |
17575 | #define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) |
17576 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) |
17577 | #define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr ) |
17578 | #endif// CATCH_CONFIG_DISABLE_MATCHERS |
17579 | #define CATCH_REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ ) |
17580 | |
17581 | #define CATCH_CHECK( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) |
17582 | #define CATCH_CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) |
17583 | #define CATCH_CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CATCH_CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) |
17584 | #define CATCH_CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) |
17585 | #define CATCH_CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ ) |
17586 | |
17587 | #define CATCH_CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) |
17588 | #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) |
17589 | #define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) |
17590 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) |
17591 | #define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) |
17592 | #endif // CATCH_CONFIG_DISABLE_MATCHERS |
17593 | #define CATCH_CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) |
17594 | |
17595 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) |
17596 | #define CATCH_CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg ) |
17597 | |
17598 | #define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) |
17599 | #endif // CATCH_CONFIG_DISABLE_MATCHERS |
17600 | |
17601 | #define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg ) |
17602 | #define CATCH_UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "CATCH_UNSCOPED_INFO", msg ) |
17603 | #define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) |
17604 | #define CATCH_CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CATCH_CAPTURE",__VA_ARGS__ ) |
17605 | |
17606 | #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) |
17607 | #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) |
17608 | #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) |
17609 | #define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) |
17610 | #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) |
17611 | #define CATCH_DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ ) |
17612 | #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) |
17613 | #define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) |
17614 | #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) |
17615 | |
17616 | #define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE() |
17617 | |
17618 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
17619 | #define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) |
17620 | #define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ ) |
17621 | #define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) |
17622 | #define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) |
17623 | #define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) |
17624 | #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ ) |
17625 | #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) |
17626 | #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) |
17627 | #else |
17628 | #define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) ) |
17629 | #define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ ) ) |
17630 | #define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) ) |
17631 | #define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) ) |
17632 | #define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) ) |
17633 | #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ ) ) |
17634 | #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) ) |
17635 | #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) ) |
17636 | #endif |
17637 | |
17638 | #if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE) |
17639 | #define CATCH_STATIC_REQUIRE( ... ) static_assert( __VA_ARGS__ , #__VA_ARGS__ ); CATCH_SUCCEED( #__VA_ARGS__ ) |
17640 | #define CATCH_STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); CATCH_SUCCEED( #__VA_ARGS__ ) |
17641 | #else |
17642 | #define CATCH_STATIC_REQUIRE( ... ) CATCH_REQUIRE( __VA_ARGS__ ) |
17643 | #define CATCH_STATIC_REQUIRE_FALSE( ... ) CATCH_REQUIRE_FALSE( __VA_ARGS__ ) |
17644 | #endif |
17645 | |
17646 | // "BDD-style" convenience wrappers |
17647 | #define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ ) |
17648 | #define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) |
17649 | #define CATCH_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc ) |
17650 | #define CATCH_AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc ) |
17651 | #define CATCH_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc ) |
17652 | #define CATCH_AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc ) |
17653 | #define CATCH_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc ) |
17654 | #define CATCH_AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc ) |
17655 | |
17656 | #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) |
17657 | #define CATCH_BENCHMARK(...) \ |
17658 | 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__,,)) |
17659 | #define CATCH_BENCHMARK_ADVANCED(name) \ |
17660 | INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(C_A_T_C_H_B_E_N_C_H_), name) |
17661 | #endif // CATCH_CONFIG_ENABLE_BENCHMARKING |
17662 | |
17663 | // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required |
17664 | #else |
17665 | |
17666 | #define REQUIRE( ... ) INTERNAL_CATCH_TEST( "REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ ) |
17667 | #define REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) |
17668 | |
17669 | #define REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ ) |
17670 | #define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr ) |
17671 | #define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr ) |
17672 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) |
17673 | #define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr ) |
17674 | #endif // CATCH_CONFIG_DISABLE_MATCHERS |
17675 | #define REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ ) |
17676 | |
17677 | #define CHECK( ... ) INTERNAL_CATCH_TEST( "CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) |
17678 | #define CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ ) |
17679 | #define CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) |
17680 | #define CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) |
17681 | #define CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ ) |
17682 | |
17683 | #define CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) |
17684 | #define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr ) |
17685 | #define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) |
17686 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) |
17687 | #define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr ) |
17688 | #endif // CATCH_CONFIG_DISABLE_MATCHERS |
17689 | #define CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) |
17690 | |
17691 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) |
17692 | #define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg ) |
17693 | |
17694 | #define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg ) |
17695 | #endif // CATCH_CONFIG_DISABLE_MATCHERS |
17696 | |
17697 | #define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg ) |
17698 | #define UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "UNSCOPED_INFO", msg ) |
17699 | #define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg ) |
17700 | #define CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CAPTURE",__VA_ARGS__ ) |
17701 | |
17702 | #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) |
17703 | #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) |
17704 | #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) |
17705 | #define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ ) |
17706 | #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) |
17707 | #define DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ ) |
17708 | #define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ) |
17709 | #define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) |
17710 | #define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ ) |
17711 | #define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE() |
17712 | |
17713 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
17714 | #define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) |
17715 | #define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ ) |
17716 | #define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) |
17717 | #define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) |
17718 | #define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) |
17719 | #define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ ) |
17720 | #define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) |
17721 | #define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) |
17722 | #define TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE(__VA_ARGS__) |
17723 | #define TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ ) |
17724 | #else |
17725 | #define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) ) |
17726 | #define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ ) ) |
17727 | #define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) ) |
17728 | #define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) ) |
17729 | #define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) ) |
17730 | #define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ ) ) |
17731 | #define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) ) |
17732 | #define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) ) |
17733 | #define TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE( __VA_ARGS__ ) ) |
17734 | #define TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ ) ) |
17735 | #endif |
17736 | |
17737 | #if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE) |
17738 | #define STATIC_REQUIRE( ... ) static_assert( __VA_ARGS__, #__VA_ARGS__ ); SUCCEED( #__VA_ARGS__ ) |
17739 | #define STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); SUCCEED( "!(" #__VA_ARGS__ ")" ) |
17740 | #else |
17741 | #define STATIC_REQUIRE( ... ) REQUIRE( __VA_ARGS__ ) |
17742 | #define STATIC_REQUIRE_FALSE( ... ) REQUIRE_FALSE( __VA_ARGS__ ) |
17743 | #endif |
17744 | |
17745 | #endif |
17746 | |
17747 | #define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) |
17748 | |
17749 | // "BDD-style" convenience wrappers |
17750 | #define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ ) |
17751 | #define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) |
17752 | |
17753 | #define GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc ) |
17754 | #define AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc ) |
17755 | #define WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc ) |
17756 | #define AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc ) |
17757 | #define THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc ) |
17758 | #define AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc ) |
17759 | |
17760 | #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) |
17761 | #define BENCHMARK(...) \ |
17762 | 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__,,)) |
17763 | #define BENCHMARK_ADVANCED(name) \ |
17764 | INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(C_A_T_C_H_B_E_N_C_H_), name) |
17765 | #endif // CATCH_CONFIG_ENABLE_BENCHMARKING |
17766 | |
17767 | using Catch::Detail::Approx; |
17768 | |
17769 | #else // CATCH_CONFIG_DISABLE |
17770 | |
17771 | ////// |
17772 | // If this config identifier is defined then all CATCH macros are prefixed with CATCH_ |
17773 | #ifdef CATCH_CONFIG_PREFIX_ALL |
17774 | |
17775 | #define CATCH_REQUIRE( ... ) (void)(0) |
17776 | #define CATCH_REQUIRE_FALSE( ... ) (void)(0) |
17777 | |
17778 | #define CATCH_REQUIRE_THROWS( ... ) (void)(0) |
17779 | #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0) |
17780 | #define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) (void)(0) |
17781 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) |
17782 | #define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) |
17783 | #endif// CATCH_CONFIG_DISABLE_MATCHERS |
17784 | #define CATCH_REQUIRE_NOTHROW( ... ) (void)(0) |
17785 | |
17786 | #define CATCH_CHECK( ... ) (void)(0) |
17787 | #define CATCH_CHECK_FALSE( ... ) (void)(0) |
17788 | #define CATCH_CHECKED_IF( ... ) if (__VA_ARGS__) |
17789 | #define CATCH_CHECKED_ELSE( ... ) if (!(__VA_ARGS__)) |
17790 | #define CATCH_CHECK_NOFAIL( ... ) (void)(0) |
17791 | |
17792 | #define CATCH_CHECK_THROWS( ... ) (void)(0) |
17793 | #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) (void)(0) |
17794 | #define CATCH_CHECK_THROWS_WITH( expr, matcher ) (void)(0) |
17795 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) |
17796 | #define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) |
17797 | #endif // CATCH_CONFIG_DISABLE_MATCHERS |
17798 | #define CATCH_CHECK_NOTHROW( ... ) (void)(0) |
17799 | |
17800 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) |
17801 | #define CATCH_CHECK_THAT( arg, matcher ) (void)(0) |
17802 | |
17803 | #define CATCH_REQUIRE_THAT( arg, matcher ) (void)(0) |
17804 | #endif // CATCH_CONFIG_DISABLE_MATCHERS |
17805 | |
17806 | #define CATCH_INFO( msg ) (void)(0) |
17807 | #define CATCH_UNSCOPED_INFO( msg ) (void)(0) |
17808 | #define CATCH_WARN( msg ) (void)(0) |
17809 | #define CATCH_CAPTURE( msg ) (void)(0) |
17810 | |
17811 | #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) |
17812 | #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) |
17813 | #define CATCH_METHOD_AS_TEST_CASE( method, ... ) |
17814 | #define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0) |
17815 | #define CATCH_SECTION( ... ) |
17816 | #define CATCH_DYNAMIC_SECTION( ... ) |
17817 | #define CATCH_FAIL( ... ) (void)(0) |
17818 | #define CATCH_FAIL_CHECK( ... ) (void)(0) |
17819 | #define CATCH_SUCCEED( ... ) (void)(0) |
17820 | |
17821 | #define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) |
17822 | |
17823 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
17824 | #define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) |
17825 | #define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__) |
17826 | #define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__) |
17827 | #define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ ) |
17828 | #define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) |
17829 | #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) |
17830 | #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) |
17831 | #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) |
17832 | #else |
17833 | #define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) ) |
17834 | #define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__) ) |
17835 | #define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__ ) ) |
17836 | #define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ ) ) |
17837 | #define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) |
17838 | #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) |
17839 | #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) |
17840 | #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) |
17841 | #endif |
17842 | |
17843 | // "BDD-style" convenience wrappers |
17844 | #define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) |
17845 | #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 ) |
17846 | #define CATCH_GIVEN( desc ) |
17847 | #define CATCH_AND_GIVEN( desc ) |
17848 | #define CATCH_WHEN( desc ) |
17849 | #define CATCH_AND_WHEN( desc ) |
17850 | #define CATCH_THEN( desc ) |
17851 | #define CATCH_AND_THEN( desc ) |
17852 | |
17853 | #define CATCH_STATIC_REQUIRE( ... ) (void)(0) |
17854 | #define CATCH_STATIC_REQUIRE_FALSE( ... ) (void)(0) |
17855 | |
17856 | // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required |
17857 | #else |
17858 | |
17859 | #define REQUIRE( ... ) (void)(0) |
17860 | #define REQUIRE_FALSE( ... ) (void)(0) |
17861 | |
17862 | #define REQUIRE_THROWS( ... ) (void)(0) |
17863 | #define REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0) |
17864 | #define REQUIRE_THROWS_WITH( expr, matcher ) (void)(0) |
17865 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) |
17866 | #define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) |
17867 | #endif // CATCH_CONFIG_DISABLE_MATCHERS |
17868 | #define REQUIRE_NOTHROW( ... ) (void)(0) |
17869 | |
17870 | #define CHECK( ... ) (void)(0) |
17871 | #define CHECK_FALSE( ... ) (void)(0) |
17872 | #define CHECKED_IF( ... ) if (__VA_ARGS__) |
17873 | #define CHECKED_ELSE( ... ) if (!(__VA_ARGS__)) |
17874 | #define CHECK_NOFAIL( ... ) (void)(0) |
17875 | |
17876 | #define CHECK_THROWS( ... ) (void)(0) |
17877 | #define CHECK_THROWS_AS( expr, exceptionType ) (void)(0) |
17878 | #define CHECK_THROWS_WITH( expr, matcher ) (void)(0) |
17879 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) |
17880 | #define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0) |
17881 | #endif // CATCH_CONFIG_DISABLE_MATCHERS |
17882 | #define CHECK_NOTHROW( ... ) (void)(0) |
17883 | |
17884 | #if !defined(CATCH_CONFIG_DISABLE_MATCHERS) |
17885 | #define CHECK_THAT( arg, matcher ) (void)(0) |
17886 | |
17887 | #define REQUIRE_THAT( arg, matcher ) (void)(0) |
17888 | #endif // CATCH_CONFIG_DISABLE_MATCHERS |
17889 | |
17890 | #define INFO( msg ) (void)(0) |
17891 | #define UNSCOPED_INFO( msg ) (void)(0) |
17892 | #define WARN( msg ) (void)(0) |
17893 | #define CAPTURE( msg ) (void)(0) |
17894 | |
17895 | #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) |
17896 | #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) |
17897 | #define METHOD_AS_TEST_CASE( method, ... ) |
17898 | #define REGISTER_TEST_CASE( Function, ... ) (void)(0) |
17899 | #define SECTION( ... ) |
17900 | #define DYNAMIC_SECTION( ... ) |
17901 | #define FAIL( ... ) (void)(0) |
17902 | #define FAIL_CHECK( ... ) (void)(0) |
17903 | #define SUCCEED( ... ) (void)(0) |
17904 | #define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) |
17905 | |
17906 | #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR |
17907 | #define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) |
17908 | #define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__) |
17909 | #define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__) |
17910 | #define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ ) |
17911 | #define TEMPLATE_PRODUCT_TEST_CASE( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ ) |
17912 | #define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ ) |
17913 | #define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) |
17914 | #define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) |
17915 | #else |
17916 | #define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) ) |
17917 | #define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__) ) |
17918 | #define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__ ) ) |
17919 | #define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ ) ) |
17920 | #define TEMPLATE_PRODUCT_TEST_CASE( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ ) |
17921 | #define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ ) |
17922 | #define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) |
17923 | #define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) |
17924 | #endif |
17925 | |
17926 | #define STATIC_REQUIRE( ... ) (void)(0) |
17927 | #define STATIC_REQUIRE_FALSE( ... ) (void)(0) |
17928 | |
17929 | #endif |
17930 | |
17931 | #define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) |
17932 | |
17933 | // "BDD-style" convenience wrappers |
17934 | #define SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ) ) |
17935 | #define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ), className ) |
17936 | |
17937 | #define GIVEN( desc ) |
17938 | #define AND_GIVEN( desc ) |
17939 | #define WHEN( desc ) |
17940 | #define AND_WHEN( desc ) |
17941 | #define THEN( desc ) |
17942 | #define AND_THEN( desc ) |
17943 | |
17944 | using Catch::Detail::Approx; |
17945 | |
17946 | #endif |
17947 | |
17948 | #endif // ! CATCH_CONFIG_IMPL_ONLY |
17949 | |
17950 | // start catch_reenable_warnings.h |
17951 | |
17952 | |
17953 | #ifdef __clang__ |
17954 | # ifdef __ICC // icpc defines the __clang__ macro |
17955 | # pragma warning(pop) |
17956 | # else |
17957 | # pragma clang diagnostic pop |
17958 | # endif |
17959 | #elif defined __GNUC__ |
17960 | # pragma GCC diagnostic pop |
17961 | #endif |
17962 | |
17963 | // end catch_reenable_warnings.h |
17964 | // end catch.hpp |
17965 | #endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED |
17966 | |
17967 | |