home
readme
diff
tree
note
docs
0commit e50ea9e1356a74af18fdd171337ef9dc931e1f4e
1Author: Mason Wright <mason@lakefox.net>
2Date: Tue Jun 24 20:44:14 2025 -0600
3
4 Added tests to parser
5
6diff --git a/.gitignore b/.gitignore
7new file mode 100644
8index 0000000..18d2eaf
9--- /dev/null
10+++ b/.gitignore
11@@ -0,0 +1,2 @@
12+build/
13+main
14diff --git a/Makefile b/Makefile
15index 1260c17..714bc8e 100644
16--- a/Makefile
17+++ b/Makefile
18@@ -2,7 +2,7 @@
19 CCFLAGS = -Wall -Wextra -std=c++23
20 CC = clang++
21
22-.PHONY: all clean run docs
23+.PHONY: all clean run docs tests
24
25 all: main
26
27@@ -18,10 +18,17 @@ build/grim.o: src/grim.cc include/grim.h | build
28 build/parser.o: src/parser.cc include/parser.h | build
29 ${CC} ${CCFLAGS} -Iinclude/ -c src/parser.cc -o build/parser.o
30
31+tests: build/grim.o build/parser.o build/catch.o
32+ clear && ${CC} ${CCFLAGS} -Itests/ -Iinclude/ ./tests/main.cc ./build/grim.o ./build/parser.o ./build/catch.o -o ./tests/main && ./tests/main
33+
34+build/catch.o: ./tests/catch_amalgamated.cpp ./tests/catch_amalgamated.hpp | build
35+ ${CC} ${CCFLAGS} -Itests/ -c ./tests/catch_amalgamated.cpp -o build/catch.o
36+
37 clean:
38 rm -f main build/*.o
39
40 run:
41 clear && ./main
42+
43 docs:
44 cd ../build && ./git.sh && ./tracker.sh
45diff --git a/build/grim.o b/build/grim.o
46deleted file mode 100644
47index a655a9c..0000000
48Binary files a/build/grim.o and /dev/null differ
49diff --git a/build/parser.o b/build/parser.o
50deleted file mode 100644
51index 4be662f..0000000
52Binary files a/build/parser.o and /dev/null differ
53diff --git a/index.html b/index.html
54index 3284123..289b7f3 100644
55--- a/index.html
56+++ b/index.html
57@@ -4,6 +4,7 @@
58 <style>
59 h1 {
60 color: red;
61+ content: "<h1>hi</h1>";
62 }
63 </style>
64 </head>
65@@ -16,5 +17,9 @@
66 <p id="test">
67 this is a test
68 </p>
69+ <pre>
70+ <script> console.log("</pre>");</script>
71+ </pre>
72+ <textarea><script>console.log(\"</pre>\");</script></textarea>
73 </body>
74 </html>
75diff --git a/main b/main
76deleted file mode 100755
77index f079efc..0000000
78Binary files a/main and /dev/null differ
79diff --git a/tests/catch_amalgamated.cpp b/tests/catch_amalgamated.cpp
80new file mode 100644
81index 0000000..6aa6788
82--- /dev/null
83+++ b/tests/catch_amalgamated.cpp
84@@ -0,0 +1,11520 @@
85+
86+// Copyright Catch2 Authors
87+// Distributed under the Boost Software License, Version 1.0.
88+// (See accompanying file LICENSE.txt or copy at
89+// https://www.boost.org/LICENSE_1_0.txt)
90+
91+// SPDX-License-Identifier: BSL-1.0
92+
93+// Catch v3.5.4
94+// Generated: 2024-04-10 12:03:46.281848
95+// ----------------------------------------------------------
96+// This file is an amalgamation of multiple different files.
97+// You probably shouldn't edit it directly.
98+// ----------------------------------------------------------
99+
100+#include "catch_amalgamated.hpp"
101+
102+
103+#ifndef CATCH_WINDOWS_H_PROXY_HPP_INCLUDED
104+#define CATCH_WINDOWS_H_PROXY_HPP_INCLUDED
105+
106+
107+#if defined(CATCH_PLATFORM_WINDOWS)
108+
109+// We might end up with the define made globally through the compiler,
110+// and we don't want to trigger warnings for this
111+#if !defined(NOMINMAX)
112+# define NOMINMAX
113+#endif
114+#if !defined(WIN32_LEAN_AND_MEAN)
115+# define WIN32_LEAN_AND_MEAN
116+#endif
117+
118+#include <windows.h>
119+
120+#endif // defined(CATCH_PLATFORM_WINDOWS)
121+
122+#endif // CATCH_WINDOWS_H_PROXY_HPP_INCLUDED
123+
124+
125+
126+
127+namespace Catch {
128+ namespace Benchmark {
129+ namespace Detail {
130+ ChronometerConcept::~ChronometerConcept() = default;
131+ } // namespace Detail
132+ } // namespace Benchmark
133+} // namespace Catch
134+
135+
136+// Adapted from donated nonius code.
137+
138+
139+#include <vector>
140+
141+namespace Catch {
142+ namespace Benchmark {
143+ namespace Detail {
144+ SampleAnalysis analyse(const IConfig &cfg, FDuration* first, FDuration* last) {
145+ if (!cfg.benchmarkNoAnalysis()) {
146+ std::vector<double> samples;
147+ samples.reserve(static_cast<size_t>(last - first));
148+ for (auto current = first; current != last; ++current) {
149+ samples.push_back( current->count() );
150+ }
151+
152+ auto analysis = Catch::Benchmark::Detail::analyse_samples(
153+ cfg.benchmarkConfidenceInterval(),
154+ cfg.benchmarkResamples(),
155+ samples.data(),
156+ samples.data() + samples.size() );
157+ auto outliers = Catch::Benchmark::Detail::classify_outliers(
158+ samples.data(), samples.data() + samples.size() );
159+
160+ auto wrap_estimate = [](Estimate<double> e) {
161+ return Estimate<FDuration> {
162+ FDuration(e.point),
163+ FDuration(e.lower_bound),
164+ FDuration(e.upper_bound),
165+ e.confidence_interval,
166+ };
167+ };
168+ std::vector<FDuration> samples2;
169+ samples2.reserve(samples.size());
170+ for (auto s : samples) {
171+ samples2.push_back( FDuration( s ) );
172+ }
173+
174+ return {
175+ CATCH_MOVE(samples2),
176+ wrap_estimate(analysis.mean),
177+ wrap_estimate(analysis.standard_deviation),
178+ outliers,
179+ analysis.outlier_variance,
180+ };
181+ } else {
182+ std::vector<FDuration> samples;
183+ samples.reserve(static_cast<size_t>(last - first));
184+
185+ FDuration mean = FDuration(0);
186+ int i = 0;
187+ for (auto it = first; it < last; ++it, ++i) {
188+ samples.push_back(*it);
189+ mean += *it;
190+ }
191+ mean /= i;
192+
193+ return SampleAnalysis{
194+ CATCH_MOVE(samples),
195+ Estimate<FDuration>{ mean, mean, mean, 0.0 },
196+ Estimate<FDuration>{ FDuration( 0 ),
197+ FDuration( 0 ),
198+ FDuration( 0 ),
199+ 0.0 },
200+ OutlierClassification{},
201+ 0.0
202+ };
203+ }
204+ }
205+ } // namespace Detail
206+ } // namespace Benchmark
207+} // namespace Catch
208+
209+
210+
211+
212+namespace Catch {
213+ namespace Benchmark {
214+ namespace Detail {
215+ BenchmarkFunction::callable::~callable() = default;
216+ } // namespace Detail
217+ } // namespace Benchmark
218+} // namespace Catch
219+
220+
221+
222+
223+#include <exception>
224+
225+namespace Catch {
226+ namespace Benchmark {
227+ namespace Detail {
228+ struct optimized_away_error : std::exception {
229+ const char* what() const noexcept override;
230+ };
231+
232+ const char* optimized_away_error::what() const noexcept {
233+ return "could not measure benchmark, maybe it was optimized away";
234+ }
235+
236+ void throw_optimized_away_error() {
237+ Catch::throw_exception(optimized_away_error{});
238+ }
239+
240+ } // namespace Detail
241+ } // namespace Benchmark
242+} // namespace Catch
243+
244+
245+// Adapted from donated nonius code.
246+
247+
248+
249+#include <algorithm>
250+#include <cassert>
251+#include <cmath>
252+#include <cstddef>
253+#include <numeric>
254+#include <random>
255+
256+
257+#if defined(CATCH_CONFIG_USE_ASYNC)
258+#include <future>
259+#endif
260+
261+namespace Catch {
262+ namespace Benchmark {
263+ namespace Detail {
264+ namespace {
265+
266+ template <typename URng, typename Estimator>
267+ static sample
268+ resample( URng& rng,
269+ unsigned int resamples,
270+ double const* first,
271+ double const* last,
272+ Estimator& estimator ) {
273+ auto n = static_cast<size_t>( last - first );
274+ Catch::uniform_integer_distribution<size_t> dist( 0, n - 1 );
275+
276+ sample out;
277+ out.reserve( resamples );
278+ std::vector<double> resampled;
279+ resampled.reserve( n );
280+ for ( size_t i = 0; i < resamples; ++i ) {
281+ resampled.clear();
282+ for ( size_t s = 0; s < n; ++s ) {
283+ resampled.push_back( first[dist( rng )] );
284+ }
285+ const auto estimate =
286+ estimator( resampled.data(), resampled.data() + resampled.size() );
287+ out.push_back( estimate );
288+ }
289+ std::sort( out.begin(), out.end() );
290+ return out;
291+ }
292+
293+ static double outlier_variance( Estimate<double> mean,
294+ Estimate<double> stddev,
295+ int n ) {
296+ double sb = stddev.point;
297+ double mn = mean.point / n;
298+ double mg_min = mn / 2.;
299+ double sg = (std::min)( mg_min / 4., sb / std::sqrt( n ) );
300+ double sg2 = sg * sg;
301+ double sb2 = sb * sb;
302+
303+ auto c_max = [n, mn, sb2, sg2]( double x ) -> double {
304+ double k = mn - x;
305+ double d = k * k;
306+ double nd = n * d;
307+ double k0 = -n * nd;
308+ double k1 = sb2 - n * sg2 + nd;
309+ double det = k1 * k1 - 4 * sg2 * k0;
310+ return static_cast<int>( -2. * k0 /
311+ ( k1 + std::sqrt( det ) ) );
312+ };
313+
314+ auto var_out = [n, sb2, sg2]( double c ) {
315+ double nc = n - c;
316+ return ( nc / n ) * ( sb2 - nc * sg2 );
317+ };
318+
319+ return (std::min)( var_out( 1 ),
320+ var_out(
321+ (std::min)( c_max( 0. ),
322+ c_max( mg_min ) ) ) ) /
323+ sb2;
324+ }
325+
326+ static double erf_inv( double x ) {
327+ // Code accompanying the article "Approximating the erfinv
328+ // function" in GPU Computing Gems, Volume 2
329+ double w, p;
330+
331+ w = -log( ( 1.0 - x ) * ( 1.0 + x ) );
332+
333+ if ( w < 6.250000 ) {
334+ w = w - 3.125000;
335+ p = -3.6444120640178196996e-21;
336+ p = -1.685059138182016589e-19 + p * w;
337+ p = 1.2858480715256400167e-18 + p * w;
338+ p = 1.115787767802518096e-17 + p * w;
339+ p = -1.333171662854620906e-16 + p * w;
340+ p = 2.0972767875968561637e-17 + p * w;
341+ p = 6.6376381343583238325e-15 + p * w;
342+ p = -4.0545662729752068639e-14 + p * w;
343+ p = -8.1519341976054721522e-14 + p * w;
344+ p = 2.6335093153082322977e-12 + p * w;
345+ p = -1.2975133253453532498e-11 + p * w;
346+ p = -5.4154120542946279317e-11 + p * w;
347+ p = 1.051212273321532285e-09 + p * w;
348+ p = -4.1126339803469836976e-09 + p * w;
349+ p = -2.9070369957882005086e-08 + p * w;
350+ p = 4.2347877827932403518e-07 + p * w;
351+ p = -1.3654692000834678645e-06 + p * w;
352+ p = -1.3882523362786468719e-05 + p * w;
353+ p = 0.0001867342080340571352 + p * w;
354+ p = -0.00074070253416626697512 + p * w;
355+ p = -0.0060336708714301490533 + p * w;
356+ p = 0.24015818242558961693 + p * w;
357+ p = 1.6536545626831027356 + p * w;
358+ } else if ( w < 16.000000 ) {
359+ w = sqrt( w ) - 3.250000;
360+ p = 2.2137376921775787049e-09;
361+ p = 9.0756561938885390979e-08 + p * w;
362+ p = -2.7517406297064545428e-07 + p * w;
363+ p = 1.8239629214389227755e-08 + p * w;
364+ p = 1.5027403968909827627e-06 + p * w;
365+ p = -4.013867526981545969e-06 + p * w;
366+ p = 2.9234449089955446044e-06 + p * w;
367+ p = 1.2475304481671778723e-05 + p * w;
368+ p = -4.7318229009055733981e-05 + p * w;
369+ p = 6.8284851459573175448e-05 + p * w;
370+ p = 2.4031110387097893999e-05 + p * w;
371+ p = -0.0003550375203628474796 + p * w;
372+ p = 0.00095328937973738049703 + p * w;
373+ p = -0.0016882755560235047313 + p * w;
374+ p = 0.0024914420961078508066 + p * w;
375+ p = -0.0037512085075692412107 + p * w;
376+ p = 0.005370914553590063617 + p * w;
377+ p = 1.0052589676941592334 + p * w;
378+ p = 3.0838856104922207635 + p * w;
379+ } else {
380+ w = sqrt( w ) - 5.000000;
381+ p = -2.7109920616438573243e-11;
382+ p = -2.5556418169965252055e-10 + p * w;
383+ p = 1.5076572693500548083e-09 + p * w;
384+ p = -3.7894654401267369937e-09 + p * w;
385+ p = 7.6157012080783393804e-09 + p * w;
386+ p = -1.4960026627149240478e-08 + p * w;
387+ p = 2.9147953450901080826e-08 + p * w;
388+ p = -6.7711997758452339498e-08 + p * w;
389+ p = 2.2900482228026654717e-07 + p * w;
390+ p = -9.9298272942317002539e-07 + p * w;
391+ p = 4.5260625972231537039e-06 + p * w;
392+ p = -1.9681778105531670567e-05 + p * w;
393+ p = 7.5995277030017761139e-05 + p * w;
394+ p = -0.00021503011930044477347 + p * w;
395+ p = -0.00013871931833623122026 + p * w;
396+ p = 1.0103004648645343977 + p * w;
397+ p = 4.8499064014085844221 + p * w;
398+ }
399+ return p * x;
400+ }
401+
402+ static double
403+ standard_deviation( double const* first, double const* last ) {
404+ auto m = Catch::Benchmark::Detail::mean( first, last );
405+ double variance =
406+ std::accumulate( first,
407+ last,
408+ 0.,
409+ [m]( double a, double b ) {
410+ double diff = b - m;
411+ return a + diff * diff;
412+ } ) /
413+ ( last - first );
414+ return std::sqrt( variance );
415+ }
416+
417+ static sample jackknife( double ( *estimator )( double const*,
418+ double const* ),
419+ double* first,
420+ double* last ) {
421+ const auto second = first + 1;
422+ sample results;
423+ results.reserve( static_cast<size_t>( last - first ) );
424+
425+ for ( auto it = first; it != last; ++it ) {
426+ std::iter_swap( it, first );
427+ results.push_back( estimator( second, last ) );
428+ }
429+
430+ return results;
431+ }
432+
433+
434+ } // namespace
435+ } // namespace Detail
436+ } // namespace Benchmark
437+} // namespace Catch
438+
439+namespace Catch {
440+ namespace Benchmark {
441+ namespace Detail {
442+
443+ double weighted_average_quantile( int k,
444+ int q,
445+ double* first,
446+ double* last ) {
447+ auto count = last - first;
448+ double idx = (count - 1) * k / static_cast<double>(q);
449+ int j = static_cast<int>(idx);
450+ double g = idx - j;
451+ std::nth_element(first, first + j, last);
452+ auto xj = first[j];
453+ if ( Catch::Detail::directCompare( g, 0 ) ) {
454+ return xj;
455+ }
456+
457+ auto xj1 = *std::min_element(first + (j + 1), last);
458+ return xj + g * (xj1 - xj);
459+ }
460+
461+ OutlierClassification
462+ classify_outliers( double const* first, double const* last ) {
463+ std::vector<double> copy( first, last );
464+
465+ auto q1 = weighted_average_quantile( 1, 4, copy.data(), copy.data() + copy.size() );
466+ auto q3 = weighted_average_quantile( 3, 4, copy.data(), copy.data() + copy.size() );
467+ auto iqr = q3 - q1;
468+ auto los = q1 - ( iqr * 3. );
469+ auto lom = q1 - ( iqr * 1.5 );
470+ auto him = q3 + ( iqr * 1.5 );
471+ auto his = q3 + ( iqr * 3. );
472+
473+ OutlierClassification o;
474+ for ( ; first != last; ++first ) {
475+ const double t = *first;
476+ if ( t < los ) {
477+ ++o.low_severe;
478+ } else if ( t < lom ) {
479+ ++o.low_mild;
480+ } else if ( t > his ) {
481+ ++o.high_severe;
482+ } else if ( t > him ) {
483+ ++o.high_mild;
484+ }
485+ ++o.samples_seen;
486+ }
487+ return o;
488+ }
489+
490+ double mean( double const* first, double const* last ) {
491+ auto count = last - first;
492+ double sum = 0.;
493+ while (first != last) {
494+ sum += *first;
495+ ++first;
496+ }
497+ return sum / static_cast<double>(count);
498+ }
499+
500+ double normal_cdf( double x ) {
501+ return std::erfc( -x / std::sqrt( 2.0 ) ) / 2.0;
502+ }
503+
504+ double erfc_inv(double x) {
505+ return erf_inv(1.0 - x);
506+ }
507+
508+ double normal_quantile(double p) {
509+ static const double ROOT_TWO = std::sqrt(2.0);
510+
511+ double result = 0.0;
512+ assert(p >= 0 && p <= 1);
513+ if (p < 0 || p > 1) {
514+ return result;
515+ }
516+
517+ result = -erfc_inv(2.0 * p);
518+ // result *= normal distribution standard deviation (1.0) * sqrt(2)
519+ result *= /*sd * */ ROOT_TWO;
520+ // result += normal disttribution mean (0)
521+ return result;
522+ }
523+
524+ Estimate<double>
525+ bootstrap( double confidence_level,
526+ double* first,
527+ double* last,
528+ sample const& resample,
529+ double ( *estimator )( double const*, double const* ) ) {
530+ auto n_samples = last - first;
531+
532+ double point = estimator( first, last );
533+ // Degenerate case with a single sample
534+ if ( n_samples == 1 )
535+ return { point, point, point, confidence_level };
536+
537+ sample jack = jackknife( estimator, first, last );
538+ double jack_mean =
539+ mean( jack.data(), jack.data() + jack.size() );
540+ double sum_squares = 0, sum_cubes = 0;
541+ for ( double x : jack ) {
542+ auto difference = jack_mean - x;
543+ auto square = difference * difference;
544+ auto cube = square * difference;
545+ sum_squares += square;
546+ sum_cubes += cube;
547+ }
548+
549+ double accel = sum_cubes / ( 6 * std::pow( sum_squares, 1.5 ) );
550+ long n = static_cast<long>( resample.size() );
551+ double prob_n =
552+ std::count_if( resample.begin(),
553+ resample.end(),
554+ [point]( double x ) { return x < point; } ) /
555+ static_cast<double>( n );
556+ // degenerate case with uniform samples
557+ if ( Catch::Detail::directCompare( prob_n, 0. ) ) {
558+ return { point, point, point, confidence_level };
559+ }
560+
561+ double bias = normal_quantile( prob_n );
562+ double z1 = normal_quantile( ( 1. - confidence_level ) / 2. );
563+
564+ auto cumn = [n]( double x ) -> long {
565+ return std::lround( normal_cdf( x ) *
566+ static_cast<double>( n ) );
567+ };
568+ auto a = [bias, accel]( double b ) {
569+ return bias + b / ( 1. - accel * b );
570+ };
571+ double b1 = bias + z1;
572+ double b2 = bias - z1;
573+ double a1 = a( b1 );
574+ double a2 = a( b2 );
575+ auto lo = static_cast<size_t>( (std::max)( cumn( a1 ), 0l ) );
576+ auto hi =
577+ static_cast<size_t>( (std::min)( cumn( a2 ), n - 1 ) );
578+
579+ return { point, resample[lo], resample[hi], confidence_level };
580+ }
581+
582+ bootstrap_analysis analyse_samples(double confidence_level,
583+ unsigned int n_resamples,
584+ double* first,
585+ double* last) {
586+ auto mean = &Detail::mean;
587+ auto stddev = &standard_deviation;
588+
589+#if defined(CATCH_CONFIG_USE_ASYNC)
590+ auto Estimate = [=](double(*f)(double const*, double const*)) {
591+ std::random_device rd;
592+ auto seed = rd();
593+ return std::async(std::launch::async, [=] {
594+ SimplePcg32 rng( seed );
595+ auto resampled = resample(rng, n_resamples, first, last, f);
596+ return bootstrap(confidence_level, first, last, resampled, f);
597+ });
598+ };
599+
600+ auto mean_future = Estimate(mean);
601+ auto stddev_future = Estimate(stddev);
602+
603+ auto mean_estimate = mean_future.get();
604+ auto stddev_estimate = stddev_future.get();
605+#else
606+ auto Estimate = [=](double(*f)(double const* , double const*)) {
607+ std::random_device rd;
608+ auto seed = rd();
609+ SimplePcg32 rng( seed );
610+ auto resampled = resample(rng, n_resamples, first, last, f);
611+ return bootstrap(confidence_level, first, last, resampled, f);
612+ };
613+
614+ auto mean_estimate = Estimate(mean);
615+ auto stddev_estimate = Estimate(stddev);
616+#endif // CATCH_USE_ASYNC
617+
618+ auto n = static_cast<int>(last - first); // seriously, one can't use integral types without hell in C++
619+ double outlier_variance = Detail::outlier_variance(mean_estimate, stddev_estimate, n);
620+
621+ return { mean_estimate, stddev_estimate, outlier_variance };
622+ }
623+ } // namespace Detail
624+ } // namespace Benchmark
625+} // namespace Catch
626+
627+
628+
629+#include <cmath>
630+#include <limits>
631+
632+namespace {
633+
634+// Performs equivalent check of std::fabs(lhs - rhs) <= margin
635+// But without the subtraction to allow for INFINITY in comparison
636+bool marginComparison(double lhs, double rhs, double margin) {
637+ return (lhs + margin >= rhs) && (rhs + margin >= lhs);
638+}
639+
640+}
641+
642+namespace Catch {
643+
644+ Approx::Approx ( double value )
645+ : m_epsilon( static_cast<double>(std::numeric_limits<float>::epsilon())*100. ),
646+ m_margin( 0.0 ),
647+ m_scale( 0.0 ),
648+ m_value( value )
649+ {}
650+
651+ Approx Approx::custom() {
652+ return Approx( 0 );
653+ }
654+
655+ Approx Approx::operator-() const {
656+ auto temp(*this);
657+ temp.m_value = -temp.m_value;
658+ return temp;
659+ }
660+
661+
662+ std::string Approx::toString() const {
663+ ReusableStringStream rss;
664+ rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )";
665+ return rss.str();
666+ }
667+
668+ bool Approx::equalityComparisonImpl(const double other) const {
669+ // First try with fixed margin, then compute margin based on epsilon, scale and Approx's value
670+ // Thanks to Richard Harris for his help refining the scaled margin value
671+ return marginComparison(m_value, other, m_margin)
672+ || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(std::isinf(m_value)? 0 : m_value)));
673+ }
674+
675+ void Approx::setMargin(double newMargin) {
676+ CATCH_ENFORCE(newMargin >= 0,
677+ "Invalid Approx::margin: " << newMargin << '.'
678+ << " Approx::Margin has to be non-negative.");
679+ m_margin = newMargin;
680+ }
681+
682+ void Approx::setEpsilon(double newEpsilon) {
683+ CATCH_ENFORCE(newEpsilon >= 0 && newEpsilon <= 1.0,
684+ "Invalid Approx::epsilon: " << newEpsilon << '.'
685+ << " Approx::epsilon has to be in [0, 1]");
686+ m_epsilon = newEpsilon;
687+ }
688+
689+namespace literals {
690+ Approx operator ""_a(long double val) {
691+ return Approx(val);
692+ }
693+ Approx operator ""_a(unsigned long long val) {
694+ return Approx(val);
695+ }
696+} // end namespace literals
697+
698+std::string StringMaker<Catch::Approx>::convert(Catch::Approx const& value) {
699+ return value.toString();
700+}
701+
702+} // end namespace Catch
703+
704+
705+
706+namespace Catch {
707+
708+ AssertionResultData::AssertionResultData(ResultWas::OfType _resultType, LazyExpression const & _lazyExpression):
709+ lazyExpression(_lazyExpression),
710+ resultType(_resultType) {}
711+
712+ std::string AssertionResultData::reconstructExpression() const {
713+
714+ if( reconstructedExpression.empty() ) {
715+ if( lazyExpression ) {
716+ ReusableStringStream rss;
717+ rss << lazyExpression;
718+ reconstructedExpression = rss.str();
719+ }
720+ }
721+ return reconstructedExpression;
722+ }
723+
724+ AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData&& data )
725+ : m_info( info ),
726+ m_resultData( CATCH_MOVE(data) )
727+ {}
728+
729+ // Result was a success
730+ bool AssertionResult::succeeded() const {
731+ return Catch::isOk( m_resultData.resultType );
732+ }
733+
734+ // Result was a success, or failure is suppressed
735+ bool AssertionResult::isOk() const {
736+ return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition );
737+ }
738+
739+ ResultWas::OfType AssertionResult::getResultType() const {
740+ return m_resultData.resultType;
741+ }
742+
743+ bool AssertionResult::hasExpression() const {
744+ return !m_info.capturedExpression.empty();
745+ }
746+
747+ bool AssertionResult::hasMessage() const {
748+ return !m_resultData.message.empty();
749+ }
750+
751+ std::string AssertionResult::getExpression() const {
752+ // Possibly overallocating by 3 characters should be basically free
753+ std::string expr; expr.reserve(m_info.capturedExpression.size() + 3);
754+ if (isFalseTest(m_info.resultDisposition)) {
755+ expr += "!(";
756+ }
757+ expr += m_info.capturedExpression;
758+ if (isFalseTest(m_info.resultDisposition)) {
759+ expr += ')';
760+ }
761+ return expr;
762+ }
763+
764+ std::string AssertionResult::getExpressionInMacro() const {
765+ if ( m_info.macroName.empty() ) {
766+ return static_cast<std::string>( m_info.capturedExpression );
767+ }
768+ std::string expr;
769+ expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 );
770+ expr += m_info.macroName;
771+ expr += "( ";
772+ expr += m_info.capturedExpression;
773+ expr += " )";
774+ return expr;
775+ }
776+
777+ bool AssertionResult::hasExpandedExpression() const {
778+ return hasExpression() && getExpandedExpression() != getExpression();
779+ }
780+
781+ std::string AssertionResult::getExpandedExpression() const {
782+ std::string expr = m_resultData.reconstructExpression();
783+ return expr.empty()
784+ ? getExpression()
785+ : expr;
786+ }
787+
788+ StringRef AssertionResult::getMessage() const {
789+ return m_resultData.message;
790+ }
791+ SourceLineInfo AssertionResult::getSourceInfo() const {
792+ return m_info.lineInfo;
793+ }
794+
795+ StringRef AssertionResult::getTestMacroName() const {
796+ return m_info.macroName;
797+ }
798+
799+} // end namespace Catch
800+
801+
802+
803+#include <fstream>
804+
805+namespace Catch {
806+
807+ namespace {
808+ static bool enableBazelEnvSupport() {
809+#if defined( CATCH_CONFIG_BAZEL_SUPPORT )
810+ return true;
811+#else
812+ return Detail::getEnv( "BAZEL_TEST" ) != nullptr;
813+#endif
814+ }
815+
816+ struct bazelShardingOptions {
817+ unsigned int shardIndex, shardCount;
818+ std::string shardFilePath;
819+ };
820+
821+ static Optional<bazelShardingOptions> readBazelShardingOptions() {
822+ const auto bazelShardIndex = Detail::getEnv( "TEST_SHARD_INDEX" );
823+ const auto bazelShardTotal = Detail::getEnv( "TEST_TOTAL_SHARDS" );
824+ const auto bazelShardInfoFile = Detail::getEnv( "TEST_SHARD_STATUS_FILE" );
825+
826+
827+ const bool has_all =
828+ bazelShardIndex && bazelShardTotal && bazelShardInfoFile;
829+ if ( !has_all ) {
830+ // We provide nice warning message if the input is
831+ // misconfigured.
832+ auto warn = []( const char* env_var ) {
833+ Catch::cerr()
834+ << "Warning: Bazel shard configuration is missing '"
835+ << env_var << "'. Shard configuration is skipped.\n";
836+ };
837+ if ( !bazelShardIndex ) {
838+ warn( "TEST_SHARD_INDEX" );
839+ }
840+ if ( !bazelShardTotal ) {
841+ warn( "TEST_TOTAL_SHARDS" );
842+ }
843+ if ( !bazelShardInfoFile ) {
844+ warn( "TEST_SHARD_STATUS_FILE" );
845+ }
846+ return {};
847+ }
848+
849+ auto shardIndex = parseUInt( bazelShardIndex );
850+ if ( !shardIndex ) {
851+ Catch::cerr()
852+ << "Warning: could not parse 'TEST_SHARD_INDEX' ('" << bazelShardIndex
853+ << "') as unsigned int.\n";
854+ return {};
855+ }
856+ auto shardTotal = parseUInt( bazelShardTotal );
857+ if ( !shardTotal ) {
858+ Catch::cerr()
859+ << "Warning: could not parse 'TEST_TOTAL_SHARD' ('"
860+ << bazelShardTotal << "') as unsigned int.\n";
861+ return {};
862+ }
863+
864+ return bazelShardingOptions{
865+ *shardIndex, *shardTotal, bazelShardInfoFile };
866+
867+ }
868+ } // end namespace
869+
870+
871+ bool operator==( ProcessedReporterSpec const& lhs,
872+ ProcessedReporterSpec const& rhs ) {
873+ return lhs.name == rhs.name &&
874+ lhs.outputFilename == rhs.outputFilename &&
875+ lhs.colourMode == rhs.colourMode &&
876+ lhs.customOptions == rhs.customOptions;
877+ }
878+
879+ Config::Config( ConfigData const& data ):
880+ m_data( data ) {
881+ // We need to trim filter specs to avoid trouble with superfluous
882+ // whitespace (esp. important for bdd macros, as those are manually
883+ // aligned with whitespace).
884+
885+ for (auto& elem : m_data.testsOrTags) {
886+ elem = trim(elem);
887+ }
888+ for (auto& elem : m_data.sectionsToRun) {
889+ elem = trim(elem);
890+ }
891+
892+ // Insert the default reporter if user hasn't asked for a specific one
893+ if ( m_data.reporterSpecifications.empty() ) {
894+#if defined( CATCH_CONFIG_DEFAULT_REPORTER )
895+ const auto default_spec = CATCH_CONFIG_DEFAULT_REPORTER;
896+#else
897+ const auto default_spec = "console";
898+#endif
899+ auto parsed = parseReporterSpec(default_spec);
900+ CATCH_ENFORCE( parsed,
901+ "Cannot parse the provided default reporter spec: '"
902+ << default_spec << '\'' );
903+ m_data.reporterSpecifications.push_back( std::move( *parsed ) );
904+ }
905+
906+ if ( enableBazelEnvSupport() ) {
907+ readBazelEnvVars();
908+ }
909+
910+ // Bazel support can modify the test specs, so parsing has to happen
911+ // after reading Bazel env vars.
912+ TestSpecParser parser( ITagAliasRegistry::get() );
913+ if ( !m_data.testsOrTags.empty() ) {
914+ m_hasTestFilters = true;
915+ for ( auto const& testOrTags : m_data.testsOrTags ) {
916+ parser.parse( testOrTags );
917+ }
918+ }
919+ m_testSpec = parser.testSpec();
920+
921+
922+ // We now fixup the reporter specs to handle default output spec,
923+ // default colour spec, etc
924+ bool defaultOutputUsed = false;
925+ for ( auto const& reporterSpec : m_data.reporterSpecifications ) {
926+ // We do the default-output check separately, while always
927+ // using the default output below to make the code simpler
928+ // and avoid superfluous copies.
929+ if ( reporterSpec.outputFile().none() ) {
930+ CATCH_ENFORCE( !defaultOutputUsed,
931+ "Internal error: cannot use default output for "
932+ "multiple reporters" );
933+ defaultOutputUsed = true;
934+ }
935+
936+ m_processedReporterSpecs.push_back( ProcessedReporterSpec{
937+ reporterSpec.name(),
938+ reporterSpec.outputFile() ? *reporterSpec.outputFile()
939+ : data.defaultOutputFilename,
940+ reporterSpec.colourMode().valueOr( data.defaultColourMode ),
941+ reporterSpec.customOptions() } );
942+ }
943+ }
944+
945+ Config::~Config() = default;
946+
947+
948+ bool Config::listTests() const { return m_data.listTests; }
949+ bool Config::listTags() const { return m_data.listTags; }
950+ bool Config::listReporters() const { return m_data.listReporters; }
951+ bool Config::listListeners() const { return m_data.listListeners; }
952+
953+ std::vector<std::string> const& Config::getTestsOrTags() const { return m_data.testsOrTags; }
954+ std::vector<std::string> const& Config::getSectionsToRun() const { return m_data.sectionsToRun; }
955+
956+ std::vector<ReporterSpec> const& Config::getReporterSpecs() const {
957+ return m_data.reporterSpecifications;
958+ }
959+
960+ std::vector<ProcessedReporterSpec> const&
961+ Config::getProcessedReporterSpecs() const {
962+ return m_processedReporterSpecs;
963+ }
964+
965+ TestSpec const& Config::testSpec() const { return m_testSpec; }
966+ bool Config::hasTestFilters() const { return m_hasTestFilters; }
967+
968+ bool Config::showHelp() const { return m_data.showHelp; }
969+
970+ // IConfig interface
971+ bool Config::allowThrows() const { return !m_data.noThrow; }
972+ StringRef Config::name() const { return m_data.name.empty() ? m_data.processName : m_data.name; }
973+ bool Config::includeSuccessfulResults() const { return m_data.showSuccessfulTests; }
974+ bool Config::warnAboutMissingAssertions() const {
975+ return !!( m_data.warnings & WarnAbout::NoAssertions );
976+ }
977+ bool Config::warnAboutUnmatchedTestSpecs() const {
978+ return !!( m_data.warnings & WarnAbout::UnmatchedTestSpec );
979+ }
980+ bool Config::zeroTestsCountAsSuccess() const { return m_data.allowZeroTests; }
981+ ShowDurations Config::showDurations() const { return m_data.showDurations; }
982+ double Config::minDuration() const { return m_data.minDuration; }
983+ TestRunOrder Config::runOrder() const { return m_data.runOrder; }
984+ uint32_t Config::rngSeed() const { return m_data.rngSeed; }
985+ unsigned int Config::shardCount() const { return m_data.shardCount; }
986+ unsigned int Config::shardIndex() const { return m_data.shardIndex; }
987+ ColourMode Config::defaultColourMode() const { return m_data.defaultColourMode; }
988+ bool Config::shouldDebugBreak() const { return m_data.shouldDebugBreak; }
989+ int Config::abortAfter() const { return m_data.abortAfter; }
990+ bool Config::showInvisibles() const { return m_data.showInvisibles; }
991+ Verbosity Config::verbosity() const { return m_data.verbosity; }
992+
993+ bool Config::skipBenchmarks() const { return m_data.skipBenchmarks; }
994+ bool Config::benchmarkNoAnalysis() const { return m_data.benchmarkNoAnalysis; }
995+ unsigned int Config::benchmarkSamples() const { return m_data.benchmarkSamples; }
996+ double Config::benchmarkConfidenceInterval() const { return m_data.benchmarkConfidenceInterval; }
997+ unsigned int Config::benchmarkResamples() const { return m_data.benchmarkResamples; }
998+ std::chrono::milliseconds Config::benchmarkWarmupTime() const { return std::chrono::milliseconds(m_data.benchmarkWarmupTime); }
999+
1000+ void Config::readBazelEnvVars() {
1001+ // Register a JUnit reporter for Bazel. Bazel sets an environment
1002+ // variable with the path to XML output. If this file is written to
1003+ // during test, Bazel will not generate a default XML output.
1004+ // This allows the XML output file to contain higher level of detail
1005+ // than what is possible otherwise.
1006+ const auto bazelOutputFile = Detail::getEnv( "XML_OUTPUT_FILE" );
1007+
1008+ if ( bazelOutputFile ) {
1009+ m_data.reporterSpecifications.push_back(
1010+ { "junit", std::string( bazelOutputFile ), {}, {} } );
1011+ }
1012+
1013+ const auto bazelTestSpec = Detail::getEnv( "TESTBRIDGE_TEST_ONLY" );
1014+ if ( bazelTestSpec ) {
1015+ // Presumably the test spec from environment should overwrite
1016+ // the one we got from CLI (if we got any)
1017+ m_data.testsOrTags.clear();
1018+ m_data.testsOrTags.push_back( bazelTestSpec );
1019+ }
1020+
1021+ const auto bazelShardOptions = readBazelShardingOptions();
1022+ if ( bazelShardOptions ) {
1023+ std::ofstream f( bazelShardOptions->shardFilePath,
1024+ std::ios_base::out | std::ios_base::trunc );
1025+ if ( f.is_open() ) {
1026+ f << "";
1027+ m_data.shardIndex = bazelShardOptions->shardIndex;
1028+ m_data.shardCount = bazelShardOptions->shardCount;
1029+ }
1030+ }
1031+ }
1032+
1033+} // end namespace Catch
1034+
1035+
1036+
1037+
1038+
1039+namespace Catch {
1040+ std::uint32_t getSeed() {
1041+ return getCurrentContext().getConfig()->rngSeed();
1042+ }
1043+}
1044+
1045+
1046+
1047+#include <cassert>
1048+#include <stack>
1049+
1050+namespace Catch {
1051+
1052+ ////////////////////////////////////////////////////////////////////////////
1053+
1054+
1055+ ScopedMessage::ScopedMessage( MessageBuilder&& builder ):
1056+ m_info( CATCH_MOVE(builder.m_info) ) {
1057+ m_info.message = builder.m_stream.str();
1058+ getResultCapture().pushScopedMessage( m_info );
1059+ }
1060+
1061+ ScopedMessage::ScopedMessage( ScopedMessage&& old ) noexcept:
1062+ m_info( CATCH_MOVE( old.m_info ) ) {
1063+ old.m_moved = true;
1064+ }
1065+
1066+ ScopedMessage::~ScopedMessage() {
1067+ if ( !uncaught_exceptions() && !m_moved ){
1068+ getResultCapture().popScopedMessage(m_info);
1069+ }
1070+ }
1071+
1072+
1073+ Capturer::Capturer( StringRef macroName,
1074+ SourceLineInfo const& lineInfo,
1075+ ResultWas::OfType resultType,
1076+ StringRef names ):
1077+ m_resultCapture( getResultCapture() ) {
1078+ auto trimmed = [&] (size_t start, size_t end) {
1079+ while (names[start] == ',' || isspace(static_cast<unsigned char>(names[start]))) {
1080+ ++start;
1081+ }
1082+ while (names[end] == ',' || isspace(static_cast<unsigned char>(names[end]))) {
1083+ --end;
1084+ }
1085+ return names.substr(start, end - start + 1);
1086+ };
1087+ auto skipq = [&] (size_t start, char quote) {
1088+ for (auto i = start + 1; i < names.size() ; ++i) {
1089+ if (names[i] == quote)
1090+ return i;
1091+ if (names[i] == '\\')
1092+ ++i;
1093+ }
1094+ CATCH_INTERNAL_ERROR("CAPTURE parsing encountered unmatched quote");
1095+ };
1096+
1097+ size_t start = 0;
1098+ std::stack<char> openings;
1099+ for (size_t pos = 0; pos < names.size(); ++pos) {
1100+ char c = names[pos];
1101+ switch (c) {
1102+ case '[':
1103+ case '{':
1104+ case '(':
1105+ // It is basically impossible to disambiguate between
1106+ // comparison and start of template args in this context
1107+// case '<':
1108+ openings.push(c);
1109+ break;
1110+ case ']':
1111+ case '}':
1112+ case ')':
1113+// case '>':
1114+ openings.pop();
1115+ break;
1116+ case '"':
1117+ case '\'':
1118+ pos = skipq(pos, c);
1119+ break;
1120+ case ',':
1121+ if (start != pos && openings.empty()) {
1122+ m_messages.emplace_back(macroName, lineInfo, resultType);
1123+ m_messages.back().message = static_cast<std::string>(trimmed(start, pos));
1124+ m_messages.back().message += " := ";
1125+ start = pos;
1126+ }
1127+ default:; // noop
1128+ }
1129+ }
1130+ assert(openings.empty() && "Mismatched openings");
1131+ m_messages.emplace_back(macroName, lineInfo, resultType);
1132+ m_messages.back().message = static_cast<std::string>(trimmed(start, names.size() - 1));
1133+ m_messages.back().message += " := ";
1134+ }
1135+ Capturer::~Capturer() {
1136+ if ( !uncaught_exceptions() ){
1137+ assert( m_captured == m_messages.size() );
1138+ for( size_t i = 0; i < m_captured; ++i )
1139+ m_resultCapture.popScopedMessage( m_messages[i] );
1140+ }
1141+ }
1142+
1143+ void Capturer::captureValue( size_t index, std::string const& value ) {
1144+ assert( index < m_messages.size() );
1145+ m_messages[index].message += value;
1146+ m_resultCapture.pushScopedMessage( m_messages[index] );
1147+ m_captured++;
1148+ }
1149+
1150+} // end namespace Catch
1151+
1152+
1153+
1154+
1155+#include <exception>
1156+
1157+namespace Catch {
1158+
1159+ namespace {
1160+
1161+ class RegistryHub : public IRegistryHub,
1162+ public IMutableRegistryHub,
1163+ private Detail::NonCopyable {
1164+
1165+ public: // IRegistryHub
1166+ RegistryHub() = default;
1167+ ReporterRegistry const& getReporterRegistry() const override {
1168+ return m_reporterRegistry;
1169+ }
1170+ ITestCaseRegistry const& getTestCaseRegistry() const override {
1171+ return m_testCaseRegistry;
1172+ }
1173+ IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const override {
1174+ return m_exceptionTranslatorRegistry;
1175+ }
1176+ ITagAliasRegistry const& getTagAliasRegistry() const override {
1177+ return m_tagAliasRegistry;
1178+ }
1179+ StartupExceptionRegistry const& getStartupExceptionRegistry() const override {
1180+ return m_exceptionRegistry;
1181+ }
1182+
1183+ public: // IMutableRegistryHub
1184+ void registerReporter( std::string const& name, IReporterFactoryPtr factory ) override {
1185+ m_reporterRegistry.registerReporter( name, CATCH_MOVE(factory) );
1186+ }
1187+ void registerListener( Detail::unique_ptr<EventListenerFactory> factory ) override {
1188+ m_reporterRegistry.registerListener( CATCH_MOVE(factory) );
1189+ }
1190+ void registerTest( Detail::unique_ptr<TestCaseInfo>&& testInfo, Detail::unique_ptr<ITestInvoker>&& invoker ) override {
1191+ m_testCaseRegistry.registerTest( CATCH_MOVE(testInfo), CATCH_MOVE(invoker) );
1192+ }
1193+ void registerTranslator( Detail::unique_ptr<IExceptionTranslator>&& translator ) override {
1194+ m_exceptionTranslatorRegistry.registerTranslator( CATCH_MOVE(translator) );
1195+ }
1196+ void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) override {
1197+ m_tagAliasRegistry.add( alias, tag, lineInfo );
1198+ }
1199+ void registerStartupException() noexcept override {
1200+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
1201+ m_exceptionRegistry.add(std::current_exception());
1202+#else
1203+ CATCH_INTERNAL_ERROR("Attempted to register active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
1204+#endif
1205+ }
1206+ IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() override {
1207+ return m_enumValuesRegistry;
1208+ }
1209+
1210+ private:
1211+ TestRegistry m_testCaseRegistry;
1212+ ReporterRegistry m_reporterRegistry;
1213+ ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;
1214+ TagAliasRegistry m_tagAliasRegistry;
1215+ StartupExceptionRegistry m_exceptionRegistry;
1216+ Detail::EnumValuesRegistry m_enumValuesRegistry;
1217+ };
1218+ }
1219+
1220+ using RegistryHubSingleton = Singleton<RegistryHub, IRegistryHub, IMutableRegistryHub>;
1221+
1222+ IRegistryHub const& getRegistryHub() {
1223+ return RegistryHubSingleton::get();
1224+ }
1225+ IMutableRegistryHub& getMutableRegistryHub() {
1226+ return RegistryHubSingleton::getMutable();
1227+ }
1228+ void cleanUp() {
1229+ cleanupSingletons();
1230+ cleanUpContext();
1231+ }
1232+ std::string translateActiveException() {
1233+ return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException();
1234+ }
1235+
1236+
1237+} // end namespace Catch
1238+
1239+
1240+
1241+#include <algorithm>
1242+#include <cassert>
1243+#include <exception>
1244+#include <iomanip>
1245+#include <set>
1246+
1247+namespace Catch {
1248+
1249+ namespace {
1250+ const int MaxExitCode = 255;
1251+
1252+ IEventListenerPtr createReporter(std::string const& reporterName, ReporterConfig&& config) {
1253+ auto reporter = Catch::getRegistryHub().getReporterRegistry().create(reporterName, CATCH_MOVE(config));
1254+ CATCH_ENFORCE(reporter, "No reporter registered with name: '" << reporterName << '\'');
1255+
1256+ return reporter;
1257+ }
1258+
1259+ IEventListenerPtr prepareReporters(Config const* config) {
1260+ if (Catch::getRegistryHub().getReporterRegistry().getListeners().empty()
1261+ && config->getProcessedReporterSpecs().size() == 1) {
1262+ auto const& spec = config->getProcessedReporterSpecs()[0];
1263+ return createReporter(
1264+ spec.name,
1265+ ReporterConfig( config,
1266+ makeStream( spec.outputFilename ),
1267+ spec.colourMode,
1268+ spec.customOptions ) );
1269+ }
1270+
1271+ auto multi = Detail::make_unique<MultiReporter>(config);
1272+
1273+ auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners();
1274+ for (auto const& listener : listeners) {
1275+ multi->addListener(listener->create(config));
1276+ }
1277+
1278+ for ( auto const& reporterSpec : config->getProcessedReporterSpecs() ) {
1279+ multi->addReporter( createReporter(
1280+ reporterSpec.name,
1281+ ReporterConfig( config,
1282+ makeStream( reporterSpec.outputFilename ),
1283+ reporterSpec.colourMode,
1284+ reporterSpec.customOptions ) ) );
1285+ }
1286+
1287+ return multi;
1288+ }
1289+
1290+ class TestGroup {
1291+ public:
1292+ explicit TestGroup(IEventListenerPtr&& reporter, Config const* config):
1293+ m_reporter(reporter.get()),
1294+ m_config{config},
1295+ m_context{config, CATCH_MOVE(reporter)} {
1296+
1297+ assert( m_config->testSpec().getInvalidSpecs().empty() &&
1298+ "Invalid test specs should be handled before running tests" );
1299+
1300+ auto const& allTestCases = getAllTestCasesSorted(*m_config);
1301+ auto const& testSpec = m_config->testSpec();
1302+ if ( !testSpec.hasFilters() ) {
1303+ for ( auto const& test : allTestCases ) {
1304+ if ( !test.getTestCaseInfo().isHidden() ) {
1305+ m_tests.emplace( &test );
1306+ }
1307+ }
1308+ } else {
1309+ m_matches =
1310+ testSpec.matchesByFilter( allTestCases, *m_config );
1311+ for ( auto const& match : m_matches ) {
1312+ m_tests.insert( match.tests.begin(),
1313+ match.tests.end() );
1314+ }
1315+ }
1316+
1317+ m_tests = createShard(m_tests, m_config->shardCount(), m_config->shardIndex());
1318+ }
1319+
1320+ Totals execute() {
1321+ Totals totals;
1322+ for (auto const& testCase : m_tests) {
1323+ if (!m_context.aborting())
1324+ totals += m_context.runTest(*testCase);
1325+ else
1326+ m_reporter->skipTest(testCase->getTestCaseInfo());
1327+ }
1328+
1329+ for (auto const& match : m_matches) {
1330+ if (match.tests.empty()) {
1331+ m_unmatchedTestSpecs = true;
1332+ m_reporter->noMatchingTestCases( match.name );
1333+ }
1334+ }
1335+
1336+ return totals;
1337+ }
1338+
1339+ bool hadUnmatchedTestSpecs() const {
1340+ return m_unmatchedTestSpecs;
1341+ }
1342+
1343+
1344+ private:
1345+ IEventListener* m_reporter;
1346+ Config const* m_config;
1347+ RunContext m_context;
1348+ std::set<TestCaseHandle const*> m_tests;
1349+ TestSpec::Matches m_matches;
1350+ bool m_unmatchedTestSpecs = false;
1351+ };
1352+
1353+ void applyFilenamesAsTags() {
1354+ for (auto const& testInfo : getRegistryHub().getTestCaseRegistry().getAllInfos()) {
1355+ testInfo->addFilenameTag();
1356+ }
1357+ }
1358+
1359+ } // anon namespace
1360+
1361+ Session::Session() {
1362+ static bool alreadyInstantiated = false;
1363+ if( alreadyInstantiated ) {
1364+ CATCH_TRY { CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); }
1365+ CATCH_CATCH_ALL { getMutableRegistryHub().registerStartupException(); }
1366+ }
1367+
1368+ // There cannot be exceptions at startup in no-exception mode.
1369+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
1370+ const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions();
1371+ if ( !exceptions.empty() ) {
1372+ config();
1373+ getCurrentMutableContext().setConfig(m_config.get());
1374+
1375+ m_startupExceptions = true;
1376+ auto errStream = makeStream( "%stderr" );
1377+ auto colourImpl = makeColourImpl(
1378+ ColourMode::PlatformDefault, errStream.get() );
1379+ auto guard = colourImpl->guardColour( Colour::Red );
1380+ errStream->stream() << "Errors occurred during startup!" << '\n';
1381+ // iterate over all exceptions and notify user
1382+ for ( const auto& ex_ptr : exceptions ) {
1383+ try {
1384+ std::rethrow_exception(ex_ptr);
1385+ } catch ( std::exception const& ex ) {
1386+ errStream->stream() << TextFlow::Column( ex.what() ).indent(2) << '\n';
1387+ }
1388+ }
1389+ }
1390+#endif
1391+
1392+ alreadyInstantiated = true;
1393+ m_cli = makeCommandLineParser( m_configData );
1394+ }
1395+ Session::~Session() {
1396+ Catch::cleanUp();
1397+ }
1398+
1399+ void Session::showHelp() const {
1400+ Catch::cout()
1401+ << "\nCatch2 v" << libraryVersion() << '\n'
1402+ << m_cli << '\n'
1403+ << "For more detailed usage please see the project docs\n\n" << std::flush;
1404+ }
1405+ void Session::libIdentify() {
1406+ Catch::cout()
1407+ << std::left << std::setw(16) << "description: " << "A Catch2 test executable\n"
1408+ << std::left << std::setw(16) << "category: " << "testframework\n"
1409+ << std::left << std::setw(16) << "framework: " << "Catch2\n"
1410+ << std::left << std::setw(16) << "version: " << libraryVersion() << '\n' << std::flush;
1411+ }
1412+
1413+ int Session::applyCommandLine( int argc, char const * const * argv ) {
1414+ if( m_startupExceptions )
1415+ return 1;
1416+
1417+ auto result = m_cli.parse( Clara::Args( argc, argv ) );
1418+
1419+ if( !result ) {
1420+ config();
1421+ getCurrentMutableContext().setConfig(m_config.get());
1422+ auto errStream = makeStream( "%stderr" );
1423+ auto colour = makeColourImpl( ColourMode::PlatformDefault, errStream.get() );
1424+
1425+ errStream->stream()
1426+ << colour->guardColour( Colour::Red )
1427+ << "\nError(s) in input:\n"
1428+ << TextFlow::Column( result.errorMessage() ).indent( 2 )
1429+ << "\n\n";
1430+ errStream->stream() << "Run with -? for usage\n\n" << std::flush;
1431+ return MaxExitCode;
1432+ }
1433+
1434+ if( m_configData.showHelp )
1435+ showHelp();
1436+ if( m_configData.libIdentify )
1437+ libIdentify();
1438+
1439+ m_config.reset();
1440+ return 0;
1441+ }
1442+
1443+#if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE)
1444+ int Session::applyCommandLine( int argc, wchar_t const * const * argv ) {
1445+
1446+ char **utf8Argv = new char *[ argc ];
1447+
1448+ for ( int i = 0; i < argc; ++i ) {
1449+ int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, nullptr, 0, nullptr, nullptr );
1450+
1451+ utf8Argv[ i ] = new char[ bufSize ];
1452+
1453+ WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, nullptr, nullptr );
1454+ }
1455+
1456+ int returnCode = applyCommandLine( argc, utf8Argv );
1457+
1458+ for ( int i = 0; i < argc; ++i )
1459+ delete [] utf8Argv[ i ];
1460+
1461+ delete [] utf8Argv;
1462+
1463+ return returnCode;
1464+ }
1465+#endif
1466+
1467+ void Session::useConfigData( ConfigData const& configData ) {
1468+ m_configData = configData;
1469+ m_config.reset();
1470+ }
1471+
1472+ int Session::run() {
1473+ if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) {
1474+ Catch::cout() << "...waiting for enter/ return before starting\n" << std::flush;
1475+ static_cast<void>(std::getchar());
1476+ }
1477+ int exitCode = runInternal();
1478+ if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) {
1479+ Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << '\n' << std::flush;
1480+ static_cast<void>(std::getchar());
1481+ }
1482+ return exitCode;
1483+ }
1484+
1485+ Clara::Parser const& Session::cli() const {
1486+ return m_cli;
1487+ }
1488+ void Session::cli( Clara::Parser const& newParser ) {
1489+ m_cli = newParser;
1490+ }
1491+ ConfigData& Session::configData() {
1492+ return m_configData;
1493+ }
1494+ Config& Session::config() {
1495+ if( !m_config )
1496+ m_config = Detail::make_unique<Config>( m_configData );
1497+ return *m_config;
1498+ }
1499+
1500+ int Session::runInternal() {
1501+ if( m_startupExceptions )
1502+ return 1;
1503+
1504+ if (m_configData.showHelp || m_configData.libIdentify) {
1505+ return 0;
1506+ }
1507+
1508+ if ( m_configData.shardIndex >= m_configData.shardCount ) {
1509+ Catch::cerr() << "The shard count (" << m_configData.shardCount
1510+ << ") must be greater than the shard index ("
1511+ << m_configData.shardIndex << ")\n"
1512+ << std::flush;
1513+ return 1;
1514+ }
1515+
1516+ CATCH_TRY {
1517+ config(); // Force config to be constructed
1518+
1519+ seedRng( *m_config );
1520+
1521+ if (m_configData.filenamesAsTags) {
1522+ applyFilenamesAsTags();
1523+ }
1524+
1525+ // Set up global config instance before we start calling into other functions
1526+ getCurrentMutableContext().setConfig(m_config.get());
1527+
1528+ // Create reporter(s) so we can route listings through them
1529+ auto reporter = prepareReporters(m_config.get());
1530+
1531+ auto const& invalidSpecs = m_config->testSpec().getInvalidSpecs();
1532+ if ( !invalidSpecs.empty() ) {
1533+ for ( auto const& spec : invalidSpecs ) {
1534+ reporter->reportInvalidTestSpec( spec );
1535+ }
1536+ return 1;
1537+ }
1538+
1539+
1540+ // Handle list request
1541+ if (list(*reporter, *m_config)) {
1542+ return 0;
1543+ }
1544+
1545+ TestGroup tests { CATCH_MOVE(reporter), m_config.get() };
1546+ auto const totals = tests.execute();
1547+
1548+ if ( tests.hadUnmatchedTestSpecs()
1549+ && m_config->warnAboutUnmatchedTestSpecs() ) {
1550+ return 3;
1551+ }
1552+
1553+ if ( totals.testCases.total() == 0
1554+ && !m_config->zeroTestsCountAsSuccess() ) {
1555+ return 2;
1556+ }
1557+
1558+ if ( totals.testCases.total() > 0 &&
1559+ totals.testCases.total() == totals.testCases.skipped
1560+ && !m_config->zeroTestsCountAsSuccess() ) {
1561+ return 4;
1562+ }
1563+
1564+ // Note that on unices only the lower 8 bits are usually used, clamping
1565+ // the return value to 255 prevents false negative when some multiple
1566+ // of 256 tests has failed
1567+ return (std::min) (MaxExitCode, static_cast<int>(totals.assertions.failed));
1568+ }
1569+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
1570+ catch( std::exception& ex ) {
1571+ Catch::cerr() << ex.what() << '\n' << std::flush;
1572+ return MaxExitCode;
1573+ }
1574+#endif
1575+ }
1576+
1577+} // end namespace Catch
1578+
1579+
1580+
1581+
1582+namespace Catch {
1583+
1584+ RegistrarForTagAliases::RegistrarForTagAliases(char const* alias, char const* tag, SourceLineInfo const& lineInfo) {
1585+ CATCH_TRY {
1586+ getMutableRegistryHub().registerTagAlias(alias, tag, lineInfo);
1587+ } CATCH_CATCH_ALL {
1588+ // Do not throw when constructing global objects, instead register the exception to be processed later
1589+ getMutableRegistryHub().registerStartupException();
1590+ }
1591+ }
1592+
1593+}
1594+
1595+
1596+
1597+#include <cassert>
1598+#include <cctype>
1599+#include <algorithm>
1600+
1601+namespace Catch {
1602+
1603+ namespace {
1604+ using TCP_underlying_type = uint8_t;
1605+ static_assert(sizeof(TestCaseProperties) == sizeof(TCP_underlying_type),
1606+ "The size of the TestCaseProperties is different from the assumed size");
1607+
1608+ TestCaseProperties operator|(TestCaseProperties lhs, TestCaseProperties rhs) {
1609+ return static_cast<TestCaseProperties>(
1610+ static_cast<TCP_underlying_type>(lhs) | static_cast<TCP_underlying_type>(rhs)
1611+ );
1612+ }
1613+
1614+ TestCaseProperties& operator|=(TestCaseProperties& lhs, TestCaseProperties rhs) {
1615+ lhs = static_cast<TestCaseProperties>(
1616+ static_cast<TCP_underlying_type>(lhs) | static_cast<TCP_underlying_type>(rhs)
1617+ );
1618+ return lhs;
1619+ }
1620+
1621+ TestCaseProperties operator&(TestCaseProperties lhs, TestCaseProperties rhs) {
1622+ return static_cast<TestCaseProperties>(
1623+ static_cast<TCP_underlying_type>(lhs) & static_cast<TCP_underlying_type>(rhs)
1624+ );
1625+ }
1626+
1627+ bool applies(TestCaseProperties tcp) {
1628+ static_assert(static_cast<TCP_underlying_type>(TestCaseProperties::None) == 0,
1629+ "TestCaseProperties::None must be equal to 0");
1630+ return tcp != TestCaseProperties::None;
1631+ }
1632+
1633+ TestCaseProperties parseSpecialTag( StringRef tag ) {
1634+ if( !tag.empty() && tag[0] == '.' )
1635+ return TestCaseProperties::IsHidden;
1636+ else if( tag == "!throws"_sr )
1637+ return TestCaseProperties::Throws;
1638+ else if( tag == "!shouldfail"_sr )
1639+ return TestCaseProperties::ShouldFail;
1640+ else if( tag == "!mayfail"_sr )
1641+ return TestCaseProperties::MayFail;
1642+ else if( tag == "!nonportable"_sr )
1643+ return TestCaseProperties::NonPortable;
1644+ else if( tag == "!benchmark"_sr )
1645+ return TestCaseProperties::Benchmark | TestCaseProperties::IsHidden;
1646+ else
1647+ return TestCaseProperties::None;
1648+ }
1649+ bool isReservedTag( StringRef tag ) {
1650+ return parseSpecialTag( tag ) == TestCaseProperties::None
1651+ && tag.size() > 0
1652+ && !std::isalnum( static_cast<unsigned char>(tag[0]) );
1653+ }
1654+ void enforceNotReservedTag( StringRef tag, SourceLineInfo const& _lineInfo ) {
1655+ CATCH_ENFORCE( !isReservedTag(tag),
1656+ "Tag name: [" << tag << "] is not allowed.\n"
1657+ << "Tag names starting with non alphanumeric characters are reserved\n"
1658+ << _lineInfo );
1659+ }
1660+
1661+ std::string makeDefaultName() {
1662+ static size_t counter = 0;
1663+ return "Anonymous test case " + std::to_string(++counter);
1664+ }
1665+
1666+ StringRef extractFilenamePart(StringRef filename) {
1667+ size_t lastDot = filename.size();
1668+ while (lastDot > 0 && filename[lastDot - 1] != '.') {
1669+ --lastDot;
1670+ }
1671+ // In theory we could have filename without any extension in it
1672+ if ( lastDot == 0 ) { return StringRef(); }
1673+
1674+ --lastDot;
1675+ size_t nameStart = lastDot;
1676+ while (nameStart > 0 && filename[nameStart - 1] != '/' && filename[nameStart - 1] != '\\') {
1677+ --nameStart;
1678+ }
1679+
1680+ return filename.substr(nameStart, lastDot - nameStart);
1681+ }
1682+
1683+ // Returns the upper bound on size of extra tags ([#file]+[.])
1684+ size_t sizeOfExtraTags(StringRef filepath) {
1685+ // [.] is 3, [#] is another 3
1686+ const size_t extras = 3 + 3;
1687+ return extractFilenamePart(filepath).size() + extras;
1688+ }
1689+ } // end unnamed namespace
1690+
1691+ bool operator<( Tag const& lhs, Tag const& rhs ) {
1692+ Detail::CaseInsensitiveLess cmp;
1693+ return cmp( lhs.original, rhs.original );
1694+ }
1695+ bool operator==( Tag const& lhs, Tag const& rhs ) {
1696+ Detail::CaseInsensitiveEqualTo cmp;
1697+ return cmp( lhs.original, rhs.original );
1698+ }
1699+
1700+ Detail::unique_ptr<TestCaseInfo>
1701+ makeTestCaseInfo(StringRef _className,
1702+ NameAndTags const& nameAndTags,
1703+ SourceLineInfo const& _lineInfo ) {
1704+ return Detail::make_unique<TestCaseInfo>(_className, nameAndTags, _lineInfo);
1705+ }
1706+
1707+ TestCaseInfo::TestCaseInfo(StringRef _className,
1708+ NameAndTags const& _nameAndTags,
1709+ SourceLineInfo const& _lineInfo):
1710+ name( _nameAndTags.name.empty() ? makeDefaultName() : _nameAndTags.name ),
1711+ className( _className ),
1712+ lineInfo( _lineInfo )
1713+ {
1714+ StringRef originalTags = _nameAndTags.tags;
1715+ // We need to reserve enough space to store all of the tags
1716+ // (including optional hidden tag and filename tag)
1717+ auto requiredSize = originalTags.size() + sizeOfExtraTags(_lineInfo.file);
1718+ backingTags.reserve(requiredSize);
1719+
1720+ // We cannot copy the tags directly, as we need to normalize
1721+ // some tags, so that [.foo] is copied as [.][foo].
1722+ size_t tagStart = 0;
1723+ size_t tagEnd = 0;
1724+ bool inTag = false;
1725+ for (size_t idx = 0; idx < originalTags.size(); ++idx) {
1726+ auto c = originalTags[idx];
1727+ if (c == '[') {
1728+ CATCH_ENFORCE(
1729+ !inTag,
1730+ "Found '[' inside a tag while registering test case '"
1731+ << _nameAndTags.name << "' at " << _lineInfo );
1732+
1733+ inTag = true;
1734+ tagStart = idx;
1735+ }
1736+ if (c == ']') {
1737+ CATCH_ENFORCE(
1738+ inTag,
1739+ "Found unmatched ']' while registering test case '"
1740+ << _nameAndTags.name << "' at " << _lineInfo );
1741+
1742+ inTag = false;
1743+ tagEnd = idx;
1744+ assert(tagStart < tagEnd);
1745+
1746+ // We need to check the tag for special meanings, copy
1747+ // it over to backing storage and actually reference the
1748+ // backing storage in the saved tags
1749+ StringRef tagStr = originalTags.substr(tagStart+1, tagEnd - tagStart - 1);
1750+ CATCH_ENFORCE( !tagStr.empty(),
1751+ "Found an empty tag while registering test case '"
1752+ << _nameAndTags.name << "' at "
1753+ << _lineInfo );
1754+
1755+ enforceNotReservedTag(tagStr, lineInfo);
1756+ properties |= parseSpecialTag(tagStr);
1757+ // When copying a tag to the backing storage, we need to
1758+ // check if it is a merged hide tag, such as [.foo], and
1759+ // if it is, we need to handle it as if it was [foo].
1760+ if (tagStr.size() > 1 && tagStr[0] == '.') {
1761+ tagStr = tagStr.substr(1, tagStr.size() - 1);
1762+ }
1763+ // We skip over dealing with the [.] tag, as we will add
1764+ // it later unconditionally and then sort and unique all
1765+ // the tags.
1766+ internalAppendTag(tagStr);
1767+ }
1768+ }
1769+ CATCH_ENFORCE( !inTag,
1770+ "Found an unclosed tag while registering test case '"
1771+ << _nameAndTags.name << "' at " << _lineInfo );
1772+
1773+
1774+ // Add [.] if relevant
1775+ if (isHidden()) {
1776+ internalAppendTag("."_sr);
1777+ }
1778+
1779+ // Sort and prepare tags
1780+ std::sort(begin(tags), end(tags));
1781+ tags.erase(std::unique(begin(tags), end(tags)),
1782+ end(tags));
1783+ }
1784+
1785+ bool TestCaseInfo::isHidden() const {
1786+ return applies( properties & TestCaseProperties::IsHidden );
1787+ }
1788+ bool TestCaseInfo::throws() const {
1789+ return applies( properties & TestCaseProperties::Throws );
1790+ }
1791+ bool TestCaseInfo::okToFail() const {
1792+ return applies( properties & (TestCaseProperties::ShouldFail | TestCaseProperties::MayFail ) );
1793+ }
1794+ bool TestCaseInfo::expectedToFail() const {
1795+ return applies( properties & (TestCaseProperties::ShouldFail) );
1796+ }
1797+
1798+ void TestCaseInfo::addFilenameTag() {
1799+ std::string combined("#");
1800+ combined += extractFilenamePart(lineInfo.file);
1801+ internalAppendTag(combined);
1802+ }
1803+
1804+ std::string TestCaseInfo::tagsAsString() const {
1805+ std::string ret;
1806+ // '[' and ']' per tag
1807+ std::size_t full_size = 2 * tags.size();
1808+ for (const auto& tag : tags) {
1809+ full_size += tag.original.size();
1810+ }
1811+ ret.reserve(full_size);
1812+ for (const auto& tag : tags) {
1813+ ret.push_back('[');
1814+ ret += tag.original;
1815+ ret.push_back(']');
1816+ }
1817+
1818+ return ret;
1819+ }
1820+
1821+ void TestCaseInfo::internalAppendTag(StringRef tagStr) {
1822+ backingTags += '[';
1823+ const auto backingStart = backingTags.size();
1824+ backingTags += tagStr;
1825+ const auto backingEnd = backingTags.size();
1826+ backingTags += ']';
1827+ tags.emplace_back(StringRef(backingTags.c_str() + backingStart, backingEnd - backingStart));
1828+ }
1829+
1830+ bool operator<( TestCaseInfo const& lhs, TestCaseInfo const& rhs ) {
1831+ // We want to avoid redoing the string comparisons multiple times,
1832+ // so we store the result of a three-way comparison before using
1833+ // it in the actual comparison logic.
1834+ const auto cmpName = lhs.name.compare( rhs.name );
1835+ if ( cmpName != 0 ) {
1836+ return cmpName < 0;
1837+ }
1838+ const auto cmpClassName = lhs.className.compare( rhs.className );
1839+ if ( cmpClassName != 0 ) {
1840+ return cmpClassName < 0;
1841+ }
1842+ return lhs.tags < rhs.tags;
1843+ }
1844+
1845+ TestCaseInfo const& TestCaseHandle::getTestCaseInfo() const {
1846+ return *m_info;
1847+ }
1848+
1849+} // end namespace Catch
1850+
1851+
1852+
1853+#include <algorithm>
1854+#include <string>
1855+#include <vector>
1856+#include <ostream>
1857+
1858+namespace Catch {
1859+
1860+ TestSpec::Pattern::Pattern( std::string const& name )
1861+ : m_name( name )
1862+ {}
1863+
1864+ TestSpec::Pattern::~Pattern() = default;
1865+
1866+ std::string const& TestSpec::Pattern::name() const {
1867+ return m_name;
1868+ }
1869+
1870+
1871+ TestSpec::NamePattern::NamePattern( std::string const& name, std::string const& filterString )
1872+ : Pattern( filterString )
1873+ , m_wildcardPattern( toLower( name ), CaseSensitive::No )
1874+ {}
1875+
1876+ bool TestSpec::NamePattern::matches( TestCaseInfo const& testCase ) const {
1877+ return m_wildcardPattern.matches( testCase.name );
1878+ }
1879+
1880+ void TestSpec::NamePattern::serializeTo( std::ostream& out ) const {
1881+ out << '"' << name() << '"';
1882+ }
1883+
1884+
1885+ TestSpec::TagPattern::TagPattern( std::string const& tag, std::string const& filterString )
1886+ : Pattern( filterString )
1887+ , m_tag( tag )
1888+ {}
1889+
1890+ bool TestSpec::TagPattern::matches( TestCaseInfo const& testCase ) const {
1891+ return std::find( begin( testCase.tags ),
1892+ end( testCase.tags ),
1893+ Tag( m_tag ) ) != end( testCase.tags );
1894+ }
1895+
1896+ void TestSpec::TagPattern::serializeTo( std::ostream& out ) const {
1897+ out << name();
1898+ }
1899+
1900+ bool TestSpec::Filter::matches( TestCaseInfo const& testCase ) const {
1901+ bool should_use = !testCase.isHidden();
1902+ for (auto const& pattern : m_required) {
1903+ should_use = true;
1904+ if (!pattern->matches(testCase)) {
1905+ return false;
1906+ }
1907+ }
1908+ for (auto const& pattern : m_forbidden) {
1909+ if (pattern->matches(testCase)) {
1910+ return false;
1911+ }
1912+ }
1913+ return should_use;
1914+ }
1915+
1916+ void TestSpec::Filter::serializeTo( std::ostream& out ) const {
1917+ bool first = true;
1918+ for ( auto const& pattern : m_required ) {
1919+ if ( !first ) {
1920+ out << ' ';
1921+ }
1922+ out << *pattern;
1923+ first = false;
1924+ }
1925+ for ( auto const& pattern : m_forbidden ) {
1926+ if ( !first ) {
1927+ out << ' ';
1928+ }
1929+ out << *pattern;
1930+ first = false;
1931+ }
1932+ }
1933+
1934+
1935+ std::string TestSpec::extractFilterName( Filter const& filter ) {
1936+ Catch::ReusableStringStream sstr;
1937+ sstr << filter;
1938+ return sstr.str();
1939+ }
1940+
1941+ bool TestSpec::hasFilters() const {
1942+ return !m_filters.empty();
1943+ }
1944+
1945+ bool TestSpec::matches( TestCaseInfo const& testCase ) const {
1946+ return std::any_of( m_filters.begin(), m_filters.end(), [&]( Filter const& f ){ return f.matches( testCase ); } );
1947+ }
1948+
1949+ TestSpec::Matches TestSpec::matchesByFilter( std::vector<TestCaseHandle> const& testCases, IConfig const& config ) const {
1950+ Matches matches;
1951+ matches.reserve( m_filters.size() );
1952+ for ( auto const& filter : m_filters ) {
1953+ std::vector<TestCaseHandle const*> currentMatches;
1954+ for ( auto const& test : testCases )
1955+ if ( isThrowSafe( test, config ) &&
1956+ filter.matches( test.getTestCaseInfo() ) )
1957+ currentMatches.emplace_back( &test );
1958+ matches.push_back(
1959+ FilterMatch{ extractFilterName( filter ), currentMatches } );
1960+ }
1961+ return matches;
1962+ }
1963+
1964+ const TestSpec::vectorStrings& TestSpec::getInvalidSpecs() const {
1965+ return m_invalidSpecs;
1966+ }
1967+
1968+ void TestSpec::serializeTo( std::ostream& out ) const {
1969+ bool first = true;
1970+ for ( auto const& filter : m_filters ) {
1971+ if ( !first ) {
1972+ out << ',';
1973+ }
1974+ out << filter;
1975+ first = false;
1976+ }
1977+ }
1978+
1979+}
1980+
1981+
1982+
1983+#include <chrono>
1984+
1985+namespace Catch {
1986+
1987+ namespace {
1988+ static auto getCurrentNanosecondsSinceEpoch() -> uint64_t {
1989+ return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count();
1990+ }
1991+ } // end unnamed namespace
1992+
1993+ void Timer::start() {
1994+ m_nanoseconds = getCurrentNanosecondsSinceEpoch();
1995+ }
1996+ auto Timer::getElapsedNanoseconds() const -> uint64_t {
1997+ return getCurrentNanosecondsSinceEpoch() - m_nanoseconds;
1998+ }
1999+ auto Timer::getElapsedMicroseconds() const -> uint64_t {
2000+ return getElapsedNanoseconds()/1000;
2001+ }
2002+ auto Timer::getElapsedMilliseconds() const -> unsigned int {
2003+ return static_cast<unsigned int>(getElapsedMicroseconds()/1000);
2004+ }
2005+ auto Timer::getElapsedSeconds() const -> double {
2006+ return getElapsedMicroseconds()/1000000.0;
2007+ }
2008+
2009+
2010+} // namespace Catch
2011+
2012+
2013+
2014+
2015+#include <cmath>
2016+#include <iomanip>
2017+
2018+namespace Catch {
2019+
2020+namespace Detail {
2021+
2022+ namespace {
2023+ const int hexThreshold = 255;
2024+
2025+ struct Endianness {
2026+ enum Arch { Big, Little };
2027+
2028+ static Arch which() {
2029+ int one = 1;
2030+ // If the lowest byte we read is non-zero, we can assume
2031+ // that little endian format is used.
2032+ auto value = *reinterpret_cast<char*>(&one);
2033+ return value ? Little : Big;
2034+ }
2035+ };
2036+
2037+ template<typename T>
2038+ std::string fpToString(T value, int precision) {
2039+ if (Catch::isnan(value)) {
2040+ return "nan";
2041+ }
2042+
2043+ ReusableStringStream rss;
2044+ rss << std::setprecision(precision)
2045+ << std::fixed
2046+ << value;
2047+ std::string d = rss.str();
2048+ std::size_t i = d.find_last_not_of('0');
2049+ if (i != std::string::npos && i != d.size() - 1) {
2050+ if (d[i] == '.')
2051+ i++;
2052+ d = d.substr(0, i + 1);
2053+ }
2054+ return d;
2055+ }
2056+ } // end unnamed namespace
2057+
2058+ std::string convertIntoString(StringRef string, bool escapeInvisibles) {
2059+ std::string ret;
2060+ // This is enough for the "don't escape invisibles" case, and a good
2061+ // lower bound on the "escape invisibles" case.
2062+ ret.reserve(string.size() + 2);
2063+
2064+ if (!escapeInvisibles) {
2065+ ret += '"';
2066+ ret += string;
2067+ ret += '"';
2068+ return ret;
2069+ }
2070+
2071+ ret += '"';
2072+ for (char c : string) {
2073+ switch (c) {
2074+ case '\r':
2075+ ret.append("\\r");
2076+ break;
2077+ case '\n':
2078+ ret.append("\\n");
2079+ break;
2080+ case '\t':
2081+ ret.append("\\t");
2082+ break;
2083+ case '\f':
2084+ ret.append("\\f");
2085+ break;
2086+ default:
2087+ ret.push_back(c);
2088+ break;
2089+ }
2090+ }
2091+ ret += '"';
2092+
2093+ return ret;
2094+ }
2095+
2096+ std::string convertIntoString(StringRef string) {
2097+ return convertIntoString(string, getCurrentContext().getConfig()->showInvisibles());
2098+ }
2099+
2100+ std::string rawMemoryToString( const void *object, std::size_t size ) {
2101+ // Reverse order for little endian architectures
2102+ int i = 0, end = static_cast<int>( size ), inc = 1;
2103+ if( Endianness::which() == Endianness::Little ) {
2104+ i = end-1;
2105+ end = inc = -1;
2106+ }
2107+
2108+ unsigned char const *bytes = static_cast<unsigned char const *>(object);
2109+ ReusableStringStream rss;
2110+ rss << "0x" << std::setfill('0') << std::hex;
2111+ for( ; i != end; i += inc )
2112+ rss << std::setw(2) << static_cast<unsigned>(bytes[i]);
2113+ return rss.str();
2114+ }
2115+} // end Detail namespace
2116+
2117+
2118+
2119+//// ======================================================= ////
2120+//
2121+// Out-of-line defs for full specialization of StringMaker
2122+//
2123+//// ======================================================= ////
2124+
2125+std::string StringMaker<std::string>::convert(const std::string& str) {
2126+ return Detail::convertIntoString( str );
2127+}
2128+
2129+#ifdef CATCH_CONFIG_CPP17_STRING_VIEW
2130+std::string StringMaker<std::string_view>::convert(std::string_view str) {
2131+ return Detail::convertIntoString( StringRef( str.data(), str.size() ) );
2132+}
2133+#endif
2134+
2135+std::string StringMaker<char const*>::convert(char const* str) {
2136+ if (str) {
2137+ return Detail::convertIntoString( str );
2138+ } else {
2139+ return{ "{null string}" };
2140+ }
2141+}
2142+std::string StringMaker<char*>::convert(char* str) { // NOLINT(readability-non-const-parameter)
2143+ if (str) {
2144+ return Detail::convertIntoString( str );
2145+ } else {
2146+ return{ "{null string}" };
2147+ }
2148+}
2149+
2150+#ifdef CATCH_CONFIG_WCHAR
2151+std::string StringMaker<std::wstring>::convert(const std::wstring& wstr) {
2152+ std::string s;
2153+ s.reserve(wstr.size());
2154+ for (auto c : wstr) {
2155+ s += (c <= 0xff) ? static_cast<char>(c) : '?';
2156+ }
2157+ return ::Catch::Detail::stringify(s);
2158+}
2159+
2160+# ifdef CATCH_CONFIG_CPP17_STRING_VIEW
2161+std::string StringMaker<std::wstring_view>::convert(std::wstring_view str) {
2162+ return StringMaker<std::wstring>::convert(std::wstring(str));
2163+}
2164+# endif
2165+
2166+std::string StringMaker<wchar_t const*>::convert(wchar_t const * str) {
2167+ if (str) {
2168+ return ::Catch::Detail::stringify(std::wstring{ str });
2169+ } else {
2170+ return{ "{null string}" };
2171+ }
2172+}
2173+std::string StringMaker<wchar_t *>::convert(wchar_t * str) {
2174+ if (str) {
2175+ return ::Catch::Detail::stringify(std::wstring{ str });
2176+ } else {
2177+ return{ "{null string}" };
2178+ }
2179+}
2180+#endif
2181+
2182+#if defined(CATCH_CONFIG_CPP17_BYTE)
2183+#include <cstddef>
2184+std::string StringMaker<std::byte>::convert(std::byte value) {
2185+ return ::Catch::Detail::stringify(std::to_integer<unsigned long long>(value));
2186+}
2187+#endif // defined(CATCH_CONFIG_CPP17_BYTE)
2188+
2189+std::string StringMaker<int>::convert(int value) {
2190+ return ::Catch::Detail::stringify(static_cast<long long>(value));
2191+}
2192+std::string StringMaker<long>::convert(long value) {
2193+ return ::Catch::Detail::stringify(static_cast<long long>(value));
2194+}
2195+std::string StringMaker<long long>::convert(long long value) {
2196+ ReusableStringStream rss;
2197+ rss << value;
2198+ if (value > Detail::hexThreshold) {
2199+ rss << " (0x" << std::hex << value << ')';
2200+ }
2201+ return rss.str();
2202+}
2203+
2204+std::string StringMaker<unsigned int>::convert(unsigned int value) {
2205+ return ::Catch::Detail::stringify(static_cast<unsigned long long>(value));
2206+}
2207+std::string StringMaker<unsigned long>::convert(unsigned long value) {
2208+ return ::Catch::Detail::stringify(static_cast<unsigned long long>(value));
2209+}
2210+std::string StringMaker<unsigned long long>::convert(unsigned long long value) {
2211+ ReusableStringStream rss;
2212+ rss << value;
2213+ if (value > Detail::hexThreshold) {
2214+ rss << " (0x" << std::hex << value << ')';
2215+ }
2216+ return rss.str();
2217+}
2218+
2219+std::string StringMaker<signed char>::convert(signed char value) {
2220+ if (value == '\r') {
2221+ return "'\\r'";
2222+ } else if (value == '\f') {
2223+ return "'\\f'";
2224+ } else if (value == '\n') {
2225+ return "'\\n'";
2226+ } else if (value == '\t') {
2227+ return "'\\t'";
2228+ } else if ('\0' <= value && value < ' ') {
2229+ return ::Catch::Detail::stringify(static_cast<unsigned int>(value));
2230+ } else {
2231+ char chstr[] = "' '";
2232+ chstr[1] = value;
2233+ return chstr;
2234+ }
2235+}
2236+std::string StringMaker<char>::convert(char c) {
2237+ return ::Catch::Detail::stringify(static_cast<signed char>(c));
2238+}
2239+std::string StringMaker<unsigned char>::convert(unsigned char value) {
2240+ return ::Catch::Detail::stringify(static_cast<char>(value));
2241+}
2242+
2243+int StringMaker<float>::precision = 5;
2244+
2245+std::string StringMaker<float>::convert(float value) {
2246+ return Detail::fpToString(value, precision) + 'f';
2247+}
2248+
2249+int StringMaker<double>::precision = 10;
2250+
2251+std::string StringMaker<double>::convert(double value) {
2252+ return Detail::fpToString(value, precision);
2253+}
2254+
2255+} // end namespace Catch
2256+
2257+
2258+
2259+namespace Catch {
2260+
2261+ Counts Counts::operator - ( Counts const& other ) const {
2262+ Counts diff;
2263+ diff.passed = passed - other.passed;
2264+ diff.failed = failed - other.failed;
2265+ diff.failedButOk = failedButOk - other.failedButOk;
2266+ diff.skipped = skipped - other.skipped;
2267+ return diff;
2268+ }
2269+
2270+ Counts& Counts::operator += ( Counts const& other ) {
2271+ passed += other.passed;
2272+ failed += other.failed;
2273+ failedButOk += other.failedButOk;
2274+ skipped += other.skipped;
2275+ return *this;
2276+ }
2277+
2278+ std::uint64_t Counts::total() const {
2279+ return passed + failed + failedButOk + skipped;
2280+ }
2281+ bool Counts::allPassed() const {
2282+ return failed == 0 && failedButOk == 0 && skipped == 0;
2283+ }
2284+ bool Counts::allOk() const {
2285+ return failed == 0;
2286+ }
2287+
2288+ Totals Totals::operator - ( Totals const& other ) const {
2289+ Totals diff;
2290+ diff.assertions = assertions - other.assertions;
2291+ diff.testCases = testCases - other.testCases;
2292+ return diff;
2293+ }
2294+
2295+ Totals& Totals::operator += ( Totals const& other ) {
2296+ assertions += other.assertions;
2297+ testCases += other.testCases;
2298+ return *this;
2299+ }
2300+
2301+ Totals Totals::delta( Totals const& prevTotals ) const {
2302+ Totals diff = *this - prevTotals;
2303+ if( diff.assertions.failed > 0 )
2304+ ++diff.testCases.failed;
2305+ else if( diff.assertions.failedButOk > 0 )
2306+ ++diff.testCases.failedButOk;
2307+ else if ( diff.assertions.skipped > 0 )
2308+ ++ diff.testCases.skipped;
2309+ else
2310+ ++diff.testCases.passed;
2311+ return diff;
2312+ }
2313+
2314+}
2315+
2316+
2317+
2318+
2319+namespace Catch {
2320+ namespace Detail {
2321+ void registerTranslatorImpl(
2322+ Detail::unique_ptr<IExceptionTranslator>&& translator ) {
2323+ getMutableRegistryHub().registerTranslator(
2324+ CATCH_MOVE( translator ) );
2325+ }
2326+ } // namespace Detail
2327+} // namespace Catch
2328+
2329+
2330+#include <ostream>
2331+
2332+namespace Catch {
2333+
2334+ Version::Version
2335+ ( unsigned int _majorVersion,
2336+ unsigned int _minorVersion,
2337+ unsigned int _patchNumber,
2338+ char const * const _branchName,
2339+ unsigned int _buildNumber )
2340+ : majorVersion( _majorVersion ),
2341+ minorVersion( _minorVersion ),
2342+ patchNumber( _patchNumber ),
2343+ branchName( _branchName ),
2344+ buildNumber( _buildNumber )
2345+ {}
2346+
2347+ std::ostream& operator << ( std::ostream& os, Version const& version ) {
2348+ os << version.majorVersion << '.'
2349+ << version.minorVersion << '.'
2350+ << version.patchNumber;
2351+ // branchName is never null -> 0th char is \0 if it is empty
2352+ if (version.branchName[0]) {
2353+ os << '-' << version.branchName
2354+ << '.' << version.buildNumber;
2355+ }
2356+ return os;
2357+ }
2358+
2359+ Version const& libraryVersion() {
2360+ static Version version( 3, 5, 4, "", 0 );
2361+ return version;
2362+ }
2363+
2364+}
2365+
2366+
2367+
2368+
2369+namespace Catch {
2370+
2371+ const char* GeneratorException::what() const noexcept {
2372+ return m_msg;
2373+ }
2374+
2375+} // end namespace Catch
2376+
2377+
2378+
2379+
2380+namespace Catch {
2381+
2382+ IGeneratorTracker::~IGeneratorTracker() = default;
2383+
2384+namespace Generators {
2385+
2386+namespace Detail {
2387+
2388+ [[noreturn]]
2389+ void throw_generator_exception(char const* msg) {
2390+ Catch::throw_exception(GeneratorException{ msg });
2391+ }
2392+} // end namespace Detail
2393+
2394+ GeneratorUntypedBase::~GeneratorUntypedBase() = default;
2395+
2396+ IGeneratorTracker* acquireGeneratorTracker(StringRef generatorName, SourceLineInfo const& lineInfo ) {
2397+ return getResultCapture().acquireGeneratorTracker( generatorName, lineInfo );
2398+ }
2399+
2400+ IGeneratorTracker* createGeneratorTracker( StringRef generatorName,
2401+ SourceLineInfo lineInfo,
2402+ GeneratorBasePtr&& generator ) {
2403+ return getResultCapture().createGeneratorTracker(
2404+ generatorName, lineInfo, CATCH_MOVE( generator ) );
2405+ }
2406+
2407+} // namespace Generators
2408+} // namespace Catch
2409+
2410+
2411+
2412+
2413+#include <random>
2414+
2415+namespace Catch {
2416+ namespace Generators {
2417+ namespace Detail {
2418+ std::uint32_t getSeed() { return sharedRng()(); }
2419+ } // namespace Detail
2420+
2421+ struct RandomFloatingGenerator<long double>::PImpl {
2422+ PImpl( long double a, long double b, uint32_t seed ):
2423+ rng( seed ), dist( a, b ) {}
2424+
2425+ Catch::SimplePcg32 rng;
2426+ std::uniform_real_distribution<long double> dist;
2427+ };
2428+
2429+ RandomFloatingGenerator<long double>::RandomFloatingGenerator(
2430+ long double a, long double b, std::uint32_t seed) :
2431+ m_pimpl(Catch::Detail::make_unique<PImpl>(a, b, seed)) {
2432+ static_cast<void>( next() );
2433+ }
2434+
2435+ RandomFloatingGenerator<long double>::~RandomFloatingGenerator() =
2436+ default;
2437+ bool RandomFloatingGenerator<long double>::next() {
2438+ m_current_number = m_pimpl->dist( m_pimpl->rng );
2439+ return true;
2440+ }
2441+ } // namespace Generators
2442+} // namespace Catch
2443+
2444+
2445+
2446+
2447+namespace Catch {
2448+ IResultCapture::~IResultCapture() = default;
2449+}
2450+
2451+
2452+
2453+
2454+namespace Catch {
2455+ IConfig::~IConfig() = default;
2456+}
2457+
2458+
2459+
2460+
2461+namespace Catch {
2462+ IExceptionTranslator::~IExceptionTranslator() = default;
2463+ IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() = default;
2464+}
2465+
2466+
2467+
2468+#include <string>
2469+
2470+namespace Catch {
2471+ namespace Generators {
2472+
2473+ bool GeneratorUntypedBase::countedNext() {
2474+ auto ret = next();
2475+ if ( ret ) {
2476+ m_stringReprCache.clear();
2477+ ++m_currentElementIndex;
2478+ }
2479+ return ret;
2480+ }
2481+
2482+ StringRef GeneratorUntypedBase::currentElementAsString() const {
2483+ if ( m_stringReprCache.empty() ) {
2484+ m_stringReprCache = stringifyImpl();
2485+ }
2486+ return m_stringReprCache;
2487+ }
2488+
2489+ } // namespace Generators
2490+} // namespace Catch
2491+
2492+
2493+
2494+
2495+namespace Catch {
2496+ IRegistryHub::~IRegistryHub() = default;
2497+ IMutableRegistryHub::~IMutableRegistryHub() = default;
2498+}
2499+
2500+
2501+
2502+#include <cassert>
2503+
2504+namespace Catch {
2505+
2506+ ReporterConfig::ReporterConfig(
2507+ IConfig const* _fullConfig,
2508+ Detail::unique_ptr<IStream> _stream,
2509+ ColourMode colourMode,
2510+ std::map<std::string, std::string> customOptions ):
2511+ m_stream( CATCH_MOVE(_stream) ),
2512+ m_fullConfig( _fullConfig ),
2513+ m_colourMode( colourMode ),
2514+ m_customOptions( CATCH_MOVE( customOptions ) ) {}
2515+
2516+ Detail::unique_ptr<IStream> ReporterConfig::takeStream() && {
2517+ assert( m_stream );
2518+ return CATCH_MOVE( m_stream );
2519+ }
2520+ IConfig const * ReporterConfig::fullConfig() const { return m_fullConfig; }
2521+ ColourMode ReporterConfig::colourMode() const { return m_colourMode; }
2522+
2523+ std::map<std::string, std::string> const&
2524+ ReporterConfig::customOptions() const {
2525+ return m_customOptions;
2526+ }
2527+
2528+ ReporterConfig::~ReporterConfig() = default;
2529+
2530+ AssertionStats::AssertionStats( AssertionResult const& _assertionResult,
2531+ std::vector<MessageInfo> const& _infoMessages,
2532+ Totals const& _totals )
2533+ : assertionResult( _assertionResult ),
2534+ infoMessages( _infoMessages ),
2535+ totals( _totals )
2536+ {
2537+ if( assertionResult.hasMessage() ) {
2538+ // Copy message into messages list.
2539+ // !TBD This should have been done earlier, somewhere
2540+ MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() );
2541+ builder.m_info.message = static_cast<std::string>(assertionResult.getMessage());
2542+
2543+ infoMessages.push_back( CATCH_MOVE(builder.m_info) );
2544+ }
2545+ }
2546+
2547+ SectionStats::SectionStats( SectionInfo&& _sectionInfo,
2548+ Counts const& _assertions,
2549+ double _durationInSeconds,
2550+ bool _missingAssertions )
2551+ : sectionInfo( CATCH_MOVE(_sectionInfo) ),
2552+ assertions( _assertions ),
2553+ durationInSeconds( _durationInSeconds ),
2554+ missingAssertions( _missingAssertions )
2555+ {}
2556+
2557+
2558+ TestCaseStats::TestCaseStats( TestCaseInfo const& _testInfo,
2559+ Totals const& _totals,
2560+ std::string&& _stdOut,
2561+ std::string&& _stdErr,
2562+ bool _aborting )
2563+ : testInfo( &_testInfo ),
2564+ totals( _totals ),
2565+ stdOut( CATCH_MOVE(_stdOut) ),
2566+ stdErr( CATCH_MOVE(_stdErr) ),
2567+ aborting( _aborting )
2568+ {}
2569+
2570+
2571+ TestRunStats::TestRunStats( TestRunInfo const& _runInfo,
2572+ Totals const& _totals,
2573+ bool _aborting )
2574+ : runInfo( _runInfo ),
2575+ totals( _totals ),
2576+ aborting( _aborting )
2577+ {}
2578+
2579+ IEventListener::~IEventListener() = default;
2580+
2581+} // end namespace Catch
2582+
2583+
2584+
2585+
2586+namespace Catch {
2587+ IReporterFactory::~IReporterFactory() = default;
2588+ EventListenerFactory::~EventListenerFactory() = default;
2589+}
2590+
2591+
2592+
2593+
2594+namespace Catch {
2595+ ITestCaseRegistry::~ITestCaseRegistry() = default;
2596+}
2597+
2598+
2599+
2600+namespace Catch {
2601+
2602+ AssertionHandler::AssertionHandler
2603+ ( StringRef macroName,
2604+ SourceLineInfo const& lineInfo,
2605+ StringRef capturedExpression,
2606+ ResultDisposition::Flags resultDisposition )
2607+ : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition },
2608+ m_resultCapture( getResultCapture() )
2609+ {
2610+ m_resultCapture.notifyAssertionStarted( m_assertionInfo );
2611+ }
2612+
2613+ void AssertionHandler::handleExpr( ITransientExpression const& expr ) {
2614+ m_resultCapture.handleExpr( m_assertionInfo, expr, m_reaction );
2615+ }
2616+ void AssertionHandler::handleMessage(ResultWas::OfType resultType, StringRef message) {
2617+ m_resultCapture.handleMessage( m_assertionInfo, resultType, message, m_reaction );
2618+ }
2619+
2620+ auto AssertionHandler::allowThrows() const -> bool {
2621+ return getCurrentContext().getConfig()->allowThrows();
2622+ }
2623+
2624+ void AssertionHandler::complete() {
2625+ m_completed = true;
2626+ if( m_reaction.shouldDebugBreak ) {
2627+
2628+ // If you find your debugger stopping you here then go one level up on the
2629+ // call-stack for the code that caused it (typically a failed assertion)
2630+
2631+ // (To go back to the test and change execution, jump over the throw, next)
2632+ CATCH_BREAK_INTO_DEBUGGER();
2633+ }
2634+ if (m_reaction.shouldThrow) {
2635+ throw_test_failure_exception();
2636+ }
2637+ if ( m_reaction.shouldSkip ) {
2638+ throw_test_skip_exception();
2639+ }
2640+ }
2641+
2642+ void AssertionHandler::handleUnexpectedInflightException() {
2643+ m_resultCapture.handleUnexpectedInflightException( m_assertionInfo, Catch::translateActiveException(), m_reaction );
2644+ }
2645+
2646+ void AssertionHandler::handleExceptionThrownAsExpected() {
2647+ m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);
2648+ }
2649+ void AssertionHandler::handleExceptionNotThrownAsExpected() {
2650+ m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);
2651+ }
2652+
2653+ void AssertionHandler::handleUnexpectedExceptionNotThrown() {
2654+ m_resultCapture.handleUnexpectedExceptionNotThrown( m_assertionInfo, m_reaction );
2655+ }
2656+
2657+ void AssertionHandler::handleThrowingCallSkipped() {
2658+ m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);
2659+ }
2660+
2661+ // This is the overload that takes a string and infers the Equals matcher from it
2662+ // The more general overload, that takes any string matcher, is in catch_capture_matchers.cpp
2663+ void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str ) {
2664+ handleExceptionMatchExpr( handler, Matchers::Equals( str ) );
2665+ }
2666+
2667+} // namespace Catch
2668+
2669+
2670+
2671+
2672+#include <algorithm>
2673+
2674+namespace Catch {
2675+ namespace Detail {
2676+
2677+ bool CaseInsensitiveLess::operator()( StringRef lhs,
2678+ StringRef rhs ) const {
2679+ return std::lexicographical_compare(
2680+ lhs.begin(), lhs.end(),
2681+ rhs.begin(), rhs.end(),
2682+ []( char l, char r ) { return toLower( l ) < toLower( r ); } );
2683+ }
2684+
2685+ bool
2686+ CaseInsensitiveEqualTo::operator()( StringRef lhs,
2687+ StringRef rhs ) const {
2688+ return std::equal(
2689+ lhs.begin(), lhs.end(),
2690+ rhs.begin(), rhs.end(),
2691+ []( char l, char r ) { return toLower( l ) == toLower( r ); } );
2692+ }
2693+
2694+ } // namespace Detail
2695+} // namespace Catch
2696+
2697+
2698+
2699+
2700+#include <algorithm>
2701+#include <ostream>
2702+
2703+namespace {
2704+ bool isOptPrefix( char c ) {
2705+ return c == '-'
2706+#ifdef CATCH_PLATFORM_WINDOWS
2707+ || c == '/'
2708+#endif
2709+ ;
2710+ }
2711+
2712+ Catch::StringRef normaliseOpt( Catch::StringRef optName ) {
2713+ if ( optName[0] == '-'
2714+#if defined(CATCH_PLATFORM_WINDOWS)
2715+ || optName[0] == '/'
2716+#endif
2717+ ) {
2718+ return optName.substr( 1, optName.size() );
2719+ }
2720+
2721+ return optName;
2722+ }
2723+
2724+ static size_t find_first_separator(Catch::StringRef sr) {
2725+ auto is_separator = []( char c ) {
2726+ return c == ' ' || c == ':' || c == '=';
2727+ };
2728+ size_t pos = 0;
2729+ while (pos < sr.size()) {
2730+ if (is_separator(sr[pos])) { return pos; }
2731+ ++pos;
2732+ }
2733+
2734+ return Catch::StringRef::npos;
2735+ }
2736+
2737+} // namespace
2738+
2739+namespace Catch {
2740+ namespace Clara {
2741+ namespace Detail {
2742+
2743+ void TokenStream::loadBuffer() {
2744+ m_tokenBuffer.clear();
2745+
2746+ // Skip any empty strings
2747+ while ( it != itEnd && it->empty() ) {
2748+ ++it;
2749+ }
2750+
2751+ if ( it != itEnd ) {
2752+ StringRef next = *it;
2753+ if ( isOptPrefix( next[0] ) ) {
2754+ auto delimiterPos = find_first_separator(next);
2755+ if ( delimiterPos != StringRef::npos ) {
2756+ m_tokenBuffer.push_back(
2757+ { TokenType::Option,
2758+ next.substr( 0, delimiterPos ) } );
2759+ m_tokenBuffer.push_back(
2760+ { TokenType::Argument,
2761+ next.substr( delimiterPos + 1, next.size() ) } );
2762+ } else {
2763+ if ( next[1] != '-' && next.size() > 2 ) {
2764+ // Combined short args, e.g. "-ab" for "-a -b"
2765+ for ( size_t i = 1; i < next.size(); ++i ) {
2766+ m_tokenBuffer.push_back(
2767+ { TokenType::Option,
2768+ next.substr( i, 1 ) } );
2769+ }
2770+ } else {
2771+ m_tokenBuffer.push_back(
2772+ { TokenType::Option, next } );
2773+ }
2774+ }
2775+ } else {
2776+ m_tokenBuffer.push_back(
2777+ { TokenType::Argument, next } );
2778+ }
2779+ }
2780+ }
2781+
2782+ TokenStream::TokenStream( Args const& args ):
2783+ TokenStream( args.m_args.begin(), args.m_args.end() ) {}
2784+
2785+ TokenStream::TokenStream( Iterator it_, Iterator itEnd_ ):
2786+ it( it_ ), itEnd( itEnd_ ) {
2787+ loadBuffer();
2788+ }
2789+
2790+ TokenStream& TokenStream::operator++() {
2791+ if ( m_tokenBuffer.size() >= 2 ) {
2792+ m_tokenBuffer.erase( m_tokenBuffer.begin() );
2793+ } else {
2794+ if ( it != itEnd )
2795+ ++it;
2796+ loadBuffer();
2797+ }
2798+ return *this;
2799+ }
2800+
2801+ ParserResult convertInto( std::string const& source,
2802+ std::string& target ) {
2803+ target = source;
2804+ return ParserResult::ok( ParseResultType::Matched );
2805+ }
2806+
2807+ ParserResult convertInto( std::string const& source,
2808+ bool& target ) {
2809+ std::string srcLC = toLower( source );
2810+
2811+ if ( srcLC == "y" || srcLC == "1" || srcLC == "true" ||
2812+ srcLC == "yes" || srcLC == "on" ) {
2813+ target = true;
2814+ } else if ( srcLC == "n" || srcLC == "0" || srcLC == "false" ||
2815+ srcLC == "no" || srcLC == "off" ) {
2816+ target = false;
2817+ } else {
2818+ return ParserResult::runtimeError(
2819+ "Expected a boolean value but did not recognise: '" +
2820+ source + '\'' );
2821+ }
2822+ return ParserResult::ok( ParseResultType::Matched );
2823+ }
2824+
2825+ size_t ParserBase::cardinality() const { return 1; }
2826+
2827+ InternalParseResult ParserBase::parse( Args const& args ) const {
2828+ return parse( static_cast<std::string>(args.exeName()), TokenStream( args ) );
2829+ }
2830+
2831+ ParseState::ParseState( ParseResultType type,
2832+ TokenStream remainingTokens ):
2833+ m_type( type ), m_remainingTokens( CATCH_MOVE(remainingTokens) ) {}
2834+
2835+ ParserResult BoundFlagRef::setFlag( bool flag ) {
2836+ m_ref = flag;
2837+ return ParserResult::ok( ParseResultType::Matched );
2838+ }
2839+
2840+ ResultBase::~ResultBase() = default;
2841+
2842+ bool BoundRef::isContainer() const { return false; }
2843+
2844+ bool BoundRef::isFlag() const { return false; }
2845+
2846+ bool BoundFlagRefBase::isFlag() const { return true; }
2847+
2848+} // namespace Detail
2849+
2850+ Detail::InternalParseResult Arg::parse(std::string const&,
2851+ Detail::TokenStream tokens) const {
2852+ auto validationResult = validate();
2853+ if (!validationResult)
2854+ return Detail::InternalParseResult(validationResult);
2855+
2856+ auto token = *tokens;
2857+ if (token.type != Detail::TokenType::Argument)
2858+ return Detail::InternalParseResult::ok(Detail::ParseState(
2859+ ParseResultType::NoMatch, CATCH_MOVE(tokens)));
2860+
2861+ assert(!m_ref->isFlag());
2862+ auto valueRef =
2863+ static_cast<Detail::BoundValueRefBase*>(m_ref.get());
2864+
2865+ auto result = valueRef->setValue(static_cast<std::string>(token.token));
2866+ if ( !result )
2867+ return Detail::InternalParseResult( result );
2868+ else
2869+ return Detail::InternalParseResult::ok(
2870+ Detail::ParseState( ParseResultType::Matched,
2871+ CATCH_MOVE( ++tokens ) ) );
2872+ }
2873+
2874+ Opt::Opt(bool& ref) :
2875+ ParserRefImpl(std::make_shared<Detail::BoundFlagRef>(ref)) {}
2876+
2877+ Detail::HelpColumns Opt::getHelpColumns() const {
2878+ ReusableStringStream oss;
2879+ bool first = true;
2880+ for (auto const& opt : m_optNames) {
2881+ if (first)
2882+ first = false;
2883+ else
2884+ oss << ", ";
2885+ oss << opt;
2886+ }
2887+ if (!m_hint.empty())
2888+ oss << " <" << m_hint << '>';
2889+ return { oss.str(), m_description };
2890+ }
2891+
2892+ bool Opt::isMatch(StringRef optToken) const {
2893+ auto normalisedToken = normaliseOpt(optToken);
2894+ for (auto const& name : m_optNames) {
2895+ if (normaliseOpt(name) == normalisedToken)
2896+ return true;
2897+ }
2898+ return false;
2899+ }
2900+
2901+ Detail::InternalParseResult Opt::parse(std::string const&,
2902+ Detail::TokenStream tokens) const {
2903+ auto validationResult = validate();
2904+ if (!validationResult)
2905+ return Detail::InternalParseResult(validationResult);
2906+
2907+ if (tokens &&
2908+ tokens->type == Detail::TokenType::Option) {
2909+ auto const& token = *tokens;
2910+ if (isMatch(token.token)) {
2911+ if (m_ref->isFlag()) {
2912+ auto flagRef =
2913+ static_cast<Detail::BoundFlagRefBase*>(
2914+ m_ref.get());
2915+ auto result = flagRef->setFlag(true);
2916+ if (!result)
2917+ return Detail::InternalParseResult(result);
2918+ if (result.value() ==
2919+ ParseResultType::ShortCircuitAll)
2920+ return Detail::InternalParseResult::ok(Detail::ParseState(
2921+ result.value(), CATCH_MOVE(tokens)));
2922+ } else {
2923+ auto valueRef =
2924+ static_cast<Detail::BoundValueRefBase*>(
2925+ m_ref.get());
2926+ ++tokens;
2927+ if (!tokens)
2928+ return Detail::InternalParseResult::runtimeError(
2929+ "Expected argument following " +
2930+ token.token);
2931+ auto const& argToken = *tokens;
2932+ if (argToken.type != Detail::TokenType::Argument)
2933+ return Detail::InternalParseResult::runtimeError(
2934+ "Expected argument following " +
2935+ token.token);
2936+ const auto result = valueRef->setValue(static_cast<std::string>(argToken.token));
2937+ if (!result)
2938+ return Detail::InternalParseResult(result);
2939+ if (result.value() ==
2940+ ParseResultType::ShortCircuitAll)
2941+ return Detail::InternalParseResult::ok(Detail::ParseState(
2942+ result.value(), CATCH_MOVE(tokens)));
2943+ }
2944+ return Detail::InternalParseResult::ok(Detail::ParseState(
2945+ ParseResultType::Matched, CATCH_MOVE(++tokens)));
2946+ }
2947+ }
2948+ return Detail::InternalParseResult::ok(
2949+ Detail::ParseState(ParseResultType::NoMatch, CATCH_MOVE(tokens)));
2950+ }
2951+
2952+ Detail::Result Opt::validate() const {
2953+ if (m_optNames.empty())
2954+ return Detail::Result::logicError("No options supplied to Opt");
2955+ for (auto const& name : m_optNames) {
2956+ if (name.empty())
2957+ return Detail::Result::logicError(
2958+ "Option name cannot be empty");
2959+#ifdef CATCH_PLATFORM_WINDOWS
2960+ if (name[0] != '-' && name[0] != '/')
2961+ return Detail::Result::logicError(
2962+ "Option name must begin with '-' or '/'");
2963+#else
2964+ if (name[0] != '-')
2965+ return Detail::Result::logicError(
2966+ "Option name must begin with '-'");
2967+#endif
2968+ }
2969+ return ParserRefImpl::validate();
2970+ }
2971+
2972+ ExeName::ExeName() :
2973+ m_name(std::make_shared<std::string>("<executable>")) {}
2974+
2975+ ExeName::ExeName(std::string& ref) : ExeName() {
2976+ m_ref = std::make_shared<Detail::BoundValueRef<std::string>>(ref);
2977+ }
2978+
2979+ Detail::InternalParseResult
2980+ ExeName::parse(std::string const&,
2981+ Detail::TokenStream tokens) const {
2982+ return Detail::InternalParseResult::ok(
2983+ Detail::ParseState(ParseResultType::NoMatch, CATCH_MOVE(tokens)));
2984+ }
2985+
2986+ ParserResult ExeName::set(std::string const& newName) {
2987+ auto lastSlash = newName.find_last_of("\\/");
2988+ auto filename = (lastSlash == std::string::npos)
2989+ ? newName
2990+ : newName.substr(lastSlash + 1);
2991+
2992+ *m_name = filename;
2993+ if (m_ref)
2994+ return m_ref->setValue(filename);
2995+ else
2996+ return ParserResult::ok(ParseResultType::Matched);
2997+ }
2998+
2999+
3000+
3001+
3002+ Parser& Parser::operator|=( Parser const& other ) {
3003+ m_options.insert( m_options.end(),
3004+ other.m_options.begin(),
3005+ other.m_options.end() );
3006+ m_args.insert(
3007+ m_args.end(), other.m_args.begin(), other.m_args.end() );
3008+ return *this;
3009+ }
3010+
3011+ std::vector<Detail::HelpColumns> Parser::getHelpColumns() const {
3012+ std::vector<Detail::HelpColumns> cols;
3013+ cols.reserve( m_options.size() );
3014+ for ( auto const& o : m_options ) {
3015+ cols.push_back(o.getHelpColumns());
3016+ }
3017+ return cols;
3018+ }
3019+
3020+ void Parser::writeToStream( std::ostream& os ) const {
3021+ if ( !m_exeName.name().empty() ) {
3022+ os << "usage:\n"
3023+ << " " << m_exeName.name() << ' ';
3024+ bool required = true, first = true;
3025+ for ( auto const& arg : m_args ) {
3026+ if ( first )
3027+ first = false;
3028+ else
3029+ os << ' ';
3030+ if ( arg.isOptional() && required ) {
3031+ os << '[';
3032+ required = false;
3033+ }
3034+ os << '<' << arg.hint() << '>';
3035+ if ( arg.cardinality() == 0 )
3036+ os << " ... ";
3037+ }
3038+ if ( !required )
3039+ os << ']';
3040+ if ( !m_options.empty() )
3041+ os << " options";
3042+ os << "\n\nwhere options are:\n";
3043+ }
3044+
3045+ auto rows = getHelpColumns();
3046+ size_t consoleWidth = CATCH_CONFIG_CONSOLE_WIDTH;
3047+ size_t optWidth = 0;
3048+ for ( auto const& cols : rows )
3049+ optWidth = ( std::max )( optWidth, cols.left.size() + 2 );
3050+
3051+ optWidth = ( std::min )( optWidth, consoleWidth / 2 );
3052+
3053+ for ( auto& cols : rows ) {
3054+ auto row = TextFlow::Column( CATCH_MOVE(cols.left) )
3055+ .width( optWidth )
3056+ .indent( 2 ) +
3057+ TextFlow::Spacer( 4 ) +
3058+ TextFlow::Column( static_cast<std::string>(cols.descriptions) )
3059+ .width( consoleWidth - 7 - optWidth );
3060+ os << row << '\n';
3061+ }
3062+ }
3063+
3064+ Detail::Result Parser::validate() const {
3065+ for ( auto const& opt : m_options ) {
3066+ auto result = opt.validate();
3067+ if ( !result )
3068+ return result;
3069+ }
3070+ for ( auto const& arg : m_args ) {
3071+ auto result = arg.validate();
3072+ if ( !result )
3073+ return result;
3074+ }
3075+ return Detail::Result::ok();
3076+ }
3077+
3078+ Detail::InternalParseResult
3079+ Parser::parse( std::string const& exeName,
3080+ Detail::TokenStream tokens ) const {
3081+
3082+ struct ParserInfo {
3083+ ParserBase const* parser = nullptr;
3084+ size_t count = 0;
3085+ };
3086+ std::vector<ParserInfo> parseInfos;
3087+ parseInfos.reserve( m_options.size() + m_args.size() );
3088+ for ( auto const& opt : m_options ) {
3089+ parseInfos.push_back( { &opt, 0 } );
3090+ }
3091+ for ( auto const& arg : m_args ) {
3092+ parseInfos.push_back( { &arg, 0 } );
3093+ }
3094+
3095+ m_exeName.set( exeName );
3096+
3097+ auto result = Detail::InternalParseResult::ok(
3098+ Detail::ParseState( ParseResultType::NoMatch, CATCH_MOVE(tokens) ) );
3099+ while ( result.value().remainingTokens() ) {
3100+ bool tokenParsed = false;
3101+
3102+ for ( auto& parseInfo : parseInfos ) {
3103+ if ( parseInfo.parser->cardinality() == 0 ||
3104+ parseInfo.count < parseInfo.parser->cardinality() ) {
3105+ result = parseInfo.parser->parse(
3106+ exeName, CATCH_MOVE(result).value().remainingTokens() );
3107+ if ( !result )
3108+ return result;
3109+ if ( result.value().type() !=
3110+ ParseResultType::NoMatch ) {
3111+ tokenParsed = true;
3112+ ++parseInfo.count;
3113+ break;
3114+ }
3115+ }
3116+ }
3117+
3118+ if ( result.value().type() == ParseResultType::ShortCircuitAll )
3119+ return result;
3120+ if ( !tokenParsed )
3121+ return Detail::InternalParseResult::runtimeError(
3122+ "Unrecognised token: " +
3123+ result.value().remainingTokens()->token );
3124+ }
3125+ // !TBD Check missing required options
3126+ return result;
3127+ }
3128+
3129+ Args::Args(int argc, char const* const* argv) :
3130+ m_exeName(argv[0]), m_args(argv + 1, argv + argc) {}
3131+
3132+ Args::Args(std::initializer_list<StringRef> args) :
3133+ m_exeName(*args.begin()),
3134+ m_args(args.begin() + 1, args.end()) {}
3135+
3136+
3137+ Help::Help( bool& showHelpFlag ):
3138+ Opt( [&]( bool flag ) {
3139+ showHelpFlag = flag;
3140+ return ParserResult::ok( ParseResultType::ShortCircuitAll );
3141+ } ) {
3142+ static_cast<Opt&> ( *this )(
3143+ "display usage information" )["-?"]["-h"]["--help"]
3144+ .optional();
3145+ }
3146+
3147+ } // namespace Clara
3148+} // namespace Catch
3149+
3150+
3151+
3152+
3153+#include <fstream>
3154+#include <string>
3155+
3156+namespace Catch {
3157+
3158+ Clara::Parser makeCommandLineParser( ConfigData& config ) {
3159+
3160+ using namespace Clara;
3161+
3162+ auto const setWarning = [&]( std::string const& warning ) {
3163+ if ( warning == "NoAssertions" ) {
3164+ config.warnings = static_cast<WarnAbout::What>(config.warnings | WarnAbout::NoAssertions);
3165+ return ParserResult::ok( ParseResultType::Matched );
3166+ } else if ( warning == "UnmatchedTestSpec" ) {
3167+ config.warnings = static_cast<WarnAbout::What>(config.warnings | WarnAbout::UnmatchedTestSpec);
3168+ return ParserResult::ok( ParseResultType::Matched );
3169+ }
3170+
3171+ return ParserResult ::runtimeError(
3172+ "Unrecognised warning option: '" + warning + '\'' );
3173+ };
3174+ auto const loadTestNamesFromFile = [&]( std::string const& filename ) {
3175+ std::ifstream f( filename.c_str() );
3176+ if( !f.is_open() )
3177+ return ParserResult::runtimeError( "Unable to load input file: '" + filename + '\'' );
3178+
3179+ std::string line;
3180+ while( std::getline( f, line ) ) {
3181+ line = trim(line);
3182+ if( !line.empty() && !startsWith( line, '#' ) ) {
3183+ if( !startsWith( line, '"' ) )
3184+ line = '"' + CATCH_MOVE(line) + '"';
3185+ config.testsOrTags.push_back( line );
3186+ config.testsOrTags.emplace_back( "," );
3187+ }
3188+ }
3189+ //Remove comma in the end
3190+ if(!config.testsOrTags.empty())
3191+ config.testsOrTags.erase( config.testsOrTags.end()-1 );
3192+
3193+ return ParserResult::ok( ParseResultType::Matched );
3194+ };
3195+ auto const setTestOrder = [&]( std::string const& order ) {
3196+ if( startsWith( "declared", order ) )
3197+ config.runOrder = TestRunOrder::Declared;
3198+ else if( startsWith( "lexical", order ) )
3199+ config.runOrder = TestRunOrder::LexicographicallySorted;
3200+ else if( startsWith( "random", order ) )
3201+ config.runOrder = TestRunOrder::Randomized;
3202+ else
3203+ return ParserResult::runtimeError( "Unrecognised ordering: '" + order + '\'' );
3204+ return ParserResult::ok( ParseResultType::Matched );
3205+ };
3206+ auto const setRngSeed = [&]( std::string const& seed ) {
3207+ if( seed == "time" ) {
3208+ config.rngSeed = generateRandomSeed(GenerateFrom::Time);
3209+ return ParserResult::ok(ParseResultType::Matched);
3210+ } else if (seed == "random-device") {
3211+ config.rngSeed = generateRandomSeed(GenerateFrom::RandomDevice);
3212+ return ParserResult::ok(ParseResultType::Matched);
3213+ }
3214+
3215+ // TODO: ideally we should be parsing uint32_t directly
3216+ // fix this later when we add new parse overload
3217+ auto parsedSeed = parseUInt( seed, 0 );
3218+ if ( !parsedSeed ) {
3219+ return ParserResult::runtimeError( "Could not parse '" + seed + "' as seed" );
3220+ }
3221+ config.rngSeed = *parsedSeed;
3222+ return ParserResult::ok( ParseResultType::Matched );
3223+ };
3224+ auto const setDefaultColourMode = [&]( std::string const& colourMode ) {
3225+ Optional<ColourMode> maybeMode = Catch::Detail::stringToColourMode(toLower( colourMode ));
3226+ if ( !maybeMode ) {
3227+ return ParserResult::runtimeError(
3228+ "colour mode must be one of: default, ansi, win32, "
3229+ "or none. '" +
3230+ colourMode + "' is not recognised" );
3231+ }
3232+ auto mode = *maybeMode;
3233+ if ( !isColourImplAvailable( mode ) ) {
3234+ return ParserResult::runtimeError(
3235+ "colour mode '" + colourMode +
3236+ "' is not supported in this binary" );
3237+ }
3238+ config.defaultColourMode = mode;
3239+ return ParserResult::ok( ParseResultType::Matched );
3240+ };
3241+ auto const setWaitForKeypress = [&]( std::string const& keypress ) {
3242+ auto keypressLc = toLower( keypress );
3243+ if (keypressLc == "never")
3244+ config.waitForKeypress = WaitForKeypress::Never;
3245+ else if( keypressLc == "start" )
3246+ config.waitForKeypress = WaitForKeypress::BeforeStart;
3247+ else if( keypressLc == "exit" )
3248+ config.waitForKeypress = WaitForKeypress::BeforeExit;
3249+ else if( keypressLc == "both" )
3250+ config.waitForKeypress = WaitForKeypress::BeforeStartAndExit;
3251+ else
3252+ return ParserResult::runtimeError( "keypress argument must be one of: never, start, exit or both. '" + keypress + "' not recognised" );
3253+ return ParserResult::ok( ParseResultType::Matched );
3254+ };
3255+ auto const setVerbosity = [&]( std::string const& verbosity ) {
3256+ auto lcVerbosity = toLower( verbosity );
3257+ if( lcVerbosity == "quiet" )
3258+ config.verbosity = Verbosity::Quiet;
3259+ else if( lcVerbosity == "normal" )
3260+ config.verbosity = Verbosity::Normal;
3261+ else if( lcVerbosity == "high" )
3262+ config.verbosity = Verbosity::High;
3263+ else
3264+ return ParserResult::runtimeError( "Unrecognised verbosity, '" + verbosity + '\'' );
3265+ return ParserResult::ok( ParseResultType::Matched );
3266+ };
3267+ auto const setReporter = [&]( std::string const& userReporterSpec ) {
3268+ if ( userReporterSpec.empty() ) {
3269+ return ParserResult::runtimeError( "Received empty reporter spec." );
3270+ }
3271+
3272+ Optional<ReporterSpec> parsed =
3273+ parseReporterSpec( userReporterSpec );
3274+ if ( !parsed ) {
3275+ return ParserResult::runtimeError(
3276+ "Could not parse reporter spec '" + userReporterSpec +
3277+ "'" );
3278+ }
3279+
3280+ auto const& reporterSpec = *parsed;
3281+
3282+ auto const& factories =
3283+ getRegistryHub().getReporterRegistry().getFactories();
3284+ auto result = factories.find( reporterSpec.name() );
3285+
3286+ if ( result == factories.end() ) {
3287+ return ParserResult::runtimeError(
3288+ "Unrecognized reporter, '" + reporterSpec.name() +
3289+ "'. Check available with --list-reporters" );
3290+ }
3291+
3292+
3293+ const bool hadOutputFile = reporterSpec.outputFile().some();
3294+ config.reporterSpecifications.push_back( CATCH_MOVE( *parsed ) );
3295+ // It would be enough to check this only once at the very end, but
3296+ // there is not a place where we could call this check, so do it
3297+ // every time it could fail. For valid inputs, this is still called
3298+ // at most once.
3299+ if (!hadOutputFile) {
3300+ int n_reporters_without_file = 0;
3301+ for (auto const& spec : config.reporterSpecifications) {
3302+ if (spec.outputFile().none()) {
3303+ n_reporters_without_file++;
3304+ }
3305+ }
3306+ if (n_reporters_without_file > 1) {
3307+ return ParserResult::runtimeError( "Only one reporter may have unspecified output file." );
3308+ }
3309+ }
3310+
3311+ return ParserResult::ok( ParseResultType::Matched );
3312+ };
3313+ auto const setShardCount = [&]( std::string const& shardCount ) {
3314+ auto parsedCount = parseUInt( shardCount );
3315+ if ( !parsedCount ) {
3316+ return ParserResult::runtimeError(
3317+ "Could not parse '" + shardCount + "' as shard count" );
3318+ }
3319+ if ( *parsedCount == 0 ) {
3320+ return ParserResult::runtimeError(
3321+ "Shard count must be positive" );
3322+ }
3323+ config.shardCount = *parsedCount;
3324+ return ParserResult::ok( ParseResultType::Matched );
3325+ };
3326+
3327+ auto const setShardIndex = [&](std::string const& shardIndex) {
3328+ auto parsedIndex = parseUInt( shardIndex );
3329+ if ( !parsedIndex ) {
3330+ return ParserResult::runtimeError(
3331+ "Could not parse '" + shardIndex + "' as shard index" );
3332+ }
3333+ config.shardIndex = *parsedIndex;
3334+ return ParserResult::ok( ParseResultType::Matched );
3335+ };
3336+
3337+ auto cli
3338+ = ExeName( config.processName )
3339+ | Help( config.showHelp )
3340+ | Opt( config.showSuccessfulTests )
3341+ ["-s"]["--success"]
3342+ ( "include successful tests in output" )
3343+ | Opt( config.shouldDebugBreak )
3344+ ["-b"]["--break"]
3345+ ( "break into debugger on failure" )
3346+ | Opt( config.noThrow )
3347+ ["-e"]["--nothrow"]
3348+ ( "skip exception tests" )
3349+ | Opt( config.showInvisibles )
3350+ ["-i"]["--invisibles"]
3351+ ( "show invisibles (tabs, newlines)" )
3352+ | Opt( config.defaultOutputFilename, "filename" )
3353+ ["-o"]["--out"]
3354+ ( "default output filename" )
3355+ | Opt( accept_many, setReporter, "name[::key=value]*" )
3356+ ["-r"]["--reporter"]
3357+ ( "reporter to use (defaults to console)" )
3358+ | Opt( config.name, "name" )
3359+ ["-n"]["--name"]
3360+ ( "suite name" )
3361+ | Opt( [&]( bool ){ config.abortAfter = 1; } )
3362+ ["-a"]["--abort"]
3363+ ( "abort at first failure" )
3364+ | Opt( [&]( int x ){ config.abortAfter = x; }, "no. failures" )
3365+ ["-x"]["--abortx"]
3366+ ( "abort after x failures" )
3367+ | Opt( accept_many, setWarning, "warning name" )
3368+ ["-w"]["--warn"]
3369+ ( "enable warnings" )
3370+ | Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" )
3371+ ["-d"]["--durations"]
3372+ ( "show test durations" )
3373+ | Opt( config.minDuration, "seconds" )
3374+ ["-D"]["--min-duration"]
3375+ ( "show test durations for tests taking at least the given number of seconds" )
3376+ | Opt( loadTestNamesFromFile, "filename" )
3377+ ["-f"]["--input-file"]
3378+ ( "load test names to run from a file" )
3379+ | Opt( config.filenamesAsTags )
3380+ ["-#"]["--filenames-as-tags"]
3381+ ( "adds a tag for the filename" )
3382+ | Opt( config.sectionsToRun, "section name" )
3383+ ["-c"]["--section"]
3384+ ( "specify section to run" )
3385+ | Opt( setVerbosity, "quiet|normal|high" )
3386+ ["-v"]["--verbosity"]
3387+ ( "set output verbosity" )
3388+ | Opt( config.listTests )
3389+ ["--list-tests"]
3390+ ( "list all/matching test cases" )
3391+ | Opt( config.listTags )
3392+ ["--list-tags"]
3393+ ( "list all/matching tags" )
3394+ | Opt( config.listReporters )
3395+ ["--list-reporters"]
3396+ ( "list all available reporters" )
3397+ | Opt( config.listListeners )
3398+ ["--list-listeners"]
3399+ ( "list all listeners" )
3400+ | Opt( setTestOrder, "decl|lex|rand" )
3401+ ["--order"]
3402+ ( "test case order (defaults to decl)" )
3403+ | Opt( setRngSeed, "'time'|'random-device'|number" )
3404+ ["--rng-seed"]
3405+ ( "set a specific seed for random numbers" )
3406+ | Opt( setDefaultColourMode, "ansi|win32|none|default" )
3407+ ["--colour-mode"]
3408+ ( "what color mode should be used as default" )
3409+ | Opt( config.libIdentify )
3410+ ["--libidentify"]
3411+ ( "report name and version according to libidentify standard" )
3412+ | Opt( setWaitForKeypress, "never|start|exit|both" )
3413+ ["--wait-for-keypress"]
3414+ ( "waits for a keypress before exiting" )
3415+ | Opt( config.skipBenchmarks)
3416+ ["--skip-benchmarks"]
3417+ ( "disable running benchmarks")
3418+ | Opt( config.benchmarkSamples, "samples" )
3419+ ["--benchmark-samples"]
3420+ ( "number of samples to collect (default: 100)" )
3421+ | Opt( config.benchmarkResamples, "resamples" )
3422+ ["--benchmark-resamples"]
3423+ ( "number of resamples for the bootstrap (default: 100000)" )
3424+ | Opt( config.benchmarkConfidenceInterval, "confidence interval" )
3425+ ["--benchmark-confidence-interval"]
3426+ ( "confidence interval for the bootstrap (between 0 and 1, default: 0.95)" )
3427+ | Opt( config.benchmarkNoAnalysis )
3428+ ["--benchmark-no-analysis"]
3429+ ( "perform only measurements; do not perform any analysis" )
3430+ | Opt( config.benchmarkWarmupTime, "benchmarkWarmupTime" )
3431+ ["--benchmark-warmup-time"]
3432+ ( "amount of time in milliseconds spent on warming up each test (default: 100)" )
3433+ | Opt( setShardCount, "shard count" )
3434+ ["--shard-count"]
3435+ ( "split the tests to execute into this many groups" )
3436+ | Opt( setShardIndex, "shard index" )
3437+ ["--shard-index"]
3438+ ( "index of the group of tests to execute (see --shard-count)" )
3439+ | Opt( config.allowZeroTests )
3440+ ["--allow-running-no-tests"]
3441+ ( "Treat 'No tests run' as a success" )
3442+ | Arg( config.testsOrTags, "test name|pattern|tags" )
3443+ ( "which test or tests to use" );
3444+
3445+ return cli;
3446+ }
3447+
3448+} // end namespace Catch
3449+
3450+
3451+#if defined(__clang__)
3452+# pragma clang diagnostic push
3453+# pragma clang diagnostic ignored "-Wexit-time-destructors"
3454+#endif
3455+
3456+
3457+
3458+#include <cassert>
3459+#include <ostream>
3460+#include <utility>
3461+
3462+namespace Catch {
3463+
3464+ ColourImpl::~ColourImpl() = default;
3465+
3466+ ColourImpl::ColourGuard ColourImpl::guardColour( Colour::Code colourCode ) {
3467+ return ColourGuard(colourCode, this );
3468+ }
3469+
3470+ void ColourImpl::ColourGuard::engageImpl( std::ostream& stream ) {
3471+ assert( &stream == &m_colourImpl->m_stream->stream() &&
3472+ "Engaging colour guard for different stream than used by the "
3473+ "parent colour implementation" );
3474+ static_cast<void>( stream );
3475+
3476+ m_engaged = true;
3477+ m_colourImpl->use( m_code );
3478+ }
3479+
3480+ ColourImpl::ColourGuard::ColourGuard( Colour::Code code,
3481+ ColourImpl const* colour ):
3482+ m_colourImpl( colour ), m_code( code ) {
3483+ }
3484+ ColourImpl::ColourGuard::ColourGuard( ColourGuard&& rhs ) noexcept:
3485+ m_colourImpl( rhs.m_colourImpl ),
3486+ m_code( rhs.m_code ),
3487+ m_engaged( rhs.m_engaged ) {
3488+ rhs.m_engaged = false;
3489+ }
3490+ ColourImpl::ColourGuard&
3491+ ColourImpl::ColourGuard::operator=( ColourGuard&& rhs ) noexcept {
3492+ using std::swap;
3493+ swap( m_colourImpl, rhs.m_colourImpl );
3494+ swap( m_code, rhs.m_code );
3495+ swap( m_engaged, rhs.m_engaged );
3496+
3497+ return *this;
3498+ }
3499+ ColourImpl::ColourGuard::~ColourGuard() {
3500+ if ( m_engaged ) {
3501+ m_colourImpl->use( Colour::None );
3502+ }
3503+ }
3504+
3505+ ColourImpl::ColourGuard&
3506+ ColourImpl::ColourGuard::engage( std::ostream& stream ) & {
3507+ engageImpl( stream );
3508+ return *this;
3509+ }
3510+
3511+ ColourImpl::ColourGuard&&
3512+ ColourImpl::ColourGuard::engage( std::ostream& stream ) && {
3513+ engageImpl( stream );
3514+ return CATCH_MOVE(*this);
3515+ }
3516+
3517+ namespace {
3518+ //! A do-nothing implementation of colour, used as fallback for unknown
3519+ //! platforms, and when the user asks to deactivate all colours.
3520+ class NoColourImpl final : public ColourImpl {
3521+ public:
3522+ NoColourImpl( IStream* stream ): ColourImpl( stream ) {}
3523+
3524+ private:
3525+ void use( Colour::Code ) const override {}
3526+ };
3527+ } // namespace
3528+
3529+
3530+} // namespace Catch
3531+
3532+
3533+#if defined ( CATCH_CONFIG_COLOUR_WIN32 ) /////////////////////////////////////////
3534+
3535+namespace Catch {
3536+namespace {
3537+
3538+ class Win32ColourImpl final : public ColourImpl {
3539+ public:
3540+ Win32ColourImpl(IStream* stream):
3541+ ColourImpl(stream) {
3542+ CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
3543+ GetConsoleScreenBufferInfo( GetStdHandle( STD_OUTPUT_HANDLE ),
3544+ &csbiInfo );
3545+ originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY );
3546+ originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY );
3547+ }
3548+
3549+ static bool useImplementationForStream(IStream const& stream) {
3550+ // Win32 text colour APIs can only be used on console streams
3551+ // We cannot check that the output hasn't been redirected,
3552+ // so we just check that the original stream is console stream.
3553+ return stream.isConsole();
3554+ }
3555+
3556+ private:
3557+ void use( Colour::Code _colourCode ) const override {
3558+ switch( _colourCode ) {
3559+ case Colour::None: return setTextAttribute( originalForegroundAttributes );
3560+ case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
3561+ case Colour::Red: return setTextAttribute( FOREGROUND_RED );
3562+ case Colour::Green: return setTextAttribute( FOREGROUND_GREEN );
3563+ case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE );
3564+ case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN );
3565+ case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN );
3566+ case Colour::Grey: return setTextAttribute( 0 );
3567+
3568+ case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY );
3569+ case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED );
3570+ case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN );
3571+ case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
3572+ case Colour::BrightYellow: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN );
3573+
3574+ case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" );
3575+
3576+ default:
3577+ CATCH_ERROR( "Unknown colour requested" );
3578+ }
3579+ }
3580+
3581+ void setTextAttribute( WORD _textAttribute ) const {
3582+ SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ),
3583+ _textAttribute |
3584+ originalBackgroundAttributes );
3585+ }
3586+ WORD originalForegroundAttributes;
3587+ WORD originalBackgroundAttributes;
3588+ };
3589+
3590+} // end anon namespace
3591+} // end namespace Catch
3592+
3593+#endif // Windows/ ANSI/ None
3594+
3595+
3596+#if defined( CATCH_PLATFORM_LINUX ) || defined( CATCH_PLATFORM_MAC )
3597+# define CATCH_INTERNAL_HAS_ISATTY
3598+# include <unistd.h>
3599+#endif
3600+
3601+namespace Catch {
3602+namespace {
3603+
3604+ class ANSIColourImpl final : public ColourImpl {
3605+ public:
3606+ ANSIColourImpl( IStream* stream ): ColourImpl( stream ) {}
3607+
3608+ static bool useImplementationForStream(IStream const& stream) {
3609+ // This is kinda messy due to trying to support a bunch of
3610+ // different platforms at once.
3611+ // The basic idea is that if we are asked to do autodetection (as
3612+ // opposed to being told to use posixy colours outright), then we
3613+ // only want to use the colours if we are writing to console.
3614+ // However, console might be redirected, so we make an attempt at
3615+ // checking for that on platforms where we know how to do that.
3616+ bool useColour = stream.isConsole();
3617+#if defined( CATCH_INTERNAL_HAS_ISATTY ) && \
3618+ !( defined( __DJGPP__ ) && defined( __STRICT_ANSI__ ) )
3619+ ErrnoGuard _; // for isatty
3620+ useColour = useColour && isatty( STDOUT_FILENO );
3621+# endif
3622+# if defined( CATCH_PLATFORM_MAC ) || defined( CATCH_PLATFORM_IPHONE )
3623+ useColour = useColour && !isDebuggerActive();
3624+# endif
3625+
3626+ return useColour;
3627+ }
3628+
3629+ private:
3630+ void use( Colour::Code _colourCode ) const override {
3631+ auto setColour = [&out =
3632+ m_stream->stream()]( char const* escapeCode ) {
3633+ // The escape sequence must be flushed to console, otherwise
3634+ // if stdin and stderr are intermixed, we'd get accidentally
3635+ // coloured output.
3636+ out << '\033' << escapeCode << std::flush;
3637+ };
3638+ switch( _colourCode ) {
3639+ case Colour::None:
3640+ case Colour::White: return setColour( "[0m" );
3641+ case Colour::Red: return setColour( "[0;31m" );
3642+ case Colour::Green: return setColour( "[0;32m" );
3643+ case Colour::Blue: return setColour( "[0;34m" );
3644+ case Colour::Cyan: return setColour( "[0;36m" );
3645+ case Colour::Yellow: return setColour( "[0;33m" );
3646+ case Colour::Grey: return setColour( "[1;30m" );
3647+
3648+ case Colour::LightGrey: return setColour( "[0;37m" );
3649+ case Colour::BrightRed: return setColour( "[1;31m" );
3650+ case Colour::BrightGreen: return setColour( "[1;32m" );
3651+ case Colour::BrightWhite: return setColour( "[1;37m" );
3652+ case Colour::BrightYellow: return setColour( "[1;33m" );
3653+
3654+ case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" );
3655+ default: CATCH_INTERNAL_ERROR( "Unknown colour requested" );
3656+ }
3657+ }
3658+ };
3659+
3660+} // end anon namespace
3661+} // end namespace Catch
3662+
3663+namespace Catch {
3664+
3665+ Detail::unique_ptr<ColourImpl> makeColourImpl( ColourMode colourSelection,
3666+ IStream* stream ) {
3667+#if defined( CATCH_CONFIG_COLOUR_WIN32 )
3668+ if ( colourSelection == ColourMode::Win32 ) {
3669+ return Detail::make_unique<Win32ColourImpl>( stream );
3670+ }
3671+#endif
3672+ if ( colourSelection == ColourMode::ANSI ) {
3673+ return Detail::make_unique<ANSIColourImpl>( stream );
3674+ }
3675+ if ( colourSelection == ColourMode::None ) {
3676+ return Detail::make_unique<NoColourImpl>( stream );
3677+ }
3678+
3679+ if ( colourSelection == ColourMode::PlatformDefault) {
3680+#if defined( CATCH_CONFIG_COLOUR_WIN32 )
3681+ if ( Win32ColourImpl::useImplementationForStream( *stream ) ) {
3682+ return Detail::make_unique<Win32ColourImpl>( stream );
3683+ }
3684+#endif
3685+ if ( ANSIColourImpl::useImplementationForStream( *stream ) ) {
3686+ return Detail::make_unique<ANSIColourImpl>( stream );
3687+ }
3688+ return Detail::make_unique<NoColourImpl>( stream );
3689+ }
3690+
3691+ CATCH_ERROR( "Could not create colour impl for selection " << static_cast<int>(colourSelection) );
3692+ }
3693+
3694+ bool isColourImplAvailable( ColourMode colourSelection ) {
3695+ switch ( colourSelection ) {
3696+#if defined( CATCH_CONFIG_COLOUR_WIN32 )
3697+ case ColourMode::Win32:
3698+#endif
3699+ case ColourMode::ANSI:
3700+ case ColourMode::None:
3701+ case ColourMode::PlatformDefault:
3702+ return true;
3703+ default:
3704+ return false;
3705+ }
3706+ }
3707+
3708+
3709+} // end namespace Catch
3710+
3711+#if defined(__clang__)
3712+# pragma clang diagnostic pop
3713+#endif
3714+
3715+
3716+
3717+
3718+namespace Catch {
3719+
3720+ Context* Context::currentContext = nullptr;
3721+
3722+ void cleanUpContext() {
3723+ delete Context::currentContext;
3724+ Context::currentContext = nullptr;
3725+ }
3726+ void Context::createContext() {
3727+ currentContext = new Context();
3728+ }
3729+
3730+ Context& getCurrentMutableContext() {
3731+ if ( !Context::currentContext ) { Context::createContext(); }
3732+ // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)
3733+ return *Context::currentContext;
3734+ }
3735+
3736+ void Context::setResultCapture( IResultCapture* resultCapture ) {
3737+ m_resultCapture = resultCapture;
3738+ }
3739+
3740+ void Context::setConfig( IConfig const* config ) { m_config = config; }
3741+
3742+ SimplePcg32& sharedRng() {
3743+ static SimplePcg32 s_rng;
3744+ return s_rng;
3745+ }
3746+
3747+}
3748+
3749+
3750+
3751+
3752+
3753+#include <ostream>
3754+
3755+#if defined(CATCH_CONFIG_ANDROID_LOGWRITE)
3756+#include <android/log.h>
3757+
3758+ namespace Catch {
3759+ void writeToDebugConsole( std::string const& text ) {
3760+ __android_log_write( ANDROID_LOG_DEBUG, "Catch", text.c_str() );
3761+ }
3762+ }
3763+
3764+#elif defined(CATCH_PLATFORM_WINDOWS)
3765+
3766+ namespace Catch {
3767+ void writeToDebugConsole( std::string const& text ) {
3768+ ::OutputDebugStringA( text.c_str() );
3769+ }
3770+ }
3771+
3772+#else
3773+
3774+ namespace Catch {
3775+ void writeToDebugConsole( std::string const& text ) {
3776+ // !TBD: Need a version for Mac/ XCode and other IDEs
3777+ Catch::cout() << text;
3778+ }
3779+ }
3780+
3781+#endif // Platform
3782+
3783+
3784+
3785+#if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE)
3786+
3787+# include <cassert>
3788+# include <sys/types.h>
3789+# include <unistd.h>
3790+# include <cstddef>
3791+# include <ostream>
3792+
3793+#ifdef __apple_build_version__
3794+ // These headers will only compile with AppleClang (XCode)
3795+ // For other compilers (Clang, GCC, ... ) we need to exclude them
3796+# include <sys/sysctl.h>
3797+#endif
3798+
3799+ namespace Catch {
3800+ #ifdef __apple_build_version__
3801+ // The following function is taken directly from the following technical note:
3802+ // https://developer.apple.com/library/archive/qa/qa1361/_index.html
3803+
3804+ // Returns true if the current process is being debugged (either
3805+ // running under the debugger or has a debugger attached post facto).
3806+ bool isDebuggerActive(){
3807+ int mib[4];
3808+ struct kinfo_proc info;
3809+ std::size_t size;
3810+
3811+ // Initialize the flags so that, if sysctl fails for some bizarre
3812+ // reason, we get a predictable result.
3813+
3814+ info.kp_proc.p_flag = 0;
3815+
3816+ // Initialize mib, which tells sysctl the info we want, in this case
3817+ // we're looking for information about a specific process ID.
3818+
3819+ mib[0] = CTL_KERN;
3820+ mib[1] = KERN_PROC;
3821+ mib[2] = KERN_PROC_PID;
3822+ mib[3] = getpid();
3823+
3824+ // Call sysctl.
3825+
3826+ size = sizeof(info);
3827+ if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, nullptr, 0) != 0 ) {
3828+ Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n\n" << std::flush;
3829+ return false;
3830+ }
3831+
3832+ // We're being debugged if the P_TRACED flag is set.
3833+
3834+ return ( (info.kp_proc.p_flag & P_TRACED) != 0 );
3835+ }
3836+ #else
3837+ bool isDebuggerActive() {
3838+ // We need to find another way to determine this for non-appleclang compilers on macOS
3839+ return false;
3840+ }
3841+ #endif
3842+ } // namespace Catch
3843+
3844+#elif defined(CATCH_PLATFORM_LINUX)
3845+ #include <fstream>
3846+ #include <string>
3847+
3848+ namespace Catch{
3849+ // The standard POSIX way of detecting a debugger is to attempt to
3850+ // ptrace() the process, but this needs to be done from a child and not
3851+ // this process itself to still allow attaching to this process later
3852+ // if wanted, so is rather heavy. Under Linux we have the PID of the
3853+ // "debugger" (which doesn't need to be gdb, of course, it could also
3854+ // be strace, for example) in /proc/$PID/status, so just get it from
3855+ // there instead.
3856+ bool isDebuggerActive(){
3857+ // Libstdc++ has a bug, where std::ifstream sets errno to 0
3858+ // This way our users can properly assert over errno values
3859+ ErrnoGuard guard;
3860+ std::ifstream in("/proc/self/status");
3861+ for( std::string line; std::getline(in, line); ) {
3862+ static const int PREFIX_LEN = 11;
3863+ if( line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0 ) {
3864+ // We're traced if the PID is not 0 and no other PID starts
3865+ // with 0 digit, so it's enough to check for just a single
3866+ // character.
3867+ return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0';
3868+ }
3869+ }
3870+
3871+ return false;
3872+ }
3873+ } // namespace Catch
3874+#elif defined(_MSC_VER)
3875+ extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
3876+ namespace Catch {
3877+ bool isDebuggerActive() {
3878+ return IsDebuggerPresent() != 0;
3879+ }
3880+ }
3881+#elif defined(__MINGW32__)
3882+ extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
3883+ namespace Catch {
3884+ bool isDebuggerActive() {
3885+ return IsDebuggerPresent() != 0;
3886+ }
3887+ }
3888+#else
3889+ namespace Catch {
3890+ bool isDebuggerActive() { return false; }
3891+ }
3892+#endif // Platform
3893+
3894+
3895+
3896+
3897+namespace Catch {
3898+
3899+ void ITransientExpression::streamReconstructedExpression(
3900+ std::ostream& os ) const {
3901+ // We can't make this function pure virtual to keep ITransientExpression
3902+ // constexpr, so we write error message instead
3903+ os << "Some class derived from ITransientExpression without overriding streamReconstructedExpression";
3904+ }
3905+
3906+ void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ) {
3907+ if( lhs.size() + rhs.size() < 40 &&
3908+ lhs.find('\n') == std::string::npos &&
3909+ rhs.find('\n') == std::string::npos )
3910+ os << lhs << ' ' << op << ' ' << rhs;
3911+ else
3912+ os << lhs << '\n' << op << '\n' << rhs;
3913+ }
3914+}
3915+
3916+
3917+
3918+#include <stdexcept>
3919+
3920+
3921+namespace Catch {
3922+#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER)
3923+ [[noreturn]]
3924+ void throw_exception(std::exception const& e) {
3925+ Catch::cerr() << "Catch will terminate because it needed to throw an exception.\n"
3926+ << "The message was: " << e.what() << '\n';
3927+ std::terminate();
3928+ }
3929+#endif
3930+
3931+ [[noreturn]]
3932+ void throw_logic_error(std::string const& msg) {
3933+ throw_exception(std::logic_error(msg));
3934+ }
3935+
3936+ [[noreturn]]
3937+ void throw_domain_error(std::string const& msg) {
3938+ throw_exception(std::domain_error(msg));
3939+ }
3940+
3941+ [[noreturn]]
3942+ void throw_runtime_error(std::string const& msg) {
3943+ throw_exception(std::runtime_error(msg));
3944+ }
3945+
3946+
3947+
3948+} // namespace Catch;
3949+
3950+
3951+
3952+#include <cassert>
3953+
3954+namespace Catch {
3955+
3956+ IMutableEnumValuesRegistry::~IMutableEnumValuesRegistry() = default;
3957+
3958+ namespace Detail {
3959+
3960+ namespace {
3961+ // Extracts the actual name part of an enum instance
3962+ // In other words, it returns the Blue part of Bikeshed::Colour::Blue
3963+ StringRef extractInstanceName(StringRef enumInstance) {
3964+ // Find last occurrence of ":"
3965+ size_t name_start = enumInstance.size();
3966+ while (name_start > 0 && enumInstance[name_start - 1] != ':') {
3967+ --name_start;
3968+ }
3969+ return enumInstance.substr(name_start, enumInstance.size() - name_start);
3970+ }
3971+ }
3972+
3973+ std::vector<StringRef> parseEnums( StringRef enums ) {
3974+ auto enumValues = splitStringRef( enums, ',' );
3975+ std::vector<StringRef> parsed;
3976+ parsed.reserve( enumValues.size() );
3977+ for( auto const& enumValue : enumValues ) {
3978+ parsed.push_back(trim(extractInstanceName(enumValue)));
3979+ }
3980+ return parsed;
3981+ }
3982+
3983+ EnumInfo::~EnumInfo() = default;
3984+
3985+ StringRef EnumInfo::lookup( int value ) const {
3986+ for( auto const& valueToName : m_values ) {
3987+ if( valueToName.first == value )
3988+ return valueToName.second;
3989+ }
3990+ return "{** unexpected enum value **}"_sr;
3991+ }
3992+
3993+ Catch::Detail::unique_ptr<EnumInfo> makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ) {
3994+ auto enumInfo = Catch::Detail::make_unique<EnumInfo>();
3995+ enumInfo->m_name = enumName;
3996+ enumInfo->m_values.reserve( values.size() );
3997+
3998+ const auto valueNames = Catch::Detail::parseEnums( allValueNames );
3999+ assert( valueNames.size() == values.size() );
4000+ std::size_t i = 0;
4001+ for( auto value : values )
4002+ enumInfo->m_values.emplace_back(value, valueNames[i++]);
4003+
4004+ return enumInfo;
4005+ }
4006+
4007+ EnumInfo const& EnumValuesRegistry::registerEnum( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ) {
4008+ m_enumInfos.push_back(makeEnumInfo(enumName, allValueNames, values));
4009+ return *m_enumInfos.back();
4010+ }
4011+
4012+ } // Detail
4013+} // Catch
4014+
4015+
4016+
4017+
4018+
4019+#include <cerrno>
4020+
4021+namespace Catch {
4022+ ErrnoGuard::ErrnoGuard():m_oldErrno(errno){}
4023+ ErrnoGuard::~ErrnoGuard() { errno = m_oldErrno; }
4024+}
4025+
4026+
4027+
4028+#include <exception>
4029+
4030+namespace Catch {
4031+
4032+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
4033+ namespace {
4034+ static std::string tryTranslators(
4035+ std::vector<
4036+ Detail::unique_ptr<IExceptionTranslator const>> const& translators ) {
4037+ if ( translators.empty() ) {
4038+ std::rethrow_exception( std::current_exception() );
4039+ } else {
4040+ return translators[0]->translate( translators.begin() + 1,
4041+ translators.end() );
4042+ }
4043+ }
4044+
4045+ }
4046+#endif //!defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
4047+
4048+ ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() = default;
4049+
4050+ void ExceptionTranslatorRegistry::registerTranslator( Detail::unique_ptr<IExceptionTranslator>&& translator ) {
4051+ m_translators.push_back( CATCH_MOVE( translator ) );
4052+ }
4053+
4054+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
4055+ std::string ExceptionTranslatorRegistry::translateActiveException() const {
4056+ // Compiling a mixed mode project with MSVC means that CLR
4057+ // exceptions will be caught in (...) as well. However, these do
4058+ // do not fill-in std::current_exception and thus lead to crash
4059+ // when attempting rethrow.
4060+ // /EHa switch also causes structured exceptions to be caught
4061+ // here, but they fill-in current_exception properly, so
4062+ // at worst the output should be a little weird, instead of
4063+ // causing a crash.
4064+ if ( std::current_exception() == nullptr ) {
4065+ return "Non C++ exception. Possibly a CLR exception.";
4066+ }
4067+
4068+ // First we try user-registered translators. If none of them can
4069+ // handle the exception, it will be rethrown handled by our defaults.
4070+ try {
4071+ return tryTranslators(m_translators);
4072+ }
4073+ // To avoid having to handle TFE explicitly everywhere, we just
4074+ // rethrow it so that it goes back up the caller.
4075+ catch( TestFailureException& ) {
4076+ std::rethrow_exception(std::current_exception());
4077+ }
4078+ catch( TestSkipException& ) {
4079+ std::rethrow_exception(std::current_exception());
4080+ }
4081+ catch( std::exception const& ex ) {
4082+ return ex.what();
4083+ }
4084+ catch( std::string const& msg ) {
4085+ return msg;
4086+ }
4087+ catch( const char* msg ) {
4088+ return msg;
4089+ }
4090+ catch(...) {
4091+ return "Unknown exception";
4092+ }
4093+ }
4094+
4095+#else // ^^ Exceptions are enabled // Exceptions are disabled vv
4096+ std::string ExceptionTranslatorRegistry::translateActiveException() const {
4097+ CATCH_INTERNAL_ERROR("Attempted to translate active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
4098+ }
4099+#endif
4100+
4101+}
4102+
4103+
4104+
4105+/** \file
4106+ * This file provides platform specific implementations of FatalConditionHandler
4107+ *
4108+ * This means that there is a lot of conditional compilation, and platform
4109+ * specific code. Currently, Catch2 supports a dummy handler (if no
4110+ * handler is desired), and 2 platform specific handlers:
4111+ * * Windows' SEH
4112+ * * POSIX signals
4113+ *
4114+ * Consequently, various pieces of code below are compiled if either of
4115+ * the platform specific handlers is enabled, or if none of them are
4116+ * enabled. It is assumed that both cannot be enabled at the same time,
4117+ * and doing so should cause a compilation error.
4118+ *
4119+ * If another platform specific handler is added, the compile guards
4120+ * below will need to be updated taking these assumptions into account.
4121+ */
4122+
4123+
4124+
4125+#include <algorithm>
4126+
4127+#if !defined( CATCH_CONFIG_WINDOWS_SEH ) && !defined( CATCH_CONFIG_POSIX_SIGNALS )
4128+
4129+namespace Catch {
4130+
4131+ // If neither SEH nor signal handling is required, the handler impls
4132+ // do not have to do anything, and can be empty.
4133+ void FatalConditionHandler::engage_platform() {}
4134+ void FatalConditionHandler::disengage_platform() noexcept {}
4135+ FatalConditionHandler::FatalConditionHandler() = default;
4136+ FatalConditionHandler::~FatalConditionHandler() = default;
4137+
4138+} // end namespace Catch
4139+
4140+#endif // !CATCH_CONFIG_WINDOWS_SEH && !CATCH_CONFIG_POSIX_SIGNALS
4141+
4142+#if defined( CATCH_CONFIG_WINDOWS_SEH ) && defined( CATCH_CONFIG_POSIX_SIGNALS )
4143+#error "Inconsistent configuration: Windows' SEH handling and POSIX signals cannot be enabled at the same time"
4144+#endif // CATCH_CONFIG_WINDOWS_SEH && CATCH_CONFIG_POSIX_SIGNALS
4145+
4146+#if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS )
4147+
4148+namespace {
4149+ //! Signals fatal error message to the run context
4150+ void reportFatal( char const * const message ) {
4151+ Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message );
4152+ }
4153+
4154+ //! Minimal size Catch2 needs for its own fatal error handling.
4155+ //! Picked empirically, so it might not be sufficient on all
4156+ //! platforms, and for all configurations.
4157+ constexpr std::size_t minStackSizeForErrors = 32 * 1024;
4158+} // end unnamed namespace
4159+
4160+#endif // CATCH_CONFIG_WINDOWS_SEH || CATCH_CONFIG_POSIX_SIGNALS
4161+
4162+#if defined( CATCH_CONFIG_WINDOWS_SEH )
4163+
4164+namespace Catch {
4165+
4166+ struct SignalDefs { DWORD id; const char* name; };
4167+
4168+ // There is no 1-1 mapping between signals and windows exceptions.
4169+ // Windows can easily distinguish between SO and SigSegV,
4170+ // but SigInt, SigTerm, etc are handled differently.
4171+ static SignalDefs signalDefs[] = {
4172+ { EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal" },
4173+ { EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" },
4174+ { EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" },
4175+ { EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" },
4176+ };
4177+
4178+ static LONG CALLBACK topLevelExceptionFilter(PEXCEPTION_POINTERS ExceptionInfo) {
4179+ for (auto const& def : signalDefs) {
4180+ if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) {
4181+ reportFatal(def.name);
4182+ }
4183+ }
4184+ // If its not an exception we care about, pass it along.
4185+ // This stops us from eating debugger breaks etc.
4186+ return EXCEPTION_CONTINUE_SEARCH;
4187+ }
4188+
4189+ // Since we do not support multiple instantiations, we put these
4190+ // into global variables and rely on cleaning them up in outlined
4191+ // constructors/destructors
4192+ static LPTOP_LEVEL_EXCEPTION_FILTER previousTopLevelExceptionFilter = nullptr;
4193+
4194+
4195+ // For MSVC, we reserve part of the stack memory for handling
4196+ // memory overflow structured exception.
4197+ FatalConditionHandler::FatalConditionHandler() {
4198+ ULONG guaranteeSize = static_cast<ULONG>(minStackSizeForErrors);
4199+ if (!SetThreadStackGuarantee(&guaranteeSize)) {
4200+ // We do not want to fully error out, because needing
4201+ // the stack reserve should be rare enough anyway.
4202+ Catch::cerr()
4203+ << "Failed to reserve piece of stack."
4204+ << " Stack overflows will not be reported successfully.";
4205+ }
4206+ }
4207+
4208+ // We do not attempt to unset the stack guarantee, because
4209+ // Windows does not support lowering the stack size guarantee.
4210+ FatalConditionHandler::~FatalConditionHandler() = default;
4211+
4212+
4213+ void FatalConditionHandler::engage_platform() {
4214+ // Register as a the top level exception filter.
4215+ previousTopLevelExceptionFilter = SetUnhandledExceptionFilter(topLevelExceptionFilter);
4216+ }
4217+
4218+ void FatalConditionHandler::disengage_platform() noexcept {
4219+ if (SetUnhandledExceptionFilter(previousTopLevelExceptionFilter) != topLevelExceptionFilter) {
4220+ Catch::cerr()
4221+ << "Unexpected SEH unhandled exception filter on disengage."
4222+ << " The filter was restored, but might be rolled back unexpectedly.";
4223+ }
4224+ previousTopLevelExceptionFilter = nullptr;
4225+ }
4226+
4227+} // end namespace Catch
4228+
4229+#endif // CATCH_CONFIG_WINDOWS_SEH
4230+
4231+#if defined( CATCH_CONFIG_POSIX_SIGNALS )
4232+
4233+#include <signal.h>
4234+
4235+namespace Catch {
4236+
4237+ struct SignalDefs {
4238+ int id;
4239+ const char* name;
4240+ };
4241+
4242+ static SignalDefs signalDefs[] = {
4243+ { SIGINT, "SIGINT - Terminal interrupt signal" },
4244+ { SIGILL, "SIGILL - Illegal instruction signal" },
4245+ { SIGFPE, "SIGFPE - Floating point error signal" },
4246+ { SIGSEGV, "SIGSEGV - Segmentation violation signal" },
4247+ { SIGTERM, "SIGTERM - Termination request signal" },
4248+ { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" }
4249+ };
4250+
4251+// Older GCCs trigger -Wmissing-field-initializers for T foo = {}
4252+// which is zero initialization, but not explicit. We want to avoid
4253+// that.
4254+#if defined(__GNUC__)
4255+# pragma GCC diagnostic push
4256+# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
4257+#endif
4258+
4259+ static char* altStackMem = nullptr;
4260+ static std::size_t altStackSize = 0;
4261+ static stack_t oldSigStack{};
4262+ static struct sigaction oldSigActions[sizeof(signalDefs) / sizeof(SignalDefs)]{};
4263+
4264+ static void restorePreviousSignalHandlers() noexcept {
4265+ // We set signal handlers back to the previous ones. Hopefully
4266+ // nobody overwrote them in the meantime, and doesn't expect
4267+ // their signal handlers to live past ours given that they
4268+ // installed them after ours..
4269+ for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) {
4270+ sigaction(signalDefs[i].id, &oldSigActions[i], nullptr);
4271+ }
4272+ // Return the old stack
4273+ sigaltstack(&oldSigStack, nullptr);
4274+ }
4275+
4276+ static void handleSignal( int sig ) {
4277+ char const * name = "<unknown signal>";
4278+ for (auto const& def : signalDefs) {
4279+ if (sig == def.id) {
4280+ name = def.name;
4281+ break;
4282+ }
4283+ }
4284+ // We need to restore previous signal handlers and let them do
4285+ // their thing, so that the users can have the debugger break
4286+ // when a signal is raised, and so on.
4287+ restorePreviousSignalHandlers();
4288+ reportFatal( name );
4289+ raise( sig );
4290+ }
4291+
4292+ FatalConditionHandler::FatalConditionHandler() {
4293+ assert(!altStackMem && "Cannot initialize POSIX signal handler when one already exists");
4294+ if (altStackSize == 0) {
4295+ altStackSize = std::max(static_cast<size_t>(SIGSTKSZ), minStackSizeForErrors);
4296+ }
4297+ altStackMem = new char[altStackSize]();
4298+ }
4299+
4300+ FatalConditionHandler::~FatalConditionHandler() {
4301+ delete[] altStackMem;
4302+ // We signal that another instance can be constructed by zeroing
4303+ // out the pointer.
4304+ altStackMem = nullptr;
4305+ }
4306+
4307+ void FatalConditionHandler::engage_platform() {
4308+ stack_t sigStack;
4309+ sigStack.ss_sp = altStackMem;
4310+ sigStack.ss_size = altStackSize;
4311+ sigStack.ss_flags = 0;
4312+ sigaltstack(&sigStack, &oldSigStack);
4313+ struct sigaction sa = { };
4314+
4315+ sa.sa_handler = handleSignal;
4316+ sa.sa_flags = SA_ONSTACK;
4317+ for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) {
4318+ sigaction(signalDefs[i].id, &sa, &oldSigActions[i]);
4319+ }
4320+ }
4321+
4322+#if defined(__GNUC__)
4323+# pragma GCC diagnostic pop
4324+#endif
4325+
4326+
4327+ void FatalConditionHandler::disengage_platform() noexcept {
4328+ restorePreviousSignalHandlers();
4329+ }
4330+
4331+} // end namespace Catch
4332+
4333+#endif // CATCH_CONFIG_POSIX_SIGNALS
4334+
4335+
4336+
4337+
4338+#include <cstring>
4339+
4340+namespace Catch {
4341+ namespace Detail {
4342+
4343+ uint32_t convertToBits(float f) {
4344+ static_assert(sizeof(float) == sizeof(uint32_t), "Important ULP matcher assumption violated");
4345+ uint32_t i;
4346+ std::memcpy(&i, &f, sizeof(f));
4347+ return i;
4348+ }
4349+
4350+ uint64_t convertToBits(double d) {
4351+ static_assert(sizeof(double) == sizeof(uint64_t), "Important ULP matcher assumption violated");
4352+ uint64_t i;
4353+ std::memcpy(&i, &d, sizeof(d));
4354+ return i;
4355+ }
4356+
4357+#if defined( __GNUC__ ) || defined( __clang__ )
4358+# pragma GCC diagnostic push
4359+# pragma GCC diagnostic ignored "-Wfloat-equal"
4360+#endif
4361+ bool directCompare( float lhs, float rhs ) { return lhs == rhs; }
4362+ bool directCompare( double lhs, double rhs ) { return lhs == rhs; }
4363+#if defined( __GNUC__ ) || defined( __clang__ )
4364+# pragma GCC diagnostic pop
4365+#endif
4366+
4367+
4368+ } // end namespace Detail
4369+} // end namespace Catch
4370+
4371+
4372+
4373+
4374+
4375+
4376+#include <cstdlib>
4377+
4378+namespace Catch {
4379+ namespace Detail {
4380+
4381+#if !defined (CATCH_CONFIG_GETENV)
4382+ char const* getEnv( char const* ) { return nullptr; }
4383+#else
4384+
4385+ char const* getEnv( char const* varName ) {
4386+# if defined( _MSC_VER )
4387+# pragma warning( push )
4388+# pragma warning( disable : 4996 ) // use getenv_s instead of getenv
4389+# endif
4390+
4391+ return std::getenv( varName );
4392+
4393+# if defined( _MSC_VER )
4394+# pragma warning( pop )
4395+# endif
4396+ }
4397+#endif
4398+} // namespace Detail
4399+} // namespace Catch
4400+
4401+
4402+
4403+
4404+#include <cstdio>
4405+#include <fstream>
4406+#include <sstream>
4407+#include <vector>
4408+
4409+namespace Catch {
4410+
4411+ Catch::IStream::~IStream() = default;
4412+
4413+namespace Detail {
4414+ namespace {
4415+ template<typename WriterF, std::size_t bufferSize=256>
4416+ class StreamBufImpl final : public std::streambuf {
4417+ char data[bufferSize];
4418+ WriterF m_writer;
4419+
4420+ public:
4421+ StreamBufImpl() {
4422+ setp( data, data + sizeof(data) );
4423+ }
4424+
4425+ ~StreamBufImpl() noexcept override {
4426+ StreamBufImpl::sync();
4427+ }
4428+
4429+ private:
4430+ int overflow( int c ) override {
4431+ sync();
4432+
4433+ if( c != EOF ) {
4434+ if( pbase() == epptr() )
4435+ m_writer( std::string( 1, static_cast<char>( c ) ) );
4436+ else
4437+ sputc( static_cast<char>( c ) );
4438+ }
4439+ return 0;
4440+ }
4441+
4442+ int sync() override {
4443+ if( pbase() != pptr() ) {
4444+ m_writer( std::string( pbase(), static_cast<std::string::size_type>( pptr() - pbase() ) ) );
4445+ setp( pbase(), epptr() );
4446+ }
4447+ return 0;
4448+ }
4449+ };
4450+
4451+ ///////////////////////////////////////////////////////////////////////////
4452+
4453+ struct OutputDebugWriter {
4454+
4455+ void operator()( std::string const& str ) {
4456+ if ( !str.empty() ) {
4457+ writeToDebugConsole( str );
4458+ }
4459+ }
4460+ };
4461+
4462+ ///////////////////////////////////////////////////////////////////////////
4463+
4464+ class FileStream final : public IStream {
4465+ std::ofstream m_ofs;
4466+ public:
4467+ FileStream( std::string const& filename ) {
4468+ m_ofs.open( filename.c_str() );
4469+ CATCH_ENFORCE( !m_ofs.fail(), "Unable to open file: '" << filename << '\'' );
4470+ m_ofs << std::unitbuf;
4471+ }
4472+ public: // IStream
4473+ std::ostream& stream() override {
4474+ return m_ofs;
4475+ }
4476+ };
4477+
4478+ ///////////////////////////////////////////////////////////////////////////
4479+
4480+ class CoutStream final : public IStream {
4481+ std::ostream m_os;
4482+ public:
4483+ // Store the streambuf from cout up-front because
4484+ // cout may get redirected when running tests
4485+ CoutStream() : m_os( Catch::cout().rdbuf() ) {}
4486+
4487+ public: // IStream
4488+ std::ostream& stream() override { return m_os; }
4489+ bool isConsole() const override { return true; }
4490+ };
4491+
4492+ class CerrStream : public IStream {
4493+ std::ostream m_os;
4494+
4495+ public:
4496+ // Store the streambuf from cerr up-front because
4497+ // cout may get redirected when running tests
4498+ CerrStream(): m_os( Catch::cerr().rdbuf() ) {}
4499+
4500+ public: // IStream
4501+ std::ostream& stream() override { return m_os; }
4502+ bool isConsole() const override { return true; }
4503+ };
4504+
4505+ ///////////////////////////////////////////////////////////////////////////
4506+
4507+ class DebugOutStream final : public IStream {
4508+ Detail::unique_ptr<StreamBufImpl<OutputDebugWriter>> m_streamBuf;
4509+ std::ostream m_os;
4510+ public:
4511+ DebugOutStream()
4512+ : m_streamBuf( Detail::make_unique<StreamBufImpl<OutputDebugWriter>>() ),
4513+ m_os( m_streamBuf.get() )
4514+ {}
4515+
4516+ public: // IStream
4517+ std::ostream& stream() override { return m_os; }
4518+ };
4519+
4520+ } // unnamed namespace
4521+} // namespace Detail
4522+
4523+ ///////////////////////////////////////////////////////////////////////////
4524+
4525+ auto makeStream( std::string const& filename ) -> Detail::unique_ptr<IStream> {
4526+ if ( filename.empty() || filename == "-" ) {
4527+ return Detail::make_unique<Detail::CoutStream>();
4528+ }
4529+ if( filename[0] == '%' ) {
4530+ if ( filename == "%debug" ) {
4531+ return Detail::make_unique<Detail::DebugOutStream>();
4532+ } else if ( filename == "%stderr" ) {
4533+ return Detail::make_unique<Detail::CerrStream>();
4534+ } else if ( filename == "%stdout" ) {
4535+ return Detail::make_unique<Detail::CoutStream>();
4536+ } else {
4537+ CATCH_ERROR( "Unrecognised stream: '" << filename << '\'' );
4538+ }
4539+ }
4540+ return Detail::make_unique<Detail::FileStream>( filename );
4541+ }
4542+
4543+}
4544+
4545+
4546+
4547+namespace Catch {
4548+ void JsonUtils::indent( std::ostream& os, std::uint64_t level ) {
4549+ for ( std::uint64_t i = 0; i < level; ++i ) {
4550+ os << " ";
4551+ }
4552+ }
4553+ void JsonUtils::appendCommaNewline( std::ostream& os,
4554+ bool& should_comma,
4555+ std::uint64_t level ) {
4556+ if ( should_comma ) { os << ','; }
4557+ should_comma = true;
4558+ os << '\n';
4559+ indent( os, level );
4560+ }
4561+
4562+ JsonObjectWriter::JsonObjectWriter( std::ostream& os ):
4563+ JsonObjectWriter{ os, 0 } {}
4564+
4565+ JsonObjectWriter::JsonObjectWriter( std::ostream& os,
4566+ std::uint64_t indent_level ):
4567+ m_os{ os }, m_indent_level{ indent_level } {
4568+ m_os << '{';
4569+ }
4570+ JsonObjectWriter::JsonObjectWriter( JsonObjectWriter&& source ) noexcept:
4571+ m_os{ source.m_os },
4572+ m_indent_level{ source.m_indent_level },
4573+ m_should_comma{ source.m_should_comma },
4574+ m_active{ source.m_active } {
4575+ source.m_active = false;
4576+ }
4577+
4578+ JsonObjectWriter::~JsonObjectWriter() {
4579+ if ( !m_active ) { return; }
4580+
4581+ m_os << '\n';
4582+ JsonUtils::indent( m_os, m_indent_level );
4583+ m_os << '}';
4584+ }
4585+
4586+ JsonValueWriter JsonObjectWriter::write( StringRef key ) {
4587+ JsonUtils::appendCommaNewline(
4588+ m_os, m_should_comma, m_indent_level + 1 );
4589+
4590+ m_os << '"' << key << "\": ";
4591+ return JsonValueWriter{ m_os, m_indent_level + 1 };
4592+ }
4593+
4594+ JsonArrayWriter::JsonArrayWriter( std::ostream& os ):
4595+ JsonArrayWriter{ os, 0 } {}
4596+ JsonArrayWriter::JsonArrayWriter( std::ostream& os,
4597+ std::uint64_t indent_level ):
4598+ m_os{ os }, m_indent_level{ indent_level } {
4599+ m_os << '[';
4600+ }
4601+ JsonArrayWriter::JsonArrayWriter( JsonArrayWriter&& source ) noexcept:
4602+ m_os{ source.m_os },
4603+ m_indent_level{ source.m_indent_level },
4604+ m_should_comma{ source.m_should_comma },
4605+ m_active{ source.m_active } {
4606+ source.m_active = false;
4607+ }
4608+ JsonArrayWriter::~JsonArrayWriter() {
4609+ if ( !m_active ) { return; }
4610+
4611+ m_os << '\n';
4612+ JsonUtils::indent( m_os, m_indent_level );
4613+ m_os << ']';
4614+ }
4615+
4616+ JsonObjectWriter JsonArrayWriter::writeObject() {
4617+ JsonUtils::appendCommaNewline(
4618+ m_os, m_should_comma, m_indent_level + 1 );
4619+ return JsonObjectWriter{ m_os, m_indent_level + 1 };
4620+ }
4621+
4622+ JsonArrayWriter JsonArrayWriter::writeArray() {
4623+ JsonUtils::appendCommaNewline(
4624+ m_os, m_should_comma, m_indent_level + 1 );
4625+ return JsonArrayWriter{ m_os, m_indent_level + 1 };
4626+ }
4627+
4628+ JsonArrayWriter& JsonArrayWriter::write( bool value ) {
4629+ return writeImpl( value );
4630+ }
4631+
4632+ JsonValueWriter::JsonValueWriter( std::ostream& os ):
4633+ JsonValueWriter{ os, 0 } {}
4634+
4635+ JsonValueWriter::JsonValueWriter( std::ostream& os,
4636+ std::uint64_t indent_level ):
4637+ m_os{ os }, m_indent_level{ indent_level } {}
4638+
4639+ JsonObjectWriter JsonValueWriter::writeObject() && {
4640+ return JsonObjectWriter{ m_os, m_indent_level };
4641+ }
4642+
4643+ JsonArrayWriter JsonValueWriter::writeArray() && {
4644+ return JsonArrayWriter{ m_os, m_indent_level };
4645+ }
4646+
4647+ void JsonValueWriter::write( Catch::StringRef value ) && {
4648+ writeImpl( value, true );
4649+ }
4650+
4651+ void JsonValueWriter::write( bool value ) && {
4652+ writeImpl( value ? "true"_sr : "false"_sr, false );
4653+ }
4654+
4655+ void JsonValueWriter::writeImpl( Catch::StringRef value, bool quote ) {
4656+ if ( quote ) { m_os << '"'; }
4657+ for (char c : value) {
4658+ // Escape list taken from https://www.json.org/json-en.html,
4659+ // string definition.
4660+ // Note that while forward slash _can_ be escaped, it does
4661+ // not have to be, if JSON is not further embedded somewhere
4662+ // where forward slash is meaningful.
4663+ if ( c == '"' ) {
4664+ m_os << "\\\"";
4665+ } else if ( c == '\\' ) {
4666+ m_os << "\\\\";
4667+ } else if ( c == '\b' ) {
4668+ m_os << "\\b";
4669+ } else if ( c == '\f' ) {
4670+ m_os << "\\f";
4671+ } else if ( c == '\n' ) {
4672+ m_os << "\\n";
4673+ } else if ( c == '\r' ) {
4674+ m_os << "\\r";
4675+ } else if ( c == '\t' ) {
4676+ m_os << "\\t";
4677+ } else {
4678+ m_os << c;
4679+ }
4680+ }
4681+ if ( quote ) { m_os << '"'; }
4682+ }
4683+
4684+} // namespace Catch
4685+
4686+
4687+
4688+
4689+namespace Catch {
4690+
4691+ auto operator << (std::ostream& os, LazyExpression const& lazyExpr) -> std::ostream& {
4692+ if (lazyExpr.m_isNegated)
4693+ os << '!';
4694+
4695+ if (lazyExpr) {
4696+ if (lazyExpr.m_isNegated && lazyExpr.m_transientExpression->isBinaryExpression())
4697+ os << '(' << *lazyExpr.m_transientExpression << ')';
4698+ else
4699+ os << *lazyExpr.m_transientExpression;
4700+ } else {
4701+ os << "{** error - unchecked empty expression requested **}";
4702+ }
4703+ return os;
4704+ }
4705+
4706+} // namespace Catch
4707+
4708+
4709+
4710+
4711+#ifdef CATCH_CONFIG_WINDOWS_CRTDBG
4712+#include <crtdbg.h>
4713+
4714+namespace Catch {
4715+
4716+ LeakDetector::LeakDetector() {
4717+ int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
4718+ flag |= _CRTDBG_LEAK_CHECK_DF;
4719+ flag |= _CRTDBG_ALLOC_MEM_DF;
4720+ _CrtSetDbgFlag(flag);
4721+ _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
4722+ _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
4723+ // Change this to leaking allocation's number to break there
4724+ _CrtSetBreakAlloc(-1);
4725+ }
4726+}
4727+
4728+#else // ^^ Windows crt debug heap enabled // Windows crt debug heap disabled vv
4729+
4730+ Catch::LeakDetector::LeakDetector() = default;
4731+
4732+#endif // CATCH_CONFIG_WINDOWS_CRTDBG
4733+
4734+Catch::LeakDetector::~LeakDetector() {
4735+ Catch::cleanUp();
4736+}
4737+
4738+
4739+
4740+
4741+namespace Catch {
4742+ namespace {
4743+
4744+ void listTests(IEventListener& reporter, IConfig const& config) {
4745+ auto const& testSpec = config.testSpec();
4746+ auto matchedTestCases = filterTests(getAllTestCasesSorted(config), testSpec, config);
4747+ reporter.listTests(matchedTestCases);
4748+ }
4749+
4750+ void listTags(IEventListener& reporter, IConfig const& config) {
4751+ auto const& testSpec = config.testSpec();
4752+ std::vector<TestCaseHandle> matchedTestCases = filterTests(getAllTestCasesSorted(config), testSpec, config);
4753+
4754+ std::map<StringRef, TagInfo, Detail::CaseInsensitiveLess> tagCounts;
4755+ for (auto const& testCase : matchedTestCases) {
4756+ for (auto const& tagName : testCase.getTestCaseInfo().tags) {
4757+ auto it = tagCounts.find(tagName.original);
4758+ if (it == tagCounts.end())
4759+ it = tagCounts.insert(std::make_pair(tagName.original, TagInfo())).first;
4760+ it->second.add(tagName.original);
4761+ }
4762+ }
4763+
4764+ std::vector<TagInfo> infos; infos.reserve(tagCounts.size());
4765+ for (auto& tagc : tagCounts) {
4766+ infos.push_back(CATCH_MOVE(tagc.second));
4767+ }
4768+
4769+ reporter.listTags(infos);
4770+ }
4771+
4772+ void listReporters(IEventListener& reporter) {
4773+ std::vector<ReporterDescription> descriptions;
4774+
4775+ auto const& factories = getRegistryHub().getReporterRegistry().getFactories();
4776+ descriptions.reserve(factories.size());
4777+ for (auto const& fac : factories) {
4778+ descriptions.push_back({ fac.first, fac.second->getDescription() });
4779+ }
4780+
4781+ reporter.listReporters(descriptions);
4782+ }
4783+
4784+ void listListeners(IEventListener& reporter) {
4785+ std::vector<ListenerDescription> descriptions;
4786+
4787+ auto const& factories =
4788+ getRegistryHub().getReporterRegistry().getListeners();
4789+ descriptions.reserve( factories.size() );
4790+ for ( auto const& fac : factories ) {
4791+ descriptions.push_back( { fac->getName(), fac->getDescription() } );
4792+ }
4793+
4794+ reporter.listListeners( descriptions );
4795+ }
4796+
4797+ } // end anonymous namespace
4798+
4799+ void TagInfo::add( StringRef spelling ) {
4800+ ++count;
4801+ spellings.insert( spelling );
4802+ }
4803+
4804+ std::string TagInfo::all() const {
4805+ // 2 per tag for brackets '[' and ']'
4806+ size_t size = spellings.size() * 2;
4807+ for (auto const& spelling : spellings) {
4808+ size += spelling.size();
4809+ }
4810+
4811+ std::string out; out.reserve(size);
4812+ for (auto const& spelling : spellings) {
4813+ out += '[';
4814+ out += spelling;
4815+ out += ']';
4816+ }
4817+ return out;
4818+ }
4819+
4820+ bool list( IEventListener& reporter, Config const& config ) {
4821+ bool listed = false;
4822+ if (config.listTests()) {
4823+ listed = true;
4824+ listTests(reporter, config);
4825+ }
4826+ if (config.listTags()) {
4827+ listed = true;
4828+ listTags(reporter, config);
4829+ }
4830+ if (config.listReporters()) {
4831+ listed = true;
4832+ listReporters(reporter);
4833+ }
4834+ if ( config.listListeners() ) {
4835+ listed = true;
4836+ listListeners( reporter );
4837+ }
4838+ return listed;
4839+ }
4840+
4841+} // end namespace Catch
4842+
4843+
4844+
4845+namespace Catch {
4846+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
4847+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
4848+ static LeakDetector leakDetector;
4849+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
4850+}
4851+
4852+// Allow users of amalgamated .cpp file to remove our main and provide their own.
4853+#if !defined(CATCH_AMALGAMATED_CUSTOM_MAIN)
4854+
4855+#if defined(CATCH_CONFIG_WCHAR) && defined(CATCH_PLATFORM_WINDOWS) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN)
4856+// Standard C/C++ Win32 Unicode wmain entry point
4857+extern "C" int __cdecl wmain (int argc, wchar_t * argv[], wchar_t * []) {
4858+#else
4859+// Standard C/C++ main entry point
4860+int main (int argc, char * argv[]) {
4861+#endif
4862+
4863+ // We want to force the linker not to discard the global variable
4864+ // and its constructor, as it (optionally) registers leak detector
4865+ (void)&Catch::leakDetector;
4866+
4867+ return Catch::Session().run( argc, argv );
4868+}
4869+
4870+#endif // !defined(CATCH_AMALGAMATED_CUSTOM_MAIN
4871+
4872+
4873+
4874+
4875+namespace Catch {
4876+
4877+ MessageInfo::MessageInfo( StringRef _macroName,
4878+ SourceLineInfo const& _lineInfo,
4879+ ResultWas::OfType _type )
4880+ : macroName( _macroName ),
4881+ lineInfo( _lineInfo ),
4882+ type( _type ),
4883+ sequence( ++globalCount )
4884+ {}
4885+
4886+ // This may need protecting if threading support is added
4887+ unsigned int MessageInfo::globalCount = 0;
4888+
4889+} // end namespace Catch
4890+
4891+
4892+
4893+#include <cstdio>
4894+#include <cstring>
4895+#include <sstream>
4896+
4897+#if defined(CATCH_CONFIG_NEW_CAPTURE)
4898+ #if defined(_MSC_VER)
4899+ #include <io.h> //_dup and _dup2
4900+ #define dup _dup
4901+ #define dup2 _dup2
4902+ #define fileno _fileno
4903+ #else
4904+ #include <unistd.h> // dup and dup2
4905+ #endif
4906+#endif
4907+
4908+
4909+namespace Catch {
4910+
4911+ RedirectedStream::RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream )
4912+ : m_originalStream( originalStream ),
4913+ m_redirectionStream( redirectionStream ),
4914+ m_prevBuf( m_originalStream.rdbuf() )
4915+ {
4916+ m_originalStream.rdbuf( m_redirectionStream.rdbuf() );
4917+ }
4918+
4919+ RedirectedStream::~RedirectedStream() {
4920+ m_originalStream.rdbuf( m_prevBuf );
4921+ }
4922+
4923+ RedirectedStdOut::RedirectedStdOut() : m_cout( Catch::cout(), m_rss.get() ) {}
4924+ auto RedirectedStdOut::str() const -> std::string { return m_rss.str(); }
4925+
4926+ RedirectedStdErr::RedirectedStdErr()
4927+ : m_cerr( Catch::cerr(), m_rss.get() ),
4928+ m_clog( Catch::clog(), m_rss.get() )
4929+ {}
4930+ auto RedirectedStdErr::str() const -> std::string { return m_rss.str(); }
4931+
4932+ RedirectedStreams::RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr)
4933+ : m_redirectedCout(redirectedCout),
4934+ m_redirectedCerr(redirectedCerr)
4935+ {}
4936+
4937+ RedirectedStreams::~RedirectedStreams() {
4938+ m_redirectedCout += m_redirectedStdOut.str();
4939+ m_redirectedCerr += m_redirectedStdErr.str();
4940+ }
4941+
4942+#if defined(CATCH_CONFIG_NEW_CAPTURE)
4943+
4944+#if defined(_MSC_VER)
4945+ TempFile::TempFile() {
4946+ if (tmpnam_s(m_buffer)) {
4947+ CATCH_RUNTIME_ERROR("Could not get a temp filename");
4948+ }
4949+ if (fopen_s(&m_file, m_buffer, "w+")) {
4950+ char buffer[100];
4951+ if (strerror_s(buffer, errno)) {
4952+ CATCH_RUNTIME_ERROR("Could not translate errno to a string");
4953+ }
4954+ CATCH_RUNTIME_ERROR("Could not open the temp file: '" << m_buffer << "' because: " << buffer);
4955+ }
4956+ }
4957+#else
4958+ TempFile::TempFile() {
4959+ m_file = std::tmpfile();
4960+ if (!m_file) {
4961+ CATCH_RUNTIME_ERROR("Could not create a temp file.");
4962+ }
4963+ }
4964+
4965+#endif
4966+
4967+ TempFile::~TempFile() {
4968+ // TBD: What to do about errors here?
4969+ std::fclose(m_file);
4970+ // We manually create the file on Windows only, on Linux
4971+ // it will be autodeleted
4972+#if defined(_MSC_VER)
4973+ std::remove(m_buffer);
4974+#endif
4975+ }
4976+
4977+
4978+ FILE* TempFile::getFile() {
4979+ return m_file;
4980+ }
4981+
4982+ std::string TempFile::getContents() {
4983+ std::stringstream sstr;
4984+ char buffer[100] = {};
4985+ std::rewind(m_file);
4986+ while (std::fgets(buffer, sizeof(buffer), m_file)) {
4987+ sstr << buffer;
4988+ }
4989+ return sstr.str();
4990+ }
4991+
4992+ OutputRedirect::OutputRedirect(std::string& stdout_dest, std::string& stderr_dest) :
4993+ m_originalStdout(dup(1)),
4994+ m_originalStderr(dup(2)),
4995+ m_stdoutDest(stdout_dest),
4996+ m_stderrDest(stderr_dest) {
4997+ dup2(fileno(m_stdoutFile.getFile()), 1);
4998+ dup2(fileno(m_stderrFile.getFile()), 2);
4999+ }
5000+
5001+ OutputRedirect::~OutputRedirect() {
5002+ Catch::cout() << std::flush;
5003+ fflush(stdout);
5004+ // Since we support overriding these streams, we flush cerr
5005+ // even though std::cerr is unbuffered
5006+ Catch::cerr() << std::flush;
5007+ Catch::clog() << std::flush;
5008+ fflush(stderr);
5009+
5010+ dup2(m_originalStdout, 1);
5011+ dup2(m_originalStderr, 2);
5012+
5013+ m_stdoutDest += m_stdoutFile.getContents();
5014+ m_stderrDest += m_stderrFile.getContents();
5015+ }
5016+
5017+#endif // CATCH_CONFIG_NEW_CAPTURE
5018+
5019+} // namespace Catch
5020+
5021+#if defined(CATCH_CONFIG_NEW_CAPTURE)
5022+ #if defined(_MSC_VER)
5023+ #undef dup
5024+ #undef dup2
5025+ #undef fileno
5026+ #endif
5027+#endif
5028+
5029+
5030+
5031+
5032+#include <limits>
5033+#include <stdexcept>
5034+
5035+namespace Catch {
5036+
5037+ Optional<unsigned int> parseUInt(std::string const& input, int base) {
5038+ auto trimmed = trim( input );
5039+ // std::stoull is annoying and accepts numbers starting with '-',
5040+ // it just negates them into unsigned int
5041+ if ( trimmed.empty() || trimmed[0] == '-' ) {
5042+ return {};
5043+ }
5044+
5045+ CATCH_TRY {
5046+ size_t pos = 0;
5047+ const auto ret = std::stoull( trimmed, &pos, base );
5048+
5049+ // We did not consume the whole input, so there is an issue
5050+ // This can be bunch of different stuff, like multiple numbers
5051+ // in the input, or invalid digits/characters and so on. Either
5052+ // way, we do not want to return the partially parsed result.
5053+ if ( pos != trimmed.size() ) {
5054+ return {};
5055+ }
5056+ // Too large
5057+ if ( ret > std::numeric_limits<unsigned int>::max() ) {
5058+ return {};
5059+ }
5060+ return static_cast<unsigned int>(ret);
5061+ }
5062+ CATCH_CATCH_ANON( std::invalid_argument const& ) {
5063+ // no conversion could be performed
5064+ }
5065+ CATCH_CATCH_ANON( std::out_of_range const& ) {
5066+ // the input does not fit into an unsigned long long
5067+ }
5068+ return {};
5069+ }
5070+
5071+} // namespace Catch
5072+
5073+
5074+
5075+
5076+#include <cmath>
5077+
5078+namespace Catch {
5079+
5080+#if !defined(CATCH_CONFIG_POLYFILL_ISNAN)
5081+ bool isnan(float f) {
5082+ return std::isnan(f);
5083+ }
5084+ bool isnan(double d) {
5085+ return std::isnan(d);
5086+ }
5087+#else
5088+ // For now we only use this for embarcadero
5089+ bool isnan(float f) {
5090+ return std::_isnan(f);
5091+ }
5092+ bool isnan(double d) {
5093+ return std::_isnan(d);
5094+ }
5095+#endif
5096+
5097+#if !defined( CATCH_CONFIG_GLOBAL_NEXTAFTER )
5098+ float nextafter( float x, float y ) { return std::nextafter( x, y ); }
5099+ double nextafter( double x, double y ) { return std::nextafter( x, y ); }
5100+#else
5101+ float nextafter( float x, float y ) { return ::nextafterf( x, y ); }
5102+ double nextafter( double x, double y ) { return ::nextafter( x, y ); }
5103+#endif
5104+
5105+} // end namespace Catch
5106+
5107+
5108+
5109+namespace Catch {
5110+
5111+namespace {
5112+
5113+#if defined(_MSC_VER)
5114+#pragma warning(push)
5115+#pragma warning(disable:4146) // we negate uint32 during the rotate
5116+#endif
5117+ // Safe rotr implementation thanks to John Regehr
5118+ uint32_t rotate_right(uint32_t val, uint32_t count) {
5119+ const uint32_t mask = 31;
5120+ count &= mask;
5121+ return (val >> count) | (val << (-count & mask));
5122+ }
5123+
5124+#if defined(_MSC_VER)
5125+#pragma warning(pop)
5126+#endif
5127+
5128+}
5129+
5130+
5131+ SimplePcg32::SimplePcg32(result_type seed_) {
5132+ seed(seed_);
5133+ }
5134+
5135+
5136+ void SimplePcg32::seed(result_type seed_) {
5137+ m_state = 0;
5138+ (*this)();
5139+ m_state += seed_;
5140+ (*this)();
5141+ }
5142+
5143+ void SimplePcg32::discard(uint64_t skip) {
5144+ // We could implement this to run in O(log n) steps, but this
5145+ // should suffice for our use case.
5146+ for (uint64_t s = 0; s < skip; ++s) {
5147+ static_cast<void>((*this)());
5148+ }
5149+ }
5150+
5151+ SimplePcg32::result_type SimplePcg32::operator()() {
5152+ // prepare the output value
5153+ const uint32_t xorshifted = static_cast<uint32_t>(((m_state >> 18u) ^ m_state) >> 27u);
5154+ const auto output = rotate_right(xorshifted, m_state >> 59u);
5155+
5156+ // advance state
5157+ m_state = m_state * 6364136223846793005ULL + s_inc;
5158+
5159+ return output;
5160+ }
5161+
5162+ bool operator==(SimplePcg32 const& lhs, SimplePcg32 const& rhs) {
5163+ return lhs.m_state == rhs.m_state;
5164+ }
5165+
5166+ bool operator!=(SimplePcg32 const& lhs, SimplePcg32 const& rhs) {
5167+ return lhs.m_state != rhs.m_state;
5168+ }
5169+}
5170+
5171+
5172+
5173+
5174+
5175+#include <ctime>
5176+#include <random>
5177+
5178+namespace Catch {
5179+
5180+ std::uint32_t generateRandomSeed( GenerateFrom from ) {
5181+ switch ( from ) {
5182+ case GenerateFrom::Time:
5183+ return static_cast<std::uint32_t>( std::time( nullptr ) );
5184+
5185+ case GenerateFrom::Default:
5186+ case GenerateFrom::RandomDevice: {
5187+ std::random_device rd;
5188+ return Detail::fillBitsFrom<std::uint32_t>( rd );
5189+ }
5190+
5191+ default:
5192+ CATCH_ERROR("Unknown generation method");
5193+ }
5194+ }
5195+
5196+} // end namespace Catch
5197+
5198+
5199+
5200+
5201+namespace Catch {
5202+ struct ReporterRegistry::ReporterRegistryImpl {
5203+ std::vector<Detail::unique_ptr<EventListenerFactory>> listeners;
5204+ std::map<std::string, IReporterFactoryPtr, Detail::CaseInsensitiveLess>
5205+ factories;
5206+ };
5207+
5208+ ReporterRegistry::ReporterRegistry():
5209+ m_impl( Detail::make_unique<ReporterRegistryImpl>() ) {
5210+ // Because it is impossible to move out of initializer list,
5211+ // we have to add the elements manually
5212+ m_impl->factories["Automake"] =
5213+ Detail::make_unique<ReporterFactory<AutomakeReporter>>();
5214+ m_impl->factories["compact"] =
5215+ Detail::make_unique<ReporterFactory<CompactReporter>>();
5216+ m_impl->factories["console"] =
5217+ Detail::make_unique<ReporterFactory<ConsoleReporter>>();
5218+ m_impl->factories["JUnit"] =
5219+ Detail::make_unique<ReporterFactory<JunitReporter>>();
5220+ m_impl->factories["SonarQube"] =
5221+ Detail::make_unique<ReporterFactory<SonarQubeReporter>>();
5222+ m_impl->factories["TAP"] =
5223+ Detail::make_unique<ReporterFactory<TAPReporter>>();
5224+ m_impl->factories["TeamCity"] =
5225+ Detail::make_unique<ReporterFactory<TeamCityReporter>>();
5226+ m_impl->factories["XML"] =
5227+ Detail::make_unique<ReporterFactory<XmlReporter>>();
5228+ m_impl->factories["JSON"] =
5229+ Detail::make_unique<ReporterFactory<JsonReporter>>();
5230+ }
5231+
5232+ ReporterRegistry::~ReporterRegistry() = default;
5233+
5234+ IEventListenerPtr
5235+ ReporterRegistry::create( std::string const& name,
5236+ ReporterConfig&& config ) const {
5237+ auto it = m_impl->factories.find( name );
5238+ if ( it == m_impl->factories.end() ) return nullptr;
5239+ return it->second->create( CATCH_MOVE( config ) );
5240+ }
5241+
5242+ void ReporterRegistry::registerReporter( std::string const& name,
5243+ IReporterFactoryPtr factory ) {
5244+ CATCH_ENFORCE( name.find( "::" ) == name.npos,
5245+ "'::' is not allowed in reporter name: '" + name +
5246+ '\'' );
5247+ auto ret = m_impl->factories.emplace( name, CATCH_MOVE( factory ) );
5248+ CATCH_ENFORCE( ret.second,
5249+ "reporter using '" + name +
5250+ "' as name was already registered" );
5251+ }
5252+ void ReporterRegistry::registerListener(
5253+ Detail::unique_ptr<EventListenerFactory> factory ) {
5254+ m_impl->listeners.push_back( CATCH_MOVE( factory ) );
5255+ }
5256+
5257+ std::map<std::string,
5258+ IReporterFactoryPtr,
5259+ Detail::CaseInsensitiveLess> const&
5260+ ReporterRegistry::getFactories() const {
5261+ return m_impl->factories;
5262+ }
5263+
5264+ std::vector<Detail::unique_ptr<EventListenerFactory>> const&
5265+ ReporterRegistry::getListeners() const {
5266+ return m_impl->listeners;
5267+ }
5268+} // namespace Catch
5269+
5270+
5271+
5272+
5273+
5274+#include <algorithm>
5275+
5276+namespace Catch {
5277+
5278+ namespace {
5279+ struct kvPair {
5280+ StringRef key, value;
5281+ };
5282+
5283+ kvPair splitKVPair(StringRef kvString) {
5284+ auto splitPos = static_cast<size_t>(
5285+ std::find( kvString.begin(), kvString.end(), '=' ) -
5286+ kvString.begin() );
5287+
5288+ return { kvString.substr( 0, splitPos ),
5289+ kvString.substr( splitPos + 1, kvString.size() ) };
5290+ }
5291+ }
5292+
5293+ namespace Detail {
5294+ std::vector<std::string> splitReporterSpec( StringRef reporterSpec ) {
5295+ static constexpr auto separator = "::";
5296+ static constexpr size_t separatorSize = 2;
5297+
5298+ size_t separatorPos = 0;
5299+ auto findNextSeparator = [&reporterSpec]( size_t startPos ) {
5300+ static_assert(
5301+ separatorSize == 2,
5302+ "The code below currently assumes 2 char separator" );
5303+
5304+ auto currentPos = startPos;
5305+ do {
5306+ while ( currentPos < reporterSpec.size() &&
5307+ reporterSpec[currentPos] != separator[0] ) {
5308+ ++currentPos;
5309+ }
5310+ if ( currentPos + 1 < reporterSpec.size() &&
5311+ reporterSpec[currentPos + 1] == separator[1] ) {
5312+ return currentPos;
5313+ }
5314+ ++currentPos;
5315+ } while ( currentPos < reporterSpec.size() );
5316+
5317+ return static_cast<size_t>( -1 );
5318+ };
5319+
5320+ std::vector<std::string> parts;
5321+
5322+ while ( separatorPos < reporterSpec.size() ) {
5323+ const auto nextSeparator = findNextSeparator( separatorPos );
5324+ parts.push_back( static_cast<std::string>( reporterSpec.substr(
5325+ separatorPos, nextSeparator - separatorPos ) ) );
5326+
5327+ if ( nextSeparator == static_cast<size_t>( -1 ) ) {
5328+ break;
5329+ }
5330+ separatorPos = nextSeparator + separatorSize;
5331+ }
5332+
5333+ // Handle a separator at the end.
5334+ // This is not a valid spec, but we want to do validation in a
5335+ // centralized place
5336+ if ( separatorPos == reporterSpec.size() ) {
5337+ parts.emplace_back();
5338+ }
5339+
5340+ return parts;
5341+ }
5342+
5343+ Optional<ColourMode> stringToColourMode( StringRef colourMode ) {
5344+ if ( colourMode == "default" ) {
5345+ return ColourMode::PlatformDefault;
5346+ } else if ( colourMode == "ansi" ) {
5347+ return ColourMode::ANSI;
5348+ } else if ( colourMode == "win32" ) {
5349+ return ColourMode::Win32;
5350+ } else if ( colourMode == "none" ) {
5351+ return ColourMode::None;
5352+ } else {
5353+ return {};
5354+ }
5355+ }
5356+ } // namespace Detail
5357+
5358+
5359+ bool operator==( ReporterSpec const& lhs, ReporterSpec const& rhs ) {
5360+ return lhs.m_name == rhs.m_name &&
5361+ lhs.m_outputFileName == rhs.m_outputFileName &&
5362+ lhs.m_colourMode == rhs.m_colourMode &&
5363+ lhs.m_customOptions == rhs.m_customOptions;
5364+ }
5365+
5366+ Optional<ReporterSpec> parseReporterSpec( StringRef reporterSpec ) {
5367+ auto parts = Detail::splitReporterSpec( reporterSpec );
5368+
5369+ assert( parts.size() > 0 && "Split should never return empty vector" );
5370+
5371+ std::map<std::string, std::string> kvPairs;
5372+ Optional<std::string> outputFileName;
5373+ Optional<ColourMode> colourMode;
5374+
5375+ // First part is always reporter name, so we skip it
5376+ for ( size_t i = 1; i < parts.size(); ++i ) {
5377+ auto kv = splitKVPair( parts[i] );
5378+ auto key = kv.key, value = kv.value;
5379+
5380+ if ( key.empty() || value.empty() ) { // NOLINT(bugprone-branch-clone)
5381+ return {};
5382+ } else if ( key[0] == 'X' ) {
5383+ // This is a reporter-specific option, we don't check these
5384+ // apart from basic sanity checks
5385+ if ( key.size() == 1 ) {
5386+ return {};
5387+ }
5388+
5389+ auto ret = kvPairs.emplace( std::string(kv.key), std::string(kv.value) );
5390+ if ( !ret.second ) {
5391+ // Duplicated key. We might want to handle this differently,
5392+ // e.g. by overwriting the existing value?
5393+ return {};
5394+ }
5395+ } else if ( key == "out" ) {
5396+ // Duplicated key
5397+ if ( outputFileName ) {
5398+ return {};
5399+ }
5400+ outputFileName = static_cast<std::string>( value );
5401+ } else if ( key == "colour-mode" ) {
5402+ // Duplicated key
5403+ if ( colourMode ) {
5404+ return {};
5405+ }
5406+ colourMode = Detail::stringToColourMode( value );
5407+ // Parsing failed
5408+ if ( !colourMode ) {
5409+ return {};
5410+ }
5411+ } else {
5412+ // Unrecognized option
5413+ return {};
5414+ }
5415+ }
5416+
5417+ return ReporterSpec{ CATCH_MOVE( parts[0] ),
5418+ CATCH_MOVE( outputFileName ),
5419+ CATCH_MOVE( colourMode ),
5420+ CATCH_MOVE( kvPairs ) };
5421+ }
5422+
5423+ReporterSpec::ReporterSpec(
5424+ std::string name,
5425+ Optional<std::string> outputFileName,
5426+ Optional<ColourMode> colourMode,
5427+ std::map<std::string, std::string> customOptions ):
5428+ m_name( CATCH_MOVE( name ) ),
5429+ m_outputFileName( CATCH_MOVE( outputFileName ) ),
5430+ m_colourMode( CATCH_MOVE( colourMode ) ),
5431+ m_customOptions( CATCH_MOVE( customOptions ) ) {}
5432+
5433+} // namespace Catch
5434+
5435+
5436+
5437+namespace Catch {
5438+
5439+ bool isOk( ResultWas::OfType resultType ) {
5440+ return ( resultType & ResultWas::FailureBit ) == 0;
5441+ }
5442+ bool isJustInfo( int flags ) {
5443+ return flags == ResultWas::Info;
5444+ }
5445+
5446+ ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) {
5447+ return static_cast<ResultDisposition::Flags>( static_cast<int>( lhs ) | static_cast<int>( rhs ) );
5448+ }
5449+
5450+ bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; }
5451+ bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; }
5452+
5453+} // end namespace Catch
5454+
5455+
5456+
5457+#include <cstdio>
5458+#include <sstream>
5459+#include <vector>
5460+
5461+namespace Catch {
5462+
5463+ // This class encapsulates the idea of a pool of ostringstreams that can be reused.
5464+ struct StringStreams {
5465+ std::vector<Detail::unique_ptr<std::ostringstream>> m_streams;
5466+ std::vector<std::size_t> m_unused;
5467+ std::ostringstream m_referenceStream; // Used for copy state/ flags from
5468+
5469+ auto add() -> std::size_t {
5470+ if( m_unused.empty() ) {
5471+ m_streams.push_back( Detail::make_unique<std::ostringstream>() );
5472+ return m_streams.size()-1;
5473+ }
5474+ else {
5475+ auto index = m_unused.back();
5476+ m_unused.pop_back();
5477+ return index;
5478+ }
5479+ }
5480+
5481+ void release( std::size_t index ) {
5482+ m_streams[index]->copyfmt( m_referenceStream ); // Restore initial flags and other state
5483+ m_unused.push_back(index);
5484+ }
5485+ };
5486+
5487+ ReusableStringStream::ReusableStringStream()
5488+ : m_index( Singleton<StringStreams>::getMutable().add() ),
5489+ m_oss( Singleton<StringStreams>::getMutable().m_streams[m_index].get() )
5490+ {}
5491+
5492+ ReusableStringStream::~ReusableStringStream() {
5493+ static_cast<std::ostringstream*>( m_oss )->str("");
5494+ m_oss->clear();
5495+ Singleton<StringStreams>::getMutable().release( m_index );
5496+ }
5497+
5498+ std::string ReusableStringStream::str() const {
5499+ return static_cast<std::ostringstream*>( m_oss )->str();
5500+ }
5501+
5502+ void ReusableStringStream::str( std::string const& str ) {
5503+ static_cast<std::ostringstream*>( m_oss )->str( str );
5504+ }
5505+
5506+
5507+}
5508+
5509+
5510+
5511+
5512+#include <cassert>
5513+#include <algorithm>
5514+
5515+namespace Catch {
5516+
5517+ namespace Generators {
5518+ namespace {
5519+ struct GeneratorTracker final : TestCaseTracking::TrackerBase,
5520+ IGeneratorTracker {
5521+ GeneratorBasePtr m_generator;
5522+
5523+ GeneratorTracker(
5524+ TestCaseTracking::NameAndLocation&& nameAndLocation,
5525+ TrackerContext& ctx,
5526+ ITracker* parent ):
5527+ TrackerBase( CATCH_MOVE( nameAndLocation ), ctx, parent ) {}
5528+
5529+ static GeneratorTracker*
5530+ acquire( TrackerContext& ctx,
5531+ TestCaseTracking::NameAndLocationRef const&
5532+ nameAndLocation ) {
5533+ GeneratorTracker* tracker;
5534+
5535+ ITracker& currentTracker = ctx.currentTracker();
5536+ // Under specific circumstances, the generator we want
5537+ // to acquire is also the current tracker. If this is
5538+ // the case, we have to avoid looking through current
5539+ // tracker's children, and instead return the current
5540+ // tracker.
5541+ // A case where this check is important is e.g.
5542+ // for (int i = 0; i < 5; ++i) {
5543+ // int n = GENERATE(1, 2);
5544+ // }
5545+ //
5546+ // without it, the code above creates 5 nested generators.
5547+ if ( currentTracker.nameAndLocation() == nameAndLocation ) {
5548+ auto thisTracker = currentTracker.parent()->findChild(
5549+ nameAndLocation );
5550+ assert( thisTracker );
5551+ assert( thisTracker->isGeneratorTracker() );
5552+ tracker = static_cast<GeneratorTracker*>( thisTracker );
5553+ } else if ( ITracker* childTracker =
5554+ currentTracker.findChild(
5555+ nameAndLocation ) ) {
5556+ assert( childTracker );
5557+ assert( childTracker->isGeneratorTracker() );
5558+ tracker =
5559+ static_cast<GeneratorTracker*>( childTracker );
5560+ } else {
5561+ return nullptr;
5562+ }
5563+
5564+ if ( !tracker->isComplete() ) { tracker->open(); }
5565+
5566+ return tracker;
5567+ }
5568+
5569+ // TrackerBase interface
5570+ bool isGeneratorTracker() const override { return true; }
5571+ auto hasGenerator() const -> bool override {
5572+ return !!m_generator;
5573+ }
5574+ void close() override {
5575+ TrackerBase::close();
5576+ // If a generator has a child (it is followed by a section)
5577+ // and none of its children have started, then we must wait
5578+ // until later to start consuming its values.
5579+ // This catches cases where `GENERATE` is placed between two
5580+ // `SECTION`s.
5581+ // **The check for m_children.empty cannot be removed**.
5582+ // doing so would break `GENERATE` _not_ followed by
5583+ // `SECTION`s.
5584+ const bool should_wait_for_child = [&]() {
5585+ // No children -> nobody to wait for
5586+ if ( m_children.empty() ) { return false; }
5587+ // If at least one child started executing, don't wait
5588+ if ( std::find_if(
5589+ m_children.begin(),
5590+ m_children.end(),
5591+ []( TestCaseTracking::ITrackerPtr const&
5592+ tracker ) {
5593+ return tracker->hasStarted();
5594+ } ) != m_children.end() ) {
5595+ return false;
5596+ }
5597+
5598+ // No children have started. We need to check if they
5599+ // _can_ start, and thus we should wait for them, or
5600+ // they cannot start (due to filters), and we shouldn't
5601+ // wait for them
5602+ ITracker* parent = m_parent;
5603+ // This is safe: there is always at least one section
5604+ // tracker in a test case tracking tree
5605+ while ( !parent->isSectionTracker() ) {
5606+ parent = parent->parent();
5607+ }
5608+ assert( parent &&
5609+ "Missing root (test case) level section" );
5610+
5611+ auto const& parentSection =
5612+ static_cast<SectionTracker const&>( *parent );
5613+ auto const& filters = parentSection.getFilters();
5614+ // No filters -> no restrictions on running sections
5615+ if ( filters.empty() ) { return true; }
5616+
5617+ for ( auto const& child : m_children ) {
5618+ if ( child->isSectionTracker() &&
5619+ std::find( filters.begin(),
5620+ filters.end(),
5621+ static_cast<SectionTracker const&>(
5622+ *child )
5623+ .trimmedName() ) !=
5624+ filters.end() ) {
5625+ return true;
5626+ }
5627+ }
5628+ return false;
5629+ }();
5630+
5631+ // This check is a bit tricky, because m_generator->next()
5632+ // has a side-effect, where it consumes generator's current
5633+ // value, but we do not want to invoke the side-effect if
5634+ // this generator is still waiting for any child to start.
5635+ assert( m_generator && "Tracker without generator" );
5636+ if ( should_wait_for_child ||
5637+ ( m_runState == CompletedSuccessfully &&
5638+ m_generator->countedNext() ) ) {
5639+ m_children.clear();
5640+ m_runState = Executing;
5641+ }
5642+ }
5643+
5644+ // IGeneratorTracker interface
5645+ auto getGenerator() const -> GeneratorBasePtr const& override {
5646+ return m_generator;
5647+ }
5648+ void setGenerator( GeneratorBasePtr&& generator ) override {
5649+ m_generator = CATCH_MOVE( generator );
5650+ }
5651+ };
5652+ } // namespace
5653+ }
5654+
5655+ RunContext::RunContext(IConfig const* _config, IEventListenerPtr&& reporter)
5656+ : m_runInfo(_config->name()),
5657+ m_config(_config),
5658+ m_reporter(CATCH_MOVE(reporter)),
5659+ m_lastAssertionInfo{ StringRef(), SourceLineInfo("",0), StringRef(), ResultDisposition::Normal },
5660+ m_includeSuccessfulResults( m_config->includeSuccessfulResults() || m_reporter->getPreferences().shouldReportAllAssertions )
5661+ {
5662+ getCurrentMutableContext().setResultCapture( this );
5663+ m_reporter->testRunStarting(m_runInfo);
5664+ }
5665+
5666+ RunContext::~RunContext() {
5667+ m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, aborting()));
5668+ }
5669+
5670+ Totals RunContext::runTest(TestCaseHandle const& testCase) {
5671+ const Totals prevTotals = m_totals;
5672+
5673+ auto const& testInfo = testCase.getTestCaseInfo();
5674+ m_reporter->testCaseStarting(testInfo);
5675+ m_activeTestCase = &testCase;
5676+
5677+
5678+ ITracker& rootTracker = m_trackerContext.startRun();
5679+ assert(rootTracker.isSectionTracker());
5680+ static_cast<SectionTracker&>(rootTracker).addInitialFilters(m_config->getSectionsToRun());
5681+
5682+ // We intentionally only seed the internal RNG once per test case,
5683+ // before it is first invoked. The reason for that is a complex
5684+ // interplay of generator/section implementation details and the
5685+ // Random*Generator types.
5686+ //
5687+ // The issue boils down to us needing to seed the Random*Generators
5688+ // with different seed each, so that they return different sequences
5689+ // of random numbers. We do this by giving them a number from the
5690+ // shared RNG instance as their seed.
5691+ //
5692+ // However, this runs into an issue if the reseeding happens each
5693+ // time the test case is entered (as opposed to first time only),
5694+ // because multiple generators could get the same seed, e.g. in
5695+ // ```cpp
5696+ // TEST_CASE() {
5697+ // auto i = GENERATE(take(10, random(0, 100));
5698+ // SECTION("A") {
5699+ // auto j = GENERATE(take(10, random(0, 100));
5700+ // }
5701+ // SECTION("B") {
5702+ // auto k = GENERATE(take(10, random(0, 100));
5703+ // }
5704+ // }
5705+ // ```
5706+ // `i` and `j` would properly return values from different sequences,
5707+ // but `i` and `k` would return the same sequence, because their seed
5708+ // would be the same.
5709+ // (The reason their seeds would be the same is that the generator
5710+ // for k would be initialized when the test case is entered the second
5711+ // time, after the shared RNG instance was reset to the same value
5712+ // it had when the generator for i was initialized.)
5713+ seedRng( *m_config );
5714+
5715+ uint64_t testRuns = 0;
5716+ std::string redirectedCout;
5717+ std::string redirectedCerr;
5718+ do {
5719+ m_trackerContext.startCycle();
5720+ m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocationRef(testInfo.name, testInfo.lineInfo));
5721+
5722+ m_reporter->testCasePartialStarting(testInfo, testRuns);
5723+
5724+ const auto beforeRunTotals = m_totals;
5725+ std::string oneRunCout, oneRunCerr;
5726+ runCurrentTest(oneRunCout, oneRunCerr);
5727+ redirectedCout += oneRunCout;
5728+ redirectedCerr += oneRunCerr;
5729+
5730+ const auto singleRunTotals = m_totals.delta(beforeRunTotals);
5731+ auto statsForOneRun = TestCaseStats(testInfo, singleRunTotals, CATCH_MOVE(oneRunCout), CATCH_MOVE(oneRunCerr), aborting());
5732+
5733+ m_reporter->testCasePartialEnded(statsForOneRun, testRuns);
5734+ ++testRuns;
5735+ } while (!m_testCaseTracker->isSuccessfullyCompleted() && !aborting());
5736+
5737+ Totals deltaTotals = m_totals.delta(prevTotals);
5738+ if (testInfo.expectedToFail() && deltaTotals.testCases.passed > 0) {
5739+ deltaTotals.assertions.failed++;
5740+ deltaTotals.testCases.passed--;
5741+ deltaTotals.testCases.failed++;
5742+ }
5743+ m_totals.testCases += deltaTotals.testCases;
5744+ m_reporter->testCaseEnded(TestCaseStats(testInfo,
5745+ deltaTotals,
5746+ CATCH_MOVE(redirectedCout),
5747+ CATCH_MOVE(redirectedCerr),
5748+ aborting()));
5749+
5750+ m_activeTestCase = nullptr;
5751+ m_testCaseTracker = nullptr;
5752+
5753+ return deltaTotals;
5754+ }
5755+
5756+
5757+ void RunContext::assertionEnded(AssertionResult&& result) {
5758+ if (result.getResultType() == ResultWas::Ok) {
5759+ m_totals.assertions.passed++;
5760+ m_lastAssertionPassed = true;
5761+ } else if (result.getResultType() == ResultWas::ExplicitSkip) {
5762+ m_totals.assertions.skipped++;
5763+ m_lastAssertionPassed = true;
5764+ } else if (!result.succeeded()) {
5765+ m_lastAssertionPassed = false;
5766+ if (result.isOk()) {
5767+ }
5768+ else if( m_activeTestCase->getTestCaseInfo().okToFail() )
5769+ m_totals.assertions.failedButOk++;
5770+ else
5771+ m_totals.assertions.failed++;
5772+ }
5773+ else {
5774+ m_lastAssertionPassed = true;
5775+ }
5776+
5777+ m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals));
5778+
5779+ if ( result.getResultType() != ResultWas::Warning ) {
5780+ m_messageScopes.clear();
5781+ }
5782+
5783+ // Reset working state. assertion info will be reset after
5784+ // populateReaction is run if it is needed
5785+ m_lastResult = CATCH_MOVE( result );
5786+ }
5787+ void RunContext::resetAssertionInfo() {
5788+ m_lastAssertionInfo.macroName = StringRef();
5789+ m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"_sr;
5790+ m_lastAssertionInfo.resultDisposition = ResultDisposition::Normal;
5791+ }
5792+
5793+ void RunContext::notifyAssertionStarted( AssertionInfo const& info ) {
5794+ m_reporter->assertionStarting( info );
5795+ }
5796+
5797+ bool RunContext::sectionStarted( StringRef sectionName,
5798+ SourceLineInfo const& sectionLineInfo,
5799+ Counts& assertions ) {
5800+ ITracker& sectionTracker =
5801+ SectionTracker::acquire( m_trackerContext,
5802+ TestCaseTracking::NameAndLocationRef(
5803+ sectionName, sectionLineInfo ) );
5804+
5805+ if (!sectionTracker.isOpen())
5806+ return false;
5807+ m_activeSections.push_back(§ionTracker);
5808+
5809+ SectionInfo sectionInfo( sectionLineInfo, static_cast<std::string>(sectionName) );
5810+ m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo;
5811+
5812+ m_reporter->sectionStarting(sectionInfo);
5813+
5814+ assertions = m_totals.assertions;
5815+
5816+ return true;
5817+ }
5818+ IGeneratorTracker*
5819+ RunContext::acquireGeneratorTracker( StringRef generatorName,
5820+ SourceLineInfo const& lineInfo ) {
5821+ using namespace Generators;
5822+ GeneratorTracker* tracker = GeneratorTracker::acquire(
5823+ m_trackerContext,
5824+ TestCaseTracking::NameAndLocationRef(
5825+ generatorName, lineInfo ) );
5826+ m_lastAssertionInfo.lineInfo = lineInfo;
5827+ return tracker;
5828+ }
5829+
5830+ IGeneratorTracker* RunContext::createGeneratorTracker(
5831+ StringRef generatorName,
5832+ SourceLineInfo lineInfo,
5833+ Generators::GeneratorBasePtr&& generator ) {
5834+
5835+ auto nameAndLoc = TestCaseTracking::NameAndLocation( static_cast<std::string>( generatorName ), lineInfo );
5836+ auto& currentTracker = m_trackerContext.currentTracker();
5837+ assert(
5838+ currentTracker.nameAndLocation() != nameAndLoc &&
5839+ "Trying to create tracker for a genreator that already has one" );
5840+
5841+ auto newTracker = Catch::Detail::make_unique<Generators::GeneratorTracker>(
5842+ CATCH_MOVE(nameAndLoc), m_trackerContext, ¤tTracker );
5843+ auto ret = newTracker.get();
5844+ currentTracker.addChild( CATCH_MOVE( newTracker ) );
5845+
5846+ ret->setGenerator( CATCH_MOVE( generator ) );
5847+ ret->open();
5848+ return ret;
5849+ }
5850+
5851+ bool RunContext::testForMissingAssertions(Counts& assertions) {
5852+ if (assertions.total() != 0)
5853+ return false;
5854+ if (!m_config->warnAboutMissingAssertions())
5855+ return false;
5856+ if (m_trackerContext.currentTracker().hasChildren())
5857+ return false;
5858+ m_totals.assertions.failed++;
5859+ assertions.failed++;
5860+ return true;
5861+ }
5862+
5863+ void RunContext::sectionEnded(SectionEndInfo&& endInfo) {
5864+ Counts assertions = m_totals.assertions - endInfo.prevAssertions;
5865+ bool missingAssertions = testForMissingAssertions(assertions);
5866+
5867+ if (!m_activeSections.empty()) {
5868+ m_activeSections.back()->close();
5869+ m_activeSections.pop_back();
5870+ }
5871+
5872+ m_reporter->sectionEnded(SectionStats(CATCH_MOVE(endInfo.sectionInfo), assertions, endInfo.durationInSeconds, missingAssertions));
5873+ m_messages.clear();
5874+ m_messageScopes.clear();
5875+ }
5876+
5877+ void RunContext::sectionEndedEarly(SectionEndInfo&& endInfo) {
5878+ if ( m_unfinishedSections.empty() ) {
5879+ m_activeSections.back()->fail();
5880+ } else {
5881+ m_activeSections.back()->close();
5882+ }
5883+ m_activeSections.pop_back();
5884+
5885+ m_unfinishedSections.push_back(CATCH_MOVE(endInfo));
5886+ }
5887+
5888+ void RunContext::benchmarkPreparing( StringRef name ) {
5889+ m_reporter->benchmarkPreparing(name);
5890+ }
5891+ void RunContext::benchmarkStarting( BenchmarkInfo const& info ) {
5892+ m_reporter->benchmarkStarting( info );
5893+ }
5894+ void RunContext::benchmarkEnded( BenchmarkStats<> const& stats ) {
5895+ m_reporter->benchmarkEnded( stats );
5896+ }
5897+ void RunContext::benchmarkFailed( StringRef error ) {
5898+ m_reporter->benchmarkFailed( error );
5899+ }
5900+
5901+ void RunContext::pushScopedMessage(MessageInfo const & message) {
5902+ m_messages.push_back(message);
5903+ }
5904+
5905+ void RunContext::popScopedMessage(MessageInfo const & message) {
5906+ m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end());
5907+ }
5908+
5909+ void RunContext::emplaceUnscopedMessage( MessageBuilder&& builder ) {
5910+ m_messageScopes.emplace_back( CATCH_MOVE(builder) );
5911+ }
5912+
5913+ std::string RunContext::getCurrentTestName() const {
5914+ return m_activeTestCase
5915+ ? m_activeTestCase->getTestCaseInfo().name
5916+ : std::string();
5917+ }
5918+
5919+ const AssertionResult * RunContext::getLastResult() const {
5920+ return &(*m_lastResult);
5921+ }
5922+
5923+ void RunContext::exceptionEarlyReported() {
5924+ m_shouldReportUnexpected = false;
5925+ }
5926+
5927+ void RunContext::handleFatalErrorCondition( StringRef message ) {
5928+ // First notify reporter that bad things happened
5929+ m_reporter->fatalErrorEncountered(message);
5930+
5931+ // Don't rebuild the result -- the stringification itself can cause more fatal errors
5932+ // Instead, fake a result data.
5933+ AssertionResultData tempResult( ResultWas::FatalErrorCondition, { false } );
5934+ tempResult.message = static_cast<std::string>(message);
5935+ AssertionResult result(m_lastAssertionInfo, CATCH_MOVE(tempResult));
5936+
5937+ assertionEnded(CATCH_MOVE(result) );
5938+ resetAssertionInfo();
5939+
5940+ handleUnfinishedSections();
5941+
5942+ // Recreate section for test case (as we will lose the one that was in scope)
5943+ auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
5944+ SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name);
5945+
5946+ Counts assertions;
5947+ assertions.failed = 1;
5948+ SectionStats testCaseSectionStats(CATCH_MOVE(testCaseSection), assertions, 0, false);
5949+ m_reporter->sectionEnded(testCaseSectionStats);
5950+
5951+ auto const& testInfo = m_activeTestCase->getTestCaseInfo();
5952+
5953+ Totals deltaTotals;
5954+ deltaTotals.testCases.failed = 1;
5955+ deltaTotals.assertions.failed = 1;
5956+ m_reporter->testCaseEnded(TestCaseStats(testInfo,
5957+ deltaTotals,
5958+ std::string(),
5959+ std::string(),
5960+ false));
5961+ m_totals.testCases.failed++;
5962+ m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, false));
5963+ }
5964+
5965+ bool RunContext::lastAssertionPassed() {
5966+ return m_lastAssertionPassed;
5967+ }
5968+
5969+ void RunContext::assertionPassed() {
5970+ m_lastAssertionPassed = true;
5971+ ++m_totals.assertions.passed;
5972+ resetAssertionInfo();
5973+ m_messageScopes.clear();
5974+ }
5975+
5976+ bool RunContext::aborting() const {
5977+ return m_totals.assertions.failed >= static_cast<std::size_t>(m_config->abortAfter());
5978+ }
5979+
5980+ void RunContext::runCurrentTest(std::string & redirectedCout, std::string & redirectedCerr) {
5981+ auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
5982+ SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name);
5983+ m_reporter->sectionStarting(testCaseSection);
5984+ Counts prevAssertions = m_totals.assertions;
5985+ double duration = 0;
5986+ m_shouldReportUnexpected = true;
5987+ m_lastAssertionInfo = { "TEST_CASE"_sr, testCaseInfo.lineInfo, StringRef(), ResultDisposition::Normal };
5988+
5989+ Timer timer;
5990+ CATCH_TRY {
5991+ if (m_reporter->getPreferences().shouldRedirectStdOut) {
5992+#if !defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT)
5993+ RedirectedStreams redirectedStreams(redirectedCout, redirectedCerr);
5994+
5995+ timer.start();
5996+ invokeActiveTestCase();
5997+#else
5998+ OutputRedirect r(redirectedCout, redirectedCerr);
5999+ timer.start();
6000+ invokeActiveTestCase();
6001+#endif
6002+ } else {
6003+ timer.start();
6004+ invokeActiveTestCase();
6005+ }
6006+ duration = timer.getElapsedSeconds();
6007+ } CATCH_CATCH_ANON (TestFailureException&) {
6008+ // This just means the test was aborted due to failure
6009+ } CATCH_CATCH_ANON (TestSkipException&) {
6010+ // This just means the test was explicitly skipped
6011+ } CATCH_CATCH_ALL {
6012+ // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions
6013+ // are reported without translation at the point of origin.
6014+ if( m_shouldReportUnexpected ) {
6015+ AssertionReaction dummyReaction;
6016+ handleUnexpectedInflightException( m_lastAssertionInfo, translateActiveException(), dummyReaction );
6017+ }
6018+ }
6019+ Counts assertions = m_totals.assertions - prevAssertions;
6020+ bool missingAssertions = testForMissingAssertions(assertions);
6021+
6022+ m_testCaseTracker->close();
6023+ handleUnfinishedSections();
6024+ m_messages.clear();
6025+ m_messageScopes.clear();
6026+
6027+ SectionStats testCaseSectionStats(CATCH_MOVE(testCaseSection), assertions, duration, missingAssertions);
6028+ m_reporter->sectionEnded(testCaseSectionStats);
6029+ }
6030+
6031+ void RunContext::invokeActiveTestCase() {
6032+ // We need to engage a handler for signals/structured exceptions
6033+ // before running the tests themselves, or the binary can crash
6034+ // without failed test being reported.
6035+ FatalConditionHandlerGuard _(&m_fatalConditionhandler);
6036+ // We keep having issue where some compilers warn about an unused
6037+ // variable, even though the type has non-trivial constructor and
6038+ // destructor. This is annoying and ugly, but it makes them stfu.
6039+ (void)_;
6040+
6041+ m_activeTestCase->invoke();
6042+ }
6043+
6044+ void RunContext::handleUnfinishedSections() {
6045+ // If sections ended prematurely due to an exception we stored their
6046+ // infos here so we can tear them down outside the unwind process.
6047+ for (auto it = m_unfinishedSections.rbegin(),
6048+ itEnd = m_unfinishedSections.rend();
6049+ it != itEnd;
6050+ ++it)
6051+ sectionEnded(CATCH_MOVE(*it));
6052+ m_unfinishedSections.clear();
6053+ }
6054+
6055+ void RunContext::handleExpr(
6056+ AssertionInfo const& info,
6057+ ITransientExpression const& expr,
6058+ AssertionReaction& reaction
6059+ ) {
6060+ bool negated = isFalseTest( info.resultDisposition );
6061+ bool result = expr.getResult() != negated;
6062+
6063+ if( result ) {
6064+ if (!m_includeSuccessfulResults) {
6065+ assertionPassed();
6066+ }
6067+ else {
6068+ reportExpr(info, ResultWas::Ok, &expr, negated);
6069+ }
6070+ }
6071+ else {
6072+ reportExpr(info, ResultWas::ExpressionFailed, &expr, negated );
6073+ populateReaction( reaction );
6074+ }
6075+ resetAssertionInfo();
6076+ }
6077+ void RunContext::reportExpr(
6078+ AssertionInfo const &info,
6079+ ResultWas::OfType resultType,
6080+ ITransientExpression const *expr,
6081+ bool negated ) {
6082+
6083+ m_lastAssertionInfo = info;
6084+ AssertionResultData data( resultType, LazyExpression( negated ) );
6085+
6086+ AssertionResult assertionResult{ info, CATCH_MOVE( data ) };
6087+ assertionResult.m_resultData.lazyExpression.m_transientExpression = expr;
6088+
6089+ assertionEnded( CATCH_MOVE(assertionResult) );
6090+ }
6091+
6092+ void RunContext::handleMessage(
6093+ AssertionInfo const& info,
6094+ ResultWas::OfType resultType,
6095+ StringRef message,
6096+ AssertionReaction& reaction
6097+ ) {
6098+ m_lastAssertionInfo = info;
6099+
6100+ AssertionResultData data( resultType, LazyExpression( false ) );
6101+ data.message = static_cast<std::string>(message);
6102+ AssertionResult assertionResult{ m_lastAssertionInfo,
6103+ CATCH_MOVE( data ) };
6104+
6105+ const auto isOk = assertionResult.isOk();
6106+ assertionEnded( CATCH_MOVE(assertionResult) );
6107+ if ( !isOk ) {
6108+ populateReaction( reaction );
6109+ } else if ( resultType == ResultWas::ExplicitSkip ) {
6110+ // TODO: Need to handle this explicitly, as ExplicitSkip is
6111+ // considered "OK"
6112+ reaction.shouldSkip = true;
6113+ }
6114+ resetAssertionInfo();
6115+ }
6116+ void RunContext::handleUnexpectedExceptionNotThrown(
6117+ AssertionInfo const& info,
6118+ AssertionReaction& reaction
6119+ ) {
6120+ handleNonExpr(info, Catch::ResultWas::DidntThrowException, reaction);
6121+ }
6122+
6123+ void RunContext::handleUnexpectedInflightException(
6124+ AssertionInfo const& info,
6125+ std::string&& message,
6126+ AssertionReaction& reaction
6127+ ) {
6128+ m_lastAssertionInfo = info;
6129+
6130+ AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) );
6131+ data.message = CATCH_MOVE(message);
6132+ AssertionResult assertionResult{ info, CATCH_MOVE(data) };
6133+ assertionEnded( CATCH_MOVE(assertionResult) );
6134+ populateReaction( reaction );
6135+ resetAssertionInfo();
6136+ }
6137+
6138+ void RunContext::populateReaction( AssertionReaction& reaction ) {
6139+ reaction.shouldDebugBreak = m_config->shouldDebugBreak();
6140+ reaction.shouldThrow = aborting() || (m_lastAssertionInfo.resultDisposition & ResultDisposition::Normal);
6141+ }
6142+
6143+ void RunContext::handleIncomplete(
6144+ AssertionInfo const& info
6145+ ) {
6146+ using namespace std::string_literals;
6147+ m_lastAssertionInfo = info;
6148+
6149+ AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) );
6150+ data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"s;
6151+ AssertionResult assertionResult{ info, CATCH_MOVE( data ) };
6152+ assertionEnded( CATCH_MOVE(assertionResult) );
6153+ resetAssertionInfo();
6154+ }
6155+ void RunContext::handleNonExpr(
6156+ AssertionInfo const &info,
6157+ ResultWas::OfType resultType,
6158+ AssertionReaction &reaction
6159+ ) {
6160+ m_lastAssertionInfo = info;
6161+
6162+ AssertionResultData data( resultType, LazyExpression( false ) );
6163+ AssertionResult assertionResult{ info, CATCH_MOVE( data ) };
6164+
6165+ const auto isOk = assertionResult.isOk();
6166+ assertionEnded( CATCH_MOVE(assertionResult) );
6167+ if ( !isOk ) { populateReaction( reaction ); }
6168+ resetAssertionInfo();
6169+ }
6170+
6171+
6172+ IResultCapture& getResultCapture() {
6173+ if (auto* capture = getCurrentContext().getResultCapture())
6174+ return *capture;
6175+ else
6176+ CATCH_INTERNAL_ERROR("No result capture instance");
6177+ }
6178+
6179+ void seedRng(IConfig const& config) {
6180+ sharedRng().seed(config.rngSeed());
6181+ }
6182+
6183+ unsigned int rngSeed() {
6184+ return getCurrentContext().getConfig()->rngSeed();
6185+ }
6186+
6187+}
6188+
6189+
6190+
6191+namespace Catch {
6192+
6193+ Section::Section( SectionInfo&& info ):
6194+ m_info( CATCH_MOVE( info ) ),
6195+ m_sectionIncluded(
6196+ getResultCapture().sectionStarted( m_info.name, m_info.lineInfo, m_assertions ) ) {
6197+ // Non-"included" sections will not use the timing information
6198+ // anyway, so don't bother with the potential syscall.
6199+ if (m_sectionIncluded) {
6200+ m_timer.start();
6201+ }
6202+ }
6203+
6204+ Section::Section( SourceLineInfo const& _lineInfo,
6205+ StringRef _name,
6206+ const char* const ):
6207+ m_info( { "invalid", static_cast<std::size_t>( -1 ) }, std::string{} ),
6208+ m_sectionIncluded(
6209+ getResultCapture().sectionStarted( _name, _lineInfo, m_assertions ) ) {
6210+ // We delay initialization the SectionInfo member until we know
6211+ // this section needs it, so we avoid allocating std::string for name.
6212+ // We also delay timer start to avoid the potential syscall unless we
6213+ // will actually use the result.
6214+ if ( m_sectionIncluded ) {
6215+ m_info.name = static_cast<std::string>( _name );
6216+ m_info.lineInfo = _lineInfo;
6217+ m_timer.start();
6218+ }
6219+ }
6220+
6221+ Section::~Section() {
6222+ if( m_sectionIncluded ) {
6223+ SectionEndInfo endInfo{ CATCH_MOVE(m_info), m_assertions, m_timer.getElapsedSeconds() };
6224+ if ( uncaught_exceptions() ) {
6225+ getResultCapture().sectionEndedEarly( CATCH_MOVE(endInfo) );
6226+ } else {
6227+ getResultCapture().sectionEnded( CATCH_MOVE( endInfo ) );
6228+ }
6229+ }
6230+ }
6231+
6232+ // This indicates whether the section should be executed or not
6233+ Section::operator bool() const {
6234+ return m_sectionIncluded;
6235+ }
6236+
6237+
6238+} // end namespace Catch
6239+
6240+
6241+
6242+#include <vector>
6243+
6244+namespace Catch {
6245+
6246+ namespace {
6247+ static auto getSingletons() -> std::vector<ISingleton*>*& {
6248+ static std::vector<ISingleton*>* g_singletons = nullptr;
6249+ if( !g_singletons )
6250+ g_singletons = new std::vector<ISingleton*>();
6251+ return g_singletons;
6252+ }
6253+ }
6254+
6255+ ISingleton::~ISingleton() = default;
6256+
6257+ void addSingleton(ISingleton* singleton ) {
6258+ getSingletons()->push_back( singleton );
6259+ }
6260+ void cleanupSingletons() {
6261+ auto& singletons = getSingletons();
6262+ for( auto singleton : *singletons )
6263+ delete singleton;
6264+ delete singletons;
6265+ singletons = nullptr;
6266+ }
6267+
6268+} // namespace Catch
6269+
6270+
6271+
6272+#include <cstring>
6273+#include <ostream>
6274+
6275+namespace Catch {
6276+
6277+ bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const noexcept {
6278+ return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0);
6279+ }
6280+ bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const noexcept {
6281+ // We can assume that the same file will usually have the same pointer.
6282+ // Thus, if the pointers are the same, there is no point in calling the strcmp
6283+ return line < other.line || ( line == other.line && file != other.file && (std::strcmp(file, other.file) < 0));
6284+ }
6285+
6286+ std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) {
6287+#ifndef __GNUG__
6288+ os << info.file << '(' << info.line << ')';
6289+#else
6290+ os << info.file << ':' << info.line;
6291+#endif
6292+ return os;
6293+ }
6294+
6295+} // end namespace Catch
6296+
6297+
6298+
6299+
6300+namespace Catch {
6301+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
6302+ void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept {
6303+ CATCH_TRY {
6304+ m_exceptions.push_back(exception);
6305+ } CATCH_CATCH_ALL {
6306+ // If we run out of memory during start-up there's really not a lot more we can do about it
6307+ std::terminate();
6308+ }
6309+ }
6310+
6311+ std::vector<std::exception_ptr> const& StartupExceptionRegistry::getExceptions() const noexcept {
6312+ return m_exceptions;
6313+ }
6314+#endif
6315+
6316+} // end namespace Catch
6317+
6318+
6319+
6320+
6321+
6322+#include <iostream>
6323+
6324+namespace Catch {
6325+
6326+// If you #define this you must implement these functions
6327+#if !defined( CATCH_CONFIG_NOSTDOUT )
6328+ std::ostream& cout() { return std::cout; }
6329+ std::ostream& cerr() { return std::cerr; }
6330+ std::ostream& clog() { return std::clog; }
6331+#endif
6332+
6333+} // namespace Catch
6334+
6335+
6336+
6337+#include <ostream>
6338+#include <cstring>
6339+#include <cctype>
6340+#include <vector>
6341+
6342+namespace Catch {
6343+
6344+ bool startsWith( std::string const& s, std::string const& prefix ) {
6345+ return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin());
6346+ }
6347+ bool startsWith( StringRef s, char prefix ) {
6348+ return !s.empty() && s[0] == prefix;
6349+ }
6350+ bool endsWith( std::string const& s, std::string const& suffix ) {
6351+ return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin());
6352+ }
6353+ bool endsWith( std::string const& s, char suffix ) {
6354+ return !s.empty() && s[s.size()-1] == suffix;
6355+ }
6356+ bool contains( std::string const& s, std::string const& infix ) {
6357+ return s.find( infix ) != std::string::npos;
6358+ }
6359+ void toLowerInPlace( std::string& s ) {
6360+ for ( char& c : s ) {
6361+ c = toLower( c );
6362+ }
6363+ }
6364+ std::string toLower( std::string const& s ) {
6365+ std::string lc = s;
6366+ toLowerInPlace( lc );
6367+ return lc;
6368+ }
6369+ char toLower(char c) {
6370+ return static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
6371+ }
6372+
6373+ std::string trim( std::string const& str ) {
6374+ static char const* whitespaceChars = "\n\r\t ";
6375+ std::string::size_type start = str.find_first_not_of( whitespaceChars );
6376+ std::string::size_type end = str.find_last_not_of( whitespaceChars );
6377+
6378+ return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string();
6379+ }
6380+
6381+ StringRef trim(StringRef ref) {
6382+ const auto is_ws = [](char c) {
6383+ return c == ' ' || c == '\t' || c == '\n' || c == '\r';
6384+ };
6385+ size_t real_begin = 0;
6386+ while (real_begin < ref.size() && is_ws(ref[real_begin])) { ++real_begin; }
6387+ size_t real_end = ref.size();
6388+ while (real_end > real_begin && is_ws(ref[real_end - 1])) { --real_end; }
6389+
6390+ return ref.substr(real_begin, real_end - real_begin);
6391+ }
6392+
6393+ bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) {
6394+ std::size_t i = str.find( replaceThis );
6395+ if (i == std::string::npos) {
6396+ return false;
6397+ }
6398+ std::size_t copyBegin = 0;
6399+ std::string origStr = CATCH_MOVE(str);
6400+ str.clear();
6401+ // There is at least one replacement, so reserve with the best guess
6402+ // we can make without actually counting the number of occurences.
6403+ str.reserve(origStr.size() - replaceThis.size() + withThis.size());
6404+ do {
6405+ str.append(origStr, copyBegin, i-copyBegin );
6406+ str += withThis;
6407+ copyBegin = i + replaceThis.size();
6408+ if( copyBegin < origStr.size() )
6409+ i = origStr.find( replaceThis, copyBegin );
6410+ else
6411+ i = std::string::npos;
6412+ } while( i != std::string::npos );
6413+ if ( copyBegin < origStr.size() ) {
6414+ str.append(origStr, copyBegin, origStr.size() );
6415+ }
6416+ return true;
6417+ }
6418+
6419+ std::vector<StringRef> splitStringRef( StringRef str, char delimiter ) {
6420+ std::vector<StringRef> subStrings;
6421+ std::size_t start = 0;
6422+ for(std::size_t pos = 0; pos < str.size(); ++pos ) {
6423+ if( str[pos] == delimiter ) {
6424+ if( pos - start > 1 )
6425+ subStrings.push_back( str.substr( start, pos-start ) );
6426+ start = pos+1;
6427+ }
6428+ }
6429+ if( start < str.size() )
6430+ subStrings.push_back( str.substr( start, str.size()-start ) );
6431+ return subStrings;
6432+ }
6433+
6434+ std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) {
6435+ os << pluraliser.m_count << ' ' << pluraliser.m_label;
6436+ if( pluraliser.m_count != 1 )
6437+ os << 's';
6438+ return os;
6439+ }
6440+
6441+}
6442+
6443+
6444+
6445+#include <algorithm>
6446+#include <ostream>
6447+#include <cstring>
6448+#include <cstdint>
6449+
6450+namespace Catch {
6451+ StringRef::StringRef( char const* rawChars ) noexcept
6452+ : StringRef( rawChars, std::strlen(rawChars) )
6453+ {}
6454+
6455+
6456+ bool StringRef::operator<(StringRef rhs) const noexcept {
6457+ if (m_size < rhs.m_size) {
6458+ return strncmp(m_start, rhs.m_start, m_size) <= 0;
6459+ }
6460+ return strncmp(m_start, rhs.m_start, rhs.m_size) < 0;
6461+ }
6462+
6463+ int StringRef::compare( StringRef rhs ) const {
6464+ auto cmpResult =
6465+ strncmp( m_start, rhs.m_start, std::min( m_size, rhs.m_size ) );
6466+
6467+ // This means that strncmp found a difference before the strings
6468+ // ended, and we can return it directly
6469+ if ( cmpResult != 0 ) {
6470+ return cmpResult;
6471+ }
6472+
6473+ // If strings are equal up to length, then their comparison results on
6474+ // their size
6475+ if ( m_size < rhs.m_size ) {
6476+ return -1;
6477+ } else if ( m_size > rhs.m_size ) {
6478+ return 1;
6479+ } else {
6480+ return 0;
6481+ }
6482+ }
6483+
6484+ auto operator << ( std::ostream& os, StringRef str ) -> std::ostream& {
6485+ return os.write(str.data(), static_cast<std::streamsize>(str.size()));
6486+ }
6487+
6488+ std::string operator+(StringRef lhs, StringRef rhs) {
6489+ std::string ret;
6490+ ret.reserve(lhs.size() + rhs.size());
6491+ ret += lhs;
6492+ ret += rhs;
6493+ return ret;
6494+ }
6495+
6496+ auto operator+=( std::string& lhs, StringRef rhs ) -> std::string& {
6497+ lhs.append(rhs.data(), rhs.size());
6498+ return lhs;
6499+ }
6500+
6501+} // namespace Catch
6502+
6503+
6504+
6505+namespace Catch {
6506+
6507+ TagAliasRegistry::~TagAliasRegistry() = default;
6508+
6509+ TagAlias const* TagAliasRegistry::find( std::string const& alias ) const {
6510+ auto it = m_registry.find( alias );
6511+ if( it != m_registry.end() )
6512+ return &(it->second);
6513+ else
6514+ return nullptr;
6515+ }
6516+
6517+ std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const {
6518+ std::string expandedTestSpec = unexpandedTestSpec;
6519+ for( auto const& registryKvp : m_registry ) {
6520+ std::size_t pos = expandedTestSpec.find( registryKvp.first );
6521+ if( pos != std::string::npos ) {
6522+ expandedTestSpec = expandedTestSpec.substr( 0, pos ) +
6523+ registryKvp.second.tag +
6524+ expandedTestSpec.substr( pos + registryKvp.first.size() );
6525+ }
6526+ }
6527+ return expandedTestSpec;
6528+ }
6529+
6530+ void TagAliasRegistry::add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) {
6531+ CATCH_ENFORCE( startsWith(alias, "[@") && endsWith(alias, ']'),
6532+ "error: tag alias, '" << alias << "' is not of the form [@alias name].\n" << lineInfo );
6533+
6534+ CATCH_ENFORCE( m_registry.insert(std::make_pair(alias, TagAlias(tag, lineInfo))).second,
6535+ "error: tag alias, '" << alias << "' already registered.\n"
6536+ << "\tFirst seen at: " << find(alias)->lineInfo << "\n"
6537+ << "\tRedefined at: " << lineInfo );
6538+ }
6539+
6540+ ITagAliasRegistry::~ITagAliasRegistry() = default;
6541+
6542+ ITagAliasRegistry const& ITagAliasRegistry::get() {
6543+ return getRegistryHub().getTagAliasRegistry();
6544+ }
6545+
6546+} // end namespace Catch
6547+
6548+
6549+
6550+
6551+namespace Catch {
6552+ TestCaseInfoHasher::TestCaseInfoHasher( hash_t seed ): m_seed( seed ) {}
6553+
6554+ uint32_t TestCaseInfoHasher::operator()( TestCaseInfo const& t ) const {
6555+ // FNV-1a hash algorithm that is designed for uniqueness:
6556+ const hash_t prime = 1099511628211u;
6557+ hash_t hash = 14695981039346656037u;
6558+ for ( const char c : t.name ) {
6559+ hash ^= c;
6560+ hash *= prime;
6561+ }
6562+ for ( const char c : t.className ) {
6563+ hash ^= c;
6564+ hash *= prime;
6565+ }
6566+ for ( const Tag& tag : t.tags ) {
6567+ for ( const char c : tag.original ) {
6568+ hash ^= c;
6569+ hash *= prime;
6570+ }
6571+ }
6572+ hash ^= m_seed;
6573+ hash *= prime;
6574+ const uint32_t low{ static_cast<uint32_t>( hash ) };
6575+ const uint32_t high{ static_cast<uint32_t>( hash >> 32 ) };
6576+ return low * high;
6577+ }
6578+} // namespace Catch
6579+
6580+
6581+
6582+
6583+#include <algorithm>
6584+#include <set>
6585+
6586+namespace Catch {
6587+
6588+ namespace {
6589+ static void enforceNoDuplicateTestCases(
6590+ std::vector<TestCaseHandle> const& tests ) {
6591+ auto testInfoCmp = []( TestCaseInfo const* lhs,
6592+ TestCaseInfo const* rhs ) {
6593+ return *lhs < *rhs;
6594+ };
6595+ std::set<TestCaseInfo const*, decltype( testInfoCmp )&> seenTests(
6596+ testInfoCmp );
6597+ for ( auto const& test : tests ) {
6598+ const auto infoPtr = &test.getTestCaseInfo();
6599+ const auto prev = seenTests.insert( infoPtr );
6600+ CATCH_ENFORCE( prev.second,
6601+ "error: test case \""
6602+ << infoPtr->name << "\", with tags \""
6603+ << infoPtr->tagsAsString()
6604+ << "\" already defined.\n"
6605+ << "\tFirst seen at "
6606+ << ( *prev.first )->lineInfo << "\n"
6607+ << "\tRedefined at " << infoPtr->lineInfo );
6608+ }
6609+ }
6610+
6611+ static bool matchTest( TestCaseHandle const& testCase,
6612+ TestSpec const& testSpec,
6613+ IConfig const& config ) {
6614+ return testSpec.matches( testCase.getTestCaseInfo() ) &&
6615+ isThrowSafe( testCase, config );
6616+ }
6617+
6618+ } // end unnamed namespace
6619+
6620+ std::vector<TestCaseHandle> sortTests( IConfig const& config, std::vector<TestCaseHandle> const& unsortedTestCases ) {
6621+ switch (config.runOrder()) {
6622+ case TestRunOrder::Declared:
6623+ return unsortedTestCases;
6624+
6625+ case TestRunOrder::LexicographicallySorted: {
6626+ std::vector<TestCaseHandle> sorted = unsortedTestCases;
6627+ std::sort(
6628+ sorted.begin(),
6629+ sorted.end(),
6630+ []( TestCaseHandle const& lhs, TestCaseHandle const& rhs ) {
6631+ return lhs.getTestCaseInfo() < rhs.getTestCaseInfo();
6632+ }
6633+ );
6634+ return sorted;
6635+ }
6636+ case TestRunOrder::Randomized: {
6637+ using TestWithHash = std::pair<TestCaseInfoHasher::hash_t, TestCaseHandle>;
6638+
6639+ TestCaseInfoHasher h{ config.rngSeed() };
6640+ std::vector<TestWithHash> indexed_tests;
6641+ indexed_tests.reserve(unsortedTestCases.size());
6642+
6643+ for (auto const& handle : unsortedTestCases) {
6644+ indexed_tests.emplace_back(h(handle.getTestCaseInfo()), handle);
6645+ }
6646+
6647+ std::sort( indexed_tests.begin(),
6648+ indexed_tests.end(),
6649+ []( TestWithHash const& lhs, TestWithHash const& rhs ) {
6650+ if ( lhs.first == rhs.first ) {
6651+ return lhs.second.getTestCaseInfo() <
6652+ rhs.second.getTestCaseInfo();
6653+ }
6654+ return lhs.first < rhs.first;
6655+ } );
6656+
6657+ std::vector<TestCaseHandle> randomized;
6658+ randomized.reserve(indexed_tests.size());
6659+
6660+ for (auto const& indexed : indexed_tests) {
6661+ randomized.push_back(indexed.second);
6662+ }
6663+
6664+ return randomized;
6665+ }
6666+ }
6667+
6668+ CATCH_INTERNAL_ERROR("Unknown test order value!");
6669+ }
6670+
6671+ bool isThrowSafe( TestCaseHandle const& testCase, IConfig const& config ) {
6672+ return !testCase.getTestCaseInfo().throws() || config.allowThrows();
6673+ }
6674+
6675+ std::vector<TestCaseHandle> filterTests( std::vector<TestCaseHandle> const& testCases, TestSpec const& testSpec, IConfig const& config ) {
6676+ std::vector<TestCaseHandle> filtered;
6677+ filtered.reserve( testCases.size() );
6678+ for (auto const& testCase : testCases) {
6679+ if ((!testSpec.hasFilters() && !testCase.getTestCaseInfo().isHidden()) ||
6680+ (testSpec.hasFilters() && matchTest(testCase, testSpec, config))) {
6681+ filtered.push_back(testCase);
6682+ }
6683+ }
6684+ return createShard(filtered, config.shardCount(), config.shardIndex());
6685+ }
6686+ std::vector<TestCaseHandle> const& getAllTestCasesSorted( IConfig const& config ) {
6687+ return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config );
6688+ }
6689+
6690+ TestRegistry::~TestRegistry() = default;
6691+
6692+ void TestRegistry::registerTest(Detail::unique_ptr<TestCaseInfo> testInfo, Detail::unique_ptr<ITestInvoker> testInvoker) {
6693+ m_handles.emplace_back(testInfo.get(), testInvoker.get());
6694+ m_viewed_test_infos.push_back(testInfo.get());
6695+ m_owned_test_infos.push_back(CATCH_MOVE(testInfo));
6696+ m_invokers.push_back(CATCH_MOVE(testInvoker));
6697+ }
6698+
6699+ std::vector<TestCaseInfo*> const& TestRegistry::getAllInfos() const {
6700+ return m_viewed_test_infos;
6701+ }
6702+
6703+ std::vector<TestCaseHandle> const& TestRegistry::getAllTests() const {
6704+ return m_handles;
6705+ }
6706+ std::vector<TestCaseHandle> const& TestRegistry::getAllTestsSorted( IConfig const& config ) const {
6707+ if( m_sortedFunctions.empty() )
6708+ enforceNoDuplicateTestCases( m_handles );
6709+
6710+ if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) {
6711+ m_sortedFunctions = sortTests( config, m_handles );
6712+ m_currentSortOrder = config.runOrder();
6713+ }
6714+ return m_sortedFunctions;
6715+ }
6716+
6717+} // end namespace Catch
6718+
6719+
6720+
6721+
6722+#include <algorithm>
6723+#include <cassert>
6724+
6725+#if defined(__clang__)
6726+# pragma clang diagnostic push
6727+# pragma clang diagnostic ignored "-Wexit-time-destructors"
6728+#endif
6729+
6730+namespace Catch {
6731+namespace TestCaseTracking {
6732+
6733+ NameAndLocation::NameAndLocation( std::string&& _name, SourceLineInfo const& _location )
6734+ : name( CATCH_MOVE(_name) ),
6735+ location( _location )
6736+ {}
6737+
6738+
6739+ ITracker::~ITracker() = default;
6740+
6741+ void ITracker::markAsNeedingAnotherRun() {
6742+ m_runState = NeedsAnotherRun;
6743+ }
6744+
6745+ void ITracker::addChild( ITrackerPtr&& child ) {
6746+ m_children.push_back( CATCH_MOVE(child) );
6747+ }
6748+
6749+ ITracker* ITracker::findChild( NameAndLocationRef const& nameAndLocation ) {
6750+ auto it = std::find_if(
6751+ m_children.begin(),
6752+ m_children.end(),
6753+ [&nameAndLocation]( ITrackerPtr const& tracker ) {
6754+ auto const& tnameAndLoc = tracker->nameAndLocation();
6755+ if ( tnameAndLoc.location.line !=
6756+ nameAndLocation.location.line ) {
6757+ return false;
6758+ }
6759+ return tnameAndLoc == nameAndLocation;
6760+ } );
6761+ return ( it != m_children.end() ) ? it->get() : nullptr;
6762+ }
6763+
6764+ bool ITracker::isSectionTracker() const { return false; }
6765+ bool ITracker::isGeneratorTracker() const { return false; }
6766+
6767+ bool ITracker::isOpen() const {
6768+ return m_runState != NotStarted && !isComplete();
6769+ }
6770+
6771+ bool ITracker::hasStarted() const { return m_runState != NotStarted; }
6772+
6773+ void ITracker::openChild() {
6774+ if (m_runState != ExecutingChildren) {
6775+ m_runState = ExecutingChildren;
6776+ if (m_parent) {
6777+ m_parent->openChild();
6778+ }
6779+ }
6780+ }
6781+
6782+ ITracker& TrackerContext::startRun() {
6783+ using namespace std::string_literals;
6784+ m_rootTracker = Catch::Detail::make_unique<SectionTracker>(
6785+ NameAndLocation( "{root}"s, CATCH_INTERNAL_LINEINFO ),
6786+ *this,
6787+ nullptr );
6788+ m_currentTracker = nullptr;
6789+ m_runState = Executing;
6790+ return *m_rootTracker;
6791+ }
6792+
6793+ void TrackerContext::completeCycle() {
6794+ m_runState = CompletedCycle;
6795+ }
6796+
6797+ bool TrackerContext::completedCycle() const {
6798+ return m_runState == CompletedCycle;
6799+ }
6800+ void TrackerContext::setCurrentTracker( ITracker* tracker ) {
6801+ m_currentTracker = tracker;
6802+ }
6803+
6804+
6805+ TrackerBase::TrackerBase( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent ):
6806+ ITracker(CATCH_MOVE(nameAndLocation), parent),
6807+ m_ctx( ctx )
6808+ {}
6809+
6810+ bool TrackerBase::isComplete() const {
6811+ return m_runState == CompletedSuccessfully || m_runState == Failed;
6812+ }
6813+
6814+ void TrackerBase::open() {
6815+ m_runState = Executing;
6816+ moveToThis();
6817+ if( m_parent )
6818+ m_parent->openChild();
6819+ }
6820+
6821+ void TrackerBase::close() {
6822+
6823+ // Close any still open children (e.g. generators)
6824+ while( &m_ctx.currentTracker() != this )
6825+ m_ctx.currentTracker().close();
6826+
6827+ switch( m_runState ) {
6828+ case NeedsAnotherRun:
6829+ break;
6830+
6831+ case Executing:
6832+ m_runState = CompletedSuccessfully;
6833+ break;
6834+ case ExecutingChildren:
6835+ if( std::all_of(m_children.begin(), m_children.end(), [](ITrackerPtr const& t){ return t->isComplete(); }) )
6836+ m_runState = CompletedSuccessfully;
6837+ break;
6838+
6839+ case NotStarted:
6840+ case CompletedSuccessfully:
6841+ case Failed:
6842+ CATCH_INTERNAL_ERROR( "Illogical state: " << m_runState );
6843+
6844+ default:
6845+ CATCH_INTERNAL_ERROR( "Unknown state: " << m_runState );
6846+ }
6847+ moveToParent();
6848+ m_ctx.completeCycle();
6849+ }
6850+ void TrackerBase::fail() {
6851+ m_runState = Failed;
6852+ if( m_parent )
6853+ m_parent->markAsNeedingAnotherRun();
6854+ moveToParent();
6855+ m_ctx.completeCycle();
6856+ }
6857+
6858+ void TrackerBase::moveToParent() {
6859+ assert( m_parent );
6860+ m_ctx.setCurrentTracker( m_parent );
6861+ }
6862+ void TrackerBase::moveToThis() {
6863+ m_ctx.setCurrentTracker( this );
6864+ }
6865+
6866+ SectionTracker::SectionTracker( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent )
6867+ : TrackerBase( CATCH_MOVE(nameAndLocation), ctx, parent ),
6868+ m_trimmed_name(trim(StringRef(ITracker::nameAndLocation().name)))
6869+ {
6870+ if( parent ) {
6871+ while ( !parent->isSectionTracker() ) {
6872+ parent = parent->parent();
6873+ }
6874+
6875+ SectionTracker& parentSection = static_cast<SectionTracker&>( *parent );
6876+ addNextFilters( parentSection.m_filters );
6877+ }
6878+ }
6879+
6880+ bool SectionTracker::isComplete() const {
6881+ bool complete = true;
6882+
6883+ if (m_filters.empty()
6884+ || m_filters[0].empty()
6885+ || std::find(m_filters.begin(), m_filters.end(), m_trimmed_name) != m_filters.end()) {
6886+ complete = TrackerBase::isComplete();
6887+ }
6888+ return complete;
6889+ }
6890+
6891+ bool SectionTracker::isSectionTracker() const { return true; }
6892+
6893+ SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocationRef const& nameAndLocation ) {
6894+ SectionTracker* tracker;
6895+
6896+ ITracker& currentTracker = ctx.currentTracker();
6897+ if ( ITracker* childTracker =
6898+ currentTracker.findChild( nameAndLocation ) ) {
6899+ assert( childTracker );
6900+ assert( childTracker->isSectionTracker() );
6901+ tracker = static_cast<SectionTracker*>( childTracker );
6902+ } else {
6903+ auto newTracker = Catch::Detail::make_unique<SectionTracker>(
6904+ NameAndLocation{ static_cast<std::string>(nameAndLocation.name),
6905+ nameAndLocation.location },
6906+ ctx,
6907+ ¤tTracker );
6908+ tracker = newTracker.get();
6909+ currentTracker.addChild( CATCH_MOVE( newTracker ) );
6910+ }
6911+
6912+ if ( !ctx.completedCycle() ) {
6913+ tracker->tryOpen();
6914+ }
6915+
6916+ return *tracker;
6917+ }
6918+
6919+ void SectionTracker::tryOpen() {
6920+ if( !isComplete() )
6921+ open();
6922+ }
6923+
6924+ void SectionTracker::addInitialFilters( std::vector<std::string> const& filters ) {
6925+ if( !filters.empty() ) {
6926+ m_filters.reserve( m_filters.size() + filters.size() + 2 );
6927+ m_filters.emplace_back(StringRef{}); // Root - should never be consulted
6928+ m_filters.emplace_back(StringRef{}); // Test Case - not a section filter
6929+ m_filters.insert( m_filters.end(), filters.begin(), filters.end() );
6930+ }
6931+ }
6932+ void SectionTracker::addNextFilters( std::vector<StringRef> const& filters ) {
6933+ if( filters.size() > 1 )
6934+ m_filters.insert( m_filters.end(), filters.begin()+1, filters.end() );
6935+ }
6936+
6937+ StringRef SectionTracker::trimmedName() const {
6938+ return m_trimmed_name;
6939+ }
6940+
6941+} // namespace TestCaseTracking
6942+
6943+} // namespace Catch
6944+
6945+#if defined(__clang__)
6946+# pragma clang diagnostic pop
6947+#endif
6948+
6949+
6950+
6951+
6952+namespace Catch {
6953+
6954+ void throw_test_failure_exception() {
6955+#if !defined( CATCH_CONFIG_DISABLE_EXCEPTIONS )
6956+ throw TestFailureException{};
6957+#else
6958+ CATCH_ERROR( "Test failure requires aborting test!" );
6959+#endif
6960+ }
6961+
6962+ void throw_test_skip_exception() {
6963+#if !defined( CATCH_CONFIG_DISABLE_EXCEPTIONS )
6964+ throw Catch::TestSkipException();
6965+#else
6966+ CATCH_ERROR( "Explicitly skipping tests during runtime requires exceptions" );
6967+#endif
6968+ }
6969+
6970+} // namespace Catch
6971+
6972+
6973+
6974+#include <algorithm>
6975+#include <iterator>
6976+
6977+namespace Catch {
6978+ ITestInvoker::~ITestInvoker() = default;
6979+
6980+ namespace {
6981+ static StringRef extractClassName( StringRef classOrMethodName ) {
6982+ if ( !startsWith( classOrMethodName, '&' ) ) {
6983+ return classOrMethodName;
6984+ }
6985+
6986+ // Remove the leading '&' to avoid having to special case it later
6987+ const auto methodName =
6988+ classOrMethodName.substr( 1, classOrMethodName.size() );
6989+
6990+ auto reverseStart = std::make_reverse_iterator( methodName.end() );
6991+ auto reverseEnd = std::make_reverse_iterator( methodName.begin() );
6992+
6993+ // We make a simplifying assumption that ":" is only present
6994+ // in the input as part of "::" from C++ typenames (this is
6995+ // relatively safe assumption because the input is generated
6996+ // as stringification of type through preprocessor).
6997+ auto lastColons = std::find( reverseStart, reverseEnd, ':' ) + 1;
6998+ auto secondLastColons =
6999+ std::find( lastColons + 1, reverseEnd, ':' );
7000+
7001+ auto const startIdx = reverseEnd - secondLastColons;
7002+ auto const classNameSize = secondLastColons - lastColons - 1;
7003+
7004+ return methodName.substr(
7005+ static_cast<std::size_t>( startIdx ),
7006+ static_cast<std::size_t>( classNameSize ) );
7007+ }
7008+
7009+ class TestInvokerAsFunction final : public ITestInvoker {
7010+ using TestType = void ( * )();
7011+ TestType m_testAsFunction;
7012+
7013+ public:
7014+ TestInvokerAsFunction( TestType testAsFunction ) noexcept:
7015+ m_testAsFunction( testAsFunction ) {}
7016+
7017+ void invoke() const override { m_testAsFunction(); }
7018+ };
7019+
7020+ } // namespace
7021+
7022+ Detail::unique_ptr<ITestInvoker> makeTestInvoker( void(*testAsFunction)() ) {
7023+ return Detail::make_unique<TestInvokerAsFunction>( testAsFunction );
7024+ }
7025+
7026+ AutoReg::AutoReg( Detail::unique_ptr<ITestInvoker> invoker, SourceLineInfo const& lineInfo, StringRef classOrMethod, NameAndTags const& nameAndTags ) noexcept {
7027+ CATCH_TRY {
7028+ getMutableRegistryHub()
7029+ .registerTest(
7030+ makeTestCaseInfo(
7031+ extractClassName( classOrMethod ),
7032+ nameAndTags,
7033+ lineInfo),
7034+ CATCH_MOVE(invoker)
7035+ );
7036+ } CATCH_CATCH_ALL {
7037+ // Do not throw when constructing global objects, instead register the exception to be processed later
7038+ getMutableRegistryHub().registerStartupException();
7039+ }
7040+ }
7041+}
7042+
7043+
7044+
7045+
7046+
7047+namespace Catch {
7048+
7049+ TestSpecParser::TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {}
7050+
7051+ TestSpecParser& TestSpecParser::parse( std::string const& arg ) {
7052+ m_mode = None;
7053+ m_exclusion = false;
7054+ m_arg = m_tagAliases->expandAliases( arg );
7055+ m_escapeChars.clear();
7056+ m_substring.reserve(m_arg.size());
7057+ m_patternName.reserve(m_arg.size());
7058+ m_realPatternPos = 0;
7059+
7060+ for( m_pos = 0; m_pos < m_arg.size(); ++m_pos )
7061+ //if visitChar fails
7062+ if( !visitChar( m_arg[m_pos] ) ){
7063+ m_testSpec.m_invalidSpecs.push_back(arg);
7064+ break;
7065+ }
7066+ endMode();
7067+ return *this;
7068+ }
7069+ TestSpec TestSpecParser::testSpec() {
7070+ addFilter();
7071+ return CATCH_MOVE(m_testSpec);
7072+ }
7073+ bool TestSpecParser::visitChar( char c ) {
7074+ if( (m_mode != EscapedName) && (c == '\\') ) {
7075+ escape();
7076+ addCharToPattern(c);
7077+ return true;
7078+ }else if((m_mode != EscapedName) && (c == ',') ) {
7079+ return separate();
7080+ }
7081+
7082+ switch( m_mode ) {
7083+ case None:
7084+ if( processNoneChar( c ) )
7085+ return true;
7086+ break;
7087+ case Name:
7088+ processNameChar( c );
7089+ break;
7090+ case EscapedName:
7091+ endMode();
7092+ addCharToPattern(c);
7093+ return true;
7094+ default:
7095+ case Tag:
7096+ case QuotedName:
7097+ if( processOtherChar( c ) )
7098+ return true;
7099+ break;
7100+ }
7101+
7102+ m_substring += c;
7103+ if( !isControlChar( c ) ) {
7104+ m_patternName += c;
7105+ m_realPatternPos++;
7106+ }
7107+ return true;
7108+ }
7109+ // Two of the processing methods return true to signal the caller to return
7110+ // without adding the given character to the current pattern strings
7111+ bool TestSpecParser::processNoneChar( char c ) {
7112+ switch( c ) {
7113+ case ' ':
7114+ return true;
7115+ case '~':
7116+ m_exclusion = true;
7117+ return false;
7118+ case '[':
7119+ startNewMode( Tag );
7120+ return false;
7121+ case '"':
7122+ startNewMode( QuotedName );
7123+ return false;
7124+ default:
7125+ startNewMode( Name );
7126+ return false;
7127+ }
7128+ }
7129+ void TestSpecParser::processNameChar( char c ) {
7130+ if( c == '[' ) {
7131+ if( m_substring == "exclude:" )
7132+ m_exclusion = true;
7133+ else
7134+ endMode();
7135+ startNewMode( Tag );
7136+ }
7137+ }
7138+ bool TestSpecParser::processOtherChar( char c ) {
7139+ if( !isControlChar( c ) )
7140+ return false;
7141+ m_substring += c;
7142+ endMode();
7143+ return true;
7144+ }
7145+ void TestSpecParser::startNewMode( Mode mode ) {
7146+ m_mode = mode;
7147+ }
7148+ void TestSpecParser::endMode() {
7149+ switch( m_mode ) {
7150+ case Name:
7151+ case QuotedName:
7152+ return addNamePattern();
7153+ case Tag:
7154+ return addTagPattern();
7155+ case EscapedName:
7156+ revertBackToLastMode();
7157+ return;
7158+ case None:
7159+ default:
7160+ return startNewMode( None );
7161+ }
7162+ }
7163+ void TestSpecParser::escape() {
7164+ saveLastMode();
7165+ m_mode = EscapedName;
7166+ m_escapeChars.push_back(m_realPatternPos);
7167+ }
7168+ bool TestSpecParser::isControlChar( char c ) const {
7169+ switch( m_mode ) {
7170+ default:
7171+ return false;
7172+ case None:
7173+ return c == '~';
7174+ case Name:
7175+ return c == '[';
7176+ case EscapedName:
7177+ return true;
7178+ case QuotedName:
7179+ return c == '"';
7180+ case Tag:
7181+ return c == '[' || c == ']';
7182+ }
7183+ }
7184+
7185+ void TestSpecParser::addFilter() {
7186+ if( !m_currentFilter.m_required.empty() || !m_currentFilter.m_forbidden.empty() ) {
7187+ m_testSpec.m_filters.push_back( CATCH_MOVE(m_currentFilter) );
7188+ m_currentFilter = TestSpec::Filter();
7189+ }
7190+ }
7191+
7192+ void TestSpecParser::saveLastMode() {
7193+ lastMode = m_mode;
7194+ }
7195+
7196+ void TestSpecParser::revertBackToLastMode() {
7197+ m_mode = lastMode;
7198+ }
7199+
7200+ bool TestSpecParser::separate() {
7201+ if( (m_mode==QuotedName) || (m_mode==Tag) ){
7202+ //invalid argument, signal failure to previous scope.
7203+ m_mode = None;
7204+ m_pos = m_arg.size();
7205+ m_substring.clear();
7206+ m_patternName.clear();
7207+ m_realPatternPos = 0;
7208+ return false;
7209+ }
7210+ endMode();
7211+ addFilter();
7212+ return true; //success
7213+ }
7214+
7215+ std::string TestSpecParser::preprocessPattern() {
7216+ std::string token = m_patternName;
7217+ for (std::size_t i = 0; i < m_escapeChars.size(); ++i)
7218+ token = token.substr(0, m_escapeChars[i] - i) + token.substr(m_escapeChars[i] - i + 1);
7219+ m_escapeChars.clear();
7220+ if (startsWith(token, "exclude:")) {
7221+ m_exclusion = true;
7222+ token = token.substr(8);
7223+ }
7224+
7225+ m_patternName.clear();
7226+ m_realPatternPos = 0;
7227+
7228+ return token;
7229+ }
7230+
7231+ void TestSpecParser::addNamePattern() {
7232+ auto token = preprocessPattern();
7233+
7234+ if (!token.empty()) {
7235+ if (m_exclusion) {
7236+ m_currentFilter.m_forbidden.emplace_back(Detail::make_unique<TestSpec::NamePattern>(token, m_substring));
7237+ } else {
7238+ m_currentFilter.m_required.emplace_back(Detail::make_unique<TestSpec::NamePattern>(token, m_substring));
7239+ }
7240+ }
7241+ m_substring.clear();
7242+ m_exclusion = false;
7243+ m_mode = None;
7244+ }
7245+
7246+ void TestSpecParser::addTagPattern() {
7247+ auto token = preprocessPattern();
7248+
7249+ if (!token.empty()) {
7250+ // If the tag pattern is the "hide and tag" shorthand (e.g. [.foo])
7251+ // we have to create a separate hide tag and shorten the real one
7252+ if (token.size() > 1 && token[0] == '.') {
7253+ token.erase(token.begin());
7254+ if (m_exclusion) {
7255+ m_currentFilter.m_forbidden.emplace_back(Detail::make_unique<TestSpec::TagPattern>(".", m_substring));
7256+ } else {
7257+ m_currentFilter.m_required.emplace_back(Detail::make_unique<TestSpec::TagPattern>(".", m_substring));
7258+ }
7259+ }
7260+ if (m_exclusion) {
7261+ m_currentFilter.m_forbidden.emplace_back(Detail::make_unique<TestSpec::TagPattern>(token, m_substring));
7262+ } else {
7263+ m_currentFilter.m_required.emplace_back(Detail::make_unique<TestSpec::TagPattern>(token, m_substring));
7264+ }
7265+ }
7266+ m_substring.clear();
7267+ m_exclusion = false;
7268+ m_mode = None;
7269+ }
7270+
7271+} // namespace Catch
7272+
7273+
7274+
7275+#include <algorithm>
7276+#include <cstring>
7277+#include <ostream>
7278+
7279+namespace {
7280+ bool isWhitespace( char c ) {
7281+ return c == ' ' || c == '\t' || c == '\n' || c == '\r';
7282+ }
7283+
7284+ bool isBreakableBefore( char c ) {
7285+ static const char chars[] = "[({<|";
7286+ return std::memchr( chars, c, sizeof( chars ) - 1 ) != nullptr;
7287+ }
7288+
7289+ bool isBreakableAfter( char c ) {
7290+ static const char chars[] = "])}>.,:;*+-=&/\\";
7291+ return std::memchr( chars, c, sizeof( chars ) - 1 ) != nullptr;
7292+ }
7293+
7294+ bool isBoundary( std::string const& line, size_t at ) {
7295+ assert( at > 0 );
7296+ assert( at <= line.size() );
7297+
7298+ return at == line.size() ||
7299+ ( isWhitespace( line[at] ) && !isWhitespace( line[at - 1] ) ) ||
7300+ isBreakableBefore( line[at] ) ||
7301+ isBreakableAfter( line[at - 1] );
7302+ }
7303+
7304+} // namespace
7305+
7306+namespace Catch {
7307+ namespace TextFlow {
7308+
7309+ void Column::const_iterator::calcLength() {
7310+ m_addHyphen = false;
7311+ m_parsedTo = m_lineStart;
7312+
7313+ std::string const& current_line = m_column.m_string;
7314+ if ( current_line[m_lineStart] == '\n' ) {
7315+ ++m_parsedTo;
7316+ }
7317+
7318+ const auto maxLineLength = m_column.m_width - indentSize();
7319+ const auto maxParseTo = std::min(current_line.size(), m_lineStart + maxLineLength);
7320+ while ( m_parsedTo < maxParseTo &&
7321+ current_line[m_parsedTo] != '\n' ) {
7322+ ++m_parsedTo;
7323+ }
7324+
7325+ // If we encountered a newline before the column is filled,
7326+ // then we linebreak at the newline and consider this line
7327+ // finished.
7328+ if ( m_parsedTo < m_lineStart + maxLineLength ) {
7329+ m_lineLength = m_parsedTo - m_lineStart;
7330+ } else {
7331+ // Look for a natural linebreak boundary in the column
7332+ // (We look from the end, so that the first found boundary is
7333+ // the right one)
7334+ size_t newLineLength = maxLineLength;
7335+ while ( newLineLength > 0 && !isBoundary( current_line, m_lineStart + newLineLength ) ) {
7336+ --newLineLength;
7337+ }
7338+ while ( newLineLength > 0 &&
7339+ isWhitespace( current_line[m_lineStart + newLineLength - 1] ) ) {
7340+ --newLineLength;
7341+ }
7342+
7343+ // If we found one, then that is where we linebreak
7344+ if ( newLineLength > 0 ) {
7345+ m_lineLength = newLineLength;
7346+ } else {
7347+ // Otherwise we have to split text with a hyphen
7348+ m_addHyphen = true;
7349+ m_lineLength = maxLineLength - 1;
7350+ }
7351+ }
7352+ }
7353+
7354+ size_t Column::const_iterator::indentSize() const {
7355+ auto initial =
7356+ m_lineStart == 0 ? m_column.m_initialIndent : std::string::npos;
7357+ return initial == std::string::npos ? m_column.m_indent : initial;
7358+ }
7359+
7360+ std::string
7361+ Column::const_iterator::addIndentAndSuffix( size_t position,
7362+ size_t length ) const {
7363+ std::string ret;
7364+ const auto desired_indent = indentSize();
7365+ ret.reserve( desired_indent + length + m_addHyphen );
7366+ ret.append( desired_indent, ' ' );
7367+ ret.append( m_column.m_string, position, length );
7368+ if ( m_addHyphen ) {
7369+ ret.push_back( '-' );
7370+ }
7371+
7372+ return ret;
7373+ }
7374+
7375+ Column::const_iterator::const_iterator( Column const& column ): m_column( column ) {
7376+ assert( m_column.m_width > m_column.m_indent );
7377+ assert( m_column.m_initialIndent == std::string::npos ||
7378+ m_column.m_width > m_column.m_initialIndent );
7379+ calcLength();
7380+ if ( m_lineLength == 0 ) {
7381+ m_lineStart = m_column.m_string.size();
7382+ }
7383+ }
7384+
7385+ std::string Column::const_iterator::operator*() const {
7386+ assert( m_lineStart <= m_parsedTo );
7387+ return addIndentAndSuffix( m_lineStart, m_lineLength );
7388+ }
7389+
7390+ Column::const_iterator& Column::const_iterator::operator++() {
7391+ m_lineStart += m_lineLength;
7392+ std::string const& current_line = m_column.m_string;
7393+ if ( m_lineStart < current_line.size() && current_line[m_lineStart] == '\n' ) {
7394+ m_lineStart += 1;
7395+ } else {
7396+ while ( m_lineStart < current_line.size() &&
7397+ isWhitespace( current_line[m_lineStart] ) ) {
7398+ ++m_lineStart;
7399+ }
7400+ }
7401+
7402+ if ( m_lineStart != current_line.size() ) {
7403+ calcLength();
7404+ }
7405+ return *this;
7406+ }
7407+
7408+ Column::const_iterator Column::const_iterator::operator++( int ) {
7409+ const_iterator prev( *this );
7410+ operator++();
7411+ return prev;
7412+ }
7413+
7414+ std::ostream& operator<<( std::ostream& os, Column const& col ) {
7415+ bool first = true;
7416+ for ( auto line : col ) {
7417+ if ( first ) {
7418+ first = false;
7419+ } else {
7420+ os << '\n';
7421+ }
7422+ os << line;
7423+ }
7424+ return os;
7425+ }
7426+
7427+ Column Spacer( size_t spaceWidth ) {
7428+ Column ret{ "" };
7429+ ret.width( spaceWidth );
7430+ return ret;
7431+ }
7432+
7433+ Columns::iterator::iterator( Columns const& columns, EndTag ):
7434+ m_columns( columns.m_columns ), m_activeIterators( 0 ) {
7435+
7436+ m_iterators.reserve( m_columns.size() );
7437+ for ( auto const& col : m_columns ) {
7438+ m_iterators.push_back( col.end() );
7439+ }
7440+ }
7441+
7442+ Columns::iterator::iterator( Columns const& columns ):
7443+ m_columns( columns.m_columns ),
7444+ m_activeIterators( m_columns.size() ) {
7445+
7446+ m_iterators.reserve( m_columns.size() );
7447+ for ( auto const& col : m_columns ) {
7448+ m_iterators.push_back( col.begin() );
7449+ }
7450+ }
7451+
7452+ std::string Columns::iterator::operator*() const {
7453+ std::string row, padding;
7454+
7455+ for ( size_t i = 0; i < m_columns.size(); ++i ) {
7456+ const auto width = m_columns[i].width();
7457+ if ( m_iterators[i] != m_columns[i].end() ) {
7458+ std::string col = *m_iterators[i];
7459+ row += padding;
7460+ row += col;
7461+
7462+ padding.clear();
7463+ if ( col.size() < width ) {
7464+ padding.append( width - col.size(), ' ' );
7465+ }
7466+ } else {
7467+ padding.append( width, ' ' );
7468+ }
7469+ }
7470+ return row;
7471+ }
7472+
7473+ Columns::iterator& Columns::iterator::operator++() {
7474+ for ( size_t i = 0; i < m_columns.size(); ++i ) {
7475+ if ( m_iterators[i] != m_columns[i].end() ) {
7476+ ++m_iterators[i];
7477+ }
7478+ }
7479+ return *this;
7480+ }
7481+
7482+ Columns::iterator Columns::iterator::operator++( int ) {
7483+ iterator prev( *this );
7484+ operator++();
7485+ return prev;
7486+ }
7487+
7488+ std::ostream& operator<<( std::ostream& os, Columns const& cols ) {
7489+ bool first = true;
7490+ for ( auto line : cols ) {
7491+ if ( first ) {
7492+ first = false;
7493+ } else {
7494+ os << '\n';
7495+ }
7496+ os << line;
7497+ }
7498+ return os;
7499+ }
7500+
7501+ Columns operator+(Column const& lhs, Column const& rhs) {
7502+ Columns cols;
7503+ cols += lhs;
7504+ cols += rhs;
7505+ return cols;
7506+ }
7507+ Columns operator+(Column&& lhs, Column&& rhs) {
7508+ Columns cols;
7509+ cols += CATCH_MOVE( lhs );
7510+ cols += CATCH_MOVE( rhs );
7511+ return cols;
7512+ }
7513+
7514+ Columns& operator+=(Columns& lhs, Column const& rhs) {
7515+ lhs.m_columns.push_back( rhs );
7516+ return lhs;
7517+ }
7518+ Columns& operator+=(Columns& lhs, Column&& rhs) {
7519+ lhs.m_columns.push_back( CATCH_MOVE(rhs) );
7520+ return lhs;
7521+ }
7522+ Columns operator+( Columns const& lhs, Column const& rhs ) {
7523+ auto combined( lhs );
7524+ combined += rhs;
7525+ return combined;
7526+ }
7527+ Columns operator+( Columns&& lhs, Column&& rhs ) {
7528+ lhs += CATCH_MOVE( rhs );
7529+ return CATCH_MOVE( lhs );
7530+ }
7531+
7532+ } // namespace TextFlow
7533+} // namespace Catch
7534+
7535+
7536+
7537+
7538+#include <exception>
7539+
7540+namespace Catch {
7541+ bool uncaught_exceptions() {
7542+#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
7543+ return false;
7544+#elif defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
7545+ return std::uncaught_exceptions() > 0;
7546+#else
7547+ return std::uncaught_exception();
7548+#endif
7549+ }
7550+} // end namespace Catch
7551+
7552+
7553+
7554+namespace Catch {
7555+
7556+ WildcardPattern::WildcardPattern( std::string const& pattern,
7557+ CaseSensitive caseSensitivity )
7558+ : m_caseSensitivity( caseSensitivity ),
7559+ m_pattern( normaliseString( pattern ) )
7560+ {
7561+ if( startsWith( m_pattern, '*' ) ) {
7562+ m_pattern = m_pattern.substr( 1 );
7563+ m_wildcard = WildcardAtStart;
7564+ }
7565+ if( endsWith( m_pattern, '*' ) ) {
7566+ m_pattern = m_pattern.substr( 0, m_pattern.size()-1 );
7567+ m_wildcard = static_cast<WildcardPosition>( m_wildcard | WildcardAtEnd );
7568+ }
7569+ }
7570+
7571+ bool WildcardPattern::matches( std::string const& str ) const {
7572+ switch( m_wildcard ) {
7573+ case NoWildcard:
7574+ return m_pattern == normaliseString( str );
7575+ case WildcardAtStart:
7576+ return endsWith( normaliseString( str ), m_pattern );
7577+ case WildcardAtEnd:
7578+ return startsWith( normaliseString( str ), m_pattern );
7579+ case WildcardAtBothEnds:
7580+ return contains( normaliseString( str ), m_pattern );
7581+ default:
7582+ CATCH_INTERNAL_ERROR( "Unknown enum" );
7583+ }
7584+ }
7585+
7586+ std::string WildcardPattern::normaliseString( std::string const& str ) const {
7587+ return trim( m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str );
7588+ }
7589+}
7590+
7591+
7592+// Note: swapping these two includes around causes MSVC to error out
7593+// while in /permissive- mode. No, I don't know why.
7594+// Tested on VS 2019, 18.{3, 4}.x
7595+
7596+#include <cstdint>
7597+#include <iomanip>
7598+#include <type_traits>
7599+
7600+namespace Catch {
7601+
7602+namespace {
7603+
7604+ size_t trailingBytes(unsigned char c) {
7605+ if ((c & 0xE0) == 0xC0) {
7606+ return 2;
7607+ }
7608+ if ((c & 0xF0) == 0xE0) {
7609+ return 3;
7610+ }
7611+ if ((c & 0xF8) == 0xF0) {
7612+ return 4;
7613+ }
7614+ CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered");
7615+ }
7616+
7617+ uint32_t headerValue(unsigned char c) {
7618+ if ((c & 0xE0) == 0xC0) {
7619+ return c & 0x1F;
7620+ }
7621+ if ((c & 0xF0) == 0xE0) {
7622+ return c & 0x0F;
7623+ }
7624+ if ((c & 0xF8) == 0xF0) {
7625+ return c & 0x07;
7626+ }
7627+ CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered");
7628+ }
7629+
7630+ void hexEscapeChar(std::ostream& os, unsigned char c) {
7631+ std::ios_base::fmtflags f(os.flags());
7632+ os << "\\x"
7633+ << std::uppercase << std::hex << std::setfill('0') << std::setw(2)
7634+ << static_cast<int>(c);
7635+ os.flags(f);
7636+ }
7637+
7638+ bool shouldNewline(XmlFormatting fmt) {
7639+ return !!(static_cast<std::underlying_type_t<XmlFormatting>>(fmt & XmlFormatting::Newline));
7640+ }
7641+
7642+ bool shouldIndent(XmlFormatting fmt) {
7643+ return !!(static_cast<std::underlying_type_t<XmlFormatting>>(fmt & XmlFormatting::Indent));
7644+ }
7645+
7646+} // anonymous namespace
7647+
7648+ XmlFormatting operator | (XmlFormatting lhs, XmlFormatting rhs) {
7649+ return static_cast<XmlFormatting>(
7650+ static_cast<std::underlying_type_t<XmlFormatting>>(lhs) |
7651+ static_cast<std::underlying_type_t<XmlFormatting>>(rhs)
7652+ );
7653+ }
7654+
7655+ XmlFormatting operator & (XmlFormatting lhs, XmlFormatting rhs) {
7656+ return static_cast<XmlFormatting>(
7657+ static_cast<std::underlying_type_t<XmlFormatting>>(lhs) &
7658+ static_cast<std::underlying_type_t<XmlFormatting>>(rhs)
7659+ );
7660+ }
7661+
7662+
7663+ XmlEncode::XmlEncode( StringRef str, ForWhat forWhat )
7664+ : m_str( str ),
7665+ m_forWhat( forWhat )
7666+ {}
7667+
7668+ void XmlEncode::encodeTo( std::ostream& os ) const {
7669+ // Apostrophe escaping not necessary if we always use " to write attributes
7670+ // (see: http://www.w3.org/TR/xml/#syntax)
7671+
7672+ for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) {
7673+ unsigned char c = static_cast<unsigned char>(m_str[idx]);
7674+ switch (c) {
7675+ case '<': os << "<"; break;
7676+ case '&': os << "&"; break;
7677+
7678+ case '>':
7679+ // See: http://www.w3.org/TR/xml/#syntax
7680+ if (idx > 2 && m_str[idx - 1] == ']' && m_str[idx - 2] == ']')
7681+ os << ">";
7682+ else
7683+ os << c;
7684+ break;
7685+
7686+ case '\"':
7687+ if (m_forWhat == ForAttributes)
7688+ os << """;
7689+ else
7690+ os << c;
7691+ break;
7692+
7693+ default:
7694+ // Check for control characters and invalid utf-8
7695+
7696+ // Escape control characters in standard ascii
7697+ // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0
7698+ if (c < 0x09 || (c > 0x0D && c < 0x20) || c == 0x7F) {
7699+ hexEscapeChar(os, c);
7700+ break;
7701+ }
7702+
7703+ // Plain ASCII: Write it to stream
7704+ if (c < 0x7F) {
7705+ os << c;
7706+ break;
7707+ }
7708+
7709+ // UTF-8 territory
7710+ // Check if the encoding is valid and if it is not, hex escape bytes.
7711+ // Important: We do not check the exact decoded values for validity, only the encoding format
7712+ // First check that this bytes is a valid lead byte:
7713+ // This means that it is not encoded as 1111 1XXX
7714+ // Or as 10XX XXXX
7715+ if (c < 0xC0 ||
7716+ c >= 0xF8) {
7717+ hexEscapeChar(os, c);
7718+ break;
7719+ }
7720+
7721+ auto encBytes = trailingBytes(c);
7722+ // Are there enough bytes left to avoid accessing out-of-bounds memory?
7723+ if (idx + encBytes - 1 >= m_str.size()) {
7724+ hexEscapeChar(os, c);
7725+ break;
7726+ }
7727+ // The header is valid, check data
7728+ // The next encBytes bytes must together be a valid utf-8
7729+ // This means: bitpattern 10XX XXXX and the extracted value is sane (ish)
7730+ bool valid = true;
7731+ uint32_t value = headerValue(c);
7732+ for (std::size_t n = 1; n < encBytes; ++n) {
7733+ unsigned char nc = static_cast<unsigned char>(m_str[idx + n]);
7734+ valid &= ((nc & 0xC0) == 0x80);
7735+ value = (value << 6) | (nc & 0x3F);
7736+ }
7737+
7738+ if (
7739+ // Wrong bit pattern of following bytes
7740+ (!valid) ||
7741+ // Overlong encodings
7742+ (value < 0x80) ||
7743+ (0x80 <= value && value < 0x800 && encBytes > 2) ||
7744+ (0x800 < value && value < 0x10000 && encBytes > 3) ||
7745+ // Encoded value out of range
7746+ (value >= 0x110000)
7747+ ) {
7748+ hexEscapeChar(os, c);
7749+ break;
7750+ }
7751+
7752+ // If we got here, this is in fact a valid(ish) utf-8 sequence
7753+ for (std::size_t n = 0; n < encBytes; ++n) {
7754+ os << m_str[idx + n];
7755+ }
7756+ idx += encBytes - 1;
7757+ break;
7758+ }
7759+ }
7760+ }
7761+
7762+ std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) {
7763+ xmlEncode.encodeTo( os );
7764+ return os;
7765+ }
7766+
7767+ XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer, XmlFormatting fmt )
7768+ : m_writer( writer ),
7769+ m_fmt(fmt)
7770+ {}
7771+
7772+ XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) noexcept
7773+ : m_writer( other.m_writer ),
7774+ m_fmt(other.m_fmt)
7775+ {
7776+ other.m_writer = nullptr;
7777+ other.m_fmt = XmlFormatting::None;
7778+ }
7779+ XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) noexcept {
7780+ if ( m_writer ) {
7781+ m_writer->endElement();
7782+ }
7783+ m_writer = other.m_writer;
7784+ other.m_writer = nullptr;
7785+ m_fmt = other.m_fmt;
7786+ other.m_fmt = XmlFormatting::None;
7787+ return *this;
7788+ }
7789+
7790+
7791+ XmlWriter::ScopedElement::~ScopedElement() {
7792+ if (m_writer) {
7793+ m_writer->endElement(m_fmt);
7794+ }
7795+ }
7796+
7797+ XmlWriter::ScopedElement&
7798+ XmlWriter::ScopedElement::writeText( StringRef text, XmlFormatting fmt ) {
7799+ m_writer->writeText( text, fmt );
7800+ return *this;
7801+ }
7802+
7803+ XmlWriter::ScopedElement&
7804+ XmlWriter::ScopedElement::writeAttribute( StringRef name,
7805+ StringRef attribute ) {
7806+ m_writer->writeAttribute( name, attribute );
7807+ return *this;
7808+ }
7809+
7810+
7811+ XmlWriter::XmlWriter( std::ostream& os ) : m_os( os )
7812+ {
7813+ writeDeclaration();
7814+ }
7815+
7816+ XmlWriter::~XmlWriter() {
7817+ while (!m_tags.empty()) {
7818+ endElement();
7819+ }
7820+ newlineIfNecessary();
7821+ }
7822+
7823+ XmlWriter& XmlWriter::startElement( std::string const& name, XmlFormatting fmt ) {
7824+ ensureTagClosed();
7825+ newlineIfNecessary();
7826+ if (shouldIndent(fmt)) {
7827+ m_os << m_indent;
7828+ m_indent += " ";
7829+ }
7830+ m_os << '<' << name;
7831+ m_tags.push_back( name );
7832+ m_tagIsOpen = true;
7833+ applyFormatting(fmt);
7834+ return *this;
7835+ }
7836+
7837+ XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name, XmlFormatting fmt ) {
7838+ ScopedElement scoped( this, fmt );
7839+ startElement( name, fmt );
7840+ return scoped;
7841+ }
7842+
7843+ XmlWriter& XmlWriter::endElement(XmlFormatting fmt) {
7844+ m_indent = m_indent.substr(0, m_indent.size() - 2);
7845+
7846+ if( m_tagIsOpen ) {
7847+ m_os << "/>";
7848+ m_tagIsOpen = false;
7849+ } else {
7850+ newlineIfNecessary();
7851+ if (shouldIndent(fmt)) {
7852+ m_os << m_indent;
7853+ }
7854+ m_os << "</" << m_tags.back() << '>';
7855+ }
7856+ m_os << std::flush;
7857+ applyFormatting(fmt);
7858+ m_tags.pop_back();
7859+ return *this;
7860+ }
7861+
7862+ XmlWriter& XmlWriter::writeAttribute( StringRef name,
7863+ StringRef attribute ) {
7864+ if( !name.empty() && !attribute.empty() )
7865+ m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"';
7866+ return *this;
7867+ }
7868+
7869+ XmlWriter& XmlWriter::writeAttribute( StringRef name, bool attribute ) {
7870+ writeAttribute(name, (attribute ? "true"_sr : "false"_sr));
7871+ return *this;
7872+ }
7873+
7874+ XmlWriter& XmlWriter::writeAttribute( StringRef name,
7875+ char const* attribute ) {
7876+ writeAttribute( name, StringRef( attribute ) );
7877+ return *this;
7878+ }
7879+
7880+ XmlWriter& XmlWriter::writeText( StringRef text, XmlFormatting fmt ) {
7881+ CATCH_ENFORCE(!m_tags.empty(), "Cannot write text as top level element");
7882+ if( !text.empty() ){
7883+ bool tagWasOpen = m_tagIsOpen;
7884+ ensureTagClosed();
7885+ if (tagWasOpen && shouldIndent(fmt)) {
7886+ m_os << m_indent;
7887+ }
7888+ m_os << XmlEncode( text, XmlEncode::ForTextNodes );
7889+ applyFormatting(fmt);
7890+ }
7891+ return *this;
7892+ }
7893+
7894+ XmlWriter& XmlWriter::writeComment( StringRef text, XmlFormatting fmt ) {
7895+ ensureTagClosed();
7896+ if (shouldIndent(fmt)) {
7897+ m_os << m_indent;
7898+ }
7899+ m_os << "<!-- " << text << " -->";
7900+ applyFormatting(fmt);
7901+ return *this;
7902+ }
7903+
7904+ void XmlWriter::writeStylesheetRef( StringRef url ) {
7905+ m_os << R"(<?xml-stylesheet type="text/xsl" href=")" << url << R"("?>)" << '\n';
7906+ }
7907+
7908+ void XmlWriter::ensureTagClosed() {
7909+ if( m_tagIsOpen ) {
7910+ m_os << '>' << std::flush;
7911+ newlineIfNecessary();
7912+ m_tagIsOpen = false;
7913+ }
7914+ }
7915+
7916+ void XmlWriter::applyFormatting(XmlFormatting fmt) {
7917+ m_needsNewline = shouldNewline(fmt);
7918+ }
7919+
7920+ void XmlWriter::writeDeclaration() {
7921+ m_os << R"(<?xml version="1.0" encoding="UTF-8"?>)" << '\n';
7922+ }
7923+
7924+ void XmlWriter::newlineIfNecessary() {
7925+ if( m_needsNewline ) {
7926+ m_os << '\n' << std::flush;
7927+ m_needsNewline = false;
7928+ }
7929+ }
7930+}
7931+
7932+
7933+
7934+
7935+
7936+namespace Catch {
7937+namespace Matchers {
7938+
7939+ std::string MatcherUntypedBase::toString() const {
7940+ if (m_cachedToString.empty()) {
7941+ m_cachedToString = describe();
7942+ }
7943+ return m_cachedToString;
7944+ }
7945+
7946+ MatcherUntypedBase::~MatcherUntypedBase() = default;
7947+
7948+} // namespace Matchers
7949+} // namespace Catch
7950+
7951+
7952+
7953+
7954+namespace Catch {
7955+namespace Matchers {
7956+
7957+ std::string IsEmptyMatcher::describe() const {
7958+ return "is empty";
7959+ }
7960+
7961+ std::string HasSizeMatcher::describe() const {
7962+ ReusableStringStream sstr;
7963+ sstr << "has size == " << m_target_size;
7964+ return sstr.str();
7965+ }
7966+
7967+ IsEmptyMatcher IsEmpty() {
7968+ return {};
7969+ }
7970+
7971+ HasSizeMatcher SizeIs(std::size_t sz) {
7972+ return HasSizeMatcher{ sz };
7973+ }
7974+
7975+} // end namespace Matchers
7976+} // end namespace Catch
7977+
7978+
7979+
7980+namespace Catch {
7981+namespace Matchers {
7982+
7983+bool ExceptionMessageMatcher::match(std::exception const& ex) const {
7984+ return ex.what() == m_message;
7985+}
7986+
7987+std::string ExceptionMessageMatcher::describe() const {
7988+ return "exception message matches \"" + m_message + '"';
7989+}
7990+
7991+ExceptionMessageMatcher Message(std::string const& message) {
7992+ return ExceptionMessageMatcher(message);
7993+}
7994+
7995+} // namespace Matchers
7996+} // namespace Catch
7997+
7998+
7999+
8000+#include <algorithm>
8001+#include <cmath>
8002+#include <cstdlib>
8003+#include <cstdint>
8004+#include <sstream>
8005+#include <iomanip>
8006+#include <limits>
8007+
8008+
8009+namespace Catch {
8010+namespace {
8011+
8012+ template <typename FP>
8013+ bool almostEqualUlps(FP lhs, FP rhs, uint64_t maxUlpDiff) {
8014+ // Comparison with NaN should always be false.
8015+ // This way we can rule it out before getting into the ugly details
8016+ if (Catch::isnan(lhs) || Catch::isnan(rhs)) {
8017+ return false;
8018+ }
8019+
8020+ // This should also handle positive and negative zeros, infinities
8021+ const auto ulpDist = ulpDistance(lhs, rhs);
8022+
8023+ return ulpDist <= maxUlpDiff;
8024+ }
8025+
8026+
8027+template <typename FP>
8028+FP step(FP start, FP direction, uint64_t steps) {
8029+ for (uint64_t i = 0; i < steps; ++i) {
8030+ start = Catch::nextafter(start, direction);
8031+ }
8032+ return start;
8033+}
8034+
8035+// Performs equivalent check of std::fabs(lhs - rhs) <= margin
8036+// But without the subtraction to allow for INFINITY in comparison
8037+bool marginComparison(double lhs, double rhs, double margin) {
8038+ return (lhs + margin >= rhs) && (rhs + margin >= lhs);
8039+}
8040+
8041+template <typename FloatingPoint>
8042+void write(std::ostream& out, FloatingPoint num) {
8043+ out << std::scientific
8044+ << std::setprecision(std::numeric_limits<FloatingPoint>::max_digits10 - 1)
8045+ << num;
8046+}
8047+
8048+} // end anonymous namespace
8049+
8050+namespace Matchers {
8051+namespace Detail {
8052+
8053+ enum class FloatingPointKind : uint8_t {
8054+ Float,
8055+ Double
8056+ };
8057+
8058+} // end namespace Detail
8059+
8060+
8061+ WithinAbsMatcher::WithinAbsMatcher(double target, double margin)
8062+ :m_target{ target }, m_margin{ margin } {
8063+ CATCH_ENFORCE(margin >= 0, "Invalid margin: " << margin << '.'
8064+ << " Margin has to be non-negative.");
8065+ }
8066+
8067+ // Performs equivalent check of std::fabs(lhs - rhs) <= margin
8068+ // But without the subtraction to allow for INFINITY in comparison
8069+ bool WithinAbsMatcher::match(double const& matchee) const {
8070+ return (matchee + m_margin >= m_target) && (m_target + m_margin >= matchee);
8071+ }
8072+
8073+ std::string WithinAbsMatcher::describe() const {
8074+ return "is within " + ::Catch::Detail::stringify(m_margin) + " of " + ::Catch::Detail::stringify(m_target);
8075+ }
8076+
8077+
8078+ WithinUlpsMatcher::WithinUlpsMatcher(double target, uint64_t ulps, Detail::FloatingPointKind baseType)
8079+ :m_target{ target }, m_ulps{ ulps }, m_type{ baseType } {
8080+ CATCH_ENFORCE(m_type == Detail::FloatingPointKind::Double
8081+ || m_ulps < (std::numeric_limits<uint32_t>::max)(),
8082+ "Provided ULP is impossibly large for a float comparison.");
8083+ CATCH_ENFORCE( std::numeric_limits<double>::is_iec559,
8084+ "WithinUlp matcher only supports platforms with "
8085+ "IEEE-754 compatible floating point representation" );
8086+ }
8087+
8088+#if defined(__clang__)
8089+#pragma clang diagnostic push
8090+// Clang <3.5 reports on the default branch in the switch below
8091+#pragma clang diagnostic ignored "-Wunreachable-code"
8092+#endif
8093+
8094+ bool WithinUlpsMatcher::match(double const& matchee) const {
8095+ switch (m_type) {
8096+ case Detail::FloatingPointKind::Float:
8097+ return almostEqualUlps<float>(static_cast<float>(matchee), static_cast<float>(m_target), m_ulps);
8098+ case Detail::FloatingPointKind::Double:
8099+ return almostEqualUlps<double>(matchee, m_target, m_ulps);
8100+ default:
8101+ CATCH_INTERNAL_ERROR( "Unknown Detail::FloatingPointKind value" );
8102+ }
8103+ }
8104+
8105+#if defined(__clang__)
8106+#pragma clang diagnostic pop
8107+#endif
8108+
8109+ std::string WithinUlpsMatcher::describe() const {
8110+ std::stringstream ret;
8111+
8112+ ret << "is within " << m_ulps << " ULPs of ";
8113+
8114+ if (m_type == Detail::FloatingPointKind::Float) {
8115+ write(ret, static_cast<float>(m_target));
8116+ ret << 'f';
8117+ } else {
8118+ write(ret, m_target);
8119+ }
8120+
8121+ ret << " ([";
8122+ if (m_type == Detail::FloatingPointKind::Double) {
8123+ write( ret,
8124+ step( m_target,
8125+ -std::numeric_limits<double>::infinity(),
8126+ m_ulps ) );
8127+ ret << ", ";
8128+ write( ret,
8129+ step( m_target,
8130+ std::numeric_limits<double>::infinity(),
8131+ m_ulps ) );
8132+ } else {
8133+ // We have to cast INFINITY to float because of MinGW, see #1782
8134+ write( ret,
8135+ step( static_cast<float>( m_target ),
8136+ -std::numeric_limits<float>::infinity(),
8137+ m_ulps ) );
8138+ ret << ", ";
8139+ write( ret,
8140+ step( static_cast<float>( m_target ),
8141+ std::numeric_limits<float>::infinity(),
8142+ m_ulps ) );
8143+ }
8144+ ret << "])";
8145+
8146+ return ret.str();
8147+ }
8148+
8149+ WithinRelMatcher::WithinRelMatcher(double target, double epsilon):
8150+ m_target(target),
8151+ m_epsilon(epsilon){
8152+ CATCH_ENFORCE(m_epsilon >= 0., "Relative comparison with epsilon < 0 does not make sense.");
8153+ CATCH_ENFORCE(m_epsilon < 1., "Relative comparison with epsilon >= 1 does not make sense.");
8154+ }
8155+
8156+ bool WithinRelMatcher::match(double const& matchee) const {
8157+ const auto relMargin = m_epsilon * (std::max)(std::fabs(matchee), std::fabs(m_target));
8158+ return marginComparison(matchee, m_target,
8159+ std::isinf(relMargin)? 0 : relMargin);
8160+ }
8161+
8162+ std::string WithinRelMatcher::describe() const {
8163+ Catch::ReusableStringStream sstr;
8164+ sstr << "and " << m_target << " are within " << m_epsilon * 100. << "% of each other";
8165+ return sstr.str();
8166+ }
8167+
8168+
8169+WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff) {
8170+ return WithinUlpsMatcher(target, maxUlpDiff, Detail::FloatingPointKind::Double);
8171+}
8172+
8173+WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff) {
8174+ return WithinUlpsMatcher(target, maxUlpDiff, Detail::FloatingPointKind::Float);
8175+}
8176+
8177+WithinAbsMatcher WithinAbs(double target, double margin) {
8178+ return WithinAbsMatcher(target, margin);
8179+}
8180+
8181+WithinRelMatcher WithinRel(double target, double eps) {
8182+ return WithinRelMatcher(target, eps);
8183+}
8184+
8185+WithinRelMatcher WithinRel(double target) {
8186+ return WithinRelMatcher(target, std::numeric_limits<double>::epsilon() * 100);
8187+}
8188+
8189+WithinRelMatcher WithinRel(float target, float eps) {
8190+ return WithinRelMatcher(target, eps);
8191+}
8192+
8193+WithinRelMatcher WithinRel(float target) {
8194+ return WithinRelMatcher(target, std::numeric_limits<float>::epsilon() * 100);
8195+}
8196+
8197+
8198+
8199+bool IsNaNMatcher::match( double const& matchee ) const {
8200+ return std::isnan( matchee );
8201+}
8202+
8203+std::string IsNaNMatcher::describe() const {
8204+ using namespace std::string_literals;
8205+ return "is NaN"s;
8206+}
8207+
8208+IsNaNMatcher IsNaN() { return IsNaNMatcher(); }
8209+
8210+ } // namespace Matchers
8211+} // namespace Catch
8212+
8213+
8214+
8215+
8216+std::string Catch::Matchers::Detail::finalizeDescription(const std::string& desc) {
8217+ if (desc.empty()) {
8218+ return "matches undescribed predicate";
8219+ } else {
8220+ return "matches predicate: \"" + desc + '"';
8221+ }
8222+}
8223+
8224+
8225+
8226+namespace Catch {
8227+ namespace Matchers {
8228+ std::string AllTrueMatcher::describe() const { return "contains only true"; }
8229+
8230+ AllTrueMatcher AllTrue() { return AllTrueMatcher{}; }
8231+
8232+ std::string NoneTrueMatcher::describe() const { return "contains no true"; }
8233+
8234+ NoneTrueMatcher NoneTrue() { return NoneTrueMatcher{}; }
8235+
8236+ std::string AnyTrueMatcher::describe() const { return "contains at least one true"; }
8237+
8238+ AnyTrueMatcher AnyTrue() { return AnyTrueMatcher{}; }
8239+ } // namespace Matchers
8240+} // namespace Catch
8241+
8242+
8243+
8244+#include <regex>
8245+
8246+namespace Catch {
8247+namespace Matchers {
8248+
8249+ CasedString::CasedString( std::string const& str, CaseSensitive caseSensitivity )
8250+ : m_caseSensitivity( caseSensitivity ),
8251+ m_str( adjustString( str ) )
8252+ {}
8253+ std::string CasedString::adjustString( std::string const& str ) const {
8254+ return m_caseSensitivity == CaseSensitive::No
8255+ ? toLower( str )
8256+ : str;
8257+ }
8258+ StringRef CasedString::caseSensitivitySuffix() const {
8259+ return m_caseSensitivity == CaseSensitive::Yes
8260+ ? StringRef()
8261+ : " (case insensitive)"_sr;
8262+ }
8263+
8264+
8265+ StringMatcherBase::StringMatcherBase( StringRef operation, CasedString const& comparator )
8266+ : m_comparator( comparator ),
8267+ m_operation( operation ) {
8268+ }
8269+
8270+ std::string StringMatcherBase::describe() const {
8271+ std::string description;
8272+ description.reserve(5 + m_operation.size() + m_comparator.m_str.size() +
8273+ m_comparator.caseSensitivitySuffix().size());
8274+ description += m_operation;
8275+ description += ": \"";
8276+ description += m_comparator.m_str;
8277+ description += '"';
8278+ description += m_comparator.caseSensitivitySuffix();
8279+ return description;
8280+ }
8281+
8282+ StringEqualsMatcher::StringEqualsMatcher( CasedString const& comparator ) : StringMatcherBase( "equals"_sr, comparator ) {}
8283+
8284+ bool StringEqualsMatcher::match( std::string const& source ) const {
8285+ return m_comparator.adjustString( source ) == m_comparator.m_str;
8286+ }
8287+
8288+
8289+ StringContainsMatcher::StringContainsMatcher( CasedString const& comparator ) : StringMatcherBase( "contains"_sr, comparator ) {}
8290+
8291+ bool StringContainsMatcher::match( std::string const& source ) const {
8292+ return contains( m_comparator.adjustString( source ), m_comparator.m_str );
8293+ }
8294+
8295+
8296+ StartsWithMatcher::StartsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "starts with"_sr, comparator ) {}
8297+
8298+ bool StartsWithMatcher::match( std::string const& source ) const {
8299+ return startsWith( m_comparator.adjustString( source ), m_comparator.m_str );
8300+ }
8301+
8302+
8303+ EndsWithMatcher::EndsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "ends with"_sr, comparator ) {}
8304+
8305+ bool EndsWithMatcher::match( std::string const& source ) const {
8306+ return endsWith( m_comparator.adjustString( source ), m_comparator.m_str );
8307+ }
8308+
8309+
8310+
8311+ RegexMatcher::RegexMatcher(std::string regex, CaseSensitive caseSensitivity): m_regex(CATCH_MOVE(regex)), m_caseSensitivity(caseSensitivity) {}
8312+
8313+ bool RegexMatcher::match(std::string const& matchee) const {
8314+ auto flags = std::regex::ECMAScript; // ECMAScript is the default syntax option anyway
8315+ if (m_caseSensitivity == CaseSensitive::No) {
8316+ flags |= std::regex::icase;
8317+ }
8318+ auto reg = std::regex(m_regex, flags);
8319+ return std::regex_match(matchee, reg);
8320+ }
8321+
8322+ std::string RegexMatcher::describe() const {
8323+ return "matches " + ::Catch::Detail::stringify(m_regex) + ((m_caseSensitivity == CaseSensitive::Yes)? " case sensitively" : " case insensitively");
8324+ }
8325+
8326+
8327+ StringEqualsMatcher Equals( std::string const& str, CaseSensitive caseSensitivity ) {
8328+ return StringEqualsMatcher( CasedString( str, caseSensitivity) );
8329+ }
8330+ StringContainsMatcher ContainsSubstring( std::string const& str, CaseSensitive caseSensitivity ) {
8331+ return StringContainsMatcher( CasedString( str, caseSensitivity) );
8332+ }
8333+ EndsWithMatcher EndsWith( std::string const& str, CaseSensitive caseSensitivity ) {
8334+ return EndsWithMatcher( CasedString( str, caseSensitivity) );
8335+ }
8336+ StartsWithMatcher StartsWith( std::string const& str, CaseSensitive caseSensitivity ) {
8337+ return StartsWithMatcher( CasedString( str, caseSensitivity) );
8338+ }
8339+
8340+ RegexMatcher Matches(std::string const& regex, CaseSensitive caseSensitivity) {
8341+ return RegexMatcher(regex, caseSensitivity);
8342+ }
8343+
8344+} // namespace Matchers
8345+} // namespace Catch
8346+
8347+
8348+
8349+namespace Catch {
8350+namespace Matchers {
8351+ MatcherGenericBase::~MatcherGenericBase() = default;
8352+
8353+ namespace Detail {
8354+
8355+ std::string describe_multi_matcher(StringRef combine, std::string const* descriptions_begin, std::string const* descriptions_end) {
8356+ std::string description;
8357+ std::size_t combined_size = 4;
8358+ for ( auto desc = descriptions_begin; desc != descriptions_end; ++desc ) {
8359+ combined_size += desc->size();
8360+ }
8361+ combined_size += static_cast<size_t>(descriptions_end - descriptions_begin - 1) * combine.size();
8362+
8363+ description.reserve(combined_size);
8364+
8365+ description += "( ";
8366+ bool first = true;
8367+ for( auto desc = descriptions_begin; desc != descriptions_end; ++desc ) {
8368+ if( first )
8369+ first = false;
8370+ else
8371+ description += combine;
8372+ description += *desc;
8373+ }
8374+ description += " )";
8375+ return description;
8376+ }
8377+
8378+ } // namespace Detail
8379+} // namespace Matchers
8380+} // namespace Catch
8381+
8382+
8383+
8384+
8385+namespace Catch {
8386+
8387+ // This is the general overload that takes a any string matcher
8388+ // There is another overload, in catch_assertionhandler.h/.cpp, that only takes a string and infers
8389+ // the Equals matcher (so the header does not mention matchers)
8390+ void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher ) {
8391+ std::string exceptionMessage = Catch::translateActiveException();
8392+ MatchExpr<std::string, StringMatcher const&> expr( CATCH_MOVE(exceptionMessage), matcher );
8393+ handler.handleExpr( expr );
8394+ }
8395+
8396+} // namespace Catch
8397+
8398+
8399+
8400+#include <ostream>
8401+
8402+namespace Catch {
8403+
8404+ AutomakeReporter::~AutomakeReporter() = default;
8405+
8406+ void AutomakeReporter::testCaseEnded(TestCaseStats const& _testCaseStats) {
8407+ // Possible values to emit are PASS, XFAIL, SKIP, FAIL, XPASS and ERROR.
8408+ m_stream << ":test-result: ";
8409+ if ( _testCaseStats.totals.testCases.skipped > 0 ) {
8410+ m_stream << "SKIP";
8411+ } else if (_testCaseStats.totals.assertions.allPassed()) {
8412+ m_stream << "PASS";
8413+ } else if (_testCaseStats.totals.assertions.allOk()) {
8414+ m_stream << "XFAIL";
8415+ } else {
8416+ m_stream << "FAIL";
8417+ }
8418+ m_stream << ' ' << _testCaseStats.testInfo->name << '\n';
8419+ StreamingReporterBase::testCaseEnded(_testCaseStats);
8420+ }
8421+
8422+ void AutomakeReporter::skipTest(TestCaseInfo const& testInfo) {
8423+ m_stream << ":test-result: SKIP " << testInfo.name << '\n';
8424+ }
8425+
8426+} // end namespace Catch
8427+
8428+
8429+
8430+
8431+
8432+
8433+namespace Catch {
8434+ ReporterBase::ReporterBase( ReporterConfig&& config ):
8435+ IEventListener( config.fullConfig() ),
8436+ m_wrapped_stream( CATCH_MOVE(config).takeStream() ),
8437+ m_stream( m_wrapped_stream->stream() ),
8438+ m_colour( makeColourImpl( config.colourMode(), m_wrapped_stream.get() ) ),
8439+ m_customOptions( config.customOptions() )
8440+ {}
8441+
8442+ ReporterBase::~ReporterBase() = default;
8443+
8444+ void ReporterBase::listReporters(
8445+ std::vector<ReporterDescription> const& descriptions ) {
8446+ defaultListReporters(m_stream, descriptions, m_config->verbosity());
8447+ }
8448+
8449+ void ReporterBase::listListeners(
8450+ std::vector<ListenerDescription> const& descriptions ) {
8451+ defaultListListeners( m_stream, descriptions );
8452+ }
8453+
8454+ void ReporterBase::listTests(std::vector<TestCaseHandle> const& tests) {
8455+ defaultListTests(m_stream,
8456+ m_colour.get(),
8457+ tests,
8458+ m_config->hasTestFilters(),
8459+ m_config->verbosity());
8460+ }
8461+
8462+ void ReporterBase::listTags(std::vector<TagInfo> const& tags) {
8463+ defaultListTags( m_stream, tags, m_config->hasTestFilters() );
8464+ }
8465+
8466+} // namespace Catch
8467+
8468+
8469+
8470+
8471+#include <ostream>
8472+
8473+namespace Catch {
8474+namespace {
8475+
8476+ // Colour::LightGrey
8477+ static constexpr Colour::Code compactDimColour = Colour::FileName;
8478+
8479+#ifdef CATCH_PLATFORM_MAC
8480+ static constexpr Catch::StringRef compactFailedString = "FAILED"_sr;
8481+ static constexpr Catch::StringRef compactPassedString = "PASSED"_sr;
8482+#else
8483+ static constexpr Catch::StringRef compactFailedString = "failed"_sr;
8484+ static constexpr Catch::StringRef compactPassedString = "passed"_sr;
8485+#endif
8486+
8487+// Implementation of CompactReporter formatting
8488+class AssertionPrinter {
8489+public:
8490+ AssertionPrinter& operator= (AssertionPrinter const&) = delete;
8491+ AssertionPrinter(AssertionPrinter const&) = delete;
8492+ AssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages, ColourImpl* colourImpl_)
8493+ : stream(_stream)
8494+ , result(_stats.assertionResult)
8495+ , messages(_stats.infoMessages)
8496+ , itMessage(_stats.infoMessages.begin())
8497+ , printInfoMessages(_printInfoMessages)
8498+ , colourImpl(colourImpl_)
8499+ {}
8500+
8501+ void print() {
8502+ printSourceInfo();
8503+
8504+ itMessage = messages.begin();
8505+
8506+ switch (result.getResultType()) {
8507+ case ResultWas::Ok:
8508+ printResultType(Colour::ResultSuccess, compactPassedString);
8509+ printOriginalExpression();
8510+ printReconstructedExpression();
8511+ if (!result.hasExpression())
8512+ printRemainingMessages(Colour::None);
8513+ else
8514+ printRemainingMessages();
8515+ break;
8516+ case ResultWas::ExpressionFailed:
8517+ if (result.isOk())
8518+ printResultType(Colour::ResultSuccess, compactFailedString + " - but was ok"_sr);
8519+ else
8520+ printResultType(Colour::Error, compactFailedString);
8521+ printOriginalExpression();
8522+ printReconstructedExpression();
8523+ printRemainingMessages();
8524+ break;
8525+ case ResultWas::ThrewException:
8526+ printResultType(Colour::Error, compactFailedString);
8527+ printIssue("unexpected exception with message:");
8528+ printMessage();
8529+ printExpressionWas();
8530+ printRemainingMessages();
8531+ break;
8532+ case ResultWas::FatalErrorCondition:
8533+ printResultType(Colour::Error, compactFailedString);
8534+ printIssue("fatal error condition with message:");
8535+ printMessage();
8536+ printExpressionWas();
8537+ printRemainingMessages();
8538+ break;
8539+ case ResultWas::DidntThrowException:
8540+ printResultType(Colour::Error, compactFailedString);
8541+ printIssue("expected exception, got none");
8542+ printExpressionWas();
8543+ printRemainingMessages();
8544+ break;
8545+ case ResultWas::Info:
8546+ printResultType(Colour::None, "info"_sr);
8547+ printMessage();
8548+ printRemainingMessages();
8549+ break;
8550+ case ResultWas::Warning:
8551+ printResultType(Colour::None, "warning"_sr);
8552+ printMessage();
8553+ printRemainingMessages();
8554+ break;
8555+ case ResultWas::ExplicitFailure:
8556+ printResultType(Colour::Error, compactFailedString);
8557+ printIssue("explicitly");
8558+ printRemainingMessages(Colour::None);
8559+ break;
8560+ case ResultWas::ExplicitSkip:
8561+ printResultType(Colour::Skip, "skipped"_sr);
8562+ printMessage();
8563+ printRemainingMessages();
8564+ break;
8565+ // These cases are here to prevent compiler warnings
8566+ case ResultWas::Unknown:
8567+ case ResultWas::FailureBit:
8568+ case ResultWas::Exception:
8569+ printResultType(Colour::Error, "** internal error **");
8570+ break;
8571+ }
8572+ }
8573+
8574+private:
8575+ void printSourceInfo() const {
8576+ stream << colourImpl->guardColour( Colour::FileName )
8577+ << result.getSourceInfo() << ':';
8578+ }
8579+
8580+ void printResultType(Colour::Code colour, StringRef passOrFail) const {
8581+ if (!passOrFail.empty()) {
8582+ stream << colourImpl->guardColour(colour) << ' ' << passOrFail;
8583+ stream << ':';
8584+ }
8585+ }
8586+
8587+ void printIssue(char const* issue) const {
8588+ stream << ' ' << issue;
8589+ }
8590+
8591+ void printExpressionWas() {
8592+ if (result.hasExpression()) {
8593+ stream << ';';
8594+ {
8595+ stream << colourImpl->guardColour(compactDimColour) << " expression was:";
8596+ }
8597+ printOriginalExpression();
8598+ }
8599+ }
8600+
8601+ void printOriginalExpression() const {
8602+ if (result.hasExpression()) {
8603+ stream << ' ' << result.getExpression();
8604+ }
8605+ }
8606+
8607+ void printReconstructedExpression() const {
8608+ if (result.hasExpandedExpression()) {
8609+ stream << colourImpl->guardColour(compactDimColour) << " for: ";
8610+ stream << result.getExpandedExpression();
8611+ }
8612+ }
8613+
8614+ void printMessage() {
8615+ if (itMessage != messages.end()) {
8616+ stream << " '" << itMessage->message << '\'';
8617+ ++itMessage;
8618+ }
8619+ }
8620+
8621+ void printRemainingMessages(Colour::Code colour = compactDimColour) {
8622+ if (itMessage == messages.end())
8623+ return;
8624+
8625+ const auto itEnd = messages.cend();
8626+ const auto N = static_cast<std::size_t>(itEnd - itMessage);
8627+
8628+ stream << colourImpl->guardColour( colour ) << " with "
8629+ << pluralise( N, "message"_sr ) << ':';
8630+
8631+ while (itMessage != itEnd) {
8632+ // If this assertion is a warning ignore any INFO messages
8633+ if (printInfoMessages || itMessage->type != ResultWas::Info) {
8634+ printMessage();
8635+ if (itMessage != itEnd) {
8636+ stream << colourImpl->guardColour(compactDimColour) << " and";
8637+ }
8638+ continue;
8639+ }
8640+ ++itMessage;
8641+ }
8642+ }
8643+
8644+private:
8645+ std::ostream& stream;
8646+ AssertionResult const& result;
8647+ std::vector<MessageInfo> const& messages;
8648+ std::vector<MessageInfo>::const_iterator itMessage;
8649+ bool printInfoMessages;
8650+ ColourImpl* colourImpl;
8651+};
8652+
8653+} // anon namespace
8654+
8655+ std::string CompactReporter::getDescription() {
8656+ return "Reports test results on a single line, suitable for IDEs";
8657+ }
8658+
8659+ void CompactReporter::noMatchingTestCases( StringRef unmatchedSpec ) {
8660+ m_stream << "No test cases matched '" << unmatchedSpec << "'\n";
8661+ }
8662+
8663+ void CompactReporter::testRunStarting( TestRunInfo const& ) {
8664+ if ( m_config->testSpec().hasFilters() ) {
8665+ m_stream << m_colour->guardColour( Colour::BrightYellow )
8666+ << "Filters: "
8667+ << m_config->testSpec()
8668+ << '\n';
8669+ }
8670+ m_stream << "RNG seed: " << getSeed() << '\n';
8671+ }
8672+
8673+ void CompactReporter::assertionEnded( AssertionStats const& _assertionStats ) {
8674+ AssertionResult const& result = _assertionStats.assertionResult;
8675+
8676+ bool printInfoMessages = true;
8677+
8678+ // Drop out if result was successful and we're not printing those
8679+ if( !m_config->includeSuccessfulResults() && result.isOk() ) {
8680+ if( result.getResultType() != ResultWas::Warning && result.getResultType() != ResultWas::ExplicitSkip )
8681+ return;
8682+ printInfoMessages = false;
8683+ }
8684+
8685+ AssertionPrinter printer( m_stream, _assertionStats, printInfoMessages, m_colour.get() );
8686+ printer.print();
8687+
8688+ m_stream << '\n' << std::flush;
8689+ }
8690+
8691+ void CompactReporter::sectionEnded(SectionStats const& _sectionStats) {
8692+ double dur = _sectionStats.durationInSeconds;
8693+ if ( shouldShowDuration( *m_config, dur ) ) {
8694+ m_stream << getFormattedDuration( dur ) << " s: " << _sectionStats.sectionInfo.name << '\n' << std::flush;
8695+ }
8696+ }
8697+
8698+ void CompactReporter::testRunEnded( TestRunStats const& _testRunStats ) {
8699+ printTestRunTotals( m_stream, *m_colour, _testRunStats.totals );
8700+ m_stream << "\n\n" << std::flush;
8701+ StreamingReporterBase::testRunEnded( _testRunStats );
8702+ }
8703+
8704+ CompactReporter::~CompactReporter() = default;
8705+
8706+} // end namespace Catch
8707+
8708+
8709+
8710+
8711+#include <cstdio>
8712+
8713+#if defined(_MSC_VER)
8714+#pragma warning(push)
8715+#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch
8716+ // Note that 4062 (not all labels are handled and default is missing) is enabled
8717+#endif
8718+
8719+#if defined(__clang__)
8720+# pragma clang diagnostic push
8721+// For simplicity, benchmarking-only helpers are always enabled
8722+# pragma clang diagnostic ignored "-Wunused-function"
8723+#endif
8724+
8725+
8726+
8727+namespace Catch {
8728+
8729+namespace {
8730+
8731+// Formatter impl for ConsoleReporter
8732+class ConsoleAssertionPrinter {
8733+public:
8734+ ConsoleAssertionPrinter& operator= (ConsoleAssertionPrinter const&) = delete;
8735+ ConsoleAssertionPrinter(ConsoleAssertionPrinter const&) = delete;
8736+ ConsoleAssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, ColourImpl* colourImpl_, bool _printInfoMessages)
8737+ : stream(_stream),
8738+ stats(_stats),
8739+ result(_stats.assertionResult),
8740+ colour(Colour::None),
8741+ messages(_stats.infoMessages),
8742+ colourImpl(colourImpl_),
8743+ printInfoMessages(_printInfoMessages) {
8744+ switch (result.getResultType()) {
8745+ case ResultWas::Ok:
8746+ colour = Colour::Success;
8747+ passOrFail = "PASSED"_sr;
8748+ //if( result.hasMessage() )
8749+ if (messages.size() == 1)
8750+ messageLabel = "with message"_sr;
8751+ if (messages.size() > 1)
8752+ messageLabel = "with messages"_sr;
8753+ break;
8754+ case ResultWas::ExpressionFailed:
8755+ if (result.isOk()) {
8756+ colour = Colour::Success;
8757+ passOrFail = "FAILED - but was ok"_sr;
8758+ } else {
8759+ colour = Colour::Error;
8760+ passOrFail = "FAILED"_sr;
8761+ }
8762+ if (messages.size() == 1)
8763+ messageLabel = "with message"_sr;
8764+ if (messages.size() > 1)
8765+ messageLabel = "with messages"_sr;
8766+ break;
8767+ case ResultWas::ThrewException:
8768+ colour = Colour::Error;
8769+ passOrFail = "FAILED"_sr;
8770+ // todo switch
8771+ switch (messages.size()) { case 0:
8772+ messageLabel = "due to unexpected exception with "_sr;
8773+ break;
8774+ case 1:
8775+ messageLabel = "due to unexpected exception with message"_sr;
8776+ break;
8777+ default:
8778+ messageLabel = "due to unexpected exception with messages"_sr;
8779+ break;
8780+ }
8781+ break;
8782+ case ResultWas::FatalErrorCondition:
8783+ colour = Colour::Error;
8784+ passOrFail = "FAILED"_sr;
8785+ messageLabel = "due to a fatal error condition"_sr;
8786+ break;
8787+ case ResultWas::DidntThrowException:
8788+ colour = Colour::Error;
8789+ passOrFail = "FAILED"_sr;
8790+ messageLabel = "because no exception was thrown where one was expected"_sr;
8791+ break;
8792+ case ResultWas::Info:
8793+ messageLabel = "info"_sr;
8794+ break;
8795+ case ResultWas::Warning:
8796+ messageLabel = "warning"_sr;
8797+ break;
8798+ case ResultWas::ExplicitFailure:
8799+ passOrFail = "FAILED"_sr;
8800+ colour = Colour::Error;
8801+ if (messages.size() == 1)
8802+ messageLabel = "explicitly with message"_sr;
8803+ if (messages.size() > 1)
8804+ messageLabel = "explicitly with messages"_sr;
8805+ break;
8806+ case ResultWas::ExplicitSkip:
8807+ colour = Colour::Skip;
8808+ passOrFail = "SKIPPED"_sr;
8809+ if (messages.size() == 1)
8810+ messageLabel = "explicitly with message"_sr;
8811+ if (messages.size() > 1)
8812+ messageLabel = "explicitly with messages"_sr;
8813+ break;
8814+ // These cases are here to prevent compiler warnings
8815+ case ResultWas::Unknown:
8816+ case ResultWas::FailureBit:
8817+ case ResultWas::Exception:
8818+ passOrFail = "** internal error **"_sr;
8819+ colour = Colour::Error;
8820+ break;
8821+ }
8822+ }
8823+
8824+ void print() const {
8825+ printSourceInfo();
8826+ if (stats.totals.assertions.total() > 0) {
8827+ printResultType();
8828+ printOriginalExpression();
8829+ printReconstructedExpression();
8830+ } else {
8831+ stream << '\n';
8832+ }
8833+ printMessage();
8834+ }
8835+
8836+private:
8837+ void printResultType() const {
8838+ if (!passOrFail.empty()) {
8839+ stream << colourImpl->guardColour(colour) << passOrFail << ":\n";
8840+ }
8841+ }
8842+ void printOriginalExpression() const {
8843+ if (result.hasExpression()) {
8844+ stream << colourImpl->guardColour( Colour::OriginalExpression )
8845+ << " " << result.getExpressionInMacro() << '\n';
8846+ }
8847+ }
8848+ void printReconstructedExpression() const {
8849+ if (result.hasExpandedExpression()) {
8850+ stream << "with expansion:\n";
8851+ stream << colourImpl->guardColour( Colour::ReconstructedExpression )
8852+ << TextFlow::Column( result.getExpandedExpression() )
8853+ .indent( 2 )
8854+ << '\n';
8855+ }
8856+ }
8857+ void printMessage() const {
8858+ if (!messageLabel.empty())
8859+ stream << messageLabel << ':' << '\n';
8860+ for (auto const& msg : messages) {
8861+ // If this assertion is a warning ignore any INFO messages
8862+ if (printInfoMessages || msg.type != ResultWas::Info)
8863+ stream << TextFlow::Column(msg.message).indent(2) << '\n';
8864+ }
8865+ }
8866+ void printSourceInfo() const {
8867+ stream << colourImpl->guardColour( Colour::FileName )
8868+ << result.getSourceInfo() << ": ";
8869+ }
8870+
8871+ std::ostream& stream;
8872+ AssertionStats const& stats;
8873+ AssertionResult const& result;
8874+ Colour::Code colour;
8875+ StringRef passOrFail;
8876+ StringRef messageLabel;
8877+ std::vector<MessageInfo> const& messages;
8878+ ColourImpl* colourImpl;
8879+ bool printInfoMessages;
8880+};
8881+
8882+std::size_t makeRatio( std::uint64_t number, std::uint64_t total ) {
8883+ const auto ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number / total : 0;
8884+ return (ratio == 0 && number > 0) ? 1 : static_cast<std::size_t>(ratio);
8885+}
8886+
8887+std::size_t&
8888+findMax( std::size_t& i, std::size_t& j, std::size_t& k, std::size_t& l ) {
8889+ if (i > j && i > k && i > l)
8890+ return i;
8891+ else if (j > k && j > l)
8892+ return j;
8893+ else if (k > l)
8894+ return k;
8895+ else
8896+ return l;
8897+}
8898+
8899+struct ColumnBreak {};
8900+struct RowBreak {};
8901+struct OutputFlush {};
8902+
8903+class Duration {
8904+ enum class Unit {
8905+ Auto,
8906+ Nanoseconds,
8907+ Microseconds,
8908+ Milliseconds,
8909+ Seconds,
8910+ Minutes
8911+ };
8912+ static const uint64_t s_nanosecondsInAMicrosecond = 1000;
8913+ static const uint64_t s_nanosecondsInAMillisecond = 1000 * s_nanosecondsInAMicrosecond;
8914+ static const uint64_t s_nanosecondsInASecond = 1000 * s_nanosecondsInAMillisecond;
8915+ static const uint64_t s_nanosecondsInAMinute = 60 * s_nanosecondsInASecond;
8916+
8917+ double m_inNanoseconds;
8918+ Unit m_units;
8919+
8920+public:
8921+ explicit Duration(double inNanoseconds, Unit units = Unit::Auto)
8922+ : m_inNanoseconds(inNanoseconds),
8923+ m_units(units) {
8924+ if (m_units == Unit::Auto) {
8925+ if (m_inNanoseconds < s_nanosecondsInAMicrosecond)
8926+ m_units = Unit::Nanoseconds;
8927+ else if (m_inNanoseconds < s_nanosecondsInAMillisecond)
8928+ m_units = Unit::Microseconds;
8929+ else if (m_inNanoseconds < s_nanosecondsInASecond)
8930+ m_units = Unit::Milliseconds;
8931+ else if (m_inNanoseconds < s_nanosecondsInAMinute)
8932+ m_units = Unit::Seconds;
8933+ else
8934+ m_units = Unit::Minutes;
8935+ }
8936+
8937+ }
8938+
8939+ auto value() const -> double {
8940+ switch (m_units) {
8941+ case Unit::Microseconds:
8942+ return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMicrosecond);
8943+ case Unit::Milliseconds:
8944+ return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMillisecond);
8945+ case Unit::Seconds:
8946+ return m_inNanoseconds / static_cast<double>(s_nanosecondsInASecond);
8947+ case Unit::Minutes:
8948+ return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMinute);
8949+ default:
8950+ return m_inNanoseconds;
8951+ }
8952+ }
8953+ StringRef unitsAsString() const {
8954+ switch (m_units) {
8955+ case Unit::Nanoseconds:
8956+ return "ns"_sr;
8957+ case Unit::Microseconds:
8958+ return "us"_sr;
8959+ case Unit::Milliseconds:
8960+ return "ms"_sr;
8961+ case Unit::Seconds:
8962+ return "s"_sr;
8963+ case Unit::Minutes:
8964+ return "m"_sr;
8965+ default:
8966+ return "** internal error **"_sr;
8967+ }
8968+
8969+ }
8970+ friend auto operator << (std::ostream& os, Duration const& duration) -> std::ostream& {
8971+ return os << duration.value() << ' ' << duration.unitsAsString();
8972+ }
8973+};
8974+} // end anon namespace
8975+
8976+enum class Justification { Left, Right };
8977+
8978+struct ColumnInfo {
8979+ std::string name;
8980+ std::size_t width;
8981+ Justification justification;
8982+};
8983+
8984+class TablePrinter {
8985+ std::ostream& m_os;
8986+ std::vector<ColumnInfo> m_columnInfos;
8987+ ReusableStringStream m_oss;
8988+ int m_currentColumn = -1;
8989+ bool m_isOpen = false;
8990+
8991+public:
8992+ TablePrinter( std::ostream& os, std::vector<ColumnInfo> columnInfos )
8993+ : m_os( os ),
8994+ m_columnInfos( CATCH_MOVE( columnInfos ) ) {}
8995+
8996+ auto columnInfos() const -> std::vector<ColumnInfo> const& {
8997+ return m_columnInfos;
8998+ }
8999+
9000+ void open() {
9001+ if (!m_isOpen) {
9002+ m_isOpen = true;
9003+ *this << RowBreak();
9004+
9005+ TextFlow::Columns headerCols;
9006+ for (auto const& info : m_columnInfos) {
9007+ assert(info.width > 2);
9008+ headerCols += TextFlow::Column(info.name).width(info.width - 2);
9009+ headerCols += TextFlow::Spacer( 2 );
9010+ }
9011+ m_os << headerCols << '\n';
9012+
9013+ m_os << lineOfChars('-') << '\n';
9014+ }
9015+ }
9016+ void close() {
9017+ if (m_isOpen) {
9018+ *this << RowBreak();
9019+ m_os << '\n' << std::flush;
9020+ m_isOpen = false;
9021+ }
9022+ }
9023+
9024+ template<typename T>
9025+ friend TablePrinter& operator<< (TablePrinter& tp, T const& value) {
9026+ tp.m_oss << value;
9027+ return tp;
9028+ }
9029+
9030+ friend TablePrinter& operator<< (TablePrinter& tp, ColumnBreak) {
9031+ auto colStr = tp.m_oss.str();
9032+ const auto strSize = colStr.size();
9033+ tp.m_oss.str("");
9034+ tp.open();
9035+ if (tp.m_currentColumn == static_cast<int>(tp.m_columnInfos.size() - 1)) {
9036+ tp.m_currentColumn = -1;
9037+ tp.m_os << '\n';
9038+ }
9039+ tp.m_currentColumn++;
9040+
9041+ auto colInfo = tp.m_columnInfos[tp.m_currentColumn];
9042+ auto padding = (strSize + 1 < colInfo.width)
9043+ ? std::string(colInfo.width - (strSize + 1), ' ')
9044+ : std::string();
9045+ if (colInfo.justification == Justification::Left)
9046+ tp.m_os << colStr << padding << ' ';
9047+ else
9048+ tp.m_os << padding << colStr << ' ';
9049+ return tp;
9050+ }
9051+
9052+ friend TablePrinter& operator<< (TablePrinter& tp, RowBreak) {
9053+ if (tp.m_currentColumn > 0) {
9054+ tp.m_os << '\n';
9055+ tp.m_currentColumn = -1;
9056+ }
9057+ return tp;
9058+ }
9059+
9060+ friend TablePrinter& operator<<(TablePrinter& tp, OutputFlush) {
9061+ tp.m_os << std::flush;
9062+ return tp;
9063+ }
9064+};
9065+
9066+ConsoleReporter::ConsoleReporter(ReporterConfig&& config):
9067+ StreamingReporterBase( CATCH_MOVE( config ) ),
9068+ m_tablePrinter(Detail::make_unique<TablePrinter>(m_stream,
9069+ [&config]() -> std::vector<ColumnInfo> {
9070+ if (config.fullConfig()->benchmarkNoAnalysis())
9071+ {
9072+ return{
9073+ { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 43, Justification::Left },
9074+ { " samples", 14, Justification::Right },
9075+ { " iterations", 14, Justification::Right },
9076+ { " mean", 14, Justification::Right }
9077+ };
9078+ }
9079+ else
9080+ {
9081+ return{
9082+ { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 43, Justification::Left },
9083+ { "samples mean std dev", 14, Justification::Right },
9084+ { "iterations low mean low std dev", 14, Justification::Right },
9085+ { "est run time high mean high std dev", 14, Justification::Right }
9086+ };
9087+ }
9088+ }())) {}
9089+ConsoleReporter::~ConsoleReporter() = default;
9090+
9091+std::string ConsoleReporter::getDescription() {
9092+ return "Reports test results as plain lines of text";
9093+}
9094+
9095+void ConsoleReporter::noMatchingTestCases( StringRef unmatchedSpec ) {
9096+ m_stream << "No test cases matched '" << unmatchedSpec << "'\n";
9097+}
9098+
9099+void ConsoleReporter::reportInvalidTestSpec( StringRef arg ) {
9100+ m_stream << "Invalid Filter: " << arg << '\n';
9101+}
9102+
9103+void ConsoleReporter::assertionStarting(AssertionInfo const&) {}
9104+
9105+void ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) {
9106+ AssertionResult const& result = _assertionStats.assertionResult;
9107+
9108+ bool includeResults = m_config->includeSuccessfulResults() || !result.isOk();
9109+
9110+ // Drop out if result was successful but we're not printing them.
9111+ // TODO: Make configurable whether skips should be printed
9112+ if (!includeResults && result.getResultType() != ResultWas::Warning && result.getResultType() != ResultWas::ExplicitSkip)
9113+ return;
9114+
9115+ lazyPrint();
9116+
9117+ ConsoleAssertionPrinter printer(m_stream, _assertionStats, m_colour.get(), includeResults);
9118+ printer.print();
9119+ m_stream << '\n' << std::flush;
9120+}
9121+
9122+void ConsoleReporter::sectionStarting(SectionInfo const& _sectionInfo) {
9123+ m_tablePrinter->close();
9124+ m_headerPrinted = false;
9125+ StreamingReporterBase::sectionStarting(_sectionInfo);
9126+}
9127+void ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) {
9128+ m_tablePrinter->close();
9129+ if (_sectionStats.missingAssertions) {
9130+ lazyPrint();
9131+ auto guard =
9132+ m_colour->guardColour( Colour::ResultError ).engage( m_stream );
9133+ if (m_sectionStack.size() > 1)
9134+ m_stream << "\nNo assertions in section";
9135+ else
9136+ m_stream << "\nNo assertions in test case";
9137+ m_stream << " '" << _sectionStats.sectionInfo.name << "'\n\n" << std::flush;
9138+ }
9139+ double dur = _sectionStats.durationInSeconds;
9140+ if (shouldShowDuration(*m_config, dur)) {
9141+ m_stream << getFormattedDuration(dur) << " s: " << _sectionStats.sectionInfo.name << '\n' << std::flush;
9142+ }
9143+ if (m_headerPrinted) {
9144+ m_headerPrinted = false;
9145+ }
9146+ StreamingReporterBase::sectionEnded(_sectionStats);
9147+}
9148+
9149+void ConsoleReporter::benchmarkPreparing( StringRef name ) {
9150+ lazyPrintWithoutClosingBenchmarkTable();
9151+
9152+ auto nameCol = TextFlow::Column( static_cast<std::string>( name ) )
9153+ .width( m_tablePrinter->columnInfos()[0].width - 2 );
9154+
9155+ bool firstLine = true;
9156+ for (auto line : nameCol) {
9157+ if (!firstLine)
9158+ (*m_tablePrinter) << ColumnBreak() << ColumnBreak() << ColumnBreak();
9159+ else
9160+ firstLine = false;
9161+
9162+ (*m_tablePrinter) << line << ColumnBreak();
9163+ }
9164+}
9165+
9166+void ConsoleReporter::benchmarkStarting(BenchmarkInfo const& info) {
9167+ (*m_tablePrinter) << info.samples << ColumnBreak()
9168+ << info.iterations << ColumnBreak();
9169+ if ( !m_config->benchmarkNoAnalysis() ) {
9170+ ( *m_tablePrinter )
9171+ << Duration( info.estimatedDuration ) << ColumnBreak();
9172+ }
9173+ ( *m_tablePrinter ) << OutputFlush{};
9174+}
9175+void ConsoleReporter::benchmarkEnded(BenchmarkStats<> const& stats) {
9176+ if (m_config->benchmarkNoAnalysis())
9177+ {
9178+ (*m_tablePrinter) << Duration(stats.mean.point.count()) << ColumnBreak();
9179+ }
9180+ else
9181+ {
9182+ (*m_tablePrinter) << ColumnBreak()
9183+ << Duration(stats.mean.point.count()) << ColumnBreak()
9184+ << Duration(stats.mean.lower_bound.count()) << ColumnBreak()
9185+ << Duration(stats.mean.upper_bound.count()) << ColumnBreak() << ColumnBreak()
9186+ << Duration(stats.standardDeviation.point.count()) << ColumnBreak()
9187+ << Duration(stats.standardDeviation.lower_bound.count()) << ColumnBreak()
9188+ << Duration(stats.standardDeviation.upper_bound.count()) << ColumnBreak() << ColumnBreak() << ColumnBreak() << ColumnBreak() << ColumnBreak();
9189+ }
9190+}
9191+
9192+void ConsoleReporter::benchmarkFailed( StringRef error ) {
9193+ auto guard = m_colour->guardColour( Colour::Red ).engage( m_stream );
9194+ (*m_tablePrinter)
9195+ << "Benchmark failed (" << error << ')'
9196+ << ColumnBreak() << RowBreak();
9197+}
9198+
9199+void ConsoleReporter::testCaseEnded(TestCaseStats const& _testCaseStats) {
9200+ m_tablePrinter->close();
9201+ StreamingReporterBase::testCaseEnded(_testCaseStats);
9202+ m_headerPrinted = false;
9203+}
9204+void ConsoleReporter::testRunEnded(TestRunStats const& _testRunStats) {
9205+ printTotalsDivider(_testRunStats.totals);
9206+ printTestRunTotals( m_stream, *m_colour, _testRunStats.totals );
9207+ m_stream << '\n' << std::flush;
9208+ StreamingReporterBase::testRunEnded(_testRunStats);
9209+}
9210+void ConsoleReporter::testRunStarting(TestRunInfo const& _testRunInfo) {
9211+ StreamingReporterBase::testRunStarting(_testRunInfo);
9212+ if ( m_config->testSpec().hasFilters() ) {
9213+ m_stream << m_colour->guardColour( Colour::BrightYellow ) << "Filters: "
9214+ << m_config->testSpec() << '\n';
9215+ }
9216+ m_stream << "Randomness seeded to: " << getSeed() << '\n';
9217+}
9218+
9219+void ConsoleReporter::lazyPrint() {
9220+
9221+ m_tablePrinter->close();
9222+ lazyPrintWithoutClosingBenchmarkTable();
9223+}
9224+
9225+void ConsoleReporter::lazyPrintWithoutClosingBenchmarkTable() {
9226+
9227+ if ( !m_testRunInfoPrinted ) {
9228+ lazyPrintRunInfo();
9229+ }
9230+ if (!m_headerPrinted) {
9231+ printTestCaseAndSectionHeader();
9232+ m_headerPrinted = true;
9233+ }
9234+}
9235+void ConsoleReporter::lazyPrintRunInfo() {
9236+ m_stream << '\n'
9237+ << lineOfChars( '~' ) << '\n'
9238+ << m_colour->guardColour( Colour::SecondaryText )
9239+ << currentTestRunInfo.name << " is a Catch2 v" << libraryVersion()
9240+ << " host application.\n"
9241+ << "Run with -? for options\n\n";
9242+
9243+ m_testRunInfoPrinted = true;
9244+}
9245+void ConsoleReporter::printTestCaseAndSectionHeader() {
9246+ assert(!m_sectionStack.empty());
9247+ printOpenHeader(currentTestCaseInfo->name);
9248+
9249+ if (m_sectionStack.size() > 1) {
9250+ auto guard = m_colour->guardColour( Colour::Headers ).engage( m_stream );
9251+
9252+ auto
9253+ it = m_sectionStack.begin() + 1, // Skip first section (test case)
9254+ itEnd = m_sectionStack.end();
9255+ for (; it != itEnd; ++it)
9256+ printHeaderString(it->name, 2);
9257+ }
9258+
9259+ SourceLineInfo lineInfo = m_sectionStack.back().lineInfo;
9260+
9261+
9262+ m_stream << lineOfChars( '-' ) << '\n'
9263+ << m_colour->guardColour( Colour::FileName ) << lineInfo << '\n'
9264+ << lineOfChars( '.' ) << "\n\n"
9265+ << std::flush;
9266+}
9267+
9268+void ConsoleReporter::printClosedHeader(std::string const& _name) {
9269+ printOpenHeader(_name);
9270+ m_stream << lineOfChars('.') << '\n';
9271+}
9272+void ConsoleReporter::printOpenHeader(std::string const& _name) {
9273+ m_stream << lineOfChars('-') << '\n';
9274+ {
9275+ auto guard = m_colour->guardColour( Colour::Headers ).engage( m_stream );
9276+ printHeaderString(_name);
9277+ }
9278+}
9279+
9280+void ConsoleReporter::printHeaderString(std::string const& _string, std::size_t indent) {
9281+ // We want to get a bit fancy with line breaking here, so that subsequent
9282+ // lines start after ":" if one is present, e.g.
9283+ // ```
9284+ // blablabla: Fancy
9285+ // linebreaking
9286+ // ```
9287+ // but we also want to avoid problems with overly long indentation causing
9288+ // the text to take up too many lines, e.g.
9289+ // ```
9290+ // blablabla: F
9291+ // a
9292+ // n
9293+ // c
9294+ // y
9295+ // .
9296+ // .
9297+ // .
9298+ // ```
9299+ // So we limit the prefix indentation check to first quarter of the possible
9300+ // width
9301+ std::size_t idx = _string.find( ": " );
9302+ if ( idx != std::string::npos && idx < CATCH_CONFIG_CONSOLE_WIDTH / 4 ) {
9303+ idx += 2;
9304+ } else {
9305+ idx = 0;
9306+ }
9307+ m_stream << TextFlow::Column( _string )
9308+ .indent( indent + idx )
9309+ .initialIndent( indent )
9310+ << '\n';
9311+}
9312+
9313+void ConsoleReporter::printTotalsDivider(Totals const& totals) {
9314+ if (totals.testCases.total() > 0) {
9315+ std::size_t failedRatio = makeRatio(totals.testCases.failed, totals.testCases.total());
9316+ std::size_t failedButOkRatio = makeRatio(totals.testCases.failedButOk, totals.testCases.total());
9317+ std::size_t passedRatio = makeRatio(totals.testCases.passed, totals.testCases.total());
9318+ std::size_t skippedRatio = makeRatio(totals.testCases.skipped, totals.testCases.total());
9319+ while (failedRatio + failedButOkRatio + passedRatio + skippedRatio < CATCH_CONFIG_CONSOLE_WIDTH - 1)
9320+ findMax(failedRatio, failedButOkRatio, passedRatio, skippedRatio)++;
9321+ while (failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH - 1)
9322+ findMax(failedRatio, failedButOkRatio, passedRatio, skippedRatio)--;
9323+
9324+ m_stream << m_colour->guardColour( Colour::Error )
9325+ << std::string( failedRatio, '=' )
9326+ << m_colour->guardColour( Colour::ResultExpectedFailure )
9327+ << std::string( failedButOkRatio, '=' );
9328+ if ( totals.testCases.allPassed() ) {
9329+ m_stream << m_colour->guardColour( Colour::ResultSuccess )
9330+ << std::string( passedRatio, '=' );
9331+ } else {
9332+ m_stream << m_colour->guardColour( Colour::Success )
9333+ << std::string( passedRatio, '=' );
9334+ }
9335+ m_stream << m_colour->guardColour( Colour::Skip )
9336+ << std::string( skippedRatio, '=' );
9337+ } else {
9338+ m_stream << m_colour->guardColour( Colour::Warning )
9339+ << std::string( CATCH_CONFIG_CONSOLE_WIDTH - 1, '=' );
9340+ }
9341+ m_stream << '\n';
9342+}
9343+
9344+} // end namespace Catch
9345+
9346+#if defined(_MSC_VER)
9347+#pragma warning(pop)
9348+#endif
9349+
9350+#if defined(__clang__)
9351+# pragma clang diagnostic pop
9352+#endif
9353+
9354+
9355+
9356+
9357+#include <algorithm>
9358+#include <cassert>
9359+
9360+namespace Catch {
9361+ namespace {
9362+ struct BySectionInfo {
9363+ BySectionInfo( SectionInfo const& other ): m_other( other ) {}
9364+ BySectionInfo( BySectionInfo const& other ) = default;
9365+ bool operator()(
9366+ Detail::unique_ptr<CumulativeReporterBase::SectionNode> const&
9367+ node ) const {
9368+ return (
9369+ ( node->stats.sectionInfo.name == m_other.name ) &&
9370+ ( node->stats.sectionInfo.lineInfo == m_other.lineInfo ) );
9371+ }
9372+ void operator=( BySectionInfo const& ) = delete;
9373+
9374+ private:
9375+ SectionInfo const& m_other;
9376+ };
9377+
9378+ } // namespace
9379+
9380+ namespace Detail {
9381+ AssertionOrBenchmarkResult::AssertionOrBenchmarkResult(
9382+ AssertionStats const& assertion ):
9383+ m_assertion( assertion ) {}
9384+
9385+ AssertionOrBenchmarkResult::AssertionOrBenchmarkResult(
9386+ BenchmarkStats<> const& benchmark ):
9387+ m_benchmark( benchmark ) {}
9388+
9389+ bool AssertionOrBenchmarkResult::isAssertion() const {
9390+ return m_assertion.some();
9391+ }
9392+ bool AssertionOrBenchmarkResult::isBenchmark() const {
9393+ return m_benchmark.some();
9394+ }
9395+
9396+ AssertionStats const& AssertionOrBenchmarkResult::asAssertion() const {
9397+ assert(m_assertion.some());
9398+
9399+ return *m_assertion;
9400+ }
9401+ BenchmarkStats<> const& AssertionOrBenchmarkResult::asBenchmark() const {
9402+ assert(m_benchmark.some());
9403+
9404+ return *m_benchmark;
9405+ }
9406+
9407+ }
9408+
9409+ CumulativeReporterBase::~CumulativeReporterBase() = default;
9410+
9411+ void CumulativeReporterBase::benchmarkEnded(BenchmarkStats<> const& benchmarkStats) {
9412+ m_sectionStack.back()->assertionsAndBenchmarks.emplace_back(benchmarkStats);
9413+ }
9414+
9415+ void
9416+ CumulativeReporterBase::sectionStarting( SectionInfo const& sectionInfo ) {
9417+ // We need a copy, because SectionStats expect to take ownership
9418+ SectionStats incompleteStats( SectionInfo(sectionInfo), Counts(), 0, false );
9419+ SectionNode* node;
9420+ if ( m_sectionStack.empty() ) {
9421+ if ( !m_rootSection ) {
9422+ m_rootSection =
9423+ Detail::make_unique<SectionNode>( incompleteStats );
9424+ }
9425+ node = m_rootSection.get();
9426+ } else {
9427+ SectionNode& parentNode = *m_sectionStack.back();
9428+ auto it = std::find_if( parentNode.childSections.begin(),
9429+ parentNode.childSections.end(),
9430+ BySectionInfo( sectionInfo ) );
9431+ if ( it == parentNode.childSections.end() ) {
9432+ auto newNode =
9433+ Detail::make_unique<SectionNode>( incompleteStats );
9434+ node = newNode.get();
9435+ parentNode.childSections.push_back( CATCH_MOVE( newNode ) );
9436+ } else {
9437+ node = it->get();
9438+ }
9439+ }
9440+
9441+ m_deepestSection = node;
9442+ m_sectionStack.push_back( node );
9443+ }
9444+
9445+ void CumulativeReporterBase::assertionEnded(
9446+ AssertionStats const& assertionStats ) {
9447+ assert( !m_sectionStack.empty() );
9448+ // AssertionResult holds a pointer to a temporary DecomposedExpression,
9449+ // which getExpandedExpression() calls to build the expression string.
9450+ // Our section stack copy of the assertionResult will likely outlive the
9451+ // temporary, so it must be expanded or discarded now to avoid calling
9452+ // a destroyed object later.
9453+ if ( m_shouldStoreFailedAssertions &&
9454+ !assertionStats.assertionResult.isOk() ) {
9455+ static_cast<void>(
9456+ assertionStats.assertionResult.getExpandedExpression() );
9457+ }
9458+ if ( m_shouldStoreSuccesfulAssertions &&
9459+ assertionStats.assertionResult.isOk() ) {
9460+ static_cast<void>(
9461+ assertionStats.assertionResult.getExpandedExpression() );
9462+ }
9463+ SectionNode& sectionNode = *m_sectionStack.back();
9464+ sectionNode.assertionsAndBenchmarks.emplace_back( assertionStats );
9465+ }
9466+
9467+ void CumulativeReporterBase::sectionEnded( SectionStats const& sectionStats ) {
9468+ assert( !m_sectionStack.empty() );
9469+ SectionNode& node = *m_sectionStack.back();
9470+ node.stats = sectionStats;
9471+ m_sectionStack.pop_back();
9472+ }
9473+
9474+ void CumulativeReporterBase::testCaseEnded(
9475+ TestCaseStats const& testCaseStats ) {
9476+ auto node = Detail::make_unique<TestCaseNode>( testCaseStats );
9477+ assert( m_sectionStack.size() == 0 );
9478+ node->children.push_back( CATCH_MOVE(m_rootSection) );
9479+ m_testCases.push_back( CATCH_MOVE(node) );
9480+
9481+ assert( m_deepestSection );
9482+ m_deepestSection->stdOut = testCaseStats.stdOut;
9483+ m_deepestSection->stdErr = testCaseStats.stdErr;
9484+ }
9485+
9486+
9487+ void CumulativeReporterBase::testRunEnded( TestRunStats const& testRunStats ) {
9488+ assert(!m_testRun && "CumulativeReporterBase assumes there can only be one test run");
9489+ m_testRun = Detail::make_unique<TestRunNode>( testRunStats );
9490+ m_testRun->children.swap( m_testCases );
9491+ testRunEndedCumulative();
9492+ }
9493+
9494+ bool CumulativeReporterBase::SectionNode::hasAnyAssertions() const {
9495+ return std::any_of(
9496+ assertionsAndBenchmarks.begin(),
9497+ assertionsAndBenchmarks.end(),
9498+ []( Detail::AssertionOrBenchmarkResult const& res ) {
9499+ return res.isAssertion();
9500+ } );
9501+ }
9502+
9503+} // end namespace Catch
9504+
9505+
9506+
9507+
9508+namespace Catch {
9509+
9510+ void EventListenerBase::fatalErrorEncountered( StringRef ) {}
9511+
9512+ void EventListenerBase::benchmarkPreparing( StringRef ) {}
9513+ void EventListenerBase::benchmarkStarting( BenchmarkInfo const& ) {}
9514+ void EventListenerBase::benchmarkEnded( BenchmarkStats<> const& ) {}
9515+ void EventListenerBase::benchmarkFailed( StringRef ) {}
9516+
9517+ void EventListenerBase::assertionStarting( AssertionInfo const& ) {}
9518+
9519+ void EventListenerBase::assertionEnded( AssertionStats const& ) {}
9520+ void EventListenerBase::listReporters(
9521+ std::vector<ReporterDescription> const& ) {}
9522+ void EventListenerBase::listListeners(
9523+ std::vector<ListenerDescription> const& ) {}
9524+ void EventListenerBase::listTests( std::vector<TestCaseHandle> const& ) {}
9525+ void EventListenerBase::listTags( std::vector<TagInfo> const& ) {}
9526+ void EventListenerBase::noMatchingTestCases( StringRef ) {}
9527+ void EventListenerBase::reportInvalidTestSpec( StringRef ) {}
9528+ void EventListenerBase::testRunStarting( TestRunInfo const& ) {}
9529+ void EventListenerBase::testCaseStarting( TestCaseInfo const& ) {}
9530+ void EventListenerBase::testCasePartialStarting(TestCaseInfo const&, uint64_t) {}
9531+ void EventListenerBase::sectionStarting( SectionInfo const& ) {}
9532+ void EventListenerBase::sectionEnded( SectionStats const& ) {}
9533+ void EventListenerBase::testCasePartialEnded(TestCaseStats const&, uint64_t) {}
9534+ void EventListenerBase::testCaseEnded( TestCaseStats const& ) {}
9535+ void EventListenerBase::testRunEnded( TestRunStats const& ) {}
9536+ void EventListenerBase::skipTest( TestCaseInfo const& ) {}
9537+} // namespace Catch
9538+
9539+
9540+
9541+
9542+#include <algorithm>
9543+#include <cfloat>
9544+#include <cstdio>
9545+#include <ostream>
9546+#include <iomanip>
9547+
9548+namespace Catch {
9549+
9550+ namespace {
9551+ void listTestNamesOnly(std::ostream& out,
9552+ std::vector<TestCaseHandle> const& tests) {
9553+ for (auto const& test : tests) {
9554+ auto const& testCaseInfo = test.getTestCaseInfo();
9555+
9556+ if (startsWith(testCaseInfo.name, '#')) {
9557+ out << '"' << testCaseInfo.name << '"';
9558+ } else {
9559+ out << testCaseInfo.name;
9560+ }
9561+
9562+ out << '\n';
9563+ }
9564+ out << std::flush;
9565+ }
9566+ } // end unnamed namespace
9567+
9568+
9569+ // Because formatting using c++ streams is stateful, drop down to C is
9570+ // required Alternatively we could use stringstream, but its performance
9571+ // is... not good.
9572+ std::string getFormattedDuration( double duration ) {
9573+ // Max exponent + 1 is required to represent the whole part
9574+ // + 1 for decimal point
9575+ // + 3 for the 3 decimal places
9576+ // + 1 for null terminator
9577+ const std::size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1;
9578+ char buffer[maxDoubleSize];
9579+
9580+ // Save previous errno, to prevent sprintf from overwriting it
9581+ ErrnoGuard guard;
9582+#ifdef _MSC_VER
9583+ size_t printedLength = static_cast<size_t>(
9584+ sprintf_s( buffer, "%.3f", duration ) );
9585+#else
9586+ size_t printedLength = static_cast<size_t>(
9587+ std::snprintf( buffer, maxDoubleSize, "%.3f", duration ) );
9588+#endif
9589+ return std::string( buffer, printedLength );
9590+ }
9591+
9592+ bool shouldShowDuration( IConfig const& config, double duration ) {
9593+ if ( config.showDurations() == ShowDurations::Always ) {
9594+ return true;
9595+ }
9596+ if ( config.showDurations() == ShowDurations::Never ) {
9597+ return false;
9598+ }
9599+ const double min = config.minDuration();
9600+ return min >= 0 && duration >= min;
9601+ }
9602+
9603+ std::string serializeFilters( std::vector<std::string> const& filters ) {
9604+ // We add a ' ' separator between each filter
9605+ size_t serialized_size = filters.size() - 1;
9606+ for (auto const& filter : filters) {
9607+ serialized_size += filter.size();
9608+ }
9609+
9610+ std::string serialized;
9611+ serialized.reserve(serialized_size);
9612+ bool first = true;
9613+
9614+ for (auto const& filter : filters) {
9615+ if (!first) {
9616+ serialized.push_back(' ');
9617+ }
9618+ first = false;
9619+ serialized.append(filter);
9620+ }
9621+
9622+ return serialized;
9623+ }
9624+
9625+ std::ostream& operator<<( std::ostream& out, lineOfChars value ) {
9626+ for ( size_t idx = 0; idx < CATCH_CONFIG_CONSOLE_WIDTH - 1; ++idx ) {
9627+ out.put( value.c );
9628+ }
9629+ return out;
9630+ }
9631+
9632+ void
9633+ defaultListReporters( std::ostream& out,
9634+ std::vector<ReporterDescription> const& descriptions,
9635+ Verbosity verbosity ) {
9636+ out << "Available reporters:\n";
9637+ const auto maxNameLen =
9638+ std::max_element( descriptions.begin(),
9639+ descriptions.end(),
9640+ []( ReporterDescription const& lhs,
9641+ ReporterDescription const& rhs ) {
9642+ return lhs.name.size() < rhs.name.size();
9643+ } )
9644+ ->name.size();
9645+
9646+ for ( auto const& desc : descriptions ) {
9647+ if ( verbosity == Verbosity::Quiet ) {
9648+ out << TextFlow::Column( desc.name )
9649+ .indent( 2 )
9650+ .width( 5 + maxNameLen )
9651+ << '\n';
9652+ } else {
9653+ out << TextFlow::Column( desc.name + ':' )
9654+ .indent( 2 )
9655+ .width( 5 + maxNameLen ) +
9656+ TextFlow::Column( desc.description )
9657+ .initialIndent( 0 )
9658+ .indent( 2 )
9659+ .width( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen - 8 )
9660+ << '\n';
9661+ }
9662+ }
9663+ out << '\n' << std::flush;
9664+ }
9665+
9666+ void defaultListListeners( std::ostream& out,
9667+ std::vector<ListenerDescription> const& descriptions ) {
9668+ out << "Registered listeners:\n";
9669+
9670+ if(descriptions.empty()) {
9671+ return;
9672+ }
9673+
9674+ const auto maxNameLen =
9675+ std::max_element( descriptions.begin(),
9676+ descriptions.end(),
9677+ []( ListenerDescription const& lhs,
9678+ ListenerDescription const& rhs ) {
9679+ return lhs.name.size() < rhs.name.size();
9680+ } )
9681+ ->name.size();
9682+
9683+ for ( auto const& desc : descriptions ) {
9684+ out << TextFlow::Column( static_cast<std::string>( desc.name ) +
9685+ ':' )
9686+ .indent( 2 )
9687+ .width( maxNameLen + 5 ) +
9688+ TextFlow::Column( desc.description )
9689+ .initialIndent( 0 )
9690+ .indent( 2 )
9691+ .width( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen - 8 )
9692+ << '\n';
9693+ }
9694+
9695+ out << '\n' << std::flush;
9696+ }
9697+
9698+ void defaultListTags( std::ostream& out,
9699+ std::vector<TagInfo> const& tags,
9700+ bool isFiltered ) {
9701+ if ( isFiltered ) {
9702+ out << "Tags for matching test cases:\n";
9703+ } else {
9704+ out << "All available tags:\n";
9705+ }
9706+
9707+ for ( auto const& tagCount : tags ) {
9708+ ReusableStringStream rss;
9709+ rss << " " << std::setw( 2 ) << tagCount.count << " ";
9710+ auto str = rss.str();
9711+ auto wrapper = TextFlow::Column( tagCount.all() )
9712+ .initialIndent( 0 )
9713+ .indent( str.size() )
9714+ .width( CATCH_CONFIG_CONSOLE_WIDTH - 10 );
9715+ out << str << wrapper << '\n';
9716+ }
9717+ out << pluralise(tags.size(), "tag"_sr) << "\n\n" << std::flush;
9718+ }
9719+
9720+ void defaultListTests(std::ostream& out, ColourImpl* streamColour, std::vector<TestCaseHandle> const& tests, bool isFiltered, Verbosity verbosity) {
9721+ // We special case this to provide the equivalent of old
9722+ // `--list-test-names-only`, which could then be used by the
9723+ // `--input-file` option.
9724+ if (verbosity == Verbosity::Quiet) {
9725+ listTestNamesOnly(out, tests);
9726+ return;
9727+ }
9728+
9729+ if (isFiltered) {
9730+ out << "Matching test cases:\n";
9731+ } else {
9732+ out << "All available test cases:\n";
9733+ }
9734+
9735+ for (auto const& test : tests) {
9736+ auto const& testCaseInfo = test.getTestCaseInfo();
9737+ Colour::Code colour = testCaseInfo.isHidden()
9738+ ? Colour::SecondaryText
9739+ : Colour::None;
9740+ auto colourGuard = streamColour->guardColour( colour ).engage( out );
9741+
9742+ out << TextFlow::Column(testCaseInfo.name).indent(2) << '\n';
9743+ if (verbosity >= Verbosity::High) {
9744+ out << TextFlow::Column(Catch::Detail::stringify(testCaseInfo.lineInfo)).indent(4) << '\n';
9745+ }
9746+ if (!testCaseInfo.tags.empty() &&
9747+ verbosity > Verbosity::Quiet) {
9748+ out << TextFlow::Column(testCaseInfo.tagsAsString()).indent(6) << '\n';
9749+ }
9750+ }
9751+
9752+ if (isFiltered) {
9753+ out << pluralise(tests.size(), "matching test case"_sr);
9754+ } else {
9755+ out << pluralise(tests.size(), "test case"_sr);
9756+ }
9757+ out << "\n\n" << std::flush;
9758+ }
9759+
9760+ namespace {
9761+ class SummaryColumn {
9762+ public:
9763+ SummaryColumn( std::string suffix, Colour::Code colour ):
9764+ m_suffix( CATCH_MOVE( suffix ) ), m_colour( colour ) {}
9765+
9766+ SummaryColumn&& addRow( std::uint64_t count ) && {
9767+ std::string row = std::to_string(count);
9768+ auto const new_width = std::max( m_width, row.size() );
9769+ if ( new_width > m_width ) {
9770+ for ( auto& oldRow : m_rows ) {
9771+ oldRow.insert( 0, new_width - m_width, ' ' );
9772+ }
9773+ } else {
9774+ row.insert( 0, m_width - row.size(), ' ' );
9775+ }
9776+ m_width = new_width;
9777+ m_rows.push_back( row );
9778+ return std::move( *this );
9779+ }
9780+
9781+ std::string const& getSuffix() const { return m_suffix; }
9782+ Colour::Code getColour() const { return m_colour; }
9783+ std::string const& getRow( std::size_t index ) const {
9784+ return m_rows[index];
9785+ }
9786+
9787+ private:
9788+ std::string m_suffix;
9789+ Colour::Code m_colour;
9790+ std::size_t m_width = 0;
9791+ std::vector<std::string> m_rows;
9792+ };
9793+
9794+ void printSummaryRow( std::ostream& stream,
9795+ ColourImpl& colour,
9796+ StringRef label,
9797+ std::vector<SummaryColumn> const& cols,
9798+ std::size_t row ) {
9799+ for ( auto const& col : cols ) {
9800+ auto const& value = col.getRow( row );
9801+ auto const& suffix = col.getSuffix();
9802+ if ( suffix.empty() ) {
9803+ stream << label << ": ";
9804+ if ( value != "0" ) {
9805+ stream << value;
9806+ } else {
9807+ stream << colour.guardColour( Colour::Warning )
9808+ << "- none -";
9809+ }
9810+ } else if ( value != "0" ) {
9811+ stream << colour.guardColour( Colour::LightGrey ) << " | "
9812+ << colour.guardColour( col.getColour() ) << value
9813+ << ' ' << suffix;
9814+ }
9815+ }
9816+ stream << '\n';
9817+ }
9818+ } // namespace
9819+
9820+ void printTestRunTotals( std::ostream& stream,
9821+ ColourImpl& streamColour,
9822+ Totals const& totals ) {
9823+ if ( totals.testCases.total() == 0 ) {
9824+ stream << streamColour.guardColour( Colour::Warning )
9825+ << "No tests ran\n";
9826+ return;
9827+ }
9828+
9829+ if ( totals.assertions.total() > 0 && totals.testCases.allPassed() ) {
9830+ stream << streamColour.guardColour( Colour::ResultSuccess )
9831+ << "All tests passed";
9832+ stream << " ("
9833+ << pluralise( totals.assertions.passed, "assertion"_sr )
9834+ << " in "
9835+ << pluralise( totals.testCases.passed, "test case"_sr )
9836+ << ')' << '\n';
9837+ return;
9838+ }
9839+
9840+ std::vector<SummaryColumn> columns;
9841+ // Don't include "skipped assertions" in total count
9842+ const auto totalAssertionCount =
9843+ totals.assertions.total() - totals.assertions.skipped;
9844+ columns.push_back( SummaryColumn( "", Colour::None )
9845+ .addRow( totals.testCases.total() )
9846+ .addRow( totalAssertionCount ) );
9847+ columns.push_back( SummaryColumn( "passed", Colour::Success )
9848+ .addRow( totals.testCases.passed )
9849+ .addRow( totals.assertions.passed ) );
9850+ columns.push_back( SummaryColumn( "failed", Colour::ResultError )
9851+ .addRow( totals.testCases.failed )
9852+ .addRow( totals.assertions.failed ) );
9853+ columns.push_back( SummaryColumn( "skipped", Colour::Skip )
9854+ .addRow( totals.testCases.skipped )
9855+ // Don't print "skipped assertions"
9856+ .addRow( 0 ) );
9857+ columns.push_back(
9858+ SummaryColumn( "failed as expected", Colour::ResultExpectedFailure )
9859+ .addRow( totals.testCases.failedButOk )
9860+ .addRow( totals.assertions.failedButOk ) );
9861+ printSummaryRow( stream, streamColour, "test cases"_sr, columns, 0 );
9862+ printSummaryRow( stream, streamColour, "assertions"_sr, columns, 1 );
9863+ }
9864+
9865+} // namespace Catch
9866+
9867+
9868+//
9869+
9870+namespace Catch {
9871+ namespace {
9872+ void writeSourceInfo( JsonObjectWriter& writer,
9873+ SourceLineInfo const& sourceInfo ) {
9874+ auto source_location_writer =
9875+ writer.write( "source-location"_sr ).writeObject();
9876+ source_location_writer.write( "filename"_sr )
9877+ .write( sourceInfo.file );
9878+ source_location_writer.write( "line"_sr ).write( sourceInfo.line );
9879+ }
9880+
9881+ void writeTags( JsonArrayWriter writer, std::vector<Tag> const& tags ) {
9882+ for ( auto const& tag : tags ) {
9883+ writer.write( tag.original );
9884+ }
9885+ }
9886+
9887+ void writeProperties( JsonArrayWriter writer,
9888+ TestCaseInfo const& info ) {
9889+ if ( info.isHidden() ) { writer.write( "is-hidden"_sr ); }
9890+ if ( info.okToFail() ) { writer.write( "ok-to-fail"_sr ); }
9891+ if ( info.expectedToFail() ) {
9892+ writer.write( "expected-to-fail"_sr );
9893+ }
9894+ if ( info.throws() ) { writer.write( "throws"_sr ); }
9895+ }
9896+
9897+ } // namespace
9898+
9899+ JsonReporter::JsonReporter( ReporterConfig&& config ):
9900+ StreamingReporterBase{ CATCH_MOVE( config ) } {
9901+
9902+ m_preferences.shouldRedirectStdOut = true;
9903+ // TBD: Do we want to report all assertions? XML reporter does
9904+ // not, but for machine-parseable reporters I think the answer
9905+ // should be yes.
9906+ m_preferences.shouldReportAllAssertions = true;
9907+
9908+ m_objectWriters.emplace( m_stream );
9909+ m_writers.emplace( Writer::Object );
9910+ auto& writer = m_objectWriters.top();
9911+
9912+ writer.write( "version"_sr ).write( 1 );
9913+
9914+ {
9915+ auto metadata_writer = writer.write( "metadata"_sr ).writeObject();
9916+ metadata_writer.write( "name"_sr ).write( m_config->name() );
9917+ metadata_writer.write( "rng-seed"_sr ).write( m_config->rngSeed() );
9918+ metadata_writer.write( "catch2-version"_sr )
9919+ .write( libraryVersion() );
9920+ if ( m_config->testSpec().hasFilters() ) {
9921+ metadata_writer.write( "filters"_sr )
9922+ .write( m_config->testSpec() );
9923+ }
9924+ }
9925+ }
9926+
9927+ JsonReporter::~JsonReporter() {
9928+ endListing();
9929+ // TODO: Ensure this closes the top level object, add asserts
9930+ assert( m_writers.size() == 1 && "Only the top level object should be open" );
9931+ assert( m_writers.top() == Writer::Object );
9932+ endObject();
9933+ m_stream << '\n' << std::flush;
9934+ assert( m_writers.empty() );
9935+ }
9936+
9937+ JsonArrayWriter& JsonReporter::startArray() {
9938+ m_arrayWriters.emplace( m_arrayWriters.top().writeArray() );
9939+ m_writers.emplace( Writer::Array );
9940+ return m_arrayWriters.top();
9941+ }
9942+ JsonArrayWriter& JsonReporter::startArray( StringRef key ) {
9943+ m_arrayWriters.emplace(
9944+ m_objectWriters.top().write( key ).writeArray() );
9945+ m_writers.emplace( Writer::Array );
9946+ return m_arrayWriters.top();
9947+ }
9948+
9949+ JsonObjectWriter& JsonReporter::startObject() {
9950+ m_objectWriters.emplace( m_arrayWriters.top().writeObject() );
9951+ m_writers.emplace( Writer::Object );
9952+ return m_objectWriters.top();
9953+ }
9954+ JsonObjectWriter& JsonReporter::startObject( StringRef key ) {
9955+ m_objectWriters.emplace(
9956+ m_objectWriters.top().write( key ).writeObject() );
9957+ m_writers.emplace( Writer::Object );
9958+ return m_objectWriters.top();
9959+ }
9960+
9961+ void JsonReporter::endObject() {
9962+ assert( isInside( Writer::Object ) );
9963+ m_objectWriters.pop();
9964+ m_writers.pop();
9965+ }
9966+ void JsonReporter::endArray() {
9967+ assert( isInside( Writer::Array ) );
9968+ m_arrayWriters.pop();
9969+ m_writers.pop();
9970+ }
9971+
9972+ bool JsonReporter::isInside( Writer writer ) {
9973+ return !m_writers.empty() && m_writers.top() == writer;
9974+ }
9975+
9976+ void JsonReporter::startListing() {
9977+ if ( !m_startedListing ) { startObject( "listings"_sr ); }
9978+ m_startedListing = true;
9979+ }
9980+ void JsonReporter::endListing() {
9981+ if ( m_startedListing ) { endObject(); }
9982+ m_startedListing = false;
9983+ }
9984+
9985+ std::string JsonReporter::getDescription() {
9986+ return "Outputs listings as JSON. Test listing is Work-in-Progress!";
9987+ }
9988+
9989+ void JsonReporter::testRunStarting( TestRunInfo const& runInfo ) {
9990+ StreamingReporterBase::testRunStarting( runInfo );
9991+ endListing();
9992+
9993+ assert( isInside( Writer::Object ) );
9994+ startObject( "test-run"_sr );
9995+ startArray( "test-cases"_sr );
9996+ }
9997+
9998+ static void writeCounts( JsonObjectWriter&& writer, Counts const& counts ) {
9999+ writer.write( "passed"_sr ).write( counts.passed );
10000+ writer.write( "failed"_sr ).write( counts.failed );
10001+ writer.write( "fail-but-ok"_sr ).write( counts.failedButOk );
10002+ writer.write( "skipped"_sr ).write( counts.skipped );
10003+ }
10004+
10005+ void JsonReporter::testRunEnded(TestRunStats const& runStats) {
10006+ assert( isInside( Writer::Array ) );
10007+ // End "test-cases"
10008+ endArray();
10009+
10010+ {
10011+ auto totals =
10012+ m_objectWriters.top().write( "totals"_sr ).writeObject();
10013+ writeCounts( totals.write( "assertions"_sr ).writeObject(),
10014+ runStats.totals.assertions );
10015+ writeCounts( totals.write( "test-cases"_sr ).writeObject(),
10016+ runStats.totals.testCases );
10017+ }
10018+
10019+ // End the "test-run" object
10020+ endObject();
10021+ }
10022+
10023+ void JsonReporter::testCaseStarting( TestCaseInfo const& tcInfo ) {
10024+ StreamingReporterBase::testCaseStarting( tcInfo );
10025+
10026+ assert( isInside( Writer::Array ) &&
10027+ "We should be in the 'test-cases' array" );
10028+ startObject();
10029+ // "test-info" prelude
10030+ {
10031+ auto testInfo =
10032+ m_objectWriters.top().write( "test-info"_sr ).writeObject();
10033+ // TODO: handle testName vs className!!
10034+ testInfo.write( "name"_sr ).write( tcInfo.name );
10035+ writeSourceInfo(testInfo, tcInfo.lineInfo);
10036+ writeTags( testInfo.write( "tags"_sr ).writeArray(), tcInfo.tags );
10037+ writeProperties( testInfo.write( "properties"_sr ).writeArray(),
10038+ tcInfo );
10039+ }
10040+
10041+
10042+ // Start the array for individual test runs (testCasePartial pairs)
10043+ startArray( "runs"_sr );
10044+ }
10045+
10046+ void JsonReporter::testCaseEnded( TestCaseStats const& tcStats ) {
10047+ StreamingReporterBase::testCaseEnded( tcStats );
10048+
10049+ // We need to close the 'runs' array before finishing the test case
10050+ assert( isInside( Writer::Array ) );
10051+ endArray();
10052+
10053+ {
10054+ auto totals =
10055+ m_objectWriters.top().write( "totals"_sr ).writeObject();
10056+ writeCounts( totals.write( "assertions"_sr ).writeObject(),
10057+ tcStats.totals.assertions );
10058+ // We do not write the test case totals, because there will always be just one test case here.
10059+ // TODO: overall "result" -> success, skip, fail here? Or in partial result?
10060+ }
10061+ // We do not write out stderr/stdout, because we instead wrote those out in partial runs
10062+
10063+ // TODO: aborting?
10064+
10065+ // And we also close this test case's object
10066+ assert( isInside( Writer::Object ) );
10067+ endObject();
10068+ }
10069+
10070+ void JsonReporter::testCasePartialStarting( TestCaseInfo const& /*tcInfo*/,
10071+ uint64_t index ) {
10072+ startObject();
10073+ m_objectWriters.top().write( "run-idx"_sr ).write( index );
10074+ startArray( "path"_sr );
10075+ // TODO: we want to delay most of the printing to the 'root' section
10076+ // TODO: childSection key name?
10077+ }
10078+
10079+ void JsonReporter::testCasePartialEnded( TestCaseStats const& tcStats,
10080+ uint64_t /*index*/ ) {
10081+ // Fixme: the top level section handles this.
10082+ //// path object
10083+ endArray();
10084+ if ( !tcStats.stdOut.empty() ) {
10085+ m_objectWriters.top()
10086+ .write( "captured-stdout"_sr )
10087+ .write( tcStats.stdOut );
10088+ }
10089+ if ( !tcStats.stdErr.empty() ) {
10090+ m_objectWriters.top()
10091+ .write( "captured-stderr"_sr )
10092+ .write( tcStats.stdErr );
10093+ }
10094+ {
10095+ auto totals =
10096+ m_objectWriters.top().write( "totals"_sr ).writeObject();
10097+ writeCounts( totals.write( "assertions"_sr ).writeObject(),
10098+ tcStats.totals.assertions );
10099+ // We do not write the test case totals, because there will
10100+ // always be just one test case here.
10101+ // TODO: overall "result" -> success, skip, fail here? Or in
10102+ // partial result?
10103+ }
10104+ // TODO: aborting?
10105+ // run object
10106+ endObject();
10107+ }
10108+
10109+ void JsonReporter::sectionStarting( SectionInfo const& sectionInfo ) {
10110+ assert( isInside( Writer::Array ) &&
10111+ "Section should always start inside an object" );
10112+ // We want to nest top level sections, even though it shares name
10113+ // and source loc with the TEST_CASE
10114+ auto& sectionObject = startObject();
10115+ sectionObject.write( "kind"_sr ).write( "section"_sr );
10116+ sectionObject.write( "name"_sr ).write( sectionInfo.name );
10117+ writeSourceInfo( m_objectWriters.top(), sectionInfo.lineInfo );
10118+
10119+
10120+ // TBD: Do we want to create this event lazily? It would become
10121+ // rather complex, but we could do it, and it would look
10122+ // better for empty sections. OTOH, empty sections should
10123+ // be rare.
10124+ startArray( "path"_sr );
10125+ }
10126+ void JsonReporter::sectionEnded( SectionStats const& /*sectionStats */) {
10127+ // End the subpath array
10128+ endArray();
10129+ // TODO: metadata
10130+ // TODO: what info do we have here?
10131+
10132+ // End the section object
10133+ endObject();
10134+ }
10135+
10136+ void JsonReporter::assertionStarting( AssertionInfo const& /*assertionInfo*/ ) {}
10137+ void JsonReporter::assertionEnded( AssertionStats const& assertionStats ) {
10138+ // TODO: There is lot of different things to handle here, but
10139+ // we can fill it in later, after we show that the basic
10140+ // outline and streaming reporter impl works well enough.
10141+ //if ( !m_config->includeSuccessfulResults()
10142+ // && assertionStats.assertionResult.isOk() ) {
10143+ // return;
10144+ //}
10145+ assert( isInside( Writer::Array ) );
10146+ auto assertionObject = m_arrayWriters.top().writeObject();
10147+
10148+ assertionObject.write( "kind"_sr ).write( "assertion"_sr );
10149+ writeSourceInfo( assertionObject,
10150+ assertionStats.assertionResult.getSourceInfo() );
10151+ assertionObject.write( "status"_sr )
10152+ .write( assertionStats.assertionResult.isOk() );
10153+ // TODO: handling of result.
10154+ // TODO: messages
10155+ // TODO: totals?
10156+ }
10157+
10158+
10159+ void JsonReporter::benchmarkPreparing( StringRef name ) { (void)name; }
10160+ void JsonReporter::benchmarkStarting( BenchmarkInfo const& ) {}
10161+ void JsonReporter::benchmarkEnded( BenchmarkStats<> const& ) {}
10162+ void JsonReporter::benchmarkFailed( StringRef error ) { (void)error; }
10163+
10164+ void JsonReporter::listReporters(
10165+ std::vector<ReporterDescription> const& descriptions ) {
10166+ startListing();
10167+
10168+ auto writer =
10169+ m_objectWriters.top().write( "reporters"_sr ).writeArray();
10170+ for ( auto const& desc : descriptions ) {
10171+ auto desc_writer = writer.writeObject();
10172+ desc_writer.write( "name"_sr ).write( desc.name );
10173+ desc_writer.write( "description"_sr ).write( desc.description );
10174+ }
10175+ }
10176+ void JsonReporter::listListeners(
10177+ std::vector<ListenerDescription> const& descriptions ) {
10178+ startListing();
10179+
10180+ auto writer =
10181+ m_objectWriters.top().write( "listeners"_sr ).writeArray();
10182+
10183+ for ( auto const& desc : descriptions ) {
10184+ auto desc_writer = writer.writeObject();
10185+ desc_writer.write( "name"_sr ).write( desc.name );
10186+ desc_writer.write( "description"_sr ).write( desc.description );
10187+ }
10188+ }
10189+ void JsonReporter::listTests( std::vector<TestCaseHandle> const& tests ) {
10190+ startListing();
10191+
10192+ auto writer = m_objectWriters.top().write( "tests"_sr ).writeArray();
10193+
10194+ for ( auto const& test : tests ) {
10195+ auto desc_writer = writer.writeObject();
10196+ auto const& info = test.getTestCaseInfo();
10197+
10198+ desc_writer.write( "name"_sr ).write( info.name );
10199+ desc_writer.write( "class-name"_sr ).write( info.className );
10200+ {
10201+ auto tag_writer = desc_writer.write( "tags"_sr ).writeArray();
10202+ for ( auto const& tag : info.tags ) {
10203+ tag_writer.write( tag.original );
10204+ }
10205+ }
10206+ writeSourceInfo( desc_writer, info.lineInfo );
10207+ }
10208+ }
10209+ void JsonReporter::listTags( std::vector<TagInfo> const& tags ) {
10210+ startListing();
10211+
10212+ auto writer = m_objectWriters.top().write( "tags"_sr ).writeArray();
10213+ for ( auto const& tag : tags ) {
10214+ auto tag_writer = writer.writeObject();
10215+ {
10216+ auto aliases_writer =
10217+ tag_writer.write( "aliases"_sr ).writeArray();
10218+ for ( auto alias : tag.spellings ) {
10219+ aliases_writer.write( alias );
10220+ }
10221+ }
10222+ tag_writer.write( "count"_sr ).write( tag.count );
10223+ }
10224+ }
10225+} // namespace Catch
10226+
10227+
10228+
10229+
10230+#include <cassert>
10231+#include <ctime>
10232+#include <algorithm>
10233+#include <iomanip>
10234+
10235+namespace Catch {
10236+
10237+ namespace {
10238+ std::string getCurrentTimestamp() {
10239+ time_t rawtime;
10240+ std::time(&rawtime);
10241+
10242+ std::tm timeInfo = {};
10243+#if defined (_MSC_VER) || defined (__MINGW32__)
10244+ gmtime_s(&timeInfo, &rawtime);
10245+#elif defined (CATCH_PLATFORM_PLAYSTATION)
10246+ gmtime_s(&rawtime, &timeInfo);
10247+#elif defined (__IAR_SYSTEMS_ICC__)
10248+ timeInfo = *std::gmtime(&rawtime);
10249+#else
10250+ gmtime_r(&rawtime, &timeInfo);
10251+#endif
10252+
10253+ auto const timeStampSize = sizeof("2017-01-16T17:06:45Z");
10254+ char timeStamp[timeStampSize];
10255+ const char * const fmt = "%Y-%m-%dT%H:%M:%SZ";
10256+
10257+ std::strftime(timeStamp, timeStampSize, fmt, &timeInfo);
10258+
10259+ return std::string(timeStamp, timeStampSize - 1);
10260+ }
10261+
10262+ std::string fileNameTag(std::vector<Tag> const& tags) {
10263+ auto it = std::find_if(begin(tags),
10264+ end(tags),
10265+ [] (Tag const& tag) {
10266+ return tag.original.size() > 0
10267+ && tag.original[0] == '#'; });
10268+ if (it != tags.end()) {
10269+ return static_cast<std::string>(
10270+ it->original.substr(1, it->original.size() - 1)
10271+ );
10272+ }
10273+ return std::string();
10274+ }
10275+
10276+ // Formats the duration in seconds to 3 decimal places.
10277+ // This is done because some genius defined Maven Surefire schema
10278+ // in a way that only accepts 3 decimal places, and tools like
10279+ // Jenkins use that schema for validation JUnit reporter output.
10280+ std::string formatDuration( double seconds ) {
10281+ ReusableStringStream rss;
10282+ rss << std::fixed << std::setprecision( 3 ) << seconds;
10283+ return rss.str();
10284+ }
10285+
10286+ static void normalizeNamespaceMarkers(std::string& str) {
10287+ std::size_t pos = str.find( "::" );
10288+ while ( pos != std::string::npos ) {
10289+ str.replace( pos, 2, "." );
10290+ pos += 1;
10291+ pos = str.find( "::", pos );
10292+ }
10293+ }
10294+
10295+ } // anonymous namespace
10296+
10297+ JunitReporter::JunitReporter( ReporterConfig&& _config )
10298+ : CumulativeReporterBase( CATCH_MOVE(_config) ),
10299+ xml( m_stream )
10300+ {
10301+ m_preferences.shouldRedirectStdOut = true;
10302+ m_preferences.shouldReportAllAssertions = true;
10303+ m_shouldStoreSuccesfulAssertions = false;
10304+ }
10305+
10306+ std::string JunitReporter::getDescription() {
10307+ return "Reports test results in an XML format that looks like Ant's junitreport target";
10308+ }
10309+
10310+ void JunitReporter::testRunStarting( TestRunInfo const& runInfo ) {
10311+ CumulativeReporterBase::testRunStarting( runInfo );
10312+ xml.startElement( "testsuites" );
10313+ suiteTimer.start();
10314+ stdOutForSuite.clear();
10315+ stdErrForSuite.clear();
10316+ unexpectedExceptions = 0;
10317+ }
10318+
10319+ void JunitReporter::testCaseStarting( TestCaseInfo const& testCaseInfo ) {
10320+ m_okToFail = testCaseInfo.okToFail();
10321+ }
10322+
10323+ void JunitReporter::assertionEnded( AssertionStats const& assertionStats ) {
10324+ if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail )
10325+ unexpectedExceptions++;
10326+ CumulativeReporterBase::assertionEnded( assertionStats );
10327+ }
10328+
10329+ void JunitReporter::testCaseEnded( TestCaseStats const& testCaseStats ) {
10330+ stdOutForSuite += testCaseStats.stdOut;
10331+ stdErrForSuite += testCaseStats.stdErr;
10332+ CumulativeReporterBase::testCaseEnded( testCaseStats );
10333+ }
10334+
10335+ void JunitReporter::testRunEndedCumulative() {
10336+ const auto suiteTime = suiteTimer.getElapsedSeconds();
10337+ writeRun( *m_testRun, suiteTime );
10338+ xml.endElement();
10339+ }
10340+
10341+ void JunitReporter::writeRun( TestRunNode const& testRunNode, double suiteTime ) {
10342+ XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" );
10343+
10344+ TestRunStats const& stats = testRunNode.value;
10345+ xml.writeAttribute( "name"_sr, stats.runInfo.name );
10346+ xml.writeAttribute( "errors"_sr, unexpectedExceptions );
10347+ xml.writeAttribute( "failures"_sr, stats.totals.assertions.failed-unexpectedExceptions );
10348+ xml.writeAttribute( "skipped"_sr, stats.totals.assertions.skipped );
10349+ xml.writeAttribute( "tests"_sr, stats.totals.assertions.total() );
10350+ xml.writeAttribute( "hostname"_sr, "tbd"_sr ); // !TBD
10351+ if( m_config->showDurations() == ShowDurations::Never )
10352+ xml.writeAttribute( "time"_sr, ""_sr );
10353+ else
10354+ xml.writeAttribute( "time"_sr, formatDuration( suiteTime ) );
10355+ xml.writeAttribute( "timestamp"_sr, getCurrentTimestamp() );
10356+
10357+ // Write properties
10358+ {
10359+ auto properties = xml.scopedElement("properties");
10360+ xml.scopedElement("property")
10361+ .writeAttribute("name"_sr, "random-seed"_sr)
10362+ .writeAttribute("value"_sr, m_config->rngSeed());
10363+ if (m_config->testSpec().hasFilters()) {
10364+ xml.scopedElement("property")
10365+ .writeAttribute("name"_sr, "filters"_sr)
10366+ .writeAttribute("value"_sr, m_config->testSpec());
10367+ }
10368+ }
10369+
10370+ // Write test cases
10371+ for( auto const& child : testRunNode.children )
10372+ writeTestCase( *child );
10373+
10374+ xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite ), XmlFormatting::Newline );
10375+ xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite ), XmlFormatting::Newline );
10376+ }
10377+
10378+ void JunitReporter::writeTestCase( TestCaseNode const& testCaseNode ) {
10379+ TestCaseStats const& stats = testCaseNode.value;
10380+
10381+ // All test cases have exactly one section - which represents the
10382+ // test case itself. That section may have 0-n nested sections
10383+ assert( testCaseNode.children.size() == 1 );
10384+ SectionNode const& rootSection = *testCaseNode.children.front();
10385+
10386+ std::string className =
10387+ static_cast<std::string>( stats.testInfo->className );
10388+
10389+ if( className.empty() ) {
10390+ className = fileNameTag(stats.testInfo->tags);
10391+ if ( className.empty() ) {
10392+ className = "global";
10393+ }
10394+ }
10395+
10396+ if ( !m_config->name().empty() )
10397+ className = static_cast<std::string>(m_config->name()) + '.' + className;
10398+
10399+ normalizeNamespaceMarkers(className);
10400+
10401+ writeSection( className, "", rootSection, stats.testInfo->okToFail() );
10402+ }
10403+
10404+ void JunitReporter::writeSection( std::string const& className,
10405+ std::string const& rootName,
10406+ SectionNode const& sectionNode,
10407+ bool testOkToFail) {
10408+ std::string name = trim( sectionNode.stats.sectionInfo.name );
10409+ if( !rootName.empty() )
10410+ name = rootName + '/' + name;
10411+
10412+ if( sectionNode.hasAnyAssertions()
10413+ || !sectionNode.stdOut.empty()
10414+ || !sectionNode.stdErr.empty() ) {
10415+ XmlWriter::ScopedElement e = xml.scopedElement( "testcase" );
10416+ if( className.empty() ) {
10417+ xml.writeAttribute( "classname"_sr, name );
10418+ xml.writeAttribute( "name"_sr, "root"_sr );
10419+ }
10420+ else {
10421+ xml.writeAttribute( "classname"_sr, className );
10422+ xml.writeAttribute( "name"_sr, name );
10423+ }
10424+ xml.writeAttribute( "time"_sr, formatDuration( sectionNode.stats.durationInSeconds ) );
10425+ // This is not ideal, but it should be enough to mimic gtest's
10426+ // junit output.
10427+ // Ideally the JUnit reporter would also handle `skipTest`
10428+ // events and write those out appropriately.
10429+ xml.writeAttribute( "status"_sr, "run"_sr );
10430+
10431+ if (sectionNode.stats.assertions.failedButOk) {
10432+ xml.scopedElement("skipped")
10433+ .writeAttribute("message", "TEST_CASE tagged with !mayfail");
10434+ }
10435+
10436+ writeAssertions( sectionNode );
10437+
10438+
10439+ if( !sectionNode.stdOut.empty() )
10440+ xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), XmlFormatting::Newline );
10441+ if( !sectionNode.stdErr.empty() )
10442+ xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), XmlFormatting::Newline );
10443+ }
10444+ for( auto const& childNode : sectionNode.childSections )
10445+ if( className.empty() )
10446+ writeSection( name, "", *childNode, testOkToFail );
10447+ else
10448+ writeSection( className, name, *childNode, testOkToFail );
10449+ }
10450+
10451+ void JunitReporter::writeAssertions( SectionNode const& sectionNode ) {
10452+ for (auto const& assertionOrBenchmark : sectionNode.assertionsAndBenchmarks) {
10453+ if (assertionOrBenchmark.isAssertion()) {
10454+ writeAssertion(assertionOrBenchmark.asAssertion());
10455+ }
10456+ }
10457+ }
10458+
10459+ void JunitReporter::writeAssertion( AssertionStats const& stats ) {
10460+ AssertionResult const& result = stats.assertionResult;
10461+ if ( !result.isOk() ||
10462+ result.getResultType() == ResultWas::ExplicitSkip ) {
10463+ std::string elementName;
10464+ switch( result.getResultType() ) {
10465+ case ResultWas::ThrewException:
10466+ case ResultWas::FatalErrorCondition:
10467+ elementName = "error";
10468+ break;
10469+ case ResultWas::ExplicitFailure:
10470+ case ResultWas::ExpressionFailed:
10471+ case ResultWas::DidntThrowException:
10472+ elementName = "failure";
10473+ break;
10474+ case ResultWas::ExplicitSkip:
10475+ elementName = "skipped";
10476+ break;
10477+ // We should never see these here:
10478+ case ResultWas::Info:
10479+ case ResultWas::Warning:
10480+ case ResultWas::Ok:
10481+ case ResultWas::Unknown:
10482+ case ResultWas::FailureBit:
10483+ case ResultWas::Exception:
10484+ elementName = "internalError";
10485+ break;
10486+ }
10487+
10488+ XmlWriter::ScopedElement e = xml.scopedElement( elementName );
10489+
10490+ xml.writeAttribute( "message"_sr, result.getExpression() );
10491+ xml.writeAttribute( "type"_sr, result.getTestMacroName() );
10492+
10493+ ReusableStringStream rss;
10494+ if ( result.getResultType() == ResultWas::ExplicitSkip ) {
10495+ rss << "SKIPPED\n";
10496+ } else {
10497+ rss << "FAILED" << ":\n";
10498+ if (result.hasExpression()) {
10499+ rss << " ";
10500+ rss << result.getExpressionInMacro();
10501+ rss << '\n';
10502+ }
10503+ if (result.hasExpandedExpression()) {
10504+ rss << "with expansion:\n";
10505+ rss << TextFlow::Column(result.getExpandedExpression()).indent(2) << '\n';
10506+ }
10507+ }
10508+
10509+ if( result.hasMessage() )
10510+ rss << result.getMessage() << '\n';
10511+ for( auto const& msg : stats.infoMessages )
10512+ if( msg.type == ResultWas::Info )
10513+ rss << msg.message << '\n';
10514+
10515+ rss << "at " << result.getSourceInfo();
10516+ xml.writeText( rss.str(), XmlFormatting::Newline );
10517+ }
10518+ }
10519+
10520+} // end namespace Catch
10521+
10522+
10523+
10524+
10525+#include <ostream>
10526+
10527+namespace Catch {
10528+ void MultiReporter::updatePreferences(IEventListener const& reporterish) {
10529+ m_preferences.shouldRedirectStdOut |=
10530+ reporterish.getPreferences().shouldRedirectStdOut;
10531+ m_preferences.shouldReportAllAssertions |=
10532+ reporterish.getPreferences().shouldReportAllAssertions;
10533+ }
10534+
10535+ void MultiReporter::addListener( IEventListenerPtr&& listener ) {
10536+ updatePreferences(*listener);
10537+ m_reporterLikes.insert(m_reporterLikes.begin() + m_insertedListeners, CATCH_MOVE(listener) );
10538+ ++m_insertedListeners;
10539+ }
10540+
10541+ void MultiReporter::addReporter( IEventListenerPtr&& reporter ) {
10542+ updatePreferences(*reporter);
10543+
10544+ // We will need to output the captured stdout if there are reporters
10545+ // that do not want it captured.
10546+ // We do not consider listeners, because it is generally assumed that
10547+ // listeners are output-transparent, even though they can ask for stdout
10548+ // capture to do something with it.
10549+ m_haveNoncapturingReporters |= !reporter->getPreferences().shouldRedirectStdOut;
10550+
10551+ // Reporters can always be placed to the back without breaking the
10552+ // reporting order
10553+ m_reporterLikes.push_back( CATCH_MOVE( reporter ) );
10554+ }
10555+
10556+ void MultiReporter::noMatchingTestCases( StringRef unmatchedSpec ) {
10557+ for ( auto& reporterish : m_reporterLikes ) {
10558+ reporterish->noMatchingTestCases( unmatchedSpec );
10559+ }
10560+ }
10561+
10562+ void MultiReporter::fatalErrorEncountered( StringRef error ) {
10563+ for ( auto& reporterish : m_reporterLikes ) {
10564+ reporterish->fatalErrorEncountered( error );
10565+ }
10566+ }
10567+
10568+ void MultiReporter::reportInvalidTestSpec( StringRef arg ) {
10569+ for ( auto& reporterish : m_reporterLikes ) {
10570+ reporterish->reportInvalidTestSpec( arg );
10571+ }
10572+ }
10573+
10574+ void MultiReporter::benchmarkPreparing( StringRef name ) {
10575+ for (auto& reporterish : m_reporterLikes) {
10576+ reporterish->benchmarkPreparing(name);
10577+ }
10578+ }
10579+ void MultiReporter::benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) {
10580+ for ( auto& reporterish : m_reporterLikes ) {
10581+ reporterish->benchmarkStarting( benchmarkInfo );
10582+ }
10583+ }
10584+ void MultiReporter::benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) {
10585+ for ( auto& reporterish : m_reporterLikes ) {
10586+ reporterish->benchmarkEnded( benchmarkStats );
10587+ }
10588+ }
10589+
10590+ void MultiReporter::benchmarkFailed( StringRef error ) {
10591+ for (auto& reporterish : m_reporterLikes) {
10592+ reporterish->benchmarkFailed(error);
10593+ }
10594+ }
10595+
10596+ void MultiReporter::testRunStarting( TestRunInfo const& testRunInfo ) {
10597+ for ( auto& reporterish : m_reporterLikes ) {
10598+ reporterish->testRunStarting( testRunInfo );
10599+ }
10600+ }
10601+
10602+ void MultiReporter::testCaseStarting( TestCaseInfo const& testInfo ) {
10603+ for ( auto& reporterish : m_reporterLikes ) {
10604+ reporterish->testCaseStarting( testInfo );
10605+ }
10606+ }
10607+
10608+ void
10609+ MultiReporter::testCasePartialStarting( TestCaseInfo const& testInfo,
10610+ uint64_t partNumber ) {
10611+ for ( auto& reporterish : m_reporterLikes ) {
10612+ reporterish->testCasePartialStarting( testInfo, partNumber );
10613+ }
10614+ }
10615+
10616+ void MultiReporter::sectionStarting( SectionInfo const& sectionInfo ) {
10617+ for ( auto& reporterish : m_reporterLikes ) {
10618+ reporterish->sectionStarting( sectionInfo );
10619+ }
10620+ }
10621+
10622+ void MultiReporter::assertionStarting( AssertionInfo const& assertionInfo ) {
10623+ for ( auto& reporterish : m_reporterLikes ) {
10624+ reporterish->assertionStarting( assertionInfo );
10625+ }
10626+ }
10627+
10628+ void MultiReporter::assertionEnded( AssertionStats const& assertionStats ) {
10629+ const bool reportByDefault =
10630+ assertionStats.assertionResult.getResultType() != ResultWas::Ok ||
10631+ m_config->includeSuccessfulResults();
10632+
10633+ for ( auto & reporterish : m_reporterLikes ) {
10634+ if ( reportByDefault ||
10635+ reporterish->getPreferences().shouldReportAllAssertions ) {
10636+ reporterish->assertionEnded( assertionStats );
10637+ }
10638+ }
10639+ }
10640+
10641+ void MultiReporter::sectionEnded( SectionStats const& sectionStats ) {
10642+ for ( auto& reporterish : m_reporterLikes ) {
10643+ reporterish->sectionEnded( sectionStats );
10644+ }
10645+ }
10646+
10647+ void MultiReporter::testCasePartialEnded( TestCaseStats const& testStats,
10648+ uint64_t partNumber ) {
10649+ if ( m_preferences.shouldRedirectStdOut &&
10650+ m_haveNoncapturingReporters ) {
10651+ if ( !testStats.stdOut.empty() ) {
10652+ Catch::cout() << testStats.stdOut << std::flush;
10653+ }
10654+ if ( !testStats.stdErr.empty() ) {
10655+ Catch::cerr() << testStats.stdErr << std::flush;
10656+ }
10657+ }
10658+
10659+ for ( auto& reporterish : m_reporterLikes ) {
10660+ reporterish->testCasePartialEnded( testStats, partNumber );
10661+ }
10662+ }
10663+
10664+ void MultiReporter::testCaseEnded( TestCaseStats const& testCaseStats ) {
10665+ for ( auto& reporterish : m_reporterLikes ) {
10666+ reporterish->testCaseEnded( testCaseStats );
10667+ }
10668+ }
10669+
10670+ void MultiReporter::testRunEnded( TestRunStats const& testRunStats ) {
10671+ for ( auto& reporterish : m_reporterLikes ) {
10672+ reporterish->testRunEnded( testRunStats );
10673+ }
10674+ }
10675+
10676+
10677+ void MultiReporter::skipTest( TestCaseInfo const& testInfo ) {
10678+ for ( auto& reporterish : m_reporterLikes ) {
10679+ reporterish->skipTest( testInfo );
10680+ }
10681+ }
10682+
10683+ void MultiReporter::listReporters(std::vector<ReporterDescription> const& descriptions) {
10684+ for (auto& reporterish : m_reporterLikes) {
10685+ reporterish->listReporters(descriptions);
10686+ }
10687+ }
10688+
10689+ void MultiReporter::listListeners(
10690+ std::vector<ListenerDescription> const& descriptions ) {
10691+ for ( auto& reporterish : m_reporterLikes ) {
10692+ reporterish->listListeners( descriptions );
10693+ }
10694+ }
10695+
10696+ void MultiReporter::listTests(std::vector<TestCaseHandle> const& tests) {
10697+ for (auto& reporterish : m_reporterLikes) {
10698+ reporterish->listTests(tests);
10699+ }
10700+ }
10701+
10702+ void MultiReporter::listTags(std::vector<TagInfo> const& tags) {
10703+ for (auto& reporterish : m_reporterLikes) {
10704+ reporterish->listTags(tags);
10705+ }
10706+ }
10707+
10708+} // end namespace Catch
10709+
10710+
10711+
10712+
10713+
10714+namespace Catch {
10715+ namespace Detail {
10716+
10717+ void registerReporterImpl( std::string const& name,
10718+ IReporterFactoryPtr reporterPtr ) {
10719+ CATCH_TRY {
10720+ getMutableRegistryHub().registerReporter(
10721+ name, CATCH_MOVE( reporterPtr ) );
10722+ }
10723+ CATCH_CATCH_ALL {
10724+ // Do not throw when constructing global objects, instead
10725+ // register the exception to be processed later
10726+ getMutableRegistryHub().registerStartupException();
10727+ }
10728+ }
10729+
10730+ void registerListenerImpl( Detail::unique_ptr<EventListenerFactory> listenerFactory ) {
10731+ getMutableRegistryHub().registerListener( CATCH_MOVE(listenerFactory) );
10732+ }
10733+
10734+
10735+ } // namespace Detail
10736+} // namespace Catch
10737+
10738+
10739+
10740+
10741+#include <map>
10742+
10743+namespace Catch {
10744+
10745+ namespace {
10746+ std::string createMetadataString(IConfig const& config) {
10747+ ReusableStringStream sstr;
10748+ if ( config.testSpec().hasFilters() ) {
10749+ sstr << "filters='"
10750+ << config.testSpec()
10751+ << "' ";
10752+ }
10753+ sstr << "rng-seed=" << config.rngSeed();
10754+ return sstr.str();
10755+ }
10756+ }
10757+
10758+ void SonarQubeReporter::testRunStarting(TestRunInfo const& testRunInfo) {
10759+ CumulativeReporterBase::testRunStarting(testRunInfo);
10760+
10761+ xml.writeComment( createMetadataString( *m_config ) );
10762+ xml.startElement("testExecutions");
10763+ xml.writeAttribute("version"_sr, '1');
10764+ }
10765+
10766+ void SonarQubeReporter::writeRun( TestRunNode const& runNode ) {
10767+ std::map<StringRef, std::vector<TestCaseNode const*>> testsPerFile;
10768+
10769+ for ( auto const& child : runNode.children ) {
10770+ testsPerFile[child->value.testInfo->lineInfo.file].push_back(
10771+ child.get() );
10772+ }
10773+
10774+ for ( auto const& kv : testsPerFile ) {
10775+ writeTestFile( kv.first, kv.second );
10776+ }
10777+ }
10778+
10779+ void SonarQubeReporter::writeTestFile(StringRef filename, std::vector<TestCaseNode const*> const& testCaseNodes) {
10780+ XmlWriter::ScopedElement e = xml.scopedElement("file");
10781+ xml.writeAttribute("path"_sr, filename);
10782+
10783+ for (auto const& child : testCaseNodes)
10784+ writeTestCase(*child);
10785+ }
10786+
10787+ void SonarQubeReporter::writeTestCase(TestCaseNode const& testCaseNode) {
10788+ // All test cases have exactly one section - which represents the
10789+ // test case itself. That section may have 0-n nested sections
10790+ assert(testCaseNode.children.size() == 1);
10791+ SectionNode const& rootSection = *testCaseNode.children.front();
10792+ writeSection("", rootSection, testCaseNode.value.testInfo->okToFail());
10793+ }
10794+
10795+ void SonarQubeReporter::writeSection(std::string const& rootName, SectionNode const& sectionNode, bool okToFail) {
10796+ std::string name = trim(sectionNode.stats.sectionInfo.name);
10797+ if (!rootName.empty())
10798+ name = rootName + '/' + name;
10799+
10800+ if ( sectionNode.hasAnyAssertions()
10801+ || !sectionNode.stdOut.empty()
10802+ || !sectionNode.stdErr.empty() ) {
10803+ XmlWriter::ScopedElement e = xml.scopedElement("testCase");
10804+ xml.writeAttribute("name"_sr, name);
10805+ xml.writeAttribute("duration"_sr, static_cast<long>(sectionNode.stats.durationInSeconds * 1000));
10806+
10807+ writeAssertions(sectionNode, okToFail);
10808+ }
10809+
10810+ for (auto const& childNode : sectionNode.childSections)
10811+ writeSection(name, *childNode, okToFail);
10812+ }
10813+
10814+ void SonarQubeReporter::writeAssertions(SectionNode const& sectionNode, bool okToFail) {
10815+ for (auto const& assertionOrBenchmark : sectionNode.assertionsAndBenchmarks) {
10816+ if (assertionOrBenchmark.isAssertion()) {
10817+ writeAssertion(assertionOrBenchmark.asAssertion(), okToFail);
10818+ }
10819+ }
10820+ }
10821+
10822+ void SonarQubeReporter::writeAssertion(AssertionStats const& stats, bool okToFail) {
10823+ AssertionResult const& result = stats.assertionResult;
10824+ if ( !result.isOk() ||
10825+ result.getResultType() == ResultWas::ExplicitSkip ) {
10826+ std::string elementName;
10827+ if (okToFail) {
10828+ elementName = "skipped";
10829+ } else {
10830+ switch (result.getResultType()) {
10831+ case ResultWas::ThrewException:
10832+ case ResultWas::FatalErrorCondition:
10833+ elementName = "error";
10834+ break;
10835+ case ResultWas::ExplicitFailure:
10836+ case ResultWas::ExpressionFailed:
10837+ case ResultWas::DidntThrowException:
10838+ elementName = "failure";
10839+ break;
10840+ case ResultWas::ExplicitSkip:
10841+ elementName = "skipped";
10842+ break;
10843+ // We should never see these here:
10844+ case ResultWas::Info:
10845+ case ResultWas::Warning:
10846+ case ResultWas::Ok:
10847+ case ResultWas::Unknown:
10848+ case ResultWas::FailureBit:
10849+ case ResultWas::Exception:
10850+ elementName = "internalError";
10851+ break;
10852+ }
10853+ }
10854+
10855+ XmlWriter::ScopedElement e = xml.scopedElement(elementName);
10856+
10857+ ReusableStringStream messageRss;
10858+ messageRss << result.getTestMacroName() << '(' << result.getExpression() << ')';
10859+ xml.writeAttribute("message"_sr, messageRss.str());
10860+
10861+ ReusableStringStream textRss;
10862+ if ( result.getResultType() == ResultWas::ExplicitSkip ) {
10863+ textRss << "SKIPPED\n";
10864+ } else {
10865+ textRss << "FAILED:\n";
10866+ if (result.hasExpression()) {
10867+ textRss << '\t' << result.getExpressionInMacro() << '\n';
10868+ }
10869+ if (result.hasExpandedExpression()) {
10870+ textRss << "with expansion:\n\t" << result.getExpandedExpression() << '\n';
10871+ }
10872+ }
10873+
10874+ if (result.hasMessage())
10875+ textRss << result.getMessage() << '\n';
10876+
10877+ for (auto const& msg : stats.infoMessages)
10878+ if (msg.type == ResultWas::Info)
10879+ textRss << msg.message << '\n';
10880+
10881+ textRss << "at " << result.getSourceInfo();
10882+ xml.writeText(textRss.str(), XmlFormatting::Newline);
10883+ }
10884+ }
10885+
10886+} // end namespace Catch
10887+
10888+
10889+
10890+namespace Catch {
10891+
10892+ StreamingReporterBase::~StreamingReporterBase() = default;
10893+
10894+ void
10895+ StreamingReporterBase::testRunStarting( TestRunInfo const& _testRunInfo ) {
10896+ currentTestRunInfo = _testRunInfo;
10897+ }
10898+
10899+ void StreamingReporterBase::testRunEnded( TestRunStats const& ) {
10900+ currentTestCaseInfo = nullptr;
10901+ }
10902+
10903+} // end namespace Catch
10904+
10905+
10906+
10907+#include <algorithm>
10908+#include <ostream>
10909+
10910+namespace Catch {
10911+
10912+ namespace {
10913+ // Yes, this has to be outside the class and namespaced by naming.
10914+ // Making older compiler happy is hard.
10915+ static constexpr StringRef tapFailedString = "not ok"_sr;
10916+ static constexpr StringRef tapPassedString = "ok"_sr;
10917+ static constexpr Colour::Code tapDimColour = Colour::FileName;
10918+
10919+ class TapAssertionPrinter {
10920+ public:
10921+ TapAssertionPrinter& operator= (TapAssertionPrinter const&) = delete;
10922+ TapAssertionPrinter(TapAssertionPrinter const&) = delete;
10923+ TapAssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, std::size_t _counter, ColourImpl* colour_)
10924+ : stream(_stream)
10925+ , result(_stats.assertionResult)
10926+ , messages(_stats.infoMessages)
10927+ , itMessage(_stats.infoMessages.begin())
10928+ , printInfoMessages(true)
10929+ , counter(_counter)
10930+ , colourImpl( colour_ ) {}
10931+
10932+ void print() {
10933+ itMessage = messages.begin();
10934+
10935+ switch (result.getResultType()) {
10936+ case ResultWas::Ok:
10937+ printResultType(tapPassedString);
10938+ printOriginalExpression();
10939+ printReconstructedExpression();
10940+ if (!result.hasExpression())
10941+ printRemainingMessages(Colour::None);
10942+ else
10943+ printRemainingMessages();
10944+ break;
10945+ case ResultWas::ExpressionFailed:
10946+ if (result.isOk()) {
10947+ printResultType(tapPassedString);
10948+ } else {
10949+ printResultType(tapFailedString);
10950+ }
10951+ printOriginalExpression();
10952+ printReconstructedExpression();
10953+ if (result.isOk()) {
10954+ printIssue(" # TODO");
10955+ }
10956+ printRemainingMessages();
10957+ break;
10958+ case ResultWas::ThrewException:
10959+ printResultType(tapFailedString);
10960+ printIssue("unexpected exception with message:"_sr);
10961+ printMessage();
10962+ printExpressionWas();
10963+ printRemainingMessages();
10964+ break;
10965+ case ResultWas::FatalErrorCondition:
10966+ printResultType(tapFailedString);
10967+ printIssue("fatal error condition with message:"_sr);
10968+ printMessage();
10969+ printExpressionWas();
10970+ printRemainingMessages();
10971+ break;
10972+ case ResultWas::DidntThrowException:
10973+ printResultType(tapFailedString);
10974+ printIssue("expected exception, got none"_sr);
10975+ printExpressionWas();
10976+ printRemainingMessages();
10977+ break;
10978+ case ResultWas::Info:
10979+ printResultType("info"_sr);
10980+ printMessage();
10981+ printRemainingMessages();
10982+ break;
10983+ case ResultWas::Warning:
10984+ printResultType("warning"_sr);
10985+ printMessage();
10986+ printRemainingMessages();
10987+ break;
10988+ case ResultWas::ExplicitFailure:
10989+ printResultType(tapFailedString);
10990+ printIssue("explicitly"_sr);
10991+ printRemainingMessages(Colour::None);
10992+ break;
10993+ case ResultWas::ExplicitSkip:
10994+ printResultType(tapPassedString);
10995+ printIssue(" # SKIP"_sr);
10996+ printMessage();
10997+ printRemainingMessages();
10998+ break;
10999+ // These cases are here to prevent compiler warnings
11000+ case ResultWas::Unknown:
11001+ case ResultWas::FailureBit:
11002+ case ResultWas::Exception:
11003+ printResultType("** internal error **"_sr);
11004+ break;
11005+ }
11006+ }
11007+
11008+ private:
11009+ void printResultType(StringRef passOrFail) const {
11010+ if (!passOrFail.empty()) {
11011+ stream << passOrFail << ' ' << counter << " -";
11012+ }
11013+ }
11014+
11015+ void printIssue(StringRef issue) const {
11016+ stream << ' ' << issue;
11017+ }
11018+
11019+ void printExpressionWas() {
11020+ if (result.hasExpression()) {
11021+ stream << ';';
11022+ stream << colourImpl->guardColour( tapDimColour )
11023+ << " expression was:";
11024+ printOriginalExpression();
11025+ }
11026+ }
11027+
11028+ void printOriginalExpression() const {
11029+ if (result.hasExpression()) {
11030+ stream << ' ' << result.getExpression();
11031+ }
11032+ }
11033+
11034+ void printReconstructedExpression() const {
11035+ if (result.hasExpandedExpression()) {
11036+ stream << colourImpl->guardColour( tapDimColour ) << " for: ";
11037+
11038+ std::string expr = result.getExpandedExpression();
11039+ std::replace(expr.begin(), expr.end(), '\n', ' ');
11040+ stream << expr;
11041+ }
11042+ }
11043+
11044+ void printMessage() {
11045+ if (itMessage != messages.end()) {
11046+ stream << " '" << itMessage->message << '\'';
11047+ ++itMessage;
11048+ }
11049+ }
11050+
11051+ void printRemainingMessages(Colour::Code colour = tapDimColour) {
11052+ if (itMessage == messages.end()) {
11053+ return;
11054+ }
11055+
11056+ // using messages.end() directly (or auto) yields compilation error:
11057+ std::vector<MessageInfo>::const_iterator itEnd = messages.end();
11058+ const std::size_t N = static_cast<std::size_t>(itEnd - itMessage);
11059+
11060+ stream << colourImpl->guardColour( colour ) << " with "
11061+ << pluralise( N, "message"_sr ) << ':';
11062+
11063+ for (; itMessage != itEnd; ) {
11064+ // If this assertion is a warning ignore any INFO messages
11065+ if (printInfoMessages || itMessage->type != ResultWas::Info) {
11066+ stream << " '" << itMessage->message << '\'';
11067+ if (++itMessage != itEnd) {
11068+ stream << colourImpl->guardColour(tapDimColour) << " and";
11069+ }
11070+ }
11071+ }
11072+ }
11073+
11074+ private:
11075+ std::ostream& stream;
11076+ AssertionResult const& result;
11077+ std::vector<MessageInfo> const& messages;
11078+ std::vector<MessageInfo>::const_iterator itMessage;
11079+ bool printInfoMessages;
11080+ std::size_t counter;
11081+ ColourImpl* colourImpl;
11082+ };
11083+
11084+ } // End anonymous namespace
11085+
11086+ void TAPReporter::testRunStarting( TestRunInfo const& ) {
11087+ if ( m_config->testSpec().hasFilters() ) {
11088+ m_stream << "# filters: " << m_config->testSpec() << '\n';
11089+ }
11090+ m_stream << "# rng-seed: " << m_config->rngSeed() << '\n';
11091+ }
11092+
11093+ void TAPReporter::noMatchingTestCases( StringRef unmatchedSpec ) {
11094+ m_stream << "# No test cases matched '" << unmatchedSpec << "'\n";
11095+ }
11096+
11097+ void TAPReporter::assertionEnded(AssertionStats const& _assertionStats) {
11098+ ++counter;
11099+
11100+ m_stream << "# " << currentTestCaseInfo->name << '\n';
11101+ TapAssertionPrinter printer(m_stream, _assertionStats, counter, m_colour.get());
11102+ printer.print();
11103+
11104+ m_stream << '\n' << std::flush;
11105+ }
11106+
11107+ void TAPReporter::testRunEnded(TestRunStats const& _testRunStats) {
11108+ m_stream << "1.." << _testRunStats.totals.assertions.total();
11109+ if (_testRunStats.totals.testCases.total() == 0) {
11110+ m_stream << " # Skipped: No tests ran.";
11111+ }
11112+ m_stream << "\n\n" << std::flush;
11113+ StreamingReporterBase::testRunEnded(_testRunStats);
11114+ }
11115+
11116+
11117+
11118+
11119+} // end namespace Catch
11120+
11121+
11122+
11123+
11124+#include <cassert>
11125+#include <ostream>
11126+
11127+namespace Catch {
11128+
11129+ namespace {
11130+ // if string has a : in first line will set indent to follow it on
11131+ // subsequent lines
11132+ void printHeaderString(std::ostream& os, std::string const& _string, std::size_t indent = 0) {
11133+ std::size_t i = _string.find(": ");
11134+ if (i != std::string::npos)
11135+ i += 2;
11136+ else
11137+ i = 0;
11138+ os << TextFlow::Column(_string)
11139+ .indent(indent + i)
11140+ .initialIndent(indent) << '\n';
11141+ }
11142+
11143+ std::string escape(StringRef str) {
11144+ std::string escaped = static_cast<std::string>(str);
11145+ replaceInPlace(escaped, "|", "||");
11146+ replaceInPlace(escaped, "'", "|'");
11147+ replaceInPlace(escaped, "\n", "|n");
11148+ replaceInPlace(escaped, "\r", "|r");
11149+ replaceInPlace(escaped, "[", "|[");
11150+ replaceInPlace(escaped, "]", "|]");
11151+ return escaped;
11152+ }
11153+ } // end anonymous namespace
11154+
11155+
11156+ TeamCityReporter::~TeamCityReporter() = default;
11157+
11158+ void TeamCityReporter::testRunStarting( TestRunInfo const& runInfo ) {
11159+ m_stream << "##teamcity[testSuiteStarted name='" << escape( runInfo.name )
11160+ << "']\n";
11161+ }
11162+
11163+ void TeamCityReporter::testRunEnded( TestRunStats const& runStats ) {
11164+ m_stream << "##teamcity[testSuiteFinished name='"
11165+ << escape( runStats.runInfo.name ) << "']\n";
11166+ }
11167+
11168+ void TeamCityReporter::assertionEnded(AssertionStats const& assertionStats) {
11169+ AssertionResult const& result = assertionStats.assertionResult;
11170+ if ( !result.isOk() ||
11171+ result.getResultType() == ResultWas::ExplicitSkip ) {
11172+
11173+ ReusableStringStream msg;
11174+ if (!m_headerPrintedForThisSection)
11175+ printSectionHeader(msg.get());
11176+ m_headerPrintedForThisSection = true;
11177+
11178+ msg << result.getSourceInfo() << '\n';
11179+
11180+ switch (result.getResultType()) {
11181+ case ResultWas::ExpressionFailed:
11182+ msg << "expression failed";
11183+ break;
11184+ case ResultWas::ThrewException:
11185+ msg << "unexpected exception";
11186+ break;
11187+ case ResultWas::FatalErrorCondition:
11188+ msg << "fatal error condition";
11189+ break;
11190+ case ResultWas::DidntThrowException:
11191+ msg << "no exception was thrown where one was expected";
11192+ break;
11193+ case ResultWas::ExplicitFailure:
11194+ msg << "explicit failure";
11195+ break;
11196+ case ResultWas::ExplicitSkip:
11197+ msg << "explicit skip";
11198+ break;
11199+
11200+ // We shouldn't get here because of the isOk() test
11201+ case ResultWas::Ok:
11202+ case ResultWas::Info:
11203+ case ResultWas::Warning:
11204+ CATCH_ERROR("Internal error in TeamCity reporter");
11205+ // These cases are here to prevent compiler warnings
11206+ case ResultWas::Unknown:
11207+ case ResultWas::FailureBit:
11208+ case ResultWas::Exception:
11209+ CATCH_ERROR("Not implemented");
11210+ }
11211+ if (assertionStats.infoMessages.size() == 1)
11212+ msg << " with message:";
11213+ if (assertionStats.infoMessages.size() > 1)
11214+ msg << " with messages:";
11215+ for (auto const& messageInfo : assertionStats.infoMessages)
11216+ msg << "\n \"" << messageInfo.message << '"';
11217+
11218+
11219+ if (result.hasExpression()) {
11220+ msg <<
11221+ "\n " << result.getExpressionInMacro() << "\n"
11222+ "with expansion:\n"
11223+ " " << result.getExpandedExpression() << '\n';
11224+ }
11225+
11226+ if ( result.getResultType() == ResultWas::ExplicitSkip ) {
11227+ m_stream << "##teamcity[testIgnored";
11228+ } else if ( currentTestCaseInfo->okToFail() ) {
11229+ msg << "- failure ignore as test marked as 'ok to fail'\n";
11230+ m_stream << "##teamcity[testIgnored";
11231+ } else {
11232+ m_stream << "##teamcity[testFailed";
11233+ }
11234+ m_stream << " name='" << escape( currentTestCaseInfo->name ) << '\''
11235+ << " message='" << escape( msg.str() ) << '\'' << "]\n";
11236+ }
11237+ m_stream.flush();
11238+ }
11239+
11240+ void TeamCityReporter::testCaseStarting(TestCaseInfo const& testInfo) {
11241+ m_testTimer.start();
11242+ StreamingReporterBase::testCaseStarting(testInfo);
11243+ m_stream << "##teamcity[testStarted name='"
11244+ << escape(testInfo.name) << "']\n";
11245+ m_stream.flush();
11246+ }
11247+
11248+ void TeamCityReporter::testCaseEnded(TestCaseStats const& testCaseStats) {
11249+ StreamingReporterBase::testCaseEnded(testCaseStats);
11250+ auto const& testCaseInfo = *testCaseStats.testInfo;
11251+ if (!testCaseStats.stdOut.empty())
11252+ m_stream << "##teamcity[testStdOut name='"
11253+ << escape(testCaseInfo.name)
11254+ << "' out='" << escape(testCaseStats.stdOut) << "']\n";
11255+ if (!testCaseStats.stdErr.empty())
11256+ m_stream << "##teamcity[testStdErr name='"
11257+ << escape(testCaseInfo.name)
11258+ << "' out='" << escape(testCaseStats.stdErr) << "']\n";
11259+ m_stream << "##teamcity[testFinished name='"
11260+ << escape(testCaseInfo.name) << "' duration='"
11261+ << m_testTimer.getElapsedMilliseconds() << "']\n";
11262+ m_stream.flush();
11263+ }
11264+
11265+ void TeamCityReporter::printSectionHeader(std::ostream& os) {
11266+ assert(!m_sectionStack.empty());
11267+
11268+ if (m_sectionStack.size() > 1) {
11269+ os << lineOfChars('-') << '\n';
11270+
11271+ std::vector<SectionInfo>::const_iterator
11272+ it = m_sectionStack.begin() + 1, // Skip first section (test case)
11273+ itEnd = m_sectionStack.end();
11274+ for (; it != itEnd; ++it)
11275+ printHeaderString(os, it->name);
11276+ os << lineOfChars('-') << '\n';
11277+ }
11278+
11279+ SourceLineInfo lineInfo = m_sectionStack.front().lineInfo;
11280+
11281+ os << lineInfo << '\n';
11282+ os << lineOfChars('.') << "\n\n";
11283+ }
11284+
11285+} // end namespace Catch
11286+
11287+
11288+
11289+
11290+#if defined(_MSC_VER)
11291+#pragma warning(push)
11292+#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch
11293+ // Note that 4062 (not all labels are handled
11294+ // and default is missing) is enabled
11295+#endif
11296+
11297+namespace Catch {
11298+ XmlReporter::XmlReporter( ReporterConfig&& _config )
11299+ : StreamingReporterBase( CATCH_MOVE(_config) ),
11300+ m_xml(m_stream)
11301+ {
11302+ m_preferences.shouldRedirectStdOut = true;
11303+ m_preferences.shouldReportAllAssertions = true;
11304+ }
11305+
11306+ XmlReporter::~XmlReporter() = default;
11307+
11308+ std::string XmlReporter::getDescription() {
11309+ return "Reports test results as an XML document";
11310+ }
11311+
11312+ std::string XmlReporter::getStylesheetRef() const {
11313+ return std::string();
11314+ }
11315+
11316+ void XmlReporter::writeSourceInfo( SourceLineInfo const& sourceInfo ) {
11317+ m_xml
11318+ .writeAttribute( "filename"_sr, sourceInfo.file )
11319+ .writeAttribute( "line"_sr, sourceInfo.line );
11320+ }
11321+
11322+ void XmlReporter::testRunStarting( TestRunInfo const& testInfo ) {
11323+ StreamingReporterBase::testRunStarting( testInfo );
11324+ std::string stylesheetRef = getStylesheetRef();
11325+ if( !stylesheetRef.empty() )
11326+ m_xml.writeStylesheetRef( stylesheetRef );
11327+ m_xml.startElement("Catch2TestRun")
11328+ .writeAttribute("name"_sr, m_config->name())
11329+ .writeAttribute("rng-seed"_sr, m_config->rngSeed())
11330+ .writeAttribute("xml-format-version"_sr, 3)
11331+ .writeAttribute("catch2-version"_sr, libraryVersion());
11332+ if ( m_config->testSpec().hasFilters() ) {
11333+ m_xml.writeAttribute( "filters"_sr, m_config->testSpec() );
11334+ }
11335+ }
11336+
11337+ void XmlReporter::testCaseStarting( TestCaseInfo const& testInfo ) {
11338+ StreamingReporterBase::testCaseStarting(testInfo);
11339+ m_xml.startElement( "TestCase" )
11340+ .writeAttribute( "name"_sr, trim( StringRef(testInfo.name) ) )
11341+ .writeAttribute( "tags"_sr, testInfo.tagsAsString() );
11342+
11343+ writeSourceInfo( testInfo.lineInfo );
11344+
11345+ if ( m_config->showDurations() == ShowDurations::Always )
11346+ m_testCaseTimer.start();
11347+ m_xml.ensureTagClosed();
11348+ }
11349+
11350+ void XmlReporter::sectionStarting( SectionInfo const& sectionInfo ) {
11351+ StreamingReporterBase::sectionStarting( sectionInfo );
11352+ if( m_sectionDepth++ > 0 ) {
11353+ m_xml.startElement( "Section" )
11354+ .writeAttribute( "name"_sr, trim( StringRef(sectionInfo.name) ) );
11355+ writeSourceInfo( sectionInfo.lineInfo );
11356+ m_xml.ensureTagClosed();
11357+ }
11358+ }
11359+
11360+ void XmlReporter::assertionStarting( AssertionInfo const& ) { }
11361+
11362+ void XmlReporter::assertionEnded( AssertionStats const& assertionStats ) {
11363+
11364+ AssertionResult const& result = assertionStats.assertionResult;
11365+
11366+ bool includeResults = m_config->includeSuccessfulResults() || !result.isOk();
11367+
11368+ if( includeResults || result.getResultType() == ResultWas::Warning ) {
11369+ // Print any info messages in <Info> tags.
11370+ for( auto const& msg : assertionStats.infoMessages ) {
11371+ if( msg.type == ResultWas::Info && includeResults ) {
11372+ auto t = m_xml.scopedElement( "Info" );
11373+ writeSourceInfo( msg.lineInfo );
11374+ t.writeText( msg.message );
11375+ } else if ( msg.type == ResultWas::Warning ) {
11376+ auto t = m_xml.scopedElement( "Warning" );
11377+ writeSourceInfo( msg.lineInfo );
11378+ t.writeText( msg.message );
11379+ }
11380+ }
11381+ }
11382+
11383+ // Drop out if result was successful but we're not printing them.
11384+ if ( !includeResults && result.getResultType() != ResultWas::Warning &&
11385+ result.getResultType() != ResultWas::ExplicitSkip ) {
11386+ return;
11387+ }
11388+
11389+ // Print the expression if there is one.
11390+ if( result.hasExpression() ) {
11391+ m_xml.startElement( "Expression" )
11392+ .writeAttribute( "success"_sr, result.succeeded() )
11393+ .writeAttribute( "type"_sr, result.getTestMacroName() );
11394+
11395+ writeSourceInfo( result.getSourceInfo() );
11396+
11397+ m_xml.scopedElement( "Original" )
11398+ .writeText( result.getExpression() );
11399+ m_xml.scopedElement( "Expanded" )
11400+ .writeText( result.getExpandedExpression() );
11401+ }
11402+
11403+ // And... Print a result applicable to each result type.
11404+ switch( result.getResultType() ) {
11405+ case ResultWas::ThrewException:
11406+ m_xml.startElement( "Exception" );
11407+ writeSourceInfo( result.getSourceInfo() );
11408+ m_xml.writeText( result.getMessage() );
11409+ m_xml.endElement();
11410+ break;
11411+ case ResultWas::FatalErrorCondition:
11412+ m_xml.startElement( "FatalErrorCondition" );
11413+ writeSourceInfo( result.getSourceInfo() );
11414+ m_xml.writeText( result.getMessage() );
11415+ m_xml.endElement();
11416+ break;
11417+ case ResultWas::Info:
11418+ m_xml.scopedElement( "Info" )
11419+ .writeText( result.getMessage() );
11420+ break;
11421+ case ResultWas::Warning:
11422+ // Warning will already have been written
11423+ break;
11424+ case ResultWas::ExplicitFailure:
11425+ m_xml.startElement( "Failure" );
11426+ writeSourceInfo( result.getSourceInfo() );
11427+ m_xml.writeText( result.getMessage() );
11428+ m_xml.endElement();
11429+ break;
11430+ case ResultWas::ExplicitSkip:
11431+ m_xml.startElement( "Skip" );
11432+ writeSourceInfo( result.getSourceInfo() );
11433+ m_xml.writeText( result.getMessage() );
11434+ m_xml.endElement();
11435+ break;
11436+ default:
11437+ break;
11438+ }
11439+
11440+ if( result.hasExpression() )
11441+ m_xml.endElement();
11442+ }
11443+
11444+ void XmlReporter::sectionEnded( SectionStats const& sectionStats ) {
11445+ StreamingReporterBase::sectionEnded( sectionStats );
11446+ if ( --m_sectionDepth > 0 ) {
11447+ {
11448+ XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" );
11449+ e.writeAttribute( "successes"_sr, sectionStats.assertions.passed );
11450+ e.writeAttribute( "failures"_sr, sectionStats.assertions.failed );
11451+ e.writeAttribute( "expectedFailures"_sr, sectionStats.assertions.failedButOk );
11452+ e.writeAttribute( "skipped"_sr, sectionStats.assertions.skipped > 0 );
11453+
11454+ if ( m_config->showDurations() == ShowDurations::Always )
11455+ e.writeAttribute( "durationInSeconds"_sr, sectionStats.durationInSeconds );
11456+ }
11457+ // Ends assertion tag
11458+ m_xml.endElement();
11459+ }
11460+ }
11461+
11462+ void XmlReporter::testCaseEnded( TestCaseStats const& testCaseStats ) {
11463+ StreamingReporterBase::testCaseEnded( testCaseStats );
11464+ XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" );
11465+ e.writeAttribute( "success"_sr, testCaseStats.totals.assertions.allOk() );
11466+ e.writeAttribute( "skips"_sr, testCaseStats.totals.assertions.skipped );
11467+
11468+ if ( m_config->showDurations() == ShowDurations::Always )
11469+ e.writeAttribute( "durationInSeconds"_sr, m_testCaseTimer.getElapsedSeconds() );
11470+ if( !testCaseStats.stdOut.empty() )
11471+ m_xml.scopedElement( "StdOut" ).writeText( trim( StringRef(testCaseStats.stdOut) ), XmlFormatting::Newline );
11472+ if( !testCaseStats.stdErr.empty() )
11473+ m_xml.scopedElement( "StdErr" ).writeText( trim( StringRef(testCaseStats.stdErr) ), XmlFormatting::Newline );
11474+
11475+ m_xml.endElement();
11476+ }
11477+
11478+ void XmlReporter::testRunEnded( TestRunStats const& testRunStats ) {
11479+ StreamingReporterBase::testRunEnded( testRunStats );
11480+ m_xml.scopedElement( "OverallResults" )
11481+ .writeAttribute( "successes"_sr, testRunStats.totals.assertions.passed )
11482+ .writeAttribute( "failures"_sr, testRunStats.totals.assertions.failed )
11483+ .writeAttribute( "expectedFailures"_sr, testRunStats.totals.assertions.failedButOk )
11484+ .writeAttribute( "skips"_sr, testRunStats.totals.assertions.skipped );
11485+ m_xml.scopedElement( "OverallResultsCases")
11486+ .writeAttribute( "successes"_sr, testRunStats.totals.testCases.passed )
11487+ .writeAttribute( "failures"_sr, testRunStats.totals.testCases.failed )
11488+ .writeAttribute( "expectedFailures"_sr, testRunStats.totals.testCases.failedButOk )
11489+ .writeAttribute( "skips"_sr, testRunStats.totals.testCases.skipped );
11490+ m_xml.endElement();
11491+ }
11492+
11493+ void XmlReporter::benchmarkPreparing( StringRef name ) {
11494+ m_xml.startElement("BenchmarkResults")
11495+ .writeAttribute("name"_sr, name);
11496+ }
11497+
11498+ void XmlReporter::benchmarkStarting(BenchmarkInfo const &info) {
11499+ m_xml.writeAttribute("samples"_sr, info.samples)
11500+ .writeAttribute("resamples"_sr, info.resamples)
11501+ .writeAttribute("iterations"_sr, info.iterations)
11502+ .writeAttribute("clockResolution"_sr, info.clockResolution)
11503+ .writeAttribute("estimatedDuration"_sr, info.estimatedDuration)
11504+ .writeComment("All values in nano seconds"_sr);
11505+ }
11506+
11507+ void XmlReporter::benchmarkEnded(BenchmarkStats<> const& benchmarkStats) {
11508+ m_xml.scopedElement("mean")
11509+ .writeAttribute("value"_sr, benchmarkStats.mean.point.count())
11510+ .writeAttribute("lowerBound"_sr, benchmarkStats.mean.lower_bound.count())
11511+ .writeAttribute("upperBound"_sr, benchmarkStats.mean.upper_bound.count())
11512+ .writeAttribute("ci"_sr, benchmarkStats.mean.confidence_interval);
11513+ m_xml.scopedElement("standardDeviation")
11514+ .writeAttribute("value"_sr, benchmarkStats.standardDeviation.point.count())
11515+ .writeAttribute("lowerBound"_sr, benchmarkStats.standardDeviation.lower_bound.count())
11516+ .writeAttribute("upperBound"_sr, benchmarkStats.standardDeviation.upper_bound.count())
11517+ .writeAttribute("ci"_sr, benchmarkStats.standardDeviation.confidence_interval);
11518+ m_xml.scopedElement("outliers")
11519+ .writeAttribute("variance"_sr, benchmarkStats.outlierVariance)
11520+ .writeAttribute("lowMild"_sr, benchmarkStats.outliers.low_mild)
11521+ .writeAttribute("lowSevere"_sr, benchmarkStats.outliers.low_severe)
11522+ .writeAttribute("highMild"_sr, benchmarkStats.outliers.high_mild)
11523+ .writeAttribute("highSevere"_sr, benchmarkStats.outliers.high_severe);
11524+ m_xml.endElement();
11525+ }
11526+
11527+ void XmlReporter::benchmarkFailed(StringRef error) {
11528+ m_xml.scopedElement("failed").
11529+ writeAttribute("message"_sr, error);
11530+ m_xml.endElement();
11531+ }
11532+
11533+ void XmlReporter::listReporters(std::vector<ReporterDescription> const& descriptions) {
11534+ auto outerTag = m_xml.scopedElement("AvailableReporters");
11535+ for (auto const& reporter : descriptions) {
11536+ auto inner = m_xml.scopedElement("Reporter");
11537+ m_xml.startElement("Name", XmlFormatting::Indent)
11538+ .writeText(reporter.name, XmlFormatting::None)
11539+ .endElement(XmlFormatting::Newline);
11540+ m_xml.startElement("Description", XmlFormatting::Indent)
11541+ .writeText(reporter.description, XmlFormatting::None)
11542+ .endElement(XmlFormatting::Newline);
11543+ }
11544+ }
11545+
11546+ void XmlReporter::listListeners(std::vector<ListenerDescription> const& descriptions) {
11547+ auto outerTag = m_xml.scopedElement( "RegisteredListeners" );
11548+ for ( auto const& listener : descriptions ) {
11549+ auto inner = m_xml.scopedElement( "Listener" );
11550+ m_xml.startElement( "Name", XmlFormatting::Indent )
11551+ .writeText( listener.name, XmlFormatting::None )
11552+ .endElement( XmlFormatting::Newline );
11553+ m_xml.startElement( "Description", XmlFormatting::Indent )
11554+ .writeText( listener.description, XmlFormatting::None )
11555+ .endElement( XmlFormatting::Newline );
11556+ }
11557+ }
11558+
11559+ void XmlReporter::listTests(std::vector<TestCaseHandle> const& tests) {
11560+ auto outerTag = m_xml.scopedElement("MatchingTests");
11561+ for (auto const& test : tests) {
11562+ auto innerTag = m_xml.scopedElement("TestCase");
11563+ auto const& testInfo = test.getTestCaseInfo();
11564+ m_xml.startElement("Name", XmlFormatting::Indent)
11565+ .writeText(testInfo.name, XmlFormatting::None)
11566+ .endElement(XmlFormatting::Newline);
11567+ m_xml.startElement("ClassName", XmlFormatting::Indent)
11568+ .writeText(testInfo.className, XmlFormatting::None)
11569+ .endElement(XmlFormatting::Newline);
11570+ m_xml.startElement("Tags", XmlFormatting::Indent)
11571+ .writeText(testInfo.tagsAsString(), XmlFormatting::None)
11572+ .endElement(XmlFormatting::Newline);
11573+
11574+ auto sourceTag = m_xml.scopedElement("SourceInfo");
11575+ m_xml.startElement("File", XmlFormatting::Indent)
11576+ .writeText(testInfo.lineInfo.file, XmlFormatting::None)
11577+ .endElement(XmlFormatting::Newline);
11578+ m_xml.startElement("Line", XmlFormatting::Indent)
11579+ .writeText(std::to_string(testInfo.lineInfo.line), XmlFormatting::None)
11580+ .endElement(XmlFormatting::Newline);
11581+ }
11582+ }
11583+
11584+ void XmlReporter::listTags(std::vector<TagInfo> const& tags) {
11585+ auto outerTag = m_xml.scopedElement("TagsFromMatchingTests");
11586+ for (auto const& tag : tags) {
11587+ auto innerTag = m_xml.scopedElement("Tag");
11588+ m_xml.startElement("Count", XmlFormatting::Indent)
11589+ .writeText(std::to_string(tag.count), XmlFormatting::None)
11590+ .endElement(XmlFormatting::Newline);
11591+ auto aliasTag = m_xml.scopedElement("Aliases");
11592+ for (auto const& alias : tag.spellings) {
11593+ m_xml.startElement("Alias", XmlFormatting::Indent)
11594+ .writeText(alias, XmlFormatting::None)
11595+ .endElement(XmlFormatting::Newline);
11596+ }
11597+ }
11598+ }
11599+
11600+} // end namespace Catch
11601+
11602+#if defined(_MSC_VER)
11603+#pragma warning(pop)
11604+#endif
11605diff --git a/tests/catch_amalgamated.hpp b/tests/catch_amalgamated.hpp
11606new file mode 100644
11607index 0000000..7e75a5d
11608--- /dev/null
11609+++ b/tests/catch_amalgamated.hpp
11610@@ -0,0 +1,13927 @@
11611+
11612+// Copyright Catch2 Authors
11613+// Distributed under the Boost Software License, Version 1.0.
11614+// (See accompanying file LICENSE.txt or copy at
11615+// https://www.boost.org/LICENSE_1_0.txt)
11616+
11617+// SPDX-License-Identifier: BSL-1.0
11618+
11619+// Catch v3.5.4
11620+// Generated: 2024-04-10 12:03:45.785902
11621+// ----------------------------------------------------------
11622+// This file is an amalgamation of multiple different files.
11623+// You probably shouldn't edit it directly.
11624+// ----------------------------------------------------------
11625+#ifndef CATCH_AMALGAMATED_HPP_INCLUDED
11626+#define CATCH_AMALGAMATED_HPP_INCLUDED
11627+
11628+
11629+/** \file
11630+ * This is a convenience header for Catch2. It includes **all** of Catch2 headers.
11631+ *
11632+ * Generally the Catch2 users should use specific includes they need,
11633+ * but this header can be used instead for ease-of-experimentation, or
11634+ * just plain convenience, at the cost of (significantly) increased
11635+ * compilation times.
11636+ *
11637+ * When a new header is added to either the top level folder, or to the
11638+ * corresponding internal subfolder, it should be added here. Headers
11639+ * added to the various subparts (e.g. matchers, generators, etc...),
11640+ * should go their respective catch-all headers.
11641+ */
11642+
11643+#ifndef CATCH_ALL_HPP_INCLUDED
11644+#define CATCH_ALL_HPP_INCLUDED
11645+
11646+
11647+
11648+/** \file
11649+ * This is a convenience header for Catch2's benchmarking. It includes
11650+ * **all** of Catch2 headers related to benchmarking.
11651+ *
11652+ * Generally the Catch2 users should use specific includes they need,
11653+ * but this header can be used instead for ease-of-experimentation, or
11654+ * just plain convenience, at the cost of (significantly) increased
11655+ * compilation times.
11656+ *
11657+ * When a new header is added to either the `benchmark` folder, or to
11658+ * the corresponding internal (detail) subfolder, it should be added here.
11659+ */
11660+
11661+#ifndef CATCH_BENCHMARK_ALL_HPP_INCLUDED
11662+#define CATCH_BENCHMARK_ALL_HPP_INCLUDED
11663+
11664+
11665+
11666+// Adapted from donated nonius code.
11667+
11668+#ifndef CATCH_BENCHMARK_HPP_INCLUDED
11669+#define CATCH_BENCHMARK_HPP_INCLUDED
11670+
11671+
11672+
11673+#ifndef CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED
11674+#define CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED
11675+
11676+// Detect a number of compiler features - by compiler
11677+// The following features are defined:
11678+//
11679+// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported?
11680+// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported?
11681+// CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled?
11682+// ****************
11683+// Note to maintainers: if new toggles are added please document them
11684+// in configuration.md, too
11685+// ****************
11686+
11687+// In general each macro has a _NO_<feature name> form
11688+// (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature.
11689+// Many features, at point of detection, define an _INTERNAL_ macro, so they
11690+// can be combined, en-mass, with the _NO_ forms later.
11691+
11692+
11693+
11694+#ifndef CATCH_PLATFORM_HPP_INCLUDED
11695+#define CATCH_PLATFORM_HPP_INCLUDED
11696+
11697+// See e.g.:
11698+// https://opensource.apple.com/source/CarbonHeaders/CarbonHeaders-18.1/TargetConditionals.h.auto.html
11699+#ifdef __APPLE__
11700+# ifndef __has_extension
11701+# define __has_extension(x) 0
11702+# endif
11703+# include <TargetConditionals.h>
11704+# if (defined(TARGET_OS_OSX) && TARGET_OS_OSX == 1) || \
11705+ (defined(TARGET_OS_MAC) && TARGET_OS_MAC == 1)
11706+# define CATCH_PLATFORM_MAC
11707+# elif (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE == 1)
11708+# define CATCH_PLATFORM_IPHONE
11709+# endif
11710+
11711+#elif defined(linux) || defined(__linux) || defined(__linux__)
11712+# define CATCH_PLATFORM_LINUX
11713+
11714+#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__)
11715+# define CATCH_PLATFORM_WINDOWS
11716+
11717+# if defined( WINAPI_FAMILY ) && ( WINAPI_FAMILY == WINAPI_FAMILY_APP )
11718+# define CATCH_PLATFORM_WINDOWS_UWP
11719+# endif
11720+
11721+#elif defined(__ORBIS__) || defined(__PROSPERO__)
11722+# define CATCH_PLATFORM_PLAYSTATION
11723+
11724+#endif
11725+
11726+#endif // CATCH_PLATFORM_HPP_INCLUDED
11727+
11728+#ifdef __cplusplus
11729+
11730+# if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
11731+# define CATCH_CPP17_OR_GREATER
11732+# endif
11733+
11734+# if (__cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)
11735+# define CATCH_CPP20_OR_GREATER
11736+# endif
11737+
11738+#endif
11739+
11740+// Only GCC compiler should be used in this block, so other compilers trying to
11741+// mask themselves as GCC should be ignored.
11742+#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__) && !defined(__NVCOMPILER)
11743+# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" )
11744+# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" )
11745+
11746+// This only works on GCC 9+. so we have to also add a global suppression of Wparentheses
11747+// for older versions of GCC.
11748+# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
11749+ _Pragma( "GCC diagnostic ignored \"-Wparentheses\"" )
11750+
11751+# define CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT \
11752+ _Pragma( "GCC diagnostic ignored \"-Wunused-result\"" )
11753+
11754+# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
11755+ _Pragma( "GCC diagnostic ignored \"-Wunused-variable\"" )
11756+
11757+# define CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \
11758+ _Pragma( "GCC diagnostic ignored \"-Wuseless-cast\"" )
11759+
11760+# define CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \
11761+ _Pragma( "GCC diagnostic ignored \"-Wshadow\"" )
11762+
11763+# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__)
11764+
11765+#endif
11766+
11767+#if defined(__NVCOMPILER)
11768+# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "diag push" )
11769+# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "diag pop" )
11770+# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS _Pragma( "diag_suppress declared_but_not_referenced" )
11771+#endif
11772+
11773+#if defined(__CUDACC__) && !defined(__clang__)
11774+# ifdef __NVCC_DIAG_PRAGMA_SUPPORT__
11775+// New pragmas introduced in CUDA 11.5+
11776+# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "nv_diagnostic push" )
11777+# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "nv_diagnostic pop" )
11778+# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS _Pragma( "nv_diag_suppress 177" )
11779+# else
11780+# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS _Pragma( "diag_suppress 177" )
11781+# endif
11782+#endif
11783+
11784+// clang-cl defines _MSC_VER as well as __clang__, which could cause the
11785+// start/stop internal suppression macros to be double defined.
11786+#if defined(__clang__) && !defined(_MSC_VER)
11787+
11788+# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" )
11789+# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" )
11790+
11791+#endif // __clang__ && !_MSC_VER
11792+
11793+#if defined(__clang__)
11794+
11795+// As of this writing, IBM XL's implementation of __builtin_constant_p has a bug
11796+// which results in calls to destructors being emitted for each temporary,
11797+// without a matching initialization. In practice, this can result in something
11798+// like `std::string::~string` being called on an uninitialized value.
11799+//
11800+// For example, this code will likely segfault under IBM XL:
11801+// ```
11802+// REQUIRE(std::string("12") + "34" == "1234")
11803+// ```
11804+//
11805+// Similarly, NVHPC's implementation of `__builtin_constant_p` has a bug which
11806+// results in calls to the immediately evaluated lambda expressions to be
11807+// reported as unevaluated lambdas.
11808+// https://developer.nvidia.com/nvidia_bug/3321845.
11809+//
11810+// Therefore, `CATCH_INTERNAL_IGNORE_BUT_WARN` is not implemented.
11811+# if !defined(__ibmxl__) && !defined(__CUDACC__) && !defined( __NVCOMPILER )
11812+# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg) */
11813+# endif
11814+
11815+
11816+# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
11817+ _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \
11818+ _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"")
11819+
11820+# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
11821+ _Pragma( "clang diagnostic ignored \"-Wparentheses\"" )
11822+
11823+# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
11824+ _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" )
11825+
11826+# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
11827+ _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" )
11828+
11829+# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
11830+ _Pragma( "clang diagnostic ignored \"-Wunused-template\"" )
11831+
11832+# define CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS \
11833+ _Pragma( "clang diagnostic ignored \"-Wcomma\"" )
11834+
11835+# define CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \
11836+ _Pragma( "clang diagnostic ignored \"-Wshadow\"" )
11837+
11838+#endif // __clang__
11839+
11840+
11841+////////////////////////////////////////////////////////////////////////////////
11842+// We know some environments not to support full POSIX signals
11843+#if defined( CATCH_PLATFORM_WINDOWS ) || \
11844+ defined( CATCH_PLATFORM_PLAYSTATION ) || \
11845+ defined( __CYGWIN__ ) || \
11846+ defined( __QNX__ ) || \
11847+ defined( __EMSCRIPTEN__ ) || \
11848+ defined( __DJGPP__ ) || \
11849+ defined( __OS400__ )
11850+# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS
11851+#else
11852+# define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS
11853+#endif
11854+
11855+////////////////////////////////////////////////////////////////////////////////
11856+// Assume that some platforms do not support getenv.
11857+#if defined( CATCH_PLATFORM_WINDOWS_UWP ) || \
11858+ defined( CATCH_PLATFORM_PLAYSTATION ) || \
11859+ defined( _GAMING_XBOX )
11860+# define CATCH_INTERNAL_CONFIG_NO_GETENV
11861+#else
11862+# define CATCH_INTERNAL_CONFIG_GETENV
11863+#endif
11864+
11865+////////////////////////////////////////////////////////////////////////////////
11866+// Android somehow still does not support std::to_string
11867+#if defined(__ANDROID__)
11868+# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING
11869+#endif
11870+
11871+////////////////////////////////////////////////////////////////////////////////
11872+// Not all Windows environments support SEH properly
11873+#if defined(__MINGW32__)
11874+# define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH
11875+#endif
11876+
11877+////////////////////////////////////////////////////////////////////////////////
11878+// PS4
11879+#if defined(__ORBIS__)
11880+# define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE
11881+#endif
11882+
11883+////////////////////////////////////////////////////////////////////////////////
11884+// Cygwin
11885+#ifdef __CYGWIN__
11886+
11887+// Required for some versions of Cygwin to declare gettimeofday
11888+// see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin
11889+# define _BSD_SOURCE
11890+// some versions of cygwin (most) do not support std::to_string. Use the libstd check.
11891+// https://gcc.gnu.org/onlinedocs/gcc-4.8.2/libstdc++/api/a01053_source.html line 2812-2813
11892+# if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \
11893+ && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF))
11894+
11895+# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING
11896+
11897+# endif
11898+#endif // __CYGWIN__
11899+
11900+////////////////////////////////////////////////////////////////////////////////
11901+// Visual C++
11902+#if defined(_MSC_VER)
11903+
11904+// We want to defer to nvcc-specific warning suppression if we are compiled
11905+// with nvcc masquerading for MSVC.
11906+# if !defined( __CUDACC__ )
11907+# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
11908+ __pragma( warning( push ) )
11909+# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
11910+ __pragma( warning( pop ) )
11911+# endif
11912+
11913+// Universal Windows platform does not support SEH
11914+// Or console colours (or console at all...)
11915+# if defined(CATCH_PLATFORM_WINDOWS_UWP)
11916+# define CATCH_INTERNAL_CONFIG_NO_COLOUR_WIN32
11917+# else
11918+# define CATCH_INTERNAL_CONFIG_WINDOWS_SEH
11919+# endif
11920+
11921+// MSVC traditional preprocessor needs some workaround for __VA_ARGS__
11922+// _MSVC_TRADITIONAL == 0 means new conformant preprocessor
11923+// _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor
11924+# if !defined(__clang__) // Handle Clang masquerading for msvc
11925+# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL)
11926+# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
11927+# endif // MSVC_TRADITIONAL
11928+# endif // __clang__
11929+
11930+#endif // _MSC_VER
11931+
11932+#if defined(_REENTRANT) || defined(_MSC_VER)
11933+// Enable async processing, as -pthread is specified or no additional linking is required
11934+# define CATCH_INTERNAL_CONFIG_USE_ASYNC
11935+#endif // _MSC_VER
11936+
11937+////////////////////////////////////////////////////////////////////////////////
11938+// Check if we are compiled with -fno-exceptions or equivalent
11939+#if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND)
11940+# define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED
11941+#endif
11942+
11943+
11944+////////////////////////////////////////////////////////////////////////////////
11945+// Embarcadero C++Build
11946+#if defined(__BORLANDC__)
11947+ #define CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN
11948+#endif
11949+
11950+////////////////////////////////////////////////////////////////////////////////
11951+
11952+// RTX is a special version of Windows that is real time.
11953+// This means that it is detected as Windows, but does not provide
11954+// the same set of capabilities as real Windows does.
11955+#if defined(UNDER_RTSS) || defined(RTX64_BUILD)
11956+ #define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH
11957+ #define CATCH_INTERNAL_CONFIG_NO_ASYNC
11958+ #define CATCH_INTERNAL_CONFIG_NO_COLOUR_WIN32
11959+#endif
11960+
11961+#if !defined(_GLIBCXX_USE_C99_MATH_TR1)
11962+#define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER
11963+#endif
11964+
11965+// Various stdlib support checks that require __has_include
11966+#if defined(__has_include)
11967+ // Check if string_view is available and usable
11968+ #if __has_include(<string_view>) && defined(CATCH_CPP17_OR_GREATER)
11969+ # define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW
11970+ #endif
11971+
11972+ // Check if optional is available and usable
11973+ # if __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)
11974+ # define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL
11975+ # endif // __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)
11976+
11977+ // Check if byte is available and usable
11978+ # if __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER)
11979+ # include <cstddef>
11980+ # if defined(__cpp_lib_byte) && (__cpp_lib_byte > 0)
11981+ # define CATCH_INTERNAL_CONFIG_CPP17_BYTE
11982+ # endif
11983+ # endif // __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER)
11984+
11985+ // Check if variant is available and usable
11986+ # if __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
11987+ # if defined(__clang__) && (__clang_major__ < 8)
11988+ // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852
11989+ // fix should be in clang 8, workaround in libstdc++ 8.2
11990+ # include <ciso646>
11991+ # if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
11992+ # define CATCH_CONFIG_NO_CPP17_VARIANT
11993+ # else
11994+ # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT
11995+ # endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
11996+ # else
11997+ # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT
11998+ # endif // defined(__clang__) && (__clang_major__ < 8)
11999+ # endif // __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
12000+#endif // defined(__has_include)
12001+
12002+
12003+#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)
12004+# define CATCH_CONFIG_WINDOWS_SEH
12005+#endif
12006+// This is set by default, because we assume that unix compilers are posix-signal-compatible by default.
12007+#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)
12008+# define CATCH_CONFIG_POSIX_SIGNALS
12009+#endif
12010+
12011+#if defined(CATCH_INTERNAL_CONFIG_GETENV) && !defined(CATCH_INTERNAL_CONFIG_NO_GETENV) && !defined(CATCH_CONFIG_NO_GETENV) && !defined(CATCH_CONFIG_GETENV)
12012+# define CATCH_CONFIG_GETENV
12013+#endif
12014+
12015+#if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING)
12016+# define CATCH_CONFIG_CPP11_TO_STRING
12017+#endif
12018+
12019+#if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL)
12020+# define CATCH_CONFIG_CPP17_OPTIONAL
12021+#endif
12022+
12023+#if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW)
12024+# define CATCH_CONFIG_CPP17_STRING_VIEW
12025+#endif
12026+
12027+#if defined(CATCH_INTERNAL_CONFIG_CPP17_VARIANT) && !defined(CATCH_CONFIG_NO_CPP17_VARIANT) && !defined(CATCH_CONFIG_CPP17_VARIANT)
12028+# define CATCH_CONFIG_CPP17_VARIANT
12029+#endif
12030+
12031+#if defined(CATCH_INTERNAL_CONFIG_CPP17_BYTE) && !defined(CATCH_CONFIG_NO_CPP17_BYTE) && !defined(CATCH_CONFIG_CPP17_BYTE)
12032+# define CATCH_CONFIG_CPP17_BYTE
12033+#endif
12034+
12035+
12036+#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT)
12037+# define CATCH_INTERNAL_CONFIG_NEW_CAPTURE
12038+#endif
12039+
12040+#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)
12041+# define CATCH_CONFIG_NEW_CAPTURE
12042+#endif
12043+
12044+#if !defined( CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED ) && \
12045+ !defined( CATCH_CONFIG_DISABLE_EXCEPTIONS ) && \
12046+ !defined( CATCH_CONFIG_NO_DISABLE_EXCEPTIONS )
12047+# define CATCH_CONFIG_DISABLE_EXCEPTIONS
12048+#endif
12049+
12050+#if defined(CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_NO_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_POLYFILL_ISNAN)
12051+# define CATCH_CONFIG_POLYFILL_ISNAN
12052+#endif
12053+
12054+#if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC) && !defined(CATCH_INTERNAL_CONFIG_NO_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC)
12055+# define CATCH_CONFIG_USE_ASYNC
12056+#endif
12057+
12058+#if defined(CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_NO_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_GLOBAL_NEXTAFTER)
12059+# define CATCH_CONFIG_GLOBAL_NEXTAFTER
12060+#endif
12061+
12062+
12063+// Even if we do not think the compiler has that warning, we still have
12064+// to provide a macro that can be used by the code.
12065+#if !defined(CATCH_INTERNAL_START_WARNINGS_SUPPRESSION)
12066+# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
12067+#endif
12068+#if !defined(CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION)
12069+# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
12070+#endif
12071+#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS)
12072+# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS
12073+#endif
12074+#if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS)
12075+# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
12076+#endif
12077+#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT)
12078+# define CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT
12079+#endif
12080+#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS)
12081+# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS
12082+#endif
12083+#if !defined(CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS)
12084+# define CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS
12085+#endif
12086+#if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS)
12087+# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS
12088+#endif
12089+#if !defined( CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS )
12090+# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS
12091+#endif
12092+#if !defined( CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS )
12093+# define CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS
12094+#endif
12095+#if !defined( CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS )
12096+# define CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS
12097+#endif
12098+
12099+
12100+// The goal of this macro is to avoid evaluation of the arguments, but
12101+// still have the compiler warn on problems inside...
12102+#if !defined(CATCH_INTERNAL_IGNORE_BUT_WARN)
12103+# define CATCH_INTERNAL_IGNORE_BUT_WARN(...)
12104+#endif
12105+
12106+#if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10)
12107+# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS
12108+#elif defined(__clang__) && (__clang_major__ < 5)
12109+# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS
12110+#endif
12111+
12112+
12113+#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
12114+#define CATCH_TRY if ((true))
12115+#define CATCH_CATCH_ALL if ((false))
12116+#define CATCH_CATCH_ANON(type) if ((false))
12117+#else
12118+#define CATCH_TRY try
12119+#define CATCH_CATCH_ALL catch (...)
12120+#define CATCH_CATCH_ANON(type) catch (type)
12121+#endif
12122+
12123+#if defined(CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_NO_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR)
12124+#define CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
12125+#endif
12126+
12127+#if defined( CATCH_PLATFORM_WINDOWS ) && \
12128+ !defined( CATCH_CONFIG_COLOUR_WIN32 ) && \
12129+ !defined( CATCH_CONFIG_NO_COLOUR_WIN32 ) && \
12130+ !defined( CATCH_INTERNAL_CONFIG_NO_COLOUR_WIN32 )
12131+# define CATCH_CONFIG_COLOUR_WIN32
12132+#endif
12133+
12134+#if defined( CATCH_CONFIG_SHARED_LIBRARY ) && defined( _MSC_VER ) && \
12135+ !defined( CATCH_CONFIG_STATIC )
12136+# ifdef Catch2_EXPORTS
12137+# define CATCH_EXPORT //__declspec( dllexport ) // not needed
12138+# else
12139+# define CATCH_EXPORT __declspec( dllimport )
12140+# endif
12141+#else
12142+# define CATCH_EXPORT
12143+#endif
12144+
12145+#endif // CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED
12146+
12147+
12148+#ifndef CATCH_CONTEXT_HPP_INCLUDED
12149+#define CATCH_CONTEXT_HPP_INCLUDED
12150+
12151+
12152+namespace Catch {
12153+
12154+ class IResultCapture;
12155+ class IConfig;
12156+
12157+ class Context {
12158+ IConfig const* m_config = nullptr;
12159+ IResultCapture* m_resultCapture = nullptr;
12160+
12161+ CATCH_EXPORT static Context* currentContext;
12162+ friend Context& getCurrentMutableContext();
12163+ friend Context const& getCurrentContext();
12164+ static void createContext();
12165+ friend void cleanUpContext();
12166+
12167+ public:
12168+ IResultCapture* getResultCapture() const { return m_resultCapture; }
12169+ IConfig const* getConfig() const { return m_config; }
12170+ void setResultCapture( IResultCapture* resultCapture );
12171+ void setConfig( IConfig const* config );
12172+ };
12173+
12174+ Context& getCurrentMutableContext();
12175+
12176+ inline Context const& getCurrentContext() {
12177+ // We duplicate the logic from `getCurrentMutableContext` here,
12178+ // to avoid paying the call overhead in debug mode.
12179+ if ( !Context::currentContext ) { Context::createContext(); }
12180+ // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)
12181+ return *Context::currentContext;
12182+ }
12183+
12184+ void cleanUpContext();
12185+
12186+ class SimplePcg32;
12187+ SimplePcg32& sharedRng();
12188+}
12189+
12190+#endif // CATCH_CONTEXT_HPP_INCLUDED
12191+
12192+
12193+#ifndef CATCH_MOVE_AND_FORWARD_HPP_INCLUDED
12194+#define CATCH_MOVE_AND_FORWARD_HPP_INCLUDED
12195+
12196+#include <type_traits>
12197+
12198+//! Replacement for std::move with better compile time performance
12199+#define CATCH_MOVE(...) static_cast<std::remove_reference_t<decltype(__VA_ARGS__)>&&>(__VA_ARGS__)
12200+
12201+//! Replacement for std::forward with better compile time performance
12202+#define CATCH_FORWARD(...) static_cast<decltype(__VA_ARGS__)&&>(__VA_ARGS__)
12203+
12204+#endif // CATCH_MOVE_AND_FORWARD_HPP_INCLUDED
12205+
12206+
12207+#ifndef CATCH_TEST_FAILURE_EXCEPTION_HPP_INCLUDED
12208+#define CATCH_TEST_FAILURE_EXCEPTION_HPP_INCLUDED
12209+
12210+namespace Catch {
12211+
12212+ //! Used to signal that an assertion macro failed
12213+ struct TestFailureException{};
12214+ //! Used to signal that the remainder of a test should be skipped
12215+ struct TestSkipException {};
12216+
12217+ /**
12218+ * Outlines throwing of `TestFailureException` into a single TU
12219+ *
12220+ * Also handles `CATCH_CONFIG_DISABLE_EXCEPTIONS` for callers.
12221+ */
12222+ [[noreturn]] void throw_test_failure_exception();
12223+
12224+ /**
12225+ * Outlines throwing of `TestSkipException` into a single TU
12226+ *
12227+ * Also handles `CATCH_CONFIG_DISABLE_EXCEPTIONS` for callers.
12228+ */
12229+ [[noreturn]] void throw_test_skip_exception();
12230+
12231+} // namespace Catch
12232+
12233+#endif // CATCH_TEST_FAILURE_EXCEPTION_HPP_INCLUDED
12234+
12235+
12236+#ifndef CATCH_UNIQUE_NAME_HPP_INCLUDED
12237+#define CATCH_UNIQUE_NAME_HPP_INCLUDED
12238+
12239+
12240+
12241+
12242+/** \file
12243+ * Wrapper for the CONFIG configuration option
12244+ *
12245+ * When generating internal unique names, there are two options. Either
12246+ * we mix in the current line number, or mix in an incrementing number.
12247+ * We prefer the latter, using `__COUNTER__`, but users might want to
12248+ * use the former.
12249+ */
12250+
12251+#ifndef CATCH_CONFIG_COUNTER_HPP_INCLUDED
12252+#define CATCH_CONFIG_COUNTER_HPP_INCLUDED
12253+
12254+
12255+#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L )
12256+ #define CATCH_INTERNAL_CONFIG_COUNTER
12257+#endif
12258+
12259+#if defined( CATCH_INTERNAL_CONFIG_COUNTER ) && \
12260+ !defined( CATCH_CONFIG_NO_COUNTER ) && \
12261+ !defined( CATCH_CONFIG_COUNTER )
12262+# define CATCH_CONFIG_COUNTER
12263+#endif
12264+
12265+
12266+#endif // CATCH_CONFIG_COUNTER_HPP_INCLUDED
12267+#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line
12268+#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line )
12269+#ifdef CATCH_CONFIG_COUNTER
12270+# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ )
12271+#else
12272+# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ )
12273+#endif
12274+
12275+#endif // CATCH_UNIQUE_NAME_HPP_INCLUDED
12276+
12277+
12278+#ifndef CATCH_INTERFACES_CAPTURE_HPP_INCLUDED
12279+#define CATCH_INTERFACES_CAPTURE_HPP_INCLUDED
12280+
12281+#include <string>
12282+#include <chrono>
12283+
12284+
12285+
12286+#ifndef CATCH_STRINGREF_HPP_INCLUDED
12287+#define CATCH_STRINGREF_HPP_INCLUDED
12288+
12289+#include <cstddef>
12290+#include <string>
12291+#include <iosfwd>
12292+#include <cassert>
12293+
12294+#include <cstring>
12295+
12296+namespace Catch {
12297+
12298+ /// A non-owning string class (similar to the forthcoming std::string_view)
12299+ /// Note that, because a StringRef may be a substring of another string,
12300+ /// it may not be null terminated.
12301+ class StringRef {
12302+ public:
12303+ using size_type = std::size_t;
12304+ using const_iterator = const char*;
12305+
12306+ static constexpr size_type npos{ static_cast<size_type>( -1 ) };
12307+
12308+ private:
12309+ static constexpr char const* const s_empty = "";
12310+
12311+ char const* m_start = s_empty;
12312+ size_type m_size = 0;
12313+
12314+ public: // construction
12315+ constexpr StringRef() noexcept = default;
12316+
12317+ StringRef( char const* rawChars ) noexcept;
12318+
12319+ constexpr StringRef( char const* rawChars, size_type size ) noexcept
12320+ : m_start( rawChars ),
12321+ m_size( size )
12322+ {}
12323+
12324+ StringRef( std::string const& stdString ) noexcept
12325+ : m_start( stdString.c_str() ),
12326+ m_size( stdString.size() )
12327+ {}
12328+
12329+ explicit operator std::string() const {
12330+ return std::string(m_start, m_size);
12331+ }
12332+
12333+ public: // operators
12334+ auto operator == ( StringRef other ) const noexcept -> bool {
12335+ return m_size == other.m_size
12336+ && (std::memcmp( m_start, other.m_start, m_size ) == 0);
12337+ }
12338+ auto operator != (StringRef other) const noexcept -> bool {
12339+ return !(*this == other);
12340+ }
12341+
12342+ constexpr auto operator[] ( size_type index ) const noexcept -> char {
12343+ assert(index < m_size);
12344+ return m_start[index];
12345+ }
12346+
12347+ bool operator<(StringRef rhs) const noexcept;
12348+
12349+ public: // named queries
12350+ constexpr auto empty() const noexcept -> bool {
12351+ return m_size == 0;
12352+ }
12353+ constexpr auto size() const noexcept -> size_type {
12354+ return m_size;
12355+ }
12356+
12357+ // Returns a substring of [start, start + length).
12358+ // If start + length > size(), then the substring is [start, size()).
12359+ // If start > size(), then the substring is empty.
12360+ constexpr StringRef substr(size_type start, size_type length) const noexcept {
12361+ if (start < m_size) {
12362+ const auto shortened_size = m_size - start;
12363+ return StringRef(m_start + start, (shortened_size < length) ? shortened_size : length);
12364+ } else {
12365+ return StringRef();
12366+ }
12367+ }
12368+
12369+ // Returns the current start pointer. May not be null-terminated.
12370+ constexpr char const* data() const noexcept {
12371+ return m_start;
12372+ }
12373+
12374+ constexpr const_iterator begin() const { return m_start; }
12375+ constexpr const_iterator end() const { return m_start + m_size; }
12376+
12377+
12378+ friend std::string& operator += (std::string& lhs, StringRef rhs);
12379+ friend std::ostream& operator << (std::ostream& os, StringRef str);
12380+ friend std::string operator+(StringRef lhs, StringRef rhs);
12381+
12382+ /**
12383+ * Provides a three-way comparison with rhs
12384+ *
12385+ * Returns negative number if lhs < rhs, 0 if lhs == rhs, and a positive
12386+ * number if lhs > rhs
12387+ */
12388+ int compare( StringRef rhs ) const;
12389+ };
12390+
12391+
12392+ constexpr auto operator ""_sr( char const* rawChars, std::size_t size ) noexcept -> StringRef {
12393+ return StringRef( rawChars, size );
12394+ }
12395+} // namespace Catch
12396+
12397+constexpr auto operator ""_catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef {
12398+ return Catch::StringRef( rawChars, size );
12399+}
12400+
12401+#endif // CATCH_STRINGREF_HPP_INCLUDED
12402+
12403+
12404+#ifndef CATCH_RESULT_TYPE_HPP_INCLUDED
12405+#define CATCH_RESULT_TYPE_HPP_INCLUDED
12406+
12407+namespace Catch {
12408+
12409+ // ResultWas::OfType enum
12410+ struct ResultWas { enum OfType {
12411+ Unknown = -1,
12412+ Ok = 0,
12413+ Info = 1,
12414+ Warning = 2,
12415+ // TODO: Should explicit skip be considered "not OK" (cf. isOk)? I.e., should it have the failure bit?
12416+ ExplicitSkip = 4,
12417+
12418+ FailureBit = 0x10,
12419+
12420+ ExpressionFailed = FailureBit | 1,
12421+ ExplicitFailure = FailureBit | 2,
12422+
12423+ Exception = 0x100 | FailureBit,
12424+
12425+ ThrewException = Exception | 1,
12426+ DidntThrowException = Exception | 2,
12427+
12428+ FatalErrorCondition = 0x200 | FailureBit
12429+
12430+ }; };
12431+
12432+ bool isOk( ResultWas::OfType resultType );
12433+ bool isJustInfo( int flags );
12434+
12435+
12436+ // ResultDisposition::Flags enum
12437+ struct ResultDisposition { enum Flags {
12438+ Normal = 0x01,
12439+
12440+ ContinueOnFailure = 0x02, // Failures fail test, but execution continues
12441+ FalseTest = 0x04, // Prefix expression with !
12442+ SuppressFail = 0x08 // Failures are reported but do not fail the test
12443+ }; };
12444+
12445+ ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs );
12446+
12447+ bool shouldContinueOnFailure( int flags );
12448+ inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; }
12449+ bool shouldSuppressFailure( int flags );
12450+
12451+} // end namespace Catch
12452+
12453+#endif // CATCH_RESULT_TYPE_HPP_INCLUDED
12454+
12455+
12456+#ifndef CATCH_UNIQUE_PTR_HPP_INCLUDED
12457+#define CATCH_UNIQUE_PTR_HPP_INCLUDED
12458+
12459+#include <cassert>
12460+#include <type_traits>
12461+
12462+
12463+namespace Catch {
12464+namespace Detail {
12465+ /**
12466+ * A reimplementation of `std::unique_ptr` for improved compilation performance
12467+ *
12468+ * Does not support arrays nor custom deleters.
12469+ */
12470+ template <typename T>
12471+ class unique_ptr {
12472+ T* m_ptr;
12473+ public:
12474+ constexpr unique_ptr(std::nullptr_t = nullptr):
12475+ m_ptr{}
12476+ {}
12477+ explicit constexpr unique_ptr(T* ptr):
12478+ m_ptr(ptr)
12479+ {}
12480+
12481+ template <typename U, typename = std::enable_if_t<std::is_base_of<T, U>::value>>
12482+ unique_ptr(unique_ptr<U>&& from):
12483+ m_ptr(from.release())
12484+ {}
12485+
12486+ template <typename U, typename = std::enable_if_t<std::is_base_of<T, U>::value>>
12487+ unique_ptr& operator=(unique_ptr<U>&& from) {
12488+ reset(from.release());
12489+
12490+ return *this;
12491+ }
12492+
12493+ unique_ptr(unique_ptr const&) = delete;
12494+ unique_ptr& operator=(unique_ptr const&) = delete;
12495+
12496+ unique_ptr(unique_ptr&& rhs) noexcept:
12497+ m_ptr(rhs.m_ptr) {
12498+ rhs.m_ptr = nullptr;
12499+ }
12500+ unique_ptr& operator=(unique_ptr&& rhs) noexcept {
12501+ reset(rhs.release());
12502+
12503+ return *this;
12504+ }
12505+
12506+ ~unique_ptr() {
12507+ delete m_ptr;
12508+ }
12509+
12510+ T& operator*() {
12511+ assert(m_ptr);
12512+ return *m_ptr;
12513+ }
12514+ T const& operator*() const {
12515+ assert(m_ptr);
12516+ return *m_ptr;
12517+ }
12518+ T* operator->() noexcept {
12519+ assert(m_ptr);
12520+ return m_ptr;
12521+ }
12522+ T const* operator->() const noexcept {
12523+ assert(m_ptr);
12524+ return m_ptr;
12525+ }
12526+
12527+ T* get() { return m_ptr; }
12528+ T const* get() const { return m_ptr; }
12529+
12530+ void reset(T* ptr = nullptr) {
12531+ delete m_ptr;
12532+ m_ptr = ptr;
12533+ }
12534+
12535+ T* release() {
12536+ auto temp = m_ptr;
12537+ m_ptr = nullptr;
12538+ return temp;
12539+ }
12540+
12541+ explicit operator bool() const {
12542+ return m_ptr;
12543+ }
12544+
12545+ friend void swap(unique_ptr& lhs, unique_ptr& rhs) {
12546+ auto temp = lhs.m_ptr;
12547+ lhs.m_ptr = rhs.m_ptr;
12548+ rhs.m_ptr = temp;
12549+ }
12550+ };
12551+
12552+ //! Specialization to cause compile-time error for arrays
12553+ template <typename T>
12554+ class unique_ptr<T[]>;
12555+
12556+ template <typename T, typename... Args>
12557+ unique_ptr<T> make_unique(Args&&... args) {
12558+ return unique_ptr<T>(new T(CATCH_FORWARD(args)...));
12559+ }
12560+
12561+
12562+} // end namespace Detail
12563+} // end namespace Catch
12564+
12565+#endif // CATCH_UNIQUE_PTR_HPP_INCLUDED
12566+
12567+
12568+#ifndef CATCH_BENCHMARK_STATS_FWD_HPP_INCLUDED
12569+#define CATCH_BENCHMARK_STATS_FWD_HPP_INCLUDED
12570+
12571+
12572+
12573+// Adapted from donated nonius code.
12574+
12575+#ifndef CATCH_CLOCK_HPP_INCLUDED
12576+#define CATCH_CLOCK_HPP_INCLUDED
12577+
12578+#include <chrono>
12579+
12580+namespace Catch {
12581+ namespace Benchmark {
12582+ using IDuration = std::chrono::nanoseconds;
12583+ using FDuration = std::chrono::duration<double, std::nano>;
12584+
12585+ template <typename Clock>
12586+ using TimePoint = typename Clock::time_point;
12587+
12588+ using default_clock = std::chrono::steady_clock;
12589+ } // namespace Benchmark
12590+} // namespace Catch
12591+
12592+#endif // CATCH_CLOCK_HPP_INCLUDED
12593+
12594+namespace Catch {
12595+
12596+ // We cannot forward declare the type with default template argument
12597+ // multiple times, so it is split out into a separate header so that
12598+ // we can prevent multiple declarations in dependees
12599+ template <typename Duration = Benchmark::FDuration>
12600+ struct BenchmarkStats;
12601+
12602+} // end namespace Catch
12603+
12604+#endif // CATCH_BENCHMARK_STATS_FWD_HPP_INCLUDED
12605+
12606+namespace Catch {
12607+
12608+ class AssertionResult;
12609+ struct AssertionInfo;
12610+ struct SectionInfo;
12611+ struct SectionEndInfo;
12612+ struct MessageInfo;
12613+ struct MessageBuilder;
12614+ struct Counts;
12615+ struct AssertionReaction;
12616+ struct SourceLineInfo;
12617+
12618+ class ITransientExpression;
12619+ class IGeneratorTracker;
12620+
12621+ struct BenchmarkInfo;
12622+
12623+ namespace Generators {
12624+ class GeneratorUntypedBase;
12625+ using GeneratorBasePtr = Catch::Detail::unique_ptr<GeneratorUntypedBase>;
12626+ }
12627+
12628+
12629+ class IResultCapture {
12630+ public:
12631+ virtual ~IResultCapture();
12632+
12633+ virtual void notifyAssertionStarted( AssertionInfo const& info ) = 0;
12634+ virtual bool sectionStarted( StringRef sectionName,
12635+ SourceLineInfo const& sectionLineInfo,
12636+ Counts& assertions ) = 0;
12637+ virtual void sectionEnded( SectionEndInfo&& endInfo ) = 0;
12638+ virtual void sectionEndedEarly( SectionEndInfo&& endInfo ) = 0;
12639+
12640+ virtual IGeneratorTracker*
12641+ acquireGeneratorTracker( StringRef generatorName,
12642+ SourceLineInfo const& lineInfo ) = 0;
12643+ virtual IGeneratorTracker*
12644+ createGeneratorTracker( StringRef generatorName,
12645+ SourceLineInfo lineInfo,
12646+ Generators::GeneratorBasePtr&& generator ) = 0;
12647+
12648+ virtual void benchmarkPreparing( StringRef name ) = 0;
12649+ virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0;
12650+ virtual void benchmarkEnded( BenchmarkStats<> const& stats ) = 0;
12651+ virtual void benchmarkFailed( StringRef error ) = 0;
12652+
12653+ virtual void pushScopedMessage( MessageInfo const& message ) = 0;
12654+ virtual void popScopedMessage( MessageInfo const& message ) = 0;
12655+
12656+ virtual void emplaceUnscopedMessage( MessageBuilder&& builder ) = 0;
12657+
12658+ virtual void handleFatalErrorCondition( StringRef message ) = 0;
12659+
12660+ virtual void handleExpr
12661+ ( AssertionInfo const& info,
12662+ ITransientExpression const& expr,
12663+ AssertionReaction& reaction ) = 0;
12664+ virtual void handleMessage
12665+ ( AssertionInfo const& info,
12666+ ResultWas::OfType resultType,
12667+ StringRef message,
12668+ AssertionReaction& reaction ) = 0;
12669+ virtual void handleUnexpectedExceptionNotThrown
12670+ ( AssertionInfo const& info,
12671+ AssertionReaction& reaction ) = 0;
12672+ virtual void handleUnexpectedInflightException
12673+ ( AssertionInfo const& info,
12674+ std::string&& message,
12675+ AssertionReaction& reaction ) = 0;
12676+ virtual void handleIncomplete
12677+ ( AssertionInfo const& info ) = 0;
12678+ virtual void handleNonExpr
12679+ ( AssertionInfo const &info,
12680+ ResultWas::OfType resultType,
12681+ AssertionReaction &reaction ) = 0;
12682+
12683+
12684+
12685+ virtual bool lastAssertionPassed() = 0;
12686+ virtual void assertionPassed() = 0;
12687+
12688+ // Deprecated, do not use:
12689+ virtual std::string getCurrentTestName() const = 0;
12690+ virtual const AssertionResult* getLastResult() const = 0;
12691+ virtual void exceptionEarlyReported() = 0;
12692+ };
12693+
12694+ IResultCapture& getResultCapture();
12695+}
12696+
12697+#endif // CATCH_INTERFACES_CAPTURE_HPP_INCLUDED
12698+
12699+
12700+#ifndef CATCH_INTERFACES_CONFIG_HPP_INCLUDED
12701+#define CATCH_INTERFACES_CONFIG_HPP_INCLUDED
12702+
12703+
12704+
12705+#ifndef CATCH_NONCOPYABLE_HPP_INCLUDED
12706+#define CATCH_NONCOPYABLE_HPP_INCLUDED
12707+
12708+namespace Catch {
12709+ namespace Detail {
12710+
12711+ //! Deriving classes become noncopyable and nonmovable
12712+ class NonCopyable {
12713+ NonCopyable( NonCopyable const& ) = delete;
12714+ NonCopyable( NonCopyable&& ) = delete;
12715+ NonCopyable& operator=( NonCopyable const& ) = delete;
12716+ NonCopyable& operator=( NonCopyable&& ) = delete;
12717+
12718+ protected:
12719+ NonCopyable() noexcept = default;
12720+ };
12721+
12722+ } // namespace Detail
12723+} // namespace Catch
12724+
12725+#endif // CATCH_NONCOPYABLE_HPP_INCLUDED
12726+
12727+#include <chrono>
12728+#include <iosfwd>
12729+#include <string>
12730+#include <vector>
12731+
12732+namespace Catch {
12733+
12734+ enum class Verbosity {
12735+ Quiet = 0,
12736+ Normal,
12737+ High
12738+ };
12739+
12740+ struct WarnAbout { enum What {
12741+ Nothing = 0x00,
12742+ //! A test case or leaf section did not run any assertions
12743+ NoAssertions = 0x01,
12744+ //! A command line test spec matched no test cases
12745+ UnmatchedTestSpec = 0x02,
12746+ }; };
12747+
12748+ enum class ShowDurations {
12749+ DefaultForReporter,
12750+ Always,
12751+ Never
12752+ };
12753+ enum class TestRunOrder {
12754+ Declared,
12755+ LexicographicallySorted,
12756+ Randomized
12757+ };
12758+ enum class ColourMode : std::uint8_t {
12759+ //! Let Catch2 pick implementation based on platform detection
12760+ PlatformDefault,
12761+ //! Use ANSI colour code escapes
12762+ ANSI,
12763+ //! Use Win32 console colour API
12764+ Win32,
12765+ //! Don't use any colour
12766+ None
12767+ };
12768+ struct WaitForKeypress { enum When {
12769+ Never,
12770+ BeforeStart = 1,
12771+ BeforeExit = 2,
12772+ BeforeStartAndExit = BeforeStart | BeforeExit
12773+ }; };
12774+
12775+ class TestSpec;
12776+ class IStream;
12777+
12778+ class IConfig : public Detail::NonCopyable {
12779+ public:
12780+ virtual ~IConfig();
12781+
12782+ virtual bool allowThrows() const = 0;
12783+ virtual StringRef name() const = 0;
12784+ virtual bool includeSuccessfulResults() const = 0;
12785+ virtual bool shouldDebugBreak() const = 0;
12786+ virtual bool warnAboutMissingAssertions() const = 0;
12787+ virtual bool warnAboutUnmatchedTestSpecs() const = 0;
12788+ virtual bool zeroTestsCountAsSuccess() const = 0;
12789+ virtual int abortAfter() const = 0;
12790+ virtual bool showInvisibles() const = 0;
12791+ virtual ShowDurations showDurations() const = 0;
12792+ virtual double minDuration() const = 0;
12793+ virtual TestSpec const& testSpec() const = 0;
12794+ virtual bool hasTestFilters() const = 0;
12795+ virtual std::vector<std::string> const& getTestsOrTags() const = 0;
12796+ virtual TestRunOrder runOrder() const = 0;
12797+ virtual uint32_t rngSeed() const = 0;
12798+ virtual unsigned int shardCount() const = 0;
12799+ virtual unsigned int shardIndex() const = 0;
12800+ virtual ColourMode defaultColourMode() const = 0;
12801+ virtual std::vector<std::string> const& getSectionsToRun() const = 0;
12802+ virtual Verbosity verbosity() const = 0;
12803+
12804+ virtual bool skipBenchmarks() const = 0;
12805+ virtual bool benchmarkNoAnalysis() const = 0;
12806+ virtual unsigned int benchmarkSamples() const = 0;
12807+ virtual double benchmarkConfidenceInterval() const = 0;
12808+ virtual unsigned int benchmarkResamples() const = 0;
12809+ virtual std::chrono::milliseconds benchmarkWarmupTime() const = 0;
12810+ };
12811+}
12812+
12813+#endif // CATCH_INTERFACES_CONFIG_HPP_INCLUDED
12814+
12815+
12816+#ifndef CATCH_INTERFACES_REGISTRY_HUB_HPP_INCLUDED
12817+#define CATCH_INTERFACES_REGISTRY_HUB_HPP_INCLUDED
12818+
12819+
12820+#include <string>
12821+
12822+namespace Catch {
12823+
12824+ class TestCaseHandle;
12825+ struct TestCaseInfo;
12826+ class ITestCaseRegistry;
12827+ class IExceptionTranslatorRegistry;
12828+ class IExceptionTranslator;
12829+ class ReporterRegistry;
12830+ class IReporterFactory;
12831+ class ITagAliasRegistry;
12832+ class ITestInvoker;
12833+ class IMutableEnumValuesRegistry;
12834+ struct SourceLineInfo;
12835+
12836+ class StartupExceptionRegistry;
12837+ class EventListenerFactory;
12838+
12839+ using IReporterFactoryPtr = Detail::unique_ptr<IReporterFactory>;
12840+
12841+ class IRegistryHub {
12842+ public:
12843+ virtual ~IRegistryHub(); // = default
12844+
12845+ virtual ReporterRegistry const& getReporterRegistry() const = 0;
12846+ virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0;
12847+ virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0;
12848+ virtual IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const = 0;
12849+
12850+
12851+ virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0;
12852+ };
12853+
12854+ class IMutableRegistryHub {
12855+ public:
12856+ virtual ~IMutableRegistryHub(); // = default
12857+ virtual void registerReporter( std::string const& name, IReporterFactoryPtr factory ) = 0;
12858+ virtual void registerListener( Detail::unique_ptr<EventListenerFactory> factory ) = 0;
12859+ virtual void registerTest(Detail::unique_ptr<TestCaseInfo>&& testInfo, Detail::unique_ptr<ITestInvoker>&& invoker) = 0;
12860+ virtual void registerTranslator( Detail::unique_ptr<IExceptionTranslator>&& translator ) = 0;
12861+ virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0;
12862+ virtual void registerStartupException() noexcept = 0;
12863+ virtual IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() = 0;
12864+ };
12865+
12866+ IRegistryHub const& getRegistryHub();
12867+ IMutableRegistryHub& getMutableRegistryHub();
12868+ void cleanUp();
12869+ std::string translateActiveException();
12870+
12871+}
12872+
12873+#endif // CATCH_INTERFACES_REGISTRY_HUB_HPP_INCLUDED
12874+
12875+
12876+#ifndef CATCH_BENCHMARK_STATS_HPP_INCLUDED
12877+#define CATCH_BENCHMARK_STATS_HPP_INCLUDED
12878+
12879+
12880+
12881+// Adapted from donated nonius code.
12882+
12883+#ifndef CATCH_ESTIMATE_HPP_INCLUDED
12884+#define CATCH_ESTIMATE_HPP_INCLUDED
12885+
12886+namespace Catch {
12887+ namespace Benchmark {
12888+ template <typename Type>
12889+ struct Estimate {
12890+ Type point;
12891+ Type lower_bound;
12892+ Type upper_bound;
12893+ double confidence_interval;
12894+ };
12895+ } // namespace Benchmark
12896+} // namespace Catch
12897+
12898+#endif // CATCH_ESTIMATE_HPP_INCLUDED
12899+
12900+
12901+// Adapted from donated nonius code.
12902+
12903+#ifndef CATCH_OUTLIER_CLASSIFICATION_HPP_INCLUDED
12904+#define CATCH_OUTLIER_CLASSIFICATION_HPP_INCLUDED
12905+
12906+namespace Catch {
12907+ namespace Benchmark {
12908+ struct OutlierClassification {
12909+ int samples_seen = 0;
12910+ int low_severe = 0; // more than 3 times IQR below Q1
12911+ int low_mild = 0; // 1.5 to 3 times IQR below Q1
12912+ int high_mild = 0; // 1.5 to 3 times IQR above Q3
12913+ int high_severe = 0; // more than 3 times IQR above Q3
12914+
12915+ int total() const {
12916+ return low_severe + low_mild + high_mild + high_severe;
12917+ }
12918+ };
12919+ } // namespace Benchmark
12920+} // namespace Catch
12921+
12922+#endif // CATCH_OUTLIERS_CLASSIFICATION_HPP_INCLUDED
12923+// The fwd decl & default specialization needs to be seen by VS2017 before
12924+// BenchmarkStats itself, or VS2017 will report compilation error.
12925+
12926+#include <string>
12927+#include <vector>
12928+
12929+namespace Catch {
12930+
12931+ struct BenchmarkInfo {
12932+ std::string name;
12933+ double estimatedDuration;
12934+ int iterations;
12935+ unsigned int samples;
12936+ unsigned int resamples;
12937+ double clockResolution;
12938+ double clockCost;
12939+ };
12940+
12941+ // We need to keep template parameter for backwards compatibility,
12942+ // but we also do not want to use the template paraneter.
12943+ template <class Dummy>
12944+ struct BenchmarkStats {
12945+ BenchmarkInfo info;
12946+
12947+ std::vector<Benchmark::FDuration> samples;
12948+ Benchmark::Estimate<Benchmark::FDuration> mean;
12949+ Benchmark::Estimate<Benchmark::FDuration> standardDeviation;
12950+ Benchmark::OutlierClassification outliers;
12951+ double outlierVariance;
12952+ };
12953+
12954+
12955+} // end namespace Catch
12956+
12957+#endif // CATCH_BENCHMARK_STATS_HPP_INCLUDED
12958+
12959+
12960+// Adapted from donated nonius code.
12961+
12962+#ifndef CATCH_ENVIRONMENT_HPP_INCLUDED
12963+#define CATCH_ENVIRONMENT_HPP_INCLUDED
12964+
12965+
12966+namespace Catch {
12967+ namespace Benchmark {
12968+ struct EnvironmentEstimate {
12969+ FDuration mean;
12970+ OutlierClassification outliers;
12971+ };
12972+ struct Environment {
12973+ EnvironmentEstimate clock_resolution;
12974+ EnvironmentEstimate clock_cost;
12975+ };
12976+ } // namespace Benchmark
12977+} // namespace Catch
12978+
12979+#endif // CATCH_ENVIRONMENT_HPP_INCLUDED
12980+
12981+
12982+// Adapted from donated nonius code.
12983+
12984+#ifndef CATCH_EXECUTION_PLAN_HPP_INCLUDED
12985+#define CATCH_EXECUTION_PLAN_HPP_INCLUDED
12986+
12987+
12988+
12989+// Adapted from donated nonius code.
12990+
12991+#ifndef CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED
12992+#define CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED
12993+
12994+
12995+
12996+// Adapted from donated nonius code.
12997+
12998+#ifndef CATCH_CHRONOMETER_HPP_INCLUDED
12999+#define CATCH_CHRONOMETER_HPP_INCLUDED
13000+
13001+
13002+
13003+// Adapted from donated nonius code.
13004+
13005+#ifndef CATCH_OPTIMIZER_HPP_INCLUDED
13006+#define CATCH_OPTIMIZER_HPP_INCLUDED
13007+
13008+#if defined(_MSC_VER) || defined(__IAR_SYSTEMS_ICC__)
13009+# include <atomic> // atomic_thread_fence
13010+#endif
13011+
13012+
13013+#include <type_traits>
13014+
13015+namespace Catch {
13016+ namespace Benchmark {
13017+#if defined(__GNUC__) || defined(__clang__)
13018+ template <typename T>
13019+ inline void keep_memory(T* p) {
13020+ asm volatile("" : : "g"(p) : "memory");
13021+ }
13022+ inline void keep_memory() {
13023+ asm volatile("" : : : "memory");
13024+ }
13025+
13026+ namespace Detail {
13027+ inline void optimizer_barrier() { keep_memory(); }
13028+ } // namespace Detail
13029+#elif defined(_MSC_VER) || defined(__IAR_SYSTEMS_ICC__)
13030+
13031+#if defined(_MSVC_VER)
13032+#pragma optimize("", off)
13033+#elif defined(__IAR_SYSTEMS_ICC__)
13034+// For IAR the pragma only affects the following function
13035+#pragma optimize=disable
13036+#endif
13037+ template <typename T>
13038+ inline void keep_memory(T* p) {
13039+ // thanks @milleniumbug
13040+ *reinterpret_cast<char volatile*>(p) = *reinterpret_cast<char const volatile*>(p);
13041+ }
13042+ // TODO equivalent keep_memory()
13043+#if defined(_MSVC_VER)
13044+#pragma optimize("", on)
13045+#endif
13046+
13047+ namespace Detail {
13048+ inline void optimizer_barrier() {
13049+ std::atomic_thread_fence(std::memory_order_seq_cst);
13050+ }
13051+ } // namespace Detail
13052+
13053+#endif
13054+
13055+ template <typename T>
13056+ inline void deoptimize_value(T&& x) {
13057+ keep_memory(&x);
13058+ }
13059+
13060+ template <typename Fn, typename... Args>
13061+ inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> std::enable_if_t<!std::is_same<void, decltype(fn(args...))>::value> {
13062+ deoptimize_value(CATCH_FORWARD(fn) (CATCH_FORWARD(args)...));
13063+ }
13064+
13065+ template <typename Fn, typename... Args>
13066+ inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> std::enable_if_t<std::is_same<void, decltype(fn(args...))>::value> {
13067+ CATCH_FORWARD((fn)) (CATCH_FORWARD(args)...);
13068+ }
13069+ } // namespace Benchmark
13070+} // namespace Catch
13071+
13072+#endif // CATCH_OPTIMIZER_HPP_INCLUDED
13073+
13074+
13075+#ifndef CATCH_META_HPP_INCLUDED
13076+#define CATCH_META_HPP_INCLUDED
13077+
13078+#include <type_traits>
13079+
13080+namespace Catch {
13081+ template <typename>
13082+ struct true_given : std::true_type {};
13083+
13084+ struct is_callable_tester {
13085+ template <typename Fun, typename... Args>
13086+ static true_given<decltype(std::declval<Fun>()(std::declval<Args>()...))> test(int);
13087+ template <typename...>
13088+ static std::false_type test(...);
13089+ };
13090+
13091+ template <typename T>
13092+ struct is_callable;
13093+
13094+ template <typename Fun, typename... Args>
13095+ struct is_callable<Fun(Args...)> : decltype(is_callable_tester::test<Fun, Args...>(0)) {};
13096+
13097+
13098+#if defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703
13099+ // std::result_of is deprecated in C++17 and removed in C++20. Hence, it is
13100+ // replaced with std::invoke_result here.
13101+ template <typename Func, typename... U>
13102+ using FunctionReturnType = std::remove_reference_t<std::remove_cv_t<std::invoke_result_t<Func, U...>>>;
13103+#else
13104+ template <typename Func, typename... U>
13105+ using FunctionReturnType = std::remove_reference_t<std::remove_cv_t<std::result_of_t<Func(U...)>>>;
13106+#endif
13107+
13108+} // namespace Catch
13109+
13110+namespace mpl_{
13111+ struct na;
13112+}
13113+
13114+#endif // CATCH_META_HPP_INCLUDED
13115+
13116+namespace Catch {
13117+ namespace Benchmark {
13118+ namespace Detail {
13119+ struct ChronometerConcept {
13120+ virtual void start() = 0;
13121+ virtual void finish() = 0;
13122+ virtual ~ChronometerConcept(); // = default;
13123+
13124+ ChronometerConcept() = default;
13125+ ChronometerConcept(ChronometerConcept const&) = default;
13126+ ChronometerConcept& operator=(ChronometerConcept const&) = default;
13127+ };
13128+ template <typename Clock>
13129+ struct ChronometerModel final : public ChronometerConcept {
13130+ void start() override { started = Clock::now(); }
13131+ void finish() override { finished = Clock::now(); }
13132+
13133+ IDuration elapsed() const {
13134+ return std::chrono::duration_cast<std::chrono::nanoseconds>(
13135+ finished - started );
13136+ }
13137+
13138+ TimePoint<Clock> started;
13139+ TimePoint<Clock> finished;
13140+ };
13141+ } // namespace Detail
13142+
13143+ struct Chronometer {
13144+ public:
13145+ template <typename Fun>
13146+ void measure(Fun&& fun) { measure(CATCH_FORWARD(fun), is_callable<Fun(int)>()); }
13147+
13148+ int runs() const { return repeats; }
13149+
13150+ Chronometer(Detail::ChronometerConcept& meter, int repeats_)
13151+ : impl(&meter)
13152+ , repeats(repeats_) {}
13153+
13154+ private:
13155+ template <typename Fun>
13156+ void measure(Fun&& fun, std::false_type) {
13157+ measure([&fun](int) { return fun(); }, std::true_type());
13158+ }
13159+
13160+ template <typename Fun>
13161+ void measure(Fun&& fun, std::true_type) {
13162+ Detail::optimizer_barrier();
13163+ impl->start();
13164+ for (int i = 0; i < repeats; ++i) invoke_deoptimized(fun, i);
13165+ impl->finish();
13166+ Detail::optimizer_barrier();
13167+ }
13168+
13169+ Detail::ChronometerConcept* impl;
13170+ int repeats;
13171+ };
13172+ } // namespace Benchmark
13173+} // namespace Catch
13174+
13175+#endif // CATCH_CHRONOMETER_HPP_INCLUDED
13176+
13177+#include <type_traits>
13178+
13179+namespace Catch {
13180+ namespace Benchmark {
13181+ namespace Detail {
13182+ template <typename T, typename U>
13183+ struct is_related
13184+ : std::is_same<std::decay_t<T>, std::decay_t<U>> {};
13185+
13186+ /// We need to reinvent std::function because every piece of code that might add overhead
13187+ /// in a measurement context needs to have consistent performance characteristics so that we
13188+ /// can account for it in the measurement.
13189+ /// Implementations of std::function with optimizations that aren't always applicable, like
13190+ /// small buffer optimizations, are not uncommon.
13191+ /// This is effectively an implementation of std::function without any such optimizations;
13192+ /// it may be slow, but it is consistently slow.
13193+ struct BenchmarkFunction {
13194+ private:
13195+ struct callable {
13196+ virtual void call(Chronometer meter) const = 0;
13197+ virtual Catch::Detail::unique_ptr<callable> clone() const = 0;
13198+ virtual ~callable(); // = default;
13199+
13200+ callable() = default;
13201+ callable(callable const&) = default;
13202+ callable& operator=(callable const&) = default;
13203+ };
13204+ template <typename Fun>
13205+ struct model : public callable {
13206+ model(Fun&& fun_) : fun(CATCH_MOVE(fun_)) {}
13207+ model(Fun const& fun_) : fun(fun_) {}
13208+
13209+ Catch::Detail::unique_ptr<callable> clone() const override {
13210+ return Catch::Detail::make_unique<model<Fun>>( *this );
13211+ }
13212+
13213+ void call(Chronometer meter) const override {
13214+ call(meter, is_callable<Fun(Chronometer)>());
13215+ }
13216+ void call(Chronometer meter, std::true_type) const {
13217+ fun(meter);
13218+ }
13219+ void call(Chronometer meter, std::false_type) const {
13220+ meter.measure(fun);
13221+ }
13222+
13223+ Fun fun;
13224+ };
13225+
13226+ struct do_nothing { void operator()() const {} };
13227+
13228+ template <typename T>
13229+ BenchmarkFunction(model<T>* c) : f(c) {}
13230+
13231+ public:
13232+ BenchmarkFunction()
13233+ : f(new model<do_nothing>{ {} }) {}
13234+
13235+ template <typename Fun,
13236+ std::enable_if_t<!is_related<Fun, BenchmarkFunction>::value, int> = 0>
13237+ BenchmarkFunction(Fun&& fun)
13238+ : f(new model<std::decay_t<Fun>>(CATCH_FORWARD(fun))) {}
13239+
13240+ BenchmarkFunction( BenchmarkFunction&& that ) noexcept:
13241+ f( CATCH_MOVE( that.f ) ) {}
13242+
13243+ BenchmarkFunction(BenchmarkFunction const& that)
13244+ : f(that.f->clone()) {}
13245+
13246+ BenchmarkFunction&
13247+ operator=( BenchmarkFunction&& that ) noexcept {
13248+ f = CATCH_MOVE( that.f );
13249+ return *this;
13250+ }
13251+
13252+ BenchmarkFunction& operator=(BenchmarkFunction const& that) {
13253+ f = that.f->clone();
13254+ return *this;
13255+ }
13256+
13257+ void operator()(Chronometer meter) const { f->call(meter); }
13258+
13259+ private:
13260+ Catch::Detail::unique_ptr<callable> f;
13261+ };
13262+ } // namespace Detail
13263+ } // namespace Benchmark
13264+} // namespace Catch
13265+
13266+#endif // CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED
13267+
13268+
13269+// Adapted from donated nonius code.
13270+
13271+#ifndef CATCH_REPEAT_HPP_INCLUDED
13272+#define CATCH_REPEAT_HPP_INCLUDED
13273+
13274+#include <type_traits>
13275+
13276+namespace Catch {
13277+ namespace Benchmark {
13278+ namespace Detail {
13279+ template <typename Fun>
13280+ struct repeater {
13281+ void operator()(int k) const {
13282+ for (int i = 0; i < k; ++i) {
13283+ fun();
13284+ }
13285+ }
13286+ Fun fun;
13287+ };
13288+ template <typename Fun>
13289+ repeater<std::decay_t<Fun>> repeat(Fun&& fun) {
13290+ return { CATCH_FORWARD(fun) };
13291+ }
13292+ } // namespace Detail
13293+ } // namespace Benchmark
13294+} // namespace Catch
13295+
13296+#endif // CATCH_REPEAT_HPP_INCLUDED
13297+
13298+
13299+// Adapted from donated nonius code.
13300+
13301+#ifndef CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED
13302+#define CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED
13303+
13304+
13305+
13306+// Adapted from donated nonius code.
13307+
13308+#ifndef CATCH_MEASURE_HPP_INCLUDED
13309+#define CATCH_MEASURE_HPP_INCLUDED
13310+
13311+
13312+
13313+// Adapted from donated nonius code.
13314+
13315+#ifndef CATCH_COMPLETE_INVOKE_HPP_INCLUDED
13316+#define CATCH_COMPLETE_INVOKE_HPP_INCLUDED
13317+
13318+
13319+namespace Catch {
13320+ namespace Benchmark {
13321+ namespace Detail {
13322+ template <typename T>
13323+ struct CompleteType { using type = T; };
13324+ template <>
13325+ struct CompleteType<void> { struct type {}; };
13326+
13327+ template <typename T>
13328+ using CompleteType_t = typename CompleteType<T>::type;
13329+
13330+ template <typename Result>
13331+ struct CompleteInvoker {
13332+ template <typename Fun, typename... Args>
13333+ static Result invoke(Fun&& fun, Args&&... args) {
13334+ return CATCH_FORWARD(fun)(CATCH_FORWARD(args)...);
13335+ }
13336+ };
13337+ template <>
13338+ struct CompleteInvoker<void> {
13339+ template <typename Fun, typename... Args>
13340+ static CompleteType_t<void> invoke(Fun&& fun, Args&&... args) {
13341+ CATCH_FORWARD(fun)(CATCH_FORWARD(args)...);
13342+ return {};
13343+ }
13344+ };
13345+
13346+ // invoke and not return void :(
13347+ template <typename Fun, typename... Args>
13348+ CompleteType_t<FunctionReturnType<Fun, Args...>> complete_invoke(Fun&& fun, Args&&... args) {
13349+ return CompleteInvoker<FunctionReturnType<Fun, Args...>>::invoke(CATCH_FORWARD(fun), CATCH_FORWARD(args)...);
13350+ }
13351+
13352+ } // namespace Detail
13353+
13354+ template <typename Fun>
13355+ Detail::CompleteType_t<FunctionReturnType<Fun>> user_code(Fun&& fun) {
13356+ return Detail::complete_invoke(CATCH_FORWARD(fun));
13357+ }
13358+ } // namespace Benchmark
13359+} // namespace Catch
13360+
13361+#endif // CATCH_COMPLETE_INVOKE_HPP_INCLUDED
13362+
13363+
13364+// Adapted from donated nonius code.
13365+
13366+#ifndef CATCH_TIMING_HPP_INCLUDED
13367+#define CATCH_TIMING_HPP_INCLUDED
13368+
13369+
13370+#include <type_traits>
13371+
13372+namespace Catch {
13373+ namespace Benchmark {
13374+ template <typename Result>
13375+ struct Timing {
13376+ IDuration elapsed;
13377+ Result result;
13378+ int iterations;
13379+ };
13380+ template <typename Func, typename... Args>
13381+ using TimingOf = Timing<Detail::CompleteType_t<FunctionReturnType<Func, Args...>>>;
13382+ } // namespace Benchmark
13383+} // namespace Catch
13384+
13385+#endif // CATCH_TIMING_HPP_INCLUDED
13386+
13387+namespace Catch {
13388+ namespace Benchmark {
13389+ namespace Detail {
13390+ template <typename Clock, typename Fun, typename... Args>
13391+ TimingOf<Fun, Args...> measure(Fun&& fun, Args&&... args) {
13392+ auto start = Clock::now();
13393+ auto&& r = Detail::complete_invoke(fun, CATCH_FORWARD(args)...);
13394+ auto end = Clock::now();
13395+ auto delta = end - start;
13396+ return { delta, CATCH_FORWARD(r), 1 };
13397+ }
13398+ } // namespace Detail
13399+ } // namespace Benchmark
13400+} // namespace Catch
13401+
13402+#endif // CATCH_MEASURE_HPP_INCLUDED
13403+
13404+#include <type_traits>
13405+
13406+namespace Catch {
13407+ namespace Benchmark {
13408+ namespace Detail {
13409+ template <typename Clock, typename Fun>
13410+ TimingOf<Fun, int> measure_one(Fun&& fun, int iters, std::false_type) {
13411+ return Detail::measure<Clock>(fun, iters);
13412+ }
13413+ template <typename Clock, typename Fun>
13414+ TimingOf<Fun, Chronometer> measure_one(Fun&& fun, int iters, std::true_type) {
13415+ Detail::ChronometerModel<Clock> meter;
13416+ auto&& result = Detail::complete_invoke(fun, Chronometer(meter, iters));
13417+
13418+ return { meter.elapsed(), CATCH_MOVE(result), iters };
13419+ }
13420+
13421+ template <typename Clock, typename Fun>
13422+ using run_for_at_least_argument_t = std::conditional_t<is_callable<Fun(Chronometer)>::value, Chronometer, int>;
13423+
13424+
13425+ [[noreturn]]
13426+ void throw_optimized_away_error();
13427+
13428+ template <typename Clock, typename Fun>
13429+ TimingOf<Fun, run_for_at_least_argument_t<Clock, Fun>>
13430+ run_for_at_least(IDuration how_long,
13431+ const int initial_iterations,
13432+ Fun&& fun) {
13433+ auto iters = initial_iterations;
13434+ while (iters < (1 << 30)) {
13435+ auto&& Timing = measure_one<Clock>(fun, iters, is_callable<Fun(Chronometer)>());
13436+
13437+ if (Timing.elapsed >= how_long) {
13438+ return { Timing.elapsed, CATCH_MOVE(Timing.result), iters };
13439+ }
13440+ iters *= 2;
13441+ }
13442+ throw_optimized_away_error();
13443+ }
13444+ } // namespace Detail
13445+ } // namespace Benchmark
13446+} // namespace Catch
13447+
13448+#endif // CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED
13449+
13450+#include <vector>
13451+
13452+namespace Catch {
13453+ namespace Benchmark {
13454+ struct ExecutionPlan {
13455+ int iterations_per_sample;
13456+ FDuration estimated_duration;
13457+ Detail::BenchmarkFunction benchmark;
13458+ FDuration warmup_time;
13459+ int warmup_iterations;
13460+
13461+ template <typename Clock>
13462+ std::vector<FDuration> run(const IConfig &cfg, Environment env) const {
13463+ // warmup a bit
13464+ Detail::run_for_at_least<Clock>(
13465+ std::chrono::duration_cast<IDuration>( warmup_time ),
13466+ warmup_iterations,
13467+ Detail::repeat( []() { return Clock::now(); } )
13468+ );
13469+
13470+ std::vector<FDuration> times;
13471+ const auto num_samples = cfg.benchmarkSamples();
13472+ times.reserve( num_samples );
13473+ for ( size_t i = 0; i < num_samples; ++i ) {
13474+ Detail::ChronometerModel<Clock> model;
13475+ this->benchmark( Chronometer( model, iterations_per_sample ) );
13476+ auto sample_time = model.elapsed() - env.clock_cost.mean;
13477+ if ( sample_time < FDuration::zero() ) {
13478+ sample_time = FDuration::zero();
13479+ }
13480+ times.push_back(sample_time / iterations_per_sample);
13481+ }
13482+ return times;
13483+ }
13484+ };
13485+ } // namespace Benchmark
13486+} // namespace Catch
13487+
13488+#endif // CATCH_EXECUTION_PLAN_HPP_INCLUDED
13489+
13490+
13491+// Adapted from donated nonius code.
13492+
13493+#ifndef CATCH_ESTIMATE_CLOCK_HPP_INCLUDED
13494+#define CATCH_ESTIMATE_CLOCK_HPP_INCLUDED
13495+
13496+
13497+
13498+// Adapted from donated nonius code.
13499+
13500+#ifndef CATCH_STATS_HPP_INCLUDED
13501+#define CATCH_STATS_HPP_INCLUDED
13502+
13503+
13504+#include <vector>
13505+
13506+namespace Catch {
13507+ namespace Benchmark {
13508+ namespace Detail {
13509+ using sample = std::vector<double>;
13510+
13511+ double weighted_average_quantile( int k,
13512+ int q,
13513+ double* first,
13514+ double* last );
13515+
13516+ OutlierClassification
13517+ classify_outliers( double const* first, double const* last );
13518+
13519+ double mean( double const* first, double const* last );
13520+
13521+ double normal_cdf( double x );
13522+
13523+ double erfc_inv(double x);
13524+
13525+ double normal_quantile(double p);
13526+
13527+ Estimate<double>
13528+ bootstrap( double confidence_level,
13529+ double* first,
13530+ double* last,
13531+ sample const& resample,
13532+ double ( *estimator )( double const*, double const* ) );
13533+
13534+ struct bootstrap_analysis {
13535+ Estimate<double> mean;
13536+ Estimate<double> standard_deviation;
13537+ double outlier_variance;
13538+ };
13539+
13540+ bootstrap_analysis analyse_samples(double confidence_level,
13541+ unsigned int n_resamples,
13542+ double* first,
13543+ double* last);
13544+ } // namespace Detail
13545+ } // namespace Benchmark
13546+} // namespace Catch
13547+
13548+#endif // CATCH_STATS_HPP_INCLUDED
13549+
13550+#include <algorithm>
13551+#include <vector>
13552+#include <cmath>
13553+
13554+namespace Catch {
13555+ namespace Benchmark {
13556+ namespace Detail {
13557+ template <typename Clock>
13558+ std::vector<double> resolution(int k) {
13559+ std::vector<TimePoint<Clock>> times;
13560+ times.reserve(static_cast<size_t>(k + 1));
13561+ for ( int i = 0; i < k + 1; ++i ) {
13562+ times.push_back( Clock::now() );
13563+ }
13564+
13565+ std::vector<double> deltas;
13566+ deltas.reserve(static_cast<size_t>(k));
13567+ for ( size_t idx = 1; idx < times.size(); ++idx ) {
13568+ deltas.push_back( static_cast<double>(
13569+ ( times[idx] - times[idx - 1] ).count() ) );
13570+ }
13571+
13572+ return deltas;
13573+ }
13574+
13575+ constexpr auto warmup_iterations = 10000;
13576+ constexpr auto warmup_time = std::chrono::milliseconds(100);
13577+ constexpr auto minimum_ticks = 1000;
13578+ constexpr auto warmup_seed = 10000;
13579+ constexpr auto clock_resolution_estimation_time = std::chrono::milliseconds(500);
13580+ constexpr auto clock_cost_estimation_time_limit = std::chrono::seconds(1);
13581+ constexpr auto clock_cost_estimation_tick_limit = 100000;
13582+ constexpr auto clock_cost_estimation_time = std::chrono::milliseconds(10);
13583+ constexpr auto clock_cost_estimation_iterations = 10000;
13584+
13585+ template <typename Clock>
13586+ int warmup() {
13587+ return run_for_at_least<Clock>(warmup_time, warmup_seed, &resolution<Clock>)
13588+ .iterations;
13589+ }
13590+ template <typename Clock>
13591+ EnvironmentEstimate estimate_clock_resolution(int iterations) {
13592+ auto r = run_for_at_least<Clock>(clock_resolution_estimation_time, iterations, &resolution<Clock>)
13593+ .result;
13594+ return {
13595+ FDuration(mean(r.data(), r.data() + r.size())),
13596+ classify_outliers(r.data(), r.data() + r.size()),
13597+ };
13598+ }
13599+ template <typename Clock>
13600+ EnvironmentEstimate estimate_clock_cost(FDuration resolution) {
13601+ auto time_limit = (std::min)(
13602+ resolution * clock_cost_estimation_tick_limit,
13603+ FDuration(clock_cost_estimation_time_limit));
13604+ auto time_clock = [](int k) {
13605+ return Detail::measure<Clock>([k] {
13606+ for (int i = 0; i < k; ++i) {
13607+ volatile auto ignored = Clock::now();
13608+ (void)ignored;
13609+ }
13610+ }).elapsed;
13611+ };
13612+ time_clock(1);
13613+ int iters = clock_cost_estimation_iterations;
13614+ auto&& r = run_for_at_least<Clock>(clock_cost_estimation_time, iters, time_clock);
13615+ std::vector<double> times;
13616+ int nsamples = static_cast<int>(std::ceil(time_limit / r.elapsed));
13617+ times.reserve(static_cast<size_t>(nsamples));
13618+ for ( int s = 0; s < nsamples; ++s ) {
13619+ times.push_back( static_cast<double>(
13620+ ( time_clock( r.iterations ) / r.iterations )
13621+ .count() ) );
13622+ }
13623+ return {
13624+ FDuration(mean(times.data(), times.data() + times.size())),
13625+ classify_outliers(times.data(), times.data() + times.size()),
13626+ };
13627+ }
13628+
13629+ template <typename Clock>
13630+ Environment measure_environment() {
13631+#if defined(__clang__)
13632+# pragma clang diagnostic push
13633+# pragma clang diagnostic ignored "-Wexit-time-destructors"
13634+#endif
13635+ static Catch::Detail::unique_ptr<Environment> env;
13636+#if defined(__clang__)
13637+# pragma clang diagnostic pop
13638+#endif
13639+ if (env) {
13640+ return *env;
13641+ }
13642+
13643+ auto iters = Detail::warmup<Clock>();
13644+ auto resolution = Detail::estimate_clock_resolution<Clock>(iters);
13645+ auto cost = Detail::estimate_clock_cost<Clock>(resolution.mean);
13646+
13647+ env = Catch::Detail::make_unique<Environment>( Environment{resolution, cost} );
13648+ return *env;
13649+ }
13650+ } // namespace Detail
13651+ } // namespace Benchmark
13652+} // namespace Catch
13653+
13654+#endif // CATCH_ESTIMATE_CLOCK_HPP_INCLUDED
13655+
13656+
13657+// Adapted from donated nonius code.
13658+
13659+#ifndef CATCH_ANALYSE_HPP_INCLUDED
13660+#define CATCH_ANALYSE_HPP_INCLUDED
13661+
13662+
13663+
13664+// Adapted from donated nonius code.
13665+
13666+#ifndef CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED
13667+#define CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED
13668+
13669+
13670+#include <vector>
13671+
13672+namespace Catch {
13673+ namespace Benchmark {
13674+ struct SampleAnalysis {
13675+ std::vector<FDuration> samples;
13676+ Estimate<FDuration> mean;
13677+ Estimate<FDuration> standard_deviation;
13678+ OutlierClassification outliers;
13679+ double outlier_variance;
13680+ };
13681+ } // namespace Benchmark
13682+} // namespace Catch
13683+
13684+#endif // CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED
13685+
13686+
13687+namespace Catch {
13688+ class IConfig;
13689+
13690+ namespace Benchmark {
13691+ namespace Detail {
13692+ SampleAnalysis analyse(const IConfig &cfg, FDuration* first, FDuration* last);
13693+ } // namespace Detail
13694+ } // namespace Benchmark
13695+} // namespace Catch
13696+
13697+#endif // CATCH_ANALYSE_HPP_INCLUDED
13698+
13699+#include <algorithm>
13700+#include <chrono>
13701+#include <exception>
13702+#include <string>
13703+#include <cmath>
13704+
13705+namespace Catch {
13706+ namespace Benchmark {
13707+ struct Benchmark {
13708+ Benchmark(std::string&& benchmarkName)
13709+ : name(CATCH_MOVE(benchmarkName)) {}
13710+
13711+ template <class FUN>
13712+ Benchmark(std::string&& benchmarkName , FUN &&func)
13713+ : fun(CATCH_MOVE(func)), name(CATCH_MOVE(benchmarkName)) {}
13714+
13715+ template <typename Clock>
13716+ ExecutionPlan prepare(const IConfig &cfg, Environment env) const {
13717+ auto min_time = env.clock_resolution.mean * Detail::minimum_ticks;
13718+ auto run_time = std::max(min_time, std::chrono::duration_cast<decltype(min_time)>(cfg.benchmarkWarmupTime()));
13719+ auto&& test = Detail::run_for_at_least<Clock>(std::chrono::duration_cast<IDuration>(run_time), 1, fun);
13720+ int new_iters = static_cast<int>(std::ceil(min_time * test.iterations / test.elapsed));
13721+ return { new_iters, test.elapsed / test.iterations * new_iters * cfg.benchmarkSamples(), fun, std::chrono::duration_cast<FDuration>(cfg.benchmarkWarmupTime()), Detail::warmup_iterations };
13722+ }
13723+
13724+ template <typename Clock = default_clock>
13725+ void run() {
13726+ static_assert( Clock::is_steady,
13727+ "Benchmarking clock should be steady" );
13728+ auto const* cfg = getCurrentContext().getConfig();
13729+
13730+ auto env = Detail::measure_environment<Clock>();
13731+
13732+ getResultCapture().benchmarkPreparing(name);
13733+ CATCH_TRY{
13734+ auto plan = user_code([&] {
13735+ return prepare<Clock>(*cfg, env);
13736+ });
13737+
13738+ BenchmarkInfo info {
13739+ CATCH_MOVE(name),
13740+ plan.estimated_duration.count(),
13741+ plan.iterations_per_sample,
13742+ cfg->benchmarkSamples(),
13743+ cfg->benchmarkResamples(),
13744+ env.clock_resolution.mean.count(),
13745+ env.clock_cost.mean.count()
13746+ };
13747+
13748+ getResultCapture().benchmarkStarting(info);
13749+
13750+ auto samples = user_code([&] {
13751+ return plan.template run<Clock>(*cfg, env);
13752+ });
13753+
13754+ auto analysis = Detail::analyse(*cfg, samples.data(), samples.data() + samples.size());
13755+ BenchmarkStats<> stats{ CATCH_MOVE(info), CATCH_MOVE(analysis.samples), analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance };
13756+ getResultCapture().benchmarkEnded(stats);
13757+ } CATCH_CATCH_ANON (TestFailureException const&) {
13758+ getResultCapture().benchmarkFailed("Benchmark failed due to failed assertion"_sr);
13759+ } CATCH_CATCH_ALL{
13760+ getResultCapture().benchmarkFailed(translateActiveException());
13761+ // We let the exception go further up so that the
13762+ // test case is marked as failed.
13763+ std::rethrow_exception(std::current_exception());
13764+ }
13765+ }
13766+
13767+ // sets lambda to be used in fun *and* executes benchmark!
13768+ template <typename Fun, std::enable_if_t<!Detail::is_related<Fun, Benchmark>::value, int> = 0>
13769+ Benchmark & operator=(Fun func) {
13770+ auto const* cfg = getCurrentContext().getConfig();
13771+ if (!cfg->skipBenchmarks()) {
13772+ fun = Detail::BenchmarkFunction(func);
13773+ run();
13774+ }
13775+ return *this;
13776+ }
13777+
13778+ explicit operator bool() {
13779+ return true;
13780+ }
13781+
13782+ private:
13783+ Detail::BenchmarkFunction fun;
13784+ std::string name;
13785+ };
13786+ }
13787+} // namespace Catch
13788+
13789+#define INTERNAL_CATCH_GET_1_ARG(arg1, arg2, ...) arg1
13790+#define INTERNAL_CATCH_GET_2_ARG(arg1, arg2, ...) arg2
13791+
13792+#define INTERNAL_CATCH_BENCHMARK(BenchmarkName, name, benchmarkIndex)\
13793+ if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \
13794+ BenchmarkName = [&](int benchmarkIndex)
13795+
13796+#define INTERNAL_CATCH_BENCHMARK_ADVANCED(BenchmarkName, name)\
13797+ if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \
13798+ BenchmarkName = [&]
13799+
13800+#if defined(CATCH_CONFIG_PREFIX_ALL)
13801+
13802+#define CATCH_BENCHMARK(...) \
13803+ INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(CATCH2_INTERNAL_BENCHMARK_), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,))
13804+#define CATCH_BENCHMARK_ADVANCED(name) \
13805+ INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(CATCH2_INTERNAL_BENCHMARK_), name)
13806+
13807+#else
13808+
13809+#define BENCHMARK(...) \
13810+ INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(CATCH2_INTERNAL_BENCHMARK_), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,))
13811+#define BENCHMARK_ADVANCED(name) \
13812+ INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(CATCH2_INTERNAL_BENCHMARK_), name)
13813+
13814+#endif
13815+
13816+#endif // CATCH_BENCHMARK_HPP_INCLUDED
13817+
13818+
13819+// Adapted from donated nonius code.
13820+
13821+#ifndef CATCH_CONSTRUCTOR_HPP_INCLUDED
13822+#define CATCH_CONSTRUCTOR_HPP_INCLUDED
13823+
13824+
13825+#include <type_traits>
13826+
13827+namespace Catch {
13828+ namespace Benchmark {
13829+ namespace Detail {
13830+ template <typename T, bool Destruct>
13831+ struct ObjectStorage
13832+ {
13833+ ObjectStorage() = default;
13834+
13835+ ObjectStorage(const ObjectStorage& other)
13836+ {
13837+ new(&data) T(other.stored_object());
13838+ }
13839+
13840+ ObjectStorage(ObjectStorage&& other)
13841+ {
13842+ new(data) T(CATCH_MOVE(other.stored_object()));
13843+ }
13844+
13845+ ~ObjectStorage() { destruct_on_exit<T>(); }
13846+
13847+ template <typename... Args>
13848+ void construct(Args&&... args)
13849+ {
13850+ new (data) T(CATCH_FORWARD(args)...);
13851+ }
13852+
13853+ template <bool AllowManualDestruction = !Destruct>
13854+ std::enable_if_t<AllowManualDestruction> destruct()
13855+ {
13856+ stored_object().~T();
13857+ }
13858+
13859+ private:
13860+ // If this is a constructor benchmark, destruct the underlying object
13861+ template <typename U>
13862+ void destruct_on_exit(std::enable_if_t<Destruct, U>* = nullptr) { destruct<true>(); }
13863+ // Otherwise, don't
13864+ template <typename U>
13865+ void destruct_on_exit(std::enable_if_t<!Destruct, U>* = nullptr) { }
13866+
13867+#if defined( __GNUC__ ) && __GNUC__ <= 6
13868+# pragma GCC diagnostic push
13869+# pragma GCC diagnostic ignored "-Wstrict-aliasing"
13870+#endif
13871+ T& stored_object() { return *reinterpret_cast<T*>( data ); }
13872+
13873+ T const& stored_object() const {
13874+ return *reinterpret_cast<T const*>( data );
13875+ }
13876+#if defined( __GNUC__ ) && __GNUC__ <= 6
13877+# pragma GCC diagnostic pop
13878+#endif
13879+
13880+ alignas( T ) unsigned char data[sizeof( T )]{};
13881+ };
13882+ } // namespace Detail
13883+
13884+ template <typename T>
13885+ using storage_for = Detail::ObjectStorage<T, true>;
13886+
13887+ template <typename T>
13888+ using destructable_object = Detail::ObjectStorage<T, false>;
13889+ } // namespace Benchmark
13890+} // namespace Catch
13891+
13892+#endif // CATCH_CONSTRUCTOR_HPP_INCLUDED
13893+
13894+#endif // CATCH_BENCHMARK_ALL_HPP_INCLUDED
13895+
13896+
13897+#ifndef CATCH_APPROX_HPP_INCLUDED
13898+#define CATCH_APPROX_HPP_INCLUDED
13899+
13900+
13901+
13902+#ifndef CATCH_TOSTRING_HPP_INCLUDED
13903+#define CATCH_TOSTRING_HPP_INCLUDED
13904+
13905+
13906+#include <vector>
13907+#include <cstddef>
13908+#include <type_traits>
13909+#include <string>
13910+
13911+
13912+
13913+
13914+/** \file
13915+ * Wrapper for the WCHAR configuration option
13916+ *
13917+ * We want to support platforms that do not provide `wchar_t`, so we
13918+ * sometimes have to disable providing wchar_t overloads through Catch2,
13919+ * e.g. the StringMaker specialization for `std::wstring`.
13920+ */
13921+
13922+#ifndef CATCH_CONFIG_WCHAR_HPP_INCLUDED
13923+#define CATCH_CONFIG_WCHAR_HPP_INCLUDED
13924+
13925+
13926+// We assume that WCHAR should be enabled by default, and only disabled
13927+// for a shortlist (so far only DJGPP) of compilers.
13928+
13929+#if defined(__DJGPP__)
13930+# define CATCH_INTERNAL_CONFIG_NO_WCHAR
13931+#endif // __DJGPP__
13932+
13933+#if !defined( CATCH_INTERNAL_CONFIG_NO_WCHAR ) && \
13934+ !defined( CATCH_CONFIG_NO_WCHAR ) && \
13935+ !defined( CATCH_CONFIG_WCHAR )
13936+# define CATCH_CONFIG_WCHAR
13937+#endif
13938+
13939+#endif // CATCH_CONFIG_WCHAR_HPP_INCLUDED
13940+
13941+
13942+#ifndef CATCH_REUSABLE_STRING_STREAM_HPP_INCLUDED
13943+#define CATCH_REUSABLE_STRING_STREAM_HPP_INCLUDED
13944+
13945+
13946+#include <iosfwd>
13947+#include <cstddef>
13948+#include <ostream>
13949+#include <string>
13950+
13951+namespace Catch {
13952+
13953+ class ReusableStringStream : Detail::NonCopyable {
13954+ std::size_t m_index;
13955+ std::ostream* m_oss;
13956+ public:
13957+ ReusableStringStream();
13958+ ~ReusableStringStream();
13959+
13960+ //! Returns the serialized state
13961+ std::string str() const;
13962+ //! Sets internal state to `str`
13963+ void str(std::string const& str);
13964+
13965+#if defined(__GNUC__) && !defined(__clang__)
13966+#pragma GCC diagnostic push
13967+// Old versions of GCC do not understand -Wnonnull-compare
13968+#pragma GCC diagnostic ignored "-Wpragmas"
13969+// Streaming a function pointer triggers Waddress and Wnonnull-compare
13970+// on GCC, because it implicitly converts it to bool and then decides
13971+// that the check it uses (a? true : false) is tautological and cannot
13972+// be null...
13973+#pragma GCC diagnostic ignored "-Waddress"
13974+#pragma GCC diagnostic ignored "-Wnonnull-compare"
13975+#endif
13976+
13977+ template<typename T>
13978+ auto operator << ( T const& value ) -> ReusableStringStream& {
13979+ *m_oss << value;
13980+ return *this;
13981+ }
13982+
13983+#if defined(__GNUC__) && !defined(__clang__)
13984+#pragma GCC diagnostic pop
13985+#endif
13986+ auto get() -> std::ostream& { return *m_oss; }
13987+ };
13988+}
13989+
13990+#endif // CATCH_REUSABLE_STRING_STREAM_HPP_INCLUDED
13991+
13992+
13993+#ifndef CATCH_VOID_TYPE_HPP_INCLUDED
13994+#define CATCH_VOID_TYPE_HPP_INCLUDED
13995+
13996+
13997+namespace Catch {
13998+ namespace Detail {
13999+
14000+ template <typename...>
14001+ struct make_void { using type = void; };
14002+
14003+ template <typename... Ts>
14004+ using void_t = typename make_void<Ts...>::type;
14005+
14006+ } // namespace Detail
14007+} // namespace Catch
14008+
14009+
14010+#endif // CATCH_VOID_TYPE_HPP_INCLUDED
14011+
14012+
14013+#ifndef CATCH_INTERFACES_ENUM_VALUES_REGISTRY_HPP_INCLUDED
14014+#define CATCH_INTERFACES_ENUM_VALUES_REGISTRY_HPP_INCLUDED
14015+
14016+
14017+#include <vector>
14018+
14019+namespace Catch {
14020+
14021+ namespace Detail {
14022+ struct EnumInfo {
14023+ StringRef m_name;
14024+ std::vector<std::pair<int, StringRef>> m_values;
14025+
14026+ ~EnumInfo();
14027+
14028+ StringRef lookup( int value ) const;
14029+ };
14030+ } // namespace Detail
14031+
14032+ class IMutableEnumValuesRegistry {
14033+ public:
14034+ virtual ~IMutableEnumValuesRegistry(); // = default;
14035+
14036+ virtual Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::vector<int> const& values ) = 0;
14037+
14038+ template<typename E>
14039+ Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::initializer_list<E> values ) {
14040+ static_assert(sizeof(int) >= sizeof(E), "Cannot serialize enum to int");
14041+ std::vector<int> intValues;
14042+ intValues.reserve( values.size() );
14043+ for( auto enumValue : values )
14044+ intValues.push_back( static_cast<int>( enumValue ) );
14045+ return registerEnum( enumName, allEnums, intValues );
14046+ }
14047+ };
14048+
14049+} // Catch
14050+
14051+#endif // CATCH_INTERFACES_ENUM_VALUES_REGISTRY_HPP_INCLUDED
14052+
14053+#ifdef CATCH_CONFIG_CPP17_STRING_VIEW
14054+#include <string_view>
14055+#endif
14056+
14057+#ifdef _MSC_VER
14058+#pragma warning(push)
14059+#pragma warning(disable:4180) // We attempt to stream a function (address) by const&, which MSVC complains about but is harmless
14060+#endif
14061+
14062+// We need a dummy global operator<< so we can bring it into Catch namespace later
14063+struct Catch_global_namespace_dummy{};
14064+std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy);
14065+
14066+namespace Catch {
14067+ // Bring in global namespace operator<< for ADL lookup in
14068+ // `IsStreamInsertable` below.
14069+ using ::operator<<;
14070+
14071+ namespace Detail {
14072+
14073+ inline std::size_t catch_strnlen(const char *str, std::size_t n) {
14074+ auto ret = std::char_traits<char>::find(str, n, '\0');
14075+ if (ret != nullptr) {
14076+ return static_cast<std::size_t>(ret - str);
14077+ }
14078+ return n;
14079+ }
14080+
14081+ constexpr StringRef unprintableString = "{?}"_sr;
14082+
14083+ //! Encases `string in quotes, and optionally escapes invisibles
14084+ std::string convertIntoString( StringRef string, bool escapeInvisibles );
14085+
14086+ //! Encases `string` in quotes, and escapes invisibles if user requested
14087+ //! it via CLI
14088+ std::string convertIntoString( StringRef string );
14089+
14090+ std::string rawMemoryToString( const void *object, std::size_t size );
14091+
14092+ template<typename T>
14093+ std::string rawMemoryToString( const T& object ) {
14094+ return rawMemoryToString( &object, sizeof(object) );
14095+ }
14096+
14097+ template<typename T>
14098+ class IsStreamInsertable {
14099+ template<typename Stream, typename U>
14100+ static auto test(int)
14101+ -> decltype(std::declval<Stream&>() << std::declval<U>(), std::true_type());
14102+
14103+ template<typename, typename>
14104+ static auto test(...)->std::false_type;
14105+
14106+ public:
14107+ static const bool value = decltype(test<std::ostream, const T&>(0))::value;
14108+ };
14109+
14110+ template<typename E>
14111+ std::string convertUnknownEnumToString( E e );
14112+
14113+ template<typename T>
14114+ std::enable_if_t<
14115+ !std::is_enum<T>::value && !std::is_base_of<std::exception, T>::value,
14116+ std::string> convertUnstreamable( T const& ) {
14117+ return std::string(Detail::unprintableString);
14118+ }
14119+ template<typename T>
14120+ std::enable_if_t<
14121+ !std::is_enum<T>::value && std::is_base_of<std::exception, T>::value,
14122+ std::string> convertUnstreamable(T const& ex) {
14123+ return ex.what();
14124+ }
14125+
14126+
14127+ template<typename T>
14128+ std::enable_if_t<
14129+ std::is_enum<T>::value,
14130+ std::string> convertUnstreamable( T const& value ) {
14131+ return convertUnknownEnumToString( value );
14132+ }
14133+
14134+#if defined(_MANAGED)
14135+ //! Convert a CLR string to a utf8 std::string
14136+ template<typename T>
14137+ std::string clrReferenceToString( T^ ref ) {
14138+ if (ref == nullptr)
14139+ return std::string("null");
14140+ auto bytes = System::Text::Encoding::UTF8->GetBytes(ref->ToString());
14141+ cli::pin_ptr<System::Byte> p = &bytes[0];
14142+ return std::string(reinterpret_cast<char const *>(p), bytes->Length);
14143+ }
14144+#endif
14145+
14146+ } // namespace Detail
14147+
14148+
14149+ template <typename T, typename = void>
14150+ struct StringMaker {
14151+ template <typename Fake = T>
14152+ static
14153+ std::enable_if_t<::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>
14154+ convert(const Fake& value) {
14155+ ReusableStringStream rss;
14156+ // NB: call using the function-like syntax to avoid ambiguity with
14157+ // user-defined templated operator<< under clang.
14158+ rss.operator<<(value);
14159+ return rss.str();
14160+ }
14161+
14162+ template <typename Fake = T>
14163+ static
14164+ std::enable_if_t<!::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>
14165+ convert( const Fake& value ) {
14166+#if !defined(CATCH_CONFIG_FALLBACK_STRINGIFIER)
14167+ return Detail::convertUnstreamable(value);
14168+#else
14169+ return CATCH_CONFIG_FALLBACK_STRINGIFIER(value);
14170+#endif
14171+ }
14172+ };
14173+
14174+ namespace Detail {
14175+
14176+ // This function dispatches all stringification requests inside of Catch.
14177+ // Should be preferably called fully qualified, like ::Catch::Detail::stringify
14178+ template <typename T>
14179+ std::string stringify(const T& e) {
14180+ return ::Catch::StringMaker<std::remove_cv_t<std::remove_reference_t<T>>>::convert(e);
14181+ }
14182+
14183+ template<typename E>
14184+ std::string convertUnknownEnumToString( E e ) {
14185+ return ::Catch::Detail::stringify(static_cast<std::underlying_type_t<E>>(e));
14186+ }
14187+
14188+#if defined(_MANAGED)
14189+ template <typename T>
14190+ std::string stringify( T^ e ) {
14191+ return ::Catch::StringMaker<T^>::convert(e);
14192+ }
14193+#endif
14194+
14195+ } // namespace Detail
14196+
14197+ // Some predefined specializations
14198+
14199+ template<>
14200+ struct StringMaker<std::string> {
14201+ static std::string convert(const std::string& str);
14202+ };
14203+
14204+#ifdef CATCH_CONFIG_CPP17_STRING_VIEW
14205+ template<>
14206+ struct StringMaker<std::string_view> {
14207+ static std::string convert(std::string_view str);
14208+ };
14209+#endif
14210+
14211+ template<>
14212+ struct StringMaker<char const *> {
14213+ static std::string convert(char const * str);
14214+ };
14215+ template<>
14216+ struct StringMaker<char *> {
14217+ static std::string convert(char * str);
14218+ };
14219+
14220+#if defined(CATCH_CONFIG_WCHAR)
14221+ template<>
14222+ struct StringMaker<std::wstring> {
14223+ static std::string convert(const std::wstring& wstr);
14224+ };
14225+
14226+# ifdef CATCH_CONFIG_CPP17_STRING_VIEW
14227+ template<>
14228+ struct StringMaker<std::wstring_view> {
14229+ static std::string convert(std::wstring_view str);
14230+ };
14231+# endif
14232+
14233+ template<>
14234+ struct StringMaker<wchar_t const *> {
14235+ static std::string convert(wchar_t const * str);
14236+ };
14237+ template<>
14238+ struct StringMaker<wchar_t *> {
14239+ static std::string convert(wchar_t * str);
14240+ };
14241+#endif // CATCH_CONFIG_WCHAR
14242+
14243+ template<size_t SZ>
14244+ struct StringMaker<char[SZ]> {
14245+ static std::string convert(char const* str) {
14246+ return Detail::convertIntoString(
14247+ StringRef( str, Detail::catch_strnlen( str, SZ ) ) );
14248+ }
14249+ };
14250+ template<size_t SZ>
14251+ struct StringMaker<signed char[SZ]> {
14252+ static std::string convert(signed char const* str) {
14253+ auto reinterpreted = reinterpret_cast<char const*>(str);
14254+ return Detail::convertIntoString(
14255+ StringRef(reinterpreted, Detail::catch_strnlen(reinterpreted, SZ)));
14256+ }
14257+ };
14258+ template<size_t SZ>
14259+ struct StringMaker<unsigned char[SZ]> {
14260+ static std::string convert(unsigned char const* str) {
14261+ auto reinterpreted = reinterpret_cast<char const*>(str);
14262+ return Detail::convertIntoString(
14263+ StringRef(reinterpreted, Detail::catch_strnlen(reinterpreted, SZ)));
14264+ }
14265+ };
14266+
14267+#if defined(CATCH_CONFIG_CPP17_BYTE)
14268+ template<>
14269+ struct StringMaker<std::byte> {
14270+ static std::string convert(std::byte value);
14271+ };
14272+#endif // defined(CATCH_CONFIG_CPP17_BYTE)
14273+ template<>
14274+ struct StringMaker<int> {
14275+ static std::string convert(int value);
14276+ };
14277+ template<>
14278+ struct StringMaker<long> {
14279+ static std::string convert(long value);
14280+ };
14281+ template<>
14282+ struct StringMaker<long long> {
14283+ static std::string convert(long long value);
14284+ };
14285+ template<>
14286+ struct StringMaker<unsigned int> {
14287+ static std::string convert(unsigned int value);
14288+ };
14289+ template<>
14290+ struct StringMaker<unsigned long> {
14291+ static std::string convert(unsigned long value);
14292+ };
14293+ template<>
14294+ struct StringMaker<unsigned long long> {
14295+ static std::string convert(unsigned long long value);
14296+ };
14297+
14298+ template<>
14299+ struct StringMaker<bool> {
14300+ static std::string convert(bool b) {
14301+ using namespace std::string_literals;
14302+ return b ? "true"s : "false"s;
14303+ }
14304+ };
14305+
14306+ template<>
14307+ struct StringMaker<char> {
14308+ static std::string convert(char c);
14309+ };
14310+ template<>
14311+ struct StringMaker<signed char> {
14312+ static std::string convert(signed char value);
14313+ };
14314+ template<>
14315+ struct StringMaker<unsigned char> {
14316+ static std::string convert(unsigned char value);
14317+ };
14318+
14319+ template<>
14320+ struct StringMaker<std::nullptr_t> {
14321+ static std::string convert(std::nullptr_t) {
14322+ using namespace std::string_literals;
14323+ return "nullptr"s;
14324+ }
14325+ };
14326+
14327+ template<>
14328+ struct StringMaker<float> {
14329+ static std::string convert(float value);
14330+ CATCH_EXPORT static int precision;
14331+ };
14332+
14333+ template<>
14334+ struct StringMaker<double> {
14335+ static std::string convert(double value);
14336+ CATCH_EXPORT static int precision;
14337+ };
14338+
14339+ template <typename T>
14340+ struct StringMaker<T*> {
14341+ template <typename U>
14342+ static std::string convert(U* p) {
14343+ if (p) {
14344+ return ::Catch::Detail::rawMemoryToString(p);
14345+ } else {
14346+ return "nullptr";
14347+ }
14348+ }
14349+ };
14350+
14351+ template <typename R, typename C>
14352+ struct StringMaker<R C::*> {
14353+ static std::string convert(R C::* p) {
14354+ if (p) {
14355+ return ::Catch::Detail::rawMemoryToString(p);
14356+ } else {
14357+ return "nullptr";
14358+ }
14359+ }
14360+ };
14361+
14362+#if defined(_MANAGED)
14363+ template <typename T>
14364+ struct StringMaker<T^> {
14365+ static std::string convert( T^ ref ) {
14366+ return ::Catch::Detail::clrReferenceToString(ref);
14367+ }
14368+ };
14369+#endif
14370+
14371+ namespace Detail {
14372+ template<typename InputIterator, typename Sentinel = InputIterator>
14373+ std::string rangeToString(InputIterator first, Sentinel last) {
14374+ ReusableStringStream rss;
14375+ rss << "{ ";
14376+ if (first != last) {
14377+ rss << ::Catch::Detail::stringify(*first);
14378+ for (++first; first != last; ++first)
14379+ rss << ", " << ::Catch::Detail::stringify(*first);
14380+ }
14381+ rss << " }";
14382+ return rss.str();
14383+ }
14384+ }
14385+
14386+} // namespace Catch
14387+
14388+//////////////////////////////////////////////////////
14389+// Separate std-lib types stringification, so it can be selectively enabled
14390+// This means that we do not bring in their headers
14391+
14392+#if defined(CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS)
14393+# define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
14394+# define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER
14395+# define CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
14396+# define CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER
14397+#endif
14398+
14399+// Separate std::pair specialization
14400+#if defined(CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER)
14401+#include <utility>
14402+namespace Catch {
14403+ template<typename T1, typename T2>
14404+ struct StringMaker<std::pair<T1, T2> > {
14405+ static std::string convert(const std::pair<T1, T2>& pair) {
14406+ ReusableStringStream rss;
14407+ rss << "{ "
14408+ << ::Catch::Detail::stringify(pair.first)
14409+ << ", "
14410+ << ::Catch::Detail::stringify(pair.second)
14411+ << " }";
14412+ return rss.str();
14413+ }
14414+ };
14415+}
14416+#endif // CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
14417+
14418+#if defined(CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_OPTIONAL)
14419+#include <optional>
14420+namespace Catch {
14421+ template<typename T>
14422+ struct StringMaker<std::optional<T> > {
14423+ static std::string convert(const std::optional<T>& optional) {
14424+ if (optional.has_value()) {
14425+ return ::Catch::Detail::stringify(*optional);
14426+ } else {
14427+ return "{ }";
14428+ }
14429+ }
14430+ };
14431+ template <>
14432+ struct StringMaker<std::nullopt_t> {
14433+ static std::string convert(const std::nullopt_t&) {
14434+ return "{ }";
14435+ }
14436+ };
14437+}
14438+#endif // CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER
14439+
14440+// Separate std::tuple specialization
14441+#if defined(CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER)
14442+#include <tuple>
14443+namespace Catch {
14444+ namespace Detail {
14445+ template<
14446+ typename Tuple,
14447+ std::size_t N = 0,
14448+ bool = (N < std::tuple_size<Tuple>::value)
14449+ >
14450+ struct TupleElementPrinter {
14451+ static void print(const Tuple& tuple, std::ostream& os) {
14452+ os << (N ? ", " : " ")
14453+ << ::Catch::Detail::stringify(std::get<N>(tuple));
14454+ TupleElementPrinter<Tuple, N + 1>::print(tuple, os);
14455+ }
14456+ };
14457+
14458+ template<
14459+ typename Tuple,
14460+ std::size_t N
14461+ >
14462+ struct TupleElementPrinter<Tuple, N, false> {
14463+ static void print(const Tuple&, std::ostream&) {}
14464+ };
14465+
14466+ }
14467+
14468+
14469+ template<typename ...Types>
14470+ struct StringMaker<std::tuple<Types...>> {
14471+ static std::string convert(const std::tuple<Types...>& tuple) {
14472+ ReusableStringStream rss;
14473+ rss << '{';
14474+ Detail::TupleElementPrinter<std::tuple<Types...>>::print(tuple, rss.get());
14475+ rss << " }";
14476+ return rss.str();
14477+ }
14478+ };
14479+}
14480+#endif // CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER
14481+
14482+#if defined(CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_VARIANT)
14483+#include <variant>
14484+namespace Catch {
14485+ template<>
14486+ struct StringMaker<std::monostate> {
14487+ static std::string convert(const std::monostate&) {
14488+ return "{ }";
14489+ }
14490+ };
14491+
14492+ template<typename... Elements>
14493+ struct StringMaker<std::variant<Elements...>> {
14494+ static std::string convert(const std::variant<Elements...>& variant) {
14495+ if (variant.valueless_by_exception()) {
14496+ return "{valueless variant}";
14497+ } else {
14498+ return std::visit(
14499+ [](const auto& value) {
14500+ return ::Catch::Detail::stringify(value);
14501+ },
14502+ variant
14503+ );
14504+ }
14505+ }
14506+ };
14507+}
14508+#endif // CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
14509+
14510+namespace Catch {
14511+ // Import begin/ end from std here
14512+ using std::begin;
14513+ using std::end;
14514+
14515+ namespace Detail {
14516+ template <typename T, typename = void>
14517+ struct is_range_impl : std::false_type {};
14518+
14519+ template <typename T>
14520+ struct is_range_impl<T, void_t<decltype(begin(std::declval<T>()))>> : std::true_type {};
14521+ } // namespace Detail
14522+
14523+ template <typename T>
14524+ struct is_range : Detail::is_range_impl<T> {};
14525+
14526+#if defined(_MANAGED) // Managed types are never ranges
14527+ template <typename T>
14528+ struct is_range<T^> {
14529+ static const bool value = false;
14530+ };
14531+#endif
14532+
14533+ template<typename Range>
14534+ std::string rangeToString( Range const& range ) {
14535+ return ::Catch::Detail::rangeToString( begin( range ), end( range ) );
14536+ }
14537+
14538+ // Handle vector<bool> specially
14539+ template<typename Allocator>
14540+ std::string rangeToString( std::vector<bool, Allocator> const& v ) {
14541+ ReusableStringStream rss;
14542+ rss << "{ ";
14543+ bool first = true;
14544+ for( bool b : v ) {
14545+ if( first )
14546+ first = false;
14547+ else
14548+ rss << ", ";
14549+ rss << ::Catch::Detail::stringify( b );
14550+ }
14551+ rss << " }";
14552+ return rss.str();
14553+ }
14554+
14555+ template<typename R>
14556+ struct StringMaker<R, std::enable_if_t<is_range<R>::value && !::Catch::Detail::IsStreamInsertable<R>::value>> {
14557+ static std::string convert( R const& range ) {
14558+ return rangeToString( range );
14559+ }
14560+ };
14561+
14562+ template <typename T, size_t SZ>
14563+ struct StringMaker<T[SZ]> {
14564+ static std::string convert(T const(&arr)[SZ]) {
14565+ return rangeToString(arr);
14566+ }
14567+ };
14568+
14569+
14570+} // namespace Catch
14571+
14572+// Separate std::chrono::duration specialization
14573+#include <ctime>
14574+#include <ratio>
14575+#include <chrono>
14576+
14577+
14578+namespace Catch {
14579+
14580+template <class Ratio>
14581+struct ratio_string {
14582+ static std::string symbol() {
14583+ Catch::ReusableStringStream rss;
14584+ rss << '[' << Ratio::num << '/'
14585+ << Ratio::den << ']';
14586+ return rss.str();
14587+ }
14588+};
14589+
14590+template <>
14591+struct ratio_string<std::atto> {
14592+ static char symbol() { return 'a'; }
14593+};
14594+template <>
14595+struct ratio_string<std::femto> {
14596+ static char symbol() { return 'f'; }
14597+};
14598+template <>
14599+struct ratio_string<std::pico> {
14600+ static char symbol() { return 'p'; }
14601+};
14602+template <>
14603+struct ratio_string<std::nano> {
14604+ static char symbol() { return 'n'; }
14605+};
14606+template <>
14607+struct ratio_string<std::micro> {
14608+ static char symbol() { return 'u'; }
14609+};
14610+template <>
14611+struct ratio_string<std::milli> {
14612+ static char symbol() { return 'm'; }
14613+};
14614+
14615+ ////////////
14616+ // std::chrono::duration specializations
14617+ template<typename Value, typename Ratio>
14618+ struct StringMaker<std::chrono::duration<Value, Ratio>> {
14619+ static std::string convert(std::chrono::duration<Value, Ratio> const& duration) {
14620+ ReusableStringStream rss;
14621+ rss << duration.count() << ' ' << ratio_string<Ratio>::symbol() << 's';
14622+ return rss.str();
14623+ }
14624+ };
14625+ template<typename Value>
14626+ struct StringMaker<std::chrono::duration<Value, std::ratio<1>>> {
14627+ static std::string convert(std::chrono::duration<Value, std::ratio<1>> const& duration) {
14628+ ReusableStringStream rss;
14629+ rss << duration.count() << " s";
14630+ return rss.str();
14631+ }
14632+ };
14633+ template<typename Value>
14634+ struct StringMaker<std::chrono::duration<Value, std::ratio<60>>> {
14635+ static std::string convert(std::chrono::duration<Value, std::ratio<60>> const& duration) {
14636+ ReusableStringStream rss;
14637+ rss << duration.count() << " m";
14638+ return rss.str();
14639+ }
14640+ };
14641+ template<typename Value>
14642+ struct StringMaker<std::chrono::duration<Value, std::ratio<3600>>> {
14643+ static std::string convert(std::chrono::duration<Value, std::ratio<3600>> const& duration) {
14644+ ReusableStringStream rss;
14645+ rss << duration.count() << " h";
14646+ return rss.str();
14647+ }
14648+ };
14649+
14650+ ////////////
14651+ // std::chrono::time_point specialization
14652+ // Generic time_point cannot be specialized, only std::chrono::time_point<system_clock>
14653+ template<typename Clock, typename Duration>
14654+ struct StringMaker<std::chrono::time_point<Clock, Duration>> {
14655+ static std::string convert(std::chrono::time_point<Clock, Duration> const& time_point) {
14656+ return ::Catch::Detail::stringify(time_point.time_since_epoch()) + " since epoch";
14657+ }
14658+ };
14659+ // std::chrono::time_point<system_clock> specialization
14660+ template<typename Duration>
14661+ struct StringMaker<std::chrono::time_point<std::chrono::system_clock, Duration>> {
14662+ static std::string convert(std::chrono::time_point<std::chrono::system_clock, Duration> const& time_point) {
14663+ auto converted = std::chrono::system_clock::to_time_t(time_point);
14664+
14665+#ifdef _MSC_VER
14666+ std::tm timeInfo = {};
14667+ gmtime_s(&timeInfo, &converted);
14668+#else
14669+ std::tm* timeInfo = std::gmtime(&converted);
14670+#endif
14671+
14672+ auto const timeStampSize = sizeof("2017-01-16T17:06:45Z");
14673+ char timeStamp[timeStampSize];
14674+ const char * const fmt = "%Y-%m-%dT%H:%M:%SZ";
14675+
14676+#ifdef _MSC_VER
14677+ std::strftime(timeStamp, timeStampSize, fmt, &timeInfo);
14678+#else
14679+ std::strftime(timeStamp, timeStampSize, fmt, timeInfo);
14680+#endif
14681+ return std::string(timeStamp, timeStampSize - 1);
14682+ }
14683+ };
14684+}
14685+
14686+
14687+#define INTERNAL_CATCH_REGISTER_ENUM( enumName, ... ) \
14688+namespace Catch { \
14689+ template<> struct StringMaker<enumName> { \
14690+ static std::string convert( enumName value ) { \
14691+ static const auto& enumInfo = ::Catch::getMutableRegistryHub().getMutableEnumValuesRegistry().registerEnum( #enumName, #__VA_ARGS__, { __VA_ARGS__ } ); \
14692+ return static_cast<std::string>(enumInfo.lookup( static_cast<int>( value ) )); \
14693+ } \
14694+ }; \
14695+}
14696+
14697+#define CATCH_REGISTER_ENUM( enumName, ... ) INTERNAL_CATCH_REGISTER_ENUM( enumName, __VA_ARGS__ )
14698+
14699+#ifdef _MSC_VER
14700+#pragma warning(pop)
14701+#endif
14702+
14703+#endif // CATCH_TOSTRING_HPP_INCLUDED
14704+
14705+#include <type_traits>
14706+
14707+namespace Catch {
14708+
14709+ class Approx {
14710+ private:
14711+ bool equalityComparisonImpl(double other) const;
14712+ // Sets and validates the new margin (margin >= 0)
14713+ void setMargin(double margin);
14714+ // Sets and validates the new epsilon (0 < epsilon < 1)
14715+ void setEpsilon(double epsilon);
14716+
14717+ public:
14718+ explicit Approx ( double value );
14719+
14720+ static Approx custom();
14721+
14722+ Approx operator-() const;
14723+
14724+ template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
14725+ Approx operator()( T const& value ) const {
14726+ Approx approx( static_cast<double>(value) );
14727+ approx.m_epsilon = m_epsilon;
14728+ approx.m_margin = m_margin;
14729+ approx.m_scale = m_scale;
14730+ return approx;
14731+ }
14732+
14733+ template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
14734+ explicit Approx( T const& value ): Approx(static_cast<double>(value))
14735+ {}
14736+
14737+
14738+ template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
14739+ friend bool operator == ( const T& lhs, Approx const& rhs ) {
14740+ auto lhs_v = static_cast<double>(lhs);
14741+ return rhs.equalityComparisonImpl(lhs_v);
14742+ }
14743+
14744+ template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
14745+ friend bool operator == ( Approx const& lhs, const T& rhs ) {
14746+ return operator==( rhs, lhs );
14747+ }
14748+
14749+ template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
14750+ friend bool operator != ( T const& lhs, Approx const& rhs ) {
14751+ return !operator==( lhs, rhs );
14752+ }
14753+
14754+ template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
14755+ friend bool operator != ( Approx const& lhs, T const& rhs ) {
14756+ return !operator==( rhs, lhs );
14757+ }
14758+
14759+ template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
14760+ friend bool operator <= ( T const& lhs, Approx const& rhs ) {
14761+ return static_cast<double>(lhs) < rhs.m_value || lhs == rhs;
14762+ }
14763+
14764+ template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
14765+ friend bool operator <= ( Approx const& lhs, T const& rhs ) {
14766+ return lhs.m_value < static_cast<double>(rhs) || lhs == rhs;
14767+ }
14768+
14769+ template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
14770+ friend bool operator >= ( T const& lhs, Approx const& rhs ) {
14771+ return static_cast<double>(lhs) > rhs.m_value || lhs == rhs;
14772+ }
14773+
14774+ template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
14775+ friend bool operator >= ( Approx const& lhs, T const& rhs ) {
14776+ return lhs.m_value > static_cast<double>(rhs) || lhs == rhs;
14777+ }
14778+
14779+ template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
14780+ Approx& epsilon( T const& newEpsilon ) {
14781+ const auto epsilonAsDouble = static_cast<double>(newEpsilon);
14782+ setEpsilon(epsilonAsDouble);
14783+ return *this;
14784+ }
14785+
14786+ template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
14787+ Approx& margin( T const& newMargin ) {
14788+ const auto marginAsDouble = static_cast<double>(newMargin);
14789+ setMargin(marginAsDouble);
14790+ return *this;
14791+ }
14792+
14793+ template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
14794+ Approx& scale( T const& newScale ) {
14795+ m_scale = static_cast<double>(newScale);
14796+ return *this;
14797+ }
14798+
14799+ std::string toString() const;
14800+
14801+ private:
14802+ double m_epsilon;
14803+ double m_margin;
14804+ double m_scale;
14805+ double m_value;
14806+ };
14807+
14808+namespace literals {
14809+ Approx operator ""_a(long double val);
14810+ Approx operator ""_a(unsigned long long val);
14811+} // end namespace literals
14812+
14813+template<>
14814+struct StringMaker<Catch::Approx> {
14815+ static std::string convert(Catch::Approx const& value);
14816+};
14817+
14818+} // end namespace Catch
14819+
14820+#endif // CATCH_APPROX_HPP_INCLUDED
14821+
14822+
14823+#ifndef CATCH_ASSERTION_INFO_HPP_INCLUDED
14824+#define CATCH_ASSERTION_INFO_HPP_INCLUDED
14825+
14826+
14827+
14828+#ifndef CATCH_SOURCE_LINE_INFO_HPP_INCLUDED
14829+#define CATCH_SOURCE_LINE_INFO_HPP_INCLUDED
14830+
14831+#include <cstddef>
14832+#include <iosfwd>
14833+
14834+namespace Catch {
14835+
14836+ struct SourceLineInfo {
14837+
14838+ SourceLineInfo() = delete;
14839+ constexpr SourceLineInfo( char const* _file, std::size_t _line ) noexcept:
14840+ file( _file ),
14841+ line( _line )
14842+ {}
14843+
14844+ bool operator == ( SourceLineInfo const& other ) const noexcept;
14845+ bool operator < ( SourceLineInfo const& other ) const noexcept;
14846+
14847+ char const* file;
14848+ std::size_t line;
14849+
14850+ friend std::ostream& operator << (std::ostream& os, SourceLineInfo const& info);
14851+ };
14852+}
14853+
14854+#define CATCH_INTERNAL_LINEINFO \
14855+ ::Catch::SourceLineInfo( __FILE__, static_cast<std::size_t>( __LINE__ ) )
14856+
14857+#endif // CATCH_SOURCE_LINE_INFO_HPP_INCLUDED
14858+
14859+namespace Catch {
14860+
14861+ struct AssertionInfo {
14862+ // AssertionInfo() = delete;
14863+
14864+ StringRef macroName;
14865+ SourceLineInfo lineInfo;
14866+ StringRef capturedExpression;
14867+ ResultDisposition::Flags resultDisposition;
14868+ };
14869+
14870+} // end namespace Catch
14871+
14872+#endif // CATCH_ASSERTION_INFO_HPP_INCLUDED
14873+
14874+
14875+#ifndef CATCH_ASSERTION_RESULT_HPP_INCLUDED
14876+#define CATCH_ASSERTION_RESULT_HPP_INCLUDED
14877+
14878+
14879+
14880+#ifndef CATCH_LAZY_EXPR_HPP_INCLUDED
14881+#define CATCH_LAZY_EXPR_HPP_INCLUDED
14882+
14883+#include <iosfwd>
14884+
14885+namespace Catch {
14886+
14887+ class ITransientExpression;
14888+
14889+ class LazyExpression {
14890+ friend class AssertionHandler;
14891+ friend struct AssertionStats;
14892+ friend class RunContext;
14893+
14894+ ITransientExpression const* m_transientExpression = nullptr;
14895+ bool m_isNegated;
14896+ public:
14897+ LazyExpression( bool isNegated ):
14898+ m_isNegated(isNegated)
14899+ {}
14900+ LazyExpression(LazyExpression const& other) = default;
14901+ LazyExpression& operator = ( LazyExpression const& ) = delete;
14902+
14903+ explicit operator bool() const {
14904+ return m_transientExpression != nullptr;
14905+ }
14906+
14907+ friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&;
14908+ };
14909+
14910+} // namespace Catch
14911+
14912+#endif // CATCH_LAZY_EXPR_HPP_INCLUDED
14913+
14914+#include <string>
14915+
14916+namespace Catch {
14917+
14918+ struct AssertionResultData
14919+ {
14920+ AssertionResultData() = delete;
14921+
14922+ AssertionResultData( ResultWas::OfType _resultType, LazyExpression const& _lazyExpression );
14923+
14924+ std::string message;
14925+ mutable std::string reconstructedExpression;
14926+ LazyExpression lazyExpression;
14927+ ResultWas::OfType resultType;
14928+
14929+ std::string reconstructExpression() const;
14930+ };
14931+
14932+ class AssertionResult {
14933+ public:
14934+ AssertionResult() = delete;
14935+ AssertionResult( AssertionInfo const& info, AssertionResultData&& data );
14936+
14937+ bool isOk() const;
14938+ bool succeeded() const;
14939+ ResultWas::OfType getResultType() const;
14940+ bool hasExpression() const;
14941+ bool hasMessage() const;
14942+ std::string getExpression() const;
14943+ std::string getExpressionInMacro() const;
14944+ bool hasExpandedExpression() const;
14945+ std::string getExpandedExpression() const;
14946+ StringRef getMessage() const;
14947+ SourceLineInfo getSourceInfo() const;
14948+ StringRef getTestMacroName() const;
14949+
14950+ //protected:
14951+ AssertionInfo m_info;
14952+ AssertionResultData m_resultData;
14953+ };
14954+
14955+} // end namespace Catch
14956+
14957+#endif // CATCH_ASSERTION_RESULT_HPP_INCLUDED
14958+
14959+
14960+#ifndef CATCH_CONFIG_HPP_INCLUDED
14961+#define CATCH_CONFIG_HPP_INCLUDED
14962+
14963+
14964+
14965+#ifndef CATCH_TEST_SPEC_HPP_INCLUDED
14966+#define CATCH_TEST_SPEC_HPP_INCLUDED
14967+
14968+#ifdef __clang__
14969+#pragma clang diagnostic push
14970+#pragma clang diagnostic ignored "-Wpadded"
14971+#endif
14972+
14973+
14974+
14975+#ifndef CATCH_WILDCARD_PATTERN_HPP_INCLUDED
14976+#define CATCH_WILDCARD_PATTERN_HPP_INCLUDED
14977+
14978+
14979+
14980+#ifndef CATCH_CASE_SENSITIVE_HPP_INCLUDED
14981+#define CATCH_CASE_SENSITIVE_HPP_INCLUDED
14982+
14983+namespace Catch {
14984+
14985+ enum class CaseSensitive { Yes, No };
14986+
14987+} // namespace Catch
14988+
14989+#endif // CATCH_CASE_SENSITIVE_HPP_INCLUDED
14990+
14991+#include <string>
14992+
14993+namespace Catch
14994+{
14995+ class WildcardPattern {
14996+ enum WildcardPosition {
14997+ NoWildcard = 0,
14998+ WildcardAtStart = 1,
14999+ WildcardAtEnd = 2,
15000+ WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd
15001+ };
15002+
15003+ public:
15004+
15005+ WildcardPattern( std::string const& pattern, CaseSensitive caseSensitivity );
15006+ bool matches( std::string const& str ) const;
15007+
15008+ private:
15009+ std::string normaliseString( std::string const& str ) const;
15010+ CaseSensitive m_caseSensitivity;
15011+ WildcardPosition m_wildcard = NoWildcard;
15012+ std::string m_pattern;
15013+ };
15014+}
15015+
15016+#endif // CATCH_WILDCARD_PATTERN_HPP_INCLUDED
15017+
15018+#include <iosfwd>
15019+#include <string>
15020+#include <vector>
15021+
15022+namespace Catch {
15023+
15024+ class IConfig;
15025+ struct TestCaseInfo;
15026+ class TestCaseHandle;
15027+
15028+ class TestSpec {
15029+
15030+ class Pattern {
15031+ public:
15032+ explicit Pattern( std::string const& name );
15033+ virtual ~Pattern();
15034+ virtual bool matches( TestCaseInfo const& testCase ) const = 0;
15035+ std::string const& name() const;
15036+ private:
15037+ virtual void serializeTo( std::ostream& out ) const = 0;
15038+ // Writes string that would be reparsed into the pattern
15039+ friend std::ostream& operator<<(std::ostream& out,
15040+ Pattern const& pattern) {
15041+ pattern.serializeTo( out );
15042+ return out;
15043+ }
15044+
15045+ std::string const m_name;
15046+ };
15047+
15048+ class NamePattern : public Pattern {
15049+ public:
15050+ explicit NamePattern( std::string const& name, std::string const& filterString );
15051+ bool matches( TestCaseInfo const& testCase ) const override;
15052+ private:
15053+ void serializeTo( std::ostream& out ) const override;
15054+
15055+ WildcardPattern m_wildcardPattern;
15056+ };
15057+
15058+ class TagPattern : public Pattern {
15059+ public:
15060+ explicit TagPattern( std::string const& tag, std::string const& filterString );
15061+ bool matches( TestCaseInfo const& testCase ) const override;
15062+ private:
15063+ void serializeTo( std::ostream& out ) const override;
15064+
15065+ std::string m_tag;
15066+ };
15067+
15068+ struct Filter {
15069+ std::vector<Detail::unique_ptr<Pattern>> m_required;
15070+ std::vector<Detail::unique_ptr<Pattern>> m_forbidden;
15071+
15072+ //! Serializes this filter into a string that would be parsed into
15073+ //! an equivalent filter
15074+ void serializeTo( std::ostream& out ) const;
15075+ friend std::ostream& operator<<(std::ostream& out, Filter const& f) {
15076+ f.serializeTo( out );
15077+ return out;
15078+ }
15079+
15080+ bool matches( TestCaseInfo const& testCase ) const;
15081+ };
15082+
15083+ static std::string extractFilterName( Filter const& filter );
15084+
15085+ public:
15086+ struct FilterMatch {
15087+ std::string name;
15088+ std::vector<TestCaseHandle const*> tests;
15089+ };
15090+ using Matches = std::vector<FilterMatch>;
15091+ using vectorStrings = std::vector<std::string>;
15092+
15093+ bool hasFilters() const;
15094+ bool matches( TestCaseInfo const& testCase ) const;
15095+ Matches matchesByFilter( std::vector<TestCaseHandle> const& testCases, IConfig const& config ) const;
15096+ const vectorStrings & getInvalidSpecs() const;
15097+
15098+ private:
15099+ std::vector<Filter> m_filters;
15100+ std::vector<std::string> m_invalidSpecs;
15101+
15102+ friend class TestSpecParser;
15103+ //! Serializes this test spec into a string that would be parsed into
15104+ //! equivalent test spec
15105+ void serializeTo( std::ostream& out ) const;
15106+ friend std::ostream& operator<<(std::ostream& out,
15107+ TestSpec const& spec) {
15108+ spec.serializeTo( out );
15109+ return out;
15110+ }
15111+ };
15112+}
15113+
15114+#ifdef __clang__
15115+#pragma clang diagnostic pop
15116+#endif
15117+
15118+#endif // CATCH_TEST_SPEC_HPP_INCLUDED
15119+
15120+
15121+#ifndef CATCH_OPTIONAL_HPP_INCLUDED
15122+#define CATCH_OPTIONAL_HPP_INCLUDED
15123+
15124+
15125+#include <cassert>
15126+
15127+namespace Catch {
15128+
15129+ // An optional type
15130+ template<typename T>
15131+ class Optional {
15132+ public:
15133+ Optional(): nullableValue( nullptr ) {}
15134+ ~Optional() { reset(); }
15135+
15136+ Optional( T const& _value ):
15137+ nullableValue( new ( storage ) T( _value ) ) {}
15138+ Optional( T&& _value ):
15139+ nullableValue( new ( storage ) T( CATCH_MOVE( _value ) ) ) {}
15140+
15141+ Optional& operator=( T const& _value ) {
15142+ reset();
15143+ nullableValue = new ( storage ) T( _value );
15144+ return *this;
15145+ }
15146+ Optional& operator=( T&& _value ) {
15147+ reset();
15148+ nullableValue = new ( storage ) T( CATCH_MOVE( _value ) );
15149+ return *this;
15150+ }
15151+
15152+ Optional( Optional const& _other ):
15153+ nullableValue( _other ? new ( storage ) T( *_other ) : nullptr ) {}
15154+ Optional( Optional&& _other ):
15155+ nullableValue( _other ? new ( storage ) T( CATCH_MOVE( *_other ) )
15156+ : nullptr ) {}
15157+
15158+ Optional& operator=( Optional const& _other ) {
15159+ if ( &_other != this ) {
15160+ reset();
15161+ if ( _other ) { nullableValue = new ( storage ) T( *_other ); }
15162+ }
15163+ return *this;
15164+ }
15165+ Optional& operator=( Optional&& _other ) {
15166+ if ( &_other != this ) {
15167+ reset();
15168+ if ( _other ) {
15169+ nullableValue = new ( storage ) T( CATCH_MOVE( *_other ) );
15170+ }
15171+ }
15172+ return *this;
15173+ }
15174+
15175+ void reset() {
15176+ if ( nullableValue ) { nullableValue->~T(); }
15177+ nullableValue = nullptr;
15178+ }
15179+
15180+ T& operator*() {
15181+ assert(nullableValue);
15182+ return *nullableValue;
15183+ }
15184+ T const& operator*() const {
15185+ assert(nullableValue);
15186+ return *nullableValue;
15187+ }
15188+ T* operator->() {
15189+ assert(nullableValue);
15190+ return nullableValue;
15191+ }
15192+ const T* operator->() const {
15193+ assert(nullableValue);
15194+ return nullableValue;
15195+ }
15196+
15197+ T valueOr( T const& defaultValue ) const {
15198+ return nullableValue ? *nullableValue : defaultValue;
15199+ }
15200+
15201+ bool some() const { return nullableValue != nullptr; }
15202+ bool none() const { return nullableValue == nullptr; }
15203+
15204+ bool operator !() const { return nullableValue == nullptr; }
15205+ explicit operator bool() const {
15206+ return some();
15207+ }
15208+
15209+ friend bool operator==(Optional const& a, Optional const& b) {
15210+ if (a.none() && b.none()) {
15211+ return true;
15212+ } else if (a.some() && b.some()) {
15213+ return *a == *b;
15214+ } else {
15215+ return false;
15216+ }
15217+ }
15218+ friend bool operator!=(Optional const& a, Optional const& b) {
15219+ return !( a == b );
15220+ }
15221+
15222+ private:
15223+ T* nullableValue;
15224+ alignas(alignof(T)) char storage[sizeof(T)];
15225+ };
15226+
15227+} // end namespace Catch
15228+
15229+#endif // CATCH_OPTIONAL_HPP_INCLUDED
15230+
15231+
15232+#ifndef CATCH_RANDOM_SEED_GENERATION_HPP_INCLUDED
15233+#define CATCH_RANDOM_SEED_GENERATION_HPP_INCLUDED
15234+
15235+#include <cstdint>
15236+
15237+namespace Catch {
15238+
15239+ enum class GenerateFrom {
15240+ Time,
15241+ RandomDevice,
15242+ //! Currently equivalent to RandomDevice, but can change at any point
15243+ Default
15244+ };
15245+
15246+ std::uint32_t generateRandomSeed(GenerateFrom from);
15247+
15248+} // end namespace Catch
15249+
15250+#endif // CATCH_RANDOM_SEED_GENERATION_HPP_INCLUDED
15251+
15252+
15253+#ifndef CATCH_REPORTER_SPEC_PARSER_HPP_INCLUDED
15254+#define CATCH_REPORTER_SPEC_PARSER_HPP_INCLUDED
15255+
15256+
15257+#include <map>
15258+#include <string>
15259+#include <vector>
15260+
15261+namespace Catch {
15262+
15263+ enum class ColourMode : std::uint8_t;
15264+
15265+ namespace Detail {
15266+ //! Splits the reporter spec into reporter name and kv-pair options
15267+ std::vector<std::string> splitReporterSpec( StringRef reporterSpec );
15268+
15269+ Optional<ColourMode> stringToColourMode( StringRef colourMode );
15270+ }
15271+
15272+ /**
15273+ * Structured reporter spec that a reporter can be created from
15274+ *
15275+ * Parsing has been validated, but semantics have not. This means e.g.
15276+ * that the colour mode is known to Catch2, but it might not be
15277+ * compiled into the binary, and the output filename might not be
15278+ * openable.
15279+ */
15280+ class ReporterSpec {
15281+ std::string m_name;
15282+ Optional<std::string> m_outputFileName;
15283+ Optional<ColourMode> m_colourMode;
15284+ std::map<std::string, std::string> m_customOptions;
15285+
15286+ friend bool operator==( ReporterSpec const& lhs,
15287+ ReporterSpec const& rhs );
15288+ friend bool operator!=( ReporterSpec const& lhs,
15289+ ReporterSpec const& rhs ) {
15290+ return !( lhs == rhs );
15291+ }
15292+
15293+ public:
15294+ ReporterSpec(
15295+ std::string name,
15296+ Optional<std::string> outputFileName,
15297+ Optional<ColourMode> colourMode,
15298+ std::map<std::string, std::string> customOptions );
15299+
15300+ std::string const& name() const { return m_name; }
15301+
15302+ Optional<std::string> const& outputFile() const {
15303+ return m_outputFileName;
15304+ }
15305+
15306+ Optional<ColourMode> const& colourMode() const { return m_colourMode; }
15307+
15308+ std::map<std::string, std::string> const& customOptions() const {
15309+ return m_customOptions;
15310+ }
15311+ };
15312+
15313+ /**
15314+ * Parses provided reporter spec string into
15315+ *
15316+ * Returns empty optional on errors, e.g.
15317+ * * field that is not first and not a key+value pair
15318+ * * duplicated keys in kv pair
15319+ * * unknown catch reporter option
15320+ * * empty key/value in an custom kv pair
15321+ * * ...
15322+ */
15323+ Optional<ReporterSpec> parseReporterSpec( StringRef reporterSpec );
15324+
15325+}
15326+
15327+#endif // CATCH_REPORTER_SPEC_PARSER_HPP_INCLUDED
15328+
15329+#include <chrono>
15330+#include <map>
15331+#include <string>
15332+#include <vector>
15333+
15334+namespace Catch {
15335+
15336+ class IStream;
15337+
15338+ /**
15339+ * `ReporterSpec` but with the defaults filled in.
15340+ *
15341+ * Like `ReporterSpec`, the semantics are unchecked.
15342+ */
15343+ struct ProcessedReporterSpec {
15344+ std::string name;
15345+ std::string outputFilename;
15346+ ColourMode colourMode;
15347+ std::map<std::string, std::string> customOptions;
15348+ friend bool operator==( ProcessedReporterSpec const& lhs,
15349+ ProcessedReporterSpec const& rhs );
15350+ friend bool operator!=( ProcessedReporterSpec const& lhs,
15351+ ProcessedReporterSpec const& rhs ) {
15352+ return !( lhs == rhs );
15353+ }
15354+ };
15355+
15356+ struct ConfigData {
15357+
15358+ bool listTests = false;
15359+ bool listTags = false;
15360+ bool listReporters = false;
15361+ bool listListeners = false;
15362+
15363+ bool showSuccessfulTests = false;
15364+ bool shouldDebugBreak = false;
15365+ bool noThrow = false;
15366+ bool showHelp = false;
15367+ bool showInvisibles = false;
15368+ bool filenamesAsTags = false;
15369+ bool libIdentify = false;
15370+ bool allowZeroTests = false;
15371+
15372+ int abortAfter = -1;
15373+ uint32_t rngSeed = generateRandomSeed(GenerateFrom::Default);
15374+
15375+ unsigned int shardCount = 1;
15376+ unsigned int shardIndex = 0;
15377+
15378+ bool skipBenchmarks = false;
15379+ bool benchmarkNoAnalysis = false;
15380+ unsigned int benchmarkSamples = 100;
15381+ double benchmarkConfidenceInterval = 0.95;
15382+ unsigned int benchmarkResamples = 100'000;
15383+ std::chrono::milliseconds::rep benchmarkWarmupTime = 100;
15384+
15385+ Verbosity verbosity = Verbosity::Normal;
15386+ WarnAbout::What warnings = WarnAbout::Nothing;
15387+ ShowDurations showDurations = ShowDurations::DefaultForReporter;
15388+ double minDuration = -1;
15389+ TestRunOrder runOrder = TestRunOrder::Declared;
15390+ ColourMode defaultColourMode = ColourMode::PlatformDefault;
15391+ WaitForKeypress::When waitForKeypress = WaitForKeypress::Never;
15392+
15393+ std::string defaultOutputFilename;
15394+ std::string name;
15395+ std::string processName;
15396+ std::vector<ReporterSpec> reporterSpecifications;
15397+
15398+ std::vector<std::string> testsOrTags;
15399+ std::vector<std::string> sectionsToRun;
15400+ };
15401+
15402+
15403+ class Config : public IConfig {
15404+ public:
15405+
15406+ Config() = default;
15407+ Config( ConfigData const& data );
15408+ ~Config() override; // = default in the cpp file
15409+
15410+ bool listTests() const;
15411+ bool listTags() const;
15412+ bool listReporters() const;
15413+ bool listListeners() const;
15414+
15415+ std::vector<ReporterSpec> const& getReporterSpecs() const;
15416+ std::vector<ProcessedReporterSpec> const&
15417+ getProcessedReporterSpecs() const;
15418+
15419+ std::vector<std::string> const& getTestsOrTags() const override;
15420+ std::vector<std::string> const& getSectionsToRun() const override;
15421+
15422+ TestSpec const& testSpec() const override;
15423+ bool hasTestFilters() const override;
15424+
15425+ bool showHelp() const;
15426+
15427+ // IConfig interface
15428+ bool allowThrows() const override;
15429+ StringRef name() const override;
15430+ bool includeSuccessfulResults() const override;
15431+ bool warnAboutMissingAssertions() const override;
15432+ bool warnAboutUnmatchedTestSpecs() const override;
15433+ bool zeroTestsCountAsSuccess() const override;
15434+ ShowDurations showDurations() const override;
15435+ double minDuration() const override;
15436+ TestRunOrder runOrder() const override;
15437+ uint32_t rngSeed() const override;
15438+ unsigned int shardCount() const override;
15439+ unsigned int shardIndex() const override;
15440+ ColourMode defaultColourMode() const override;
15441+ bool shouldDebugBreak() const override;
15442+ int abortAfter() const override;
15443+ bool showInvisibles() const override;
15444+ Verbosity verbosity() const override;
15445+ bool skipBenchmarks() const override;
15446+ bool benchmarkNoAnalysis() const override;
15447+ unsigned int benchmarkSamples() const override;
15448+ double benchmarkConfidenceInterval() const override;
15449+ unsigned int benchmarkResamples() const override;
15450+ std::chrono::milliseconds benchmarkWarmupTime() const override;
15451+
15452+ private:
15453+ // Reads Bazel env vars and applies them to the config
15454+ void readBazelEnvVars();
15455+
15456+ ConfigData m_data;
15457+ std::vector<ProcessedReporterSpec> m_processedReporterSpecs;
15458+ TestSpec m_testSpec;
15459+ bool m_hasTestFilters = false;
15460+ };
15461+} // end namespace Catch
15462+
15463+#endif // CATCH_CONFIG_HPP_INCLUDED
15464+
15465+
15466+#ifndef CATCH_GET_RANDOM_SEED_HPP_INCLUDED
15467+#define CATCH_GET_RANDOM_SEED_HPP_INCLUDED
15468+
15469+#include <cstdint>
15470+
15471+namespace Catch {
15472+ //! Returns Catch2's current RNG seed.
15473+ std::uint32_t getSeed();
15474+}
15475+
15476+#endif // CATCH_GET_RANDOM_SEED_HPP_INCLUDED
15477+
15478+
15479+#ifndef CATCH_MESSAGE_HPP_INCLUDED
15480+#define CATCH_MESSAGE_HPP_INCLUDED
15481+
15482+
15483+
15484+
15485+/** \file
15486+ * Wrapper for the CATCH_CONFIG_PREFIX_MESSAGES configuration option
15487+ *
15488+ * CATCH_CONFIG_PREFIX_ALL can be used to avoid clashes with other macros
15489+ * by prepending CATCH_. This may not be desirable if the only clashes are with
15490+ * logger macros such as INFO and WARN. In this cases
15491+ * CATCH_CONFIG_PREFIX_MESSAGES can be used to only prefix a small subset
15492+ * of relevant macros.
15493+ *
15494+ */
15495+
15496+#ifndef CATCH_CONFIG_PREFIX_MESSAGES_HPP_INCLUDED
15497+#define CATCH_CONFIG_PREFIX_MESSAGES_HPP_INCLUDED
15498+
15499+
15500+#if defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_PREFIX_MESSAGES)
15501+ #define CATCH_CONFIG_PREFIX_MESSAGES
15502+#endif
15503+
15504+#endif // CATCH_CONFIG_PREFIX_MESSAGES_HPP_INCLUDED
15505+
15506+
15507+#ifndef CATCH_STREAM_END_STOP_HPP_INCLUDED
15508+#define CATCH_STREAM_END_STOP_HPP_INCLUDED
15509+
15510+
15511+namespace Catch {
15512+
15513+ // Use this in variadic streaming macros to allow
15514+ // << +StreamEndStop
15515+ // as well as
15516+ // << stuff +StreamEndStop
15517+ struct StreamEndStop {
15518+ constexpr StringRef operator+() const { return StringRef(); }
15519+
15520+ template <typename T>
15521+ constexpr friend T const& operator+( T const& value, StreamEndStop ) {
15522+ return value;
15523+ }
15524+ };
15525+
15526+} // namespace Catch
15527+
15528+#endif // CATCH_STREAM_END_STOP_HPP_INCLUDED
15529+
15530+
15531+#ifndef CATCH_MESSAGE_INFO_HPP_INCLUDED
15532+#define CATCH_MESSAGE_INFO_HPP_INCLUDED
15533+
15534+
15535+#include <string>
15536+
15537+namespace Catch {
15538+
15539+ struct MessageInfo {
15540+ MessageInfo( StringRef _macroName,
15541+ SourceLineInfo const& _lineInfo,
15542+ ResultWas::OfType _type );
15543+
15544+ StringRef macroName;
15545+ std::string message;
15546+ SourceLineInfo lineInfo;
15547+ ResultWas::OfType type;
15548+ unsigned int sequence;
15549+
15550+ bool operator == (MessageInfo const& other) const {
15551+ return sequence == other.sequence;
15552+ }
15553+ bool operator < (MessageInfo const& other) const {
15554+ return sequence < other.sequence;
15555+ }
15556+ private:
15557+ static unsigned int globalCount;
15558+ };
15559+
15560+} // end namespace Catch
15561+
15562+#endif // CATCH_MESSAGE_INFO_HPP_INCLUDED
15563+
15564+#include <string>
15565+#include <vector>
15566+
15567+namespace Catch {
15568+
15569+ struct SourceLineInfo;
15570+ class IResultCapture;
15571+
15572+ struct MessageStream {
15573+
15574+ template<typename T>
15575+ MessageStream& operator << ( T const& value ) {
15576+ m_stream << value;
15577+ return *this;
15578+ }
15579+
15580+ ReusableStringStream m_stream;
15581+ };
15582+
15583+ struct MessageBuilder : MessageStream {
15584+ MessageBuilder( StringRef macroName,
15585+ SourceLineInfo const& lineInfo,
15586+ ResultWas::OfType type ):
15587+ m_info(macroName, lineInfo, type) {}
15588+
15589+ template<typename T>
15590+ MessageBuilder&& operator << ( T const& value ) && {
15591+ m_stream << value;
15592+ return CATCH_MOVE(*this);
15593+ }
15594+
15595+ MessageInfo m_info;
15596+ };
15597+
15598+ class ScopedMessage {
15599+ public:
15600+ explicit ScopedMessage( MessageBuilder&& builder );
15601+ ScopedMessage( ScopedMessage& duplicate ) = delete;
15602+ ScopedMessage( ScopedMessage&& old ) noexcept;
15603+ ~ScopedMessage();
15604+
15605+ MessageInfo m_info;
15606+ bool m_moved = false;
15607+ };
15608+
15609+ class Capturer {
15610+ std::vector<MessageInfo> m_messages;
15611+ IResultCapture& m_resultCapture;
15612+ size_t m_captured = 0;
15613+ public:
15614+ Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names );
15615+
15616+ Capturer(Capturer const&) = delete;
15617+ Capturer& operator=(Capturer const&) = delete;
15618+
15619+ ~Capturer();
15620+
15621+ void captureValue( size_t index, std::string const& value );
15622+
15623+ template<typename T>
15624+ void captureValues( size_t index, T const& value ) {
15625+ captureValue( index, Catch::Detail::stringify( value ) );
15626+ }
15627+
15628+ template<typename T, typename... Ts>
15629+ void captureValues( size_t index, T const& value, Ts const&... values ) {
15630+ captureValue( index, Catch::Detail::stringify(value) );
15631+ captureValues( index+1, values... );
15632+ }
15633+ };
15634+
15635+} // end namespace Catch
15636+
15637+///////////////////////////////////////////////////////////////////////////////
15638+#define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \
15639+ do { \
15640+ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::StringRef(), resultDisposition ); \
15641+ catchAssertionHandler.handleMessage( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \
15642+ INTERNAL_CATCH_REACT( catchAssertionHandler ) \
15643+ } while( false )
15644+
15645+///////////////////////////////////////////////////////////////////////////////
15646+#define INTERNAL_CATCH_CAPTURE( varName, macroName, ... ) \
15647+ Catch::Capturer varName( macroName##_catch_sr, \
15648+ CATCH_INTERNAL_LINEINFO, \
15649+ Catch::ResultWas::Info, \
15650+ #__VA_ARGS__##_catch_sr ); \
15651+ varName.captureValues( 0, __VA_ARGS__ )
15652+
15653+///////////////////////////////////////////////////////////////////////////////
15654+#define INTERNAL_CATCH_INFO( macroName, log ) \
15655+ const Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log )
15656+
15657+///////////////////////////////////////////////////////////////////////////////
15658+#define INTERNAL_CATCH_UNSCOPED_INFO( macroName, log ) \
15659+ Catch::getResultCapture().emplaceUnscopedMessage( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log )
15660+
15661+
15662+#if defined(CATCH_CONFIG_PREFIX_MESSAGES) && !defined(CATCH_CONFIG_DISABLE)
15663+
15664+ #define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg )
15665+ #define CATCH_UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "CATCH_UNSCOPED_INFO", msg )
15666+ #define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
15667+ #define CATCH_CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CATCH_CAPTURE", __VA_ARGS__ )
15668+
15669+#elif defined(CATCH_CONFIG_PREFIX_MESSAGES) && defined(CATCH_CONFIG_DISABLE)
15670+
15671+ #define CATCH_INFO( msg ) (void)(0)
15672+ #define CATCH_UNSCOPED_INFO( msg ) (void)(0)
15673+ #define CATCH_WARN( msg ) (void)(0)
15674+ #define CATCH_CAPTURE( ... ) (void)(0)
15675+
15676+#elif !defined(CATCH_CONFIG_PREFIX_MESSAGES) && !defined(CATCH_CONFIG_DISABLE)
15677+
15678+ #define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg )
15679+ #define UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "UNSCOPED_INFO", msg )
15680+ #define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
15681+ #define CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CAPTURE", __VA_ARGS__ )
15682+
15683+#elif !defined(CATCH_CONFIG_PREFIX_MESSAGES) && defined(CATCH_CONFIG_DISABLE)
15684+
15685+ #define INFO( msg ) (void)(0)
15686+ #define UNSCOPED_INFO( msg ) (void)(0)
15687+ #define WARN( msg ) (void)(0)
15688+ #define CAPTURE( ... ) (void)(0)
15689+
15690+#endif // end of user facing macro declarations
15691+
15692+
15693+
15694+
15695+#endif // CATCH_MESSAGE_HPP_INCLUDED
15696+
15697+
15698+#ifndef CATCH_SECTION_INFO_HPP_INCLUDED
15699+#define CATCH_SECTION_INFO_HPP_INCLUDED
15700+
15701+
15702+
15703+#ifndef CATCH_TOTALS_HPP_INCLUDED
15704+#define CATCH_TOTALS_HPP_INCLUDED
15705+
15706+#include <cstdint>
15707+
15708+namespace Catch {
15709+
15710+ struct Counts {
15711+ Counts operator - ( Counts const& other ) const;
15712+ Counts& operator += ( Counts const& other );
15713+
15714+ std::uint64_t total() const;
15715+ bool allPassed() const;
15716+ bool allOk() const;
15717+
15718+ std::uint64_t passed = 0;
15719+ std::uint64_t failed = 0;
15720+ std::uint64_t failedButOk = 0;
15721+ std::uint64_t skipped = 0;
15722+ };
15723+
15724+ struct Totals {
15725+
15726+ Totals operator - ( Totals const& other ) const;
15727+ Totals& operator += ( Totals const& other );
15728+
15729+ Totals delta( Totals const& prevTotals ) const;
15730+
15731+ Counts assertions;
15732+ Counts testCases;
15733+ };
15734+}
15735+
15736+#endif // CATCH_TOTALS_HPP_INCLUDED
15737+
15738+#include <string>
15739+
15740+namespace Catch {
15741+
15742+ struct SectionInfo {
15743+ // The last argument is ignored, so that people can write
15744+ // SECTION("ShortName", "Proper description that is long") and
15745+ // still use the `-c` flag comfortably.
15746+ SectionInfo( SourceLineInfo const& _lineInfo, std::string _name,
15747+ const char* const = nullptr ):
15748+ name(CATCH_MOVE(_name)),
15749+ lineInfo(_lineInfo)
15750+ {}
15751+
15752+ std::string name;
15753+ SourceLineInfo lineInfo;
15754+ };
15755+
15756+ struct SectionEndInfo {
15757+ SectionInfo sectionInfo;
15758+ Counts prevAssertions;
15759+ double durationInSeconds;
15760+ };
15761+
15762+} // end namespace Catch
15763+
15764+#endif // CATCH_SECTION_INFO_HPP_INCLUDED
15765+
15766+
15767+#ifndef CATCH_SESSION_HPP_INCLUDED
15768+#define CATCH_SESSION_HPP_INCLUDED
15769+
15770+
15771+
15772+#ifndef CATCH_COMMANDLINE_HPP_INCLUDED
15773+#define CATCH_COMMANDLINE_HPP_INCLUDED
15774+
15775+
15776+
15777+#ifndef CATCH_CLARA_HPP_INCLUDED
15778+#define CATCH_CLARA_HPP_INCLUDED
15779+
15780+#if defined( __clang__ )
15781+# pragma clang diagnostic push
15782+# pragma clang diagnostic ignored "-Wweak-vtables"
15783+# pragma clang diagnostic ignored "-Wshadow"
15784+# pragma clang diagnostic ignored "-Wdeprecated"
15785+#endif
15786+
15787+#if defined( __GNUC__ )
15788+# pragma GCC diagnostic push
15789+# pragma GCC diagnostic ignored "-Wsign-conversion"
15790+#endif
15791+
15792+#ifndef CLARA_CONFIG_OPTIONAL_TYPE
15793+# ifdef __has_include
15794+# if __has_include( <optional>) && __cplusplus >= 201703L
15795+# include <optional>
15796+# define CLARA_CONFIG_OPTIONAL_TYPE std::optional
15797+# endif
15798+# endif
15799+#endif
15800+
15801+
15802+#include <cassert>
15803+#include <memory>
15804+#include <ostream>
15805+#include <sstream>
15806+#include <string>
15807+#include <type_traits>
15808+#include <vector>
15809+
15810+namespace Catch {
15811+ namespace Clara {
15812+
15813+ class Args;
15814+ class Parser;
15815+
15816+ // enum of result types from a parse
15817+ enum class ParseResultType {
15818+ Matched,
15819+ NoMatch,
15820+ ShortCircuitAll,
15821+ ShortCircuitSame
15822+ };
15823+
15824+ struct accept_many_t {};
15825+ constexpr accept_many_t accept_many {};
15826+
15827+ namespace Detail {
15828+ struct fake_arg {
15829+ template <typename T>
15830+ operator T();
15831+ };
15832+
15833+ template <typename F, typename = void>
15834+ struct is_unary_function : std::false_type {};
15835+
15836+ template <typename F>
15837+ struct is_unary_function<
15838+ F,
15839+ Catch::Detail::void_t<decltype(
15840+ std::declval<F>()( fake_arg() ) )
15841+ >
15842+ > : std::true_type {};
15843+
15844+ // Traits for extracting arg and return type of lambdas (for single
15845+ // argument lambdas)
15846+ template <typename L>
15847+ struct UnaryLambdaTraits
15848+ : UnaryLambdaTraits<decltype( &L::operator() )> {};
15849+
15850+ template <typename ClassT, typename ReturnT, typename... Args>
15851+ struct UnaryLambdaTraits<ReturnT ( ClassT::* )( Args... ) const> {
15852+ static const bool isValid = false;
15853+ };
15854+
15855+ template <typename ClassT, typename ReturnT, typename ArgT>
15856+ struct UnaryLambdaTraits<ReturnT ( ClassT::* )( ArgT ) const> {
15857+ static const bool isValid = true;
15858+ using ArgType = std::remove_const_t<std::remove_reference_t<ArgT>>;
15859+ using ReturnType = ReturnT;
15860+ };
15861+
15862+ class TokenStream;
15863+
15864+ // Wraps a token coming from a token stream. These may not directly
15865+ // correspond to strings as a single string may encode an option +
15866+ // its argument if the : or = form is used
15867+ enum class TokenType { Option, Argument };
15868+ struct Token {
15869+ TokenType type;
15870+ StringRef token;
15871+ };
15872+
15873+ // Abstracts iterators into args as a stream of tokens, with option
15874+ // arguments uniformly handled
15875+ class TokenStream {
15876+ using Iterator = std::vector<StringRef>::const_iterator;
15877+ Iterator it;
15878+ Iterator itEnd;
15879+ std::vector<Token> m_tokenBuffer;
15880+ void loadBuffer();
15881+
15882+ public:
15883+ explicit TokenStream( Args const& args );
15884+ TokenStream( Iterator it, Iterator itEnd );
15885+
15886+ explicit operator bool() const {
15887+ return !m_tokenBuffer.empty() || it != itEnd;
15888+ }
15889+
15890+ size_t count() const {
15891+ return m_tokenBuffer.size() + ( itEnd - it );
15892+ }
15893+
15894+ Token operator*() const {
15895+ assert( !m_tokenBuffer.empty() );
15896+ return m_tokenBuffer.front();
15897+ }
15898+
15899+ Token const* operator->() const {
15900+ assert( !m_tokenBuffer.empty() );
15901+ return &m_tokenBuffer.front();
15902+ }
15903+
15904+ TokenStream& operator++();
15905+ };
15906+
15907+ //! Denotes type of a parsing result
15908+ enum class ResultType {
15909+ Ok, ///< No errors
15910+ LogicError, ///< Error in user-specified arguments for
15911+ ///< construction
15912+ RuntimeError ///< Error in parsing inputs
15913+ };
15914+
15915+ class ResultBase {
15916+ protected:
15917+ ResultBase( ResultType type ): m_type( type ) {}
15918+ virtual ~ResultBase(); // = default;
15919+
15920+
15921+ ResultBase(ResultBase const&) = default;
15922+ ResultBase& operator=(ResultBase const&) = default;
15923+ ResultBase(ResultBase&&) = default;
15924+ ResultBase& operator=(ResultBase&&) = default;
15925+
15926+ virtual void enforceOk() const = 0;
15927+
15928+ ResultType m_type;
15929+ };
15930+
15931+ template <typename T>
15932+ class ResultValueBase : public ResultBase {
15933+ public:
15934+ T const& value() const& {
15935+ enforceOk();
15936+ return m_value;
15937+ }
15938+ T&& value() && {
15939+ enforceOk();
15940+ return CATCH_MOVE( m_value );
15941+ }
15942+
15943+ protected:
15944+ ResultValueBase( ResultType type ): ResultBase( type ) {}
15945+
15946+ ResultValueBase( ResultValueBase const& other ):
15947+ ResultBase( other ) {
15948+ if ( m_type == ResultType::Ok )
15949+ new ( &m_value ) T( other.m_value );
15950+ }
15951+ ResultValueBase( ResultValueBase&& other ):
15952+ ResultBase( other ) {
15953+ if ( m_type == ResultType::Ok )
15954+ new ( &m_value ) T( CATCH_MOVE(other.m_value) );
15955+ }
15956+
15957+
15958+ ResultValueBase( ResultType, T const& value ):
15959+ ResultBase( ResultType::Ok ) {
15960+ new ( &m_value ) T( value );
15961+ }
15962+ ResultValueBase( ResultType, T&& value ):
15963+ ResultBase( ResultType::Ok ) {
15964+ new ( &m_value ) T( CATCH_MOVE(value) );
15965+ }
15966+
15967+ ResultValueBase& operator=( ResultValueBase const& other ) {
15968+ if ( m_type == ResultType::Ok )
15969+ m_value.~T();
15970+ ResultBase::operator=( other );
15971+ if ( m_type == ResultType::Ok )
15972+ new ( &m_value ) T( other.m_value );
15973+ return *this;
15974+ }
15975+ ResultValueBase& operator=( ResultValueBase&& other ) {
15976+ if ( m_type == ResultType::Ok ) m_value.~T();
15977+ ResultBase::operator=( other );
15978+ if ( m_type == ResultType::Ok )
15979+ new ( &m_value ) T( CATCH_MOVE(other.m_value) );
15980+ return *this;
15981+ }
15982+
15983+
15984+ ~ResultValueBase() override {
15985+ if ( m_type == ResultType::Ok )
15986+ m_value.~T();
15987+ }
15988+
15989+ union {
15990+ T m_value;
15991+ };
15992+ };
15993+
15994+ template <> class ResultValueBase<void> : public ResultBase {
15995+ protected:
15996+ using ResultBase::ResultBase;
15997+ };
15998+
15999+ template <typename T = void>
16000+ class BasicResult : public ResultValueBase<T> {
16001+ public:
16002+ template <typename U>
16003+ explicit BasicResult( BasicResult<U> const& other ):
16004+ ResultValueBase<T>( other.type() ),
16005+ m_errorMessage( other.errorMessage() ) {
16006+ assert( type() != ResultType::Ok );
16007+ }
16008+
16009+ template <typename U>
16010+ static auto ok( U&& value ) -> BasicResult {
16011+ return { ResultType::Ok, CATCH_FORWARD(value) };
16012+ }
16013+ static auto ok() -> BasicResult { return { ResultType::Ok }; }
16014+ static auto logicError( std::string&& message )
16015+ -> BasicResult {
16016+ return { ResultType::LogicError, CATCH_MOVE(message) };
16017+ }
16018+ static auto runtimeError( std::string&& message )
16019+ -> BasicResult {
16020+ return { ResultType::RuntimeError, CATCH_MOVE(message) };
16021+ }
16022+
16023+ explicit operator bool() const {
16024+ return m_type == ResultType::Ok;
16025+ }
16026+ auto type() const -> ResultType { return m_type; }
16027+ auto errorMessage() const -> std::string const& {
16028+ return m_errorMessage;
16029+ }
16030+
16031+ protected:
16032+ void enforceOk() const override {
16033+
16034+ // Errors shouldn't reach this point, but if they do
16035+ // the actual error message will be in m_errorMessage
16036+ assert( m_type != ResultType::LogicError );
16037+ assert( m_type != ResultType::RuntimeError );
16038+ if ( m_type != ResultType::Ok )
16039+ std::abort();
16040+ }
16041+
16042+ std::string
16043+ m_errorMessage; // Only populated if resultType is an error
16044+
16045+ BasicResult( ResultType type,
16046+ std::string&& message ):
16047+ ResultValueBase<T>( type ), m_errorMessage( CATCH_MOVE(message) ) {
16048+ assert( m_type != ResultType::Ok );
16049+ }
16050+
16051+ using ResultValueBase<T>::ResultValueBase;
16052+ using ResultBase::m_type;
16053+ };
16054+
16055+ class ParseState {
16056+ public:
16057+ ParseState( ParseResultType type,
16058+ TokenStream remainingTokens );
16059+
16060+ ParseResultType type() const { return m_type; }
16061+ TokenStream const& remainingTokens() const& {
16062+ return m_remainingTokens;
16063+ }
16064+ TokenStream&& remainingTokens() && {
16065+ return CATCH_MOVE( m_remainingTokens );
16066+ }
16067+
16068+ private:
16069+ ParseResultType m_type;
16070+ TokenStream m_remainingTokens;
16071+ };
16072+
16073+ using Result = BasicResult<void>;
16074+ using ParserResult = BasicResult<ParseResultType>;
16075+ using InternalParseResult = BasicResult<ParseState>;
16076+
16077+ struct HelpColumns {
16078+ std::string left;
16079+ StringRef descriptions;
16080+ };
16081+
16082+ template <typename T>
16083+ ParserResult convertInto( std::string const& source, T& target ) {
16084+ std::stringstream ss( source );
16085+ ss >> target;
16086+ if ( ss.fail() ) {
16087+ return ParserResult::runtimeError(
16088+ "Unable to convert '" + source +
16089+ "' to destination type" );
16090+ } else {
16091+ return ParserResult::ok( ParseResultType::Matched );
16092+ }
16093+ }
16094+ ParserResult convertInto( std::string const& source,
16095+ std::string& target );
16096+ ParserResult convertInto( std::string const& source, bool& target );
16097+
16098+#ifdef CLARA_CONFIG_OPTIONAL_TYPE
16099+ template <typename T>
16100+ auto convertInto( std::string const& source,
16101+ CLARA_CONFIG_OPTIONAL_TYPE<T>& target )
16102+ -> ParserResult {
16103+ T temp;
16104+ auto result = convertInto( source, temp );
16105+ if ( result )
16106+ target = CATCH_MOVE( temp );
16107+ return result;
16108+ }
16109+#endif // CLARA_CONFIG_OPTIONAL_TYPE
16110+
16111+ struct BoundRef : Catch::Detail::NonCopyable {
16112+ virtual ~BoundRef() = default;
16113+ virtual bool isContainer() const;
16114+ virtual bool isFlag() const;
16115+ };
16116+ struct BoundValueRefBase : BoundRef {
16117+ virtual auto setValue( std::string const& arg )
16118+ -> ParserResult = 0;
16119+ };
16120+ struct BoundFlagRefBase : BoundRef {
16121+ virtual auto setFlag( bool flag ) -> ParserResult = 0;
16122+ bool isFlag() const override;
16123+ };
16124+
16125+ template <typename T> struct BoundValueRef : BoundValueRefBase {
16126+ T& m_ref;
16127+
16128+ explicit BoundValueRef( T& ref ): m_ref( ref ) {}
16129+
16130+ ParserResult setValue( std::string const& arg ) override {
16131+ return convertInto( arg, m_ref );
16132+ }
16133+ };
16134+
16135+ template <typename T>
16136+ struct BoundValueRef<std::vector<T>> : BoundValueRefBase {
16137+ std::vector<T>& m_ref;
16138+
16139+ explicit BoundValueRef( std::vector<T>& ref ): m_ref( ref ) {}
16140+
16141+ auto isContainer() const -> bool override { return true; }
16142+
16143+ auto setValue( std::string const& arg )
16144+ -> ParserResult override {
16145+ T temp;
16146+ auto result = convertInto( arg, temp );
16147+ if ( result )
16148+ m_ref.push_back( temp );
16149+ return result;
16150+ }
16151+ };
16152+
16153+ struct BoundFlagRef : BoundFlagRefBase {
16154+ bool& m_ref;
16155+
16156+ explicit BoundFlagRef( bool& ref ): m_ref( ref ) {}
16157+
16158+ ParserResult setFlag( bool flag ) override;
16159+ };
16160+
16161+ template <typename ReturnType> struct LambdaInvoker {
16162+ static_assert(
16163+ std::is_same<ReturnType, ParserResult>::value,
16164+ "Lambda must return void or clara::ParserResult" );
16165+
16166+ template <typename L, typename ArgType>
16167+ static auto invoke( L const& lambda, ArgType const& arg )
16168+ -> ParserResult {
16169+ return lambda( arg );
16170+ }
16171+ };
16172+
16173+ template <> struct LambdaInvoker<void> {
16174+ template <typename L, typename ArgType>
16175+ static auto invoke( L const& lambda, ArgType const& arg )
16176+ -> ParserResult {
16177+ lambda( arg );
16178+ return ParserResult::ok( ParseResultType::Matched );
16179+ }
16180+ };
16181+
16182+ template <typename ArgType, typename L>
16183+ auto invokeLambda( L const& lambda, std::string const& arg )
16184+ -> ParserResult {
16185+ ArgType temp{};
16186+ auto result = convertInto( arg, temp );
16187+ return !result ? result
16188+ : LambdaInvoker<typename UnaryLambdaTraits<
16189+ L>::ReturnType>::invoke( lambda, temp );
16190+ }
16191+
16192+ template <typename L> struct BoundLambda : BoundValueRefBase {
16193+ L m_lambda;
16194+
16195+ static_assert(
16196+ UnaryLambdaTraits<L>::isValid,
16197+ "Supplied lambda must take exactly one argument" );
16198+ explicit BoundLambda( L const& lambda ): m_lambda( lambda ) {}
16199+
16200+ auto setValue( std::string const& arg )
16201+ -> ParserResult override {
16202+ return invokeLambda<typename UnaryLambdaTraits<L>::ArgType>(
16203+ m_lambda, arg );
16204+ }
16205+ };
16206+
16207+ template <typename L> struct BoundManyLambda : BoundLambda<L> {
16208+ explicit BoundManyLambda( L const& lambda ): BoundLambda<L>( lambda ) {}
16209+ bool isContainer() const override { return true; }
16210+ };
16211+
16212+ template <typename L> struct BoundFlagLambda : BoundFlagRefBase {
16213+ L m_lambda;
16214+
16215+ static_assert(
16216+ UnaryLambdaTraits<L>::isValid,
16217+ "Supplied lambda must take exactly one argument" );
16218+ static_assert(
16219+ std::is_same<typename UnaryLambdaTraits<L>::ArgType,
16220+ bool>::value,
16221+ "flags must be boolean" );
16222+
16223+ explicit BoundFlagLambda( L const& lambda ):
16224+ m_lambda( lambda ) {}
16225+
16226+ auto setFlag( bool flag ) -> ParserResult override {
16227+ return LambdaInvoker<typename UnaryLambdaTraits<
16228+ L>::ReturnType>::invoke( m_lambda, flag );
16229+ }
16230+ };
16231+
16232+ enum class Optionality { Optional, Required };
16233+
16234+ class ParserBase {
16235+ public:
16236+ virtual ~ParserBase() = default;
16237+ virtual auto validate() const -> Result { return Result::ok(); }
16238+ virtual auto parse( std::string const& exeName,
16239+ TokenStream tokens ) const
16240+ -> InternalParseResult = 0;
16241+ virtual size_t cardinality() const;
16242+
16243+ InternalParseResult parse( Args const& args ) const;
16244+ };
16245+
16246+ template <typename DerivedT>
16247+ class ComposableParserImpl : public ParserBase {
16248+ public:
16249+ template <typename T>
16250+ auto operator|( T const& other ) const -> Parser;
16251+ };
16252+
16253+ // Common code and state for Args and Opts
16254+ template <typename DerivedT>
16255+ class ParserRefImpl : public ComposableParserImpl<DerivedT> {
16256+ protected:
16257+ Optionality m_optionality = Optionality::Optional;
16258+ std::shared_ptr<BoundRef> m_ref;
16259+ StringRef m_hint;
16260+ StringRef m_description;
16261+
16262+ explicit ParserRefImpl( std::shared_ptr<BoundRef> const& ref ):
16263+ m_ref( ref ) {}
16264+
16265+ public:
16266+ template <typename LambdaT>
16267+ ParserRefImpl( accept_many_t,
16268+ LambdaT const& ref,
16269+ StringRef hint ):
16270+ m_ref( std::make_shared<BoundManyLambda<LambdaT>>( ref ) ),
16271+ m_hint( hint ) {}
16272+
16273+ template <typename T,
16274+ typename = typename std::enable_if_t<
16275+ !Detail::is_unary_function<T>::value>>
16276+ ParserRefImpl( T& ref, StringRef hint ):
16277+ m_ref( std::make_shared<BoundValueRef<T>>( ref ) ),
16278+ m_hint( hint ) {}
16279+
16280+ template <typename LambdaT,
16281+ typename = typename std::enable_if_t<
16282+ Detail::is_unary_function<LambdaT>::value>>
16283+ ParserRefImpl( LambdaT const& ref, StringRef hint ):
16284+ m_ref( std::make_shared<BoundLambda<LambdaT>>( ref ) ),
16285+ m_hint( hint ) {}
16286+
16287+ DerivedT& operator()( StringRef description ) & {
16288+ m_description = description;
16289+ return static_cast<DerivedT&>( *this );
16290+ }
16291+ DerivedT&& operator()( StringRef description ) && {
16292+ m_description = description;
16293+ return static_cast<DerivedT&&>( *this );
16294+ }
16295+
16296+ auto optional() -> DerivedT& {
16297+ m_optionality = Optionality::Optional;
16298+ return static_cast<DerivedT&>( *this );
16299+ }
16300+
16301+ auto required() -> DerivedT& {
16302+ m_optionality = Optionality::Required;
16303+ return static_cast<DerivedT&>( *this );
16304+ }
16305+
16306+ auto isOptional() const -> bool {
16307+ return m_optionality == Optionality::Optional;
16308+ }
16309+
16310+ auto cardinality() const -> size_t override {
16311+ if ( m_ref->isContainer() )
16312+ return 0;
16313+ else
16314+ return 1;
16315+ }
16316+
16317+ StringRef hint() const { return m_hint; }
16318+ };
16319+
16320+ } // namespace detail
16321+
16322+
16323+ // A parser for arguments
16324+ class Arg : public Detail::ParserRefImpl<Arg> {
16325+ public:
16326+ using ParserRefImpl::ParserRefImpl;
16327+ using ParserBase::parse;
16328+
16329+ Detail::InternalParseResult
16330+ parse(std::string const&,
16331+ Detail::TokenStream tokens) const override;
16332+ };
16333+
16334+ // A parser for options
16335+ class Opt : public Detail::ParserRefImpl<Opt> {
16336+ protected:
16337+ std::vector<StringRef> m_optNames;
16338+
16339+ public:
16340+ template <typename LambdaT>
16341+ explicit Opt(LambdaT const& ref) :
16342+ ParserRefImpl(
16343+ std::make_shared<Detail::BoundFlagLambda<LambdaT>>(ref)) {}
16344+
16345+ explicit Opt(bool& ref);
16346+
16347+ template <typename LambdaT,
16348+ typename = typename std::enable_if_t<
16349+ Detail::is_unary_function<LambdaT>::value>>
16350+ Opt( LambdaT const& ref, StringRef hint ):
16351+ ParserRefImpl( ref, hint ) {}
16352+
16353+ template <typename LambdaT>
16354+ Opt( accept_many_t, LambdaT const& ref, StringRef hint ):
16355+ ParserRefImpl( accept_many, ref, hint ) {}
16356+
16357+ template <typename T,
16358+ typename = typename std::enable_if_t<
16359+ !Detail::is_unary_function<T>::value>>
16360+ Opt( T& ref, StringRef hint ):
16361+ ParserRefImpl( ref, hint ) {}
16362+
16363+ Opt& operator[]( StringRef optName ) & {
16364+ m_optNames.push_back(optName);
16365+ return *this;
16366+ }
16367+ Opt&& operator[]( StringRef optName ) && {
16368+ m_optNames.push_back( optName );
16369+ return CATCH_MOVE(*this);
16370+ }
16371+
16372+ Detail::HelpColumns getHelpColumns() const;
16373+
16374+ bool isMatch(StringRef optToken) const;
16375+
16376+ using ParserBase::parse;
16377+
16378+ Detail::InternalParseResult
16379+ parse(std::string const&,
16380+ Detail::TokenStream tokens) const override;
16381+
16382+ Detail::Result validate() const override;
16383+ };
16384+
16385+ // Specifies the name of the executable
16386+ class ExeName : public Detail::ComposableParserImpl<ExeName> {
16387+ std::shared_ptr<std::string> m_name;
16388+ std::shared_ptr<Detail::BoundValueRefBase> m_ref;
16389+
16390+ public:
16391+ ExeName();
16392+ explicit ExeName(std::string& ref);
16393+
16394+ template <typename LambdaT>
16395+ explicit ExeName(LambdaT const& lambda) : ExeName() {
16396+ m_ref = std::make_shared<Detail::BoundLambda<LambdaT>>(lambda);
16397+ }
16398+
16399+ // The exe name is not parsed out of the normal tokens, but is
16400+ // handled specially
16401+ Detail::InternalParseResult
16402+ parse(std::string const&,
16403+ Detail::TokenStream tokens) const override;
16404+
16405+ std::string const& name() const { return *m_name; }
16406+ Detail::ParserResult set(std::string const& newName);
16407+ };
16408+
16409+
16410+ // A Combined parser
16411+ class Parser : Detail::ParserBase {
16412+ mutable ExeName m_exeName;
16413+ std::vector<Opt> m_options;
16414+ std::vector<Arg> m_args;
16415+
16416+ public:
16417+
16418+ auto operator|=(ExeName const& exeName) -> Parser& {
16419+ m_exeName = exeName;
16420+ return *this;
16421+ }
16422+
16423+ auto operator|=(Arg const& arg) -> Parser& {
16424+ m_args.push_back(arg);
16425+ return *this;
16426+ }
16427+
16428+ friend Parser& operator|=( Parser& p, Opt const& opt ) {
16429+ p.m_options.push_back( opt );
16430+ return p;
16431+ }
16432+ friend Parser& operator|=( Parser& p, Opt&& opt ) {
16433+ p.m_options.push_back( CATCH_MOVE(opt) );
16434+ return p;
16435+ }
16436+
16437+ Parser& operator|=(Parser const& other);
16438+
16439+ template <typename T>
16440+ friend Parser operator|( Parser const& p, T&& rhs ) {
16441+ Parser temp( p );
16442+ temp |= rhs;
16443+ return temp;
16444+ }
16445+
16446+ template <typename T>
16447+ friend Parser operator|( Parser&& p, T&& rhs ) {
16448+ p |= CATCH_FORWARD(rhs);
16449+ return CATCH_MOVE(p);
16450+ }
16451+
16452+ std::vector<Detail::HelpColumns> getHelpColumns() const;
16453+
16454+ void writeToStream(std::ostream& os) const;
16455+
16456+ friend auto operator<<(std::ostream& os, Parser const& parser)
16457+ -> std::ostream& {
16458+ parser.writeToStream(os);
16459+ return os;
16460+ }
16461+
16462+ Detail::Result validate() const override;
16463+
16464+ using ParserBase::parse;
16465+ Detail::InternalParseResult
16466+ parse(std::string const& exeName,
16467+ Detail::TokenStream tokens) const override;
16468+ };
16469+
16470+ /**
16471+ * Wrapper over argc + argv, assumes that the inputs outlive it
16472+ */
16473+ class Args {
16474+ friend Detail::TokenStream;
16475+ StringRef m_exeName;
16476+ std::vector<StringRef> m_args;
16477+
16478+ public:
16479+ Args(int argc, char const* const* argv);
16480+ // Helper constructor for testing
16481+ Args(std::initializer_list<StringRef> args);
16482+
16483+ StringRef exeName() const { return m_exeName; }
16484+ };
16485+
16486+
16487+ // Convenience wrapper for option parser that specifies the help option
16488+ struct Help : Opt {
16489+ Help(bool& showHelpFlag);
16490+ };
16491+
16492+ // Result type for parser operation
16493+ using Detail::ParserResult;
16494+
16495+ namespace Detail {
16496+ template <typename DerivedT>
16497+ template <typename T>
16498+ Parser
16499+ ComposableParserImpl<DerivedT>::operator|(T const& other) const {
16500+ return Parser() | static_cast<DerivedT const&>(*this) | other;
16501+ }
16502+ }
16503+
16504+ } // namespace Clara
16505+} // namespace Catch
16506+
16507+#if defined( __clang__ )
16508+# pragma clang diagnostic pop
16509+#endif
16510+
16511+#if defined( __GNUC__ )
16512+# pragma GCC diagnostic pop
16513+#endif
16514+
16515+#endif // CATCH_CLARA_HPP_INCLUDED
16516+
16517+namespace Catch {
16518+
16519+ struct ConfigData;
16520+
16521+ Clara::Parser makeCommandLineParser( ConfigData& config );
16522+
16523+} // end namespace Catch
16524+
16525+#endif // CATCH_COMMANDLINE_HPP_INCLUDED
16526+
16527+namespace Catch {
16528+
16529+ class Session : Detail::NonCopyable {
16530+ public:
16531+
16532+ Session();
16533+ ~Session();
16534+
16535+ void showHelp() const;
16536+ void libIdentify();
16537+
16538+ int applyCommandLine( int argc, char const * const * argv );
16539+ #if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE)
16540+ int applyCommandLine( int argc, wchar_t const * const * argv );
16541+ #endif
16542+
16543+ void useConfigData( ConfigData const& configData );
16544+
16545+ template<typename CharT>
16546+ int run(int argc, CharT const * const argv[]) {
16547+ if (m_startupExceptions)
16548+ return 1;
16549+ int returnCode = applyCommandLine(argc, argv);
16550+ if (returnCode == 0)
16551+ returnCode = run();
16552+ return returnCode;
16553+ }
16554+
16555+ int run();
16556+
16557+ Clara::Parser const& cli() const;
16558+ void cli( Clara::Parser const& newParser );
16559+ ConfigData& configData();
16560+ Config& config();
16561+ private:
16562+ int runInternal();
16563+
16564+ Clara::Parser m_cli;
16565+ ConfigData m_configData;
16566+ Detail::unique_ptr<Config> m_config;
16567+ bool m_startupExceptions = false;
16568+ };
16569+
16570+} // end namespace Catch
16571+
16572+#endif // CATCH_SESSION_HPP_INCLUDED
16573+
16574+
16575+#ifndef CATCH_TAG_ALIAS_HPP_INCLUDED
16576+#define CATCH_TAG_ALIAS_HPP_INCLUDED
16577+
16578+
16579+#include <string>
16580+
16581+namespace Catch {
16582+
16583+ struct TagAlias {
16584+ TagAlias(std::string const& _tag, SourceLineInfo _lineInfo):
16585+ tag(_tag),
16586+ lineInfo(_lineInfo)
16587+ {}
16588+
16589+ std::string tag;
16590+ SourceLineInfo lineInfo;
16591+ };
16592+
16593+} // end namespace Catch
16594+
16595+#endif // CATCH_TAG_ALIAS_HPP_INCLUDED
16596+
16597+
16598+#ifndef CATCH_TAG_ALIAS_AUTOREGISTRAR_HPP_INCLUDED
16599+#define CATCH_TAG_ALIAS_AUTOREGISTRAR_HPP_INCLUDED
16600+
16601+
16602+namespace Catch {
16603+
16604+ struct RegistrarForTagAliases {
16605+ RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo );
16606+ };
16607+
16608+} // end namespace Catch
16609+
16610+#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \
16611+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
16612+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
16613+ namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \
16614+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
16615+
16616+#endif // CATCH_TAG_ALIAS_AUTOREGISTRAR_HPP_INCLUDED
16617+
16618+
16619+#ifndef CATCH_TEMPLATE_TEST_MACROS_HPP_INCLUDED
16620+#define CATCH_TEMPLATE_TEST_MACROS_HPP_INCLUDED
16621+
16622+// We need this suppression to leak, because it took until GCC 10
16623+// for the front end to handle local suppression via _Pragma properly
16624+// inside templates (so `TEMPLATE_TEST_CASE` and co).
16625+// **THIS IS DIFFERENT FOR STANDARD TESTS, WHERE GCC 9 IS SUFFICIENT**
16626+#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && __GNUC__ < 10
16627+#pragma GCC diagnostic ignored "-Wparentheses"
16628+#endif
16629+
16630+
16631+
16632+
16633+#ifndef CATCH_TEST_MACROS_HPP_INCLUDED
16634+#define CATCH_TEST_MACROS_HPP_INCLUDED
16635+
16636+
16637+
16638+#ifndef CATCH_TEST_MACRO_IMPL_HPP_INCLUDED
16639+#define CATCH_TEST_MACRO_IMPL_HPP_INCLUDED
16640+
16641+
16642+
16643+#ifndef CATCH_ASSERTION_HANDLER_HPP_INCLUDED
16644+#define CATCH_ASSERTION_HANDLER_HPP_INCLUDED
16645+
16646+
16647+
16648+#ifndef CATCH_DECOMPOSER_HPP_INCLUDED
16649+#define CATCH_DECOMPOSER_HPP_INCLUDED
16650+
16651+
16652+
16653+#ifndef CATCH_COMPARE_TRAITS_HPP_INCLUDED
16654+#define CATCH_COMPARE_TRAITS_HPP_INCLUDED
16655+
16656+
16657+#include <type_traits>
16658+
16659+namespace Catch {
16660+ namespace Detail {
16661+
16662+#if defined( __GNUC__ ) && !defined( __clang__ )
16663+# pragma GCC diagnostic push
16664+ // GCC likes to complain about comparing bool with 0, in the decltype()
16665+ // that defines the comparable traits below.
16666+# pragma GCC diagnostic ignored "-Wbool-compare"
16667+ // "ordered comparison of pointer with integer zero" same as above,
16668+ // but it does not have a separate warning flag to suppress
16669+# pragma GCC diagnostic ignored "-Wextra"
16670+ // Did you know that comparing floats with `0` directly
16671+ // is super-duper dangerous in unevaluated context?
16672+# pragma GCC diagnostic ignored "-Wfloat-equal"
16673+#endif
16674+
16675+#if defined( __clang__ )
16676+# pragma clang diagnostic push
16677+ // Did you know that comparing floats with `0` directly
16678+ // is super-duper dangerous in unevaluated context?
16679+# pragma clang diagnostic ignored "-Wfloat-equal"
16680+#endif
16681+
16682+#define CATCH_DEFINE_COMPARABLE_TRAIT( id, op ) \
16683+ template <typename, typename, typename = void> \
16684+ struct is_##id##_comparable : std::false_type {}; \
16685+ template <typename T, typename U> \
16686+ struct is_##id##_comparable< \
16687+ T, \
16688+ U, \
16689+ void_t<decltype( std::declval<T>() op std::declval<U>() )>> \
16690+ : std::true_type {}; \
16691+ template <typename, typename = void> \
16692+ struct is_##id##_0_comparable : std::false_type {}; \
16693+ template <typename T> \
16694+ struct is_##id##_0_comparable<T, \
16695+ void_t<decltype( std::declval<T>() op 0 )>> \
16696+ : std::true_type {};
16697+
16698+ // We need all 6 pre-spaceship comparison ops: <, <=, >, >=, ==, !=
16699+ CATCH_DEFINE_COMPARABLE_TRAIT( lt, < )
16700+ CATCH_DEFINE_COMPARABLE_TRAIT( le, <= )
16701+ CATCH_DEFINE_COMPARABLE_TRAIT( gt, > )
16702+ CATCH_DEFINE_COMPARABLE_TRAIT( ge, >= )
16703+ CATCH_DEFINE_COMPARABLE_TRAIT( eq, == )
16704+ CATCH_DEFINE_COMPARABLE_TRAIT( ne, != )
16705+
16706+#undef CATCH_DEFINE_COMPARABLE_TRAIT
16707+
16708+#if defined( __GNUC__ ) && !defined( __clang__ )
16709+# pragma GCC diagnostic pop
16710+#endif
16711+#if defined( __clang__ )
16712+# pragma clang diagnostic pop
16713+#endif
16714+
16715+
16716+ } // namespace Detail
16717+} // namespace Catch
16718+
16719+#endif // CATCH_COMPARE_TRAITS_HPP_INCLUDED
16720+
16721+
16722+#ifndef CATCH_LOGICAL_TRAITS_HPP_INCLUDED
16723+#define CATCH_LOGICAL_TRAITS_HPP_INCLUDED
16724+
16725+#include <type_traits>
16726+
16727+namespace Catch {
16728+namespace Detail {
16729+
16730+#if defined( __cpp_lib_logical_traits ) && __cpp_lib_logical_traits >= 201510
16731+
16732+ using std::conjunction;
16733+ using std::disjunction;
16734+ using std::negation;
16735+
16736+#else
16737+
16738+ template <class...> struct conjunction : std::true_type {};
16739+ template <class B1> struct conjunction<B1> : B1 {};
16740+ template <class B1, class... Bn>
16741+ struct conjunction<B1, Bn...>
16742+ : std::conditional_t<bool( B1::value ), conjunction<Bn...>, B1> {};
16743+
16744+ template <class...> struct disjunction : std::false_type {};
16745+ template <class B1> struct disjunction<B1> : B1 {};
16746+ template <class B1, class... Bn>
16747+ struct disjunction<B1, Bn...>
16748+ : std::conditional_t<bool( B1::value ), B1, disjunction<Bn...>> {};
16749+
16750+ template <class B>
16751+ struct negation : std::integral_constant<bool, !bool(B::value)> {};
16752+
16753+#endif
16754+
16755+} // namespace Detail
16756+} // namespace Catch
16757+
16758+#endif // CATCH_LOGICAL_TRAITS_HPP_INCLUDED
16759+
16760+#include <type_traits>
16761+#include <iosfwd>
16762+
16763+/** \file
16764+ * Why does decomposing look the way it does:
16765+ *
16766+ * Conceptually, decomposing is simple. We change `REQUIRE( a == b )` into
16767+ * `Decomposer{} <= a == b`, so that `Decomposer{} <= a` is evaluated first,
16768+ * and our custom operator is used for `a == b`, because `a` is transformed
16769+ * into `ExprLhs<T&>` and then into `BinaryExpr<T&, U&>`.
16770+ *
16771+ * In practice, decomposing ends up a mess, because we have to support
16772+ * various fun things.
16773+ *
16774+ * 1) Types that are only comparable with literal 0, and they do this by
16775+ * comparing against a magic type with pointer constructor and deleted
16776+ * other constructors. Example: `REQUIRE((a <=> b) == 0)` in libstdc++
16777+ *
16778+ * 2) Types that are only comparable with literal 0, and they do this by
16779+ * comparing against a magic type with consteval integer constructor.
16780+ * Example: `REQUIRE((a <=> b) == 0)` in current MSVC STL.
16781+ *
16782+ * 3) Types that have no linkage, and so we cannot form a reference to
16783+ * them. Example: some implementations of traits.
16784+ *
16785+ * 4) Starting with C++20, when the compiler sees `a == b`, it also uses
16786+ * `b == a` when constructing the overload set. For us this means that
16787+ * when the compiler handles `ExprLhs<T> == b`, it also tries to resolve
16788+ * the overload set for `b == ExprLhs<T>`.
16789+ *
16790+ * To accomodate these use cases, decomposer ended up rather complex.
16791+ *
16792+ * 1) These types are handled by adding SFINAE overloads to our comparison
16793+ * operators, checking whether `T == U` are comparable with the given
16794+ * operator, and if not, whether T (or U) are comparable with literal 0.
16795+ * If yes, the overload compares T (or U) with 0 literal inline in the
16796+ * definition.
16797+ *
16798+ * Note that for extra correctness, we check that the other type is
16799+ * either an `int` (literal 0 is captured as `int` by templates), or
16800+ * a `long` (some platforms use 0L for `NULL` and we want to support
16801+ * that for pointer comparisons).
16802+ *
16803+ * 2) For these types, `is_foo_comparable<T, int>` is true, but letting
16804+ * them fall into the overload that actually does `T == int` causes
16805+ * compilation error. Handling them requires that the decomposition
16806+ * is `constexpr`, so that P2564R3 applies and the `consteval` from
16807+ * their accompanying magic type is propagated through the `constexpr`
16808+ * call stack.
16809+ *
16810+ * However this is not enough to handle these types automatically,
16811+ * because our default is to capture types by reference, to avoid
16812+ * runtime copies. While these references cannot become dangling,
16813+ * they outlive the constexpr context and thus the default capture
16814+ * path cannot be actually constexpr.
16815+ *
16816+ * The solution is to capture these types by value, by explicitly
16817+ * specializing `Catch::capture_by_value` for them. Catch2 provides
16818+ * specialization for `std::foo_ordering`s, but users can specialize
16819+ * the trait for their own types as well.
16820+ *
16821+ * 3) If a type has no linkage, we also cannot capture it by reference.
16822+ * The solution is once again to capture them by value. We handle
16823+ * the common cases by using `std::is_arithmetic` as the default
16824+ * for `Catch::capture_by_value`, but that is only a some-effort
16825+ * heuristic. But as with 2), users can specialize `capture_by_value`
16826+ * for their own types as needed.
16827+ *
16828+ * 4) To support C++20 and make the SFINAE on our decomposing operators
16829+ * work, the SFINAE has to happen in return type, rather than in
16830+ * a template type. This is due to our use of logical type traits
16831+ * (`conjunction`/`disjunction`/`negation`), that we use to workaround
16832+ * an issue in older (9-) versions of GCC. I still blame C++20 for
16833+ * this, because without the comparison order switching, the logical
16834+ * traits could still be used in template type.
16835+ *
16836+ * There are also other side concerns, e.g. supporting both `REQUIRE(a)`
16837+ * and `REQUIRE(a == b)`, or making `REQUIRE_THAT(a, IsEqual(b))` slot
16838+ * nicely into the same expression handling logic, but these are rather
16839+ * straightforward and add only a bit of complexity (e.g. common base
16840+ * class for decomposed expressions).
16841+ */
16842+
16843+#ifdef _MSC_VER
16844+#pragma warning(push)
16845+#pragma warning(disable:4389) // '==' : signed/unsigned mismatch
16846+#pragma warning(disable:4018) // more "signed/unsigned mismatch"
16847+#pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform)
16848+#pragma warning(disable:4180) // qualifier applied to function type has no meaning
16849+#pragma warning(disable:4800) // Forcing result to true or false
16850+#endif
16851+
16852+#ifdef __clang__
16853+# pragma clang diagnostic push
16854+# pragma clang diagnostic ignored "-Wsign-compare"
16855+#elif defined __GNUC__
16856+# pragma GCC diagnostic push
16857+# pragma GCC diagnostic ignored "-Wsign-compare"
16858+#endif
16859+
16860+#if defined(CATCH_CPP20_OR_GREATER) && __has_include(<compare>)
16861+# include <compare>
16862+# if defined( __cpp_lib_three_way_comparison ) && \
16863+ __cpp_lib_three_way_comparison >= 201907L
16864+# define CATCH_CONFIG_CPP20_COMPARE_OVERLOADS
16865+# endif
16866+#endif
16867+
16868+namespace Catch {
16869+
16870+ namespace Detail {
16871+ // This was added in C++20, but we require only C++14 for now.
16872+ template <typename T>
16873+ using RemoveCVRef_t = std::remove_cv_t<std::remove_reference_t<T>>;
16874+ }
16875+
16876+ // Note: There is nothing that stops us from extending this,
16877+ // e.g. to `std::is_scalar`, but the more encompassing
16878+ // traits are usually also more expensive. For now we
16879+ // keep this as it used to be and it can be changed later.
16880+ template <typename T>
16881+ struct capture_by_value
16882+ : std::integral_constant<bool, std::is_arithmetic<T>{}> {};
16883+
16884+#if defined( CATCH_CONFIG_CPP20_COMPARE_OVERLOADS )
16885+ template <>
16886+ struct capture_by_value<std::strong_ordering> : std::true_type {};
16887+ template <>
16888+ struct capture_by_value<std::weak_ordering> : std::true_type {};
16889+ template <>
16890+ struct capture_by_value<std::partial_ordering> : std::true_type {};
16891+#endif
16892+
16893+ template <typename T>
16894+ struct always_false : std::false_type {};
16895+
16896+ class ITransientExpression {
16897+ bool m_isBinaryExpression;
16898+ bool m_result;
16899+
16900+ public:
16901+ constexpr auto isBinaryExpression() const -> bool { return m_isBinaryExpression; }
16902+ constexpr auto getResult() const -> bool { return m_result; }
16903+ //! This function **has** to be overriden by the derived class.
16904+ virtual void streamReconstructedExpression( std::ostream& os ) const;
16905+
16906+ constexpr ITransientExpression( bool isBinaryExpression, bool result )
16907+ : m_isBinaryExpression( isBinaryExpression ),
16908+ m_result( result )
16909+ {}
16910+
16911+ ITransientExpression() = default;
16912+ ITransientExpression(ITransientExpression const&) = default;
16913+ ITransientExpression& operator=(ITransientExpression const&) = default;
16914+
16915+ friend std::ostream& operator<<(std::ostream& out, ITransientExpression const& expr) {
16916+ expr.streamReconstructedExpression(out);
16917+ return out;
16918+ }
16919+
16920+ protected:
16921+ ~ITransientExpression() = default;
16922+ };
16923+
16924+ void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs );
16925+
16926+ template<typename LhsT, typename RhsT>
16927+ class BinaryExpr : public ITransientExpression {
16928+ LhsT m_lhs;
16929+ StringRef m_op;
16930+ RhsT m_rhs;
16931+
16932+ void streamReconstructedExpression( std::ostream &os ) const override {
16933+ formatReconstructedExpression
16934+ ( os, Catch::Detail::stringify( m_lhs ), m_op, Catch::Detail::stringify( m_rhs ) );
16935+ }
16936+
16937+ public:
16938+ constexpr BinaryExpr( bool comparisonResult, LhsT lhs, StringRef op, RhsT rhs )
16939+ : ITransientExpression{ true, comparisonResult },
16940+ m_lhs( lhs ),
16941+ m_op( op ),
16942+ m_rhs( rhs )
16943+ {}
16944+
16945+ template<typename T>
16946+ auto operator && ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
16947+ static_assert(always_false<T>::value,
16948+ "chained comparisons are not supported inside assertions, "
16949+ "wrap the expression inside parentheses, or decompose it");
16950+ }
16951+
16952+ template<typename T>
16953+ auto operator || ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
16954+ static_assert(always_false<T>::value,
16955+ "chained comparisons are not supported inside assertions, "
16956+ "wrap the expression inside parentheses, or decompose it");
16957+ }
16958+
16959+ template<typename T>
16960+ auto operator == ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
16961+ static_assert(always_false<T>::value,
16962+ "chained comparisons are not supported inside assertions, "
16963+ "wrap the expression inside parentheses, or decompose it");
16964+ }
16965+
16966+ template<typename T>
16967+ auto operator != ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
16968+ static_assert(always_false<T>::value,
16969+ "chained comparisons are not supported inside assertions, "
16970+ "wrap the expression inside parentheses, or decompose it");
16971+ }
16972+
16973+ template<typename T>
16974+ auto operator > ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
16975+ static_assert(always_false<T>::value,
16976+ "chained comparisons are not supported inside assertions, "
16977+ "wrap the expression inside parentheses, or decompose it");
16978+ }
16979+
16980+ template<typename T>
16981+ auto operator < ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
16982+ static_assert(always_false<T>::value,
16983+ "chained comparisons are not supported inside assertions, "
16984+ "wrap the expression inside parentheses, or decompose it");
16985+ }
16986+
16987+ template<typename T>
16988+ auto operator >= ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
16989+ static_assert(always_false<T>::value,
16990+ "chained comparisons are not supported inside assertions, "
16991+ "wrap the expression inside parentheses, or decompose it");
16992+ }
16993+
16994+ template<typename T>
16995+ auto operator <= ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
16996+ static_assert(always_false<T>::value,
16997+ "chained comparisons are not supported inside assertions, "
16998+ "wrap the expression inside parentheses, or decompose it");
16999+ }
17000+ };
17001+
17002+ template<typename LhsT>
17003+ class UnaryExpr : public ITransientExpression {
17004+ LhsT m_lhs;
17005+
17006+ void streamReconstructedExpression( std::ostream &os ) const override {
17007+ os << Catch::Detail::stringify( m_lhs );
17008+ }
17009+
17010+ public:
17011+ explicit constexpr UnaryExpr( LhsT lhs )
17012+ : ITransientExpression{ false, static_cast<bool>(lhs) },
17013+ m_lhs( lhs )
17014+ {}
17015+ };
17016+
17017+
17018+ template<typename LhsT>
17019+ class ExprLhs {
17020+ LhsT m_lhs;
17021+ public:
17022+ explicit constexpr ExprLhs( LhsT lhs ) : m_lhs( lhs ) {}
17023+
17024+#define CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR( id, op ) \
17025+ template <typename RhsT> \
17026+ constexpr friend auto operator op( ExprLhs&& lhs, RhsT&& rhs ) \
17027+ -> std::enable_if_t< \
17028+ Detail::conjunction<Detail::is_##id##_comparable<LhsT, RhsT>, \
17029+ Detail::negation<capture_by_value< \
17030+ Detail::RemoveCVRef_t<RhsT>>>>::value, \
17031+ BinaryExpr<LhsT, RhsT const&>> { \
17032+ return { \
17033+ static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
17034+ } \
17035+ template <typename RhsT> \
17036+ constexpr friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
17037+ -> std::enable_if_t< \
17038+ Detail::conjunction<Detail::is_##id##_comparable<LhsT, RhsT>, \
17039+ capture_by_value<RhsT>>::value, \
17040+ BinaryExpr<LhsT, RhsT>> { \
17041+ return { \
17042+ static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
17043+ } \
17044+ template <typename RhsT> \
17045+ constexpr friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
17046+ -> std::enable_if_t< \
17047+ Detail::conjunction< \
17048+ Detail::negation<Detail::is_##id##_comparable<LhsT, RhsT>>, \
17049+ Detail::is_eq_0_comparable<LhsT>, \
17050+ /* We allow long because we want `ptr op NULL` to be accepted */ \
17051+ Detail::disjunction<std::is_same<RhsT, int>, \
17052+ std::is_same<RhsT, long>>>::value, \
17053+ BinaryExpr<LhsT, RhsT>> { \
17054+ if ( rhs != 0 ) { throw_test_failure_exception(); } \
17055+ return { \
17056+ static_cast<bool>( lhs.m_lhs op 0 ), lhs.m_lhs, #op##_sr, rhs }; \
17057+ } \
17058+ template <typename RhsT> \
17059+ constexpr friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
17060+ -> std::enable_if_t< \
17061+ Detail::conjunction< \
17062+ Detail::negation<Detail::is_##id##_comparable<LhsT, RhsT>>, \
17063+ Detail::is_eq_0_comparable<RhsT>, \
17064+ /* We allow long because we want `ptr op NULL` to be accepted */ \
17065+ Detail::disjunction<std::is_same<LhsT, int>, \
17066+ std::is_same<LhsT, long>>>::value, \
17067+ BinaryExpr<LhsT, RhsT>> { \
17068+ if ( lhs.m_lhs != 0 ) { throw_test_failure_exception(); } \
17069+ return { static_cast<bool>( 0 op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
17070+ }
17071+
17072+ CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR( eq, == )
17073+ CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR( ne, != )
17074+
17075+ #undef CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR
17076+
17077+
17078+#define CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR( id, op ) \
17079+ template <typename RhsT> \
17080+ constexpr friend auto operator op( ExprLhs&& lhs, RhsT&& rhs ) \
17081+ -> std::enable_if_t< \
17082+ Detail::conjunction<Detail::is_##id##_comparable<LhsT, RhsT>, \
17083+ Detail::negation<capture_by_value< \
17084+ Detail::RemoveCVRef_t<RhsT>>>>::value, \
17085+ BinaryExpr<LhsT, RhsT const&>> { \
17086+ return { \
17087+ static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
17088+ } \
17089+ template <typename RhsT> \
17090+ constexpr friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
17091+ -> std::enable_if_t< \
17092+ Detail::conjunction<Detail::is_##id##_comparable<LhsT, RhsT>, \
17093+ capture_by_value<RhsT>>::value, \
17094+ BinaryExpr<LhsT, RhsT>> { \
17095+ return { \
17096+ static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
17097+ } \
17098+ template <typename RhsT> \
17099+ constexpr friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
17100+ -> std::enable_if_t< \
17101+ Detail::conjunction< \
17102+ Detail::negation<Detail::is_##id##_comparable<LhsT, RhsT>>, \
17103+ Detail::is_##id##_0_comparable<LhsT>, \
17104+ std::is_same<RhsT, int>>::value, \
17105+ BinaryExpr<LhsT, RhsT>> { \
17106+ if ( rhs != 0 ) { throw_test_failure_exception(); } \
17107+ return { \
17108+ static_cast<bool>( lhs.m_lhs op 0 ), lhs.m_lhs, #op##_sr, rhs }; \
17109+ } \
17110+ template <typename RhsT> \
17111+ constexpr friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
17112+ -> std::enable_if_t< \
17113+ Detail::conjunction< \
17114+ Detail::negation<Detail::is_##id##_comparable<LhsT, RhsT>>, \
17115+ Detail::is_##id##_0_comparable<RhsT>, \
17116+ std::is_same<LhsT, int>>::value, \
17117+ BinaryExpr<LhsT, RhsT>> { \
17118+ if ( lhs.m_lhs != 0 ) { throw_test_failure_exception(); } \
17119+ return { static_cast<bool>( 0 op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
17120+ }
17121+
17122+ CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR( lt, < )
17123+ CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR( le, <= )
17124+ CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR( gt, > )
17125+ CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR( ge, >= )
17126+
17127+ #undef CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR
17128+
17129+
17130+#define CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR( op ) \
17131+ template <typename RhsT> \
17132+ constexpr friend auto operator op( ExprLhs&& lhs, RhsT&& rhs ) \
17133+ -> std::enable_if_t< \
17134+ !capture_by_value<Detail::RemoveCVRef_t<RhsT>>::value, \
17135+ BinaryExpr<LhsT, RhsT const&>> { \
17136+ return { \
17137+ static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
17138+ } \
17139+ template <typename RhsT> \
17140+ constexpr friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
17141+ -> std::enable_if_t<capture_by_value<RhsT>::value, \
17142+ BinaryExpr<LhsT, RhsT>> { \
17143+ return { \
17144+ static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
17145+ }
17146+
17147+ CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR(|)
17148+ CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR(&)
17149+ CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR(^)
17150+
17151+ #undef CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR
17152+
17153+ template<typename RhsT>
17154+ friend auto operator && ( ExprLhs &&, RhsT && ) -> BinaryExpr<LhsT, RhsT const&> {
17155+ static_assert(always_false<RhsT>::value,
17156+ "operator&& is not supported inside assertions, "
17157+ "wrap the expression inside parentheses, or decompose it");
17158+ }
17159+
17160+ template<typename RhsT>
17161+ friend auto operator || ( ExprLhs &&, RhsT && ) -> BinaryExpr<LhsT, RhsT const&> {
17162+ static_assert(always_false<RhsT>::value,
17163+ "operator|| is not supported inside assertions, "
17164+ "wrap the expression inside parentheses, or decompose it");
17165+ }
17166+
17167+ constexpr auto makeUnaryExpr() const -> UnaryExpr<LhsT> {
17168+ return UnaryExpr<LhsT>{ m_lhs };
17169+ }
17170+ };
17171+
17172+ struct Decomposer {
17173+ template <typename T,
17174+ std::enable_if_t<!capture_by_value<Detail::RemoveCVRef_t<T>>::value,
17175+ int> = 0>
17176+ constexpr friend auto operator <= ( Decomposer &&, T && lhs ) -> ExprLhs<T const&> {
17177+ return ExprLhs<const T&>{ lhs };
17178+ }
17179+
17180+ template <typename T,
17181+ std::enable_if_t<capture_by_value<T>::value, int> = 0>
17182+ constexpr friend auto operator <= ( Decomposer &&, T value ) -> ExprLhs<T> {
17183+ return ExprLhs<T>{ value };
17184+ }
17185+ };
17186+
17187+} // end namespace Catch
17188+
17189+#ifdef _MSC_VER
17190+#pragma warning(pop)
17191+#endif
17192+#ifdef __clang__
17193+# pragma clang diagnostic pop
17194+#elif defined __GNUC__
17195+# pragma GCC diagnostic pop
17196+#endif
17197+
17198+#endif // CATCH_DECOMPOSER_HPP_INCLUDED
17199+
17200+#include <string>
17201+
17202+namespace Catch {
17203+
17204+ struct AssertionReaction {
17205+ bool shouldDebugBreak = false;
17206+ bool shouldThrow = false;
17207+ bool shouldSkip = false;
17208+ };
17209+
17210+ class AssertionHandler {
17211+ AssertionInfo m_assertionInfo;
17212+ AssertionReaction m_reaction;
17213+ bool m_completed = false;
17214+ IResultCapture& m_resultCapture;
17215+
17216+ public:
17217+ AssertionHandler
17218+ ( StringRef macroName,
17219+ SourceLineInfo const& lineInfo,
17220+ StringRef capturedExpression,
17221+ ResultDisposition::Flags resultDisposition );
17222+ ~AssertionHandler() {
17223+ if ( !m_completed ) {
17224+ m_resultCapture.handleIncomplete( m_assertionInfo );
17225+ }
17226+ }
17227+
17228+
17229+ template<typename T>
17230+ void handleExpr( ExprLhs<T> const& expr ) {
17231+ handleExpr( expr.makeUnaryExpr() );
17232+ }
17233+ void handleExpr( ITransientExpression const& expr );
17234+
17235+ void handleMessage(ResultWas::OfType resultType, StringRef message);
17236+
17237+ void handleExceptionThrownAsExpected();
17238+ void handleUnexpectedExceptionNotThrown();
17239+ void handleExceptionNotThrownAsExpected();
17240+ void handleThrowingCallSkipped();
17241+ void handleUnexpectedInflightException();
17242+
17243+ void complete();
17244+
17245+ // query
17246+ auto allowThrows() const -> bool;
17247+ };
17248+
17249+ void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str );
17250+
17251+} // namespace Catch
17252+
17253+#endif // CATCH_ASSERTION_HANDLER_HPP_INCLUDED
17254+
17255+
17256+#ifndef CATCH_PREPROCESSOR_INTERNAL_STRINGIFY_HPP_INCLUDED
17257+#define CATCH_PREPROCESSOR_INTERNAL_STRINGIFY_HPP_INCLUDED
17258+
17259+
17260+#if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION)
17261+ #define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__##_catch_sr
17262+#else
17263+ #define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION"_catch_sr
17264+#endif
17265+
17266+#endif // CATCH_PREPROCESSOR_INTERNAL_STRINGIFY_HPP_INCLUDED
17267+
17268+// We need this suppression to leak, because it took until GCC 10
17269+// for the front end to handle local suppression via _Pragma properly
17270+#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && __GNUC__ <= 9
17271+ #pragma GCC diagnostic ignored "-Wparentheses"
17272+#endif
17273+
17274+#if !defined(CATCH_CONFIG_DISABLE)
17275+
17276+#if defined(CATCH_CONFIG_FAST_COMPILE) || defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
17277+
17278+///////////////////////////////////////////////////////////////////////////////
17279+// Another way to speed-up compilation is to omit local try-catch for REQUIRE*
17280+// macros.
17281+#define INTERNAL_CATCH_TRY
17282+#define INTERNAL_CATCH_CATCH( capturer )
17283+
17284+#else // CATCH_CONFIG_FAST_COMPILE
17285+
17286+#define INTERNAL_CATCH_TRY try
17287+#define INTERNAL_CATCH_CATCH( handler ) catch(...) { (handler).handleUnexpectedInflightException(); }
17288+
17289+#endif
17290+
17291+#define INTERNAL_CATCH_REACT( handler ) handler.complete();
17292+
17293+///////////////////////////////////////////////////////////////////////////////
17294+#define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \
17295+ do { /* NOLINT(bugprone-infinite-loop) */ \
17296+ /* The expression should not be evaluated, but warnings should hopefully be checked */ \
17297+ CATCH_INTERNAL_IGNORE_BUT_WARN(__VA_ARGS__); \
17298+ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
17299+ INTERNAL_CATCH_TRY { \
17300+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
17301+ CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
17302+ catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); /* NOLINT(bugprone-chained-comparison) */ \
17303+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
17304+ } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
17305+ INTERNAL_CATCH_REACT( catchAssertionHandler ) \
17306+ } while( (void)0, (false) && static_cast<const bool&>( !!(__VA_ARGS__) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look
17307+ // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&.
17308+
17309+///////////////////////////////////////////////////////////////////////////////
17310+#define INTERNAL_CATCH_IF( macroName, resultDisposition, ... ) \
17311+ INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \
17312+ if( Catch::getResultCapture().lastAssertionPassed() )
17313+
17314+///////////////////////////////////////////////////////////////////////////////
17315+#define INTERNAL_CATCH_ELSE( macroName, resultDisposition, ... ) \
17316+ INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \
17317+ if( !Catch::getResultCapture().lastAssertionPassed() )
17318+
17319+///////////////////////////////////////////////////////////////////////////////
17320+#define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \
17321+ do { \
17322+ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
17323+ try { \
17324+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
17325+ CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \
17326+ static_cast<void>(__VA_ARGS__); \
17327+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
17328+ catchAssertionHandler.handleExceptionNotThrownAsExpected(); \
17329+ } \
17330+ catch( ... ) { \
17331+ catchAssertionHandler.handleUnexpectedInflightException(); \
17332+ } \
17333+ INTERNAL_CATCH_REACT( catchAssertionHandler ) \
17334+ } while( false )
17335+
17336+///////////////////////////////////////////////////////////////////////////////
17337+#define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \
17338+ do { \
17339+ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition); \
17340+ if( catchAssertionHandler.allowThrows() ) \
17341+ try { \
17342+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
17343+ CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT \
17344+ CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \
17345+ static_cast<void>(__VA_ARGS__); \
17346+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
17347+ catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
17348+ } \
17349+ catch( ... ) { \
17350+ catchAssertionHandler.handleExceptionThrownAsExpected(); \
17351+ } \
17352+ else \
17353+ catchAssertionHandler.handleThrowingCallSkipped(); \
17354+ INTERNAL_CATCH_REACT( catchAssertionHandler ) \
17355+ } while( false )
17356+
17357+///////////////////////////////////////////////////////////////////////////////
17358+#define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \
17359+ do { \
17360+ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \
17361+ if( catchAssertionHandler.allowThrows() ) \
17362+ try { \
17363+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
17364+ CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT \
17365+ CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \
17366+ static_cast<void>(expr); \
17367+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
17368+ catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
17369+ } \
17370+ catch( exceptionType const& ) { \
17371+ catchAssertionHandler.handleExceptionThrownAsExpected(); \
17372+ } \
17373+ catch( ... ) { \
17374+ catchAssertionHandler.handleUnexpectedInflightException(); \
17375+ } \
17376+ else \
17377+ catchAssertionHandler.handleThrowingCallSkipped(); \
17378+ INTERNAL_CATCH_REACT( catchAssertionHandler ) \
17379+ } while( false )
17380+
17381+
17382+
17383+///////////////////////////////////////////////////////////////////////////////
17384+// Although this is matcher-based, it can be used with just a string
17385+#define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \
17386+ do { \
17387+ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
17388+ if( catchAssertionHandler.allowThrows() ) \
17389+ try { \
17390+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
17391+ CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT \
17392+ CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \
17393+ static_cast<void>(__VA_ARGS__); \
17394+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
17395+ catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
17396+ } \
17397+ catch( ... ) { \
17398+ Catch::handleExceptionMatchExpr( catchAssertionHandler, matcher ); \
17399+ } \
17400+ else \
17401+ catchAssertionHandler.handleThrowingCallSkipped(); \
17402+ INTERNAL_CATCH_REACT( catchAssertionHandler ) \
17403+ } while( false )
17404+
17405+#endif // CATCH_CONFIG_DISABLE
17406+
17407+#endif // CATCH_TEST_MACRO_IMPL_HPP_INCLUDED
17408+
17409+
17410+#ifndef CATCH_SECTION_HPP_INCLUDED
17411+#define CATCH_SECTION_HPP_INCLUDED
17412+
17413+
17414+
17415+
17416+/** \file
17417+ * Wrapper for the STATIC_ANALYSIS_SUPPORT configuration option
17418+ *
17419+ * Some of Catch2's macros can be defined differently to work better with
17420+ * static analysis tools, like clang-tidy or coverity.
17421+ * Currently the main use case is to show that `SECTION`s are executed
17422+ * exclusively, and not all in one run of a `TEST_CASE`.
17423+ */
17424+
17425+#ifndef CATCH_CONFIG_STATIC_ANALYSIS_SUPPORT_HPP_INCLUDED
17426+#define CATCH_CONFIG_STATIC_ANALYSIS_SUPPORT_HPP_INCLUDED
17427+
17428+
17429+#if defined(__clang_analyzer__) || defined(__COVERITY__)
17430+ #define CATCH_INTERNAL_CONFIG_STATIC_ANALYSIS_SUPPORT
17431+#endif
17432+
17433+#if defined( CATCH_INTERNAL_CONFIG_STATIC_ANALYSIS_SUPPORT ) && \
17434+ !defined( CATCH_CONFIG_NO_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT ) && \
17435+ !defined( CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT )
17436+# define CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT
17437+#endif
17438+
17439+
17440+#endif // CATCH_CONFIG_STATIC_ANALYSIS_SUPPORT_HPP_INCLUDED
17441+
17442+
17443+#ifndef CATCH_TIMER_HPP_INCLUDED
17444+#define CATCH_TIMER_HPP_INCLUDED
17445+
17446+#include <cstdint>
17447+
17448+namespace Catch {
17449+
17450+ class Timer {
17451+ uint64_t m_nanoseconds = 0;
17452+ public:
17453+ void start();
17454+ auto getElapsedNanoseconds() const -> uint64_t;
17455+ auto getElapsedMicroseconds() const -> uint64_t;
17456+ auto getElapsedMilliseconds() const -> unsigned int;
17457+ auto getElapsedSeconds() const -> double;
17458+ };
17459+
17460+} // namespace Catch
17461+
17462+#endif // CATCH_TIMER_HPP_INCLUDED
17463+
17464+namespace Catch {
17465+
17466+ class Section : Detail::NonCopyable {
17467+ public:
17468+ Section( SectionInfo&& info );
17469+ Section( SourceLineInfo const& _lineInfo,
17470+ StringRef _name,
17471+ const char* const = nullptr );
17472+ ~Section();
17473+
17474+ // This indicates whether the section should be executed or not
17475+ explicit operator bool() const;
17476+
17477+ private:
17478+ SectionInfo m_info;
17479+
17480+ Counts m_assertions;
17481+ bool m_sectionIncluded;
17482+ Timer m_timer;
17483+ };
17484+
17485+} // end namespace Catch
17486+
17487+#if !defined(CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT)
17488+# define INTERNAL_CATCH_SECTION( ... ) \
17489+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
17490+ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
17491+ if ( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( \
17492+ catch_internal_Section ) = \
17493+ Catch::Section( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \
17494+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
17495+
17496+# define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \
17497+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
17498+ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
17499+ if ( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( \
17500+ catch_internal_Section ) = \
17501+ Catch::SectionInfo( \
17502+ CATCH_INTERNAL_LINEINFO, \
17503+ ( Catch::ReusableStringStream() << __VA_ARGS__ ) \
17504+ .str() ) ) \
17505+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
17506+
17507+#else
17508+
17509+// These section definitions imply that at most one section at one level
17510+// will be intered (because only one section's __LINE__ can be equal to
17511+// the dummy `catchInternalSectionHint` variable from `TEST_CASE`).
17512+
17513+namespace Catch {
17514+ namespace Detail {
17515+ // Intentionally without linkage, as it should only be used as a dummy
17516+ // symbol for static analysis.
17517+ // The arguments are used as a dummy for checking warnings in the passed
17518+ // expressions.
17519+ int GetNewSectionHint( StringRef, const char* const = nullptr );
17520+ } // namespace Detail
17521+} // namespace Catch
17522+
17523+
17524+# define INTERNAL_CATCH_SECTION( ... ) \
17525+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
17526+ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
17527+ CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \
17528+ if ( [[maybe_unused]] const int catchInternalPreviousSectionHint = \
17529+ catchInternalSectionHint, \
17530+ catchInternalSectionHint = \
17531+ Catch::Detail::GetNewSectionHint(__VA_ARGS__); \
17532+ catchInternalPreviousSectionHint == __LINE__ ) \
17533+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
17534+
17535+# define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \
17536+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
17537+ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
17538+ CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \
17539+ if ( [[maybe_unused]] const int catchInternalPreviousSectionHint = \
17540+ catchInternalSectionHint, \
17541+ catchInternalSectionHint = Catch::Detail::GetNewSectionHint( \
17542+ ( Catch::ReusableStringStream() << __VA_ARGS__ ).str()); \
17543+ catchInternalPreviousSectionHint == __LINE__ ) \
17544+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
17545+
17546+#endif
17547+
17548+
17549+#endif // CATCH_SECTION_HPP_INCLUDED
17550+
17551+
17552+#ifndef CATCH_TEST_REGISTRY_HPP_INCLUDED
17553+#define CATCH_TEST_REGISTRY_HPP_INCLUDED
17554+
17555+
17556+
17557+#ifndef CATCH_INTERFACES_TEST_INVOKER_HPP_INCLUDED
17558+#define CATCH_INTERFACES_TEST_INVOKER_HPP_INCLUDED
17559+
17560+namespace Catch {
17561+
17562+ class ITestInvoker {
17563+ public:
17564+ virtual void invoke() const = 0;
17565+ virtual ~ITestInvoker(); // = default
17566+ };
17567+
17568+} // namespace Catch
17569+
17570+#endif // CATCH_INTERFACES_TEST_INVOKER_HPP_INCLUDED
17571+
17572+
17573+#ifndef CATCH_PREPROCESSOR_REMOVE_PARENS_HPP_INCLUDED
17574+#define CATCH_PREPROCESSOR_REMOVE_PARENS_HPP_INCLUDED
17575+
17576+#define INTERNAL_CATCH_EXPAND1( param ) INTERNAL_CATCH_EXPAND2( param )
17577+#define INTERNAL_CATCH_EXPAND2( ... ) INTERNAL_CATCH_NO##__VA_ARGS__
17578+#define INTERNAL_CATCH_DEF( ... ) INTERNAL_CATCH_DEF __VA_ARGS__
17579+#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF
17580+
17581+#define INTERNAL_CATCH_REMOVE_PARENS( ... ) \
17582+ INTERNAL_CATCH_EXPAND1( INTERNAL_CATCH_DEF __VA_ARGS__ )
17583+
17584+#endif // CATCH_PREPROCESSOR_REMOVE_PARENS_HPP_INCLUDED
17585+
17586+// GCC 5 and older do not properly handle disabling unused-variable warning
17587+// with a _Pragma. This means that we have to leak the suppression to the
17588+// user code as well :-(
17589+#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ <= 5
17590+#pragma GCC diagnostic ignored "-Wunused-variable"
17591+#endif
17592+
17593+
17594+
17595+namespace Catch {
17596+
17597+template<typename C>
17598+class TestInvokerAsMethod : public ITestInvoker {
17599+ void (C::*m_testAsMethod)();
17600+public:
17601+ TestInvokerAsMethod( void (C::*testAsMethod)() ) noexcept : m_testAsMethod( testAsMethod ) {}
17602+
17603+ void invoke() const override {
17604+ C obj;
17605+ (obj.*m_testAsMethod)();
17606+ }
17607+};
17608+
17609+Detail::unique_ptr<ITestInvoker> makeTestInvoker( void(*testAsFunction)() );
17610+
17611+template<typename C>
17612+Detail::unique_ptr<ITestInvoker> makeTestInvoker( void (C::*testAsMethod)() ) {
17613+ return Detail::make_unique<TestInvokerAsMethod<C>>( testAsMethod );
17614+}
17615+
17616+struct NameAndTags {
17617+ constexpr NameAndTags( StringRef name_ = StringRef(),
17618+ StringRef tags_ = StringRef() ) noexcept:
17619+ name( name_ ), tags( tags_ ) {}
17620+ StringRef name;
17621+ StringRef tags;
17622+};
17623+
17624+struct AutoReg : Detail::NonCopyable {
17625+ AutoReg( Detail::unique_ptr<ITestInvoker> invoker, SourceLineInfo const& lineInfo, StringRef classOrMethod, NameAndTags const& nameAndTags ) noexcept;
17626+};
17627+
17628+} // end namespace Catch
17629+
17630+#if defined(CATCH_CONFIG_DISABLE)
17631+ #define INTERNAL_CATCH_TESTCASE_NO_REGISTRATION( TestName, ... ) \
17632+ static inline void TestName()
17633+ #define INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... ) \
17634+ namespace{ \
17635+ struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \
17636+ void test(); \
17637+ }; \
17638+ } \
17639+ void TestName::test()
17640+#endif
17641+
17642+
17643+#if !defined(CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT)
17644+
17645+ ///////////////////////////////////////////////////////////////////////////////
17646+ #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \
17647+ static void TestName(); \
17648+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
17649+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
17650+ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
17651+ namespace{ const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \
17652+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
17653+ static void TestName()
17654+ #define INTERNAL_CATCH_TESTCASE( ... ) \
17655+ INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), __VA_ARGS__ )
17656+
17657+#else // ^^ !CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT | vv CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT
17658+
17659+
17660+// Dummy registrator for the dumy test case macros
17661+namespace Catch {
17662+ namespace Detail {
17663+ struct DummyUse {
17664+ DummyUse( void ( * )( int ), Catch::NameAndTags const& );
17665+ };
17666+ } // namespace Detail
17667+} // namespace Catch
17668+
17669+// Note that both the presence of the argument and its exact name are
17670+// necessary for the section support.
17671+
17672+// We provide a shadowed variable so that a `SECTION` inside non-`TEST_CASE`
17673+// tests can compile. The redefined `TEST_CASE` shadows this with param.
17674+static int catchInternalSectionHint = 0;
17675+
17676+# define INTERNAL_CATCH_TESTCASE2( fname, ... ) \
17677+ static void fname( int ); \
17678+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
17679+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
17680+ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
17681+ static const Catch::Detail::DummyUse INTERNAL_CATCH_UNIQUE_NAME( \
17682+ dummyUser )( &(fname), Catch::NameAndTags{ __VA_ARGS__ } ); \
17683+ CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \
17684+ static void fname( [[maybe_unused]] int catchInternalSectionHint ) \
17685+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
17686+# define INTERNAL_CATCH_TESTCASE( ... ) \
17687+ INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( dummyFunction ), __VA_ARGS__ )
17688+
17689+
17690+#endif // CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT
17691+
17692+ ///////////////////////////////////////////////////////////////////////////////
17693+ #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\
17694+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
17695+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
17696+ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
17697+ namespace{ \
17698+ struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \
17699+ void test(); \
17700+ }; \
17701+ const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( \
17702+ Catch::makeTestInvoker( &TestName::test ), \
17703+ CATCH_INTERNAL_LINEINFO, \
17704+ #ClassName##_catch_sr, \
17705+ Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \
17706+ } \
17707+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
17708+ void TestName::test()
17709+ #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \
17710+ INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), ClassName, __VA_ARGS__ )
17711+
17712+
17713+ ///////////////////////////////////////////////////////////////////////////////
17714+ #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \
17715+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
17716+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
17717+ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
17718+ namespace { \
17719+ const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( \
17720+ Catch::makeTestInvoker( &QualifiedMethod ), \
17721+ CATCH_INTERNAL_LINEINFO, \
17722+ "&" #QualifiedMethod##_catch_sr, \
17723+ Catch::NameAndTags{ __VA_ARGS__ } ); \
17724+ } /* NOLINT */ \
17725+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
17726+
17727+
17728+ ///////////////////////////////////////////////////////////////////////////////
17729+ #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \
17730+ do { \
17731+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
17732+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
17733+ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
17734+ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \
17735+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
17736+ } while(false)
17737+
17738+
17739+#endif // CATCH_TEST_REGISTRY_HPP_INCLUDED
17740+
17741+
17742+// All of our user-facing macros support configuration toggle, that
17743+// forces them to be defined prefixed with CATCH_. We also like to
17744+// support another toggle that can minimize (disable) their implementation.
17745+// Given this, we have 4 different configuration options below
17746+
17747+#if defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE)
17748+
17749+ #define CATCH_REQUIRE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ )
17750+ #define CATCH_REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
17751+
17752+ #define CATCH_REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ )
17753+ #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr )
17754+ #define CATCH_REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ )
17755+
17756+ #define CATCH_CHECK( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
17757+ #define CATCH_CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
17758+ #define CATCH_CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CATCH_CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
17759+ #define CATCH_CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
17760+ #define CATCH_CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
17761+
17762+ #define CATCH_CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
17763+ #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr )
17764+ #define CATCH_CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
17765+
17766+ #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
17767+ #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
17768+ #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
17769+ #define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
17770+ #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
17771+ #define CATCH_DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ )
17772+ #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )
17773+ #define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
17774+ #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
17775+ #define CATCH_SKIP( ... ) INTERNAL_CATCH_MSG( "SKIP", Catch::ResultWas::ExplicitSkip, Catch::ResultDisposition::Normal, __VA_ARGS__ )
17776+
17777+
17778+ #if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE)
17779+ #define CATCH_STATIC_REQUIRE( ... ) static_assert( __VA_ARGS__ , #__VA_ARGS__ ); CATCH_SUCCEED( #__VA_ARGS__ )
17780+ #define CATCH_STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); CATCH_SUCCEED( #__VA_ARGS__ )
17781+ #define CATCH_STATIC_CHECK( ... ) static_assert( __VA_ARGS__ , #__VA_ARGS__ ); CATCH_SUCCEED( #__VA_ARGS__ )
17782+ #define CATCH_STATIC_CHECK_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); CATCH_SUCCEED( #__VA_ARGS__ )
17783+ #else
17784+ #define CATCH_STATIC_REQUIRE( ... ) CATCH_REQUIRE( __VA_ARGS__ )
17785+ #define CATCH_STATIC_REQUIRE_FALSE( ... ) CATCH_REQUIRE_FALSE( __VA_ARGS__ )
17786+ #define CATCH_STATIC_CHECK( ... ) CATCH_CHECK( __VA_ARGS__ )
17787+ #define CATCH_STATIC_CHECK_FALSE( ... ) CATCH_CHECK_FALSE( __VA_ARGS__ )
17788+ #endif
17789+
17790+
17791+ // "BDD-style" convenience wrappers
17792+ #define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ )
17793+ #define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
17794+ #define CATCH_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc )
17795+ #define CATCH_AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc )
17796+ #define CATCH_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc )
17797+ #define CATCH_AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc )
17798+ #define CATCH_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc )
17799+ #define CATCH_AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc )
17800+
17801+#elif defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE) // ^^ prefixed, implemented | vv prefixed, disabled
17802+
17803+ #define CATCH_REQUIRE( ... ) (void)(0)
17804+ #define CATCH_REQUIRE_FALSE( ... ) (void)(0)
17805+
17806+ #define CATCH_REQUIRE_THROWS( ... ) (void)(0)
17807+ #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0)
17808+ #define CATCH_REQUIRE_NOTHROW( ... ) (void)(0)
17809+
17810+ #define CATCH_CHECK( ... ) (void)(0)
17811+ #define CATCH_CHECK_FALSE( ... ) (void)(0)
17812+ #define CATCH_CHECKED_IF( ... ) if (__VA_ARGS__)
17813+ #define CATCH_CHECKED_ELSE( ... ) if (!(__VA_ARGS__))
17814+ #define CATCH_CHECK_NOFAIL( ... ) (void)(0)
17815+
17816+ #define CATCH_CHECK_THROWS( ... ) (void)(0)
17817+ #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) (void)(0)
17818+ #define CATCH_CHECK_NOTHROW( ... ) (void)(0)
17819+
17820+ #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ))
17821+ #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ))
17822+ #define CATCH_METHOD_AS_TEST_CASE( method, ... )
17823+ #define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0)
17824+ #define CATCH_SECTION( ... )
17825+ #define CATCH_DYNAMIC_SECTION( ... )
17826+ #define CATCH_FAIL( ... ) (void)(0)
17827+ #define CATCH_FAIL_CHECK( ... ) (void)(0)
17828+ #define CATCH_SUCCEED( ... ) (void)(0)
17829+ #define CATCH_SKIP( ... ) (void)(0)
17830+
17831+ #define CATCH_STATIC_REQUIRE( ... ) (void)(0)
17832+ #define CATCH_STATIC_REQUIRE_FALSE( ... ) (void)(0)
17833+ #define CATCH_STATIC_CHECK( ... ) (void)(0)
17834+ #define CATCH_STATIC_CHECK_FALSE( ... ) (void)(0)
17835+
17836+ // "BDD-style" convenience wrappers
17837+ #define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ))
17838+ #define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), className )
17839+ #define CATCH_GIVEN( desc )
17840+ #define CATCH_AND_GIVEN( desc )
17841+ #define CATCH_WHEN( desc )
17842+ #define CATCH_AND_WHEN( desc )
17843+ #define CATCH_THEN( desc )
17844+ #define CATCH_AND_THEN( desc )
17845+
17846+#elif !defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE) // ^^ prefixed, disabled | vv unprefixed, implemented
17847+
17848+ #define REQUIRE( ... ) INTERNAL_CATCH_TEST( "REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ )
17849+ #define REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
17850+
17851+ #define REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ )
17852+ #define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr )
17853+ #define REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ )
17854+
17855+ #define CHECK( ... ) INTERNAL_CATCH_TEST( "CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
17856+ #define CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
17857+ #define CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
17858+ #define CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
17859+ #define CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
17860+
17861+ #define CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
17862+ #define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr )
17863+ #define CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
17864+
17865+ #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
17866+ #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
17867+ #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
17868+ #define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
17869+ #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
17870+ #define DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ )
17871+ #define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )
17872+ #define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
17873+ #define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
17874+ #define SKIP( ... ) INTERNAL_CATCH_MSG( "SKIP", Catch::ResultWas::ExplicitSkip, Catch::ResultDisposition::Normal, __VA_ARGS__ )
17875+
17876+
17877+ #if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE)
17878+ #define STATIC_REQUIRE( ... ) static_assert( __VA_ARGS__, #__VA_ARGS__ ); SUCCEED( #__VA_ARGS__ )
17879+ #define STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); SUCCEED( "!(" #__VA_ARGS__ ")" )
17880+ #define STATIC_CHECK( ... ) static_assert( __VA_ARGS__, #__VA_ARGS__ ); SUCCEED( #__VA_ARGS__ )
17881+ #define STATIC_CHECK_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); SUCCEED( "!(" #__VA_ARGS__ ")" )
17882+ #else
17883+ #define STATIC_REQUIRE( ... ) REQUIRE( __VA_ARGS__ )
17884+ #define STATIC_REQUIRE_FALSE( ... ) REQUIRE_FALSE( __VA_ARGS__ )
17885+ #define STATIC_CHECK( ... ) CHECK( __VA_ARGS__ )
17886+ #define STATIC_CHECK_FALSE( ... ) CHECK_FALSE( __VA_ARGS__ )
17887+ #endif
17888+
17889+ // "BDD-style" convenience wrappers
17890+ #define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ )
17891+ #define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
17892+ #define GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc )
17893+ #define AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc )
17894+ #define WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc )
17895+ #define AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc )
17896+ #define THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc )
17897+ #define AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc )
17898+
17899+#elif !defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE) // ^^ unprefixed, implemented | vv unprefixed, disabled
17900+
17901+ #define REQUIRE( ... ) (void)(0)
17902+ #define REQUIRE_FALSE( ... ) (void)(0)
17903+
17904+ #define REQUIRE_THROWS( ... ) (void)(0)
17905+ #define REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0)
17906+ #define REQUIRE_NOTHROW( ... ) (void)(0)
17907+
17908+ #define CHECK( ... ) (void)(0)
17909+ #define CHECK_FALSE( ... ) (void)(0)
17910+ #define CHECKED_IF( ... ) if (__VA_ARGS__)
17911+ #define CHECKED_ELSE( ... ) if (!(__VA_ARGS__))
17912+ #define CHECK_NOFAIL( ... ) (void)(0)
17913+
17914+ #define CHECK_THROWS( ... ) (void)(0)
17915+ #define CHECK_THROWS_AS( expr, exceptionType ) (void)(0)
17916+ #define CHECK_NOTHROW( ... ) (void)(0)
17917+
17918+ #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), __VA_ARGS__)
17919+ #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ))
17920+ #define METHOD_AS_TEST_CASE( method, ... )
17921+ #define REGISTER_TEST_CASE( Function, ... ) (void)(0)
17922+ #define SECTION( ... )
17923+ #define DYNAMIC_SECTION( ... )
17924+ #define FAIL( ... ) (void)(0)
17925+ #define FAIL_CHECK( ... ) (void)(0)
17926+ #define SUCCEED( ... ) (void)(0)
17927+ #define SKIP( ... ) (void)(0)
17928+
17929+ #define STATIC_REQUIRE( ... ) (void)(0)
17930+ #define STATIC_REQUIRE_FALSE( ... ) (void)(0)
17931+ #define STATIC_CHECK( ... ) (void)(0)
17932+ #define STATIC_CHECK_FALSE( ... ) (void)(0)
17933+
17934+ // "BDD-style" convenience wrappers
17935+ #define SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ) )
17936+ #define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), className )
17937+
17938+ #define GIVEN( desc )
17939+ #define AND_GIVEN( desc )
17940+ #define WHEN( desc )
17941+ #define AND_WHEN( desc )
17942+ #define THEN( desc )
17943+ #define AND_THEN( desc )
17944+
17945+#endif // ^^ unprefixed, disabled
17946+
17947+// end of user facing macros
17948+
17949+#endif // CATCH_TEST_MACROS_HPP_INCLUDED
17950+
17951+
17952+#ifndef CATCH_TEMPLATE_TEST_REGISTRY_HPP_INCLUDED
17953+#define CATCH_TEMPLATE_TEST_REGISTRY_HPP_INCLUDED
17954+
17955+
17956+
17957+#ifndef CATCH_PREPROCESSOR_HPP_INCLUDED
17958+#define CATCH_PREPROCESSOR_HPP_INCLUDED
17959+
17960+
17961+#if defined(__GNUC__)
17962+// We need to silence "empty __VA_ARGS__ warning", and using just _Pragma does not work
17963+#pragma GCC system_header
17964+#endif
17965+
17966+
17967+#define CATCH_RECURSION_LEVEL0(...) __VA_ARGS__
17968+#define CATCH_RECURSION_LEVEL1(...) CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(__VA_ARGS__)))
17969+#define CATCH_RECURSION_LEVEL2(...) CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(__VA_ARGS__)))
17970+#define CATCH_RECURSION_LEVEL3(...) CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(__VA_ARGS__)))
17971+#define CATCH_RECURSION_LEVEL4(...) CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(__VA_ARGS__)))
17972+#define CATCH_RECURSION_LEVEL5(...) CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(__VA_ARGS__)))
17973+
17974+#ifdef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
17975+#define INTERNAL_CATCH_EXPAND_VARGS(...) __VA_ARGS__
17976+// MSVC needs more evaluations
17977+#define CATCH_RECURSION_LEVEL6(...) CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(__VA_ARGS__)))
17978+#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL6(CATCH_RECURSION_LEVEL6(__VA_ARGS__))
17979+#else
17980+#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL5(__VA_ARGS__)
17981+#endif
17982+
17983+#define CATCH_REC_END(...)
17984+#define CATCH_REC_OUT
17985+
17986+#define CATCH_EMPTY()
17987+#define CATCH_DEFER(id) id CATCH_EMPTY()
17988+
17989+#define CATCH_REC_GET_END2() 0, CATCH_REC_END
17990+#define CATCH_REC_GET_END1(...) CATCH_REC_GET_END2
17991+#define CATCH_REC_GET_END(...) CATCH_REC_GET_END1
17992+#define CATCH_REC_NEXT0(test, next, ...) next CATCH_REC_OUT
17993+#define CATCH_REC_NEXT1(test, next) CATCH_DEFER ( CATCH_REC_NEXT0 ) ( test, next, 0)
17994+#define CATCH_REC_NEXT(test, next) CATCH_REC_NEXT1(CATCH_REC_GET_END test, next)
17995+
17996+#define CATCH_REC_LIST0(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ )
17997+#define CATCH_REC_LIST1(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0) ) ( f, peek, __VA_ARGS__ )
17998+#define CATCH_REC_LIST2(f, x, peek, ...) f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ )
17999+
18000+#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__ )
18001+#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__ )
18002+#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__ )
18003+
18004+// Applies the function macro `f` to each of the remaining parameters, inserts commas between the results,
18005+// and passes userdata as the first parameter to each invocation,
18006+// e.g. CATCH_REC_LIST_UD(f, x, a, b, c) evaluates to f(x, a), f(x, b), f(x, c)
18007+#define CATCH_REC_LIST_UD(f, userdata, ...) CATCH_RECURSE(CATCH_REC_LIST2_UD(f, userdata, __VA_ARGS__, ()()(), ()()(), ()()(), 0))
18008+
18009+#define CATCH_REC_LIST(f, ...) CATCH_RECURSE(CATCH_REC_LIST2(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0))
18010+
18011+#define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__)
18012+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
18013+#define INTERNAL_CATCH_STRINGIZE2(...) #__VA_ARGS__
18014+#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param))
18015+#else
18016+// MSVC is adding extra space and needs another indirection to expand INTERNAL_CATCH_NOINTERNAL_CATCH_DEF
18017+#define INTERNAL_CATCH_STRINGIZE2(...) INTERNAL_CATCH_STRINGIZE3(__VA_ARGS__)
18018+#define INTERNAL_CATCH_STRINGIZE3(...) #__VA_ARGS__
18019+#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1)
18020+#endif
18021+
18022+#define INTERNAL_CATCH_MAKE_NAMESPACE2(...) ns_##__VA_ARGS__
18023+#define INTERNAL_CATCH_MAKE_NAMESPACE(name) INTERNAL_CATCH_MAKE_NAMESPACE2(name)
18024+
18025+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
18026+#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS_GEN(__VA_ARGS__)>())
18027+#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))
18028+#else
18029+#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) INTERNAL_CATCH_EXPAND_VARGS(decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS_GEN(__VA_ARGS__)>()))
18030+#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)))
18031+#endif
18032+
18033+#define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(...)\
18034+ CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,__VA_ARGS__)
18035+
18036+#define INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_0) INTERNAL_CATCH_REMOVE_PARENS(_0)
18037+#define INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_0, _1) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_1)
18038+#define INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_0, _1, _2) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_1, _2)
18039+#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)
18040+#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)
18041+#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)
18042+#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)
18043+#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)
18044+#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)
18045+#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)
18046+#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)
18047+
18048+#define INTERNAL_CATCH_VA_NARGS_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N
18049+
18050+#define INTERNAL_CATCH_TYPE_GEN\
18051+ template<typename...> struct TypeList {};\
18052+ template<typename...Ts>\
18053+ constexpr auto get_wrapper() noexcept -> TypeList<Ts...> { return {}; }\
18054+ template<template<typename...> class...> struct TemplateTypeList{};\
18055+ template<template<typename...> class...Cs>\
18056+ constexpr auto get_wrapper() noexcept -> TemplateTypeList<Cs...> { return {}; }\
18057+ template<typename...>\
18058+ struct append;\
18059+ template<typename...>\
18060+ struct rewrap;\
18061+ template<template<typename...> class, typename...>\
18062+ struct create;\
18063+ template<template<typename...> class, typename>\
18064+ struct convert;\
18065+ \
18066+ template<typename T> \
18067+ struct append<T> { using type = T; };\
18068+ template< template<typename...> class L1, typename...E1, template<typename...> class L2, typename...E2, typename...Rest>\
18069+ struct append<L1<E1...>, L2<E2...>, Rest...> { using type = typename append<L1<E1...,E2...>, Rest...>::type; };\
18070+ template< template<typename...> class L1, typename...E1, typename...Rest>\
18071+ struct append<L1<E1...>, TypeList<mpl_::na>, Rest...> { using type = L1<E1...>; };\
18072+ \
18073+ template< template<typename...> class Container, template<typename...> class List, typename...elems>\
18074+ struct rewrap<TemplateTypeList<Container>, List<elems...>> { using type = TypeList<Container<elems...>>; };\
18075+ template< template<typename...> class Container, template<typename...> class List, class...Elems, typename...Elements>\
18076+ struct rewrap<TemplateTypeList<Container>, List<Elems...>, Elements...> { using type = typename append<TypeList<Container<Elems...>>, typename rewrap<TemplateTypeList<Container>, Elements...>::type>::type; };\
18077+ \
18078+ template<template <typename...> class Final, template< typename...> class...Containers, typename...Types>\
18079+ struct create<Final, TemplateTypeList<Containers...>, TypeList<Types...>> { using type = typename append<Final<>, typename rewrap<TemplateTypeList<Containers>, Types...>::type...>::type; };\
18080+ template<template <typename...> class Final, template <typename...> class List, typename...Ts>\
18081+ struct convert<Final, List<Ts...>> { using type = typename append<Final<>,TypeList<Ts>...>::type; };
18082+
18083+#define INTERNAL_CATCH_NTTP_1(signature, ...)\
18084+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)> struct Nttp{};\
18085+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
18086+ constexpr auto get_wrapper() noexcept -> Nttp<__VA_ARGS__> { return {}; } \
18087+ template<template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...> struct NttpTemplateTypeList{};\
18088+ template<template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...Cs>\
18089+ constexpr auto get_wrapper() noexcept -> NttpTemplateTypeList<Cs...> { return {}; } \
18090+ \
18091+ template< template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class Container, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class List, INTERNAL_CATCH_REMOVE_PARENS(signature)>\
18092+ struct rewrap<NttpTemplateTypeList<Container>, List<__VA_ARGS__>> { using type = TypeList<Container<__VA_ARGS__>>; };\
18093+ template< template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class Container, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class List, INTERNAL_CATCH_REMOVE_PARENS(signature), typename...Elements>\
18094+ struct rewrap<NttpTemplateTypeList<Container>, List<__VA_ARGS__>, Elements...> { using type = typename append<TypeList<Container<__VA_ARGS__>>, typename rewrap<NttpTemplateTypeList<Container>, Elements...>::type>::type; };\
18095+ template<template <typename...> class Final, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...Containers, typename...Types>\
18096+ struct create<Final, NttpTemplateTypeList<Containers...>, TypeList<Types...>> { using type = typename append<Final<>, typename rewrap<NttpTemplateTypeList<Containers>, Types...>::type...>::type; };
18097+
18098+#define INTERNAL_CATCH_DECLARE_SIG_TEST0(TestName)
18099+#define INTERNAL_CATCH_DECLARE_SIG_TEST1(TestName, signature)\
18100+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
18101+ static void TestName()
18102+#define INTERNAL_CATCH_DECLARE_SIG_TEST_X(TestName, signature, ...)\
18103+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
18104+ static void TestName()
18105+
18106+#define INTERNAL_CATCH_DEFINE_SIG_TEST0(TestName)
18107+#define INTERNAL_CATCH_DEFINE_SIG_TEST1(TestName, signature)\
18108+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
18109+ static void TestName()
18110+#define INTERNAL_CATCH_DEFINE_SIG_TEST_X(TestName, signature,...)\
18111+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
18112+ static void TestName()
18113+
18114+#define INTERNAL_CATCH_NTTP_REGISTER0(TestFunc, signature)\
18115+ template<typename Type>\
18116+ void reg_test(TypeList<Type>, Catch::NameAndTags nameAndTags)\
18117+ {\
18118+ Catch::AutoReg( Catch::makeTestInvoker(&TestFunc<Type>), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), nameAndTags);\
18119+ }
18120+
18121+#define INTERNAL_CATCH_NTTP_REGISTER(TestFunc, signature, ...)\
18122+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
18123+ void reg_test(Nttp<__VA_ARGS__>, Catch::NameAndTags nameAndTags)\
18124+ {\
18125+ Catch::AutoReg( Catch::makeTestInvoker(&TestFunc<__VA_ARGS__>), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), nameAndTags);\
18126+ }
18127+
18128+#define INTERNAL_CATCH_NTTP_REGISTER_METHOD0(TestName, signature, ...)\
18129+ template<typename Type>\
18130+ void reg_test(TypeList<Type>, Catch::StringRef className, Catch::NameAndTags nameAndTags)\
18131+ {\
18132+ Catch::AutoReg( Catch::makeTestInvoker(&TestName<Type>::test), CATCH_INTERNAL_LINEINFO, className, nameAndTags);\
18133+ }
18134+
18135+#define INTERNAL_CATCH_NTTP_REGISTER_METHOD(TestName, signature, ...)\
18136+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
18137+ void reg_test(Nttp<__VA_ARGS__>, Catch::StringRef className, Catch::NameAndTags nameAndTags)\
18138+ {\
18139+ Catch::AutoReg( Catch::makeTestInvoker(&TestName<__VA_ARGS__>::test), CATCH_INTERNAL_LINEINFO, className, nameAndTags);\
18140+ }
18141+
18142+#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD0(TestName, ClassName)
18143+#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD1(TestName, ClassName, signature)\
18144+ template<typename TestType> \
18145+ struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName)<TestType> { \
18146+ void test();\
18147+ }
18148+
18149+#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X(TestName, ClassName, signature, ...)\
18150+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)> \
18151+ struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName)<__VA_ARGS__> { \
18152+ void test();\
18153+ }
18154+
18155+#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD0(TestName)
18156+#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD1(TestName, signature)\
18157+ template<typename TestType> \
18158+ void INTERNAL_CATCH_MAKE_NAMESPACE(TestName)::TestName<TestType>::test()
18159+#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X(TestName, signature, ...)\
18160+ template<INTERNAL_CATCH_REMOVE_PARENS(signature)> \
18161+ void INTERNAL_CATCH_MAKE_NAMESPACE(TestName)::TestName<__VA_ARGS__>::test()
18162+
18163+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
18164+#define INTERNAL_CATCH_NTTP_0
18165+#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)
18166+#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__)
18167+#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__)
18168+#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__)
18169+#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__)
18170+#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__)
18171+#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__)
18172+#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__)
18173+#else
18174+#define INTERNAL_CATCH_NTTP_0(signature)
18175+#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__))
18176+#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__))
18177+#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__))
18178+#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__))
18179+#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__))
18180+#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__))
18181+#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__))
18182+#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__))
18183+#endif
18184+
18185+#endif // CATCH_PREPROCESSOR_HPP_INCLUDED
18186+
18187+
18188+// GCC 5 and older do not properly handle disabling unused-variable warning
18189+// with a _Pragma. This means that we have to leak the suppression to the
18190+// user code as well :-(
18191+#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ <= 5
18192+#pragma GCC diagnostic ignored "-Wunused-variable"
18193+#endif
18194+
18195+#if defined(CATCH_CONFIG_DISABLE)
18196+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( TestName, TestFunc, Name, Tags, Signature, ... ) \
18197+ INTERNAL_CATCH_DEFINE_SIG_TEST(TestFunc, INTERNAL_CATCH_REMOVE_PARENS(Signature))
18198+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( TestNameClass, TestName, ClassName, Name, Tags, Signature, ... ) \
18199+ namespace{ \
18200+ namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName) { \
18201+ INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, INTERNAL_CATCH_REMOVE_PARENS(Signature));\
18202+ } \
18203+ } \
18204+ INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature))
18205+
18206+ #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
18207+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(Name, Tags, ...) \
18208+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), Name, Tags, typename TestType, __VA_ARGS__ )
18209+ #else
18210+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(Name, Tags, ...) \
18211+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), Name, Tags, typename TestType, __VA_ARGS__ ) )
18212+ #endif
18213+
18214+ #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
18215+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(Name, Tags, Signature, ...) \
18216+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), Name, Tags, Signature, __VA_ARGS__ )
18217+ #else
18218+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(Name, Tags, Signature, ...) \
18219+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), Name, Tags, Signature, __VA_ARGS__ ) )
18220+ #endif
18221+
18222+ #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
18223+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( ClassName, Name, Tags,... ) \
18224+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_CLASS_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ )
18225+ #else
18226+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( ClassName, Name, Tags,... ) \
18227+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_CLASS_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) )
18228+ #endif
18229+
18230+ #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
18231+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION( ClassName, Name, Tags, Signature, ... ) \
18232+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_CLASS_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ )
18233+ #else
18234+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION( ClassName, Name, Tags, Signature, ... ) \
18235+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_CLASS_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) )
18236+ #endif
18237+#endif
18238+
18239+
18240+ ///////////////////////////////////////////////////////////////////////////////
18241+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_2(TestName, TestFunc, Name, Tags, Signature, ... )\
18242+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
18243+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
18244+ CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
18245+ CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
18246+ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
18247+ CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS \
18248+ INTERNAL_CATCH_DECLARE_SIG_TEST(TestFunc, INTERNAL_CATCH_REMOVE_PARENS(Signature));\
18249+ namespace {\
18250+ namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){\
18251+ INTERNAL_CATCH_TYPE_GEN\
18252+ INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\
18253+ INTERNAL_CATCH_NTTP_REG_GEN(TestFunc,INTERNAL_CATCH_REMOVE_PARENS(Signature))\
18254+ template<typename...Types> \
18255+ struct TestName{\
18256+ TestName(){\
18257+ size_t index = 0; \
18258+ constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, __VA_ARGS__)}; /* NOLINT(cppcoreguidelines-avoid-c-arrays,modernize-avoid-c-arrays,hicpp-avoid-c-arrays) */\
18259+ using expander = size_t[]; /* NOLINT(cppcoreguidelines-avoid-c-arrays,modernize-avoid-c-arrays,hicpp-avoid-c-arrays) */\
18260+ (void)expander{(reg_test(Types{}, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++)... };/* NOLINT */ \
18261+ }\
18262+ };\
18263+ static const int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
18264+ TestName<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(__VA_ARGS__)>();\
18265+ return 0;\
18266+ }();\
18267+ }\
18268+ }\
18269+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
18270+ INTERNAL_CATCH_DEFINE_SIG_TEST(TestFunc,INTERNAL_CATCH_REMOVE_PARENS(Signature))
18271+
18272+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
18273+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \
18274+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), Name, Tags, typename TestType, __VA_ARGS__ )
18275+#else
18276+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \
18277+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), Name, Tags, typename TestType, __VA_ARGS__ ) )
18278+#endif
18279+
18280+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
18281+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG(Name, Tags, Signature, ...) \
18282+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), Name, Tags, Signature, __VA_ARGS__ )
18283+#else
18284+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG(Name, Tags, Signature, ...) \
18285+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), Name, Tags, Signature, __VA_ARGS__ ) )
18286+#endif
18287+
18288+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(TestName, TestFuncName, Name, Tags, Signature, TmplTypes, TypesList) \
18289+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
18290+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
18291+ CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
18292+ CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
18293+ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
18294+ CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS \
18295+ template<typename TestType> static void TestFuncName(); \
18296+ namespace {\
18297+ namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName) { \
18298+ INTERNAL_CATCH_TYPE_GEN \
18299+ INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature)) \
18300+ template<typename... Types> \
18301+ struct TestName { \
18302+ void reg_tests() { \
18303+ size_t index = 0; \
18304+ using expander = size_t[]; \
18305+ constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\
18306+ constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\
18307+ constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\
18308+ (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 */\
18309+ } \
18310+ }; \
18311+ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \
18312+ 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; \
18313+ TestInit t; \
18314+ t.reg_tests(); \
18315+ return 0; \
18316+ }(); \
18317+ } \
18318+ } \
18319+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
18320+ template<typename TestType> \
18321+ static void TestFuncName()
18322+
18323+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
18324+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\
18325+ INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), Name, Tags, typename T,__VA_ARGS__)
18326+#else
18327+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\
18328+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), Name, Tags, typename T, __VA_ARGS__ ) )
18329+#endif
18330+
18331+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
18332+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG(Name, Tags, Signature, ...)\
18333+ INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), Name, Tags, Signature, __VA_ARGS__)
18334+#else
18335+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG(Name, Tags, Signature, ...)\
18336+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), Name, Tags, Signature, __VA_ARGS__ ) )
18337+#endif
18338+
18339+ #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_2(TestName, TestFunc, Name, Tags, TmplList)\
18340+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
18341+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
18342+ CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
18343+ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
18344+ CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS \
18345+ template<typename TestType> static void TestFunc(); \
18346+ namespace {\
18347+ namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){\
18348+ INTERNAL_CATCH_TYPE_GEN\
18349+ template<typename... Types> \
18350+ struct TestName { \
18351+ void reg_tests() { \
18352+ size_t index = 0; \
18353+ using expander = size_t[]; \
18354+ (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " INTERNAL_CATCH_STRINGIZE(TmplList) " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */\
18355+ } \
18356+ };\
18357+ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \
18358+ using TestInit = typename convert<TestName, TmplList>::type; \
18359+ TestInit t; \
18360+ t.reg_tests(); \
18361+ return 0; \
18362+ }(); \
18363+ }}\
18364+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
18365+ template<typename TestType> \
18366+ static void TestFunc()
18367+
18368+ #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE(Name, Tags, TmplList) \
18369+ INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), Name, Tags, TmplList )
18370+
18371+
18372+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, Signature, ... ) \
18373+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
18374+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
18375+ CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
18376+ CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
18377+ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
18378+ namespace {\
18379+ namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){ \
18380+ INTERNAL_CATCH_TYPE_GEN\
18381+ INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\
18382+ INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, INTERNAL_CATCH_REMOVE_PARENS(Signature));\
18383+ INTERNAL_CATCH_NTTP_REG_METHOD_GEN(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature))\
18384+ template<typename...Types> \
18385+ struct TestNameClass{\
18386+ TestNameClass(){\
18387+ size_t index = 0; \
18388+ constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, __VA_ARGS__)};\
18389+ using expander = size_t[];\
18390+ (void)expander{(reg_test(Types{}, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++)... };/* NOLINT */ \
18391+ }\
18392+ };\
18393+ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
18394+ TestNameClass<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(__VA_ARGS__)>();\
18395+ return 0;\
18396+ }();\
18397+ }\
18398+ }\
18399+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
18400+ INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature))
18401+
18402+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
18403+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \
18404+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_CLASS_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ )
18405+#else
18406+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \
18407+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_CLASS_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) )
18408+#endif
18409+
18410+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
18411+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... ) \
18412+ INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_CLASS_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ )
18413+#else
18414+ #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... ) \
18415+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_CLASS_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) )
18416+#endif
18417+
18418+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2(TestNameClass, TestName, ClassName, Name, Tags, Signature, TmplTypes, TypesList)\
18419+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
18420+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
18421+ CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
18422+ CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
18423+ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
18424+ template<typename TestType> \
18425+ struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
18426+ void test();\
18427+ };\
18428+ namespace {\
18429+ namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestNameClass) {\
18430+ INTERNAL_CATCH_TYPE_GEN \
18431+ INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\
18432+ template<typename...Types>\
18433+ struct TestNameClass{\
18434+ void reg_tests(){\
18435+ std::size_t index = 0;\
18436+ using expander = std::size_t[];\
18437+ constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\
18438+ constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\
18439+ constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\
18440+ (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 */ \
18441+ }\
18442+ };\
18443+ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
18444+ 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;\
18445+ TestInit t;\
18446+ t.reg_tests();\
18447+ return 0;\
18448+ }(); \
18449+ }\
18450+ }\
18451+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
18452+ template<typename TestType> \
18453+ void TestName<TestType>::test()
18454+
18455+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
18456+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\
18457+ INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), ClassName, Name, Tags, typename T, __VA_ARGS__ )
18458+#else
18459+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\
18460+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), ClassName, Name, Tags, typename T,__VA_ARGS__ ) )
18461+#endif
18462+
18463+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
18464+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... )\
18465+ INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), ClassName, Name, Tags, Signature, __VA_ARGS__ )
18466+#else
18467+ #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... )\
18468+ INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), ClassName, Name, Tags, Signature,__VA_ARGS__ ) )
18469+#endif
18470+
18471+ #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, TmplList) \
18472+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
18473+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
18474+ CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
18475+ CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
18476+ CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS \
18477+ template<typename TestType> \
18478+ struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
18479+ void test();\
18480+ };\
18481+ namespace {\
18482+ namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){ \
18483+ INTERNAL_CATCH_TYPE_GEN\
18484+ template<typename...Types>\
18485+ struct TestNameClass{\
18486+ void reg_tests(){\
18487+ size_t index = 0;\
18488+ using expander = size_t[];\
18489+ (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName##_catch_sr, Catch::NameAndTags{ Name " - " INTERNAL_CATCH_STRINGIZE(TmplList) " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */ \
18490+ }\
18491+ };\
18492+ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
18493+ using TestInit = typename convert<TestNameClass, TmplList>::type;\
18494+ TestInit t;\
18495+ t.reg_tests();\
18496+ return 0;\
18497+ }(); \
18498+ }}\
18499+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
18500+ template<typename TestType> \
18501+ void TestName<TestType>::test()
18502+
18503+#define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD(ClassName, Name, Tags, TmplList) \
18504+ INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), ClassName, Name, Tags, TmplList )
18505+
18506+
18507+#endif // CATCH_TEMPLATE_TEST_REGISTRY_HPP_INCLUDED
18508+
18509+
18510+#if defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE)
18511+
18512+ #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
18513+ #define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
18514+ #define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ )
18515+ #define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
18516+ #define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
18517+ #define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ )
18518+ #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ )
18519+ #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ )
18520+ #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
18521+ #define CATCH_TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE(__VA_ARGS__)
18522+ #define CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ )
18523+ #else
18524+ #define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) )
18525+ #define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ ) )
18526+ #define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
18527+ #define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
18528+ #define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) )
18529+ #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ ) )
18530+ #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
18531+ #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
18532+ #define CATCH_TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE( __VA_ARGS__ ) )
18533+ #define CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
18534+ #endif
18535+
18536+#elif defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE)
18537+
18538+ #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
18539+ #define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__)
18540+ #define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__)
18541+ #define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__)
18542+ #define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ )
18543+ #else
18544+ #define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) )
18545+ #define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__) )
18546+ #define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__ ) )
18547+ #define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ ) )
18548+ #endif
18549+
18550+ // When disabled, these can be shared between proper preprocessor and MSVC preprocessor
18551+ #define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
18552+ #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
18553+ #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
18554+ #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
18555+ #define CATCH_TEMPLATE_LIST_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE(__VA_ARGS__)
18556+ #define CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
18557+
18558+#elif !defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE)
18559+
18560+ #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
18561+ #define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
18562+ #define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ )
18563+ #define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
18564+ #define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
18565+ #define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ )
18566+ #define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ )
18567+ #define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ )
18568+ #define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
18569+ #define TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE(__VA_ARGS__)
18570+ #define TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ )
18571+ #else
18572+ #define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) )
18573+ #define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ ) )
18574+ #define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
18575+ #define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
18576+ #define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) )
18577+ #define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ ) )
18578+ #define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
18579+ #define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
18580+ #define TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE( __VA_ARGS__ ) )
18581+ #define TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
18582+ #endif
18583+
18584+#elif !defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE)
18585+
18586+ #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
18587+ #define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__)
18588+ #define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__)
18589+ #define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__)
18590+ #define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ )
18591+ #else
18592+ #define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) )
18593+ #define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__) )
18594+ #define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__ ) )
18595+ #define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ ) )
18596+ #endif
18597+
18598+ // When disabled, these can be shared between proper preprocessor and MSVC preprocessor
18599+ #define TEMPLATE_PRODUCT_TEST_CASE( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )
18600+ #define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )
18601+ #define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
18602+ #define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
18603+ #define TEMPLATE_LIST_TEST_CASE( ... ) TEMPLATE_TEST_CASE(__VA_ARGS__)
18604+ #define TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
18605+
18606+#endif // end of user facing macro declarations
18607+
18608+
18609+#endif // CATCH_TEMPLATE_TEST_MACROS_HPP_INCLUDED
18610+
18611+
18612+#ifndef CATCH_TEST_CASE_INFO_HPP_INCLUDED
18613+#define CATCH_TEST_CASE_INFO_HPP_INCLUDED
18614+
18615+
18616+
18617+#include <cstdint>
18618+#include <string>
18619+#include <vector>
18620+
18621+#ifdef __clang__
18622+#pragma clang diagnostic push
18623+#pragma clang diagnostic ignored "-Wpadded"
18624+#endif
18625+
18626+namespace Catch {
18627+
18628+ /**
18629+ * A **view** of a tag string that provides case insensitive comparisons
18630+ *
18631+ * Note that in Catch2 internals, the square brackets around tags are
18632+ * not a part of tag's representation, so e.g. "[cool-tag]" is represented
18633+ * as "cool-tag" internally.
18634+ */
18635+ struct Tag {
18636+ constexpr Tag(StringRef original_):
18637+ original(original_)
18638+ {}
18639+ StringRef original;
18640+
18641+ friend bool operator< ( Tag const& lhs, Tag const& rhs );
18642+ friend bool operator==( Tag const& lhs, Tag const& rhs );
18643+ };
18644+
18645+ class ITestInvoker;
18646+ struct NameAndTags;
18647+
18648+ enum class TestCaseProperties : uint8_t {
18649+ None = 0,
18650+ IsHidden = 1 << 1,
18651+ ShouldFail = 1 << 2,
18652+ MayFail = 1 << 3,
18653+ Throws = 1 << 4,
18654+ NonPortable = 1 << 5,
18655+ Benchmark = 1 << 6
18656+ };
18657+
18658+ /**
18659+ * Various metadata about the test case.
18660+ *
18661+ * A test case is uniquely identified by its (class)name and tags
18662+ * combination, with source location being ignored, and other properties
18663+ * being determined from tags.
18664+ *
18665+ * Tags are kept sorted.
18666+ */
18667+ struct TestCaseInfo : Detail::NonCopyable {
18668+
18669+ TestCaseInfo(StringRef _className,
18670+ NameAndTags const& _nameAndTags,
18671+ SourceLineInfo const& _lineInfo);
18672+
18673+ bool isHidden() const;
18674+ bool throws() const;
18675+ bool okToFail() const;
18676+ bool expectedToFail() const;
18677+
18678+ // Adds the tag(s) with test's filename (for the -# flag)
18679+ void addFilenameTag();
18680+
18681+ //! Orders by name, classname and tags
18682+ friend bool operator<( TestCaseInfo const& lhs,
18683+ TestCaseInfo const& rhs );
18684+
18685+
18686+ std::string tagsAsString() const;
18687+
18688+ std::string name;
18689+ StringRef className;
18690+ private:
18691+ std::string backingTags;
18692+ // Internally we copy tags to the backing storage and then add
18693+ // refs to this storage to the tags vector.
18694+ void internalAppendTag(StringRef tagString);
18695+ public:
18696+ std::vector<Tag> tags;
18697+ SourceLineInfo lineInfo;
18698+ TestCaseProperties properties = TestCaseProperties::None;
18699+ };
18700+
18701+ /**
18702+ * Wrapper over the test case information and the test case invoker
18703+ *
18704+ * Does not own either, and is specifically made to be cheap
18705+ * to copy around.
18706+ */
18707+ class TestCaseHandle {
18708+ TestCaseInfo* m_info;
18709+ ITestInvoker* m_invoker;
18710+ public:
18711+ TestCaseHandle(TestCaseInfo* info, ITestInvoker* invoker) :
18712+ m_info(info), m_invoker(invoker) {}
18713+
18714+ void invoke() const {
18715+ m_invoker->invoke();
18716+ }
18717+
18718+ TestCaseInfo const& getTestCaseInfo() const;
18719+ };
18720+
18721+ Detail::unique_ptr<TestCaseInfo>
18722+ makeTestCaseInfo( StringRef className,
18723+ NameAndTags const& nameAndTags,
18724+ SourceLineInfo const& lineInfo );
18725+}
18726+
18727+#ifdef __clang__
18728+#pragma clang diagnostic pop
18729+#endif
18730+
18731+#endif // CATCH_TEST_CASE_INFO_HPP_INCLUDED
18732+
18733+
18734+#ifndef CATCH_TRANSLATE_EXCEPTION_HPP_INCLUDED
18735+#define CATCH_TRANSLATE_EXCEPTION_HPP_INCLUDED
18736+
18737+
18738+
18739+#ifndef CATCH_INTERFACES_EXCEPTION_HPP_INCLUDED
18740+#define CATCH_INTERFACES_EXCEPTION_HPP_INCLUDED
18741+
18742+
18743+#include <string>
18744+#include <vector>
18745+
18746+namespace Catch {
18747+ using exceptionTranslateFunction = std::string(*)();
18748+
18749+ class IExceptionTranslator;
18750+ using ExceptionTranslators = std::vector<Detail::unique_ptr<IExceptionTranslator const>>;
18751+
18752+ class IExceptionTranslator {
18753+ public:
18754+ virtual ~IExceptionTranslator(); // = default
18755+ virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0;
18756+ };
18757+
18758+ class IExceptionTranslatorRegistry {
18759+ public:
18760+ virtual ~IExceptionTranslatorRegistry(); // = default
18761+ virtual std::string translateActiveException() const = 0;
18762+ };
18763+
18764+} // namespace Catch
18765+
18766+#endif // CATCH_INTERFACES_EXCEPTION_HPP_INCLUDED
18767+
18768+#include <exception>
18769+
18770+namespace Catch {
18771+ namespace Detail {
18772+ void registerTranslatorImpl(
18773+ Detail::unique_ptr<IExceptionTranslator>&& translator );
18774+ }
18775+
18776+ class ExceptionTranslatorRegistrar {
18777+ template<typename T>
18778+ class ExceptionTranslator : public IExceptionTranslator {
18779+ public:
18780+
18781+ ExceptionTranslator( std::string(*translateFunction)( T const& ) )
18782+ : m_translateFunction( translateFunction )
18783+ {}
18784+
18785+ std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const override {
18786+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
18787+ try {
18788+ if( it == itEnd )
18789+ std::rethrow_exception(std::current_exception());
18790+ else
18791+ return (*it)->translate( it+1, itEnd );
18792+ }
18793+ catch( T const& ex ) {
18794+ return m_translateFunction( ex );
18795+ }
18796+#else
18797+ return "You should never get here!";
18798+#endif
18799+ }
18800+
18801+ protected:
18802+ std::string(*m_translateFunction)( T const& );
18803+ };
18804+
18805+ public:
18806+ template<typename T>
18807+ ExceptionTranslatorRegistrar( std::string(*translateFunction)( T const& ) ) {
18808+ Detail::registerTranslatorImpl(
18809+ Detail::make_unique<ExceptionTranslator<T>>(
18810+ translateFunction ) );
18811+ }
18812+ };
18813+
18814+} // namespace Catch
18815+
18816+///////////////////////////////////////////////////////////////////////////////
18817+#define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \
18818+ static std::string translatorName( signature ); \
18819+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
18820+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
18821+ namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); } \
18822+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
18823+ static std::string translatorName( signature )
18824+
18825+#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )
18826+
18827+#if defined(CATCH_CONFIG_DISABLE)
18828+ #define INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( translatorName, signature) \
18829+ static std::string translatorName( signature )
18830+#endif
18831+
18832+
18833+// This macro is always prefixed
18834+#if !defined(CATCH_CONFIG_DISABLE)
18835+#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature )
18836+#else
18837+#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )
18838+#endif
18839+
18840+
18841+#endif // CATCH_TRANSLATE_EXCEPTION_HPP_INCLUDED
18842+
18843+
18844+#ifndef CATCH_VERSION_HPP_INCLUDED
18845+#define CATCH_VERSION_HPP_INCLUDED
18846+
18847+#include <iosfwd>
18848+
18849+namespace Catch {
18850+
18851+ // Versioning information
18852+ struct Version {
18853+ Version( Version const& ) = delete;
18854+ Version& operator=( Version const& ) = delete;
18855+ Version( unsigned int _majorVersion,
18856+ unsigned int _minorVersion,
18857+ unsigned int _patchNumber,
18858+ char const * const _branchName,
18859+ unsigned int _buildNumber );
18860+
18861+ unsigned int const majorVersion;
18862+ unsigned int const minorVersion;
18863+ unsigned int const patchNumber;
18864+
18865+ // buildNumber is only used if branchName is not null
18866+ char const * const branchName;
18867+ unsigned int const buildNumber;
18868+
18869+ friend std::ostream& operator << ( std::ostream& os, Version const& version );
18870+ };
18871+
18872+ Version const& libraryVersion();
18873+}
18874+
18875+#endif // CATCH_VERSION_HPP_INCLUDED
18876+
18877+
18878+#ifndef CATCH_VERSION_MACROS_HPP_INCLUDED
18879+#define CATCH_VERSION_MACROS_HPP_INCLUDED
18880+
18881+#define CATCH_VERSION_MAJOR 3
18882+#define CATCH_VERSION_MINOR 5
18883+#define CATCH_VERSION_PATCH 4
18884+
18885+#endif // CATCH_VERSION_MACROS_HPP_INCLUDED
18886+
18887+
18888+/** \file
18889+ * This is a convenience header for Catch2's Generator support. It includes
18890+ * **all** of Catch2 headers related to generators.
18891+ *
18892+ * Generally the Catch2 users should use specific includes they need,
18893+ * but this header can be used instead for ease-of-experimentation, or
18894+ * just plain convenience, at the cost of (significantly) increased
18895+ * compilation times.
18896+ *
18897+ * When a new header is added to either the `generators` folder,
18898+ * or to the corresponding internal subfolder, it should be added here.
18899+ */
18900+
18901+#ifndef CATCH_GENERATORS_ALL_HPP_INCLUDED
18902+#define CATCH_GENERATORS_ALL_HPP_INCLUDED
18903+
18904+
18905+
18906+#ifndef CATCH_GENERATOR_EXCEPTION_HPP_INCLUDED
18907+#define CATCH_GENERATOR_EXCEPTION_HPP_INCLUDED
18908+
18909+#include <exception>
18910+
18911+namespace Catch {
18912+
18913+ // Exception type to be thrown when a Generator runs into an error,
18914+ // e.g. it cannot initialize the first return value based on
18915+ // runtime information
18916+ class GeneratorException : public std::exception {
18917+ const char* const m_msg = "";
18918+
18919+ public:
18920+ GeneratorException(const char* msg):
18921+ m_msg(msg)
18922+ {}
18923+
18924+ const char* what() const noexcept override final;
18925+ };
18926+
18927+} // end namespace Catch
18928+
18929+#endif // CATCH_GENERATOR_EXCEPTION_HPP_INCLUDED
18930+
18931+
18932+#ifndef CATCH_GENERATORS_HPP_INCLUDED
18933+#define CATCH_GENERATORS_HPP_INCLUDED
18934+
18935+
18936+
18937+#ifndef CATCH_INTERFACES_GENERATORTRACKER_HPP_INCLUDED
18938+#define CATCH_INTERFACES_GENERATORTRACKER_HPP_INCLUDED
18939+
18940+
18941+#include <string>
18942+
18943+namespace Catch {
18944+
18945+ namespace Generators {
18946+ class GeneratorUntypedBase {
18947+ // Caches result from `toStringImpl`, assume that when it is an
18948+ // empty string, the cache is invalidated.
18949+ mutable std::string m_stringReprCache;
18950+
18951+ // Counts based on `next` returning true
18952+ std::size_t m_currentElementIndex = 0;
18953+
18954+ /**
18955+ * Attempts to move the generator to the next element
18956+ *
18957+ * Returns true iff the move succeeded (and a valid element
18958+ * can be retrieved).
18959+ */
18960+ virtual bool next() = 0;
18961+
18962+ //! Customization point for `currentElementAsString`
18963+ virtual std::string stringifyImpl() const = 0;
18964+
18965+ public:
18966+ GeneratorUntypedBase() = default;
18967+ // Generation of copy ops is deprecated (and Clang will complain)
18968+ // if there is a user destructor defined
18969+ GeneratorUntypedBase(GeneratorUntypedBase const&) = default;
18970+ GeneratorUntypedBase& operator=(GeneratorUntypedBase const&) = default;
18971+
18972+ virtual ~GeneratorUntypedBase(); // = default;
18973+
18974+ /**
18975+ * Attempts to move the generator to the next element
18976+ *
18977+ * Serves as a non-virtual interface to `next`, so that the
18978+ * top level interface can provide sanity checking and shared
18979+ * features.
18980+ *
18981+ * As with `next`, returns true iff the move succeeded and
18982+ * the generator has new valid element to provide.
18983+ */
18984+ bool countedNext();
18985+
18986+ std::size_t currentElementIndex() const { return m_currentElementIndex; }
18987+
18988+ /**
18989+ * Returns generator's current element as user-friendly string.
18990+ *
18991+ * By default returns string equivalent to calling
18992+ * `Catch::Detail::stringify` on the current element, but generators
18993+ * can customize their implementation as needed.
18994+ *
18995+ * Not thread-safe due to internal caching.
18996+ *
18997+ * The returned ref is valid only until the generator instance
18998+ * is destructed, or it moves onto the next element, whichever
18999+ * comes first.
19000+ */
19001+ StringRef currentElementAsString() const;
19002+ };
19003+ using GeneratorBasePtr = Catch::Detail::unique_ptr<GeneratorUntypedBase>;
19004+
19005+ } // namespace Generators
19006+
19007+ class IGeneratorTracker {
19008+ public:
19009+ virtual ~IGeneratorTracker(); // = default;
19010+ virtual auto hasGenerator() const -> bool = 0;
19011+ virtual auto getGenerator() const -> Generators::GeneratorBasePtr const& = 0;
19012+ virtual void setGenerator( Generators::GeneratorBasePtr&& generator ) = 0;
19013+ };
19014+
19015+} // namespace Catch
19016+
19017+#endif // CATCH_INTERFACES_GENERATORTRACKER_HPP_INCLUDED
19018+
19019+#include <vector>
19020+#include <tuple>
19021+
19022+namespace Catch {
19023+
19024+namespace Generators {
19025+
19026+namespace Detail {
19027+
19028+ //! Throws GeneratorException with the provided message
19029+ [[noreturn]]
19030+ void throw_generator_exception(char const * msg);
19031+
19032+} // end namespace detail
19033+
19034+ template<typename T>
19035+ class IGenerator : public GeneratorUntypedBase {
19036+ std::string stringifyImpl() const override {
19037+ return ::Catch::Detail::stringify( get() );
19038+ }
19039+
19040+ public:
19041+ // Returns the current element of the generator
19042+ //
19043+ // \Precondition The generator is either freshly constructed,
19044+ // or the last call to `next()` returned true
19045+ virtual T const& get() const = 0;
19046+ using type = T;
19047+ };
19048+
19049+ template <typename T>
19050+ using GeneratorPtr = Catch::Detail::unique_ptr<IGenerator<T>>;
19051+
19052+ template <typename T>
19053+ class GeneratorWrapper final {
19054+ GeneratorPtr<T> m_generator;
19055+ public:
19056+ //! Takes ownership of the passed pointer.
19057+ GeneratorWrapper(IGenerator<T>* generator):
19058+ m_generator(generator) {}
19059+ GeneratorWrapper(GeneratorPtr<T> generator):
19060+ m_generator(CATCH_MOVE(generator)) {}
19061+
19062+ T const& get() const {
19063+ return m_generator->get();
19064+ }
19065+ bool next() {
19066+ return m_generator->countedNext();
19067+ }
19068+ };
19069+
19070+
19071+ template<typename T>
19072+ class SingleValueGenerator final : public IGenerator<T> {
19073+ T m_value;
19074+ public:
19075+ SingleValueGenerator(T const& value) :
19076+ m_value(value)
19077+ {}
19078+ SingleValueGenerator(T&& value):
19079+ m_value(CATCH_MOVE(value))
19080+ {}
19081+
19082+ T const& get() const override {
19083+ return m_value;
19084+ }
19085+ bool next() override {
19086+ return false;
19087+ }
19088+ };
19089+
19090+ template<typename T>
19091+ class FixedValuesGenerator final : public IGenerator<T> {
19092+ static_assert(!std::is_same<T, bool>::value,
19093+ "FixedValuesGenerator does not support bools because of std::vector<bool>"
19094+ "specialization, use SingleValue Generator instead.");
19095+ std::vector<T> m_values;
19096+ size_t m_idx = 0;
19097+ public:
19098+ FixedValuesGenerator( std::initializer_list<T> values ) : m_values( values ) {}
19099+
19100+ T const& get() const override {
19101+ return m_values[m_idx];
19102+ }
19103+ bool next() override {
19104+ ++m_idx;
19105+ return m_idx < m_values.size();
19106+ }
19107+ };
19108+
19109+ template <typename T, typename DecayedT = std::decay_t<T>>
19110+ GeneratorWrapper<DecayedT> value( T&& value ) {
19111+ return GeneratorWrapper<DecayedT>(
19112+ Catch::Detail::make_unique<SingleValueGenerator<DecayedT>>(
19113+ CATCH_FORWARD( value ) ) );
19114+ }
19115+ template <typename T>
19116+ GeneratorWrapper<T> values(std::initializer_list<T> values) {
19117+ return GeneratorWrapper<T>(Catch::Detail::make_unique<FixedValuesGenerator<T>>(values));
19118+ }
19119+
19120+ template<typename T>
19121+ class Generators : public IGenerator<T> {
19122+ std::vector<GeneratorWrapper<T>> m_generators;
19123+ size_t m_current = 0;
19124+
19125+ void add_generator( GeneratorWrapper<T>&& generator ) {
19126+ m_generators.emplace_back( CATCH_MOVE( generator ) );
19127+ }
19128+ void add_generator( T const& val ) {
19129+ m_generators.emplace_back( value( val ) );
19130+ }
19131+ void add_generator( T&& val ) {
19132+ m_generators.emplace_back( value( CATCH_MOVE( val ) ) );
19133+ }
19134+ template <typename U>
19135+ std::enable_if_t<!std::is_same<std::decay_t<U>, T>::value>
19136+ add_generator( U&& val ) {
19137+ add_generator( T( CATCH_FORWARD( val ) ) );
19138+ }
19139+
19140+ template <typename U> void add_generators( U&& valueOrGenerator ) {
19141+ add_generator( CATCH_FORWARD( valueOrGenerator ) );
19142+ }
19143+
19144+ template <typename U, typename... Gs>
19145+ void add_generators( U&& valueOrGenerator, Gs&&... moreGenerators ) {
19146+ add_generator( CATCH_FORWARD( valueOrGenerator ) );
19147+ add_generators( CATCH_FORWARD( moreGenerators )... );
19148+ }
19149+
19150+ public:
19151+ template <typename... Gs>
19152+ Generators(Gs &&... moreGenerators) {
19153+ m_generators.reserve(sizeof...(Gs));
19154+ add_generators(CATCH_FORWARD(moreGenerators)...);
19155+ }
19156+
19157+ T const& get() const override {
19158+ return m_generators[m_current].get();
19159+ }
19160+
19161+ bool next() override {
19162+ if (m_current >= m_generators.size()) {
19163+ return false;
19164+ }
19165+ const bool current_status = m_generators[m_current].next();
19166+ if (!current_status) {
19167+ ++m_current;
19168+ }
19169+ return m_current < m_generators.size();
19170+ }
19171+ };
19172+
19173+
19174+ template <typename... Ts>
19175+ GeneratorWrapper<std::tuple<std::decay_t<Ts>...>>
19176+ table( std::initializer_list<std::tuple<std::decay_t<Ts>...>> tuples ) {
19177+ return values<std::tuple<Ts...>>( tuples );
19178+ }
19179+
19180+ // Tag type to signal that a generator sequence should convert arguments to a specific type
19181+ template <typename T>
19182+ struct as {};
19183+
19184+ template<typename T, typename... Gs>
19185+ auto makeGenerators( GeneratorWrapper<T>&& generator, Gs &&... moreGenerators ) -> Generators<T> {
19186+ return Generators<T>(CATCH_MOVE(generator), CATCH_FORWARD(moreGenerators)...);
19187+ }
19188+ template<typename T>
19189+ auto makeGenerators( GeneratorWrapper<T>&& generator ) -> Generators<T> {
19190+ return Generators<T>(CATCH_MOVE(generator));
19191+ }
19192+ template<typename T, typename... Gs>
19193+ auto makeGenerators( T&& val, Gs &&... moreGenerators ) -> Generators<std::decay_t<T>> {
19194+ return makeGenerators( value( CATCH_FORWARD( val ) ), CATCH_FORWARD( moreGenerators )... );
19195+ }
19196+ template<typename T, typename U, typename... Gs>
19197+ auto makeGenerators( as<T>, U&& val, Gs &&... moreGenerators ) -> Generators<T> {
19198+ return makeGenerators( value( T( CATCH_FORWARD( val ) ) ), CATCH_FORWARD( moreGenerators )... );
19199+ }
19200+
19201+ IGeneratorTracker* acquireGeneratorTracker( StringRef generatorName,
19202+ SourceLineInfo const& lineInfo );
19203+ IGeneratorTracker* createGeneratorTracker( StringRef generatorName,
19204+ SourceLineInfo lineInfo,
19205+ GeneratorBasePtr&& generator );
19206+
19207+ template<typename L>
19208+ auto generate( StringRef generatorName, SourceLineInfo const& lineInfo, L const& generatorExpression ) -> typename decltype(generatorExpression())::type {
19209+ using UnderlyingType = typename decltype(generatorExpression())::type;
19210+
19211+ IGeneratorTracker* tracker = acquireGeneratorTracker( generatorName, lineInfo );
19212+ // Creation of tracker is delayed after generator creation, so
19213+ // that constructing generator can fail without breaking everything.
19214+ if (!tracker) {
19215+ tracker = createGeneratorTracker(
19216+ generatorName,
19217+ lineInfo,
19218+ Catch::Detail::make_unique<Generators<UnderlyingType>>(
19219+ generatorExpression() ) );
19220+ }
19221+
19222+ auto const& generator = static_cast<IGenerator<UnderlyingType> const&>( *tracker->getGenerator() );
19223+ return generator.get();
19224+ }
19225+
19226+} // namespace Generators
19227+} // namespace Catch
19228+
19229+#define CATCH_INTERNAL_GENERATOR_STRINGIZE_IMPL( ... ) #__VA_ARGS__##_catch_sr
19230+#define CATCH_INTERNAL_GENERATOR_STRINGIZE(...) CATCH_INTERNAL_GENERATOR_STRINGIZE_IMPL(__VA_ARGS__)
19231+
19232+#define GENERATE( ... ) \
19233+ Catch::Generators::generate( CATCH_INTERNAL_GENERATOR_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
19234+ CATCH_INTERNAL_LINEINFO, \
19235+ [ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
19236+#define GENERATE_COPY( ... ) \
19237+ Catch::Generators::generate( CATCH_INTERNAL_GENERATOR_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
19238+ CATCH_INTERNAL_LINEINFO, \
19239+ [=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
19240+#define GENERATE_REF( ... ) \
19241+ Catch::Generators::generate( CATCH_INTERNAL_GENERATOR_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
19242+ CATCH_INTERNAL_LINEINFO, \
19243+ [&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
19244+
19245+#endif // CATCH_GENERATORS_HPP_INCLUDED
19246+
19247+
19248+#ifndef CATCH_GENERATORS_ADAPTERS_HPP_INCLUDED
19249+#define CATCH_GENERATORS_ADAPTERS_HPP_INCLUDED
19250+
19251+
19252+#include <cassert>
19253+
19254+namespace Catch {
19255+namespace Generators {
19256+
19257+ template <typename T>
19258+ class TakeGenerator final : public IGenerator<T> {
19259+ GeneratorWrapper<T> m_generator;
19260+ size_t m_returned = 0;
19261+ size_t m_target;
19262+ public:
19263+ TakeGenerator(size_t target, GeneratorWrapper<T>&& generator):
19264+ m_generator(CATCH_MOVE(generator)),
19265+ m_target(target)
19266+ {
19267+ assert(target != 0 && "Empty generators are not allowed");
19268+ }
19269+ T const& get() const override {
19270+ return m_generator.get();
19271+ }
19272+ bool next() override {
19273+ ++m_returned;
19274+ if (m_returned >= m_target) {
19275+ return false;
19276+ }
19277+
19278+ const auto success = m_generator.next();
19279+ // If the underlying generator does not contain enough values
19280+ // then we cut short as well
19281+ if (!success) {
19282+ m_returned = m_target;
19283+ }
19284+ return success;
19285+ }
19286+ };
19287+
19288+ template <typename T>
19289+ GeneratorWrapper<T> take(size_t target, GeneratorWrapper<T>&& generator) {
19290+ return GeneratorWrapper<T>(Catch::Detail::make_unique<TakeGenerator<T>>(target, CATCH_MOVE(generator)));
19291+ }
19292+
19293+
19294+ template <typename T, typename Predicate>
19295+ class FilterGenerator final : public IGenerator<T> {
19296+ GeneratorWrapper<T> m_generator;
19297+ Predicate m_predicate;
19298+ public:
19299+ template <typename P = Predicate>
19300+ FilterGenerator(P&& pred, GeneratorWrapper<T>&& generator):
19301+ m_generator(CATCH_MOVE(generator)),
19302+ m_predicate(CATCH_FORWARD(pred))
19303+ {
19304+ if (!m_predicate(m_generator.get())) {
19305+ // It might happen that there are no values that pass the
19306+ // filter. In that case we throw an exception.
19307+ auto has_initial_value = next();
19308+ if (!has_initial_value) {
19309+ Detail::throw_generator_exception("No valid value found in filtered generator");
19310+ }
19311+ }
19312+ }
19313+
19314+ T const& get() const override {
19315+ return m_generator.get();
19316+ }
19317+
19318+ bool next() override {
19319+ bool success = m_generator.next();
19320+ if (!success) {
19321+ return false;
19322+ }
19323+ while (!m_predicate(m_generator.get()) && (success = m_generator.next()) == true);
19324+ return success;
19325+ }
19326+ };
19327+
19328+
19329+ template <typename T, typename Predicate>
19330+ GeneratorWrapper<T> filter(Predicate&& pred, GeneratorWrapper<T>&& generator) {
19331+ return GeneratorWrapper<T>(Catch::Detail::make_unique<FilterGenerator<T, Predicate>>(CATCH_FORWARD(pred), CATCH_MOVE(generator)));
19332+ }
19333+
19334+ template <typename T>
19335+ class RepeatGenerator final : public IGenerator<T> {
19336+ static_assert(!std::is_same<T, bool>::value,
19337+ "RepeatGenerator currently does not support bools"
19338+ "because of std::vector<bool> specialization");
19339+ GeneratorWrapper<T> m_generator;
19340+ mutable std::vector<T> m_returned;
19341+ size_t m_target_repeats;
19342+ size_t m_current_repeat = 0;
19343+ size_t m_repeat_index = 0;
19344+ public:
19345+ RepeatGenerator(size_t repeats, GeneratorWrapper<T>&& generator):
19346+ m_generator(CATCH_MOVE(generator)),
19347+ m_target_repeats(repeats)
19348+ {
19349+ assert(m_target_repeats > 0 && "Repeat generator must repeat at least once");
19350+ }
19351+
19352+ T const& get() const override {
19353+ if (m_current_repeat == 0) {
19354+ m_returned.push_back(m_generator.get());
19355+ return m_returned.back();
19356+ }
19357+ return m_returned[m_repeat_index];
19358+ }
19359+
19360+ bool next() override {
19361+ // There are 2 basic cases:
19362+ // 1) We are still reading the generator
19363+ // 2) We are reading our own cache
19364+
19365+ // In the first case, we need to poke the underlying generator.
19366+ // If it happily moves, we are left in that state, otherwise it is time to start reading from our cache
19367+ if (m_current_repeat == 0) {
19368+ const auto success = m_generator.next();
19369+ if (!success) {
19370+ ++m_current_repeat;
19371+ }
19372+ return m_current_repeat < m_target_repeats;
19373+ }
19374+
19375+ // In the second case, we need to move indices forward and check that we haven't run up against the end
19376+ ++m_repeat_index;
19377+ if (m_repeat_index == m_returned.size()) {
19378+ m_repeat_index = 0;
19379+ ++m_current_repeat;
19380+ }
19381+ return m_current_repeat < m_target_repeats;
19382+ }
19383+ };
19384+
19385+ template <typename T>
19386+ GeneratorWrapper<T> repeat(size_t repeats, GeneratorWrapper<T>&& generator) {
19387+ return GeneratorWrapper<T>(Catch::Detail::make_unique<RepeatGenerator<T>>(repeats, CATCH_MOVE(generator)));
19388+ }
19389+
19390+ template <typename T, typename U, typename Func>
19391+ class MapGenerator final : public IGenerator<T> {
19392+ // TBD: provide static assert for mapping function, for friendly error message
19393+ GeneratorWrapper<U> m_generator;
19394+ Func m_function;
19395+ // To avoid returning dangling reference, we have to save the values
19396+ T m_cache;
19397+ public:
19398+ template <typename F2 = Func>
19399+ MapGenerator(F2&& function, GeneratorWrapper<U>&& generator) :
19400+ m_generator(CATCH_MOVE(generator)),
19401+ m_function(CATCH_FORWARD(function)),
19402+ m_cache(m_function(m_generator.get()))
19403+ {}
19404+
19405+ T const& get() const override {
19406+ return m_cache;
19407+ }
19408+ bool next() override {
19409+ const auto success = m_generator.next();
19410+ if (success) {
19411+ m_cache = m_function(m_generator.get());
19412+ }
19413+ return success;
19414+ }
19415+ };
19416+
19417+ template <typename Func, typename U, typename T = FunctionReturnType<Func, U>>
19418+ GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) {
19419+ return GeneratorWrapper<T>(
19420+ Catch::Detail::make_unique<MapGenerator<T, U, Func>>(CATCH_FORWARD(function), CATCH_MOVE(generator))
19421+ );
19422+ }
19423+
19424+ template <typename T, typename U, typename Func>
19425+ GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) {
19426+ return GeneratorWrapper<T>(
19427+ Catch::Detail::make_unique<MapGenerator<T, U, Func>>(CATCH_FORWARD(function), CATCH_MOVE(generator))
19428+ );
19429+ }
19430+
19431+ template <typename T>
19432+ class ChunkGenerator final : public IGenerator<std::vector<T>> {
19433+ std::vector<T> m_chunk;
19434+ size_t m_chunk_size;
19435+ GeneratorWrapper<T> m_generator;
19436+ bool m_used_up = false;
19437+ public:
19438+ ChunkGenerator(size_t size, GeneratorWrapper<T> generator) :
19439+ m_chunk_size(size), m_generator(CATCH_MOVE(generator))
19440+ {
19441+ m_chunk.reserve(m_chunk_size);
19442+ if (m_chunk_size != 0) {
19443+ m_chunk.push_back(m_generator.get());
19444+ for (size_t i = 1; i < m_chunk_size; ++i) {
19445+ if (!m_generator.next()) {
19446+ Detail::throw_generator_exception("Not enough values to initialize the first chunk");
19447+ }
19448+ m_chunk.push_back(m_generator.get());
19449+ }
19450+ }
19451+ }
19452+ std::vector<T> const& get() const override {
19453+ return m_chunk;
19454+ }
19455+ bool next() override {
19456+ m_chunk.clear();
19457+ for (size_t idx = 0; idx < m_chunk_size; ++idx) {
19458+ if (!m_generator.next()) {
19459+ return false;
19460+ }
19461+ m_chunk.push_back(m_generator.get());
19462+ }
19463+ return true;
19464+ }
19465+ };
19466+
19467+ template <typename T>
19468+ GeneratorWrapper<std::vector<T>> chunk(size_t size, GeneratorWrapper<T>&& generator) {
19469+ return GeneratorWrapper<std::vector<T>>(
19470+ Catch::Detail::make_unique<ChunkGenerator<T>>(size, CATCH_MOVE(generator))
19471+ );
19472+ }
19473+
19474+} // namespace Generators
19475+} // namespace Catch
19476+
19477+
19478+#endif // CATCH_GENERATORS_ADAPTERS_HPP_INCLUDED
19479+
19480+
19481+#ifndef CATCH_GENERATORS_RANDOM_HPP_INCLUDED
19482+#define CATCH_GENERATORS_RANDOM_HPP_INCLUDED
19483+
19484+
19485+
19486+#ifndef CATCH_RANDOM_NUMBER_GENERATOR_HPP_INCLUDED
19487+#define CATCH_RANDOM_NUMBER_GENERATOR_HPP_INCLUDED
19488+
19489+#include <cstdint>
19490+
19491+namespace Catch {
19492+
19493+ // This is a simple implementation of C++11 Uniform Random Number
19494+ // Generator. It does not provide all operators, because Catch2
19495+ // does not use it, but it should behave as expected inside stdlib's
19496+ // distributions.
19497+ // The implementation is based on the PCG family (http://pcg-random.org)
19498+ class SimplePcg32 {
19499+ using state_type = std::uint64_t;
19500+ public:
19501+ using result_type = std::uint32_t;
19502+ static constexpr result_type (min)() {
19503+ return 0;
19504+ }
19505+ static constexpr result_type (max)() {
19506+ return static_cast<result_type>(-1);
19507+ }
19508+
19509+ // Provide some default initial state for the default constructor
19510+ SimplePcg32():SimplePcg32(0xed743cc4U) {}
19511+
19512+ explicit SimplePcg32(result_type seed_);
19513+
19514+ void seed(result_type seed_);
19515+ void discard(uint64_t skip);
19516+
19517+ result_type operator()();
19518+
19519+ private:
19520+ friend bool operator==(SimplePcg32 const& lhs, SimplePcg32 const& rhs);
19521+ friend bool operator!=(SimplePcg32 const& lhs, SimplePcg32 const& rhs);
19522+
19523+ // In theory we also need operator<< and operator>>
19524+ // In practice we do not use them, so we will skip them for now
19525+
19526+
19527+ std::uint64_t m_state;
19528+ // This part of the state determines which "stream" of the numbers
19529+ // is chosen -- we take it as a constant for Catch2, so we only
19530+ // need to deal with seeding the main state.
19531+ // Picked by reading 8 bytes from `/dev/random` :-)
19532+ static const std::uint64_t s_inc = (0x13ed0cc53f939476ULL << 1ULL) | 1ULL;
19533+ };
19534+
19535+} // end namespace Catch
19536+
19537+#endif // CATCH_RANDOM_NUMBER_GENERATOR_HPP_INCLUDED
19538+
19539+
19540+
19541+#ifndef CATCH_UNIFORM_INTEGER_DISTRIBUTION_HPP_INCLUDED
19542+#define CATCH_UNIFORM_INTEGER_DISTRIBUTION_HPP_INCLUDED
19543+
19544+
19545+
19546+
19547+#ifndef CATCH_RANDOM_INTEGER_HELPERS_HPP_INCLUDED
19548+#define CATCH_RANDOM_INTEGER_HELPERS_HPP_INCLUDED
19549+
19550+#include <climits>
19551+#include <cstddef>
19552+#include <cstdint>
19553+#include <type_traits>
19554+
19555+// Note: We use the usual enable-disable-autodetect dance here even though
19556+// we do not support these in CMake configuration options (yet?).
19557+// It is highly unlikely that we will need to make these actually
19558+// user-configurable, but this will make it simpler if weend up needing
19559+// it, and it provides an escape hatch to the users who need it.
19560+#if defined( __SIZEOF_INT128__ )
19561+# define CATCH_CONFIG_INTERNAL_UINT128
19562+#elif defined( _MSC_VER ) && ( defined( _WIN64 ) || defined( _M_ARM64 ) )
19563+# define CATCH_CONFIG_INTERNAL_MSVC_UMUL128
19564+#endif
19565+
19566+#if defined( CATCH_CONFIG_INTERNAL_UINT128 ) && \
19567+ !defined( CATCH_CONFIG_NO_UINT128 ) && \
19568+ !defined( CATCH_CONFIG_UINT128 )
19569+#define CATCH_CONFIG_UINT128
19570+#endif
19571+
19572+#if defined( CATCH_CONFIG_INTERNAL_MSVC_UMUL128 ) && \
19573+ !defined( CATCH_CONFIG_NO_MSVC_UMUL128 ) && \
19574+ !defined( CATCH_CONFIG_MSVC_UMUL128 )
19575+# define CATCH_CONFIG_MSVC_UMUL128
19576+# include <intrin.h>
19577+# pragma intrinsic( _umul128 )
19578+#endif
19579+
19580+
19581+namespace Catch {
19582+ namespace Detail {
19583+
19584+ template <std::size_t>
19585+ struct SizedUnsignedType;
19586+#define SizedUnsignedTypeHelper( TYPE ) \
19587+ template <> \
19588+ struct SizedUnsignedType<sizeof( TYPE )> { \
19589+ using type = TYPE; \
19590+ }
19591+
19592+ SizedUnsignedTypeHelper( std::uint8_t );
19593+ SizedUnsignedTypeHelper( std::uint16_t );
19594+ SizedUnsignedTypeHelper( std::uint32_t );
19595+ SizedUnsignedTypeHelper( std::uint64_t );
19596+#undef SizedUnsignedTypeHelper
19597+
19598+ template <std::size_t sz>
19599+ using SizedUnsignedType_t = typename SizedUnsignedType<sz>::type;
19600+
19601+ template <typename T>
19602+ using DoubleWidthUnsignedType_t = SizedUnsignedType_t<2 * sizeof( T )>;
19603+
19604+ template <typename T>
19605+ struct ExtendedMultResult {
19606+ T upper;
19607+ T lower;
19608+ bool operator==( ExtendedMultResult const& rhs ) const {
19609+ return upper == rhs.upper && lower == rhs.lower;
19610+ }
19611+ };
19612+
19613+ /**
19614+ * Returns 128 bit result of lhs * rhs using portable C++ code
19615+ *
19616+ * This implementation is almost twice as fast as naive long multiplication,
19617+ * and unlike intrinsic-based approach, it supports constexpr evaluation.
19618+ */
19619+ constexpr ExtendedMultResult<std::uint64_t>
19620+ extendedMultPortable(std::uint64_t lhs, std::uint64_t rhs) {
19621+#define CarryBits( x ) ( x >> 32 )
19622+#define Digits( x ) ( x & 0xFF'FF'FF'FF )
19623+ std::uint64_t lhs_low = Digits( lhs );
19624+ std::uint64_t rhs_low = Digits( rhs );
19625+ std::uint64_t low_low = ( lhs_low * rhs_low );
19626+ std::uint64_t high_high = CarryBits( lhs ) * CarryBits( rhs );
19627+
19628+ // We add in carry bits from low-low already
19629+ std::uint64_t high_low =
19630+ ( CarryBits( lhs ) * rhs_low ) + CarryBits( low_low );
19631+ // Note that we can add only low bits from high_low, to avoid
19632+ // overflow with large inputs
19633+ std::uint64_t low_high =
19634+ ( lhs_low * CarryBits( rhs ) ) + Digits( high_low );
19635+
19636+ return { high_high + CarryBits( high_low ) + CarryBits( low_high ),
19637+ ( low_high << 32 ) | Digits( low_low ) };
19638+#undef CarryBits
19639+#undef Digits
19640+ }
19641+
19642+ //! Returns 128 bit result of lhs * rhs
19643+ inline ExtendedMultResult<std::uint64_t>
19644+ extendedMult( std::uint64_t lhs, std::uint64_t rhs ) {
19645+#if defined( CATCH_CONFIG_UINT128 )
19646+ auto result = __uint128_t( lhs ) * __uint128_t( rhs );
19647+ return { static_cast<std::uint64_t>( result >> 64 ),
19648+ static_cast<std::uint64_t>( result ) };
19649+#elif defined( CATCH_CONFIG_MSVC_UMUL128 )
19650+ std::uint64_t high;
19651+ std::uint64_t low = _umul128( lhs, rhs, &high );
19652+ return { high, low };
19653+#else
19654+ return extendedMultPortable( lhs, rhs );
19655+#endif
19656+ }
19657+
19658+
19659+ template <typename UInt>
19660+ constexpr ExtendedMultResult<UInt> extendedMult( UInt lhs, UInt rhs ) {
19661+ static_assert( std::is_unsigned<UInt>::value,
19662+ "extendedMult can only handle unsigned integers" );
19663+ static_assert( sizeof( UInt ) < sizeof( std::uint64_t ),
19664+ "Generic extendedMult can only handle types smaller "
19665+ "than uint64_t" );
19666+ using WideType = DoubleWidthUnsignedType_t<UInt>;
19667+
19668+ auto result = WideType( lhs ) * WideType( rhs );
19669+ return {
19670+ static_cast<UInt>( result >> ( CHAR_BIT * sizeof( UInt ) ) ),
19671+ static_cast<UInt>( result & UInt( -1 ) ) };
19672+ }
19673+
19674+
19675+ template <typename TargetType,
19676+ typename Generator>
19677+ std::enable_if_t<sizeof(typename Generator::result_type) >= sizeof(TargetType),
19678+ TargetType> fillBitsFrom(Generator& gen) {
19679+ using gresult_type = typename Generator::result_type;
19680+ static_assert( std::is_unsigned<TargetType>::value, "Only unsigned integers are supported" );
19681+ static_assert( Generator::min() == 0 &&
19682+ Generator::max() == static_cast<gresult_type>( -1 ),
19683+ "Generator must be able to output all numbers in its result type (effectively it must be a random bit generator)" );
19684+
19685+ // We want to return the top bits from a generator, as they are
19686+ // usually considered higher quality.
19687+ constexpr auto generated_bits = sizeof( gresult_type ) * CHAR_BIT;
19688+ constexpr auto return_bits = sizeof( TargetType ) * CHAR_BIT;
19689+
19690+ return static_cast<TargetType>( gen() >>
19691+ ( generated_bits - return_bits) );
19692+ }
19693+
19694+ template <typename TargetType,
19695+ typename Generator>
19696+ std::enable_if_t<sizeof(typename Generator::result_type) < sizeof(TargetType),
19697+ TargetType> fillBitsFrom(Generator& gen) {
19698+ using gresult_type = typename Generator::result_type;
19699+ static_assert( std::is_unsigned<TargetType>::value,
19700+ "Only unsigned integers are supported" );
19701+ static_assert( Generator::min() == 0 &&
19702+ Generator::max() == static_cast<gresult_type>( -1 ),
19703+ "Generator must be able to output all numbers in its result type (effectively it must be a random bit generator)" );
19704+
19705+ constexpr auto generated_bits = sizeof( gresult_type ) * CHAR_BIT;
19706+ constexpr auto return_bits = sizeof( TargetType ) * CHAR_BIT;
19707+ std::size_t filled_bits = 0;
19708+ TargetType ret = 0;
19709+ do {
19710+ ret <<= generated_bits;
19711+ ret |= gen();
19712+ filled_bits += generated_bits;
19713+ } while ( filled_bits < return_bits );
19714+
19715+ return ret;
19716+ }
19717+
19718+ /*
19719+ * Transposes numbers into unsigned type while keeping their ordering
19720+ *
19721+ * This means that signed types are changed so that the ordering is
19722+ * [INT_MIN, ..., -1, 0, ..., INT_MAX], rather than order we would
19723+ * get by simple casting ([0, ..., INT_MAX, INT_MIN, ..., -1])
19724+ */
19725+ template <typename OriginalType, typename UnsignedType>
19726+ std::enable_if_t<std::is_signed<OriginalType>::value, UnsignedType>
19727+ transposeToNaturalOrder( UnsignedType in ) {
19728+ static_assert(
19729+ sizeof( OriginalType ) == sizeof( UnsignedType ),
19730+ "reordering requires the same sized types on both sides" );
19731+ static_assert( std::is_unsigned<UnsignedType>::value,
19732+ "Input type must be unsigned" );
19733+ // Assuming 2s complement (standardized in current C++), the
19734+ // positive and negative numbers are already internally ordered,
19735+ // and their difference is in the top bit. Swapping it orders
19736+ // them the desired way.
19737+ constexpr auto highest_bit =
19738+ UnsignedType( 1 ) << ( sizeof( UnsignedType ) * CHAR_BIT - 1 );
19739+ return static_cast<UnsignedType>( in ^ highest_bit );
19740+ }
19741+
19742+
19743+
19744+ template <typename OriginalType,
19745+ typename UnsignedType>
19746+ std::enable_if_t<std::is_unsigned<OriginalType>::value, UnsignedType>
19747+ transposeToNaturalOrder(UnsignedType in) {
19748+ static_assert(
19749+ sizeof( OriginalType ) == sizeof( UnsignedType ),
19750+ "reordering requires the same sized types on both sides" );
19751+ static_assert( std::is_unsigned<UnsignedType>::value, "Input type must be unsigned" );
19752+ // No reordering is needed for unsigned -> unsigned
19753+ return in;
19754+ }
19755+ } // namespace Detail
19756+} // namespace Catch
19757+
19758+#endif // CATCH_RANDOM_INTEGER_HELPERS_HPP_INCLUDED
19759+
19760+namespace Catch {
19761+
19762+/**
19763+ * Implementation of uniform distribution on integers.
19764+ *
19765+ * Unlike `std::uniform_int_distribution`, this implementation supports
19766+ * various 1 byte integral types, including bool (but you should not
19767+ * actually use it for bools).
19768+ *
19769+ * The underlying algorithm is based on the one described in "Fast Random
19770+ * Integer Generation in an Interval" by Daniel Lemire, but has been
19771+ * optimized under the assumption of reuse of the same distribution object.
19772+ */
19773+template <typename IntegerType>
19774+class uniform_integer_distribution {
19775+ static_assert(std::is_integral<IntegerType>::value, "...");
19776+
19777+ using UnsignedIntegerType = Detail::SizedUnsignedType_t<sizeof(IntegerType)>;
19778+
19779+ // Only the left bound is stored, and we store it converted to its
19780+ // unsigned image. This avoids having to do the conversions inside
19781+ // the operator(), at the cost of having to do the conversion in
19782+ // the a() getter. The right bound is only needed in the b() getter,
19783+ // so we recompute it there from other stored data.
19784+ UnsignedIntegerType m_a;
19785+
19786+ // How many different values are there in [a, b]. a == b => 1, can be 0 for distribution over all values in the type.
19787+ UnsignedIntegerType m_ab_distance;
19788+
19789+ // We hoisted this out of the main generation function. Technically,
19790+ // this means that using this distribution will be slower than Lemire's
19791+ // algorithm if this distribution instance will be used only few times,
19792+ // but it will be faster if it is used many times. Since Catch2 uses
19793+ // distributions only to implement random generators, we assume that each
19794+ // distribution will be reused many times and this is an optimization.
19795+ UnsignedIntegerType m_rejection_threshold = 0;
19796+
19797+ UnsignedIntegerType computeDistance(IntegerType a, IntegerType b) const {
19798+ // This overflows and returns 0 if a == 0 and b == TYPE_MAX.
19799+ // We handle that later when generating the number.
19800+ return transposeTo(b) - transposeTo(a) + 1;
19801+ }
19802+
19803+ static UnsignedIntegerType computeRejectionThreshold(UnsignedIntegerType ab_distance) {
19804+ // distance == 0 means that we will return all possible values from
19805+ // the type's range, and that we shouldn't reject anything.
19806+ if ( ab_distance == 0 ) { return 0; }
19807+ return ( ~ab_distance + 1 ) % ab_distance;
19808+ }
19809+
19810+ static UnsignedIntegerType transposeTo(IntegerType in) {
19811+ return Detail::transposeToNaturalOrder<IntegerType>(
19812+ static_cast<UnsignedIntegerType>( in ) );
19813+ }
19814+ static IntegerType transposeBack(UnsignedIntegerType in) {
19815+ return static_cast<IntegerType>(
19816+ Detail::transposeToNaturalOrder<IntegerType>(in) );
19817+ }
19818+
19819+public:
19820+ using result_type = IntegerType;
19821+
19822+ uniform_integer_distribution( IntegerType a, IntegerType b ):
19823+ m_a( transposeTo(a) ),
19824+ m_ab_distance( computeDistance(a, b) ),
19825+ m_rejection_threshold( computeRejectionThreshold(m_ab_distance) ) {
19826+ assert( a <= b );
19827+ }
19828+
19829+ template <typename Generator>
19830+ result_type operator()( Generator& g ) {
19831+ // All possible values of result_type are valid.
19832+ if ( m_ab_distance == 0 ) {
19833+ return transposeBack( Detail::fillBitsFrom<UnsignedIntegerType>( g ) );
19834+ }
19835+
19836+ auto random_number = Detail::fillBitsFrom<UnsignedIntegerType>( g );
19837+ auto emul = Detail::extendedMult( random_number, m_ab_distance );
19838+ // Unlike Lemire's algorithm we skip the ab_distance check, since
19839+ // we precomputed the rejection threshold, which is always tighter.
19840+ while (emul.lower < m_rejection_threshold) {
19841+ random_number = Detail::fillBitsFrom<UnsignedIntegerType>( g );
19842+ emul = Detail::extendedMult( random_number, m_ab_distance );
19843+ }
19844+
19845+ return transposeBack(m_a + emul.upper);
19846+ }
19847+
19848+ result_type a() const { return transposeBack(m_a); }
19849+ result_type b() const { return transposeBack(m_ab_distance + m_a - 1); }
19850+};
19851+
19852+} // end namespace Catch
19853+
19854+#endif // CATCH_UNIFORM_INTEGER_DISTRIBUTION_HPP_INCLUDED
19855+
19856+
19857+
19858+#ifndef CATCH_UNIFORM_FLOATING_POINT_DISTRIBUTION_HPP_INCLUDED
19859+#define CATCH_UNIFORM_FLOATING_POINT_DISTRIBUTION_HPP_INCLUDED
19860+
19861+
19862+
19863+
19864+#ifndef CATCH_RANDOM_FLOATING_POINT_HELPERS_HPP_INCLUDED
19865+#define CATCH_RANDOM_FLOATING_POINT_HELPERS_HPP_INCLUDED
19866+
19867+
19868+
19869+#ifndef CATCH_POLYFILLS_HPP_INCLUDED
19870+#define CATCH_POLYFILLS_HPP_INCLUDED
19871+
19872+namespace Catch {
19873+
19874+ bool isnan(float f);
19875+ bool isnan(double d);
19876+
19877+ float nextafter(float x, float y);
19878+ double nextafter(double x, double y);
19879+
19880+}
19881+
19882+#endif // CATCH_POLYFILLS_HPP_INCLUDED
19883+
19884+#include <cassert>
19885+#include <cmath>
19886+#include <cstdint>
19887+#include <limits>
19888+#include <type_traits>
19889+
19890+namespace Catch {
19891+
19892+ namespace Detail {
19893+ /**
19894+ * Returns the largest magnitude of 1-ULP distance inside the [a, b] range.
19895+ *
19896+ * Assumes `a < b`.
19897+ */
19898+ template <typename FloatType>
19899+ FloatType gamma(FloatType a, FloatType b) {
19900+ static_assert( std::is_floating_point<FloatType>::value,
19901+ "gamma returns the largest ULP magnitude within "
19902+ "floating point range [a, b]. This only makes sense "
19903+ "for floating point types" );
19904+ assert( a <= b );
19905+
19906+ const auto gamma_up = Catch::nextafter( a, std::numeric_limits<FloatType>::infinity() ) - a;
19907+ const auto gamma_down = b - Catch::nextafter( b, -std::numeric_limits<FloatType>::infinity() );
19908+
19909+ return gamma_up < gamma_down ? gamma_down : gamma_up;
19910+ }
19911+
19912+ template <typename FloatingPoint>
19913+ struct DistanceTypePicker;
19914+ template <>
19915+ struct DistanceTypePicker<float> {
19916+ using type = std::uint32_t;
19917+ };
19918+ template <>
19919+ struct DistanceTypePicker<double> {
19920+ using type = std::uint64_t;
19921+ };
19922+
19923+ template <typename T>
19924+ using DistanceType = typename DistanceTypePicker<T>::type;
19925+
19926+#if defined( __GNUC__ ) || defined( __clang__ )
19927+# pragma GCC diagnostic push
19928+# pragma GCC diagnostic ignored "-Wfloat-equal"
19929+#endif
19930+ /**
19931+ * Computes the number of equi-distant floats in [a, b]
19932+ *
19933+ * Since not every range can be split into equidistant floats
19934+ * exactly, we actually compute ceil(b/distance - a/distance),
19935+ * because in those cases we want to overcount.
19936+ *
19937+ * Uses modified Dekker's FastTwoSum algorithm to handle rounding.
19938+ */
19939+ template <typename FloatType>
19940+ DistanceType<FloatType>
19941+ count_equidistant_floats( FloatType a, FloatType b, FloatType distance ) {
19942+ assert( a <= b );
19943+ // We get distance as gamma for our uniform float distribution,
19944+ // so this will round perfectly.
19945+ const auto ag = a / distance;
19946+ const auto bg = b / distance;
19947+
19948+ const auto s = bg - ag;
19949+ const auto err = ( std::fabs( a ) <= std::fabs( b ) )
19950+ ? -ag - ( s - bg )
19951+ : bg - ( s + ag );
19952+ const auto ceil_s = static_cast<DistanceType<FloatType>>( std::ceil( s ) );
19953+
19954+ return ( ceil_s != s ) ? ceil_s : ceil_s + ( err > 0 );
19955+ }
19956+#if defined( __GNUC__ ) || defined( __clang__ )
19957+# pragma GCC diagnostic pop
19958+#endif
19959+
19960+ }
19961+
19962+} // end namespace Catch
19963+
19964+#endif // CATCH_RANDOM_FLOATING_POINT_HELPERS_HPP_INCLUDED
19965+
19966+#include <cmath>
19967+#include <type_traits>
19968+
19969+namespace Catch {
19970+
19971+ namespace Detail {
19972+#if defined( __GNUC__ ) || defined( __clang__ )
19973+# pragma GCC diagnostic push
19974+# pragma GCC diagnostic ignored "-Wfloat-equal"
19975+#endif
19976+ // The issue with overflow only happens with maximal ULP and HUGE
19977+ // distance, e.g. when generating numbers in [-inf, inf] for given
19978+ // type. So we only check for the largest possible ULP in the
19979+ // type, and return something that does not overflow to inf in 1 mult.
19980+ constexpr std::uint64_t calculate_max_steps_in_one_go(double gamma) {
19981+ if ( gamma == 1.99584030953472e+292 ) { return 9007199254740991; }
19982+ return static_cast<std::uint64_t>( -1 );
19983+ }
19984+ constexpr std::uint32_t calculate_max_steps_in_one_go(float gamma) {
19985+ if ( gamma == 2.028241e+31f ) { return 16777215; }
19986+ return static_cast<std::uint32_t>( -1 );
19987+ }
19988+#if defined( __GNUC__ ) || defined( __clang__ )
19989+# pragma GCC diagnostic pop
19990+#endif
19991+ }
19992+
19993+/**
19994+ * Implementation of uniform distribution on floating point numbers.
19995+ *
19996+ * Note that we support only `float` and `double` types, because these
19997+ * usually mean the same thing across different platform. `long double`
19998+ * varies wildly by platform and thus we cannot provide reproducible
19999+ * implementation. Also note that we don't implement all parts of
20000+ * distribution per standard: this distribution is not serializable, nor
20001+ * can the range be arbitrarily reset.
20002+ *
20003+ * The implementation also uses different approach than the one taken by
20004+ * `std::uniform_real_distribution`, where instead of generating a number
20005+ * between [0, 1) and then multiplying the range bounds with it, we first
20006+ * split the [a, b] range into a set of equidistributed floating point
20007+ * numbers, and then use uniform int distribution to pick which one to
20008+ * return.
20009+ *
20010+ * This has the advantage of guaranteeing uniformity (the multiplication
20011+ * method loses uniformity due to rounding when multiplying floats), except
20012+ * for small non-uniformity at one side of the interval, where we have
20013+ * to deal with the fact that not every interval is splittable into
20014+ * equidistributed floats.
20015+ *
20016+ * Based on "Drawing random floating-point numbers from an interval" by
20017+ * Frederic Goualard.
20018+ */
20019+template <typename FloatType>
20020+class uniform_floating_point_distribution {
20021+ static_assert(std::is_floating_point<FloatType>::value, "...");
20022+ static_assert(!std::is_same<FloatType, long double>::value,
20023+ "We do not support long double due to inconsistent behaviour between platforms");
20024+
20025+ using WidthType = Detail::DistanceType<FloatType>;
20026+
20027+ FloatType m_a, m_b;
20028+ FloatType m_ulp_magnitude;
20029+ WidthType m_floats_in_range;
20030+ uniform_integer_distribution<WidthType> m_int_dist;
20031+
20032+ // In specific cases, we can overflow into `inf` when computing the
20033+ // `steps * g` offset. To avoid this, we don't offset by more than this
20034+ // in one multiply + addition.
20035+ WidthType m_max_steps_in_one_go;
20036+ // We don't want to do the magnitude check every call to `operator()`
20037+ bool m_a_has_leq_magnitude;
20038+
20039+public:
20040+ using result_type = FloatType;
20041+
20042+ uniform_floating_point_distribution( FloatType a, FloatType b ):
20043+ m_a( a ),
20044+ m_b( b ),
20045+ m_ulp_magnitude( Detail::gamma( m_a, m_b ) ),
20046+ m_floats_in_range( Detail::count_equidistant_floats( m_a, m_b, m_ulp_magnitude ) ),
20047+ m_int_dist(0, m_floats_in_range),
20048+ m_max_steps_in_one_go( Detail::calculate_max_steps_in_one_go(m_ulp_magnitude)),
20049+ m_a_has_leq_magnitude(std::fabs(m_a) <= std::fabs(m_b))
20050+ {
20051+ assert( a <= b );
20052+ }
20053+
20054+ template <typename Generator>
20055+ result_type operator()( Generator& g ) {
20056+ WidthType steps = m_int_dist( g );
20057+ if ( m_a_has_leq_magnitude ) {
20058+ if ( steps == m_floats_in_range ) { return m_a; }
20059+ auto b = m_b;
20060+ while (steps > m_max_steps_in_one_go) {
20061+ b -= m_max_steps_in_one_go * m_ulp_magnitude;
20062+ steps -= m_max_steps_in_one_go;
20063+ }
20064+ return b - steps * m_ulp_magnitude;
20065+ } else {
20066+ if ( steps == m_floats_in_range ) { return m_b; }
20067+ auto a = m_a;
20068+ while (steps > m_max_steps_in_one_go) {
20069+ a += m_max_steps_in_one_go * m_ulp_magnitude;
20070+ steps -= m_max_steps_in_one_go;
20071+ }
20072+ return a + steps * m_ulp_magnitude;
20073+ }
20074+ }
20075+
20076+ result_type a() const { return m_a; }
20077+ result_type b() const { return m_b; }
20078+};
20079+
20080+} // end namespace Catch
20081+
20082+#endif // CATCH_UNIFORM_FLOATING_POINT_DISTRIBUTION_HPP_INCLUDED
20083+
20084+namespace Catch {
20085+namespace Generators {
20086+namespace Detail {
20087+ // Returns a suitable seed for a random floating generator based off
20088+ // the primary internal rng. It does so by taking current value from
20089+ // the rng and returning it as the seed.
20090+ std::uint32_t getSeed();
20091+}
20092+
20093+template <typename Float>
20094+class RandomFloatingGenerator final : public IGenerator<Float> {
20095+ Catch::SimplePcg32 m_rng;
20096+ Catch::uniform_floating_point_distribution<Float> m_dist;
20097+ Float m_current_number;
20098+public:
20099+ RandomFloatingGenerator( Float a, Float b, std::uint32_t seed ):
20100+ m_rng(seed),
20101+ m_dist(a, b) {
20102+ static_cast<void>(next());
20103+ }
20104+
20105+ Float const& get() const override {
20106+ return m_current_number;
20107+ }
20108+ bool next() override {
20109+ m_current_number = m_dist(m_rng);
20110+ return true;
20111+ }
20112+};
20113+
20114+template <>
20115+class RandomFloatingGenerator<long double> final : public IGenerator<long double> {
20116+ // We still rely on <random> for this specialization, but we don't
20117+ // want to drag it into the header.
20118+ struct PImpl;
20119+ Catch::Detail::unique_ptr<PImpl> m_pimpl;
20120+ long double m_current_number;
20121+
20122+public:
20123+ RandomFloatingGenerator( long double a, long double b, std::uint32_t seed );
20124+
20125+ long double const& get() const override { return m_current_number; }
20126+ bool next() override;
20127+
20128+ ~RandomFloatingGenerator() override; // = default
20129+};
20130+
20131+template <typename Integer>
20132+class RandomIntegerGenerator final : public IGenerator<Integer> {
20133+ Catch::SimplePcg32 m_rng;
20134+ Catch::uniform_integer_distribution<Integer> m_dist;
20135+ Integer m_current_number;
20136+public:
20137+ RandomIntegerGenerator( Integer a, Integer b, std::uint32_t seed ):
20138+ m_rng(seed),
20139+ m_dist(a, b) {
20140+ static_cast<void>(next());
20141+ }
20142+
20143+ Integer const& get() const override {
20144+ return m_current_number;
20145+ }
20146+ bool next() override {
20147+ m_current_number = m_dist(m_rng);
20148+ return true;
20149+ }
20150+};
20151+
20152+template <typename T>
20153+std::enable_if_t<std::is_integral<T>::value, GeneratorWrapper<T>>
20154+random(T a, T b) {
20155+ return GeneratorWrapper<T>(
20156+ Catch::Detail::make_unique<RandomIntegerGenerator<T>>(a, b, Detail::getSeed())
20157+ );
20158+}
20159+
20160+template <typename T>
20161+std::enable_if_t<std::is_floating_point<T>::value,
20162+GeneratorWrapper<T>>
20163+random(T a, T b) {
20164+ return GeneratorWrapper<T>(
20165+ Catch::Detail::make_unique<RandomFloatingGenerator<T>>(a, b, Detail::getSeed())
20166+ );
20167+}
20168+
20169+
20170+} // namespace Generators
20171+} // namespace Catch
20172+
20173+
20174+#endif // CATCH_GENERATORS_RANDOM_HPP_INCLUDED
20175+
20176+
20177+#ifndef CATCH_GENERATORS_RANGE_HPP_INCLUDED
20178+#define CATCH_GENERATORS_RANGE_HPP_INCLUDED
20179+
20180+
20181+#include <iterator>
20182+#include <type_traits>
20183+
20184+namespace Catch {
20185+namespace Generators {
20186+
20187+
20188+template <typename T>
20189+class RangeGenerator final : public IGenerator<T> {
20190+ T m_current;
20191+ T m_end;
20192+ T m_step;
20193+ bool m_positive;
20194+
20195+public:
20196+ RangeGenerator(T const& start, T const& end, T const& step):
20197+ m_current(start),
20198+ m_end(end),
20199+ m_step(step),
20200+ m_positive(m_step > T(0))
20201+ {
20202+ assert(m_current != m_end && "Range start and end cannot be equal");
20203+ assert(m_step != T(0) && "Step size cannot be zero");
20204+ assert(((m_positive && m_current <= m_end) || (!m_positive && m_current >= m_end)) && "Step moves away from end");
20205+ }
20206+
20207+ RangeGenerator(T const& start, T const& end):
20208+ RangeGenerator(start, end, (start < end) ? T(1) : T(-1))
20209+ {}
20210+
20211+ T const& get() const override {
20212+ return m_current;
20213+ }
20214+
20215+ bool next() override {
20216+ m_current += m_step;
20217+ return (m_positive) ? (m_current < m_end) : (m_current > m_end);
20218+ }
20219+};
20220+
20221+template <typename T>
20222+GeneratorWrapper<T> range(T const& start, T const& end, T const& step) {
20223+ static_assert(std::is_arithmetic<T>::value && !std::is_same<T, bool>::value, "Type must be numeric");
20224+ return GeneratorWrapper<T>(Catch::Detail::make_unique<RangeGenerator<T>>(start, end, step));
20225+}
20226+
20227+template <typename T>
20228+GeneratorWrapper<T> range(T const& start, T const& end) {
20229+ static_assert(std::is_integral<T>::value && !std::is_same<T, bool>::value, "Type must be an integer");
20230+ return GeneratorWrapper<T>(Catch::Detail::make_unique<RangeGenerator<T>>(start, end));
20231+}
20232+
20233+
20234+template <typename T>
20235+class IteratorGenerator final : public IGenerator<T> {
20236+ static_assert(!std::is_same<T, bool>::value,
20237+ "IteratorGenerator currently does not support bools"
20238+ "because of std::vector<bool> specialization");
20239+
20240+ std::vector<T> m_elems;
20241+ size_t m_current = 0;
20242+public:
20243+ template <typename InputIterator, typename InputSentinel>
20244+ IteratorGenerator(InputIterator first, InputSentinel last):m_elems(first, last) {
20245+ if (m_elems.empty()) {
20246+ Detail::throw_generator_exception("IteratorGenerator received no valid values");
20247+ }
20248+ }
20249+
20250+ T const& get() const override {
20251+ return m_elems[m_current];
20252+ }
20253+
20254+ bool next() override {
20255+ ++m_current;
20256+ return m_current != m_elems.size();
20257+ }
20258+};
20259+
20260+template <typename InputIterator,
20261+ typename InputSentinel,
20262+ typename ResultType = typename std::iterator_traits<InputIterator>::value_type>
20263+GeneratorWrapper<ResultType> from_range(InputIterator from, InputSentinel to) {
20264+ return GeneratorWrapper<ResultType>(Catch::Detail::make_unique<IteratorGenerator<ResultType>>(from, to));
20265+}
20266+
20267+template <typename Container>
20268+auto from_range(Container const& cnt) {
20269+ using std::begin;
20270+ using std::end;
20271+ return from_range( begin( cnt ), end( cnt ) );
20272+}
20273+
20274+
20275+} // namespace Generators
20276+} // namespace Catch
20277+
20278+
20279+#endif // CATCH_GENERATORS_RANGE_HPP_INCLUDED
20280+
20281+#endif // CATCH_GENERATORS_ALL_HPP_INCLUDED
20282+
20283+
20284+/** \file
20285+ * This is a convenience header for Catch2's interfaces. It includes
20286+ * **all** of Catch2 headers related to interfaces.
20287+ *
20288+ * Generally the Catch2 users should use specific includes they need,
20289+ * but this header can be used instead for ease-of-experimentation, or
20290+ * just plain convenience, at the cost of somewhat increased compilation
20291+ * times.
20292+ *
20293+ * When a new header is added to either the `interfaces` folder, or to
20294+ * the corresponding internal subfolder, it should be added here.
20295+ */
20296+
20297+
20298+#ifndef CATCH_INTERFACES_ALL_HPP_INCLUDED
20299+#define CATCH_INTERFACES_ALL_HPP_INCLUDED
20300+
20301+
20302+
20303+#ifndef CATCH_INTERFACES_REPORTER_HPP_INCLUDED
20304+#define CATCH_INTERFACES_REPORTER_HPP_INCLUDED
20305+
20306+
20307+
20308+#ifndef CATCH_TEST_RUN_INFO_HPP_INCLUDED
20309+#define CATCH_TEST_RUN_INFO_HPP_INCLUDED
20310+
20311+
20312+namespace Catch {
20313+
20314+ struct TestRunInfo {
20315+ constexpr TestRunInfo(StringRef _name) : name(_name) {}
20316+ StringRef name;
20317+ };
20318+
20319+} // end namespace Catch
20320+
20321+#endif // CATCH_TEST_RUN_INFO_HPP_INCLUDED
20322+
20323+#include <map>
20324+#include <string>
20325+#include <vector>
20326+#include <iosfwd>
20327+
20328+namespace Catch {
20329+
20330+ struct ReporterDescription;
20331+ struct ListenerDescription;
20332+ struct TagInfo;
20333+ struct TestCaseInfo;
20334+ class TestCaseHandle;
20335+ class IConfig;
20336+ class IStream;
20337+ enum class ColourMode : std::uint8_t;
20338+
20339+ struct ReporterConfig {
20340+ ReporterConfig( IConfig const* _fullConfig,
20341+ Detail::unique_ptr<IStream> _stream,
20342+ ColourMode colourMode,
20343+ std::map<std::string, std::string> customOptions );
20344+
20345+ ReporterConfig( ReporterConfig&& ) = default;
20346+ ReporterConfig& operator=( ReporterConfig&& ) = default;
20347+ ~ReporterConfig(); // = default
20348+
20349+ Detail::unique_ptr<IStream> takeStream() &&;
20350+ IConfig const* fullConfig() const;
20351+ ColourMode colourMode() const;
20352+ std::map<std::string, std::string> const& customOptions() const;
20353+
20354+ private:
20355+ Detail::unique_ptr<IStream> m_stream;
20356+ IConfig const* m_fullConfig;
20357+ ColourMode m_colourMode;
20358+ std::map<std::string, std::string> m_customOptions;
20359+ };
20360+
20361+ struct AssertionStats {
20362+ AssertionStats( AssertionResult const& _assertionResult,
20363+ std::vector<MessageInfo> const& _infoMessages,
20364+ Totals const& _totals );
20365+
20366+ AssertionStats( AssertionStats const& ) = default;
20367+ AssertionStats( AssertionStats && ) = default;
20368+ AssertionStats& operator = ( AssertionStats const& ) = delete;
20369+ AssertionStats& operator = ( AssertionStats && ) = delete;
20370+
20371+ AssertionResult assertionResult;
20372+ std::vector<MessageInfo> infoMessages;
20373+ Totals totals;
20374+ };
20375+
20376+ struct SectionStats {
20377+ SectionStats( SectionInfo&& _sectionInfo,
20378+ Counts const& _assertions,
20379+ double _durationInSeconds,
20380+ bool _missingAssertions );
20381+
20382+ SectionInfo sectionInfo;
20383+ Counts assertions;
20384+ double durationInSeconds;
20385+ bool missingAssertions;
20386+ };
20387+
20388+ struct TestCaseStats {
20389+ TestCaseStats( TestCaseInfo const& _testInfo,
20390+ Totals const& _totals,
20391+ std::string&& _stdOut,
20392+ std::string&& _stdErr,
20393+ bool _aborting );
20394+
20395+ TestCaseInfo const * testInfo;
20396+ Totals totals;
20397+ std::string stdOut;
20398+ std::string stdErr;
20399+ bool aborting;
20400+ };
20401+
20402+ struct TestRunStats {
20403+ TestRunStats( TestRunInfo const& _runInfo,
20404+ Totals const& _totals,
20405+ bool _aborting );
20406+
20407+ TestRunInfo runInfo;
20408+ Totals totals;
20409+ bool aborting;
20410+ };
20411+
20412+ //! By setting up its preferences, a reporter can modify Catch2's behaviour
20413+ //! in some regards, e.g. it can request Catch2 to capture writes to
20414+ //! stdout/stderr during test execution, and pass them to the reporter.
20415+ struct ReporterPreferences {
20416+ //! Catch2 should redirect writes to stdout and pass them to the
20417+ //! reporter
20418+ bool shouldRedirectStdOut = false;
20419+ //! Catch2 should call `Reporter::assertionEnded` even for passing
20420+ //! assertions
20421+ bool shouldReportAllAssertions = false;
20422+ };
20423+
20424+ /**
20425+ * The common base for all reporters and event listeners
20426+ *
20427+ * Implementing classes must also implement:
20428+ *
20429+ * //! User-friendly description of the reporter/listener type
20430+ * static std::string getDescription()
20431+ *
20432+ * Generally shouldn't be derived from by users of Catch2 directly,
20433+ * instead they should derive from one of the utility bases that
20434+ * derive from this class.
20435+ */
20436+ class IEventListener {
20437+ protected:
20438+ //! Derived classes can set up their preferences here
20439+ ReporterPreferences m_preferences;
20440+ //! The test run's config as filled in from CLI and defaults
20441+ IConfig const* m_config;
20442+
20443+ public:
20444+ IEventListener( IConfig const* config ): m_config( config ) {}
20445+
20446+ virtual ~IEventListener(); // = default;
20447+
20448+ // Implementing class must also provide the following static methods:
20449+ // static std::string getDescription();
20450+
20451+ ReporterPreferences const& getPreferences() const {
20452+ return m_preferences;
20453+ }
20454+
20455+ //! Called when no test cases match provided test spec
20456+ virtual void noMatchingTestCases( StringRef unmatchedSpec ) = 0;
20457+ //! Called for all invalid test specs from the cli
20458+ virtual void reportInvalidTestSpec( StringRef invalidArgument ) = 0;
20459+
20460+ /**
20461+ * Called once in a testing run before tests are started
20462+ *
20463+ * Not called if tests won't be run (e.g. only listing will happen)
20464+ */
20465+ virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0;
20466+
20467+ //! Called _once_ for each TEST_CASE, no matter how many times it is entered
20468+ virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0;
20469+ //! Called _every time_ a TEST_CASE is entered, including repeats (due to sections)
20470+ virtual void testCasePartialStarting( TestCaseInfo const& testInfo, uint64_t partNumber ) = 0;
20471+ //! Called when a `SECTION` is being entered. Not called for skipped sections
20472+ virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0;
20473+
20474+ //! Called when user-code is being probed before the actual benchmark runs
20475+ virtual void benchmarkPreparing( StringRef benchmarkName ) = 0;
20476+ //! Called after probe but before the user-code is being benchmarked
20477+ virtual void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) = 0;
20478+ //! Called with the benchmark results if benchmark successfully finishes
20479+ virtual void benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) = 0;
20480+ //! Called if running the benchmarks fails for any reason
20481+ virtual void benchmarkFailed( StringRef benchmarkName ) = 0;
20482+
20483+ //! Called before assertion success/failure is evaluated
20484+ virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0;
20485+
20486+ //! Called after assertion was fully evaluated
20487+ virtual void assertionEnded( AssertionStats const& assertionStats ) = 0;
20488+
20489+ //! Called after a `SECTION` has finished running
20490+ virtual void sectionEnded( SectionStats const& sectionStats ) = 0;
20491+ //! Called _every time_ a TEST_CASE is entered, including repeats (due to sections)
20492+ virtual void testCasePartialEnded(TestCaseStats const& testCaseStats, uint64_t partNumber ) = 0;
20493+ //! Called _once_ for each TEST_CASE, no matter how many times it is entered
20494+ virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0;
20495+ /**
20496+ * Called once after all tests in a testing run are finished
20497+ *
20498+ * Not called if tests weren't run (e.g. only listings happened)
20499+ */
20500+ virtual void testRunEnded( TestRunStats const& testRunStats ) = 0;
20501+
20502+ /**
20503+ * Called with test cases that are skipped due to the test run aborting.
20504+ * NOT called for test cases that are explicitly skipped using the `SKIP` macro.
20505+ *
20506+ * Deprecated - will be removed in the next major release.
20507+ */
20508+ virtual void skipTest( TestCaseInfo const& testInfo ) = 0;
20509+
20510+ //! Called if a fatal error (signal/structured exception) occurred
20511+ virtual void fatalErrorEncountered( StringRef error ) = 0;
20512+
20513+ //! Writes out information about provided reporters using reporter-specific format
20514+ virtual void listReporters(std::vector<ReporterDescription> const& descriptions) = 0;
20515+ //! Writes out the provided listeners descriptions using reporter-specific format
20516+ virtual void listListeners(std::vector<ListenerDescription> const& descriptions) = 0;
20517+ //! Writes out information about provided tests using reporter-specific format
20518+ virtual void listTests(std::vector<TestCaseHandle> const& tests) = 0;
20519+ //! Writes out information about the provided tags using reporter-specific format
20520+ virtual void listTags(std::vector<TagInfo> const& tags) = 0;
20521+ };
20522+ using IEventListenerPtr = Detail::unique_ptr<IEventListener>;
20523+
20524+} // end namespace Catch
20525+
20526+#endif // CATCH_INTERFACES_REPORTER_HPP_INCLUDED
20527+
20528+
20529+#ifndef CATCH_INTERFACES_REPORTER_FACTORY_HPP_INCLUDED
20530+#define CATCH_INTERFACES_REPORTER_FACTORY_HPP_INCLUDED
20531+
20532+
20533+#include <string>
20534+
20535+namespace Catch {
20536+
20537+ struct ReporterConfig;
20538+ class IConfig;
20539+ class IEventListener;
20540+ using IEventListenerPtr = Detail::unique_ptr<IEventListener>;
20541+
20542+
20543+ class IReporterFactory {
20544+ public:
20545+ virtual ~IReporterFactory(); // = default
20546+
20547+ virtual IEventListenerPtr
20548+ create( ReporterConfig&& config ) const = 0;
20549+ virtual std::string getDescription() const = 0;
20550+ };
20551+ using IReporterFactoryPtr = Detail::unique_ptr<IReporterFactory>;
20552+
20553+ class EventListenerFactory {
20554+ public:
20555+ virtual ~EventListenerFactory(); // = default
20556+ virtual IEventListenerPtr create( IConfig const* config ) const = 0;
20557+ //! Return a meaningful name for the listener, e.g. its type name
20558+ virtual StringRef getName() const = 0;
20559+ //! Return listener's description if available
20560+ virtual std::string getDescription() const = 0;
20561+ };
20562+} // namespace Catch
20563+
20564+#endif // CATCH_INTERFACES_REPORTER_FACTORY_HPP_INCLUDED
20565+
20566+
20567+#ifndef CATCH_INTERFACES_TAG_ALIAS_REGISTRY_HPP_INCLUDED
20568+#define CATCH_INTERFACES_TAG_ALIAS_REGISTRY_HPP_INCLUDED
20569+
20570+#include <string>
20571+
20572+namespace Catch {
20573+
20574+ struct TagAlias;
20575+
20576+ class ITagAliasRegistry {
20577+ public:
20578+ virtual ~ITagAliasRegistry(); // = default
20579+ // Nullptr if not present
20580+ virtual TagAlias const* find( std::string const& alias ) const = 0;
20581+ virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0;
20582+
20583+ static ITagAliasRegistry const& get();
20584+ };
20585+
20586+} // end namespace Catch
20587+
20588+#endif // CATCH_INTERFACES_TAG_ALIAS_REGISTRY_HPP_INCLUDED
20589+
20590+
20591+#ifndef CATCH_INTERFACES_TESTCASE_HPP_INCLUDED
20592+#define CATCH_INTERFACES_TESTCASE_HPP_INCLUDED
20593+
20594+#include <vector>
20595+
20596+namespace Catch {
20597+
20598+ struct TestCaseInfo;
20599+ class TestCaseHandle;
20600+ class IConfig;
20601+
20602+ class ITestCaseRegistry {
20603+ public:
20604+ virtual ~ITestCaseRegistry(); // = default
20605+ // TODO: this exists only for adding filenames to test cases -- let's expose this in a saner way later
20606+ virtual std::vector<TestCaseInfo* > const& getAllInfos() const = 0;
20607+ virtual std::vector<TestCaseHandle> const& getAllTests() const = 0;
20608+ virtual std::vector<TestCaseHandle> const& getAllTestsSorted( IConfig const& config ) const = 0;
20609+ };
20610+
20611+}
20612+
20613+#endif // CATCH_INTERFACES_TESTCASE_HPP_INCLUDED
20614+
20615+#endif // CATCH_INTERFACES_ALL_HPP_INCLUDED
20616+
20617+
20618+#ifndef CATCH_CASE_INSENSITIVE_COMPARISONS_HPP_INCLUDED
20619+#define CATCH_CASE_INSENSITIVE_COMPARISONS_HPP_INCLUDED
20620+
20621+
20622+namespace Catch {
20623+ namespace Detail {
20624+ //! Provides case-insensitive `op<` semantics when called
20625+ struct CaseInsensitiveLess {
20626+ bool operator()( StringRef lhs,
20627+ StringRef rhs ) const;
20628+ };
20629+
20630+ //! Provides case-insensitive `op==` semantics when called
20631+ struct CaseInsensitiveEqualTo {
20632+ bool operator()( StringRef lhs,
20633+ StringRef rhs ) const;
20634+ };
20635+
20636+ } // namespace Detail
20637+} // namespace Catch
20638+
20639+#endif // CATCH_CASE_INSENSITIVE_COMPARISONS_HPP_INCLUDED
20640+
20641+
20642+
20643+/** \file
20644+ * Wrapper for ANDROID_LOGWRITE configuration option
20645+ *
20646+ * We want to default to enabling it when compiled for android, but
20647+ * users of the library should also be able to disable it if they want
20648+ * to.
20649+ */
20650+
20651+#ifndef CATCH_CONFIG_ANDROID_LOGWRITE_HPP_INCLUDED
20652+#define CATCH_CONFIG_ANDROID_LOGWRITE_HPP_INCLUDED
20653+
20654+
20655+#if defined(__ANDROID__)
20656+# define CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE
20657+#endif
20658+
20659+
20660+#if defined( CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE ) && \
20661+ !defined( CATCH_CONFIG_NO_ANDROID_LOGWRITE ) && \
20662+ !defined( CATCH_CONFIG_ANDROID_LOGWRITE )
20663+# define CATCH_CONFIG_ANDROID_LOGWRITE
20664+#endif
20665+
20666+#endif // CATCH_CONFIG_ANDROID_LOGWRITE_HPP_INCLUDED
20667+
20668+
20669+
20670+/** \file
20671+ * Wrapper for UNCAUGHT_EXCEPTIONS configuration option
20672+ *
20673+ * For some functionality, Catch2 requires to know whether there is
20674+ * an active exception. Because `std::uncaught_exception` is deprecated
20675+ * in C++17, we want to use `std::uncaught_exceptions` if possible.
20676+ */
20677+
20678+#ifndef CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP_INCLUDED
20679+#define CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP_INCLUDED
20680+
20681+
20682+#if defined(_MSC_VER)
20683+# if _MSC_VER >= 1900 // Visual Studio 2015 or newer
20684+# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
20685+# endif
20686+#endif
20687+
20688+
20689+#include <exception>
20690+
20691+#if defined(__cpp_lib_uncaught_exceptions) \
20692+ && !defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
20693+
20694+# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
20695+#endif // __cpp_lib_uncaught_exceptions
20696+
20697+
20698+#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) \
20699+ && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) \
20700+ && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
20701+
20702+# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
20703+#endif
20704+
20705+
20706+#endif // CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP_INCLUDED
20707+
20708+
20709+#ifndef CATCH_CONSOLE_COLOUR_HPP_INCLUDED
20710+#define CATCH_CONSOLE_COLOUR_HPP_INCLUDED
20711+
20712+
20713+#include <iosfwd>
20714+#include <cstdint>
20715+
20716+namespace Catch {
20717+
20718+ enum class ColourMode : std::uint8_t;
20719+ class IStream;
20720+
20721+ struct Colour {
20722+ enum Code {
20723+ None = 0,
20724+
20725+ White,
20726+ Red,
20727+ Green,
20728+ Blue,
20729+ Cyan,
20730+ Yellow,
20731+ Grey,
20732+
20733+ Bright = 0x10,
20734+
20735+ BrightRed = Bright | Red,
20736+ BrightGreen = Bright | Green,
20737+ LightGrey = Bright | Grey,
20738+ BrightWhite = Bright | White,
20739+ BrightYellow = Bright | Yellow,
20740+
20741+ // By intention
20742+ FileName = LightGrey,
20743+ Warning = BrightYellow,
20744+ ResultError = BrightRed,
20745+ ResultSuccess = BrightGreen,
20746+ ResultExpectedFailure = Warning,
20747+
20748+ Error = BrightRed,
20749+ Success = Green,
20750+ Skip = LightGrey,
20751+
20752+ OriginalExpression = Cyan,
20753+ ReconstructedExpression = BrightYellow,
20754+
20755+ SecondaryText = LightGrey,
20756+ Headers = White
20757+ };
20758+ };
20759+
20760+ class ColourImpl {
20761+ protected:
20762+ //! The associated stream of this ColourImpl instance
20763+ IStream* m_stream;
20764+ public:
20765+ ColourImpl( IStream* stream ): m_stream( stream ) {}
20766+
20767+ //! RAII wrapper around writing specific colour of text using specific
20768+ //! colour impl into a stream.
20769+ class ColourGuard {
20770+ ColourImpl const* m_colourImpl;
20771+ Colour::Code m_code;
20772+ bool m_engaged = false;
20773+
20774+ public:
20775+ //! Does **not** engage the guard/start the colour
20776+ ColourGuard( Colour::Code code,
20777+ ColourImpl const* colour );
20778+
20779+ ColourGuard( ColourGuard const& rhs ) = delete;
20780+ ColourGuard& operator=( ColourGuard const& rhs ) = delete;
20781+
20782+ ColourGuard( ColourGuard&& rhs ) noexcept;
20783+ ColourGuard& operator=( ColourGuard&& rhs ) noexcept;
20784+
20785+ //! Removes colour _if_ the guard was engaged
20786+ ~ColourGuard();
20787+
20788+ /**
20789+ * Explicitly engages colour for given stream.
20790+ *
20791+ * The API based on operator<< should be preferred.
20792+ */
20793+ ColourGuard& engage( std::ostream& stream ) &;
20794+ /**
20795+ * Explicitly engages colour for given stream.
20796+ *
20797+ * The API based on operator<< should be preferred.
20798+ */
20799+ ColourGuard&& engage( std::ostream& stream ) &&;
20800+
20801+ private:
20802+ //! Engages the guard and starts using colour
20803+ friend std::ostream& operator<<( std::ostream& lhs,
20804+ ColourGuard& guard ) {
20805+ guard.engageImpl( lhs );
20806+ return lhs;
20807+ }
20808+ //! Engages the guard and starts using colour
20809+ friend std::ostream& operator<<( std::ostream& lhs,
20810+ ColourGuard&& guard) {
20811+ guard.engageImpl( lhs );
20812+ return lhs;
20813+ }
20814+
20815+ void engageImpl( std::ostream& stream );
20816+
20817+ };
20818+
20819+ virtual ~ColourImpl(); // = default
20820+ /**
20821+ * Creates a guard object for given colour and this colour impl
20822+ *
20823+ * **Important:**
20824+ * the guard starts disengaged, and has to be engaged explicitly.
20825+ */
20826+ ColourGuard guardColour( Colour::Code colourCode );
20827+
20828+ private:
20829+ virtual void use( Colour::Code colourCode ) const = 0;
20830+ };
20831+
20832+ //! Provides ColourImpl based on global config and target compilation platform
20833+ Detail::unique_ptr<ColourImpl> makeColourImpl( ColourMode colourSelection,
20834+ IStream* stream );
20835+
20836+ //! Checks if specific colour impl has been compiled into the binary
20837+ bool isColourImplAvailable( ColourMode colourSelection );
20838+
20839+} // end namespace Catch
20840+
20841+#endif // CATCH_CONSOLE_COLOUR_HPP_INCLUDED
20842+
20843+
20844+#ifndef CATCH_CONSOLE_WIDTH_HPP_INCLUDED
20845+#define CATCH_CONSOLE_WIDTH_HPP_INCLUDED
20846+
20847+// This include must be kept so that user's configured value for CONSOLE_WIDTH
20848+// is used before we attempt to provide a default value
20849+
20850+#ifndef CATCH_CONFIG_CONSOLE_WIDTH
20851+#define CATCH_CONFIG_CONSOLE_WIDTH 80
20852+#endif
20853+
20854+#endif // CATCH_CONSOLE_WIDTH_HPP_INCLUDED
20855+
20856+
20857+#ifndef CATCH_CONTAINER_NONMEMBERS_HPP_INCLUDED
20858+#define CATCH_CONTAINER_NONMEMBERS_HPP_INCLUDED
20859+
20860+
20861+#include <cstddef>
20862+#include <initializer_list>
20863+
20864+// We want a simple polyfill over `std::empty`, `std::size` and so on
20865+// for C++14 or C++ libraries with incomplete support.
20866+// We also have to handle that MSVC std lib will happily provide these
20867+// under older standards.
20868+#if defined(CATCH_CPP17_OR_GREATER) || defined(_MSC_VER)
20869+
20870+// We are already using this header either way, so there shouldn't
20871+// be much additional overhead in including it to get the feature
20872+// test macros
20873+#include <string>
20874+
20875+# if !defined(__cpp_lib_nonmember_container_access)
20876+# define CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS
20877+# endif
20878+
20879+#else
20880+#define CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS
20881+#endif
20882+
20883+
20884+
20885+namespace Catch {
20886+namespace Detail {
20887+
20888+#if defined(CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS)
20889+ template <typename Container>
20890+ constexpr auto empty(Container const& cont) -> decltype(cont.empty()) {
20891+ return cont.empty();
20892+ }
20893+ template <typename T, std::size_t N>
20894+ constexpr bool empty(const T (&)[N]) noexcept {
20895+ // GCC < 7 does not support the const T(&)[] parameter syntax
20896+ // so we have to ignore the length explicitly
20897+ (void)N;
20898+ return false;
20899+ }
20900+ template <typename T>
20901+ constexpr bool empty(std::initializer_list<T> list) noexcept {
20902+ return list.size() > 0;
20903+ }
20904+
20905+
20906+ template <typename Container>
20907+ constexpr auto size(Container const& cont) -> decltype(cont.size()) {
20908+ return cont.size();
20909+ }
20910+ template <typename T, std::size_t N>
20911+ constexpr std::size_t size(const T(&)[N]) noexcept {
20912+ return N;
20913+ }
20914+#endif // CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS
20915+
20916+} // end namespace Detail
20917+} // end namespace Catch
20918+
20919+
20920+
20921+#endif // CATCH_CONTAINER_NONMEMBERS_HPP_INCLUDED
20922+
20923+
20924+#ifndef CATCH_DEBUG_CONSOLE_HPP_INCLUDED
20925+#define CATCH_DEBUG_CONSOLE_HPP_INCLUDED
20926+
20927+#include <string>
20928+
20929+namespace Catch {
20930+ void writeToDebugConsole( std::string const& text );
20931+}
20932+
20933+#endif // CATCH_DEBUG_CONSOLE_HPP_INCLUDED
20934+
20935+
20936+#ifndef CATCH_DEBUGGER_HPP_INCLUDED
20937+#define CATCH_DEBUGGER_HPP_INCLUDED
20938+
20939+
20940+namespace Catch {
20941+ bool isDebuggerActive();
20942+}
20943+
20944+#ifdef CATCH_PLATFORM_MAC
20945+
20946+ #if defined(__i386__) || defined(__x86_64__)
20947+ #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */
20948+ #elif defined(__aarch64__)
20949+ #define CATCH_TRAP() __asm__(".inst 0xd43e0000")
20950+ #elif defined(__POWERPC__)
20951+ #define CATCH_TRAP() __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \
20952+ : : : "memory","r0","r3","r4" ) /* NOLINT */
20953+ #endif
20954+
20955+#elif defined(CATCH_PLATFORM_IPHONE)
20956+
20957+ // use inline assembler
20958+ #if defined(__i386__) || defined(__x86_64__)
20959+ #define CATCH_TRAP() __asm__("int $3")
20960+ #elif defined(__aarch64__)
20961+ #define CATCH_TRAP() __asm__(".inst 0xd4200000")
20962+ #elif defined(__arm__) && !defined(__thumb__)
20963+ #define CATCH_TRAP() __asm__(".inst 0xe7f001f0")
20964+ #elif defined(__arm__) && defined(__thumb__)
20965+ #define CATCH_TRAP() __asm__(".inst 0xde01")
20966+ #endif
20967+
20968+#elif defined(CATCH_PLATFORM_LINUX)
20969+ // If we can use inline assembler, do it because this allows us to break
20970+ // directly at the location of the failing check instead of breaking inside
20971+ // raise() called from it, i.e. one stack frame below.
20972+ #if defined(__GNUC__) && (defined(__i386) || defined(__x86_64))
20973+ #define CATCH_TRAP() asm volatile ("int $3") /* NOLINT */
20974+ #else // Fall back to the generic way.
20975+ #include <signal.h>
20976+
20977+ #define CATCH_TRAP() raise(SIGTRAP)
20978+ #endif
20979+#elif defined(_MSC_VER)
20980+ #define CATCH_TRAP() __debugbreak()
20981+#elif defined(__MINGW32__)
20982+ extern "C" __declspec(dllimport) void __stdcall DebugBreak();
20983+ #define CATCH_TRAP() DebugBreak()
20984+#endif
20985+
20986+#ifndef CATCH_BREAK_INTO_DEBUGGER
20987+ #ifdef CATCH_TRAP
20988+ #define CATCH_BREAK_INTO_DEBUGGER() []{ if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } }()
20989+ #else
20990+ #define CATCH_BREAK_INTO_DEBUGGER() []{}()
20991+ #endif
20992+#endif
20993+
20994+#endif // CATCH_DEBUGGER_HPP_INCLUDED
20995+
20996+
20997+#ifndef CATCH_ENFORCE_HPP_INCLUDED
20998+#define CATCH_ENFORCE_HPP_INCLUDED
20999+
21000+
21001+#include <exception>
21002+
21003+namespace Catch {
21004+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
21005+ template <typename Ex>
21006+ [[noreturn]]
21007+ void throw_exception(Ex const& e) {
21008+ throw e;
21009+ }
21010+#else // ^^ Exceptions are enabled // Exceptions are disabled vv
21011+ [[noreturn]]
21012+ void throw_exception(std::exception const& e);
21013+#endif
21014+
21015+ [[noreturn]]
21016+ void throw_logic_error(std::string const& msg);
21017+ [[noreturn]]
21018+ void throw_domain_error(std::string const& msg);
21019+ [[noreturn]]
21020+ void throw_runtime_error(std::string const& msg);
21021+
21022+} // namespace Catch;
21023+
21024+#define CATCH_MAKE_MSG(...) \
21025+ (Catch::ReusableStringStream() << __VA_ARGS__).str()
21026+
21027+#define CATCH_INTERNAL_ERROR(...) \
21028+ Catch::throw_logic_error(CATCH_MAKE_MSG( CATCH_INTERNAL_LINEINFO << ": Internal Catch2 error: " << __VA_ARGS__))
21029+
21030+#define CATCH_ERROR(...) \
21031+ Catch::throw_domain_error(CATCH_MAKE_MSG( __VA_ARGS__ ))
21032+
21033+#define CATCH_RUNTIME_ERROR(...) \
21034+ Catch::throw_runtime_error(CATCH_MAKE_MSG( __VA_ARGS__ ))
21035+
21036+#define CATCH_ENFORCE( condition, ... ) \
21037+ do{ if( !(condition) ) CATCH_ERROR( __VA_ARGS__ ); } while(false)
21038+
21039+
21040+#endif // CATCH_ENFORCE_HPP_INCLUDED
21041+
21042+
21043+#ifndef CATCH_ENUM_VALUES_REGISTRY_HPP_INCLUDED
21044+#define CATCH_ENUM_VALUES_REGISTRY_HPP_INCLUDED
21045+
21046+
21047+#include <vector>
21048+
21049+namespace Catch {
21050+
21051+ namespace Detail {
21052+
21053+ Catch::Detail::unique_ptr<EnumInfo> makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int> const& values );
21054+
21055+ class EnumValuesRegistry : public IMutableEnumValuesRegistry {
21056+
21057+ std::vector<Catch::Detail::unique_ptr<EnumInfo>> m_enumInfos;
21058+
21059+ EnumInfo const& registerEnum( StringRef enumName, StringRef allValueNames, std::vector<int> const& values) override;
21060+ };
21061+
21062+ std::vector<StringRef> parseEnums( StringRef enums );
21063+
21064+ } // Detail
21065+
21066+} // Catch
21067+
21068+#endif // CATCH_ENUM_VALUES_REGISTRY_HPP_INCLUDED
21069+
21070+
21071+#ifndef CATCH_ERRNO_GUARD_HPP_INCLUDED
21072+#define CATCH_ERRNO_GUARD_HPP_INCLUDED
21073+
21074+namespace Catch {
21075+
21076+ //! Simple RAII class that stores the value of `errno`
21077+ //! at construction and restores it at destruction.
21078+ class ErrnoGuard {
21079+ public:
21080+ // Keep these outlined to avoid dragging in macros from <cerrno>
21081+
21082+ ErrnoGuard();
21083+ ~ErrnoGuard();
21084+ private:
21085+ int m_oldErrno;
21086+ };
21087+
21088+}
21089+
21090+#endif // CATCH_ERRNO_GUARD_HPP_INCLUDED
21091+
21092+
21093+#ifndef CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED
21094+#define CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED
21095+
21096+
21097+#include <vector>
21098+#include <string>
21099+
21100+namespace Catch {
21101+
21102+ class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry {
21103+ public:
21104+ ~ExceptionTranslatorRegistry() override;
21105+ void registerTranslator( Detail::unique_ptr<IExceptionTranslator>&& translator );
21106+ std::string translateActiveException() const override;
21107+
21108+ private:
21109+ ExceptionTranslators m_translators;
21110+ };
21111+}
21112+
21113+#endif // CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED
21114+
21115+
21116+#ifndef CATCH_FATAL_CONDITION_HANDLER_HPP_INCLUDED
21117+#define CATCH_FATAL_CONDITION_HANDLER_HPP_INCLUDED
21118+
21119+#include <cassert>
21120+
21121+namespace Catch {
21122+
21123+ /**
21124+ * Wrapper for platform-specific fatal error (signals/SEH) handlers
21125+ *
21126+ * Tries to be cooperative with other handlers, and not step over
21127+ * other handlers. This means that unknown structured exceptions
21128+ * are passed on, previous signal handlers are called, and so on.
21129+ *
21130+ * Can only be instantiated once, and assumes that once a signal
21131+ * is caught, the binary will end up terminating. Thus, there
21132+ */
21133+ class FatalConditionHandler {
21134+ bool m_started = false;
21135+
21136+ // Install/disengage implementation for specific platform.
21137+ // Should be if-defed to work on current platform, can assume
21138+ // engage-disengage 1:1 pairing.
21139+ void engage_platform();
21140+ void disengage_platform() noexcept;
21141+ public:
21142+ // Should also have platform-specific implementations as needed
21143+ FatalConditionHandler();
21144+ ~FatalConditionHandler();
21145+
21146+ void engage() {
21147+ assert(!m_started && "Handler cannot be installed twice.");
21148+ m_started = true;
21149+ engage_platform();
21150+ }
21151+
21152+ void disengage() noexcept {
21153+ assert(m_started && "Handler cannot be uninstalled without being installed first");
21154+ m_started = false;
21155+ disengage_platform();
21156+ }
21157+ };
21158+
21159+ //! Simple RAII guard for (dis)engaging the FatalConditionHandler
21160+ class FatalConditionHandlerGuard {
21161+ FatalConditionHandler* m_handler;
21162+ public:
21163+ FatalConditionHandlerGuard(FatalConditionHandler* handler):
21164+ m_handler(handler) {
21165+ m_handler->engage();
21166+ }
21167+ ~FatalConditionHandlerGuard() {
21168+ m_handler->disengage();
21169+ }
21170+ };
21171+
21172+} // end namespace Catch
21173+
21174+#endif // CATCH_FATAL_CONDITION_HANDLER_HPP_INCLUDED
21175+
21176+
21177+#ifndef CATCH_FLOATING_POINT_HELPERS_HPP_INCLUDED
21178+#define CATCH_FLOATING_POINT_HELPERS_HPP_INCLUDED
21179+
21180+
21181+#include <cassert>
21182+#include <cmath>
21183+#include <cstdint>
21184+#include <utility>
21185+#include <limits>
21186+
21187+namespace Catch {
21188+ namespace Detail {
21189+
21190+ uint32_t convertToBits(float f);
21191+ uint64_t convertToBits(double d);
21192+
21193+ // Used when we know we want == comparison of two doubles
21194+ // to centralize warning suppression
21195+ bool directCompare( float lhs, float rhs );
21196+ bool directCompare( double lhs, double rhs );
21197+
21198+ } // end namespace Detail
21199+
21200+
21201+
21202+#if defined( __GNUC__ ) || defined( __clang__ )
21203+# pragma GCC diagnostic push
21204+ // We do a bunch of direct compensations of floating point numbers,
21205+ // because we know what we are doing and actually do want the direct
21206+ // comparison behaviour.
21207+# pragma GCC diagnostic ignored "-Wfloat-equal"
21208+#endif
21209+
21210+ /**
21211+ * Calculates the ULP distance between two floating point numbers
21212+ *
21213+ * The ULP distance of two floating point numbers is the count of
21214+ * valid floating point numbers representable between them.
21215+ *
21216+ * There are some exceptions between how this function counts the
21217+ * distance, and the interpretation of the standard as implemented.
21218+ * by e.g. `nextafter`. For this function it always holds that:
21219+ * * `(x == y) => ulpDistance(x, y) == 0` (so `ulpDistance(-0, 0) == 0`)
21220+ * * `ulpDistance(maxFinite, INF) == 1`
21221+ * * `ulpDistance(x, -x) == 2 * ulpDistance(x, 0)`
21222+ *
21223+ * \pre `!isnan( lhs )`
21224+ * \pre `!isnan( rhs )`
21225+ * \pre floating point numbers are represented in IEEE-754 format
21226+ */
21227+ template <typename FP>
21228+ uint64_t ulpDistance( FP lhs, FP rhs ) {
21229+ assert( std::numeric_limits<FP>::is_iec559 &&
21230+ "ulpDistance assumes IEEE-754 format for floating point types" );
21231+ assert( !Catch::isnan( lhs ) &&
21232+ "Distance between NaN and number is not meaningful" );
21233+ assert( !Catch::isnan( rhs ) &&
21234+ "Distance between NaN and number is not meaningful" );
21235+
21236+ // We want X == Y to imply 0 ULP distance even if X and Y aren't
21237+ // bit-equal (-0 and 0), or X - Y != 0 (same sign infinities).
21238+ if ( lhs == rhs ) { return 0; }
21239+
21240+ // We need a properly typed positive zero for type inference.
21241+ static constexpr FP positive_zero{};
21242+
21243+ // We want to ensure that +/- 0 is always represented as positive zero
21244+ if ( lhs == positive_zero ) { lhs = positive_zero; }
21245+ if ( rhs == positive_zero ) { rhs = positive_zero; }
21246+
21247+ // If arguments have different signs, we can handle them by summing
21248+ // how far are they from 0 each.
21249+ if ( std::signbit( lhs ) != std::signbit( rhs ) ) {
21250+ return ulpDistance( std::abs( lhs ), positive_zero ) +
21251+ ulpDistance( std::abs( rhs ), positive_zero );
21252+ }
21253+
21254+ // When both lhs and rhs are of the same sign, we can just
21255+ // read the numbers bitwise as integers, and then subtract them
21256+ // (assuming IEEE).
21257+ uint64_t lc = Detail::convertToBits( lhs );
21258+ uint64_t rc = Detail::convertToBits( rhs );
21259+
21260+ // The ulp distance between two numbers is symmetric, so to avoid
21261+ // dealing with overflows we want the bigger converted number on the lhs
21262+ if ( lc < rc ) {
21263+ std::swap( lc, rc );
21264+ }
21265+
21266+ return lc - rc;
21267+ }
21268+
21269+#if defined( __GNUC__ ) || defined( __clang__ )
21270+# pragma GCC diagnostic pop
21271+#endif
21272+
21273+
21274+} // end namespace Catch
21275+
21276+#endif // CATCH_FLOATING_POINT_HELPERS_HPP_INCLUDED
21277+
21278+
21279+#ifndef CATCH_GETENV_HPP_INCLUDED
21280+#define CATCH_GETENV_HPP_INCLUDED
21281+
21282+namespace Catch {
21283+namespace Detail {
21284+
21285+ //! Wrapper over `std::getenv` that compiles on UWP (and always returns nullptr there)
21286+ char const* getEnv(char const* varName);
21287+
21288+}
21289+}
21290+
21291+#endif // CATCH_GETENV_HPP_INCLUDED
21292+
21293+
21294+#ifndef CATCH_IS_PERMUTATION_HPP_INCLUDED
21295+#define CATCH_IS_PERMUTATION_HPP_INCLUDED
21296+
21297+#include <algorithm>
21298+#include <iterator>
21299+
21300+namespace Catch {
21301+ namespace Detail {
21302+
21303+ template <typename ForwardIter,
21304+ typename Sentinel,
21305+ typename T,
21306+ typename Comparator>
21307+ ForwardIter find_sentinel( ForwardIter start,
21308+ Sentinel sentinel,
21309+ T const& value,
21310+ Comparator cmp ) {
21311+ while ( start != sentinel ) {
21312+ if ( cmp( *start, value ) ) { break; }
21313+ ++start;
21314+ }
21315+ return start;
21316+ }
21317+
21318+ template <typename ForwardIter,
21319+ typename Sentinel,
21320+ typename T,
21321+ typename Comparator>
21322+ std::ptrdiff_t count_sentinel( ForwardIter start,
21323+ Sentinel sentinel,
21324+ T const& value,
21325+ Comparator cmp ) {
21326+ std::ptrdiff_t count = 0;
21327+ while ( start != sentinel ) {
21328+ if ( cmp( *start, value ) ) { ++count; }
21329+ ++start;
21330+ }
21331+ return count;
21332+ }
21333+
21334+ template <typename ForwardIter, typename Sentinel>
21335+ std::enable_if_t<!std::is_same<ForwardIter, Sentinel>::value,
21336+ std::ptrdiff_t>
21337+ sentinel_distance( ForwardIter iter, const Sentinel sentinel ) {
21338+ std::ptrdiff_t dist = 0;
21339+ while ( iter != sentinel ) {
21340+ ++iter;
21341+ ++dist;
21342+ }
21343+ return dist;
21344+ }
21345+
21346+ template <typename ForwardIter>
21347+ std::ptrdiff_t sentinel_distance( ForwardIter first,
21348+ ForwardIter last ) {
21349+ return std::distance( first, last );
21350+ }
21351+
21352+ template <typename ForwardIter1,
21353+ typename Sentinel1,
21354+ typename ForwardIter2,
21355+ typename Sentinel2,
21356+ typename Comparator>
21357+ bool check_element_counts( ForwardIter1 first_1,
21358+ const Sentinel1 end_1,
21359+ ForwardIter2 first_2,
21360+ const Sentinel2 end_2,
21361+ Comparator cmp ) {
21362+ auto cursor = first_1;
21363+ while ( cursor != end_1 ) {
21364+ if ( find_sentinel( first_1, cursor, *cursor, cmp ) ==
21365+ cursor ) {
21366+ // we haven't checked this element yet
21367+ const auto count_in_range_2 =
21368+ count_sentinel( first_2, end_2, *cursor, cmp );
21369+ // Not a single instance in 2nd range, so it cannot be a
21370+ // permutation of 1st range
21371+ if ( count_in_range_2 == 0 ) { return false; }
21372+
21373+ const auto count_in_range_1 =
21374+ count_sentinel( cursor, end_1, *cursor, cmp );
21375+ if ( count_in_range_1 != count_in_range_2 ) {
21376+ return false;
21377+ }
21378+ }
21379+
21380+ ++cursor;
21381+ }
21382+
21383+ return true;
21384+ }
21385+
21386+ template <typename ForwardIter1,
21387+ typename Sentinel1,
21388+ typename ForwardIter2,
21389+ typename Sentinel2,
21390+ typename Comparator>
21391+ bool is_permutation( ForwardIter1 first_1,
21392+ const Sentinel1 end_1,
21393+ ForwardIter2 first_2,
21394+ const Sentinel2 end_2,
21395+ Comparator cmp ) {
21396+ // TODO: no optimization for stronger iterators, because we would also have to constrain on sentinel vs not sentinel types
21397+ // TODO: Comparator has to be "both sides", e.g. a == b => b == a
21398+ // This skips shared prefix of the two ranges
21399+ while (first_1 != end_1 && first_2 != end_2 && cmp(*first_1, *first_2)) {
21400+ ++first_1;
21401+ ++first_2;
21402+ }
21403+
21404+ // We need to handle case where at least one of the ranges has no more elements
21405+ if (first_1 == end_1 || first_2 == end_2) {
21406+ return first_1 == end_1 && first_2 == end_2;
21407+ }
21408+
21409+ // pair counting is n**2, so we pay linear walk to compare the sizes first
21410+ auto dist_1 = sentinel_distance( first_1, end_1 );
21411+ auto dist_2 = sentinel_distance( first_2, end_2 );
21412+
21413+ if (dist_1 != dist_2) { return false; }
21414+
21415+ // Since we do not try to handle stronger iterators pair (e.g.
21416+ // bidir) optimally, the only thing left to do is to check counts in
21417+ // the remaining ranges.
21418+ return check_element_counts( first_1, end_1, first_2, end_2, cmp );
21419+ }
21420+
21421+ } // namespace Detail
21422+} // namespace Catch
21423+
21424+#endif // CATCH_IS_PERMUTATION_HPP_INCLUDED
21425+
21426+
21427+#ifndef CATCH_ISTREAM_HPP_INCLUDED
21428+#define CATCH_ISTREAM_HPP_INCLUDED
21429+
21430+
21431+#include <iosfwd>
21432+#include <cstddef>
21433+#include <ostream>
21434+#include <string>
21435+
21436+namespace Catch {
21437+
21438+ class IStream {
21439+ public:
21440+ virtual ~IStream(); // = default
21441+ virtual std::ostream& stream() = 0;
21442+ /**
21443+ * Best guess on whether the instance is writing to a console (e.g. via stdout/stderr)
21444+ *
21445+ * This is useful for e.g. Win32 colour support, because the Win32
21446+ * API manipulates console directly, unlike POSIX escape codes,
21447+ * that can be written anywhere.
21448+ *
21449+ * Due to variety of ways to change where the stdout/stderr is
21450+ * _actually_ being written, users should always assume that
21451+ * the answer might be wrong.
21452+ */
21453+ virtual bool isConsole() const { return false; }
21454+ };
21455+
21456+ /**
21457+ * Creates a stream wrapper that writes to specific file.
21458+ *
21459+ * Also recognizes 4 special filenames
21460+ * * `-` for stdout
21461+ * * `%stdout` for stdout
21462+ * * `%stderr` for stderr
21463+ * * `%debug` for platform specific debugging output
21464+ *
21465+ * \throws if passed an unrecognized %-prefixed stream
21466+ */
21467+ auto makeStream( std::string const& filename ) -> Detail::unique_ptr<IStream>;
21468+
21469+}
21470+
21471+#endif // CATCH_STREAM_HPP_INCLUDED
21472+
21473+
21474+#ifndef CATCH_JSONWRITER_HPP_INCLUDED
21475+#define CATCH_JSONWRITER_HPP_INCLUDED
21476+
21477+
21478+#include <cstdint>
21479+#include <sstream>
21480+
21481+namespace Catch {
21482+ class JsonObjectWriter;
21483+ class JsonArrayWriter;
21484+
21485+ struct JsonUtils {
21486+ static void indent( std::ostream& os, std::uint64_t level );
21487+ static void appendCommaNewline( std::ostream& os,
21488+ bool& should_comma,
21489+ std::uint64_t level );
21490+ };
21491+
21492+ class JsonValueWriter {
21493+ public:
21494+ JsonValueWriter( std::ostream& os );
21495+ JsonValueWriter( std::ostream& os, std::uint64_t indent_level );
21496+
21497+ JsonObjectWriter writeObject() &&;
21498+ JsonArrayWriter writeArray() &&;
21499+
21500+ template <typename T>
21501+ void write( T const& value ) && {
21502+ writeImpl( value, !std::is_arithmetic<T>::value );
21503+ }
21504+ void write( StringRef value ) &&;
21505+ void write( bool value ) &&;
21506+
21507+ private:
21508+ void writeImpl( StringRef value, bool quote );
21509+
21510+ // Without this SFINAE, this overload is a better match
21511+ // for `std::string`, `char const*`, `char const[N]` args.
21512+ // While it would still work, it would cause code bloat
21513+ // and multiple iteration over the strings
21514+ template <typename T,
21515+ typename = typename std::enable_if_t<
21516+ !std::is_convertible<T, StringRef>::value>>
21517+ void writeImpl( T const& value, bool quote_value ) {
21518+ m_sstream << value;
21519+ writeImpl( m_sstream.str(), quote_value );
21520+ }
21521+
21522+ std::ostream& m_os;
21523+ std::stringstream m_sstream;
21524+ std::uint64_t m_indent_level;
21525+ };
21526+
21527+ class JsonObjectWriter {
21528+ public:
21529+ JsonObjectWriter( std::ostream& os );
21530+ JsonObjectWriter( std::ostream& os, std::uint64_t indent_level );
21531+
21532+ JsonObjectWriter( JsonObjectWriter&& source ) noexcept;
21533+ JsonObjectWriter& operator=( JsonObjectWriter&& source ) = delete;
21534+
21535+ ~JsonObjectWriter();
21536+
21537+ JsonValueWriter write( StringRef key );
21538+
21539+ private:
21540+ std::ostream& m_os;
21541+ std::uint64_t m_indent_level;
21542+ bool m_should_comma = false;
21543+ bool m_active = true;
21544+ };
21545+
21546+ class JsonArrayWriter {
21547+ public:
21548+ JsonArrayWriter( std::ostream& os );
21549+ JsonArrayWriter( std::ostream& os, std::uint64_t indent_level );
21550+
21551+ JsonArrayWriter( JsonArrayWriter&& source ) noexcept;
21552+ JsonArrayWriter& operator=( JsonArrayWriter&& source ) = delete;
21553+
21554+ ~JsonArrayWriter();
21555+
21556+ JsonObjectWriter writeObject();
21557+ JsonArrayWriter writeArray();
21558+
21559+ template <typename T>
21560+ JsonArrayWriter& write( T const& value ) {
21561+ return writeImpl( value );
21562+ }
21563+
21564+ JsonArrayWriter& write( bool value );
21565+
21566+ private:
21567+ template <typename T>
21568+ JsonArrayWriter& writeImpl( T const& value ) {
21569+ JsonUtils::appendCommaNewline(
21570+ m_os, m_should_comma, m_indent_level + 1 );
21571+ JsonValueWriter{ m_os }.write( value );
21572+
21573+ return *this;
21574+ }
21575+
21576+ std::ostream& m_os;
21577+ std::uint64_t m_indent_level;
21578+ bool m_should_comma = false;
21579+ bool m_active = true;
21580+ };
21581+
21582+} // namespace Catch
21583+
21584+#endif // CATCH_JSONWRITER_HPP_INCLUDED
21585+
21586+
21587+#ifndef CATCH_LEAK_DETECTOR_HPP_INCLUDED
21588+#define CATCH_LEAK_DETECTOR_HPP_INCLUDED
21589+
21590+namespace Catch {
21591+
21592+ struct LeakDetector {
21593+ LeakDetector();
21594+ ~LeakDetector();
21595+ };
21596+
21597+}
21598+#endif // CATCH_LEAK_DETECTOR_HPP_INCLUDED
21599+
21600+
21601+#ifndef CATCH_LIST_HPP_INCLUDED
21602+#define CATCH_LIST_HPP_INCLUDED
21603+
21604+
21605+#include <set>
21606+#include <string>
21607+
21608+
21609+namespace Catch {
21610+
21611+ class IEventListener;
21612+ class Config;
21613+
21614+
21615+ struct ReporterDescription {
21616+ std::string name, description;
21617+ };
21618+ struct ListenerDescription {
21619+ StringRef name;
21620+ std::string description;
21621+ };
21622+
21623+ struct TagInfo {
21624+ void add(StringRef spelling);
21625+ std::string all() const;
21626+
21627+ std::set<StringRef> spellings;
21628+ std::size_t count = 0;
21629+ };
21630+
21631+ bool list( IEventListener& reporter, Config const& config );
21632+
21633+} // end namespace Catch
21634+
21635+#endif // CATCH_LIST_HPP_INCLUDED
21636+
21637+
21638+#ifndef CATCH_OUTPUT_REDIRECT_HPP_INCLUDED
21639+#define CATCH_OUTPUT_REDIRECT_HPP_INCLUDED
21640+
21641+
21642+#include <cstdio>
21643+#include <iosfwd>
21644+#include <string>
21645+
21646+namespace Catch {
21647+
21648+ class RedirectedStream {
21649+ std::ostream& m_originalStream;
21650+ std::ostream& m_redirectionStream;
21651+ std::streambuf* m_prevBuf;
21652+
21653+ public:
21654+ RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream );
21655+ ~RedirectedStream();
21656+ };
21657+
21658+ class RedirectedStdOut {
21659+ ReusableStringStream m_rss;
21660+ RedirectedStream m_cout;
21661+ public:
21662+ RedirectedStdOut();
21663+ auto str() const -> std::string;
21664+ };
21665+
21666+ // StdErr has two constituent streams in C++, std::cerr and std::clog
21667+ // This means that we need to redirect 2 streams into 1 to keep proper
21668+ // order of writes
21669+ class RedirectedStdErr {
21670+ ReusableStringStream m_rss;
21671+ RedirectedStream m_cerr;
21672+ RedirectedStream m_clog;
21673+ public:
21674+ RedirectedStdErr();
21675+ auto str() const -> std::string;
21676+ };
21677+
21678+ class RedirectedStreams {
21679+ public:
21680+ RedirectedStreams(RedirectedStreams const&) = delete;
21681+ RedirectedStreams& operator=(RedirectedStreams const&) = delete;
21682+ RedirectedStreams(RedirectedStreams&&) = delete;
21683+ RedirectedStreams& operator=(RedirectedStreams&&) = delete;
21684+
21685+ RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr);
21686+ ~RedirectedStreams();
21687+ private:
21688+ std::string& m_redirectedCout;
21689+ std::string& m_redirectedCerr;
21690+ RedirectedStdOut m_redirectedStdOut;
21691+ RedirectedStdErr m_redirectedStdErr;
21692+ };
21693+
21694+#if defined(CATCH_CONFIG_NEW_CAPTURE)
21695+
21696+ // Windows's implementation of std::tmpfile is terrible (it tries
21697+ // to create a file inside system folder, thus requiring elevated
21698+ // privileges for the binary), so we have to use tmpnam(_s) and
21699+ // create the file ourselves there.
21700+ class TempFile {
21701+ public:
21702+ TempFile(TempFile const&) = delete;
21703+ TempFile& operator=(TempFile const&) = delete;
21704+ TempFile(TempFile&&) = delete;
21705+ TempFile& operator=(TempFile&&) = delete;
21706+
21707+ TempFile();
21708+ ~TempFile();
21709+
21710+ std::FILE* getFile();
21711+ std::string getContents();
21712+
21713+ private:
21714+ std::FILE* m_file = nullptr;
21715+ #if defined(_MSC_VER)
21716+ char m_buffer[L_tmpnam] = { 0 };
21717+ #endif
21718+ };
21719+
21720+
21721+ class OutputRedirect {
21722+ public:
21723+ OutputRedirect(OutputRedirect const&) = delete;
21724+ OutputRedirect& operator=(OutputRedirect const&) = delete;
21725+ OutputRedirect(OutputRedirect&&) = delete;
21726+ OutputRedirect& operator=(OutputRedirect&&) = delete;
21727+
21728+
21729+ OutputRedirect(std::string& stdout_dest, std::string& stderr_dest);
21730+ ~OutputRedirect();
21731+
21732+ private:
21733+ int m_originalStdout = -1;
21734+ int m_originalStderr = -1;
21735+ TempFile m_stdoutFile;
21736+ TempFile m_stderrFile;
21737+ std::string& m_stdoutDest;
21738+ std::string& m_stderrDest;
21739+ };
21740+
21741+#endif
21742+
21743+} // end namespace Catch
21744+
21745+#endif // CATCH_OUTPUT_REDIRECT_HPP_INCLUDED
21746+
21747+
21748+#ifndef CATCH_PARSE_NUMBERS_HPP_INCLUDED
21749+#define CATCH_PARSE_NUMBERS_HPP_INCLUDED
21750+
21751+
21752+#include <string>
21753+
21754+namespace Catch {
21755+
21756+ /**
21757+ * Parses unsigned int from the input, using provided base
21758+ *
21759+ * Effectively a wrapper around std::stoul but with better error checking
21760+ * e.g. "-1" is rejected, instead of being parsed as UINT_MAX.
21761+ */
21762+ Optional<unsigned int> parseUInt(std::string const& input, int base = 10);
21763+}
21764+
21765+#endif // CATCH_PARSE_NUMBERS_HPP_INCLUDED
21766+
21767+
21768+#ifndef CATCH_REPORTER_REGISTRY_HPP_INCLUDED
21769+#define CATCH_REPORTER_REGISTRY_HPP_INCLUDED
21770+
21771+
21772+#include <map>
21773+#include <string>
21774+#include <vector>
21775+
21776+namespace Catch {
21777+
21778+ class IEventListener;
21779+ using IEventListenerPtr = Detail::unique_ptr<IEventListener>;
21780+ class IReporterFactory;
21781+ using IReporterFactoryPtr = Detail::unique_ptr<IReporterFactory>;
21782+ struct ReporterConfig;
21783+ class EventListenerFactory;
21784+
21785+ class ReporterRegistry {
21786+ struct ReporterRegistryImpl;
21787+ Detail::unique_ptr<ReporterRegistryImpl> m_impl;
21788+
21789+ public:
21790+ ReporterRegistry();
21791+ ~ReporterRegistry(); // = default;
21792+
21793+ IEventListenerPtr create( std::string const& name,
21794+ ReporterConfig&& config ) const;
21795+
21796+ void registerReporter( std::string const& name,
21797+ IReporterFactoryPtr factory );
21798+
21799+ void
21800+ registerListener( Detail::unique_ptr<EventListenerFactory> factory );
21801+
21802+ std::map<std::string,
21803+ IReporterFactoryPtr,
21804+ Detail::CaseInsensitiveLess> const&
21805+ getFactories() const;
21806+
21807+ std::vector<Detail::unique_ptr<EventListenerFactory>> const&
21808+ getListeners() const;
21809+ };
21810+
21811+} // end namespace Catch
21812+
21813+#endif // CATCH_REPORTER_REGISTRY_HPP_INCLUDED
21814+
21815+
21816+#ifndef CATCH_RUN_CONTEXT_HPP_INCLUDED
21817+#define CATCH_RUN_CONTEXT_HPP_INCLUDED
21818+
21819+
21820+
21821+#ifndef CATCH_TEST_CASE_TRACKER_HPP_INCLUDED
21822+#define CATCH_TEST_CASE_TRACKER_HPP_INCLUDED
21823+
21824+
21825+#include <string>
21826+#include <vector>
21827+
21828+namespace Catch {
21829+namespace TestCaseTracking {
21830+
21831+ struct NameAndLocation {
21832+ std::string name;
21833+ SourceLineInfo location;
21834+
21835+ NameAndLocation( std::string&& _name, SourceLineInfo const& _location );
21836+ friend bool operator==(NameAndLocation const& lhs, NameAndLocation const& rhs) {
21837+ // This is a very cheap check that should have a very high hit rate.
21838+ // If we get to SourceLineInfo::operator==, we will redo it, but the
21839+ // cost of repeating is trivial at that point (we will be paying
21840+ // multiple strcmp/memcmps at that point).
21841+ if ( lhs.location.line != rhs.location.line ) { return false; }
21842+ return lhs.name == rhs.name && lhs.location == rhs.location;
21843+ }
21844+ friend bool operator!=(NameAndLocation const& lhs,
21845+ NameAndLocation const& rhs) {
21846+ return !( lhs == rhs );
21847+ }
21848+ };
21849+
21850+ /**
21851+ * This is a variant of `NameAndLocation` that does not own the name string
21852+ *
21853+ * This avoids extra allocations when trying to locate a tracker by its
21854+ * name and location, as long as we make sure that trackers only keep
21855+ * around the owning variant.
21856+ */
21857+ struct NameAndLocationRef {
21858+ StringRef name;
21859+ SourceLineInfo location;
21860+
21861+ constexpr NameAndLocationRef( StringRef name_,
21862+ SourceLineInfo location_ ):
21863+ name( name_ ), location( location_ ) {}
21864+
21865+ friend bool operator==( NameAndLocation const& lhs,
21866+ NameAndLocationRef const& rhs ) {
21867+ // This is a very cheap check that should have a very high hit rate.
21868+ // If we get to SourceLineInfo::operator==, we will redo it, but the
21869+ // cost of repeating is trivial at that point (we will be paying
21870+ // multiple strcmp/memcmps at that point).
21871+ if ( lhs.location.line != rhs.location.line ) { return false; }
21872+ return StringRef( lhs.name ) == rhs.name &&
21873+ lhs.location == rhs.location;
21874+ }
21875+ friend bool operator==( NameAndLocationRef const& lhs,
21876+ NameAndLocation const& rhs ) {
21877+ return rhs == lhs;
21878+ }
21879+ };
21880+
21881+ class ITracker;
21882+
21883+ using ITrackerPtr = Catch::Detail::unique_ptr<ITracker>;
21884+
21885+ class ITracker {
21886+ NameAndLocation m_nameAndLocation;
21887+
21888+ using Children = std::vector<ITrackerPtr>;
21889+
21890+ protected:
21891+ enum CycleState {
21892+ NotStarted,
21893+ Executing,
21894+ ExecutingChildren,
21895+ NeedsAnotherRun,
21896+ CompletedSuccessfully,
21897+ Failed
21898+ };
21899+
21900+ ITracker* m_parent = nullptr;
21901+ Children m_children;
21902+ CycleState m_runState = NotStarted;
21903+
21904+ public:
21905+ ITracker( NameAndLocation&& nameAndLoc, ITracker* parent ):
21906+ m_nameAndLocation( CATCH_MOVE(nameAndLoc) ),
21907+ m_parent( parent )
21908+ {}
21909+
21910+
21911+ // static queries
21912+ NameAndLocation const& nameAndLocation() const {
21913+ return m_nameAndLocation;
21914+ }
21915+ ITracker* parent() const {
21916+ return m_parent;
21917+ }
21918+
21919+ virtual ~ITracker(); // = default
21920+
21921+
21922+ // dynamic queries
21923+
21924+ //! Returns true if tracker run to completion (successfully or not)
21925+ virtual bool isComplete() const = 0;
21926+ //! Returns true if tracker run to completion successfully
21927+ bool isSuccessfullyCompleted() const {
21928+ return m_runState == CompletedSuccessfully;
21929+ }
21930+ //! Returns true if tracker has started but hasn't been completed
21931+ bool isOpen() const;
21932+ //! Returns true iff tracker has started
21933+ bool hasStarted() const;
21934+
21935+ // actions
21936+ virtual void close() = 0; // Successfully complete
21937+ virtual void fail() = 0;
21938+ void markAsNeedingAnotherRun();
21939+
21940+ //! Register a nested ITracker
21941+ void addChild( ITrackerPtr&& child );
21942+ /**
21943+ * Returns ptr to specific child if register with this tracker.
21944+ *
21945+ * Returns nullptr if not found.
21946+ */
21947+ ITracker* findChild( NameAndLocationRef const& nameAndLocation );
21948+ //! Have any children been added?
21949+ bool hasChildren() const {
21950+ return !m_children.empty();
21951+ }
21952+
21953+
21954+ //! Marks tracker as executing a child, doing se recursively up the tree
21955+ void openChild();
21956+
21957+ /**
21958+ * Returns true if the instance is a section tracker
21959+ *
21960+ * Subclasses should override to true if they are, replaces RTTI
21961+ * for internal debug checks.
21962+ */
21963+ virtual bool isSectionTracker() const;
21964+ /**
21965+ * Returns true if the instance is a generator tracker
21966+ *
21967+ * Subclasses should override to true if they are, replaces RTTI
21968+ * for internal debug checks.
21969+ */
21970+ virtual bool isGeneratorTracker() const;
21971+ };
21972+
21973+ class TrackerContext {
21974+
21975+ enum RunState {
21976+ NotStarted,
21977+ Executing,
21978+ CompletedCycle
21979+ };
21980+
21981+ ITrackerPtr m_rootTracker;
21982+ ITracker* m_currentTracker = nullptr;
21983+ RunState m_runState = NotStarted;
21984+
21985+ public:
21986+
21987+ ITracker& startRun();
21988+
21989+ void startCycle() {
21990+ m_currentTracker = m_rootTracker.get();
21991+ m_runState = Executing;
21992+ }
21993+ void completeCycle();
21994+
21995+ bool completedCycle() const;
21996+ ITracker& currentTracker() { return *m_currentTracker; }
21997+ void setCurrentTracker( ITracker* tracker );
21998+ };
21999+
22000+ class TrackerBase : public ITracker {
22001+ protected:
22002+
22003+ TrackerContext& m_ctx;
22004+
22005+ public:
22006+ TrackerBase( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent );
22007+
22008+ bool isComplete() const override;
22009+
22010+ void open();
22011+
22012+ void close() override;
22013+ void fail() override;
22014+
22015+ private:
22016+ void moveToParent();
22017+ void moveToThis();
22018+ };
22019+
22020+ class SectionTracker : public TrackerBase {
22021+ std::vector<StringRef> m_filters;
22022+ // Note that lifetime-wise we piggy back off the name stored in the `ITracker` parent`.
22023+ // Currently it allocates owns the name, so this is safe. If it is later refactored
22024+ // to not own the name, the name still has to outlive the `ITracker` parent, so
22025+ // this should still be safe.
22026+ StringRef m_trimmed_name;
22027+ public:
22028+ SectionTracker( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent );
22029+
22030+ bool isSectionTracker() const override;
22031+
22032+ bool isComplete() const override;
22033+
22034+ static SectionTracker& acquire( TrackerContext& ctx, NameAndLocationRef const& nameAndLocation );
22035+
22036+ void tryOpen();
22037+
22038+ void addInitialFilters( std::vector<std::string> const& filters );
22039+ void addNextFilters( std::vector<StringRef> const& filters );
22040+ //! Returns filters active in this tracker
22041+ std::vector<StringRef> const& getFilters() const { return m_filters; }
22042+ //! Returns whitespace-trimmed name of the tracked section
22043+ StringRef trimmedName() const;
22044+ };
22045+
22046+} // namespace TestCaseTracking
22047+
22048+using TestCaseTracking::ITracker;
22049+using TestCaseTracking::TrackerContext;
22050+using TestCaseTracking::SectionTracker;
22051+
22052+} // namespace Catch
22053+
22054+#endif // CATCH_TEST_CASE_TRACKER_HPP_INCLUDED
22055+
22056+#include <string>
22057+
22058+namespace Catch {
22059+
22060+ class IGeneratorTracker;
22061+ class IConfig;
22062+ class IEventListener;
22063+ using IEventListenerPtr = Detail::unique_ptr<IEventListener>;
22064+
22065+ ///////////////////////////////////////////////////////////////////////////
22066+
22067+ class RunContext final : public IResultCapture {
22068+
22069+ public:
22070+ RunContext( RunContext const& ) = delete;
22071+ RunContext& operator =( RunContext const& ) = delete;
22072+
22073+ explicit RunContext( IConfig const* _config, IEventListenerPtr&& reporter );
22074+
22075+ ~RunContext() override;
22076+
22077+ Totals runTest(TestCaseHandle const& testCase);
22078+
22079+ public: // IResultCapture
22080+
22081+ // Assertion handlers
22082+ void handleExpr
22083+ ( AssertionInfo const& info,
22084+ ITransientExpression const& expr,
22085+ AssertionReaction& reaction ) override;
22086+ void handleMessage
22087+ ( AssertionInfo const& info,
22088+ ResultWas::OfType resultType,
22089+ StringRef message,
22090+ AssertionReaction& reaction ) override;
22091+ void handleUnexpectedExceptionNotThrown
22092+ ( AssertionInfo const& info,
22093+ AssertionReaction& reaction ) override;
22094+ void handleUnexpectedInflightException
22095+ ( AssertionInfo const& info,
22096+ std::string&& message,
22097+ AssertionReaction& reaction ) override;
22098+ void handleIncomplete
22099+ ( AssertionInfo const& info ) override;
22100+ void handleNonExpr
22101+ ( AssertionInfo const &info,
22102+ ResultWas::OfType resultType,
22103+ AssertionReaction &reaction ) override;
22104+
22105+ void notifyAssertionStarted( AssertionInfo const& info ) override;
22106+ bool sectionStarted( StringRef sectionName,
22107+ SourceLineInfo const& sectionLineInfo,
22108+ Counts& assertions ) override;
22109+
22110+ void sectionEnded( SectionEndInfo&& endInfo ) override;
22111+ void sectionEndedEarly( SectionEndInfo&& endInfo ) override;
22112+
22113+ IGeneratorTracker*
22114+ acquireGeneratorTracker( StringRef generatorName,
22115+ SourceLineInfo const& lineInfo ) override;
22116+ IGeneratorTracker* createGeneratorTracker(
22117+ StringRef generatorName,
22118+ SourceLineInfo lineInfo,
22119+ Generators::GeneratorBasePtr&& generator ) override;
22120+
22121+
22122+ void benchmarkPreparing( StringRef name ) override;
22123+ void benchmarkStarting( BenchmarkInfo const& info ) override;
22124+ void benchmarkEnded( BenchmarkStats<> const& stats ) override;
22125+ void benchmarkFailed( StringRef error ) override;
22126+
22127+ void pushScopedMessage( MessageInfo const& message ) override;
22128+ void popScopedMessage( MessageInfo const& message ) override;
22129+
22130+ void emplaceUnscopedMessage( MessageBuilder&& builder ) override;
22131+
22132+ std::string getCurrentTestName() const override;
22133+
22134+ const AssertionResult* getLastResult() const override;
22135+
22136+ void exceptionEarlyReported() override;
22137+
22138+ void handleFatalErrorCondition( StringRef message ) override;
22139+
22140+ bool lastAssertionPassed() override;
22141+
22142+ void assertionPassed() override;
22143+
22144+ public:
22145+ // !TBD We need to do this another way!
22146+ bool aborting() const;
22147+
22148+ private:
22149+
22150+ void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr );
22151+ void invokeActiveTestCase();
22152+
22153+ void resetAssertionInfo();
22154+ bool testForMissingAssertions( Counts& assertions );
22155+
22156+ void assertionEnded( AssertionResult&& result );
22157+ void reportExpr
22158+ ( AssertionInfo const &info,
22159+ ResultWas::OfType resultType,
22160+ ITransientExpression const *expr,
22161+ bool negated );
22162+
22163+ void populateReaction( AssertionReaction& reaction );
22164+
22165+ private:
22166+
22167+ void handleUnfinishedSections();
22168+
22169+ TestRunInfo m_runInfo;
22170+ TestCaseHandle const* m_activeTestCase = nullptr;
22171+ ITracker* m_testCaseTracker = nullptr;
22172+ Optional<AssertionResult> m_lastResult;
22173+
22174+ IConfig const* m_config;
22175+ Totals m_totals;
22176+ IEventListenerPtr m_reporter;
22177+ std::vector<MessageInfo> m_messages;
22178+ std::vector<ScopedMessage> m_messageScopes; /* Keeps owners of so-called unscoped messages. */
22179+ AssertionInfo m_lastAssertionInfo;
22180+ std::vector<SectionEndInfo> m_unfinishedSections;
22181+ std::vector<ITracker*> m_activeSections;
22182+ TrackerContext m_trackerContext;
22183+ FatalConditionHandler m_fatalConditionhandler;
22184+ bool m_lastAssertionPassed = false;
22185+ bool m_shouldReportUnexpected = true;
22186+ bool m_includeSuccessfulResults;
22187+ };
22188+
22189+ void seedRng(IConfig const& config);
22190+ unsigned int rngSeed();
22191+} // end namespace Catch
22192+
22193+#endif // CATCH_RUN_CONTEXT_HPP_INCLUDED
22194+
22195+
22196+#ifndef CATCH_SHARDING_HPP_INCLUDED
22197+#define CATCH_SHARDING_HPP_INCLUDED
22198+
22199+#include <cassert>
22200+#include <cmath>
22201+#include <algorithm>
22202+
22203+namespace Catch {
22204+
22205+ template<typename Container>
22206+ Container createShard(Container const& container, std::size_t const shardCount, std::size_t const shardIndex) {
22207+ assert(shardCount > shardIndex);
22208+
22209+ if (shardCount == 1) {
22210+ return container;
22211+ }
22212+
22213+ const std::size_t totalTestCount = container.size();
22214+
22215+ const std::size_t shardSize = totalTestCount / shardCount;
22216+ const std::size_t leftoverTests = totalTestCount % shardCount;
22217+
22218+ const std::size_t startIndex = shardIndex * shardSize + (std::min)(shardIndex, leftoverTests);
22219+ const std::size_t endIndex = (shardIndex + 1) * shardSize + (std::min)(shardIndex + 1, leftoverTests);
22220+
22221+ auto startIterator = std::next(container.begin(), static_cast<std::ptrdiff_t>(startIndex));
22222+ auto endIterator = std::next(container.begin(), static_cast<std::ptrdiff_t>(endIndex));
22223+
22224+ return Container(startIterator, endIterator);
22225+ }
22226+
22227+}
22228+
22229+#endif // CATCH_SHARDING_HPP_INCLUDED
22230+
22231+
22232+#ifndef CATCH_SINGLETONS_HPP_INCLUDED
22233+#define CATCH_SINGLETONS_HPP_INCLUDED
22234+
22235+namespace Catch {
22236+
22237+ struct ISingleton {
22238+ virtual ~ISingleton(); // = default
22239+ };
22240+
22241+
22242+ void addSingleton( ISingleton* singleton );
22243+ void cleanupSingletons();
22244+
22245+
22246+ template<typename SingletonImplT, typename InterfaceT = SingletonImplT, typename MutableInterfaceT = InterfaceT>
22247+ class Singleton : SingletonImplT, public ISingleton {
22248+
22249+ static auto getInternal() -> Singleton* {
22250+ static Singleton* s_instance = nullptr;
22251+ if( !s_instance ) {
22252+ s_instance = new Singleton;
22253+ addSingleton( s_instance );
22254+ }
22255+ return s_instance;
22256+ }
22257+
22258+ public:
22259+ static auto get() -> InterfaceT const& {
22260+ return *getInternal();
22261+ }
22262+ static auto getMutable() -> MutableInterfaceT& {
22263+ return *getInternal();
22264+ }
22265+ };
22266+
22267+} // namespace Catch
22268+
22269+#endif // CATCH_SINGLETONS_HPP_INCLUDED
22270+
22271+
22272+#ifndef CATCH_STARTUP_EXCEPTION_REGISTRY_HPP_INCLUDED
22273+#define CATCH_STARTUP_EXCEPTION_REGISTRY_HPP_INCLUDED
22274+
22275+
22276+#include <vector>
22277+#include <exception>
22278+
22279+namespace Catch {
22280+
22281+ class StartupExceptionRegistry {
22282+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
22283+ public:
22284+ void add(std::exception_ptr const& exception) noexcept;
22285+ std::vector<std::exception_ptr> const& getExceptions() const noexcept;
22286+ private:
22287+ std::vector<std::exception_ptr> m_exceptions;
22288+#endif
22289+ };
22290+
22291+} // end namespace Catch
22292+
22293+#endif // CATCH_STARTUP_EXCEPTION_REGISTRY_HPP_INCLUDED
22294+
22295+
22296+
22297+#ifndef CATCH_STDSTREAMS_HPP_INCLUDED
22298+#define CATCH_STDSTREAMS_HPP_INCLUDED
22299+
22300+#include <iosfwd>
22301+
22302+namespace Catch {
22303+
22304+ std::ostream& cout();
22305+ std::ostream& cerr();
22306+ std::ostream& clog();
22307+
22308+} // namespace Catch
22309+
22310+#endif
22311+
22312+
22313+#ifndef CATCH_STRING_MANIP_HPP_INCLUDED
22314+#define CATCH_STRING_MANIP_HPP_INCLUDED
22315+
22316+
22317+#include <cstdint>
22318+#include <string>
22319+#include <iosfwd>
22320+#include <vector>
22321+
22322+namespace Catch {
22323+
22324+ bool startsWith( std::string const& s, std::string const& prefix );
22325+ bool startsWith( StringRef s, char prefix );
22326+ bool endsWith( std::string const& s, std::string const& suffix );
22327+ bool endsWith( std::string const& s, char suffix );
22328+ bool contains( std::string const& s, std::string const& infix );
22329+ void toLowerInPlace( std::string& s );
22330+ std::string toLower( std::string const& s );
22331+ char toLower( char c );
22332+ //! Returns a new string without whitespace at the start/end
22333+ std::string trim( std::string const& str );
22334+ //! Returns a substring of the original ref without whitespace. Beware lifetimes!
22335+ StringRef trim(StringRef ref);
22336+
22337+ // !!! Be aware, returns refs into original string - make sure original string outlives them
22338+ std::vector<StringRef> splitStringRef( StringRef str, char delimiter );
22339+ bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis );
22340+
22341+ /**
22342+ * Helper for streaming a "count [maybe-plural-of-label]" human-friendly string
22343+ *
22344+ * Usage example:
22345+ * ```cpp
22346+ * std::cout << "Found " << pluralise(count, "error") << '\n';
22347+ * ```
22348+ *
22349+ * **Important:** The provided string must outlive the instance
22350+ */
22351+ class pluralise {
22352+ std::uint64_t m_count;
22353+ StringRef m_label;
22354+
22355+ public:
22356+ constexpr pluralise(std::uint64_t count, StringRef label):
22357+ m_count(count),
22358+ m_label(label)
22359+ {}
22360+
22361+ friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser );
22362+ };
22363+}
22364+
22365+#endif // CATCH_STRING_MANIP_HPP_INCLUDED
22366+
22367+
22368+#ifndef CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED
22369+#define CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED
22370+
22371+
22372+#include <map>
22373+#include <string>
22374+
22375+namespace Catch {
22376+ struct SourceLineInfo;
22377+
22378+ class TagAliasRegistry : public ITagAliasRegistry {
22379+ public:
22380+ ~TagAliasRegistry() override;
22381+ TagAlias const* find( std::string const& alias ) const override;
22382+ std::string expandAliases( std::string const& unexpandedTestSpec ) const override;
22383+ void add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo );
22384+
22385+ private:
22386+ std::map<std::string, TagAlias> m_registry;
22387+ };
22388+
22389+} // end namespace Catch
22390+
22391+#endif // CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED
22392+
22393+
22394+#ifndef CATCH_TEST_CASE_INFO_HASHER_HPP_INCLUDED
22395+#define CATCH_TEST_CASE_INFO_HASHER_HPP_INCLUDED
22396+
22397+#include <cstdint>
22398+
22399+namespace Catch {
22400+
22401+ struct TestCaseInfo;
22402+
22403+ class TestCaseInfoHasher {
22404+ public:
22405+ using hash_t = std::uint64_t;
22406+ TestCaseInfoHasher( hash_t seed );
22407+ uint32_t operator()( TestCaseInfo const& t ) const;
22408+
22409+ private:
22410+ hash_t m_seed;
22411+ };
22412+
22413+} // namespace Catch
22414+
22415+#endif /* CATCH_TEST_CASE_INFO_HASHER_HPP_INCLUDED */
22416+
22417+
22418+#ifndef CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED
22419+#define CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED
22420+
22421+
22422+#include <vector>
22423+
22424+namespace Catch {
22425+
22426+ class IConfig;
22427+ class ITestInvoker;
22428+ class TestCaseHandle;
22429+ class TestSpec;
22430+
22431+ std::vector<TestCaseHandle> sortTests( IConfig const& config, std::vector<TestCaseHandle> const& unsortedTestCases );
22432+
22433+ bool isThrowSafe( TestCaseHandle const& testCase, IConfig const& config );
22434+
22435+ std::vector<TestCaseHandle> filterTests( std::vector<TestCaseHandle> const& testCases, TestSpec const& testSpec, IConfig const& config );
22436+ std::vector<TestCaseHandle> const& getAllTestCasesSorted( IConfig const& config );
22437+
22438+ class TestRegistry : public ITestCaseRegistry {
22439+ public:
22440+ void registerTest( Detail::unique_ptr<TestCaseInfo> testInfo, Detail::unique_ptr<ITestInvoker> testInvoker );
22441+
22442+ std::vector<TestCaseInfo*> const& getAllInfos() const override;
22443+ std::vector<TestCaseHandle> const& getAllTests() const override;
22444+ std::vector<TestCaseHandle> const& getAllTestsSorted( IConfig const& config ) const override;
22445+
22446+ ~TestRegistry() override; // = default
22447+
22448+ private:
22449+ std::vector<Detail::unique_ptr<TestCaseInfo>> m_owned_test_infos;
22450+ // Keeps a materialized vector for `getAllInfos`.
22451+ // We should get rid of that eventually (see interface note)
22452+ std::vector<TestCaseInfo*> m_viewed_test_infos;
22453+
22454+ std::vector<Detail::unique_ptr<ITestInvoker>> m_invokers;
22455+ std::vector<TestCaseHandle> m_handles;
22456+ mutable TestRunOrder m_currentSortOrder = TestRunOrder::Declared;
22457+ mutable std::vector<TestCaseHandle> m_sortedFunctions;
22458+ };
22459+
22460+ ///////////////////////////////////////////////////////////////////////////
22461+
22462+
22463+} // end namespace Catch
22464+
22465+
22466+#endif // CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED
22467+
22468+
22469+#ifndef CATCH_TEST_SPEC_PARSER_HPP_INCLUDED
22470+#define CATCH_TEST_SPEC_PARSER_HPP_INCLUDED
22471+
22472+#ifdef __clang__
22473+#pragma clang diagnostic push
22474+#pragma clang diagnostic ignored "-Wpadded"
22475+#endif
22476+
22477+
22478+#include <vector>
22479+#include <string>
22480+
22481+namespace Catch {
22482+
22483+ class ITagAliasRegistry;
22484+
22485+ class TestSpecParser {
22486+ enum Mode{ None, Name, QuotedName, Tag, EscapedName };
22487+ Mode m_mode = None;
22488+ Mode lastMode = None;
22489+ bool m_exclusion = false;
22490+ std::size_t m_pos = 0;
22491+ std::size_t m_realPatternPos = 0;
22492+ std::string m_arg;
22493+ std::string m_substring;
22494+ std::string m_patternName;
22495+ std::vector<std::size_t> m_escapeChars;
22496+ TestSpec::Filter m_currentFilter;
22497+ TestSpec m_testSpec;
22498+ ITagAliasRegistry const* m_tagAliases = nullptr;
22499+
22500+ public:
22501+ TestSpecParser( ITagAliasRegistry const& tagAliases );
22502+
22503+ TestSpecParser& parse( std::string const& arg );
22504+ TestSpec testSpec();
22505+
22506+ private:
22507+ bool visitChar( char c );
22508+ void startNewMode( Mode mode );
22509+ bool processNoneChar( char c );
22510+ void processNameChar( char c );
22511+ bool processOtherChar( char c );
22512+ void endMode();
22513+ void escape();
22514+ bool isControlChar( char c ) const;
22515+ void saveLastMode();
22516+ void revertBackToLastMode();
22517+ void addFilter();
22518+ bool separate();
22519+
22520+ // Handles common preprocessing of the pattern for name/tag patterns
22521+ std::string preprocessPattern();
22522+ // Adds the current pattern as a test name
22523+ void addNamePattern();
22524+ // Adds the current pattern as a tag
22525+ void addTagPattern();
22526+
22527+ inline void addCharToPattern(char c) {
22528+ m_substring += c;
22529+ m_patternName += c;
22530+ m_realPatternPos++;
22531+ }
22532+
22533+ };
22534+
22535+} // namespace Catch
22536+
22537+#ifdef __clang__
22538+#pragma clang diagnostic pop
22539+#endif
22540+
22541+#endif // CATCH_TEST_SPEC_PARSER_HPP_INCLUDED
22542+
22543+
22544+#ifndef CATCH_TEXTFLOW_HPP_INCLUDED
22545+#define CATCH_TEXTFLOW_HPP_INCLUDED
22546+
22547+
22548+#include <cassert>
22549+#include <string>
22550+#include <vector>
22551+
22552+namespace Catch {
22553+ namespace TextFlow {
22554+
22555+ class Columns;
22556+
22557+ /**
22558+ * Represents a column of text with specific width and indentation
22559+ *
22560+ * When written out to a stream, it will perform linebreaking
22561+ * of the provided text so that the written lines fit within
22562+ * target width.
22563+ */
22564+ class Column {
22565+ // String to be written out
22566+ std::string m_string;
22567+ // Width of the column for linebreaking
22568+ size_t m_width = CATCH_CONFIG_CONSOLE_WIDTH - 1;
22569+ // Indentation of other lines (including first if initial indent is unset)
22570+ size_t m_indent = 0;
22571+ // Indentation of the first line
22572+ size_t m_initialIndent = std::string::npos;
22573+
22574+ public:
22575+ /**
22576+ * Iterates "lines" in `Column` and returns them
22577+ */
22578+ class const_iterator {
22579+ friend Column;
22580+ struct EndTag {};
22581+
22582+ Column const& m_column;
22583+ // Where does the current line start?
22584+ size_t m_lineStart = 0;
22585+ // How long should the current line be?
22586+ size_t m_lineLength = 0;
22587+ // How far have we checked the string to iterate?
22588+ size_t m_parsedTo = 0;
22589+ // Should a '-' be appended to the line?
22590+ bool m_addHyphen = false;
22591+
22592+ const_iterator( Column const& column, EndTag ):
22593+ m_column( column ), m_lineStart( m_column.m_string.size() ) {}
22594+
22595+ // Calculates the length of the current line
22596+ void calcLength();
22597+
22598+ // Returns current indentation width
22599+ size_t indentSize() const;
22600+
22601+ // Creates an indented and (optionally) suffixed string from
22602+ // current iterator position, indentation and length.
22603+ std::string addIndentAndSuffix( size_t position,
22604+ size_t length ) const;
22605+
22606+ public:
22607+ using difference_type = std::ptrdiff_t;
22608+ using value_type = std::string;
22609+ using pointer = value_type*;
22610+ using reference = value_type&;
22611+ using iterator_category = std::forward_iterator_tag;
22612+
22613+ explicit const_iterator( Column const& column );
22614+
22615+ std::string operator*() const;
22616+
22617+ const_iterator& operator++();
22618+ const_iterator operator++( int );
22619+
22620+ bool operator==( const_iterator const& other ) const {
22621+ return m_lineStart == other.m_lineStart && &m_column == &other.m_column;
22622+ }
22623+ bool operator!=( const_iterator const& other ) const {
22624+ return !operator==( other );
22625+ }
22626+ };
22627+ using iterator = const_iterator;
22628+
22629+ explicit Column( std::string const& text ): m_string( text ) {}
22630+ explicit Column( std::string&& text ):
22631+ m_string( CATCH_MOVE(text)) {}
22632+
22633+ Column& width( size_t newWidth ) & {
22634+ assert( newWidth > 0 );
22635+ m_width = newWidth;
22636+ return *this;
22637+ }
22638+ Column&& width( size_t newWidth ) && {
22639+ assert( newWidth > 0 );
22640+ m_width = newWidth;
22641+ return CATCH_MOVE( *this );
22642+ }
22643+ Column& indent( size_t newIndent ) & {
22644+ m_indent = newIndent;
22645+ return *this;
22646+ }
22647+ Column&& indent( size_t newIndent ) && {
22648+ m_indent = newIndent;
22649+ return CATCH_MOVE( *this );
22650+ }
22651+ Column& initialIndent( size_t newIndent ) & {
22652+ m_initialIndent = newIndent;
22653+ return *this;
22654+ }
22655+ Column&& initialIndent( size_t newIndent ) && {
22656+ m_initialIndent = newIndent;
22657+ return CATCH_MOVE( *this );
22658+ }
22659+
22660+ size_t width() const { return m_width; }
22661+ const_iterator begin() const { return const_iterator( *this ); }
22662+ const_iterator end() const { return { *this, const_iterator::EndTag{} }; }
22663+
22664+ friend std::ostream& operator<<( std::ostream& os,
22665+ Column const& col );
22666+
22667+ friend Columns operator+( Column const& lhs, Column const& rhs );
22668+ friend Columns operator+( Column&& lhs, Column&& rhs );
22669+ };
22670+
22671+ //! Creates a column that serves as an empty space of specific width
22672+ Column Spacer( size_t spaceWidth );
22673+
22674+ class Columns {
22675+ std::vector<Column> m_columns;
22676+
22677+ public:
22678+ class iterator {
22679+ friend Columns;
22680+ struct EndTag {};
22681+
22682+ std::vector<Column> const& m_columns;
22683+ std::vector<Column::const_iterator> m_iterators;
22684+ size_t m_activeIterators;
22685+
22686+ iterator( Columns const& columns, EndTag );
22687+
22688+ public:
22689+ using difference_type = std::ptrdiff_t;
22690+ using value_type = std::string;
22691+ using pointer = value_type*;
22692+ using reference = value_type&;
22693+ using iterator_category = std::forward_iterator_tag;
22694+
22695+ explicit iterator( Columns const& columns );
22696+
22697+ auto operator==( iterator const& other ) const -> bool {
22698+ return m_iterators == other.m_iterators;
22699+ }
22700+ auto operator!=( iterator const& other ) const -> bool {
22701+ return m_iterators != other.m_iterators;
22702+ }
22703+ std::string operator*() const;
22704+ iterator& operator++();
22705+ iterator operator++( int );
22706+ };
22707+ using const_iterator = iterator;
22708+
22709+ iterator begin() const { return iterator( *this ); }
22710+ iterator end() const { return { *this, iterator::EndTag() }; }
22711+
22712+ friend Columns& operator+=( Columns& lhs, Column const& rhs );
22713+ friend Columns& operator+=( Columns& lhs, Column&& rhs );
22714+ friend Columns operator+( Columns const& lhs, Column const& rhs );
22715+ friend Columns operator+( Columns&& lhs, Column&& rhs );
22716+
22717+ friend std::ostream& operator<<( std::ostream& os,
22718+ Columns const& cols );
22719+ };
22720+
22721+ } // namespace TextFlow
22722+} // namespace Catch
22723+#endif // CATCH_TEXTFLOW_HPP_INCLUDED
22724+
22725+
22726+#ifndef CATCH_TO_STRING_HPP_INCLUDED
22727+#define CATCH_TO_STRING_HPP_INCLUDED
22728+
22729+#include <string>
22730+
22731+
22732+namespace Catch {
22733+ template <typename T>
22734+ std::string to_string(T const& t) {
22735+#if defined(CATCH_CONFIG_CPP11_TO_STRING)
22736+ return std::to_string(t);
22737+#else
22738+ ReusableStringStream rss;
22739+ rss << t;
22740+ return rss.str();
22741+#endif
22742+ }
22743+} // end namespace Catch
22744+
22745+#endif // CATCH_TO_STRING_HPP_INCLUDED
22746+
22747+
22748+#ifndef CATCH_UNCAUGHT_EXCEPTIONS_HPP_INCLUDED
22749+#define CATCH_UNCAUGHT_EXCEPTIONS_HPP_INCLUDED
22750+
22751+namespace Catch {
22752+ bool uncaught_exceptions();
22753+} // end namespace Catch
22754+
22755+#endif // CATCH_UNCAUGHT_EXCEPTIONS_HPP_INCLUDED
22756+
22757+
22758+#ifndef CATCH_XMLWRITER_HPP_INCLUDED
22759+#define CATCH_XMLWRITER_HPP_INCLUDED
22760+
22761+
22762+#include <iosfwd>
22763+#include <vector>
22764+
22765+namespace Catch {
22766+ enum class XmlFormatting {
22767+ None = 0x00,
22768+ Indent = 0x01,
22769+ Newline = 0x02,
22770+ };
22771+
22772+ XmlFormatting operator | (XmlFormatting lhs, XmlFormatting rhs);
22773+ XmlFormatting operator & (XmlFormatting lhs, XmlFormatting rhs);
22774+
22775+ /**
22776+ * Helper for XML-encoding text (escaping angle brackets, quotes, etc)
22777+ *
22778+ * Note: doesn't take ownership of passed strings, and thus the
22779+ * encoded string must outlive the encoding instance.
22780+ */
22781+ class XmlEncode {
22782+ public:
22783+ enum ForWhat { ForTextNodes, ForAttributes };
22784+
22785+ XmlEncode( StringRef str, ForWhat forWhat = ForTextNodes );
22786+
22787+ void encodeTo( std::ostream& os ) const;
22788+
22789+ friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode );
22790+
22791+ private:
22792+ StringRef m_str;
22793+ ForWhat m_forWhat;
22794+ };
22795+
22796+ class XmlWriter {
22797+ public:
22798+
22799+ class ScopedElement {
22800+ public:
22801+ ScopedElement( XmlWriter* writer, XmlFormatting fmt );
22802+
22803+ ScopedElement( ScopedElement&& other ) noexcept;
22804+ ScopedElement& operator=( ScopedElement&& other ) noexcept;
22805+
22806+ ~ScopedElement();
22807+
22808+ ScopedElement&
22809+ writeText( StringRef text,
22810+ XmlFormatting fmt = XmlFormatting::Newline |
22811+ XmlFormatting::Indent );
22812+
22813+ ScopedElement& writeAttribute( StringRef name,
22814+ StringRef attribute );
22815+ template <typename T,
22816+ // Without this SFINAE, this overload is a better match
22817+ // for `std::string`, `char const*`, `char const[N]` args.
22818+ // While it would still work, it would cause code bloat
22819+ // and multiple iteration over the strings
22820+ typename = typename std::enable_if_t<
22821+ !std::is_convertible<T, StringRef>::value>>
22822+ ScopedElement& writeAttribute( StringRef name,
22823+ T const& attribute ) {
22824+ m_writer->writeAttribute( name, attribute );
22825+ return *this;
22826+ }
22827+
22828+ private:
22829+ XmlWriter* m_writer = nullptr;
22830+ XmlFormatting m_fmt;
22831+ };
22832+
22833+ XmlWriter( std::ostream& os );
22834+ ~XmlWriter();
22835+
22836+ XmlWriter( XmlWriter const& ) = delete;
22837+ XmlWriter& operator=( XmlWriter const& ) = delete;
22838+
22839+ XmlWriter& startElement( std::string const& name, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
22840+
22841+ ScopedElement scopedElement( std::string const& name, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
22842+
22843+ XmlWriter& endElement(XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
22844+
22845+ //! The attribute content is XML-encoded
22846+ XmlWriter& writeAttribute( StringRef name, StringRef attribute );
22847+
22848+ //! Writes the attribute as "true/false"
22849+ XmlWriter& writeAttribute( StringRef name, bool attribute );
22850+
22851+ //! The attribute content is XML-encoded
22852+ XmlWriter& writeAttribute( StringRef name, char const* attribute );
22853+
22854+ //! The attribute value must provide op<<(ostream&, T). The resulting
22855+ //! serialization is XML-encoded
22856+ template <typename T,
22857+ // Without this SFINAE, this overload is a better match
22858+ // for `std::string`, `char const*`, `char const[N]` args.
22859+ // While it would still work, it would cause code bloat
22860+ // and multiple iteration over the strings
22861+ typename = typename std::enable_if_t<
22862+ !std::is_convertible<T, StringRef>::value>>
22863+ XmlWriter& writeAttribute( StringRef name, T const& attribute ) {
22864+ ReusableStringStream rss;
22865+ rss << attribute;
22866+ return writeAttribute( name, rss.str() );
22867+ }
22868+
22869+ //! Writes escaped `text` in a element
22870+ XmlWriter& writeText( StringRef text,
22871+ XmlFormatting fmt = XmlFormatting::Newline |
22872+ XmlFormatting::Indent );
22873+
22874+ //! Writes XML comment as "<!-- text -->"
22875+ XmlWriter& writeComment( StringRef text,
22876+ XmlFormatting fmt = XmlFormatting::Newline |
22877+ XmlFormatting::Indent );
22878+
22879+ void writeStylesheetRef( StringRef url );
22880+
22881+ void ensureTagClosed();
22882+
22883+ private:
22884+
22885+ void applyFormatting(XmlFormatting fmt);
22886+
22887+ void writeDeclaration();
22888+
22889+ void newlineIfNecessary();
22890+
22891+ bool m_tagIsOpen = false;
22892+ bool m_needsNewline = false;
22893+ std::vector<std::string> m_tags;
22894+ std::string m_indent;
22895+ std::ostream& m_os;
22896+ };
22897+
22898+}
22899+
22900+#endif // CATCH_XMLWRITER_HPP_INCLUDED
22901+
22902+
22903+/** \file
22904+ * This is a convenience header for Catch2's Matcher support. It includes
22905+ * **all** of Catch2 headers related to matchers.
22906+ *
22907+ * Generally the Catch2 users should use specific includes they need,
22908+ * but this header can be used instead for ease-of-experimentation, or
22909+ * just plain convenience, at the cost of increased compilation times.
22910+ *
22911+ * When a new header is added to either the `matchers` folder, or to
22912+ * the corresponding internal subfolder, it should be added here.
22913+ */
22914+
22915+#ifndef CATCH_MATCHERS_ALL_HPP_INCLUDED
22916+#define CATCH_MATCHERS_ALL_HPP_INCLUDED
22917+
22918+
22919+
22920+#ifndef CATCH_MATCHERS_HPP_INCLUDED
22921+#define CATCH_MATCHERS_HPP_INCLUDED
22922+
22923+
22924+
22925+#ifndef CATCH_MATCHERS_IMPL_HPP_INCLUDED
22926+#define CATCH_MATCHERS_IMPL_HPP_INCLUDED
22927+
22928+
22929+#include <string>
22930+
22931+namespace Catch {
22932+
22933+ template<typename ArgT, typename MatcherT>
22934+ class MatchExpr : public ITransientExpression {
22935+ ArgT && m_arg;
22936+ MatcherT const& m_matcher;
22937+ public:
22938+ MatchExpr( ArgT && arg, MatcherT const& matcher )
22939+ : ITransientExpression{ true, matcher.match( arg ) }, // not forwarding arg here on purpose
22940+ m_arg( CATCH_FORWARD(arg) ),
22941+ m_matcher( matcher )
22942+ {}
22943+
22944+ void streamReconstructedExpression( std::ostream& os ) const override {
22945+ os << Catch::Detail::stringify( m_arg )
22946+ << ' '
22947+ << m_matcher.toString();
22948+ }
22949+ };
22950+
22951+ namespace Matchers {
22952+ template <typename ArgT>
22953+ class MatcherBase;
22954+ }
22955+
22956+ using StringMatcher = Matchers::MatcherBase<std::string>;
22957+
22958+ void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher );
22959+
22960+ template<typename ArgT, typename MatcherT>
22961+ auto makeMatchExpr( ArgT && arg, MatcherT const& matcher ) -> MatchExpr<ArgT, MatcherT> {
22962+ return MatchExpr<ArgT, MatcherT>( CATCH_FORWARD(arg), matcher );
22963+ }
22964+
22965+} // namespace Catch
22966+
22967+
22968+///////////////////////////////////////////////////////////////////////////////
22969+#define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \
22970+ do { \
22971+ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
22972+ INTERNAL_CATCH_TRY { \
22973+ catchAssertionHandler.handleExpr( Catch::makeMatchExpr( arg, matcher ) ); \
22974+ } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
22975+ INTERNAL_CATCH_REACT( catchAssertionHandler ) \
22976+ } while( false )
22977+
22978+
22979+///////////////////////////////////////////////////////////////////////////////
22980+#define INTERNAL_CATCH_THROWS_MATCHES( macroName, exceptionType, resultDisposition, matcher, ... ) \
22981+ do { \
22982+ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(exceptionType) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
22983+ if( catchAssertionHandler.allowThrows() ) \
22984+ try { \
22985+ static_cast<void>(__VA_ARGS__ ); \
22986+ catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
22987+ } \
22988+ catch( exceptionType const& ex ) { \
22989+ catchAssertionHandler.handleExpr( Catch::makeMatchExpr( ex, matcher ) ); \
22990+ } \
22991+ catch( ... ) { \
22992+ catchAssertionHandler.handleUnexpectedInflightException(); \
22993+ } \
22994+ else \
22995+ catchAssertionHandler.handleThrowingCallSkipped(); \
22996+ INTERNAL_CATCH_REACT( catchAssertionHandler ) \
22997+ } while( false )
22998+
22999+
23000+#endif // CATCH_MATCHERS_IMPL_HPP_INCLUDED
23001+
23002+#include <string>
23003+#include <vector>
23004+
23005+namespace Catch {
23006+namespace Matchers {
23007+
23008+ class MatcherUntypedBase {
23009+ public:
23010+ MatcherUntypedBase() = default;
23011+
23012+ MatcherUntypedBase(MatcherUntypedBase const&) = default;
23013+ MatcherUntypedBase(MatcherUntypedBase&&) = default;
23014+
23015+ MatcherUntypedBase& operator = (MatcherUntypedBase const&) = delete;
23016+ MatcherUntypedBase& operator = (MatcherUntypedBase&&) = delete;
23017+
23018+ std::string toString() const;
23019+
23020+ protected:
23021+ virtual ~MatcherUntypedBase(); // = default;
23022+ virtual std::string describe() const = 0;
23023+ mutable std::string m_cachedToString;
23024+ };
23025+
23026+
23027+ template<typename T>
23028+ class MatcherBase : public MatcherUntypedBase {
23029+ public:
23030+ virtual bool match( T const& arg ) const = 0;
23031+ };
23032+
23033+ namespace Detail {
23034+
23035+ template<typename ArgT>
23036+ class MatchAllOf final : public MatcherBase<ArgT> {
23037+ std::vector<MatcherBase<ArgT> const*> m_matchers;
23038+
23039+ public:
23040+ MatchAllOf() = default;
23041+ MatchAllOf(MatchAllOf const&) = delete;
23042+ MatchAllOf& operator=(MatchAllOf const&) = delete;
23043+ MatchAllOf(MatchAllOf&&) = default;
23044+ MatchAllOf& operator=(MatchAllOf&&) = default;
23045+
23046+
23047+ bool match( ArgT const& arg ) const override {
23048+ for( auto matcher : m_matchers ) {
23049+ if (!matcher->match(arg))
23050+ return false;
23051+ }
23052+ return true;
23053+ }
23054+ std::string describe() const override {
23055+ std::string description;
23056+ description.reserve( 4 + m_matchers.size()*32 );
23057+ description += "( ";
23058+ bool first = true;
23059+ for( auto matcher : m_matchers ) {
23060+ if( first )
23061+ first = false;
23062+ else
23063+ description += " and ";
23064+ description += matcher->toString();
23065+ }
23066+ description += " )";
23067+ return description;
23068+ }
23069+
23070+ friend MatchAllOf operator&& (MatchAllOf&& lhs, MatcherBase<ArgT> const& rhs) {
23071+ lhs.m_matchers.push_back(&rhs);
23072+ return CATCH_MOVE(lhs);
23073+ }
23074+ friend MatchAllOf operator&& (MatcherBase<ArgT> const& lhs, MatchAllOf&& rhs) {
23075+ rhs.m_matchers.insert(rhs.m_matchers.begin(), &lhs);
23076+ return CATCH_MOVE(rhs);
23077+ }
23078+ };
23079+
23080+ //! lvalue overload is intentionally deleted, users should
23081+ //! not be trying to compose stored composition matchers
23082+ template<typename ArgT>
23083+ MatchAllOf<ArgT> operator&& (MatchAllOf<ArgT> const& lhs, MatcherBase<ArgT> const& rhs) = delete;
23084+ //! lvalue overload is intentionally deleted, users should
23085+ //! not be trying to compose stored composition matchers
23086+ template<typename ArgT>
23087+ MatchAllOf<ArgT> operator&& (MatcherBase<ArgT> const& lhs, MatchAllOf<ArgT> const& rhs) = delete;
23088+
23089+ template<typename ArgT>
23090+ class MatchAnyOf final : public MatcherBase<ArgT> {
23091+ std::vector<MatcherBase<ArgT> const*> m_matchers;
23092+ public:
23093+ MatchAnyOf() = default;
23094+ MatchAnyOf(MatchAnyOf const&) = delete;
23095+ MatchAnyOf& operator=(MatchAnyOf const&) = delete;
23096+ MatchAnyOf(MatchAnyOf&&) = default;
23097+ MatchAnyOf& operator=(MatchAnyOf&&) = default;
23098+
23099+ bool match( ArgT const& arg ) const override {
23100+ for( auto matcher : m_matchers ) {
23101+ if (matcher->match(arg))
23102+ return true;
23103+ }
23104+ return false;
23105+ }
23106+ std::string describe() const override {
23107+ std::string description;
23108+ description.reserve( 4 + m_matchers.size()*32 );
23109+ description += "( ";
23110+ bool first = true;
23111+ for( auto matcher : m_matchers ) {
23112+ if( first )
23113+ first = false;
23114+ else
23115+ description += " or ";
23116+ description += matcher->toString();
23117+ }
23118+ description += " )";
23119+ return description;
23120+ }
23121+
23122+ friend MatchAnyOf operator|| (MatchAnyOf&& lhs, MatcherBase<ArgT> const& rhs) {
23123+ lhs.m_matchers.push_back(&rhs);
23124+ return CATCH_MOVE(lhs);
23125+ }
23126+ friend MatchAnyOf operator|| (MatcherBase<ArgT> const& lhs, MatchAnyOf&& rhs) {
23127+ rhs.m_matchers.insert(rhs.m_matchers.begin(), &lhs);
23128+ return CATCH_MOVE(rhs);
23129+ }
23130+ };
23131+
23132+ //! lvalue overload is intentionally deleted, users should
23133+ //! not be trying to compose stored composition matchers
23134+ template<typename ArgT>
23135+ MatchAnyOf<ArgT> operator|| (MatchAnyOf<ArgT> const& lhs, MatcherBase<ArgT> const& rhs) = delete;
23136+ //! lvalue overload is intentionally deleted, users should
23137+ //! not be trying to compose stored composition matchers
23138+ template<typename ArgT>
23139+ MatchAnyOf<ArgT> operator|| (MatcherBase<ArgT> const& lhs, MatchAnyOf<ArgT> const& rhs) = delete;
23140+
23141+ template<typename ArgT>
23142+ class MatchNotOf final : public MatcherBase<ArgT> {
23143+ MatcherBase<ArgT> const& m_underlyingMatcher;
23144+
23145+ public:
23146+ explicit MatchNotOf( MatcherBase<ArgT> const& underlyingMatcher ):
23147+ m_underlyingMatcher( underlyingMatcher )
23148+ {}
23149+
23150+ bool match( ArgT const& arg ) const override {
23151+ return !m_underlyingMatcher.match( arg );
23152+ }
23153+
23154+ std::string describe() const override {
23155+ return "not " + m_underlyingMatcher.toString();
23156+ }
23157+ };
23158+
23159+ } // namespace Detail
23160+
23161+ template <typename T>
23162+ Detail::MatchAllOf<T> operator&& (MatcherBase<T> const& lhs, MatcherBase<T> const& rhs) {
23163+ return Detail::MatchAllOf<T>{} && lhs && rhs;
23164+ }
23165+ template <typename T>
23166+ Detail::MatchAnyOf<T> operator|| (MatcherBase<T> const& lhs, MatcherBase<T> const& rhs) {
23167+ return Detail::MatchAnyOf<T>{} || lhs || rhs;
23168+ }
23169+
23170+ template <typename T>
23171+ Detail::MatchNotOf<T> operator! (MatcherBase<T> const& matcher) {
23172+ return Detail::MatchNotOf<T>{ matcher };
23173+ }
23174+
23175+
23176+} // namespace Matchers
23177+} // namespace Catch
23178+
23179+
23180+#if defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE)
23181+ #define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr )
23182+ #define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr )
23183+
23184+ #define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
23185+ #define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
23186+
23187+ #define CATCH_CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg )
23188+ #define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )
23189+
23190+#elif defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE)
23191+
23192+ #define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) (void)(0)
23193+ #define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0)
23194+
23195+ #define CATCH_CHECK_THROWS_WITH( expr, matcher ) (void)(0)
23196+ #define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0)
23197+
23198+ #define CATCH_CHECK_THAT( arg, matcher ) (void)(0)
23199+ #define CATCH_REQUIRE_THAT( arg, matcher ) (void)(0)
23200+
23201+#elif !defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE)
23202+
23203+ #define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr )
23204+ #define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr )
23205+
23206+ #define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
23207+ #define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
23208+
23209+ #define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg )
23210+ #define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )
23211+
23212+#elif !defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE)
23213+
23214+ #define REQUIRE_THROWS_WITH( expr, matcher ) (void)(0)
23215+ #define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0)
23216+
23217+ #define CHECK_THROWS_WITH( expr, matcher ) (void)(0)
23218+ #define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0)
23219+
23220+ #define CHECK_THAT( arg, matcher ) (void)(0)
23221+ #define REQUIRE_THAT( arg, matcher ) (void)(0)
23222+
23223+#endif // end of user facing macro declarations
23224+
23225+#endif // CATCH_MATCHERS_HPP_INCLUDED
23226+
23227+
23228+#ifndef CATCH_MATCHERS_CONTAINER_PROPERTIES_HPP_INCLUDED
23229+#define CATCH_MATCHERS_CONTAINER_PROPERTIES_HPP_INCLUDED
23230+
23231+
23232+
23233+#ifndef CATCH_MATCHERS_TEMPLATED_HPP_INCLUDED
23234+#define CATCH_MATCHERS_TEMPLATED_HPP_INCLUDED
23235+
23236+
23237+#include <array>
23238+#include <algorithm>
23239+#include <string>
23240+#include <type_traits>
23241+
23242+namespace Catch {
23243+namespace Matchers {
23244+ class MatcherGenericBase : public MatcherUntypedBase {
23245+ public:
23246+ MatcherGenericBase() = default;
23247+ ~MatcherGenericBase() override; // = default;
23248+
23249+ MatcherGenericBase(MatcherGenericBase const&) = default;
23250+ MatcherGenericBase(MatcherGenericBase&&) = default;
23251+
23252+ MatcherGenericBase& operator=(MatcherGenericBase const&) = delete;
23253+ MatcherGenericBase& operator=(MatcherGenericBase&&) = delete;
23254+ };
23255+
23256+
23257+ namespace Detail {
23258+ template<std::size_t N, std::size_t M>
23259+ std::array<void const*, N + M> array_cat(std::array<void const*, N> && lhs, std::array<void const*, M> && rhs) {
23260+ std::array<void const*, N + M> arr{};
23261+ std::copy_n(lhs.begin(), N, arr.begin());
23262+ std::copy_n(rhs.begin(), M, arr.begin() + N);
23263+ return arr;
23264+ }
23265+
23266+ template<std::size_t N>
23267+ std::array<void const*, N+1> array_cat(std::array<void const*, N> && lhs, void const* rhs) {
23268+ std::array<void const*, N+1> arr{};
23269+ std::copy_n(lhs.begin(), N, arr.begin());
23270+ arr[N] = rhs;
23271+ return arr;
23272+ }
23273+
23274+ template<std::size_t N>
23275+ std::array<void const*, N+1> array_cat(void const* lhs, std::array<void const*, N> && rhs) {
23276+ std::array<void const*, N + 1> arr{ {lhs} };
23277+ std::copy_n(rhs.begin(), N, arr.begin() + 1);
23278+ return arr;
23279+ }
23280+
23281+ template<typename T>
23282+ using is_generic_matcher = std::is_base_of<
23283+ Catch::Matchers::MatcherGenericBase,
23284+ std::remove_cv_t<std::remove_reference_t<T>>
23285+ >;
23286+
23287+ template<typename... Ts>
23288+ using are_generic_matchers = Catch::Detail::conjunction<is_generic_matcher<Ts>...>;
23289+
23290+ template<typename T>
23291+ using is_matcher = std::is_base_of<
23292+ Catch::Matchers::MatcherUntypedBase,
23293+ std::remove_cv_t<std::remove_reference_t<T>>
23294+ >;
23295+
23296+
23297+ template<std::size_t N, typename Arg>
23298+ bool match_all_of(Arg&&, std::array<void const*, N> const&, std::index_sequence<>) {
23299+ return true;
23300+ }
23301+
23302+ template<typename T, typename... MatcherTs, std::size_t N, typename Arg, std::size_t Idx, std::size_t... Indices>
23303+ bool match_all_of(Arg&& arg, std::array<void const*, N> const& matchers, std::index_sequence<Idx, Indices...>) {
23304+ return static_cast<T const*>(matchers[Idx])->match(arg) && match_all_of<MatcherTs...>(arg, matchers, std::index_sequence<Indices...>{});
23305+ }
23306+
23307+
23308+ template<std::size_t N, typename Arg>
23309+ bool match_any_of(Arg&&, std::array<void const*, N> const&, std::index_sequence<>) {
23310+ return false;
23311+ }
23312+
23313+ template<typename T, typename... MatcherTs, std::size_t N, typename Arg, std::size_t Idx, std::size_t... Indices>
23314+ bool match_any_of(Arg&& arg, std::array<void const*, N> const& matchers, std::index_sequence<Idx, Indices...>) {
23315+ return static_cast<T const*>(matchers[Idx])->match(arg) || match_any_of<MatcherTs...>(arg, matchers, std::index_sequence<Indices...>{});
23316+ }
23317+
23318+ std::string describe_multi_matcher(StringRef combine, std::string const* descriptions_begin, std::string const* descriptions_end);
23319+
23320+ template<typename... MatcherTs, std::size_t... Idx>
23321+ std::string describe_multi_matcher(StringRef combine, std::array<void const*, sizeof...(MatcherTs)> const& matchers, std::index_sequence<Idx...>) {
23322+ std::array<std::string, sizeof...(MatcherTs)> descriptions {{
23323+ static_cast<MatcherTs const*>(matchers[Idx])->toString()...
23324+ }};
23325+
23326+ return describe_multi_matcher(combine, descriptions.data(), descriptions.data() + descriptions.size());
23327+ }
23328+
23329+
23330+ template<typename... MatcherTs>
23331+ class MatchAllOfGeneric final : public MatcherGenericBase {
23332+ public:
23333+ MatchAllOfGeneric(MatchAllOfGeneric const&) = delete;
23334+ MatchAllOfGeneric& operator=(MatchAllOfGeneric const&) = delete;
23335+ MatchAllOfGeneric(MatchAllOfGeneric&&) = default;
23336+ MatchAllOfGeneric& operator=(MatchAllOfGeneric&&) = default;
23337+
23338+ MatchAllOfGeneric(MatcherTs const&... matchers) : m_matchers{ {std::addressof(matchers)...} } {}
23339+ explicit MatchAllOfGeneric(std::array<void const*, sizeof...(MatcherTs)> matchers) : m_matchers{matchers} {}
23340+
23341+ template<typename Arg>
23342+ bool match(Arg&& arg) const {
23343+ return match_all_of<MatcherTs...>(arg, m_matchers, std::index_sequence_for<MatcherTs...>{});
23344+ }
23345+
23346+ std::string describe() const override {
23347+ return describe_multi_matcher<MatcherTs...>(" and "_sr, m_matchers, std::index_sequence_for<MatcherTs...>{});
23348+ }
23349+
23350+ // Has to be public to enable the concatenating operators
23351+ // below, because they are not friend of the RHS, only LHS,
23352+ // and thus cannot access private fields of RHS
23353+ std::array<void const*, sizeof...( MatcherTs )> m_matchers;
23354+
23355+
23356+ //! Avoids type nesting for `GenericAllOf && GenericAllOf` case
23357+ template<typename... MatchersRHS>
23358+ friend
23359+ MatchAllOfGeneric<MatcherTs..., MatchersRHS...> operator && (
23360+ MatchAllOfGeneric<MatcherTs...>&& lhs,
23361+ MatchAllOfGeneric<MatchersRHS...>&& rhs) {
23362+ return MatchAllOfGeneric<MatcherTs..., MatchersRHS...>{array_cat(CATCH_MOVE(lhs.m_matchers), CATCH_MOVE(rhs.m_matchers))};
23363+ }
23364+
23365+ //! Avoids type nesting for `GenericAllOf && some matcher` case
23366+ template<typename MatcherRHS>
23367+ friend std::enable_if_t<is_matcher<MatcherRHS>::value,
23368+ MatchAllOfGeneric<MatcherTs..., MatcherRHS>> operator && (
23369+ MatchAllOfGeneric<MatcherTs...>&& lhs,
23370+ MatcherRHS const& rhs) {
23371+ return MatchAllOfGeneric<MatcherTs..., MatcherRHS>{array_cat(CATCH_MOVE(lhs.m_matchers), static_cast<void const*>(&rhs))};
23372+ }
23373+
23374+ //! Avoids type nesting for `some matcher && GenericAllOf` case
23375+ template<typename MatcherLHS>
23376+ friend std::enable_if_t<is_matcher<MatcherLHS>::value,
23377+ MatchAllOfGeneric<MatcherLHS, MatcherTs...>> operator && (
23378+ MatcherLHS const& lhs,
23379+ MatchAllOfGeneric<MatcherTs...>&& rhs) {
23380+ return MatchAllOfGeneric<MatcherLHS, MatcherTs...>{array_cat(static_cast<void const*>(std::addressof(lhs)), CATCH_MOVE(rhs.m_matchers))};
23381+ }
23382+ };
23383+
23384+
23385+ template<typename... MatcherTs>
23386+ class MatchAnyOfGeneric final : public MatcherGenericBase {
23387+ public:
23388+ MatchAnyOfGeneric(MatchAnyOfGeneric const&) = delete;
23389+ MatchAnyOfGeneric& operator=(MatchAnyOfGeneric const&) = delete;
23390+ MatchAnyOfGeneric(MatchAnyOfGeneric&&) = default;
23391+ MatchAnyOfGeneric& operator=(MatchAnyOfGeneric&&) = default;
23392+
23393+ MatchAnyOfGeneric(MatcherTs const&... matchers) : m_matchers{ {std::addressof(matchers)...} } {}
23394+ explicit MatchAnyOfGeneric(std::array<void const*, sizeof...(MatcherTs)> matchers) : m_matchers{matchers} {}
23395+
23396+ template<typename Arg>
23397+ bool match(Arg&& arg) const {
23398+ return match_any_of<MatcherTs...>(arg, m_matchers, std::index_sequence_for<MatcherTs...>{});
23399+ }
23400+
23401+ std::string describe() const override {
23402+ return describe_multi_matcher<MatcherTs...>(" or "_sr, m_matchers, std::index_sequence_for<MatcherTs...>{});
23403+ }
23404+
23405+
23406+ // Has to be public to enable the concatenating operators
23407+ // below, because they are not friend of the RHS, only LHS,
23408+ // and thus cannot access private fields of RHS
23409+ std::array<void const*, sizeof...( MatcherTs )> m_matchers;
23410+
23411+ //! Avoids type nesting for `GenericAnyOf || GenericAnyOf` case
23412+ template<typename... MatchersRHS>
23413+ friend MatchAnyOfGeneric<MatcherTs..., MatchersRHS...> operator || (
23414+ MatchAnyOfGeneric<MatcherTs...>&& lhs,
23415+ MatchAnyOfGeneric<MatchersRHS...>&& rhs) {
23416+ return MatchAnyOfGeneric<MatcherTs..., MatchersRHS...>{array_cat(CATCH_MOVE(lhs.m_matchers), CATCH_MOVE(rhs.m_matchers))};
23417+ }
23418+
23419+ //! Avoids type nesting for `GenericAnyOf || some matcher` case
23420+ template<typename MatcherRHS>
23421+ friend std::enable_if_t<is_matcher<MatcherRHS>::value,
23422+ MatchAnyOfGeneric<MatcherTs..., MatcherRHS>> operator || (
23423+ MatchAnyOfGeneric<MatcherTs...>&& lhs,
23424+ MatcherRHS const& rhs) {
23425+ return MatchAnyOfGeneric<MatcherTs..., MatcherRHS>{array_cat(CATCH_MOVE(lhs.m_matchers), static_cast<void const*>(std::addressof(rhs)))};
23426+ }
23427+
23428+ //! Avoids type nesting for `some matcher || GenericAnyOf` case
23429+ template<typename MatcherLHS>
23430+ friend std::enable_if_t<is_matcher<MatcherLHS>::value,
23431+ MatchAnyOfGeneric<MatcherLHS, MatcherTs...>> operator || (
23432+ MatcherLHS const& lhs,
23433+ MatchAnyOfGeneric<MatcherTs...>&& rhs) {
23434+ return MatchAnyOfGeneric<MatcherLHS, MatcherTs...>{array_cat(static_cast<void const*>(std::addressof(lhs)), CATCH_MOVE(rhs.m_matchers))};
23435+ }
23436+ };
23437+
23438+
23439+ template<typename MatcherT>
23440+ class MatchNotOfGeneric final : public MatcherGenericBase {
23441+ MatcherT const& m_matcher;
23442+
23443+ public:
23444+ MatchNotOfGeneric(MatchNotOfGeneric const&) = delete;
23445+ MatchNotOfGeneric& operator=(MatchNotOfGeneric const&) = delete;
23446+ MatchNotOfGeneric(MatchNotOfGeneric&&) = default;
23447+ MatchNotOfGeneric& operator=(MatchNotOfGeneric&&) = default;
23448+
23449+ explicit MatchNotOfGeneric(MatcherT const& matcher) : m_matcher{matcher} {}
23450+
23451+ template<typename Arg>
23452+ bool match(Arg&& arg) const {
23453+ return !m_matcher.match(arg);
23454+ }
23455+
23456+ std::string describe() const override {
23457+ return "not " + m_matcher.toString();
23458+ }
23459+
23460+ //! Negating negation can just unwrap and return underlying matcher
23461+ friend MatcherT const& operator ! (MatchNotOfGeneric<MatcherT> const& matcher) {
23462+ return matcher.m_matcher;
23463+ }
23464+ };
23465+ } // namespace Detail
23466+
23467+
23468+ // compose only generic matchers
23469+ template<typename MatcherLHS, typename MatcherRHS>
23470+ std::enable_if_t<Detail::are_generic_matchers<MatcherLHS, MatcherRHS>::value, Detail::MatchAllOfGeneric<MatcherLHS, MatcherRHS>>
23471+ operator && (MatcherLHS const& lhs, MatcherRHS const& rhs) {
23472+ return { lhs, rhs };
23473+ }
23474+
23475+ template<typename MatcherLHS, typename MatcherRHS>
23476+ std::enable_if_t<Detail::are_generic_matchers<MatcherLHS, MatcherRHS>::value, Detail::MatchAnyOfGeneric<MatcherLHS, MatcherRHS>>
23477+ operator || (MatcherLHS const& lhs, MatcherRHS const& rhs) {
23478+ return { lhs, rhs };
23479+ }
23480+
23481+ //! Wrap provided generic matcher in generic negator
23482+ template<typename MatcherT>
23483+ std::enable_if_t<Detail::is_generic_matcher<MatcherT>::value, Detail::MatchNotOfGeneric<MatcherT>>
23484+ operator ! (MatcherT const& matcher) {
23485+ return Detail::MatchNotOfGeneric<MatcherT>{matcher};
23486+ }
23487+
23488+
23489+ // compose mixed generic and non-generic matchers
23490+ template<typename MatcherLHS, typename ArgRHS>
23491+ std::enable_if_t<Detail::is_generic_matcher<MatcherLHS>::value, Detail::MatchAllOfGeneric<MatcherLHS, MatcherBase<ArgRHS>>>
23492+ operator && (MatcherLHS const& lhs, MatcherBase<ArgRHS> const& rhs) {
23493+ return { lhs, rhs };
23494+ }
23495+
23496+ template<typename ArgLHS, typename MatcherRHS>
23497+ std::enable_if_t<Detail::is_generic_matcher<MatcherRHS>::value, Detail::MatchAllOfGeneric<MatcherBase<ArgLHS>, MatcherRHS>>
23498+ operator && (MatcherBase<ArgLHS> const& lhs, MatcherRHS const& rhs) {
23499+ return { lhs, rhs };
23500+ }
23501+
23502+ template<typename MatcherLHS, typename ArgRHS>
23503+ std::enable_if_t<Detail::is_generic_matcher<MatcherLHS>::value, Detail::MatchAnyOfGeneric<MatcherLHS, MatcherBase<ArgRHS>>>
23504+ operator || (MatcherLHS const& lhs, MatcherBase<ArgRHS> const& rhs) {
23505+ return { lhs, rhs };
23506+ }
23507+
23508+ template<typename ArgLHS, typename MatcherRHS>
23509+ std::enable_if_t<Detail::is_generic_matcher<MatcherRHS>::value, Detail::MatchAnyOfGeneric<MatcherBase<ArgLHS>, MatcherRHS>>
23510+ operator || (MatcherBase<ArgLHS> const& lhs, MatcherRHS const& rhs) {
23511+ return { lhs, rhs };
23512+ }
23513+
23514+} // namespace Matchers
23515+} // namespace Catch
23516+
23517+#endif // CATCH_MATCHERS_TEMPLATED_HPP_INCLUDED
23518+
23519+namespace Catch {
23520+ namespace Matchers {
23521+
23522+ class IsEmptyMatcher final : public MatcherGenericBase {
23523+ public:
23524+ template <typename RangeLike>
23525+ bool match(RangeLike&& rng) const {
23526+#if defined(CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS)
23527+ using Catch::Detail::empty;
23528+#else
23529+ using std::empty;
23530+#endif
23531+ return empty(rng);
23532+ }
23533+
23534+ std::string describe() const override;
23535+ };
23536+
23537+ class HasSizeMatcher final : public MatcherGenericBase {
23538+ std::size_t m_target_size;
23539+ public:
23540+ explicit HasSizeMatcher(std::size_t target_size):
23541+ m_target_size(target_size)
23542+ {}
23543+
23544+ template <typename RangeLike>
23545+ bool match(RangeLike&& rng) const {
23546+#if defined(CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS)
23547+ using Catch::Detail::size;
23548+#else
23549+ using std::size;
23550+#endif
23551+ return size(rng) == m_target_size;
23552+ }
23553+
23554+ std::string describe() const override;
23555+ };
23556+
23557+ template <typename Matcher>
23558+ class SizeMatchesMatcher final : public MatcherGenericBase {
23559+ Matcher m_matcher;
23560+ public:
23561+ explicit SizeMatchesMatcher(Matcher m):
23562+ m_matcher(CATCH_MOVE(m))
23563+ {}
23564+
23565+ template <typename RangeLike>
23566+ bool match(RangeLike&& rng) const {
23567+#if defined(CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS)
23568+ using Catch::Detail::size;
23569+#else
23570+ using std::size;
23571+#endif
23572+ return m_matcher.match(size(rng));
23573+ }
23574+
23575+ std::string describe() const override {
23576+ return "size matches " + m_matcher.describe();
23577+ }
23578+ };
23579+
23580+
23581+ //! Creates a matcher that accepts empty ranges/containers
23582+ IsEmptyMatcher IsEmpty();
23583+ //! Creates a matcher that accepts ranges/containers with specific size
23584+ HasSizeMatcher SizeIs(std::size_t sz);
23585+ template <typename Matcher>
23586+ std::enable_if_t<Detail::is_matcher<Matcher>::value,
23587+ SizeMatchesMatcher<Matcher>> SizeIs(Matcher&& m) {
23588+ return SizeMatchesMatcher<Matcher>{CATCH_FORWARD(m)};
23589+ }
23590+
23591+ } // end namespace Matchers
23592+} // end namespace Catch
23593+
23594+#endif // CATCH_MATCHERS_CONTAINER_PROPERTIES_HPP_INCLUDED
23595+
23596+
23597+#ifndef CATCH_MATCHERS_CONTAINS_HPP_INCLUDED
23598+#define CATCH_MATCHERS_CONTAINS_HPP_INCLUDED
23599+
23600+
23601+#include <algorithm>
23602+#include <functional>
23603+
23604+namespace Catch {
23605+ namespace Matchers {
23606+ //! Matcher for checking that an element in range is equal to specific element
23607+ template <typename T, typename Equality>
23608+ class ContainsElementMatcher final : public MatcherGenericBase {
23609+ T m_desired;
23610+ Equality m_eq;
23611+ public:
23612+ template <typename T2, typename Equality2>
23613+ ContainsElementMatcher(T2&& target, Equality2&& predicate):
23614+ m_desired(CATCH_FORWARD(target)),
23615+ m_eq(CATCH_FORWARD(predicate))
23616+ {}
23617+
23618+ std::string describe() const override {
23619+ return "contains element " + Catch::Detail::stringify(m_desired);
23620+ }
23621+
23622+ template <typename RangeLike>
23623+ bool match( RangeLike&& rng ) const {
23624+ for ( auto&& elem : rng ) {
23625+ if ( m_eq( elem, m_desired ) ) { return true; }
23626+ }
23627+ return false;
23628+ }
23629+ };
23630+
23631+ //! Meta-matcher for checking that an element in a range matches a specific matcher
23632+ template <typename Matcher>
23633+ class ContainsMatcherMatcher final : public MatcherGenericBase {
23634+ Matcher m_matcher;
23635+ public:
23636+ // Note that we do a copy+move to avoid having to SFINAE this
23637+ // constructor (and also avoid some perfect forwarding failure
23638+ // cases)
23639+ ContainsMatcherMatcher(Matcher matcher):
23640+ m_matcher(CATCH_MOVE(matcher))
23641+ {}
23642+
23643+ template <typename RangeLike>
23644+ bool match(RangeLike&& rng) const {
23645+ for (auto&& elem : rng) {
23646+ if (m_matcher.match(elem)) {
23647+ return true;
23648+ }
23649+ }
23650+ return false;
23651+ }
23652+
23653+ std::string describe() const override {
23654+ return "contains element matching " + m_matcher.describe();
23655+ }
23656+ };
23657+
23658+ /**
23659+ * Creates a matcher that checks whether a range contains a specific element.
23660+ *
23661+ * Uses `std::equal_to` to do the comparison
23662+ */
23663+ template <typename T>
23664+ std::enable_if_t<!Detail::is_matcher<T>::value,
23665+ ContainsElementMatcher<T, std::equal_to<>>> Contains(T&& elem) {
23666+ return { CATCH_FORWARD(elem), std::equal_to<>{} };
23667+ }
23668+
23669+ //! Creates a matcher that checks whether a range contains element matching a matcher
23670+ template <typename Matcher>
23671+ std::enable_if_t<Detail::is_matcher<Matcher>::value,
23672+ ContainsMatcherMatcher<Matcher>> Contains(Matcher&& matcher) {
23673+ return { CATCH_FORWARD(matcher) };
23674+ }
23675+
23676+ /**
23677+ * Creates a matcher that checks whether a range contains a specific element.
23678+ *
23679+ * Uses `eq` to do the comparisons, the element is provided on the rhs
23680+ */
23681+ template <typename T, typename Equality>
23682+ ContainsElementMatcher<T, Equality> Contains(T&& elem, Equality&& eq) {
23683+ return { CATCH_FORWARD(elem), CATCH_FORWARD(eq) };
23684+ }
23685+
23686+ }
23687+}
23688+
23689+#endif // CATCH_MATCHERS_CONTAINS_HPP_INCLUDED
23690+
23691+
23692+#ifndef CATCH_MATCHERS_EXCEPTION_HPP_INCLUDED
23693+#define CATCH_MATCHERS_EXCEPTION_HPP_INCLUDED
23694+
23695+
23696+namespace Catch {
23697+namespace Matchers {
23698+
23699+class ExceptionMessageMatcher final : public MatcherBase<std::exception> {
23700+ std::string m_message;
23701+public:
23702+
23703+ ExceptionMessageMatcher(std::string const& message):
23704+ m_message(message)
23705+ {}
23706+
23707+ bool match(std::exception const& ex) const override;
23708+
23709+ std::string describe() const override;
23710+};
23711+
23712+//! Creates a matcher that checks whether a std derived exception has the provided message
23713+ExceptionMessageMatcher Message(std::string const& message);
23714+
23715+template <typename StringMatcherType>
23716+class ExceptionMessageMatchesMatcher final
23717+ : public MatcherBase<std::exception> {
23718+ StringMatcherType m_matcher;
23719+
23720+public:
23721+ ExceptionMessageMatchesMatcher( StringMatcherType matcher ):
23722+ m_matcher( CATCH_MOVE( matcher ) ) {}
23723+
23724+ bool match( std::exception const& ex ) const override {
23725+ return m_matcher.match( ex.what() );
23726+ }
23727+
23728+ std::string describe() const override {
23729+ return " matches \"" + m_matcher.describe() + '"';
23730+ }
23731+};
23732+
23733+//! Creates a matcher that checks whether a message from an std derived
23734+//! exception matches a provided matcher
23735+template <typename StringMatcherType>
23736+ExceptionMessageMatchesMatcher<StringMatcherType>
23737+MessageMatches( StringMatcherType&& matcher ) {
23738+ return { CATCH_FORWARD( matcher ) };
23739+}
23740+
23741+} // namespace Matchers
23742+} // namespace Catch
23743+
23744+#endif // CATCH_MATCHERS_EXCEPTION_HPP_INCLUDED
23745+
23746+
23747+#ifndef CATCH_MATCHERS_FLOATING_POINT_HPP_INCLUDED
23748+#define CATCH_MATCHERS_FLOATING_POINT_HPP_INCLUDED
23749+
23750+
23751+namespace Catch {
23752+namespace Matchers {
23753+
23754+ namespace Detail {
23755+ enum class FloatingPointKind : uint8_t;
23756+ }
23757+
23758+ class WithinAbsMatcher final : public MatcherBase<double> {
23759+ public:
23760+ WithinAbsMatcher(double target, double margin);
23761+ bool match(double const& matchee) const override;
23762+ std::string describe() const override;
23763+ private:
23764+ double m_target;
23765+ double m_margin;
23766+ };
23767+
23768+ //! Creates a matcher that accepts numbers within certain range of target
23769+ WithinAbsMatcher WithinAbs( double target, double margin );
23770+
23771+
23772+
23773+ class WithinUlpsMatcher final : public MatcherBase<double> {
23774+ public:
23775+ WithinUlpsMatcher( double target,
23776+ uint64_t ulps,
23777+ Detail::FloatingPointKind baseType );
23778+ bool match(double const& matchee) const override;
23779+ std::string describe() const override;
23780+ private:
23781+ double m_target;
23782+ uint64_t m_ulps;
23783+ Detail::FloatingPointKind m_type;
23784+ };
23785+
23786+ //! Creates a matcher that accepts doubles within certain ULP range of target
23787+ WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff);
23788+ //! Creates a matcher that accepts floats within certain ULP range of target
23789+ WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff);
23790+
23791+
23792+
23793+ // Given IEEE-754 format for floats and doubles, we can assume
23794+ // that float -> double promotion is lossless. Given this, we can
23795+ // assume that if we do the standard relative comparison of
23796+ // |lhs - rhs| <= epsilon * max(fabs(lhs), fabs(rhs)), then we get
23797+ // the same result if we do this for floats, as if we do this for
23798+ // doubles that were promoted from floats.
23799+ class WithinRelMatcher final : public MatcherBase<double> {
23800+ public:
23801+ WithinRelMatcher( double target, double epsilon );
23802+ bool match(double const& matchee) const override;
23803+ std::string describe() const override;
23804+ private:
23805+ double m_target;
23806+ double m_epsilon;
23807+ };
23808+
23809+ //! Creates a matcher that accepts doubles within certain relative range of target
23810+ WithinRelMatcher WithinRel(double target, double eps);
23811+ //! Creates a matcher that accepts doubles within 100*DBL_EPS relative range of target
23812+ WithinRelMatcher WithinRel(double target);
23813+ //! Creates a matcher that accepts doubles within certain relative range of target
23814+ WithinRelMatcher WithinRel(float target, float eps);
23815+ //! Creates a matcher that accepts floats within 100*FLT_EPS relative range of target
23816+ WithinRelMatcher WithinRel(float target);
23817+
23818+
23819+
23820+ class IsNaNMatcher final : public MatcherBase<double> {
23821+ public:
23822+ IsNaNMatcher() = default;
23823+ bool match( double const& matchee ) const override;
23824+ std::string describe() const override;
23825+ };
23826+
23827+ IsNaNMatcher IsNaN();
23828+
23829+} // namespace Matchers
23830+} // namespace Catch
23831+
23832+#endif // CATCH_MATCHERS_FLOATING_POINT_HPP_INCLUDED
23833+
23834+
23835+#ifndef CATCH_MATCHERS_PREDICATE_HPP_INCLUDED
23836+#define CATCH_MATCHERS_PREDICATE_HPP_INCLUDED
23837+
23838+
23839+#include <string>
23840+
23841+namespace Catch {
23842+namespace Matchers {
23843+
23844+namespace Detail {
23845+ std::string finalizeDescription(const std::string& desc);
23846+} // namespace Detail
23847+
23848+template <typename T, typename Predicate>
23849+class PredicateMatcher final : public MatcherBase<T> {
23850+ Predicate m_predicate;
23851+ std::string m_description;
23852+public:
23853+
23854+ PredicateMatcher(Predicate&& elem, std::string const& descr)
23855+ :m_predicate(CATCH_FORWARD(elem)),
23856+ m_description(Detail::finalizeDescription(descr))
23857+ {}
23858+
23859+ bool match( T const& item ) const override {
23860+ return m_predicate(item);
23861+ }
23862+
23863+ std::string describe() const override {
23864+ return m_description;
23865+ }
23866+};
23867+
23868+ /**
23869+ * Creates a matcher that calls delegates `match` to the provided predicate.
23870+ *
23871+ * The user has to explicitly specify the argument type to the matcher
23872+ */
23873+ template<typename T, typename Pred>
23874+ PredicateMatcher<T, Pred> Predicate(Pred&& predicate, std::string const& description = "") {
23875+ static_assert(is_callable<Pred(T)>::value, "Predicate not callable with argument T");
23876+ static_assert(std::is_same<bool, FunctionReturnType<Pred, T>>::value, "Predicate does not return bool");
23877+ return PredicateMatcher<T, Pred>(CATCH_FORWARD(predicate), description);
23878+ }
23879+
23880+} // namespace Matchers
23881+} // namespace Catch
23882+
23883+#endif // CATCH_MATCHERS_PREDICATE_HPP_INCLUDED
23884+
23885+
23886+#ifndef CATCH_MATCHERS_QUANTIFIERS_HPP_INCLUDED
23887+#define CATCH_MATCHERS_QUANTIFIERS_HPP_INCLUDED
23888+
23889+
23890+namespace Catch {
23891+ namespace Matchers {
23892+ // Matcher for checking that all elements in range matches a given matcher.
23893+ template <typename Matcher>
23894+ class AllMatchMatcher final : public MatcherGenericBase {
23895+ Matcher m_matcher;
23896+ public:
23897+ AllMatchMatcher(Matcher matcher):
23898+ m_matcher(CATCH_MOVE(matcher))
23899+ {}
23900+
23901+ std::string describe() const override {
23902+ return "all match " + m_matcher.describe();
23903+ }
23904+
23905+ template <typename RangeLike>
23906+ bool match(RangeLike&& rng) const {
23907+ for (auto&& elem : rng) {
23908+ if (!m_matcher.match(elem)) {
23909+ return false;
23910+ }
23911+ }
23912+ return true;
23913+ }
23914+ };
23915+
23916+ // Matcher for checking that no element in range matches a given matcher.
23917+ template <typename Matcher>
23918+ class NoneMatchMatcher final : public MatcherGenericBase {
23919+ Matcher m_matcher;
23920+ public:
23921+ NoneMatchMatcher(Matcher matcher):
23922+ m_matcher(CATCH_MOVE(matcher))
23923+ {}
23924+
23925+ std::string describe() const override {
23926+ return "none match " + m_matcher.describe();
23927+ }
23928+
23929+ template <typename RangeLike>
23930+ bool match(RangeLike&& rng) const {
23931+ for (auto&& elem : rng) {
23932+ if (m_matcher.match(elem)) {
23933+ return false;
23934+ }
23935+ }
23936+ return true;
23937+ }
23938+ };
23939+
23940+ // Matcher for checking that at least one element in range matches a given matcher.
23941+ template <typename Matcher>
23942+ class AnyMatchMatcher final : public MatcherGenericBase {
23943+ Matcher m_matcher;
23944+ public:
23945+ AnyMatchMatcher(Matcher matcher):
23946+ m_matcher(CATCH_MOVE(matcher))
23947+ {}
23948+
23949+ std::string describe() const override {
23950+ return "any match " + m_matcher.describe();
23951+ }
23952+
23953+ template <typename RangeLike>
23954+ bool match(RangeLike&& rng) const {
23955+ for (auto&& elem : rng) {
23956+ if (m_matcher.match(elem)) {
23957+ return true;
23958+ }
23959+ }
23960+ return false;
23961+ }
23962+ };
23963+
23964+ // Matcher for checking that all elements in range are true.
23965+ class AllTrueMatcher final : public MatcherGenericBase {
23966+ public:
23967+ std::string describe() const override;
23968+
23969+ template <typename RangeLike>
23970+ bool match(RangeLike&& rng) const {
23971+ for (auto&& elem : rng) {
23972+ if (!elem) {
23973+ return false;
23974+ }
23975+ }
23976+ return true;
23977+ }
23978+ };
23979+
23980+ // Matcher for checking that no element in range is true.
23981+ class NoneTrueMatcher final : public MatcherGenericBase {
23982+ public:
23983+ std::string describe() const override;
23984+
23985+ template <typename RangeLike>
23986+ bool match(RangeLike&& rng) const {
23987+ for (auto&& elem : rng) {
23988+ if (elem) {
23989+ return false;
23990+ }
23991+ }
23992+ return true;
23993+ }
23994+ };
23995+
23996+ // Matcher for checking that any element in range is true.
23997+ class AnyTrueMatcher final : public MatcherGenericBase {
23998+ public:
23999+ std::string describe() const override;
24000+
24001+ template <typename RangeLike>
24002+ bool match(RangeLike&& rng) const {
24003+ for (auto&& elem : rng) {
24004+ if (elem) {
24005+ return true;
24006+ }
24007+ }
24008+ return false;
24009+ }
24010+ };
24011+
24012+ // Creates a matcher that checks whether all elements in a range match a matcher
24013+ template <typename Matcher>
24014+ AllMatchMatcher<Matcher> AllMatch(Matcher&& matcher) {
24015+ return { CATCH_FORWARD(matcher) };
24016+ }
24017+
24018+ // Creates a matcher that checks whether no element in a range matches a matcher.
24019+ template <typename Matcher>
24020+ NoneMatchMatcher<Matcher> NoneMatch(Matcher&& matcher) {
24021+ return { CATCH_FORWARD(matcher) };
24022+ }
24023+
24024+ // Creates a matcher that checks whether any element in a range matches a matcher.
24025+ template <typename Matcher>
24026+ AnyMatchMatcher<Matcher> AnyMatch(Matcher&& matcher) {
24027+ return { CATCH_FORWARD(matcher) };
24028+ }
24029+
24030+ // Creates a matcher that checks whether all elements in a range are true
24031+ AllTrueMatcher AllTrue();
24032+
24033+ // Creates a matcher that checks whether no element in a range is true
24034+ NoneTrueMatcher NoneTrue();
24035+
24036+ // Creates a matcher that checks whether any element in a range is true
24037+ AnyTrueMatcher AnyTrue();
24038+ }
24039+}
24040+
24041+#endif // CATCH_MATCHERS_QUANTIFIERS_HPP_INCLUDED
24042+
24043+
24044+#ifndef CATCH_MATCHERS_RANGE_EQUALS_HPP_INCLUDED
24045+#define CATCH_MATCHERS_RANGE_EQUALS_HPP_INCLUDED
24046+
24047+
24048+#include <algorithm>
24049+#include <utility>
24050+
24051+namespace Catch {
24052+ namespace Matchers {
24053+
24054+ /**
24055+ * Matcher for checking that an element contains the same
24056+ * elements in the same order
24057+ */
24058+ template <typename TargetRangeLike, typename Equality>
24059+ class RangeEqualsMatcher final : public MatcherGenericBase {
24060+ TargetRangeLike m_desired;
24061+ Equality m_predicate;
24062+
24063+ public:
24064+ template <typename TargetRangeLike2, typename Equality2>
24065+ RangeEqualsMatcher( TargetRangeLike2&& range,
24066+ Equality2&& predicate ):
24067+ m_desired( CATCH_FORWARD( range ) ),
24068+ m_predicate( CATCH_FORWARD( predicate ) ) {}
24069+
24070+ template <typename RangeLike>
24071+ bool match( RangeLike&& rng ) const {
24072+ auto rng_start = begin( rng );
24073+ const auto rng_end = end( rng );
24074+ auto target_start = begin( m_desired );
24075+ const auto target_end = end( m_desired );
24076+
24077+ while (rng_start != rng_end && target_start != target_end) {
24078+ if (!m_predicate(*rng_start, *target_start)) {
24079+ return false;
24080+ }
24081+ ++rng_start;
24082+ ++target_start;
24083+ }
24084+ return rng_start == rng_end && target_start == target_end;
24085+ }
24086+
24087+ std::string describe() const override {
24088+ return "elements are " + Catch::Detail::stringify( m_desired );
24089+ }
24090+ };
24091+
24092+ /**
24093+ * Matcher for checking that an element contains the same
24094+ * elements (but not necessarily in the same order)
24095+ */
24096+ template <typename TargetRangeLike, typename Equality>
24097+ class UnorderedRangeEqualsMatcher final : public MatcherGenericBase {
24098+ TargetRangeLike m_desired;
24099+ Equality m_predicate;
24100+
24101+ public:
24102+ template <typename TargetRangeLike2, typename Equality2>
24103+ UnorderedRangeEqualsMatcher( TargetRangeLike2&& range,
24104+ Equality2&& predicate ):
24105+ m_desired( CATCH_FORWARD( range ) ),
24106+ m_predicate( CATCH_FORWARD( predicate ) ) {}
24107+
24108+ template <typename RangeLike>
24109+ bool match( RangeLike&& rng ) const {
24110+ using std::begin;
24111+ using std::end;
24112+ return Catch::Detail::is_permutation( begin( m_desired ),
24113+ end( m_desired ),
24114+ begin( rng ),
24115+ end( rng ),
24116+ m_predicate );
24117+ }
24118+
24119+ std::string describe() const override {
24120+ return "unordered elements are " +
24121+ ::Catch::Detail::stringify( m_desired );
24122+ }
24123+ };
24124+
24125+ /**
24126+ * Creates a matcher that checks if all elements in a range are equal
24127+ * to all elements in another range.
24128+ *
24129+ * Uses `std::equal_to` to do the comparison
24130+ */
24131+ template <typename RangeLike>
24132+ std::enable_if_t<!Detail::is_matcher<RangeLike>::value,
24133+ RangeEqualsMatcher<RangeLike, std::equal_to<>>>
24134+ RangeEquals( RangeLike&& range ) {
24135+ return { CATCH_FORWARD( range ), std::equal_to<>{} };
24136+ }
24137+
24138+ /**
24139+ * Creates a matcher that checks if all elements in a range are equal
24140+ * to all elements in another range.
24141+ *
24142+ * Uses to provided predicate `predicate` to do the comparisons
24143+ */
24144+ template <typename RangeLike, typename Equality>
24145+ RangeEqualsMatcher<RangeLike, Equality>
24146+ RangeEquals( RangeLike&& range, Equality&& predicate ) {
24147+ return { CATCH_FORWARD( range ), CATCH_FORWARD( predicate ) };
24148+ }
24149+
24150+ /**
24151+ * Creates a matcher that checks if all elements in a range are equal
24152+ * to all elements in another range, in some permutation
24153+ *
24154+ * Uses `std::equal_to` to do the comparison
24155+ */
24156+ template <typename RangeLike>
24157+ std::enable_if_t<
24158+ !Detail::is_matcher<RangeLike>::value,
24159+ UnorderedRangeEqualsMatcher<RangeLike, std::equal_to<>>>
24160+ UnorderedRangeEquals( RangeLike&& range ) {
24161+ return { CATCH_FORWARD( range ), std::equal_to<>{} };
24162+ }
24163+
24164+ /**
24165+ * Creates a matcher that checks if all elements in a range are equal
24166+ * to all elements in another range, in some permutation.
24167+ *
24168+ * Uses to provided predicate `predicate` to do the comparisons
24169+ */
24170+ template <typename RangeLike, typename Equality>
24171+ UnorderedRangeEqualsMatcher<RangeLike, Equality>
24172+ UnorderedRangeEquals( RangeLike&& range, Equality&& predicate ) {
24173+ return { CATCH_FORWARD( range ), CATCH_FORWARD( predicate ) };
24174+ }
24175+ } // namespace Matchers
24176+} // namespace Catch
24177+
24178+#endif // CATCH_MATCHERS_RANGE_EQUALS_HPP_INCLUDED
24179+
24180+
24181+#ifndef CATCH_MATCHERS_STRING_HPP_INCLUDED
24182+#define CATCH_MATCHERS_STRING_HPP_INCLUDED
24183+
24184+
24185+#include <string>
24186+
24187+namespace Catch {
24188+namespace Matchers {
24189+
24190+ struct CasedString {
24191+ CasedString( std::string const& str, CaseSensitive caseSensitivity );
24192+ std::string adjustString( std::string const& str ) const;
24193+ StringRef caseSensitivitySuffix() const;
24194+
24195+ CaseSensitive m_caseSensitivity;
24196+ std::string m_str;
24197+ };
24198+
24199+ class StringMatcherBase : public MatcherBase<std::string> {
24200+ protected:
24201+ CasedString m_comparator;
24202+ StringRef m_operation;
24203+
24204+ public:
24205+ StringMatcherBase( StringRef operation,
24206+ CasedString const& comparator );
24207+ std::string describe() const override;
24208+ };
24209+
24210+ class StringEqualsMatcher final : public StringMatcherBase {
24211+ public:
24212+ StringEqualsMatcher( CasedString const& comparator );
24213+ bool match( std::string const& source ) const override;
24214+ };
24215+ class StringContainsMatcher final : public StringMatcherBase {
24216+ public:
24217+ StringContainsMatcher( CasedString const& comparator );
24218+ bool match( std::string const& source ) const override;
24219+ };
24220+ class StartsWithMatcher final : public StringMatcherBase {
24221+ public:
24222+ StartsWithMatcher( CasedString const& comparator );
24223+ bool match( std::string const& source ) const override;
24224+ };
24225+ class EndsWithMatcher final : public StringMatcherBase {
24226+ public:
24227+ EndsWithMatcher( CasedString const& comparator );
24228+ bool match( std::string const& source ) const override;
24229+ };
24230+
24231+ class RegexMatcher final : public MatcherBase<std::string> {
24232+ std::string m_regex;
24233+ CaseSensitive m_caseSensitivity;
24234+
24235+ public:
24236+ RegexMatcher( std::string regex, CaseSensitive caseSensitivity );
24237+ bool match( std::string const& matchee ) const override;
24238+ std::string describe() const override;
24239+ };
24240+
24241+ //! Creates matcher that accepts strings that are exactly equal to `str`
24242+ StringEqualsMatcher Equals( std::string const& str, CaseSensitive caseSensitivity = CaseSensitive::Yes );
24243+ //! Creates matcher that accepts strings that contain `str`
24244+ StringContainsMatcher ContainsSubstring( std::string const& str, CaseSensitive caseSensitivity = CaseSensitive::Yes );
24245+ //! Creates matcher that accepts strings that _end_ with `str`
24246+ EndsWithMatcher EndsWith( std::string const& str, CaseSensitive caseSensitivity = CaseSensitive::Yes );
24247+ //! Creates matcher that accepts strings that _start_ with `str`
24248+ StartsWithMatcher StartsWith( std::string const& str, CaseSensitive caseSensitivity = CaseSensitive::Yes );
24249+ //! Creates matcher that accepts strings matching `regex`
24250+ RegexMatcher Matches( std::string const& regex, CaseSensitive caseSensitivity = CaseSensitive::Yes );
24251+
24252+} // namespace Matchers
24253+} // namespace Catch
24254+
24255+#endif // CATCH_MATCHERS_STRING_HPP_INCLUDED
24256+
24257+
24258+#ifndef CATCH_MATCHERS_VECTOR_HPP_INCLUDED
24259+#define CATCH_MATCHERS_VECTOR_HPP_INCLUDED
24260+
24261+
24262+#include <algorithm>
24263+
24264+namespace Catch {
24265+namespace Matchers {
24266+
24267+ template<typename T, typename Alloc>
24268+ class VectorContainsElementMatcher final : public MatcherBase<std::vector<T, Alloc>> {
24269+ T const& m_comparator;
24270+
24271+ public:
24272+ VectorContainsElementMatcher(T const& comparator):
24273+ m_comparator(comparator)
24274+ {}
24275+
24276+ bool match(std::vector<T, Alloc> const& v) const override {
24277+ for (auto const& el : v) {
24278+ if (el == m_comparator) {
24279+ return true;
24280+ }
24281+ }
24282+ return false;
24283+ }
24284+
24285+ std::string describe() const override {
24286+ return "Contains: " + ::Catch::Detail::stringify( m_comparator );
24287+ }
24288+ };
24289+
24290+ template<typename T, typename AllocComp, typename AllocMatch>
24291+ class ContainsMatcher final : public MatcherBase<std::vector<T, AllocMatch>> {
24292+ std::vector<T, AllocComp> const& m_comparator;
24293+
24294+ public:
24295+ ContainsMatcher(std::vector<T, AllocComp> const& comparator):
24296+ m_comparator( comparator )
24297+ {}
24298+
24299+ bool match(std::vector<T, AllocMatch> const& v) const override {
24300+ // !TBD: see note in EqualsMatcher
24301+ if (m_comparator.size() > v.size())
24302+ return false;
24303+ for (auto const& comparator : m_comparator) {
24304+ auto present = false;
24305+ for (const auto& el : v) {
24306+ if (el == comparator) {
24307+ present = true;
24308+ break;
24309+ }
24310+ }
24311+ if (!present) {
24312+ return false;
24313+ }
24314+ }
24315+ return true;
24316+ }
24317+ std::string describe() const override {
24318+ return "Contains: " + ::Catch::Detail::stringify( m_comparator );
24319+ }
24320+ };
24321+
24322+ template<typename T, typename AllocComp, typename AllocMatch>
24323+ class EqualsMatcher final : public MatcherBase<std::vector<T, AllocMatch>> {
24324+ std::vector<T, AllocComp> const& m_comparator;
24325+
24326+ public:
24327+ EqualsMatcher(std::vector<T, AllocComp> const& comparator):
24328+ m_comparator( comparator )
24329+ {}
24330+
24331+ bool match(std::vector<T, AllocMatch> const& v) const override {
24332+ // !TBD: This currently works if all elements can be compared using !=
24333+ // - a more general approach would be via a compare template that defaults
24334+ // to using !=. but could be specialised for, e.g. std::vector<T> etc
24335+ // - then just call that directly
24336+ if ( m_comparator.size() != v.size() ) { return false; }
24337+ for ( std::size_t i = 0; i < v.size(); ++i ) {
24338+ if ( !( m_comparator[i] == v[i] ) ) { return false; }
24339+ }
24340+ return true;
24341+ }
24342+ std::string describe() const override {
24343+ return "Equals: " + ::Catch::Detail::stringify( m_comparator );
24344+ }
24345+ };
24346+
24347+ template<typename T, typename AllocComp, typename AllocMatch>
24348+ class ApproxMatcher final : public MatcherBase<std::vector<T, AllocMatch>> {
24349+ std::vector<T, AllocComp> const& m_comparator;
24350+ mutable Catch::Approx approx = Catch::Approx::custom();
24351+
24352+ public:
24353+ ApproxMatcher(std::vector<T, AllocComp> const& comparator):
24354+ m_comparator( comparator )
24355+ {}
24356+
24357+ bool match(std::vector<T, AllocMatch> const& v) const override {
24358+ if (m_comparator.size() != v.size())
24359+ return false;
24360+ for (std::size_t i = 0; i < v.size(); ++i)
24361+ if (m_comparator[i] != approx(v[i]))
24362+ return false;
24363+ return true;
24364+ }
24365+ std::string describe() const override {
24366+ return "is approx: " + ::Catch::Detail::stringify( m_comparator );
24367+ }
24368+ template <typename = std::enable_if_t<std::is_constructible<double, T>::value>>
24369+ ApproxMatcher& epsilon( T const& newEpsilon ) {
24370+ approx.epsilon(static_cast<double>(newEpsilon));
24371+ return *this;
24372+ }
24373+ template <typename = std::enable_if_t<std::is_constructible<double, T>::value>>
24374+ ApproxMatcher& margin( T const& newMargin ) {
24375+ approx.margin(static_cast<double>(newMargin));
24376+ return *this;
24377+ }
24378+ template <typename = std::enable_if_t<std::is_constructible<double, T>::value>>
24379+ ApproxMatcher& scale( T const& newScale ) {
24380+ approx.scale(static_cast<double>(newScale));
24381+ return *this;
24382+ }
24383+ };
24384+
24385+ template<typename T, typename AllocComp, typename AllocMatch>
24386+ class UnorderedEqualsMatcher final : public MatcherBase<std::vector<T, AllocMatch>> {
24387+ std::vector<T, AllocComp> const& m_target;
24388+
24389+ public:
24390+ UnorderedEqualsMatcher(std::vector<T, AllocComp> const& target):
24391+ m_target(target)
24392+ {}
24393+ bool match(std::vector<T, AllocMatch> const& vec) const override {
24394+ if (m_target.size() != vec.size()) {
24395+ return false;
24396+ }
24397+ return std::is_permutation(m_target.begin(), m_target.end(), vec.begin());
24398+ }
24399+
24400+ std::string describe() const override {
24401+ return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target);
24402+ }
24403+ };
24404+
24405+
24406+ // The following functions create the actual matcher objects.
24407+ // This allows the types to be inferred
24408+
24409+ //! Creates a matcher that matches vectors that contain all elements in `comparator`
24410+ template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>
24411+ ContainsMatcher<T, AllocComp, AllocMatch> Contains( std::vector<T, AllocComp> const& comparator ) {
24412+ return ContainsMatcher<T, AllocComp, AllocMatch>(comparator);
24413+ }
24414+
24415+ //! Creates a matcher that matches vectors that contain `comparator` as an element
24416+ template<typename T, typename Alloc = std::allocator<T>>
24417+ VectorContainsElementMatcher<T, Alloc> VectorContains( T const& comparator ) {
24418+ return VectorContainsElementMatcher<T, Alloc>(comparator);
24419+ }
24420+
24421+ //! Creates a matcher that matches vectors that are exactly equal to `comparator`
24422+ template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>
24423+ EqualsMatcher<T, AllocComp, AllocMatch> Equals( std::vector<T, AllocComp> const& comparator ) {
24424+ return EqualsMatcher<T, AllocComp, AllocMatch>(comparator);
24425+ }
24426+
24427+ //! Creates a matcher that matches vectors that `comparator` as an element
24428+ template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>
24429+ ApproxMatcher<T, AllocComp, AllocMatch> Approx( std::vector<T, AllocComp> const& comparator ) {
24430+ return ApproxMatcher<T, AllocComp, AllocMatch>(comparator);
24431+ }
24432+
24433+ //! Creates a matcher that matches vectors that is equal to `target` modulo permutation
24434+ template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>
24435+ UnorderedEqualsMatcher<T, AllocComp, AllocMatch> UnorderedEquals(std::vector<T, AllocComp> const& target) {
24436+ return UnorderedEqualsMatcher<T, AllocComp, AllocMatch>(target);
24437+ }
24438+
24439+} // namespace Matchers
24440+} // namespace Catch
24441+
24442+#endif // CATCH_MATCHERS_VECTOR_HPP_INCLUDED
24443+
24444+#endif // CATCH_MATCHERS_ALL_HPP_INCLUDED
24445+
24446+
24447+/** \file
24448+ * This is a convenience header for Catch2's Reporter support. It includes
24449+ * **all** of Catch2 headers related to reporters, including all reporters.
24450+ *
24451+ * Generally the Catch2 users should use specific includes they need,
24452+ * but this header can be used instead for ease-of-experimentation, or
24453+ * just plain convenience, at the cost of (significantly) increased
24454+ * compilation times.
24455+ *
24456+ * When a new header (reporter) is added to either the `reporter` folder,
24457+ * or to the corresponding internal subfolder, it should be added here.
24458+ */
24459+
24460+#ifndef CATCH_REPORTERS_ALL_HPP_INCLUDED
24461+#define CATCH_REPORTERS_ALL_HPP_INCLUDED
24462+
24463+
24464+
24465+#ifndef CATCH_REPORTER_AUTOMAKE_HPP_INCLUDED
24466+#define CATCH_REPORTER_AUTOMAKE_HPP_INCLUDED
24467+
24468+
24469+
24470+#ifndef CATCH_REPORTER_STREAMING_BASE_HPP_INCLUDED
24471+#define CATCH_REPORTER_STREAMING_BASE_HPP_INCLUDED
24472+
24473+
24474+
24475+#ifndef CATCH_REPORTER_COMMON_BASE_HPP_INCLUDED
24476+#define CATCH_REPORTER_COMMON_BASE_HPP_INCLUDED
24477+
24478+
24479+#include <map>
24480+#include <string>
24481+
24482+namespace Catch {
24483+ class ColourImpl;
24484+
24485+ /**
24486+ * This is the base class for all reporters.
24487+ *
24488+ * If are writing a reporter, you must derive from this type, or one
24489+ * of the helper reporter bases that are derived from this type.
24490+ *
24491+ * ReporterBase centralizes handling of various common tasks in reporters,
24492+ * like storing the right stream for the reporters to write to, and
24493+ * providing the default implementation of the different listing events.
24494+ */
24495+ class ReporterBase : public IEventListener {
24496+ protected:
24497+ //! The stream wrapper as passed to us by outside code
24498+ Detail::unique_ptr<IStream> m_wrapped_stream;
24499+ //! Cached output stream from `m_wrapped_stream` to reduce
24500+ //! number of indirect calls needed to write output.
24501+ std::ostream& m_stream;
24502+ //! Colour implementation this reporter was configured for
24503+ Detail::unique_ptr<ColourImpl> m_colour;
24504+ //! The custom reporter options user passed down to the reporter
24505+ std::map<std::string, std::string> m_customOptions;
24506+
24507+ public:
24508+ ReporterBase( ReporterConfig&& config );
24509+ ~ReporterBase() override; // = default;
24510+
24511+ /**
24512+ * Provides a simple default listing of reporters.
24513+ *
24514+ * Should look roughly like the reporter listing in v2 and earlier
24515+ * versions of Catch2.
24516+ */
24517+ void listReporters(
24518+ std::vector<ReporterDescription> const& descriptions ) override;
24519+ /**
24520+ * Provides a simple default listing of listeners
24521+ *
24522+ * Looks similarly to listing of reporters, but with listener type
24523+ * instead of reporter name.
24524+ */
24525+ void listListeners(
24526+ std::vector<ListenerDescription> const& descriptions ) override;
24527+ /**
24528+ * Provides a simple default listing of tests.
24529+ *
24530+ * Should look roughly like the test listing in v2 and earlier versions
24531+ * of Catch2. Especially supports low-verbosity listing that mimics the
24532+ * old `--list-test-names-only` output.
24533+ */
24534+ void listTests( std::vector<TestCaseHandle> const& tests ) override;
24535+ /**
24536+ * Provides a simple default listing of tags.
24537+ *
24538+ * Should look roughly like the tag listing in v2 and earlier versions
24539+ * of Catch2.
24540+ */
24541+ void listTags( std::vector<TagInfo> const& tags ) override;
24542+ };
24543+} // namespace Catch
24544+
24545+#endif // CATCH_REPORTER_COMMON_BASE_HPP_INCLUDED
24546+
24547+#include <vector>
24548+
24549+namespace Catch {
24550+
24551+ class StreamingReporterBase : public ReporterBase {
24552+ public:
24553+ // GCC5 compat: we cannot use inherited constructor, because it
24554+ // doesn't implement backport of P0136
24555+ StreamingReporterBase(ReporterConfig&& _config):
24556+ ReporterBase(CATCH_MOVE(_config))
24557+ {}
24558+ ~StreamingReporterBase() override;
24559+
24560+ void benchmarkPreparing( StringRef ) override {}
24561+ void benchmarkStarting( BenchmarkInfo const& ) override {}
24562+ void benchmarkEnded( BenchmarkStats<> const& ) override {}
24563+ void benchmarkFailed( StringRef ) override {}
24564+
24565+ void fatalErrorEncountered( StringRef /*error*/ ) override {}
24566+ void noMatchingTestCases( StringRef /*unmatchedSpec*/ ) override {}
24567+ void reportInvalidTestSpec( StringRef /*invalidArgument*/ ) override {}
24568+
24569+ void testRunStarting( TestRunInfo const& _testRunInfo ) override;
24570+
24571+ void testCaseStarting(TestCaseInfo const& _testInfo) override {
24572+ currentTestCaseInfo = &_testInfo;
24573+ }
24574+ void testCasePartialStarting( TestCaseInfo const&, uint64_t ) override {}
24575+ void sectionStarting(SectionInfo const& _sectionInfo) override {
24576+ m_sectionStack.push_back(_sectionInfo);
24577+ }
24578+
24579+ void assertionStarting( AssertionInfo const& ) override {}
24580+ void assertionEnded( AssertionStats const& ) override {}
24581+
24582+ void sectionEnded(SectionStats const& /* _sectionStats */) override {
24583+ m_sectionStack.pop_back();
24584+ }
24585+ void testCasePartialEnded( TestCaseStats const&, uint64_t ) override {}
24586+ void testCaseEnded(TestCaseStats const& /* _testCaseStats */) override {
24587+ currentTestCaseInfo = nullptr;
24588+ }
24589+ void testRunEnded( TestRunStats const& /* _testRunStats */ ) override;
24590+
24591+ void skipTest(TestCaseInfo const&) override {
24592+ // Don't do anything with this by default.
24593+ // It can optionally be overridden in the derived class.
24594+ }
24595+
24596+ protected:
24597+ TestRunInfo currentTestRunInfo{ "test run has not started yet"_sr };
24598+ TestCaseInfo const* currentTestCaseInfo = nullptr;
24599+
24600+ //! Stack of all _active_ sections in the _current_ test case
24601+ std::vector<SectionInfo> m_sectionStack;
24602+ };
24603+
24604+} // end namespace Catch
24605+
24606+#endif // CATCH_REPORTER_STREAMING_BASE_HPP_INCLUDED
24607+
24608+#include <string>
24609+
24610+namespace Catch {
24611+
24612+ class AutomakeReporter final : public StreamingReporterBase {
24613+ public:
24614+ // GCC5 compat: we cannot use inherited constructor, because it
24615+ // doesn't implement backport of P0136
24616+ AutomakeReporter(ReporterConfig&& _config):
24617+ StreamingReporterBase(CATCH_MOVE(_config))
24618+ {}
24619+ ~AutomakeReporter() override;
24620+
24621+ static std::string getDescription() {
24622+ using namespace std::string_literals;
24623+ return "Reports test results in the format of Automake .trs files"s;
24624+ }
24625+
24626+ void testCaseEnded(TestCaseStats const& _testCaseStats) override;
24627+ void skipTest(TestCaseInfo const& testInfo) override;
24628+ };
24629+
24630+} // end namespace Catch
24631+
24632+#endif // CATCH_REPORTER_AUTOMAKE_HPP_INCLUDED
24633+
24634+
24635+#ifndef CATCH_REPORTER_COMPACT_HPP_INCLUDED
24636+#define CATCH_REPORTER_COMPACT_HPP_INCLUDED
24637+
24638+
24639+
24640+
24641+namespace Catch {
24642+
24643+ class CompactReporter final : public StreamingReporterBase {
24644+ public:
24645+ using StreamingReporterBase::StreamingReporterBase;
24646+
24647+ ~CompactReporter() override;
24648+
24649+ static std::string getDescription();
24650+
24651+ void noMatchingTestCases( StringRef unmatchedSpec ) override;
24652+
24653+ void testRunStarting( TestRunInfo const& _testInfo ) override;
24654+
24655+ void assertionEnded(AssertionStats const& _assertionStats) override;
24656+
24657+ void sectionEnded(SectionStats const& _sectionStats) override;
24658+
24659+ void testRunEnded(TestRunStats const& _testRunStats) override;
24660+
24661+ };
24662+
24663+} // end namespace Catch
24664+
24665+#endif // CATCH_REPORTER_COMPACT_HPP_INCLUDED
24666+
24667+
24668+#ifndef CATCH_REPORTER_CONSOLE_HPP_INCLUDED
24669+#define CATCH_REPORTER_CONSOLE_HPP_INCLUDED
24670+
24671+
24672+namespace Catch {
24673+ // Fwd decls
24674+ class TablePrinter;
24675+
24676+ class ConsoleReporter final : public StreamingReporterBase {
24677+ Detail::unique_ptr<TablePrinter> m_tablePrinter;
24678+
24679+ public:
24680+ ConsoleReporter(ReporterConfig&& config);
24681+ ~ConsoleReporter() override;
24682+ static std::string getDescription();
24683+
24684+ void noMatchingTestCases( StringRef unmatchedSpec ) override;
24685+ void reportInvalidTestSpec( StringRef arg ) override;
24686+
24687+ void assertionStarting(AssertionInfo const&) override;
24688+
24689+ void assertionEnded(AssertionStats const& _assertionStats) override;
24690+
24691+ void sectionStarting(SectionInfo const& _sectionInfo) override;
24692+ void sectionEnded(SectionStats const& _sectionStats) override;
24693+
24694+ void benchmarkPreparing( StringRef name ) override;
24695+ void benchmarkStarting(BenchmarkInfo const& info) override;
24696+ void benchmarkEnded(BenchmarkStats<> const& stats) override;
24697+ void benchmarkFailed( StringRef error ) override;
24698+
24699+ void testCaseEnded(TestCaseStats const& _testCaseStats) override;
24700+ void testRunEnded(TestRunStats const& _testRunStats) override;
24701+ void testRunStarting(TestRunInfo const& _testRunInfo) override;
24702+
24703+ private:
24704+ void lazyPrint();
24705+
24706+ void lazyPrintWithoutClosingBenchmarkTable();
24707+ void lazyPrintRunInfo();
24708+ void printTestCaseAndSectionHeader();
24709+
24710+ void printClosedHeader(std::string const& _name);
24711+ void printOpenHeader(std::string const& _name);
24712+
24713+ // if string has a : in first line will set indent to follow it on
24714+ // subsequent lines
24715+ void printHeaderString(std::string const& _string, std::size_t indent = 0);
24716+
24717+ void printTotalsDivider(Totals const& totals);
24718+
24719+ bool m_headerPrinted = false;
24720+ bool m_testRunInfoPrinted = false;
24721+ };
24722+
24723+} // end namespace Catch
24724+
24725+#endif // CATCH_REPORTER_CONSOLE_HPP_INCLUDED
24726+
24727+
24728+#ifndef CATCH_REPORTER_CUMULATIVE_BASE_HPP_INCLUDED
24729+#define CATCH_REPORTER_CUMULATIVE_BASE_HPP_INCLUDED
24730+
24731+
24732+#include <string>
24733+#include <vector>
24734+
24735+namespace Catch {
24736+
24737+ namespace Detail {
24738+
24739+ //! Represents either an assertion or a benchmark result to be handled by cumulative reporter later
24740+ class AssertionOrBenchmarkResult {
24741+ // This should really be a variant, but this is much faster
24742+ // to write and the data layout here is already terrible
24743+ // enough that we do not have to care about the object size.
24744+ Optional<AssertionStats> m_assertion;
24745+ Optional<BenchmarkStats<>> m_benchmark;
24746+ public:
24747+ AssertionOrBenchmarkResult(AssertionStats const& assertion);
24748+ AssertionOrBenchmarkResult(BenchmarkStats<> const& benchmark);
24749+
24750+ bool isAssertion() const;
24751+ bool isBenchmark() const;
24752+
24753+ AssertionStats const& asAssertion() const;
24754+ BenchmarkStats<> const& asBenchmark() const;
24755+ };
24756+ }
24757+
24758+ /**
24759+ * Utility base for reporters that need to handle all results at once
24760+ *
24761+ * It stores tree of all test cases, sections and assertions, and after the
24762+ * test run is finished, calls into `testRunEndedCumulative` to pass the
24763+ * control to the deriving class.
24764+ *
24765+ * If you are deriving from this class and override any testing related
24766+ * member functions, you should first call into the base's implementation to
24767+ * avoid breaking the tree construction.
24768+ *
24769+ * Due to the way this base functions, it has to expand assertions up-front,
24770+ * even if they are later unused (e.g. because the deriving reporter does
24771+ * not report successful assertions, or because the deriving reporter does
24772+ * not use assertion expansion at all). Derived classes can use two
24773+ * customization points, `m_shouldStoreSuccesfulAssertions` and
24774+ * `m_shouldStoreFailedAssertions`, to disable the expansion and gain extra
24775+ * performance. **Accessing the assertion expansions if it wasn't stored is
24776+ * UB.**
24777+ */
24778+ class CumulativeReporterBase : public ReporterBase {
24779+ public:
24780+ template<typename T, typename ChildNodeT>
24781+ struct Node {
24782+ explicit Node( T const& _value ) : value( _value ) {}
24783+
24784+ using ChildNodes = std::vector<Detail::unique_ptr<ChildNodeT>>;
24785+ T value;
24786+ ChildNodes children;
24787+ };
24788+ struct SectionNode {
24789+ explicit SectionNode(SectionStats const& _stats) : stats(_stats) {}
24790+
24791+ bool operator == (SectionNode const& other) const {
24792+ return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo;
24793+ }
24794+
24795+ bool hasAnyAssertions() const;
24796+
24797+ SectionStats stats;
24798+ std::vector<Detail::unique_ptr<SectionNode>> childSections;
24799+ std::vector<Detail::AssertionOrBenchmarkResult> assertionsAndBenchmarks;
24800+ std::string stdOut;
24801+ std::string stdErr;
24802+ };
24803+
24804+
24805+ using TestCaseNode = Node<TestCaseStats, SectionNode>;
24806+ using TestRunNode = Node<TestRunStats, TestCaseNode>;
24807+
24808+ // GCC5 compat: we cannot use inherited constructor, because it
24809+ // doesn't implement backport of P0136
24810+ CumulativeReporterBase(ReporterConfig&& _config):
24811+ ReporterBase(CATCH_MOVE(_config))
24812+ {}
24813+ ~CumulativeReporterBase() override;
24814+
24815+ void benchmarkPreparing( StringRef ) override {}
24816+ void benchmarkStarting( BenchmarkInfo const& ) override {}
24817+ void benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) override;
24818+ void benchmarkFailed( StringRef ) override {}
24819+
24820+ void noMatchingTestCases( StringRef ) override {}
24821+ void reportInvalidTestSpec( StringRef ) override {}
24822+ void fatalErrorEncountered( StringRef /*error*/ ) override {}
24823+
24824+ void testRunStarting( TestRunInfo const& ) override {}
24825+
24826+ void testCaseStarting( TestCaseInfo const& ) override {}
24827+ void testCasePartialStarting( TestCaseInfo const&, uint64_t ) override {}
24828+ void sectionStarting( SectionInfo const& sectionInfo ) override;
24829+
24830+ void assertionStarting( AssertionInfo const& ) override {}
24831+
24832+ void assertionEnded( AssertionStats const& assertionStats ) override;
24833+ void sectionEnded( SectionStats const& sectionStats ) override;
24834+ void testCasePartialEnded( TestCaseStats const&, uint64_t ) override {}
24835+ void testCaseEnded( TestCaseStats const& testCaseStats ) override;
24836+ void testRunEnded( TestRunStats const& testRunStats ) override;
24837+ //! Customization point: called after last test finishes (testRunEnded has been handled)
24838+ virtual void testRunEndedCumulative() = 0;
24839+
24840+ void skipTest(TestCaseInfo const&) override {}
24841+
24842+ protected:
24843+ //! Should the cumulative base store the assertion expansion for successful assertions?
24844+ bool m_shouldStoreSuccesfulAssertions = true;
24845+ //! Should the cumulative base store the assertion expansion for failed assertions?
24846+ bool m_shouldStoreFailedAssertions = true;
24847+
24848+ // We need lazy construction here. We should probably refactor it
24849+ // later, after the events are redone.
24850+ //! The root node of the test run tree.
24851+ Detail::unique_ptr<TestRunNode> m_testRun;
24852+
24853+ private:
24854+ // Note: We rely on pointer identity being stable, which is why
24855+ // we store pointers to the nodes rather than the values.
24856+ std::vector<Detail::unique_ptr<TestCaseNode>> m_testCases;
24857+ // Root section of the _current_ test case
24858+ Detail::unique_ptr<SectionNode> m_rootSection;
24859+ // Deepest section of the _current_ test case
24860+ SectionNode* m_deepestSection = nullptr;
24861+ // Stack of _active_ sections in the _current_ test case
24862+ std::vector<SectionNode*> m_sectionStack;
24863+ };
24864+
24865+} // end namespace Catch
24866+
24867+#endif // CATCH_REPORTER_CUMULATIVE_BASE_HPP_INCLUDED
24868+
24869+
24870+#ifndef CATCH_REPORTER_EVENT_LISTENER_HPP_INCLUDED
24871+#define CATCH_REPORTER_EVENT_LISTENER_HPP_INCLUDED
24872+
24873+
24874+namespace Catch {
24875+
24876+ /**
24877+ * Base class to simplify implementing listeners.
24878+ *
24879+ * Provides empty default implementation for all IEventListener member
24880+ * functions, so that a listener implementation can pick which
24881+ * member functions it actually cares about.
24882+ */
24883+ class EventListenerBase : public IEventListener {
24884+ public:
24885+ using IEventListener::IEventListener;
24886+
24887+ void reportInvalidTestSpec( StringRef unmatchedSpec ) override;
24888+ void fatalErrorEncountered( StringRef error ) override;
24889+
24890+ void benchmarkPreparing( StringRef name ) override;
24891+ void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) override;
24892+ void benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) override;
24893+ void benchmarkFailed( StringRef error ) override;
24894+
24895+ void assertionStarting( AssertionInfo const& assertionInfo ) override;
24896+ void assertionEnded( AssertionStats const& assertionStats ) override;
24897+
24898+ void listReporters(
24899+ std::vector<ReporterDescription> const& descriptions ) override;
24900+ void listListeners(
24901+ std::vector<ListenerDescription> const& descriptions ) override;
24902+ void listTests( std::vector<TestCaseHandle> const& tests ) override;
24903+ void listTags( std::vector<TagInfo> const& tagInfos ) override;
24904+
24905+ void noMatchingTestCases( StringRef unmatchedSpec ) override;
24906+ void testRunStarting( TestRunInfo const& testRunInfo ) override;
24907+ void testCaseStarting( TestCaseInfo const& testInfo ) override;
24908+ void testCasePartialStarting( TestCaseInfo const& testInfo,
24909+ uint64_t partNumber ) override;
24910+ void sectionStarting( SectionInfo const& sectionInfo ) override;
24911+ void sectionEnded( SectionStats const& sectionStats ) override;
24912+ void testCasePartialEnded( TestCaseStats const& testCaseStats,
24913+ uint64_t partNumber ) override;
24914+ void testCaseEnded( TestCaseStats const& testCaseStats ) override;
24915+ void testRunEnded( TestRunStats const& testRunStats ) override;
24916+ void skipTest( TestCaseInfo const& testInfo ) override;
24917+ };
24918+
24919+} // end namespace Catch
24920+
24921+#endif // CATCH_REPORTER_EVENT_LISTENER_HPP_INCLUDED
24922+
24923+
24924+#ifndef CATCH_REPORTER_HELPERS_HPP_INCLUDED
24925+#define CATCH_REPORTER_HELPERS_HPP_INCLUDED
24926+
24927+#include <iosfwd>
24928+#include <string>
24929+#include <vector>
24930+
24931+
24932+namespace Catch {
24933+
24934+ class IConfig;
24935+ class TestCaseHandle;
24936+ class ColourImpl;
24937+
24938+ // Returns double formatted as %.3f (format expected on output)
24939+ std::string getFormattedDuration( double duration );
24940+
24941+ //! Should the reporter show duration of test given current configuration?
24942+ bool shouldShowDuration( IConfig const& config, double duration );
24943+
24944+ std::string serializeFilters( std::vector<std::string> const& filters );
24945+
24946+ struct lineOfChars {
24947+ char c;
24948+ constexpr lineOfChars( char c_ ): c( c_ ) {}
24949+
24950+ friend std::ostream& operator<<( std::ostream& out, lineOfChars value );
24951+ };
24952+
24953+ /**
24954+ * Lists reporter descriptions to the provided stream in user-friendly
24955+ * format
24956+ *
24957+ * Used as the default listing implementation by the first party reporter
24958+ * bases. The output should be backwards compatible with the output of
24959+ * Catch2 v2 binaries.
24960+ */
24961+ void
24962+ defaultListReporters( std::ostream& out,
24963+ std::vector<ReporterDescription> const& descriptions,
24964+ Verbosity verbosity );
24965+
24966+ /**
24967+ * Lists listeners descriptions to the provided stream in user-friendly
24968+ * format
24969+ */
24970+ void defaultListListeners( std::ostream& out,
24971+ std::vector<ListenerDescription> const& descriptions );
24972+
24973+ /**
24974+ * Lists tag information to the provided stream in user-friendly format
24975+ *
24976+ * Used as the default listing implementation by the first party reporter
24977+ * bases. The output should be backwards compatible with the output of
24978+ * Catch2 v2 binaries.
24979+ */
24980+ void defaultListTags( std::ostream& out, std::vector<TagInfo> const& tags, bool isFiltered );
24981+
24982+ /**
24983+ * Lists test case information to the provided stream in user-friendly
24984+ * format
24985+ *
24986+ * Used as the default listing implementation by the first party reporter
24987+ * bases. The output is backwards compatible with the output of Catch2
24988+ * v2 binaries, and also supports the format specific to the old
24989+ * `--list-test-names-only` option, for people who used it in integrations.
24990+ */
24991+ void defaultListTests( std::ostream& out,
24992+ ColourImpl* streamColour,
24993+ std::vector<TestCaseHandle> const& tests,
24994+ bool isFiltered,
24995+ Verbosity verbosity );
24996+
24997+ /**
24998+ * Prints test run totals to the provided stream in user-friendly format
24999+ *
25000+ * Used by the console and compact reporters.
25001+ */
25002+ void printTestRunTotals( std::ostream& stream,
25003+ ColourImpl& streamColour,
25004+ Totals const& totals );
25005+
25006+} // end namespace Catch
25007+
25008+#endif // CATCH_REPORTER_HELPERS_HPP_INCLUDED
25009+
25010+
25011+
25012+#ifndef CATCH_REPORTER_JSON_HPP_INCLUDED
25013+#define CATCH_REPORTER_JSON_HPP_INCLUDED
25014+
25015+
25016+#include <stack>
25017+
25018+namespace Catch {
25019+ class JsonReporter : public StreamingReporterBase {
25020+ public:
25021+ JsonReporter( ReporterConfig&& config );
25022+
25023+ ~JsonReporter() override;
25024+
25025+ static std::string getDescription();
25026+
25027+ public: // StreamingReporterBase
25028+ void testRunStarting( TestRunInfo const& runInfo ) override;
25029+ void testRunEnded( TestRunStats const& runStats ) override;
25030+
25031+ void testCaseStarting( TestCaseInfo const& tcInfo ) override;
25032+ void testCaseEnded( TestCaseStats const& tcStats ) override;
25033+
25034+ void testCasePartialStarting( TestCaseInfo const& tcInfo,
25035+ uint64_t index ) override;
25036+ void testCasePartialEnded( TestCaseStats const& tcStats,
25037+ uint64_t index ) override;
25038+
25039+ void sectionStarting( SectionInfo const& sectionInfo ) override;
25040+ void sectionEnded( SectionStats const& sectionStats ) override;
25041+
25042+ void assertionStarting( AssertionInfo const& assertionInfo ) override;
25043+ void assertionEnded( AssertionStats const& assertionStats ) override;
25044+
25045+ //void testRunEndedCumulative() override;
25046+
25047+ void benchmarkPreparing( StringRef name ) override;
25048+ void benchmarkStarting( BenchmarkInfo const& ) override;
25049+ void benchmarkEnded( BenchmarkStats<> const& ) override;
25050+ void benchmarkFailed( StringRef error ) override;
25051+
25052+ void listReporters(
25053+ std::vector<ReporterDescription> const& descriptions ) override;
25054+ void listListeners(
25055+ std::vector<ListenerDescription> const& descriptions ) override;
25056+ void listTests( std::vector<TestCaseHandle> const& tests ) override;
25057+ void listTags( std::vector<TagInfo> const& tags ) override;
25058+
25059+ private:
25060+ Timer m_testCaseTimer;
25061+ enum class Writer {
25062+ Object,
25063+ Array
25064+ };
25065+
25066+ JsonArrayWriter& startArray();
25067+ JsonArrayWriter& startArray( StringRef key );
25068+
25069+ JsonObjectWriter& startObject();
25070+ JsonObjectWriter& startObject( StringRef key );
25071+
25072+ void endObject();
25073+ void endArray();
25074+
25075+ bool isInside( Writer writer );
25076+
25077+ void startListing();
25078+ void endListing();
25079+
25080+ // Invariant:
25081+ // When m_writers is not empty and its top element is
25082+ // - Writer::Object, then m_objectWriters is not be empty
25083+ // - Writer::Array, then m_arrayWriters shall not be empty
25084+ std::stack<JsonObjectWriter> m_objectWriters{};
25085+ std::stack<JsonArrayWriter> m_arrayWriters{};
25086+ std::stack<Writer> m_writers{};
25087+
25088+ bool m_startedListing = false;
25089+
25090+ // std::size_t m_sectionDepth = 0;
25091+ // std::size_t m_sectionStarted = 0;
25092+ };
25093+} // namespace Catch
25094+
25095+#endif // CATCH_REPORTER_JSON_HPP_INCLUDED
25096+
25097+
25098+#ifndef CATCH_REPORTER_JUNIT_HPP_INCLUDED
25099+#define CATCH_REPORTER_JUNIT_HPP_INCLUDED
25100+
25101+
25102+
25103+namespace Catch {
25104+
25105+ class JunitReporter final : public CumulativeReporterBase {
25106+ public:
25107+ JunitReporter(ReporterConfig&& _config);
25108+
25109+ static std::string getDescription();
25110+
25111+ void testRunStarting(TestRunInfo const& runInfo) override;
25112+
25113+ void testCaseStarting(TestCaseInfo const& testCaseInfo) override;
25114+ void assertionEnded(AssertionStats const& assertionStats) override;
25115+
25116+ void testCaseEnded(TestCaseStats const& testCaseStats) override;
25117+
25118+ void testRunEndedCumulative() override;
25119+
25120+ private:
25121+ void writeRun(TestRunNode const& testRunNode, double suiteTime);
25122+
25123+ void writeTestCase(TestCaseNode const& testCaseNode);
25124+
25125+ void writeSection( std::string const& className,
25126+ std::string const& rootName,
25127+ SectionNode const& sectionNode,
25128+ bool testOkToFail );
25129+
25130+ void writeAssertions(SectionNode const& sectionNode);
25131+ void writeAssertion(AssertionStats const& stats);
25132+
25133+ XmlWriter xml;
25134+ Timer suiteTimer;
25135+ std::string stdOutForSuite;
25136+ std::string stdErrForSuite;
25137+ unsigned int unexpectedExceptions = 0;
25138+ bool m_okToFail = false;
25139+ };
25140+
25141+} // end namespace Catch
25142+
25143+#endif // CATCH_REPORTER_JUNIT_HPP_INCLUDED
25144+
25145+
25146+#ifndef CATCH_REPORTER_MULTI_HPP_INCLUDED
25147+#define CATCH_REPORTER_MULTI_HPP_INCLUDED
25148+
25149+
25150+namespace Catch {
25151+
25152+ class MultiReporter final : public IEventListener {
25153+ /*
25154+ * Stores all added reporters and listeners
25155+ *
25156+ * All Listeners are stored before all reporters, and individual
25157+ * listeners/reporters are stored in order of insertion.
25158+ */
25159+ std::vector<IEventListenerPtr> m_reporterLikes;
25160+ bool m_haveNoncapturingReporters = false;
25161+
25162+ // Keep track of how many listeners we have already inserted,
25163+ // so that we can insert them into the main vector at the right place
25164+ size_t m_insertedListeners = 0;
25165+
25166+ void updatePreferences(IEventListener const& reporterish);
25167+
25168+ public:
25169+ using IEventListener::IEventListener;
25170+
25171+ void addListener( IEventListenerPtr&& listener );
25172+ void addReporter( IEventListenerPtr&& reporter );
25173+
25174+ public: // IEventListener
25175+
25176+ void noMatchingTestCases( StringRef unmatchedSpec ) override;
25177+ void fatalErrorEncountered( StringRef error ) override;
25178+ void reportInvalidTestSpec( StringRef arg ) override;
25179+
25180+ void benchmarkPreparing( StringRef name ) override;
25181+ void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) override;
25182+ void benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) override;
25183+ void benchmarkFailed( StringRef error ) override;
25184+
25185+ void testRunStarting( TestRunInfo const& testRunInfo ) override;
25186+ void testCaseStarting( TestCaseInfo const& testInfo ) override;
25187+ void testCasePartialStarting(TestCaseInfo const& testInfo, uint64_t partNumber) override;
25188+ void sectionStarting( SectionInfo const& sectionInfo ) override;
25189+ void assertionStarting( AssertionInfo const& assertionInfo ) override;
25190+
25191+ void assertionEnded( AssertionStats const& assertionStats ) override;
25192+ void sectionEnded( SectionStats const& sectionStats ) override;
25193+ void testCasePartialEnded(TestCaseStats const& testStats, uint64_t partNumber) override;
25194+ void testCaseEnded( TestCaseStats const& testCaseStats ) override;
25195+ void testRunEnded( TestRunStats const& testRunStats ) override;
25196+
25197+ void skipTest( TestCaseInfo const& testInfo ) override;
25198+
25199+ void listReporters(std::vector<ReporterDescription> const& descriptions) override;
25200+ void listListeners(std::vector<ListenerDescription> const& descriptions) override;
25201+ void listTests(std::vector<TestCaseHandle> const& tests) override;
25202+ void listTags(std::vector<TagInfo> const& tags) override;
25203+
25204+
25205+ };
25206+
25207+} // end namespace Catch
25208+
25209+#endif // CATCH_REPORTER_MULTI_HPP_INCLUDED
25210+
25211+
25212+#ifndef CATCH_REPORTER_REGISTRARS_HPP_INCLUDED
25213+#define CATCH_REPORTER_REGISTRARS_HPP_INCLUDED
25214+
25215+
25216+#include <type_traits>
25217+
25218+namespace Catch {
25219+
25220+ namespace Detail {
25221+
25222+ template <typename T, typename = void>
25223+ struct has_description : std::false_type {};
25224+
25225+ template <typename T>
25226+ struct has_description<
25227+ T,
25228+ void_t<decltype( T::getDescription() )>>
25229+ : std::true_type {};
25230+
25231+ //! Indirection for reporter registration, so that the error handling is
25232+ //! independent on the reporter's concrete type
25233+ void registerReporterImpl( std::string const& name,
25234+ IReporterFactoryPtr reporterPtr );
25235+ //! Actually registers the factory, independent on listener's concrete type
25236+ void registerListenerImpl( Detail::unique_ptr<EventListenerFactory> listenerFactory );
25237+ } // namespace Detail
25238+
25239+ class IEventListener;
25240+ using IEventListenerPtr = Detail::unique_ptr<IEventListener>;
25241+
25242+ template <typename T>
25243+ class ReporterFactory : public IReporterFactory {
25244+
25245+ IEventListenerPtr create( ReporterConfig&& config ) const override {
25246+ return Detail::make_unique<T>( CATCH_MOVE(config) );
25247+ }
25248+
25249+ std::string getDescription() const override {
25250+ return T::getDescription();
25251+ }
25252+ };
25253+
25254+
25255+ template<typename T>
25256+ class ReporterRegistrar {
25257+ public:
25258+ explicit ReporterRegistrar( std::string const& name ) {
25259+ registerReporterImpl( name,
25260+ Detail::make_unique<ReporterFactory<T>>() );
25261+ }
25262+ };
25263+
25264+ template<typename T>
25265+ class ListenerRegistrar {
25266+
25267+ class TypedListenerFactory : public EventListenerFactory {
25268+ StringRef m_listenerName;
25269+
25270+ std::string getDescriptionImpl( std::true_type ) const {
25271+ return T::getDescription();
25272+ }
25273+
25274+ std::string getDescriptionImpl( std::false_type ) const {
25275+ return "(No description provided)";
25276+ }
25277+
25278+ public:
25279+ TypedListenerFactory( StringRef listenerName ):
25280+ m_listenerName( listenerName ) {}
25281+
25282+ IEventListenerPtr create( IConfig const* config ) const override {
25283+ return Detail::make_unique<T>( config );
25284+ }
25285+
25286+ StringRef getName() const override {
25287+ return m_listenerName;
25288+ }
25289+
25290+ std::string getDescription() const override {
25291+ return getDescriptionImpl( Detail::has_description<T>{} );
25292+ }
25293+ };
25294+
25295+ public:
25296+ ListenerRegistrar(StringRef listenerName) {
25297+ registerListenerImpl( Detail::make_unique<TypedListenerFactory>(listenerName) );
25298+ }
25299+ };
25300+}
25301+
25302+#if !defined(CATCH_CONFIG_DISABLE)
25303+
25304+# define CATCH_REGISTER_REPORTER( name, reporterType ) \
25305+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
25306+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
25307+ namespace { \
25308+ Catch::ReporterRegistrar<reporterType> INTERNAL_CATCH_UNIQUE_NAME( \
25309+ catch_internal_RegistrarFor )( name ); \
25310+ } \
25311+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
25312+
25313+# define CATCH_REGISTER_LISTENER( listenerType ) \
25314+ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
25315+ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
25316+ namespace { \
25317+ Catch::ListenerRegistrar<listenerType> INTERNAL_CATCH_UNIQUE_NAME( \
25318+ catch_internal_RegistrarFor )( #listenerType##_catch_sr ); \
25319+ } \
25320+ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
25321+
25322+#else // CATCH_CONFIG_DISABLE
25323+
25324+#define CATCH_REGISTER_REPORTER(name, reporterType)
25325+#define CATCH_REGISTER_LISTENER(listenerType)
25326+
25327+#endif // CATCH_CONFIG_DISABLE
25328+
25329+#endif // CATCH_REPORTER_REGISTRARS_HPP_INCLUDED
25330+
25331+
25332+#ifndef CATCH_REPORTER_SONARQUBE_HPP_INCLUDED
25333+#define CATCH_REPORTER_SONARQUBE_HPP_INCLUDED
25334+
25335+
25336+
25337+namespace Catch {
25338+
25339+ class SonarQubeReporter final : public CumulativeReporterBase {
25340+ public:
25341+ SonarQubeReporter(ReporterConfig&& config)
25342+ : CumulativeReporterBase(CATCH_MOVE(config))
25343+ , xml(m_stream) {
25344+ m_preferences.shouldRedirectStdOut = true;
25345+ m_preferences.shouldReportAllAssertions = true;
25346+ m_shouldStoreSuccesfulAssertions = false;
25347+ }
25348+
25349+ static std::string getDescription() {
25350+ using namespace std::string_literals;
25351+ return "Reports test results in the Generic Test Data SonarQube XML format"s;
25352+ }
25353+
25354+ void testRunStarting( TestRunInfo const& testRunInfo ) override;
25355+
25356+ void testRunEndedCumulative() override {
25357+ writeRun( *m_testRun );
25358+ xml.endElement();
25359+ }
25360+
25361+ void writeRun( TestRunNode const& runNode );
25362+
25363+ void writeTestFile(StringRef filename, std::vector<TestCaseNode const*> const& testCaseNodes);
25364+
25365+ void writeTestCase(TestCaseNode const& testCaseNode);
25366+
25367+ void writeSection(std::string const& rootName, SectionNode const& sectionNode, bool okToFail);
25368+
25369+ void writeAssertions(SectionNode const& sectionNode, bool okToFail);
25370+
25371+ void writeAssertion(AssertionStats const& stats, bool okToFail);
25372+
25373+ private:
25374+ XmlWriter xml;
25375+ };
25376+
25377+
25378+} // end namespace Catch
25379+
25380+#endif // CATCH_REPORTER_SONARQUBE_HPP_INCLUDED
25381+
25382+
25383+#ifndef CATCH_REPORTER_TAP_HPP_INCLUDED
25384+#define CATCH_REPORTER_TAP_HPP_INCLUDED
25385+
25386+
25387+namespace Catch {
25388+
25389+ class TAPReporter final : public StreamingReporterBase {
25390+ public:
25391+ TAPReporter( ReporterConfig&& config ):
25392+ StreamingReporterBase( CATCH_MOVE(config) ) {
25393+ m_preferences.shouldReportAllAssertions = true;
25394+ }
25395+
25396+ static std::string getDescription() {
25397+ using namespace std::string_literals;
25398+ return "Reports test results in TAP format, suitable for test harnesses"s;
25399+ }
25400+
25401+ void testRunStarting( TestRunInfo const& testInfo ) override;
25402+
25403+ void noMatchingTestCases( StringRef unmatchedSpec ) override;
25404+
25405+ void assertionEnded(AssertionStats const& _assertionStats) override;
25406+
25407+ void testRunEnded(TestRunStats const& _testRunStats) override;
25408+
25409+ private:
25410+ std::size_t counter = 0;
25411+ };
25412+
25413+} // end namespace Catch
25414+
25415+#endif // CATCH_REPORTER_TAP_HPP_INCLUDED
25416+
25417+
25418+#ifndef CATCH_REPORTER_TEAMCITY_HPP_INCLUDED
25419+#define CATCH_REPORTER_TEAMCITY_HPP_INCLUDED
25420+
25421+
25422+#include <cstring>
25423+
25424+#ifdef __clang__
25425+# pragma clang diagnostic push
25426+# pragma clang diagnostic ignored "-Wpadded"
25427+#endif
25428+
25429+namespace Catch {
25430+
25431+ class TeamCityReporter final : public StreamingReporterBase {
25432+ public:
25433+ TeamCityReporter( ReporterConfig&& _config )
25434+ : StreamingReporterBase( CATCH_MOVE(_config) )
25435+ {
25436+ m_preferences.shouldRedirectStdOut = true;
25437+ }
25438+
25439+ ~TeamCityReporter() override;
25440+
25441+ static std::string getDescription() {
25442+ using namespace std::string_literals;
25443+ return "Reports test results as TeamCity service messages"s;
25444+ }
25445+
25446+ void testRunStarting( TestRunInfo const& runInfo ) override;
25447+ void testRunEnded( TestRunStats const& runStats ) override;
25448+
25449+
25450+ void assertionEnded(AssertionStats const& assertionStats) override;
25451+
25452+ void sectionStarting(SectionInfo const& sectionInfo) override {
25453+ m_headerPrintedForThisSection = false;
25454+ StreamingReporterBase::sectionStarting( sectionInfo );
25455+ }
25456+
25457+ void testCaseStarting(TestCaseInfo const& testInfo) override;
25458+
25459+ void testCaseEnded(TestCaseStats const& testCaseStats) override;
25460+
25461+ private:
25462+ void printSectionHeader(std::ostream& os);
25463+
25464+ bool m_headerPrintedForThisSection = false;
25465+ Timer m_testTimer;
25466+ };
25467+
25468+} // end namespace Catch
25469+
25470+#ifdef __clang__
25471+# pragma clang diagnostic pop
25472+#endif
25473+
25474+#endif // CATCH_REPORTER_TEAMCITY_HPP_INCLUDED
25475+
25476+
25477+#ifndef CATCH_REPORTER_XML_HPP_INCLUDED
25478+#define CATCH_REPORTER_XML_HPP_INCLUDED
25479+
25480+
25481+
25482+
25483+namespace Catch {
25484+ class XmlReporter : public StreamingReporterBase {
25485+ public:
25486+ XmlReporter(ReporterConfig&& _config);
25487+
25488+ ~XmlReporter() override;
25489+
25490+ static std::string getDescription();
25491+
25492+ virtual std::string getStylesheetRef() const;
25493+
25494+ void writeSourceInfo(SourceLineInfo const& sourceInfo);
25495+
25496+ public: // StreamingReporterBase
25497+
25498+ void testRunStarting(TestRunInfo const& testInfo) override;
25499+
25500+ void testCaseStarting(TestCaseInfo const& testInfo) override;
25501+
25502+ void sectionStarting(SectionInfo const& sectionInfo) override;
25503+
25504+ void assertionStarting(AssertionInfo const&) override;
25505+
25506+ void assertionEnded(AssertionStats const& assertionStats) override;
25507+
25508+ void sectionEnded(SectionStats const& sectionStats) override;
25509+
25510+ void testCaseEnded(TestCaseStats const& testCaseStats) override;
25511+
25512+ void testRunEnded(TestRunStats const& testRunStats) override;
25513+
25514+ void benchmarkPreparing( StringRef name ) override;
25515+ void benchmarkStarting(BenchmarkInfo const&) override;
25516+ void benchmarkEnded(BenchmarkStats<> const&) override;
25517+ void benchmarkFailed( StringRef error ) override;
25518+
25519+ void listReporters(std::vector<ReporterDescription> const& descriptions) override;
25520+ void listListeners(std::vector<ListenerDescription> const& descriptions) override;
25521+ void listTests(std::vector<TestCaseHandle> const& tests) override;
25522+ void listTags(std::vector<TagInfo> const& tags) override;
25523+
25524+ private:
25525+ Timer m_testCaseTimer;
25526+ XmlWriter m_xml;
25527+ int m_sectionDepth = 0;
25528+ };
25529+
25530+} // end namespace Catch
25531+
25532+#endif // CATCH_REPORTER_XML_HPP_INCLUDED
25533+
25534+#endif // CATCH_REPORTERS_ALL_HPP_INCLUDED
25535+
25536+#endif // CATCH_ALL_HPP_INCLUDED
25537+#endif // CATCH_AMALGAMATED_HPP_INCLUDED
25538diff --git a/tests/main.cc b/tests/main.cc
25539new file mode 100644
25540index 0000000..e115601
25541--- /dev/null
25542+++ b/tests/main.cc
25543@@ -0,0 +1,189 @@
25544+#include <catch_amalgamated.hpp>
25545+#include "../include/grim.h"
25546+#include "../include/parser.h"
25547+#include <string>
25548+#include <fstream>
25549+
25550+void checkNode(Node* node, std::string tagName, unsigned long children, std::string id, std::vector<std::string> classes, std::unordered_map<std::string, std::string> attributes, std::string note = "") {
25551+ INFO("=========================");
25552+ INFO("TAG: "+tagName);
25553+ INFO("NOTE: "+note+"\n");
25554+ INFO("HTML:\n"+node->print());
25555+
25556+ REQUIRE(node->getTagName() == tagName);
25557+ REQUIRE(node->children.size() == children);
25558+ REQUIRE(node->getId() == id);
25559+
25560+ size_t i = 0;
25561+ for (auto c : node->classList.values()) {
25562+ REQUIRE(c == classes[i]);
25563+ i++;
25564+ }
25565+
25566+ for (auto pair : attributes) {
25567+ REQUIRE(node->getAttribute(pair.first) == pair.second);
25568+ }
25569+}
25570+
25571+
25572+TEST_CASE( "parseStream can parse various types of HTML strings", "[html]" ) {
25573+ SECTION("Parses a simple HTML document") {
25574+ std::string html = "<!DOCTYPE html>"
25575+ "<html>"
25576+ "<head>"
25577+ "<title>This is a simple test</title>"
25578+ "<link rel=\"stylesheet\" href=\'/style.css\'/>"
25579+ "</head>"
25580+ "<body>"
25581+ "<p id=\"paragraph\" class=\"class1 class2\">This is some text for a simple test</p>"
25582+ "</body>"
25583+ "</html>";
25584+
25585+
25586+ std::stringstream ss(html);
25587+ std::unique_ptr<Node> document = parseStream(ss);
25588+
25589+ // Ensure the only child of root is html
25590+ Node* current = document->children[0].get();
25591+
25592+ checkNode(current, "html", 2, "", {}, {{}});
25593+
25594+ current = current->children[0].get();
25595+ checkNode(current, "head", 2, "", {}, {{}});
25596+
25597+ current = current->children[0].get();
25598+ checkNode(current, "title", 1, "", {}, {{}});
25599+
25600+ current = current->children[0].get();
25601+ checkNode(current, "text", 0, "", {}, {{"innerText","This is a simple test"}}, "First innerText check");
25602+
25603+ current = current->parent->parent->children[1].get();
25604+ checkNode(current, "link", 0, "", {}, {{"rel","stylesheet"}, {"href","/style.css"}}
25605+ , "Check attribute parsing with different quote types. Also check self closing tags");
25606+
25607+ current = current->parent->parent->children[1].get();
25608+ checkNode(current, "body", 1, "", {}, {{}});
25609+
25610+ current = current->children[0].get();
25611+ checkNode(current, "p", 1, "paragraph", {"class1", "class2"}, {{}}, "Checks for id and class parsing");
25612+
25613+ current = current->children[0].get();
25614+ checkNode(current, "text", 0, "", {}, {{"innerText","This is some text for a simple test"}}, "Second innerText check");
25615+ }
25616+
25617+ SECTION("Inline comment") {
25618+ std::string html = "<div>"
25619+ "<!-- this is a comment -->"
25620+ "</div>";
25621+
25622+ std::stringstream ss(html);
25623+ std::unique_ptr<Node> document = parseStream(ss);
25624+
25625+ // Ensure the only child of root is html
25626+ Node* current = document->children[0].get();
25627+
25628+ checkNode(current, "div", 0, "", {}, {{}});
25629+ }
25630+
25631+ SECTION("Multi line comment") {
25632+ std::string html = "<div>"
25633+ "<!-- this is a comment"
25634+ "That has two lines!"
25635+ " -->"
25636+ "</div>";
25637+
25638+ std::stringstream ss(html);
25639+ std::unique_ptr<Node> document = parseStream(ss);
25640+
25641+ // Ensure the only child of root is html
25642+ Node* current = document->children[0].get();
25643+
25644+ checkNode(current, "div", 0, "", {}, {{}});
25645+ }
25646+
25647+ SECTION("Multi line comment with html") {
25648+ std::string html = "<div>"
25649+ "<!-- this is a comment"
25650+ "<html>with HTML inside</html>"
25651+ " -->"
25652+ "</div>";
25653+
25654+ std::stringstream ss(html);
25655+ std::unique_ptr<Node> document = parseStream(ss);
25656+
25657+ // Ensure the only child of root is html
25658+ Node* current = document->children[0].get();
25659+
25660+ checkNode(current, "div", 0, "", {}, {{}});
25661+ }
25662+
25663+ SECTION("Style tag parsing (with HTML in the content prop)") {
25664+ std::string html = "<style>"
25665+ "body > h1 {"
25666+ "margin-left: calc(100% / 50px);"
25667+ "background: url(https://example.com/image.png);"
25668+ "content: \"<h1>hi</h1>\";"
25669+ "}"
25670+ "</style>"
25671+ "<h1>test</h1>";
25672+
25673+ std::stringstream ss(html);
25674+ std::unique_ptr<Node> document = parseStream(ss);
25675+
25676+ // Ensure the only child of root is html
25677+ Node* current = document->children[0].get();
25678+
25679+ checkNode(current, "style", 1, "", {}, {{}});
25680+
25681+ current = current->children[0].get();
25682+ checkNode(current, "text", 0, "", {}, {{"innerText", "body > h1 {"
25683+ "margin-left: calc(100% / 50px);"
25684+ "background: url(https://example.com/image.png);"
25685+ "content: \"<h1>hi</h1>\";"
25686+ "}"}});
25687+ current = document->children[1].get();
25688+ checkNode(current, "h1", 1, "", {}, {{}});
25689+
25690+
25691+ current = current->children[0].get();
25692+ checkNode(current, "text", 0, "", {}, {{"innerText", "test"}});
25693+ }
25694+
25695+ SECTION("Script tag prematurly closing a pre tag") {
25696+ std::string html = "<pre>"
25697+ "<script>console.log(\"</pre>\");</script>"
25698+ "</pre>";
25699+
25700+ std::stringstream ss(html);
25701+ std::unique_ptr<Node> document = parseStream(ss);
25702+
25703+ // Ensure the only child of root is html
25704+ Node* current = document->children[0].get();
25705+
25706+ checkNode(current, "pre", 1, "", {}, {{}});
25707+
25708+ current = current->children[0].get();
25709+ checkNode(current, "script", 1, "", {}, {{}});
25710+
25711+ current = current->children[0].get();
25712+ checkNode(current, "text", 0, "", {}, {{"innerText", "console.log(\"</pre>\");"}});
25713+ }
25714+
25715+ SECTION("Textarea with script tag inside") {
25716+ std::string html = "<textarea>"
25717+ "<script>console.log(\"</pre>\");</script>"
25718+ "</textarea>";
25719+
25720+ std::stringstream ss(html);
25721+ std::unique_ptr<Node> document = parseStream(ss);
25722+
25723+ // Ensure the only child of root is html
25724+ Node* current = document->children[0].get();
25725+
25726+ checkNode(current, "textarea", 1, "", {}, {{}});
25727+
25728+ current = current->children[0].get();
25729+ checkNode(current, "text", 0, "", {}, {{"innerText","<script>console.log(\"</pre>\");</script>"}});
25730+ }
25731+}
25732+