home
readme
diff
tree
note
docs
0commit 0bbc98204176a8855677486887f32637baf46b73
1Author: lakefox <mason@lakefox.net>
2Date: Sun Feb 1 14:11:59 2026 -0700
3
4 ParseSelectorParts works
5
6diff --git a/Makefile b/Makefile
7index e30b7f0..7ff62e0 100755
8--- a/Makefile
9+++ b/Makefile
10@@ -1,16 +1,7 @@
11 # --- Variables ---
12-#CCFLAGS = -std=c++2b -O3
13-CCFLAGS = -Wall -Wextra -std=c++2b -g -O0 -fsanitize=address,undefined -fno-omit-frame-pointer
14-# -O2 -Wall -Wformat -Wformat=2 -Wconversion -Wimplicit-fallthrough \
15-# -Werror=format-security \
16-# -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3 \
17-# -D_GLIBCXX_ASSERTIONS \
18-# -fstrict-flex-arrays=3 \
19-# -fstack-clash-protection -fstack-protector-strong \
20-# -Wl,-z,nodlopen -Wl,-z,noexecstack \
21-# -Wl,-z,relro -Wl,-z,now \
22-# -Wl,--as-needed -Wl,--no-copy-dt-needed-entries
23-CC = clang++
24+#CCFLAGS = -std=c23 -O3
25+CCFLAGS = -Wall -Wextra -std=c23 -g -O0 -fsanitize=address,undefined -fno-omit-frame-pointer
26+CC = clang
27
28 .PHONY: all clean all_tests
29
30@@ -19,11 +10,11 @@ all: main
31 build:
32 mkdir -p build
33
34-main: main.cc build/grim.o build/parser.o
35+main: main.c build/grim.o build/parser.o
36 ${CC} ${CCFLAGS} main.cc -Iinclude/ build/grim.o build/parser.o -o main
37
38-build/grim.o: src/grim.cc include/grim.h | build
39- ${CC} ${CCFLAGS} -Iinclude/ -c src/grim.cc -o build/grim.o
40+build/grim.o: src/grim.c include/grim.h | build
41+ ${CC} ${CCFLAGS} -Iinclude/ -c src/grim.c -o build/grim.o
42
43 build/parser.o: src/parser.cc include/parser.h | build
44 ${CC} ${CCFLAGS} -Iinclude/ -c src/parser.cc -o build/parser.o
45@@ -52,52 +43,9 @@ bench_%: build/%
46 @echo "--- Running $* ---"
47 @./build/$*
48
49-build/css_unit_test: tests/css_unit.cc build/grim.o build/catch.o build/parser.o | build
50- ${CC} ${CCFLAGS} -Iinclude/ tests/css_unit.cc build/grim.o build/catch.o build/parser.o -o build/css_unit_test
51+build/parseselectorparts_playground: playground/parseselectorparts.c build/grim.o | build
52+ ${CC} ${CCFLAGS} -Iinclude/ playground/parseselectorparts.c build/grim.o -o build/parseselectorparts_playground
53
54-build/html_node_test: tests/html_node.cc build/grim.o build/catch.o build/parser.o | build
55- ${CC} ${CCFLAGS} -Iinclude/ tests/html_node.cc build/grim.o build/catch.o build/parser.o -o build/html_node_test
56-
57-build/css_selector_test: tests/css_selector.cc build/grim.o build/catch.o build/parser.o | build
58- ${CC} ${CCFLAGS} -Iinclude/ tests/css_selector.cc build/grim.o build/catch.o build/parser.o -o build/css_selector_test
59-
60-build/html_parser_test: tests/html_parser.cc build/grim.o build/parser.o build/catch.o | build
61- ${CC} ${CCFLAGS} -Iinclude/ tests/html_parser.cc build/grim.o build/parser.o build/catch.o -o build/html_parser_test
62-
63-build/css_parser_test: tests/css_parser.cc build/grim.o build/parser.o build/catch.o | build
64- ${CC} ${CCFLAGS} -Iinclude/ tests/css_parser.cc build/grim.o build/parser.o build/catch.o -o build/css_parser_test
65-
66-build/query_select_test: tests/query_select.cc build/grim.o build/parser.o build/catch.o | build
67- ${CC} ${CCFLAGS} -Iinclude/ tests/query_select.cc build/grim.o build/parser.o build/catch.o -o build/query_select_test
68-
69-build/windowunitlength_test: tests/windowunitlength.cc build/grim.o build/parser.o build/catch.o | build
70- ${CC} ${CCFLAGS} -Iinclude/ tests/windowunitlength.cc build/grim.o build/parser.o build/catch.o -o build/windowunitlength_test
71-
72-build/unitvalue_test: tests/unitvalue.cc build/grim.o build/parser.o build/catch.o | build
73- ${CC} ${CCFLAGS} -Iinclude/ tests/unitvalue.cc build/grim.o build/parser.o build/catch.o -o build/unitvalue_test
74-
75-
76-build/catch.o: ./include/catch_amalgamated.cpp ./include/catch_amalgamated.hpp | build
77- ${CC} ${CCFLAGS} -Iinclude/ -c include/catch_amalgamated.cpp -o build/catch.o
78-
79-# --- Playground ---
80-build/parseselectorparts_playground: playground/parseselectorparts.cc build/grim.o build/parser.o | build
81- ${CC} ${CCFLAGS} -Iinclude/ playground/parseselectorparts.cc build/grim.o build/parser.o -o build/parseselectorparts_playground
82-
83-build/testselector_playground: playground/testselector.cc build/grim.o build/parser.o | build
84- ${CC} ${CCFLAGS} -Iinclude/ playground/testselector.cc build/grim.o build/parser.o -o build/testselector_playground
85-
86-build/css_parser_playground: playground/css_parser.cc build/grim.o build/parser.o | build
87- ${CC} ${CCFLAGS} -Iinclude/ playground/css_parser.cc build/grim.o build/parser.o -o build/css_parser_playground
88-
89-build/css_unit_playground: playground/css_unit.cc build/grim.o build/parser.o | build
90- ${CC} ${CCFLAGS} -Iinclude/ playground/css_unit.cc build/grim.o build/parser.o -o build/css_unit_playground
91-
92-build/window_playground: playground/window.cc build/grim.o build/parser.o | build
93- ${CC} ${CCFLAGS} -Iinclude/ playground/window.cc build/grim.o build/parser.o -o build/window_playground
94-
95-build/unitvalue_playground: playground/unitvalue.cc build/grim.o build/parser.o | build
96- ${CC} ${CCFLAGS} -Iinclude/ playground/unitvalue.cc build/grim.o build/parser.o -o build/unitvalue_playground
97
98
99 # --- Prebuild ---
100diff --git a/include/catch_amalgamated.cpp b/include/catch_amalgamated.cpp
101deleted file mode 100644
102index 892d637..0000000
103--- a/include/catch_amalgamated.cpp
104+++ /dev/null
105@@ -1,12083 +0,0 @@
106-
107-// Copyright Catch2 Authors
108-// Distributed under the Boost Software License, Version 1.0.
109-// (See accompanying file LICENSE.txt or copy at
110-// https://www.boost.org/LICENSE_1_0.txt)
111-
112-// SPDX-License-Identifier: BSL-1.0
113-
114-// Catch v3.11.0
115-// Generated: 2025-09-30 10:49:12.549018
116-// ----------------------------------------------------------
117-// This file is an amalgamation of multiple different files.
118-// You probably shouldn't edit it directly.
119-// ----------------------------------------------------------
120-
121-#include "catch_amalgamated.hpp"
122-
123-
124-#ifndef CATCH_WINDOWS_H_PROXY_HPP_INCLUDED
125-#define CATCH_WINDOWS_H_PROXY_HPP_INCLUDED
126-
127-
128-#if defined(CATCH_PLATFORM_WINDOWS)
129-
130-// We might end up with the define made globally through the compiler,
131-// and we don't want to trigger warnings for this
132-#if !defined(NOMINMAX)
133-# define NOMINMAX
134-#endif
135-#if !defined(WIN32_LEAN_AND_MEAN)
136-# define WIN32_LEAN_AND_MEAN
137-#endif
138-
139-#include <windows.h>
140-
141-#endif // defined(CATCH_PLATFORM_WINDOWS)
142-
143-#endif // CATCH_WINDOWS_H_PROXY_HPP_INCLUDED
144-
145-
146-
147-
148-namespace Catch {
149- namespace Benchmark {
150- namespace Detail {
151- ChronometerConcept::~ChronometerConcept() = default;
152- } // namespace Detail
153- } // namespace Benchmark
154-} // namespace Catch
155-
156-
157-// Adapted from donated nonius code.
158-
159-
160-#include <vector>
161-
162-namespace Catch {
163- namespace Benchmark {
164- namespace Detail {
165- SampleAnalysis analyse(const IConfig &cfg, FDuration* first, FDuration* last) {
166- if (!cfg.benchmarkNoAnalysis()) {
167- std::vector<double> samples;
168- samples.reserve(static_cast<size_t>(last - first));
169- for (auto current = first; current != last; ++current) {
170- samples.push_back( current->count() );
171- }
172-
173- auto analysis = Catch::Benchmark::Detail::analyse_samples(
174- cfg.benchmarkConfidenceInterval(),
175- cfg.benchmarkResamples(),
176- samples.data(),
177- samples.data() + samples.size() );
178- auto outliers = Catch::Benchmark::Detail::classify_outliers(
179- samples.data(), samples.data() + samples.size() );
180-
181- auto wrap_estimate = [](Estimate<double> e) {
182- return Estimate<FDuration> {
183- FDuration(e.point),
184- FDuration(e.lower_bound),
185- FDuration(e.upper_bound),
186- e.confidence_interval,
187- };
188- };
189- std::vector<FDuration> samples2;
190- samples2.reserve(samples.size());
191- for (auto s : samples) {
192- samples2.push_back( FDuration( s ) );
193- }
194-
195- return {
196- CATCH_MOVE(samples2),
197- wrap_estimate(analysis.mean),
198- wrap_estimate(analysis.standard_deviation),
199- outliers,
200- analysis.outlier_variance,
201- };
202- } else {
203- std::vector<FDuration> samples;
204- samples.reserve(static_cast<size_t>(last - first));
205-
206- FDuration mean = FDuration(0);
207- int i = 0;
208- for (auto it = first; it < last; ++it, ++i) {
209- samples.push_back(*it);
210- mean += *it;
211- }
212- mean /= i;
213-
214- return SampleAnalysis{
215- CATCH_MOVE(samples),
216- Estimate<FDuration>{ mean, mean, mean, 0.0 },
217- Estimate<FDuration>{ FDuration( 0 ),
218- FDuration( 0 ),
219- FDuration( 0 ),
220- 0.0 },
221- OutlierClassification{},
222- 0.0
223- };
224- }
225- }
226- } // namespace Detail
227- } // namespace Benchmark
228-} // namespace Catch
229-
230-
231-
232-
233-namespace Catch {
234- namespace Benchmark {
235- namespace Detail {
236- struct do_nothing {
237- void operator()() const {}
238- };
239-
240- BenchmarkFunction::callable::~callable() = default;
241- BenchmarkFunction::BenchmarkFunction():
242- f( new model<do_nothing>{ {} } ){}
243- } // namespace Detail
244- } // namespace Benchmark
245-} // namespace Catch
246-
247-
248-
249-
250-#include <exception>
251-
252-namespace Catch {
253- namespace Benchmark {
254- namespace Detail {
255- struct optimized_away_error : std::exception {
256- const char* what() const noexcept override;
257- };
258-
259- const char* optimized_away_error::what() const noexcept {
260- return "could not measure benchmark, maybe it was optimized away";
261- }
262-
263- void throw_optimized_away_error() {
264- Catch::throw_exception(optimized_away_error{});
265- }
266-
267- } // namespace Detail
268- } // namespace Benchmark
269-} // namespace Catch
270-
271-
272-// Adapted from donated nonius code.
273-
274-
275-
276-#include <algorithm>
277-#include <cassert>
278-#include <cmath>
279-#include <cstddef>
280-#include <numeric>
281-#include <random>
282-
283-
284-#if defined(CATCH_CONFIG_USE_ASYNC)
285-#include <future>
286-#endif
287-
288-namespace Catch {
289- namespace Benchmark {
290- namespace Detail {
291- namespace {
292-
293- template <typename URng, typename Estimator>
294- static sample
295- resample( URng& rng,
296- unsigned int resamples,
297- double const* first,
298- double const* last,
299- Estimator& estimator ) {
300- auto n = static_cast<size_t>( last - first );
301- Catch::uniform_integer_distribution<size_t> dist( 0, n - 1 );
302-
303- sample out;
304- out.reserve( resamples );
305- std::vector<double> resampled;
306- resampled.reserve( n );
307- for ( size_t i = 0; i < resamples; ++i ) {
308- resampled.clear();
309- for ( size_t s = 0; s < n; ++s ) {
310- resampled.push_back( first[dist( rng )] );
311- }
312- const auto estimate =
313- estimator( resampled.data(), resampled.data() + resampled.size() );
314- out.push_back( estimate );
315- }
316- std::sort( out.begin(), out.end() );
317- return out;
318- }
319-
320- static double outlier_variance( Estimate<double> mean,
321- Estimate<double> stddev,
322- int n ) {
323- double sb = stddev.point;
324- double mn = mean.point / n;
325- double mg_min = mn / 2.;
326- double sg = (std::min)( mg_min / 4., sb / std::sqrt( n ) );
327- double sg2 = sg * sg;
328- double sb2 = sb * sb;
329-
330- auto c_max = [n, mn, sb2, sg2]( double x ) -> double {
331- double k = mn - x;
332- double d = k * k;
333- double nd = n * d;
334- double k0 = -n * nd;
335- double k1 = sb2 - n * sg2 + nd;
336- double det = k1 * k1 - 4 * sg2 * k0;
337- return static_cast<int>( -2. * k0 /
338- ( k1 + std::sqrt( det ) ) );
339- };
340-
341- auto var_out = [n, sb2, sg2]( double c ) {
342- double nc = n - c;
343- return ( nc / n ) * ( sb2 - nc * sg2 );
344- };
345-
346- return (std::min)( var_out( 1 ),
347- var_out(
348- (std::min)( c_max( 0. ),
349- c_max( mg_min ) ) ) ) /
350- sb2;
351- }
352-
353- static double erf_inv( double x ) {
354- // Code accompanying the article "Approximating the erfinv
355- // function" in GPU Computing Gems, Volume 2
356- double w, p;
357-
358- w = -log( ( 1.0 - x ) * ( 1.0 + x ) );
359-
360- if ( w < 6.250000 ) {
361- w = w - 3.125000;
362- p = -3.6444120640178196996e-21;
363- p = -1.685059138182016589e-19 + p * w;
364- p = 1.2858480715256400167e-18 + p * w;
365- p = 1.115787767802518096e-17 + p * w;
366- p = -1.333171662854620906e-16 + p * w;
367- p = 2.0972767875968561637e-17 + p * w;
368- p = 6.6376381343583238325e-15 + p * w;
369- p = -4.0545662729752068639e-14 + p * w;
370- p = -8.1519341976054721522e-14 + p * w;
371- p = 2.6335093153082322977e-12 + p * w;
372- p = -1.2975133253453532498e-11 + p * w;
373- p = -5.4154120542946279317e-11 + p * w;
374- p = 1.051212273321532285e-09 + p * w;
375- p = -4.1126339803469836976e-09 + p * w;
376- p = -2.9070369957882005086e-08 + p * w;
377- p = 4.2347877827932403518e-07 + p * w;
378- p = -1.3654692000834678645e-06 + p * w;
379- p = -1.3882523362786468719e-05 + p * w;
380- p = 0.0001867342080340571352 + p * w;
381- p = -0.00074070253416626697512 + p * w;
382- p = -0.0060336708714301490533 + p * w;
383- p = 0.24015818242558961693 + p * w;
384- p = 1.6536545626831027356 + p * w;
385- } else if ( w < 16.000000 ) {
386- w = sqrt( w ) - 3.250000;
387- p = 2.2137376921775787049e-09;
388- p = 9.0756561938885390979e-08 + p * w;
389- p = -2.7517406297064545428e-07 + p * w;
390- p = 1.8239629214389227755e-08 + p * w;
391- p = 1.5027403968909827627e-06 + p * w;
392- p = -4.013867526981545969e-06 + p * w;
393- p = 2.9234449089955446044e-06 + p * w;
394- p = 1.2475304481671778723e-05 + p * w;
395- p = -4.7318229009055733981e-05 + p * w;
396- p = 6.8284851459573175448e-05 + p * w;
397- p = 2.4031110387097893999e-05 + p * w;
398- p = -0.0003550375203628474796 + p * w;
399- p = 0.00095328937973738049703 + p * w;
400- p = -0.0016882755560235047313 + p * w;
401- p = 0.0024914420961078508066 + p * w;
402- p = -0.0037512085075692412107 + p * w;
403- p = 0.005370914553590063617 + p * w;
404- p = 1.0052589676941592334 + p * w;
405- p = 3.0838856104922207635 + p * w;
406- } else {
407- w = sqrt( w ) - 5.000000;
408- p = -2.7109920616438573243e-11;
409- p = -2.5556418169965252055e-10 + p * w;
410- p = 1.5076572693500548083e-09 + p * w;
411- p = -3.7894654401267369937e-09 + p * w;
412- p = 7.6157012080783393804e-09 + p * w;
413- p = -1.4960026627149240478e-08 + p * w;
414- p = 2.9147953450901080826e-08 + p * w;
415- p = -6.7711997758452339498e-08 + p * w;
416- p = 2.2900482228026654717e-07 + p * w;
417- p = -9.9298272942317002539e-07 + p * w;
418- p = 4.5260625972231537039e-06 + p * w;
419- p = -1.9681778105531670567e-05 + p * w;
420- p = 7.5995277030017761139e-05 + p * w;
421- p = -0.00021503011930044477347 + p * w;
422- p = -0.00013871931833623122026 + p * w;
423- p = 1.0103004648645343977 + p * w;
424- p = 4.8499064014085844221 + p * w;
425- }
426- return p * x;
427- }
428-
429- static double
430- standard_deviation( double const* first, double const* last ) {
431- auto m = Catch::Benchmark::Detail::mean( first, last );
432- double variance =
433- std::accumulate( first,
434- last,
435- 0.,
436- [m]( double a, double b ) {
437- double diff = b - m;
438- return a + diff * diff;
439- } ) /
440- static_cast<double>( last - first );
441- return std::sqrt( variance );
442- }
443-
444- static sample jackknife( double ( *estimator )( double const*,
445- double const* ),
446- double* first,
447- double* last ) {
448- const auto second = first + 1;
449- sample results;
450- results.reserve( static_cast<size_t>( last - first ) );
451-
452- for ( auto it = first; it != last; ++it ) {
453- std::iter_swap( it, first );
454- results.push_back( estimator( second, last ) );
455- }
456-
457- return results;
458- }
459-
460-
461- } // namespace
462- } // namespace Detail
463- } // namespace Benchmark
464-} // namespace Catch
465-
466-namespace Catch {
467- namespace Benchmark {
468- namespace Detail {
469-
470- double weighted_average_quantile( int k,
471- int q,
472- double* first,
473- double* last ) {
474- auto count = last - first;
475- double idx = static_cast<double>((count - 1) * k) / static_cast<double>(q);
476- int j = static_cast<int>(idx);
477- double g = idx - j;
478- std::nth_element(first, first + j, last);
479- auto xj = first[j];
480- if ( Catch::Detail::directCompare( g, 0 ) ) {
481- return xj;
482- }
483-
484- auto xj1 = *std::min_element(first + (j + 1), last);
485- return xj + g * (xj1 - xj);
486- }
487-
488- OutlierClassification
489- classify_outliers( double const* first, double const* last ) {
490- std::vector<double> copy( first, last );
491-
492- auto q1 = weighted_average_quantile( 1, 4, copy.data(), copy.data() + copy.size() );
493- auto q3 = weighted_average_quantile( 3, 4, copy.data(), copy.data() + copy.size() );
494- auto iqr = q3 - q1;
495- auto los = q1 - ( iqr * 3. );
496- auto lom = q1 - ( iqr * 1.5 );
497- auto him = q3 + ( iqr * 1.5 );
498- auto his = q3 + ( iqr * 3. );
499-
500- OutlierClassification o;
501- for ( ; first != last; ++first ) {
502- const double t = *first;
503- if ( t < los ) {
504- ++o.low_severe;
505- } else if ( t < lom ) {
506- ++o.low_mild;
507- } else if ( t > his ) {
508- ++o.high_severe;
509- } else if ( t > him ) {
510- ++o.high_mild;
511- }
512- ++o.samples_seen;
513- }
514- return o;
515- }
516-
517- double mean( double const* first, double const* last ) {
518- auto count = last - first;
519- double sum = 0.;
520- while (first != last) {
521- sum += *first;
522- ++first;
523- }
524- return sum / static_cast<double>(count);
525- }
526-
527- double normal_cdf( double x ) {
528- return std::erfc( -x / std::sqrt( 2.0 ) ) / 2.0;
529- }
530-
531- double erfc_inv(double x) {
532- return erf_inv(1.0 - x);
533- }
534-
535- double normal_quantile(double p) {
536- static const double ROOT_TWO = std::sqrt(2.0);
537-
538- double result = 0.0;
539- assert(p >= 0 && p <= 1);
540- if (p < 0 || p > 1) {
541- return result;
542- }
543-
544- result = -erfc_inv(2.0 * p);
545- // result *= normal distribution standard deviation (1.0) * sqrt(2)
546- result *= /*sd * */ ROOT_TWO;
547- // result += normal disttribution mean (0)
548- return result;
549- }
550-
551- Estimate<double>
552- bootstrap( double confidence_level,
553- double* first,
554- double* last,
555- sample const& resample,
556- double ( *estimator )( double const*, double const* ) ) {
557- auto n_samples = last - first;
558-
559- double point = estimator( first, last );
560- // Degenerate case with a single sample
561- if ( n_samples == 1 )
562- return { point, point, point, confidence_level };
563-
564- sample jack = jackknife( estimator, first, last );
565- double jack_mean =
566- mean( jack.data(), jack.data() + jack.size() );
567- double sum_squares = 0, sum_cubes = 0;
568- for ( double x : jack ) {
569- auto difference = jack_mean - x;
570- auto square = difference * difference;
571- auto cube = square * difference;
572- sum_squares += square;
573- sum_cubes += cube;
574- }
575-
576- double accel = sum_cubes / ( 6 * std::pow( sum_squares, 1.5 ) );
577- long n = static_cast<long>( resample.size() );
578- double prob_n = static_cast<double>(
579- std::count_if( resample.begin(),
580- resample.end(),
581- [point]( double x ) { return x < point; } )) /
582- static_cast<double>( n );
583- // degenerate case with uniform samples
584- if ( Catch::Detail::directCompare( prob_n, 0. ) ) {
585- return { point, point, point, confidence_level };
586- }
587-
588- double bias = normal_quantile( prob_n );
589- double z1 = normal_quantile( ( 1. - confidence_level ) / 2. );
590-
591- auto cumn = [n]( double x ) -> long {
592- return std::lround( normal_cdf( x ) *
593- static_cast<double>( n ) );
594- };
595- auto a = [bias, accel]( double b ) {
596- return bias + b / ( 1. - accel * b );
597- };
598- double b1 = bias + z1;
599- double b2 = bias - z1;
600- double a1 = a( b1 );
601- double a2 = a( b2 );
602- auto lo = static_cast<size_t>( (std::max)( cumn( a1 ), 0l ) );
603- auto hi =
604- static_cast<size_t>( (std::min)( cumn( a2 ), n - 1 ) );
605-
606- return { point, resample[lo], resample[hi], confidence_level };
607- }
608-
609- bootstrap_analysis analyse_samples(double confidence_level,
610- unsigned int n_resamples,
611- double* first,
612- double* last) {
613- auto mean = &Detail::mean;
614- auto stddev = &standard_deviation;
615-
616-#if defined(CATCH_CONFIG_USE_ASYNC)
617- auto Estimate = [=](double(*f)(double const*, double const*)) {
618- std::random_device rd;
619- auto seed = rd();
620- return std::async(std::launch::async, [=] {
621- SimplePcg32 rng( seed );
622- auto resampled = resample(rng, n_resamples, first, last, f);
623- return bootstrap(confidence_level, first, last, resampled, f);
624- });
625- };
626-
627- auto mean_future = Estimate(mean);
628- auto stddev_future = Estimate(stddev);
629-
630- auto mean_estimate = mean_future.get();
631- auto stddev_estimate = stddev_future.get();
632-#else
633- auto Estimate = [=](double(*f)(double const* , double const*)) {
634- std::random_device rd;
635- auto seed = rd();
636- SimplePcg32 rng( seed );
637- auto resampled = resample(rng, n_resamples, first, last, f);
638- return bootstrap(confidence_level, first, last, resampled, f);
639- };
640-
641- auto mean_estimate = Estimate(mean);
642- auto stddev_estimate = Estimate(stddev);
643-#endif // CATCH_USE_ASYNC
644-
645- auto n = static_cast<int>(last - first); // seriously, one can't use integral types without hell in C++
646- double outlier_variance = Detail::outlier_variance(mean_estimate, stddev_estimate, n);
647-
648- return { mean_estimate, stddev_estimate, outlier_variance };
649- }
650- } // namespace Detail
651- } // namespace Benchmark
652-} // namespace Catch
653-
654-
655-
656-#include <cmath>
657-#include <limits>
658-
659-namespace {
660-
661-// Performs equivalent check of std::fabs(lhs - rhs) <= margin
662-// But without the subtraction to allow for INFINITY in comparison
663-bool marginComparison(double lhs, double rhs, double margin) {
664- return (lhs + margin >= rhs) && (rhs + margin >= lhs);
665-}
666-
667-}
668-
669-namespace Catch {
670-
671- Approx::Approx ( double value )
672- : m_epsilon( static_cast<double>(std::numeric_limits<float>::epsilon())*100. ),
673- m_margin( 0.0 ),
674- m_scale( 0.0 ),
675- m_value( value )
676- {}
677-
678- Approx Approx::custom() {
679- return Approx( 0 );
680- }
681-
682- Approx Approx::operator-() const {
683- auto temp(*this);
684- temp.m_value = -temp.m_value;
685- return temp;
686- }
687-
688-
689- std::string Approx::toString() const {
690- ReusableStringStream rss;
691- rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )";
692- return rss.str();
693- }
694-
695- bool Approx::equalityComparisonImpl(const double other) const {
696- // First try with fixed margin, then compute margin based on epsilon, scale and Approx's value
697- // Thanks to Richard Harris for his help refining the scaled margin value
698- return marginComparison(m_value, other, m_margin)
699- || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(std::isinf(m_value)? 0 : m_value)));
700- }
701-
702- void Approx::setMargin(double newMargin) {
703- CATCH_ENFORCE(newMargin >= 0,
704- "Invalid Approx::margin: " << newMargin << '.'
705- << " Approx::Margin has to be non-negative.");
706- m_margin = newMargin;
707- }
708-
709- void Approx::setEpsilon(double newEpsilon) {
710- CATCH_ENFORCE(newEpsilon >= 0 && newEpsilon <= 1.0,
711- "Invalid Approx::epsilon: " << newEpsilon << '.'
712- << " Approx::epsilon has to be in [0, 1]");
713- m_epsilon = newEpsilon;
714- }
715-
716-namespace literals {
717- Approx operator ""_a(long double val) {
718- return Approx(val);
719- }
720- Approx operator ""_a(unsigned long long val) {
721- return Approx(val);
722- }
723-} // end namespace literals
724-
725-std::string StringMaker<Catch::Approx>::convert(Catch::Approx const& value) {
726- return value.toString();
727-}
728-
729-} // end namespace Catch
730-
731-
732-
733-namespace Catch {
734-
735- AssertionResultData::AssertionResultData(ResultWas::OfType _resultType, LazyExpression const& _lazyExpression):
736- lazyExpression(_lazyExpression),
737- resultType(_resultType) {}
738-
739- std::string AssertionResultData::reconstructExpression() const {
740-
741- if( reconstructedExpression.empty() ) {
742- if( lazyExpression ) {
743- ReusableStringStream rss;
744- rss << lazyExpression;
745- reconstructedExpression = rss.str();
746- }
747- }
748- return reconstructedExpression;
749- }
750-
751- AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData&& data )
752- : m_info( info ),
753- m_resultData( CATCH_MOVE(data) )
754- {}
755-
756- // Result was a success
757- bool AssertionResult::succeeded() const {
758- return Catch::isOk( m_resultData.resultType );
759- }
760-
761- // Result was a success, or failure is suppressed
762- bool AssertionResult::isOk() const {
763- return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition );
764- }
765-
766- ResultWas::OfType AssertionResult::getResultType() const {
767- return m_resultData.resultType;
768- }
769-
770- bool AssertionResult::hasExpression() const {
771- return !m_info.capturedExpression.empty();
772- }
773-
774- bool AssertionResult::hasMessage() const {
775- return !m_resultData.message.empty();
776- }
777-
778- std::string AssertionResult::getExpression() const {
779- // Possibly overallocating by 3 characters should be basically free
780- std::string expr; expr.reserve(m_info.capturedExpression.size() + 3);
781- if (isFalseTest(m_info.resultDisposition)) {
782- expr += "!(";
783- }
784- expr += m_info.capturedExpression;
785- if (isFalseTest(m_info.resultDisposition)) {
786- expr += ')';
787- }
788- return expr;
789- }
790-
791- std::string AssertionResult::getExpressionInMacro() const {
792- if ( m_info.macroName.empty() ) {
793- return static_cast<std::string>( m_info.capturedExpression );
794- }
795- std::string expr;
796- expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 );
797- expr += m_info.macroName;
798- expr += "( ";
799- expr += m_info.capturedExpression;
800- expr += " )";
801- return expr;
802- }
803-
804- bool AssertionResult::hasExpandedExpression() const {
805- return hasExpression() && getExpandedExpression() != getExpression();
806- }
807-
808- std::string AssertionResult::getExpandedExpression() const {
809- std::string expr = m_resultData.reconstructExpression();
810- return expr.empty()
811- ? getExpression()
812- : expr;
813- }
814-
815- StringRef AssertionResult::getMessage() const {
816- return m_resultData.message;
817- }
818- SourceLineInfo AssertionResult::getSourceInfo() const {
819- return m_info.lineInfo;
820- }
821-
822- StringRef AssertionResult::getTestMacroName() const {
823- return m_info.macroName;
824- }
825-
826-} // end namespace Catch
827-
828-
829-
830-#include <fstream>
831-
832-namespace Catch {
833-
834- namespace {
835- static bool enableBazelEnvSupport() {
836-#if defined( CATCH_CONFIG_BAZEL_SUPPORT )
837- return true;
838-#else
839- return Detail::getEnv( "BAZEL_TEST" ) != nullptr;
840-#endif
841- }
842-
843- struct bazelShardingOptions {
844- unsigned int shardIndex, shardCount;
845- std::string shardFilePath;
846- };
847-
848- static Optional<bazelShardingOptions> readBazelShardingOptions() {
849- const auto bazelShardIndex = Detail::getEnv( "TEST_SHARD_INDEX" );
850- const auto bazelShardTotal = Detail::getEnv( "TEST_TOTAL_SHARDS" );
851- const auto bazelShardInfoFile = Detail::getEnv( "TEST_SHARD_STATUS_FILE" );
852-
853-
854- const bool has_all =
855- bazelShardIndex && bazelShardTotal && bazelShardInfoFile;
856- if ( !has_all ) {
857- // We provide nice warning message if the input is
858- // misconfigured.
859- auto warn = []( const char* env_var ) {
860- Catch::cerr()
861- << "Warning: Bazel shard configuration is missing '"
862- << env_var << "'. Shard configuration is skipped.\n";
863- };
864- if ( !bazelShardIndex ) {
865- warn( "TEST_SHARD_INDEX" );
866- }
867- if ( !bazelShardTotal ) {
868- warn( "TEST_TOTAL_SHARDS" );
869- }
870- if ( !bazelShardInfoFile ) {
871- warn( "TEST_SHARD_STATUS_FILE" );
872- }
873- return {};
874- }
875-
876- auto shardIndex = parseUInt( bazelShardIndex );
877- if ( !shardIndex ) {
878- Catch::cerr()
879- << "Warning: could not parse 'TEST_SHARD_INDEX' ('" << bazelShardIndex
880- << "') as unsigned int.\n";
881- return {};
882- }
883- auto shardTotal = parseUInt( bazelShardTotal );
884- if ( !shardTotal ) {
885- Catch::cerr()
886- << "Warning: could not parse 'TEST_TOTAL_SHARD' ('"
887- << bazelShardTotal << "') as unsigned int.\n";
888- return {};
889- }
890-
891- return bazelShardingOptions{
892- *shardIndex, *shardTotal, bazelShardInfoFile };
893-
894- }
895- } // end namespace
896-
897-
898- bool operator==( ProcessedReporterSpec const& lhs,
899- ProcessedReporterSpec const& rhs ) {
900- return lhs.name == rhs.name &&
901- lhs.outputFilename == rhs.outputFilename &&
902- lhs.colourMode == rhs.colourMode &&
903- lhs.customOptions == rhs.customOptions;
904- }
905-
906- Config::Config( ConfigData const& data ):
907- m_data( data ) {
908- // We need to trim filter specs to avoid trouble with superfluous
909- // whitespace (esp. important for bdd macros, as those are manually
910- // aligned with whitespace).
911-
912- for (auto& elem : m_data.testsOrTags) {
913- elem = trim(elem);
914- }
915- for (auto& elem : m_data.sectionsToRun) {
916- elem = trim(elem);
917- }
918-
919- // Insert the default reporter if user hasn't asked for a specific one
920- if ( m_data.reporterSpecifications.empty() ) {
921-#if defined( CATCH_CONFIG_DEFAULT_REPORTER )
922- const auto default_spec = CATCH_CONFIG_DEFAULT_REPORTER;
923-#else
924- const auto default_spec = "console";
925-#endif
926- auto parsed = parseReporterSpec(default_spec);
927- CATCH_ENFORCE( parsed,
928- "Cannot parse the provided default reporter spec: '"
929- << default_spec << '\'' );
930- m_data.reporterSpecifications.push_back( std::move( *parsed ) );
931- }
932-
933- // Reading bazel env vars can change some parts of the config data,
934- // so we have to process the bazel env before acting on the config.
935- if ( enableBazelEnvSupport() ) {
936- readBazelEnvVars();
937- }
938-
939- // Bazel support can modify the test specs, so parsing has to happen
940- // after reading Bazel env vars.
941- TestSpecParser parser( ITagAliasRegistry::get() );
942- if ( !m_data.testsOrTags.empty() ) {
943- m_hasTestFilters = true;
944- for ( auto const& testOrTags : m_data.testsOrTags ) {
945- parser.parse( testOrTags );
946- }
947- }
948- m_testSpec = parser.testSpec();
949-
950-
951- // We now fixup the reporter specs to handle default output spec,
952- // default colour spec, etc
953- bool defaultOutputUsed = false;
954- for ( auto const& reporterSpec : m_data.reporterSpecifications ) {
955- // We do the default-output check separately, while always
956- // using the default output below to make the code simpler
957- // and avoid superfluous copies.
958- if ( reporterSpec.outputFile().none() ) {
959- CATCH_ENFORCE( !defaultOutputUsed,
960- "Internal error: cannot use default output for "
961- "multiple reporters" );
962- defaultOutputUsed = true;
963- }
964-
965- m_processedReporterSpecs.push_back( ProcessedReporterSpec{
966- reporterSpec.name(),
967- reporterSpec.outputFile() ? *reporterSpec.outputFile()
968- : data.defaultOutputFilename,
969- reporterSpec.colourMode().valueOr( data.defaultColourMode ),
970- reporterSpec.customOptions() } );
971- }
972- }
973-
974- Config::~Config() = default;
975-
976-
977- bool Config::listTests() const { return m_data.listTests; }
978- bool Config::listTags() const { return m_data.listTags; }
979- bool Config::listReporters() const { return m_data.listReporters; }
980- bool Config::listListeners() const { return m_data.listListeners; }
981-
982- std::vector<std::string> const& Config::getTestsOrTags() const { return m_data.testsOrTags; }
983- std::vector<std::string> const& Config::getSectionsToRun() const { return m_data.sectionsToRun; }
984-
985- std::vector<ReporterSpec> const& Config::getReporterSpecs() const {
986- return m_data.reporterSpecifications;
987- }
988-
989- std::vector<ProcessedReporterSpec> const&
990- Config::getProcessedReporterSpecs() const {
991- return m_processedReporterSpecs;
992- }
993-
994- TestSpec const& Config::testSpec() const { return m_testSpec; }
995- bool Config::hasTestFilters() const { return m_hasTestFilters; }
996-
997- bool Config::showHelp() const { return m_data.showHelp; }
998-
999- std::string const& Config::getExitGuardFilePath() const { return m_data.prematureExitGuardFilePath; }
1000-
1001- // IConfig interface
1002- bool Config::allowThrows() const { return !m_data.noThrow; }
1003- StringRef Config::name() const { return m_data.name.empty() ? m_data.processName : m_data.name; }
1004- bool Config::includeSuccessfulResults() const { return m_data.showSuccessfulTests; }
1005- bool Config::warnAboutMissingAssertions() const {
1006- return !!( m_data.warnings & WarnAbout::NoAssertions );
1007- }
1008- bool Config::warnAboutUnmatchedTestSpecs() const {
1009- return !!( m_data.warnings & WarnAbout::UnmatchedTestSpec );
1010- }
1011- bool Config::zeroTestsCountAsSuccess() const { return m_data.allowZeroTests; }
1012- ShowDurations Config::showDurations() const { return m_data.showDurations; }
1013- double Config::minDuration() const { return m_data.minDuration; }
1014- TestRunOrder Config::runOrder() const { return m_data.runOrder; }
1015- uint32_t Config::rngSeed() const { return m_data.rngSeed; }
1016- unsigned int Config::shardCount() const { return m_data.shardCount; }
1017- unsigned int Config::shardIndex() const { return m_data.shardIndex; }
1018- ColourMode Config::defaultColourMode() const { return m_data.defaultColourMode; }
1019- bool Config::shouldDebugBreak() const { return m_data.shouldDebugBreak; }
1020- int Config::abortAfter() const { return m_data.abortAfter; }
1021- bool Config::showInvisibles() const { return m_data.showInvisibles; }
1022- Verbosity Config::verbosity() const { return m_data.verbosity; }
1023-
1024- bool Config::skipBenchmarks() const { return m_data.skipBenchmarks; }
1025- bool Config::benchmarkNoAnalysis() const { return m_data.benchmarkNoAnalysis; }
1026- unsigned int Config::benchmarkSamples() const { return m_data.benchmarkSamples; }
1027- double Config::benchmarkConfidenceInterval() const { return m_data.benchmarkConfidenceInterval; }
1028- unsigned int Config::benchmarkResamples() const { return m_data.benchmarkResamples; }
1029- std::chrono::milliseconds Config::benchmarkWarmupTime() const { return std::chrono::milliseconds(m_data.benchmarkWarmupTime); }
1030-
1031- void Config::readBazelEnvVars() {
1032- // Register a JUnit reporter for Bazel. Bazel sets an environment
1033- // variable with the path to XML output. If this file is written to
1034- // during test, Bazel will not generate a default XML output.
1035- // This allows the XML output file to contain higher level of detail
1036- // than what is possible otherwise.
1037- const auto bazelOutputFile = Detail::getEnv( "XML_OUTPUT_FILE" );
1038-
1039- if ( bazelOutputFile ) {
1040- m_data.reporterSpecifications.push_back(
1041- { "junit", std::string( bazelOutputFile ), {}, {} } );
1042- }
1043-
1044- const auto bazelTestSpec = Detail::getEnv( "TESTBRIDGE_TEST_ONLY" );
1045- if ( bazelTestSpec ) {
1046- // Presumably the test spec from environment should overwrite
1047- // the one we got from CLI (if we got any)
1048- m_data.testsOrTags.clear();
1049- m_data.testsOrTags.push_back( bazelTestSpec );
1050- }
1051-
1052- const auto bazelShardOptions = readBazelShardingOptions();
1053- if ( bazelShardOptions ) {
1054- std::ofstream f( bazelShardOptions->shardFilePath,
1055- std::ios_base::out | std::ios_base::trunc );
1056- if ( f.is_open() ) {
1057- f << "";
1058- m_data.shardIndex = bazelShardOptions->shardIndex;
1059- m_data.shardCount = bazelShardOptions->shardCount;
1060- }
1061- }
1062-
1063- const auto bazelExitGuardFile = Detail::getEnv( "TEST_PREMATURE_EXIT_FILE" );
1064- if (bazelExitGuardFile) {
1065- m_data.prematureExitGuardFilePath = bazelExitGuardFile;
1066- }
1067-
1068- const auto bazelRandomSeed = Detail::getEnv( "TEST_RANDOM_SEED" );
1069- if ( bazelRandomSeed ) {
1070- auto parsedSeed = parseUInt( bazelRandomSeed, 0 );
1071- if ( !parsedSeed ) {
1072- // Currently we handle issues with parsing other Bazel Env
1073- // options by warning and ignoring the issue. So we do the
1074- // same for random seed option.
1075- Catch::cerr()
1076- << "Warning: could not parse 'TEST_RANDOM_SEED' ('"
1077- << bazelRandomSeed << "') as proper seed.\n";
1078- } else {
1079- m_data.rngSeed = *parsedSeed;
1080- }
1081- }
1082- }
1083-
1084-} // end namespace Catch
1085-
1086-
1087-
1088-
1089-
1090-namespace Catch {
1091- std::uint32_t getSeed() {
1092- return getCurrentContext().getConfig()->rngSeed();
1093- }
1094-}
1095-
1096-
1097-
1098-#include <cassert>
1099-#include <stack>
1100-
1101-namespace Catch {
1102-
1103- ////////////////////////////////////////////////////////////////////////////
1104-
1105-
1106- ScopedMessage::ScopedMessage( MessageBuilder&& builder ):
1107- m_messageId( builder.m_info.sequence ) {
1108- MessageInfo info( CATCH_MOVE( builder.m_info ) );
1109- info.message = builder.m_stream.str();
1110- IResultCapture::pushScopedMessage( CATCH_MOVE( info ) );
1111- }
1112-
1113- ScopedMessage::ScopedMessage( ScopedMessage&& old ) noexcept:
1114- m_messageId( old.m_messageId ) {
1115- old.m_moved = true;
1116- }
1117-
1118- ScopedMessage::~ScopedMessage() {
1119- if ( !m_moved ) { IResultCapture::popScopedMessage( m_messageId ); }
1120- }
1121-
1122-
1123- Capturer::Capturer( StringRef macroName,
1124- SourceLineInfo const& lineInfo,
1125- ResultWas::OfType resultType,
1126- StringRef names ) {
1127- auto trimmed = [&] (size_t start, size_t end) {
1128- while (names[start] == ',' || isspace(static_cast<unsigned char>(names[start]))) {
1129- ++start;
1130- }
1131- while (names[end] == ',' || isspace(static_cast<unsigned char>(names[end]))) {
1132- --end;
1133- }
1134- return names.substr(start, end - start + 1);
1135- };
1136- auto skipq = [&] (size_t start, char quote) {
1137- for (auto i = start + 1; i < names.size() ; ++i) {
1138- if (names[i] == quote)
1139- return i;
1140- if (names[i] == '\\')
1141- ++i;
1142- }
1143- CATCH_INTERNAL_ERROR("CAPTURE parsing encountered unmatched quote");
1144- };
1145-
1146- size_t start = 0;
1147- std::stack<char> openings;
1148- for (size_t pos = 0; pos < names.size(); ++pos) {
1149- char c = names[pos];
1150- switch (c) {
1151- case '[':
1152- case '{':
1153- case '(':
1154- // It is basically impossible to disambiguate between
1155- // comparison and start of template args in this context
1156-// case '<':
1157- openings.push(c);
1158- break;
1159- case ']':
1160- case '}':
1161- case ')':
1162-// case '>':
1163- openings.pop();
1164- break;
1165- case '"':
1166- case '\'':
1167- pos = skipq(pos, c);
1168- break;
1169- case ',':
1170- if (start != pos && openings.empty()) {
1171- m_messages.emplace_back(macroName, lineInfo, resultType);
1172- m_messages.back().message += trimmed(start, pos);
1173- m_messages.back().message += " := "_sr;
1174- start = pos;
1175- }
1176- break;
1177- default:; // noop
1178- }
1179- }
1180- assert(openings.empty() && "Mismatched openings");
1181- m_messages.emplace_back(macroName, lineInfo, resultType);
1182- m_messages.back().message += trimmed(start, names.size() - 1);
1183- m_messages.back().message += " := "_sr;
1184- }
1185- Capturer::~Capturer() {
1186- assert( m_captured == m_messages.size() );
1187- for (auto const& message : m_messages) {
1188- IResultCapture::popScopedMessage( message.sequence );
1189- }
1190- }
1191-
1192- void Capturer::captureValue( size_t index, std::string const& value ) {
1193- assert( index < m_messages.size() );
1194- m_messages[index].message += value;
1195- IResultCapture::pushScopedMessage( CATCH_MOVE( m_messages[index] ) );
1196- m_captured++;
1197- }
1198-
1199-} // end namespace Catch
1200-
1201-
1202-
1203-
1204-#include <exception>
1205-
1206-namespace Catch {
1207-
1208- namespace {
1209-
1210- class RegistryHub : public IRegistryHub,
1211- public IMutableRegistryHub,
1212- private Detail::NonCopyable {
1213-
1214- public: // IRegistryHub
1215- RegistryHub() = default;
1216- ReporterRegistry const& getReporterRegistry() const override {
1217- return m_reporterRegistry;
1218- }
1219- ITestCaseRegistry const& getTestCaseRegistry() const override {
1220- return m_testCaseRegistry;
1221- }
1222- IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const override {
1223- return m_exceptionTranslatorRegistry;
1224- }
1225- ITagAliasRegistry const& getTagAliasRegistry() const override {
1226- return m_tagAliasRegistry;
1227- }
1228- StartupExceptionRegistry const& getStartupExceptionRegistry() const override {
1229- return m_exceptionRegistry;
1230- }
1231-
1232- public: // IMutableRegistryHub
1233- void registerReporter( std::string const& name, IReporterFactoryPtr factory ) override {
1234- m_reporterRegistry.registerReporter( name, CATCH_MOVE(factory) );
1235- }
1236- void registerListener( Detail::unique_ptr<EventListenerFactory> factory ) override {
1237- m_reporterRegistry.registerListener( CATCH_MOVE(factory) );
1238- }
1239- void registerTest( Detail::unique_ptr<TestCaseInfo>&& testInfo, Detail::unique_ptr<ITestInvoker>&& invoker ) override {
1240- m_testCaseRegistry.registerTest( CATCH_MOVE(testInfo), CATCH_MOVE(invoker) );
1241- }
1242- void registerTranslator( Detail::unique_ptr<IExceptionTranslator>&& translator ) override {
1243- m_exceptionTranslatorRegistry.registerTranslator( CATCH_MOVE(translator) );
1244- }
1245- void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) override {
1246- m_tagAliasRegistry.add( alias, tag, lineInfo );
1247- }
1248- void registerStartupException() noexcept override {
1249-#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
1250- m_exceptionRegistry.add(std::current_exception());
1251-#else
1252- CATCH_INTERNAL_ERROR("Attempted to register active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
1253-#endif
1254- }
1255- IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() override {
1256- return m_enumValuesRegistry;
1257- }
1258-
1259- private:
1260- TestRegistry m_testCaseRegistry;
1261- ReporterRegistry m_reporterRegistry;
1262- ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;
1263- TagAliasRegistry m_tagAliasRegistry;
1264- StartupExceptionRegistry m_exceptionRegistry;
1265- Detail::EnumValuesRegistry m_enumValuesRegistry;
1266- };
1267- }
1268-
1269- using RegistryHubSingleton = Singleton<RegistryHub, IRegistryHub, IMutableRegistryHub>;
1270-
1271- IRegistryHub const& getRegistryHub() {
1272- return RegistryHubSingleton::get();
1273- }
1274- IMutableRegistryHub& getMutableRegistryHub() {
1275- return RegistryHubSingleton::getMutable();
1276- }
1277- void cleanUp() {
1278- cleanupSingletons();
1279- }
1280- std::string translateActiveException() {
1281- return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException();
1282- }
1283-
1284-
1285-} // end namespace Catch
1286-
1287-
1288-
1289-#include <cassert>
1290-#include <cstdio>
1291-#include <cstdlib>
1292-#include <exception>
1293-#include <iomanip>
1294-#include <set>
1295-
1296-namespace Catch {
1297-
1298- namespace {
1299- IEventListenerPtr createReporter(std::string const& reporterName, ReporterConfig&& config) {
1300- auto reporter = Catch::getRegistryHub().getReporterRegistry().create(reporterName, CATCH_MOVE(config));
1301- CATCH_ENFORCE(reporter, "No reporter registered with name: '" << reporterName << '\'');
1302-
1303- return reporter;
1304- }
1305-
1306- IEventListenerPtr prepareReporters(Config const* config) {
1307- if (Catch::getRegistryHub().getReporterRegistry().getListeners().empty()
1308- && config->getProcessedReporterSpecs().size() == 1) {
1309- auto const& spec = config->getProcessedReporterSpecs()[0];
1310- return createReporter(
1311- spec.name,
1312- ReporterConfig( config,
1313- makeStream( spec.outputFilename ),
1314- spec.colourMode,
1315- spec.customOptions ) );
1316- }
1317-
1318- auto multi = Detail::make_unique<MultiReporter>(config);
1319-
1320- auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners();
1321- for (auto const& listener : listeners) {
1322- multi->addListener(listener->create(config));
1323- }
1324-
1325- for ( auto const& reporterSpec : config->getProcessedReporterSpecs() ) {
1326- multi->addReporter( createReporter(
1327- reporterSpec.name,
1328- ReporterConfig( config,
1329- makeStream( reporterSpec.outputFilename ),
1330- reporterSpec.colourMode,
1331- reporterSpec.customOptions ) ) );
1332- }
1333-
1334- return multi;
1335- }
1336-
1337- class TestGroup {
1338- public:
1339- explicit TestGroup(IEventListenerPtr&& reporter, Config const* config):
1340- m_reporter(reporter.get()),
1341- m_config{config},
1342- m_context{config, CATCH_MOVE(reporter)} {
1343-
1344- assert( m_config->testSpec().getInvalidSpecs().empty() &&
1345- "Invalid test specs should be handled before running tests" );
1346-
1347- auto const& allTestCases = getAllTestCasesSorted(*m_config);
1348- auto const& testSpec = m_config->testSpec();
1349- if ( !testSpec.hasFilters() ) {
1350- for ( auto const& test : allTestCases ) {
1351- if ( !test.getTestCaseInfo().isHidden() ) {
1352- m_tests.emplace( &test );
1353- }
1354- }
1355- } else {
1356- m_matches =
1357- testSpec.matchesByFilter( allTestCases, *m_config );
1358- for ( auto const& match : m_matches ) {
1359- m_tests.insert( match.tests.begin(),
1360- match.tests.end() );
1361- }
1362- }
1363-
1364- m_tests = createShard(m_tests, m_config->shardCount(), m_config->shardIndex());
1365- }
1366-
1367- Totals execute() {
1368- Totals totals;
1369- for (auto const& testCase : m_tests) {
1370- if (!m_context.aborting())
1371- totals += m_context.runTest(*testCase);
1372- else
1373- m_reporter->skipTest(testCase->getTestCaseInfo());
1374- }
1375-
1376- for (auto const& match : m_matches) {
1377- if (match.tests.empty()) {
1378- m_unmatchedTestSpecs = true;
1379- m_reporter->noMatchingTestCases( match.name );
1380- }
1381- }
1382-
1383- return totals;
1384- }
1385-
1386- bool hadUnmatchedTestSpecs() const {
1387- return m_unmatchedTestSpecs;
1388- }
1389-
1390-
1391- private:
1392- IEventListener* m_reporter;
1393- Config const* m_config;
1394- RunContext m_context;
1395- std::set<TestCaseHandle const*> m_tests;
1396- TestSpec::Matches m_matches;
1397- bool m_unmatchedTestSpecs = false;
1398- };
1399-
1400- void applyFilenamesAsTags() {
1401- for (auto const& testInfo : getRegistryHub().getTestCaseRegistry().getAllInfos()) {
1402- testInfo->addFilenameTag();
1403- }
1404- }
1405-
1406- // Creates empty file at path. The path must be writable, we do not
1407- // try to create directories in path because that's hard in C++14.
1408- void setUpGuardFile( std::string const& guardFilePath ) {
1409- if ( !guardFilePath.empty() ) {
1410-#if defined( _MSC_VER )
1411- std::FILE* file = nullptr;
1412- if ( fopen_s( &file, guardFilePath.c_str(), "w" ) ) {
1413- char msgBuffer[100];
1414- const auto err = errno;
1415- std::string errMsg;
1416- if ( !strerror_s( msgBuffer, err ) ) {
1417- errMsg = msgBuffer;
1418- } else {
1419- errMsg = "Could not translate errno to a string";
1420- }
1421-
1422-#else
1423- std::FILE* file = std::fopen( guardFilePath.c_str(), "w" );
1424- if ( !file ) {
1425- const auto err = errno;
1426- const char* errMsg = std::strerror( err );
1427-#endif
1428-
1429- CATCH_RUNTIME_ERROR( "Could not open the exit guard file '"
1430- << guardFilePath << "' because '"
1431- << errMsg << "' (" << err << ')' );
1432- }
1433- const int ret = std::fclose( file );
1434- CATCH_ENFORCE(
1435- ret == 0,
1436- "Error when closing the exit guard file: " << ret );
1437- }
1438- }
1439-
1440- // Removes file at path. Assuming we created it in setUpGuardFile.
1441- void tearDownGuardFile( std::string const& guardFilePath ) {
1442- if ( !guardFilePath.empty() ) {
1443- const int ret = std::remove( guardFilePath.c_str() );
1444- CATCH_ENFORCE(
1445- ret == 0,
1446- "Error when removing the exit guard file: " << ret );
1447- }
1448- }
1449-
1450- } // anon namespace
1451-
1452- Session::Session() {
1453- static bool alreadyInstantiated = false;
1454- if( alreadyInstantiated ) {
1455- CATCH_TRY { CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); }
1456- CATCH_CATCH_ALL { getMutableRegistryHub().registerStartupException(); }
1457- }
1458-
1459- // There cannot be exceptions at startup in no-exception mode.
1460-#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
1461- const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions();
1462- if ( !exceptions.empty() ) {
1463- config();
1464- getCurrentMutableContext().setConfig(m_config.get());
1465-
1466- m_startupExceptions = true;
1467- auto errStream = makeStream( "%stderr" );
1468- auto colourImpl = makeColourImpl(
1469- ColourMode::PlatformDefault, errStream.get() );
1470- auto guard = colourImpl->guardColour( Colour::Red );
1471- errStream->stream() << "Errors occurred during startup!" << '\n';
1472- // iterate over all exceptions and notify user
1473- for ( const auto& ex_ptr : exceptions ) {
1474- try {
1475- std::rethrow_exception(ex_ptr);
1476- } catch ( std::exception const& ex ) {
1477- errStream->stream() << TextFlow::Column( ex.what() ).indent(2) << '\n';
1478- }
1479- }
1480- }
1481-#endif
1482-
1483- alreadyInstantiated = true;
1484- m_cli = makeCommandLineParser( m_configData );
1485- }
1486- Session::~Session() {
1487- Catch::cleanUp();
1488- }
1489-
1490- void Session::showHelp() const {
1491- Catch::cout()
1492- << "\nCatch2 v" << libraryVersion() << '\n'
1493- << m_cli << '\n'
1494- << "For more detailed usage please see the project docs\n\n" << std::flush;
1495- }
1496- void Session::libIdentify() {
1497- Catch::cout()
1498- << std::left << std::setw(16) << "description: " << "A Catch2 test executable\n"
1499- << std::left << std::setw(16) << "category: " << "testframework\n"
1500- << std::left << std::setw(16) << "framework: " << "Catch2\n"
1501- << std::left << std::setw(16) << "version: " << libraryVersion() << '\n' << std::flush;
1502- }
1503-
1504- int Session::applyCommandLine( int argc, char const * const * argv ) {
1505- if ( m_startupExceptions ) { return UnspecifiedErrorExitCode; }
1506-
1507- auto result = m_cli.parse( Clara::Args( argc, argv ) );
1508-
1509- if( !result ) {
1510- config();
1511- getCurrentMutableContext().setConfig(m_config.get());
1512- auto errStream = makeStream( "%stderr" );
1513- auto colour = makeColourImpl( ColourMode::PlatformDefault, errStream.get() );
1514-
1515- errStream->stream()
1516- << colour->guardColour( Colour::Red )
1517- << "\nError(s) in input:\n"
1518- << TextFlow::Column( result.errorMessage() ).indent( 2 )
1519- << "\n\n";
1520- errStream->stream() << "Run with -? for usage\n\n" << std::flush;
1521- return UnspecifiedErrorExitCode;
1522- }
1523-
1524- if( m_configData.showHelp )
1525- showHelp();
1526- if( m_configData.libIdentify )
1527- libIdentify();
1528-
1529- m_config.reset();
1530- return 0;
1531- }
1532-
1533-#if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE)
1534- int Session::applyCommandLine( int argc, wchar_t const * const * argv ) {
1535-
1536- char **utf8Argv = new char *[ argc ];
1537-
1538- for ( int i = 0; i < argc; ++i ) {
1539- int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, nullptr, 0, nullptr, nullptr );
1540-
1541- utf8Argv[ i ] = new char[ bufSize ];
1542-
1543- WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, nullptr, nullptr );
1544- }
1545-
1546- int returnCode = applyCommandLine( argc, utf8Argv );
1547-
1548- for ( int i = 0; i < argc; ++i )
1549- delete [] utf8Argv[ i ];
1550-
1551- delete [] utf8Argv;
1552-
1553- return returnCode;
1554- }
1555-#endif
1556-
1557- void Session::useConfigData( ConfigData const& configData ) {
1558- m_configData = configData;
1559- m_config.reset();
1560- }
1561-
1562- int Session::run() {
1563- if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) {
1564- Catch::cout() << "...waiting for enter/ return before starting\n" << std::flush;
1565- static_cast<void>(std::getchar());
1566- }
1567- int exitCode = runInternal();
1568-
1569- if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) {
1570- Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << '\n' << std::flush;
1571- static_cast<void>(std::getchar());
1572- }
1573- return exitCode;
1574- }
1575-
1576- Clara::Parser const& Session::cli() const {
1577- return m_cli;
1578- }
1579- void Session::cli( Clara::Parser const& newParser ) {
1580- m_cli = newParser;
1581- }
1582- ConfigData& Session::configData() {
1583- return m_configData;
1584- }
1585- Config& Session::config() {
1586- if( !m_config )
1587- m_config = Detail::make_unique<Config>( m_configData );
1588- return *m_config;
1589- }
1590-
1591- int Session::runInternal() {
1592- if ( m_startupExceptions ) { return UnspecifiedErrorExitCode; }
1593-
1594- if (m_configData.showHelp || m_configData.libIdentify) {
1595- return 0;
1596- }
1597-
1598- if ( m_configData.shardIndex >= m_configData.shardCount ) {
1599- Catch::cerr() << "The shard count (" << m_configData.shardCount
1600- << ") must be greater than the shard index ("
1601- << m_configData.shardIndex << ")\n"
1602- << std::flush;
1603- return UnspecifiedErrorExitCode;
1604- }
1605-
1606- CATCH_TRY {
1607- config(); // Force config to be constructed
1608-
1609- // We need to retrieve potential Bazel config with the full Config
1610- // constructor, so we have to create the guard file after it is created.
1611- setUpGuardFile( m_config->getExitGuardFilePath() );
1612-
1613- seedRng( *m_config );
1614-
1615- if (m_configData.filenamesAsTags) {
1616- applyFilenamesAsTags();
1617- }
1618-
1619- // Set up global config instance before we start calling into other functions
1620- getCurrentMutableContext().setConfig(m_config.get());
1621-
1622- // Create reporter(s) so we can route listings through them
1623- auto reporter = prepareReporters(m_config.get());
1624-
1625- auto const& invalidSpecs = m_config->testSpec().getInvalidSpecs();
1626- if ( !invalidSpecs.empty() ) {
1627- for ( auto const& spec : invalidSpecs ) {
1628- reporter->reportInvalidTestSpec( spec );
1629- }
1630- return InvalidTestSpecExitCode;
1631- }
1632-
1633-
1634- // Handle list request
1635- if (list(*reporter, *m_config)) {
1636- return 0;
1637- }
1638-
1639- TestGroup tests { CATCH_MOVE(reporter), m_config.get() };
1640- auto const totals = tests.execute();
1641-
1642- // If we got here, running the tests finished normally-enough.
1643- // They might've failed, but that would've been reported elsewhere.
1644- tearDownGuardFile( m_config->getExitGuardFilePath() );
1645-
1646- if ( tests.hadUnmatchedTestSpecs()
1647- && m_config->warnAboutUnmatchedTestSpecs() ) {
1648- return UnmatchedTestSpecExitCode;
1649- }
1650-
1651- if ( totals.testCases.total() == 0
1652- && !m_config->zeroTestsCountAsSuccess() ) {
1653- return NoTestsRunExitCode;
1654- }
1655-
1656- if ( totals.testCases.total() > 0 &&
1657- totals.testCases.total() == totals.testCases.skipped
1658- && !m_config->zeroTestsCountAsSuccess() ) {
1659- return AllTestsSkippedExitCode;
1660- }
1661-
1662- if ( totals.assertions.failed ) { return TestFailureExitCode; }
1663- return 0;
1664-
1665- }
1666-#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
1667- catch( std::exception& ex ) {
1668- Catch::cerr() << ex.what() << '\n' << std::flush;
1669- return UnspecifiedErrorExitCode;
1670- }
1671-#endif
1672- }
1673-
1674-} // end namespace Catch
1675-
1676-
1677-
1678-
1679-namespace Catch {
1680-
1681- RegistrarForTagAliases::RegistrarForTagAliases(char const* alias, char const* tag, SourceLineInfo const& lineInfo) {
1682- CATCH_TRY {
1683- getMutableRegistryHub().registerTagAlias(alias, tag, lineInfo);
1684- } CATCH_CATCH_ALL {
1685- // Do not throw when constructing global objects, instead register the exception to be processed later
1686- getMutableRegistryHub().registerStartupException();
1687- }
1688- }
1689-
1690-}
1691-
1692-
1693-
1694-#include <cassert>
1695-#include <cctype>
1696-#include <algorithm>
1697-
1698-namespace Catch {
1699-
1700- namespace {
1701- using TCP_underlying_type = uint8_t;
1702- static_assert(sizeof(TestCaseProperties) == sizeof(TCP_underlying_type),
1703- "The size of the TestCaseProperties is different from the assumed size");
1704-
1705- constexpr TestCaseProperties operator|(TestCaseProperties lhs, TestCaseProperties rhs) {
1706- return static_cast<TestCaseProperties>(
1707- static_cast<TCP_underlying_type>(lhs) | static_cast<TCP_underlying_type>(rhs)
1708- );
1709- }
1710-
1711- constexpr TestCaseProperties& operator|=(TestCaseProperties& lhs, TestCaseProperties rhs) {
1712- lhs = static_cast<TestCaseProperties>(
1713- static_cast<TCP_underlying_type>(lhs) | static_cast<TCP_underlying_type>(rhs)
1714- );
1715- return lhs;
1716- }
1717-
1718- constexpr TestCaseProperties operator&(TestCaseProperties lhs, TestCaseProperties rhs) {
1719- return static_cast<TestCaseProperties>(
1720- static_cast<TCP_underlying_type>(lhs) & static_cast<TCP_underlying_type>(rhs)
1721- );
1722- }
1723-
1724- constexpr bool applies(TestCaseProperties tcp) {
1725- static_assert(static_cast<TCP_underlying_type>(TestCaseProperties::None) == 0,
1726- "TestCaseProperties::None must be equal to 0");
1727- return tcp != TestCaseProperties::None;
1728- }
1729-
1730- TestCaseProperties parseSpecialTag( StringRef tag ) {
1731- if( !tag.empty() && tag[0] == '.' )
1732- return TestCaseProperties::IsHidden;
1733- else if( tag == "!throws"_sr )
1734- return TestCaseProperties::Throws;
1735- else if( tag == "!shouldfail"_sr )
1736- return TestCaseProperties::ShouldFail;
1737- else if( tag == "!mayfail"_sr )
1738- return TestCaseProperties::MayFail;
1739- else if( tag == "!nonportable"_sr )
1740- return TestCaseProperties::NonPortable;
1741- else if( tag == "!benchmark"_sr )
1742- return TestCaseProperties::Benchmark | TestCaseProperties::IsHidden;
1743- else
1744- return TestCaseProperties::None;
1745- }
1746- bool isReservedTag( StringRef tag ) {
1747- return parseSpecialTag( tag ) == TestCaseProperties::None
1748- && tag.size() > 0
1749- && !std::isalnum( static_cast<unsigned char>(tag[0]) );
1750- }
1751- void enforceNotReservedTag( StringRef tag, SourceLineInfo const& _lineInfo ) {
1752- CATCH_ENFORCE( !isReservedTag(tag),
1753- "Tag name: [" << tag << "] is not allowed.\n"
1754- << "Tag names starting with non alphanumeric characters are reserved\n"
1755- << _lineInfo );
1756- }
1757-
1758- std::string makeDefaultName() {
1759- static size_t counter = 0;
1760- return "Anonymous test case " + std::to_string(++counter);
1761- }
1762-
1763- constexpr StringRef extractFilenamePart(StringRef filename) {
1764- size_t lastDot = filename.size();
1765- while (lastDot > 0 && filename[lastDot - 1] != '.') {
1766- --lastDot;
1767- }
1768- // In theory we could have filename without any extension in it
1769- if ( lastDot == 0 ) { return StringRef(); }
1770-
1771- --lastDot;
1772- size_t nameStart = lastDot;
1773- while (nameStart > 0 && filename[nameStart - 1] != '/' && filename[nameStart - 1] != '\\') {
1774- --nameStart;
1775- }
1776-
1777- return filename.substr(nameStart, lastDot - nameStart);
1778- }
1779-
1780- // Returns the upper bound on size of extra tags ([#file]+[.])
1781- constexpr size_t sizeOfExtraTags(StringRef filepath) {
1782- // [.] is 3, [#] is another 3
1783- const size_t extras = 3 + 3;
1784- return extractFilenamePart(filepath).size() + extras;
1785- }
1786- } // end unnamed namespace
1787-
1788- bool operator<( Tag const& lhs, Tag const& rhs ) {
1789- Detail::CaseInsensitiveLess cmp;
1790- return cmp( lhs.original, rhs.original );
1791- }
1792- bool operator==( Tag const& lhs, Tag const& rhs ) {
1793- Detail::CaseInsensitiveEqualTo cmp;
1794- return cmp( lhs.original, rhs.original );
1795- }
1796-
1797- Detail::unique_ptr<TestCaseInfo>
1798- makeTestCaseInfo(StringRef _className,
1799- NameAndTags const& nameAndTags,
1800- SourceLineInfo const& _lineInfo ) {
1801- return Detail::make_unique<TestCaseInfo>(_className, nameAndTags, _lineInfo);
1802- }
1803-
1804- TestCaseInfo::TestCaseInfo(StringRef _className,
1805- NameAndTags const& _nameAndTags,
1806- SourceLineInfo const& _lineInfo):
1807- name( _nameAndTags.name.empty() ? makeDefaultName() : _nameAndTags.name ),
1808- className( _className ),
1809- lineInfo( _lineInfo )
1810- {
1811- StringRef originalTags = _nameAndTags.tags;
1812- // We need to reserve enough space to store all of the tags
1813- // (including optional hidden tag and filename tag)
1814- auto requiredSize = originalTags.size() + sizeOfExtraTags(_lineInfo.file);
1815- backingTags.reserve(requiredSize);
1816-
1817- // We cannot copy the tags directly, as we need to normalize
1818- // some tags, so that [.foo] is copied as [.][foo].
1819- size_t tagStart = 0;
1820- size_t tagEnd = 0;
1821- bool inTag = false;
1822- for (size_t idx = 0; idx < originalTags.size(); ++idx) {
1823- auto c = originalTags[idx];
1824- if (c == '[') {
1825- CATCH_ENFORCE(
1826- !inTag,
1827- "Found '[' inside a tag while registering test case '"
1828- << _nameAndTags.name << "' at " << _lineInfo );
1829-
1830- inTag = true;
1831- tagStart = idx;
1832- }
1833- if (c == ']') {
1834- CATCH_ENFORCE(
1835- inTag,
1836- "Found unmatched ']' while registering test case '"
1837- << _nameAndTags.name << "' at " << _lineInfo );
1838-
1839- inTag = false;
1840- tagEnd = idx;
1841- assert(tagStart < tagEnd);
1842-
1843- // We need to check the tag for special meanings, copy
1844- // it over to backing storage and actually reference the
1845- // backing storage in the saved tags
1846- StringRef tagStr = originalTags.substr(tagStart+1, tagEnd - tagStart - 1);
1847- CATCH_ENFORCE( !tagStr.empty(),
1848- "Found an empty tag while registering test case '"
1849- << _nameAndTags.name << "' at "
1850- << _lineInfo );
1851-
1852- enforceNotReservedTag(tagStr, lineInfo);
1853- properties |= parseSpecialTag(tagStr);
1854- // When copying a tag to the backing storage, we need to
1855- // check if it is a merged hide tag, such as [.foo], and
1856- // if it is, we need to handle it as if it was [foo].
1857- if (tagStr.size() > 1 && tagStr[0] == '.') {
1858- tagStr = tagStr.substr(1, tagStr.size() - 1);
1859- }
1860- // We skip over dealing with the [.] tag, as we will add
1861- // it later unconditionally and then sort and unique all
1862- // the tags.
1863- internalAppendTag(tagStr);
1864- }
1865- }
1866- CATCH_ENFORCE( !inTag,
1867- "Found an unclosed tag while registering test case '"
1868- << _nameAndTags.name << "' at " << _lineInfo );
1869-
1870-
1871- // Add [.] if relevant
1872- if (isHidden()) {
1873- internalAppendTag("."_sr);
1874- }
1875-
1876- // Sort and prepare tags
1877- std::sort(begin(tags), end(tags));
1878- tags.erase(std::unique(begin(tags), end(tags)),
1879- end(tags));
1880- }
1881-
1882- bool TestCaseInfo::isHidden() const {
1883- return applies( properties & TestCaseProperties::IsHidden );
1884- }
1885- bool TestCaseInfo::throws() const {
1886- return applies( properties & TestCaseProperties::Throws );
1887- }
1888- bool TestCaseInfo::okToFail() const {
1889- return applies( properties & (TestCaseProperties::ShouldFail | TestCaseProperties::MayFail ) );
1890- }
1891- bool TestCaseInfo::expectedToFail() const {
1892- return applies( properties & (TestCaseProperties::ShouldFail) );
1893- }
1894-
1895- void TestCaseInfo::addFilenameTag() {
1896- std::string combined("#");
1897- combined += extractFilenamePart(lineInfo.file);
1898- internalAppendTag(combined);
1899- }
1900-
1901- std::string TestCaseInfo::tagsAsString() const {
1902- std::string ret;
1903- // '[' and ']' per tag
1904- std::size_t full_size = 2 * tags.size();
1905- for (const auto& tag : tags) {
1906- full_size += tag.original.size();
1907- }
1908- ret.reserve(full_size);
1909- for (const auto& tag : tags) {
1910- ret.push_back('[');
1911- ret += tag.original;
1912- ret.push_back(']');
1913- }
1914-
1915- return ret;
1916- }
1917-
1918- void TestCaseInfo::internalAppendTag(StringRef tagStr) {
1919- backingTags += '[';
1920- const auto backingStart = backingTags.size();
1921- backingTags += tagStr;
1922- const auto backingEnd = backingTags.size();
1923- backingTags += ']';
1924- tags.emplace_back(StringRef(backingTags.c_str() + backingStart, backingEnd - backingStart));
1925- }
1926-
1927- bool operator<( TestCaseInfo const& lhs, TestCaseInfo const& rhs ) {
1928- // We want to avoid redoing the string comparisons multiple times,
1929- // so we store the result of a three-way comparison before using
1930- // it in the actual comparison logic.
1931- const auto cmpName = lhs.name.compare( rhs.name );
1932- if ( cmpName != 0 ) {
1933- return cmpName < 0;
1934- }
1935- const auto cmpClassName = lhs.className.compare( rhs.className );
1936- if ( cmpClassName != 0 ) {
1937- return cmpClassName < 0;
1938- }
1939- return lhs.tags < rhs.tags;
1940- }
1941-
1942-} // end namespace Catch
1943-
1944-
1945-
1946-#include <algorithm>
1947-#include <string>
1948-#include <vector>
1949-#include <ostream>
1950-
1951-namespace Catch {
1952-
1953- TestSpec::Pattern::Pattern( std::string const& name )
1954- : m_name( name )
1955- {}
1956-
1957- TestSpec::Pattern::~Pattern() = default;
1958-
1959- std::string const& TestSpec::Pattern::name() const {
1960- return m_name;
1961- }
1962-
1963-
1964- TestSpec::NamePattern::NamePattern( std::string const& name, std::string const& filterString )
1965- : Pattern( filterString )
1966- , m_wildcardPattern( toLower( name ), CaseSensitive::No )
1967- {}
1968-
1969- bool TestSpec::NamePattern::matches( TestCaseInfo const& testCase ) const {
1970- return m_wildcardPattern.matches( testCase.name );
1971- }
1972-
1973- void TestSpec::NamePattern::serializeTo( std::ostream& out ) const {
1974- out << '"' << name() << '"';
1975- }
1976-
1977-
1978- TestSpec::TagPattern::TagPattern( std::string const& tag, std::string const& filterString )
1979- : Pattern( filterString )
1980- , m_tag( tag )
1981- {}
1982-
1983- bool TestSpec::TagPattern::matches( TestCaseInfo const& testCase ) const {
1984- return std::find( begin( testCase.tags ),
1985- end( testCase.tags ),
1986- Tag( m_tag ) ) != end( testCase.tags );
1987- }
1988-
1989- void TestSpec::TagPattern::serializeTo( std::ostream& out ) const {
1990- out << name();
1991- }
1992-
1993- bool TestSpec::Filter::matches( TestCaseInfo const& testCase ) const {
1994- bool should_use = !testCase.isHidden();
1995- for (auto const& pattern : m_required) {
1996- should_use = true;
1997- if (!pattern->matches(testCase)) {
1998- return false;
1999- }
2000- }
2001- for (auto const& pattern : m_forbidden) {
2002- if (pattern->matches(testCase)) {
2003- return false;
2004- }
2005- }
2006- return should_use;
2007- }
2008-
2009- void TestSpec::Filter::serializeTo( std::ostream& out ) const {
2010- bool first = true;
2011- for ( auto const& pattern : m_required ) {
2012- if ( !first ) {
2013- out << ' ';
2014- }
2015- out << *pattern;
2016- first = false;
2017- }
2018- for ( auto const& pattern : m_forbidden ) {
2019- if ( !first ) {
2020- out << ' ';
2021- }
2022- out << *pattern;
2023- first = false;
2024- }
2025- }
2026-
2027-
2028- std::string TestSpec::extractFilterName( Filter const& filter ) {
2029- Catch::ReusableStringStream sstr;
2030- sstr << filter;
2031- return sstr.str();
2032- }
2033-
2034- bool TestSpec::hasFilters() const {
2035- return !m_filters.empty();
2036- }
2037-
2038- bool TestSpec::matches( TestCaseInfo const& testCase ) const {
2039- return std::any_of( m_filters.begin(), m_filters.end(), [&]( Filter const& f ){ return f.matches( testCase ); } );
2040- }
2041-
2042- TestSpec::Matches TestSpec::matchesByFilter( std::vector<TestCaseHandle> const& testCases, IConfig const& config ) const {
2043- Matches matches;
2044- matches.reserve( m_filters.size() );
2045- for ( auto const& filter : m_filters ) {
2046- std::vector<TestCaseHandle const*> currentMatches;
2047- for ( auto const& test : testCases )
2048- if ( isThrowSafe( test, config ) &&
2049- filter.matches( test.getTestCaseInfo() ) )
2050- currentMatches.emplace_back( &test );
2051- matches.push_back(
2052- FilterMatch{ extractFilterName( filter ), currentMatches } );
2053- }
2054- return matches;
2055- }
2056-
2057- const TestSpec::vectorStrings& TestSpec::getInvalidSpecs() const {
2058- return m_invalidSpecs;
2059- }
2060-
2061- void TestSpec::serializeTo( std::ostream& out ) const {
2062- bool first = true;
2063- for ( auto const& filter : m_filters ) {
2064- if ( !first ) {
2065- out << ',';
2066- }
2067- out << filter;
2068- first = false;
2069- }
2070- }
2071-
2072-}
2073-
2074-
2075-
2076-#include <chrono>
2077-
2078-namespace Catch {
2079-
2080- namespace {
2081- static auto getCurrentNanosecondsSinceEpoch() -> uint64_t {
2082- return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now().time_since_epoch()).count();
2083- }
2084- } // end unnamed namespace
2085-
2086- void Timer::start() {
2087- m_nanoseconds = getCurrentNanosecondsSinceEpoch();
2088- }
2089- auto Timer::getElapsedNanoseconds() const -> uint64_t {
2090- return getCurrentNanosecondsSinceEpoch() - m_nanoseconds;
2091- }
2092- auto Timer::getElapsedMicroseconds() const -> uint64_t {
2093- return getElapsedNanoseconds()/1000;
2094- }
2095- auto Timer::getElapsedMilliseconds() const -> unsigned int {
2096- return static_cast<unsigned int>(getElapsedMicroseconds()/1000);
2097- }
2098- auto Timer::getElapsedSeconds() const -> double {
2099- return static_cast<double>(getElapsedMicroseconds())/1000000.0;
2100- }
2101-
2102-
2103-} // namespace Catch
2104-
2105-
2106-
2107-
2108-#include <iomanip>
2109-
2110-namespace Catch {
2111-
2112-namespace Detail {
2113-
2114- namespace {
2115- const int hexThreshold = 255;
2116-
2117- struct Endianness {
2118- enum Arch : uint8_t {
2119- Big,
2120- Little
2121- };
2122-
2123- static Arch which() {
2124- int one = 1;
2125- // If the lowest byte we read is non-zero, we can assume
2126- // that little endian format is used.
2127- auto value = *reinterpret_cast<char*>(&one);
2128- return value ? Little : Big;
2129- }
2130- };
2131-
2132- template<typename T>
2133- std::string fpToString(T value, int precision) {
2134- if (Catch::isnan(value)) {
2135- return "nan";
2136- }
2137-
2138- ReusableStringStream rss;
2139- rss << std::setprecision(precision)
2140- << std::fixed
2141- << value;
2142- std::string d = rss.str();
2143- std::size_t i = d.find_last_not_of('0');
2144- if (i != std::string::npos && i != d.size() - 1) {
2145- if (d[i] == '.')
2146- i++;
2147- d = d.substr(0, i + 1);
2148- }
2149- return d;
2150- }
2151- } // end unnamed namespace
2152-
2153- std::string convertIntoString(StringRef string, bool escapeInvisibles) {
2154- std::string ret;
2155- // This is enough for the "don't escape invisibles" case, and a good
2156- // lower bound on the "escape invisibles" case.
2157- ret.reserve( string.size() + 2 );
2158-
2159- if ( !escapeInvisibles ) {
2160- ret += '"';
2161- ret += string;
2162- ret += '"';
2163- return ret;
2164- }
2165-
2166- size_t last_start = 0;
2167- auto write_to = [&]( size_t idx ) {
2168- if ( last_start < idx ) {
2169- ret += string.substr( last_start, idx - last_start );
2170- }
2171- last_start = idx + 1;
2172- };
2173-
2174- ret += '"';
2175- for ( size_t i = 0; i < string.size(); ++i ) {
2176- const char c = string[i];
2177- if ( c == '\r' || c == '\n' || c == '\t' || c == '\f' ) {
2178- write_to( i );
2179- if ( c == '\r' ) { ret.append( "\\r" ); }
2180- if ( c == '\n' ) { ret.append( "\\n" ); }
2181- if ( c == '\t' ) { ret.append( "\\t" ); }
2182- if ( c == '\f' ) { ret.append( "\\f" ); }
2183- }
2184- }
2185- write_to( string.size() );
2186- ret += '"';
2187-
2188- return ret;
2189- }
2190-
2191- std::string convertIntoString(StringRef string) {
2192- return convertIntoString(string, getCurrentContext().getConfig()->showInvisibles());
2193- }
2194-
2195- std::string rawMemoryToString( const void *object, std::size_t size ) {
2196- // Reverse order for little endian architectures
2197- int i = 0, end = static_cast<int>( size ), inc = 1;
2198- if( Endianness::which() == Endianness::Little ) {
2199- i = end-1;
2200- end = inc = -1;
2201- }
2202-
2203- unsigned char const *bytes = static_cast<unsigned char const *>(object);
2204- ReusableStringStream rss;
2205- rss << "0x" << std::setfill('0') << std::hex;
2206- for( ; i != end; i += inc )
2207- rss << std::setw(2) << static_cast<unsigned>(bytes[i]);
2208- return rss.str();
2209- }
2210-
2211- std::string makeExceptionHappenedString() {
2212- return "{ stringification failed with an exception: \"" +
2213- translateActiveException() + "\" }";
2214-
2215- }
2216-
2217-} // end Detail namespace
2218-
2219-
2220-
2221-//// ======================================================= ////
2222-//
2223-// Out-of-line defs for full specialization of StringMaker
2224-//
2225-//// ======================================================= ////
2226-
2227-std::string StringMaker<std::string>::convert(const std::string& str) {
2228- return Detail::convertIntoString( str );
2229-}
2230-
2231-#ifdef CATCH_CONFIG_CPP17_STRING_VIEW
2232-std::string StringMaker<std::string_view>::convert(std::string_view str) {
2233- return Detail::convertIntoString( StringRef( str.data(), str.size() ) );
2234-}
2235-#endif
2236-
2237-std::string StringMaker<char const*>::convert(char const* str) {
2238- if (str) {
2239- return Detail::convertIntoString( str );
2240- } else {
2241- return{ "{null string}" };
2242- }
2243-}
2244-std::string StringMaker<char*>::convert(char* str) { // NOLINT(readability-non-const-parameter)
2245- if (str) {
2246- return Detail::convertIntoString( str );
2247- } else {
2248- return{ "{null string}" };
2249- }
2250-}
2251-
2252-#ifdef CATCH_CONFIG_WCHAR
2253-std::string StringMaker<std::wstring>::convert(const std::wstring& wstr) {
2254- std::string s;
2255- s.reserve(wstr.size());
2256- for (auto c : wstr) {
2257- s += (c <= 0xff) ? static_cast<char>(c) : '?';
2258- }
2259- return ::Catch::Detail::stringify(s);
2260-}
2261-
2262-# ifdef CATCH_CONFIG_CPP17_STRING_VIEW
2263-std::string StringMaker<std::wstring_view>::convert(std::wstring_view str) {
2264- return StringMaker<std::wstring>::convert(std::wstring(str));
2265-}
2266-# endif
2267-
2268-std::string StringMaker<wchar_t const*>::convert(wchar_t const * str) {
2269- if (str) {
2270- return ::Catch::Detail::stringify(std::wstring{ str });
2271- } else {
2272- return{ "{null string}" };
2273- }
2274-}
2275-std::string StringMaker<wchar_t *>::convert(wchar_t * str) {
2276- if (str) {
2277- return ::Catch::Detail::stringify(std::wstring{ str });
2278- } else {
2279- return{ "{null string}" };
2280- }
2281-}
2282-#endif
2283-
2284-#if defined(CATCH_CONFIG_CPP17_BYTE)
2285-#include <cstddef>
2286-std::string StringMaker<std::byte>::convert(std::byte value) {
2287- return ::Catch::Detail::stringify(std::to_integer<unsigned long long>(value));
2288-}
2289-#endif // defined(CATCH_CONFIG_CPP17_BYTE)
2290-
2291-std::string StringMaker<int>::convert(int value) {
2292- return ::Catch::Detail::stringify(static_cast<long long>(value));
2293-}
2294-std::string StringMaker<long>::convert(long value) {
2295- return ::Catch::Detail::stringify(static_cast<long long>(value));
2296-}
2297-std::string StringMaker<long long>::convert(long long value) {
2298- ReusableStringStream rss;
2299- rss << value;
2300- if (value > Detail::hexThreshold) {
2301- rss << " (0x" << std::hex << value << ')';
2302- }
2303- return rss.str();
2304-}
2305-
2306-std::string StringMaker<unsigned int>::convert(unsigned int value) {
2307- return ::Catch::Detail::stringify(static_cast<unsigned long long>(value));
2308-}
2309-std::string StringMaker<unsigned long>::convert(unsigned long value) {
2310- return ::Catch::Detail::stringify(static_cast<unsigned long long>(value));
2311-}
2312-std::string StringMaker<unsigned long long>::convert(unsigned long long value) {
2313- ReusableStringStream rss;
2314- rss << value;
2315- if (value > Detail::hexThreshold) {
2316- rss << " (0x" << std::hex << value << ')';
2317- }
2318- return rss.str();
2319-}
2320-
2321-std::string StringMaker<signed char>::convert(signed char value) {
2322- if (value == '\r') {
2323- return "'\\r'";
2324- } else if (value == '\f') {
2325- return "'\\f'";
2326- } else if (value == '\n') {
2327- return "'\\n'";
2328- } else if (value == '\t') {
2329- return "'\\t'";
2330- } else if ('\0' <= value && value < ' ') {
2331- return ::Catch::Detail::stringify(static_cast<unsigned int>(value));
2332- } else {
2333- char chstr[] = "' '";
2334- chstr[1] = value;
2335- return chstr;
2336- }
2337-}
2338-std::string StringMaker<char>::convert(char c) {
2339- return ::Catch::Detail::stringify(static_cast<signed char>(c));
2340-}
2341-std::string StringMaker<unsigned char>::convert(unsigned char value) {
2342- return ::Catch::Detail::stringify(static_cast<char>(value));
2343-}
2344-
2345-int StringMaker<float>::precision = std::numeric_limits<float>::max_digits10;
2346-
2347-std::string StringMaker<float>::convert(float value) {
2348- return Detail::fpToString(value, precision) + 'f';
2349-}
2350-
2351-int StringMaker<double>::precision = std::numeric_limits<double>::max_digits10;
2352-
2353-std::string StringMaker<double>::convert(double value) {
2354- return Detail::fpToString(value, precision);
2355-}
2356-
2357-} // end namespace Catch
2358-
2359-
2360-
2361-namespace Catch {
2362-
2363- Counts Counts::operator - ( Counts const& other ) const {
2364- Counts diff;
2365- diff.passed = passed - other.passed;
2366- diff.failed = failed - other.failed;
2367- diff.failedButOk = failedButOk - other.failedButOk;
2368- diff.skipped = skipped - other.skipped;
2369- return diff;
2370- }
2371-
2372- Counts& Counts::operator += ( Counts const& other ) {
2373- passed += other.passed;
2374- failed += other.failed;
2375- failedButOk += other.failedButOk;
2376- skipped += other.skipped;
2377- return *this;
2378- }
2379-
2380- std::uint64_t Counts::total() const {
2381- return passed + failed + failedButOk + skipped;
2382- }
2383- bool Counts::allPassed() const {
2384- return failed == 0 && failedButOk == 0 && skipped == 0;
2385- }
2386- bool Counts::allOk() const {
2387- return failed == 0;
2388- }
2389-
2390- Totals Totals::operator - ( Totals const& other ) const {
2391- Totals diff;
2392- diff.assertions = assertions - other.assertions;
2393- diff.testCases = testCases - other.testCases;
2394- return diff;
2395- }
2396-
2397- Totals& Totals::operator += ( Totals const& other ) {
2398- assertions += other.assertions;
2399- testCases += other.testCases;
2400- return *this;
2401- }
2402-
2403- Totals Totals::delta( Totals const& prevTotals ) const {
2404- Totals diff = *this - prevTotals;
2405- if( diff.assertions.failed > 0 )
2406- ++diff.testCases.failed;
2407- else if( diff.assertions.failedButOk > 0 )
2408- ++diff.testCases.failedButOk;
2409- else if ( diff.assertions.skipped > 0 )
2410- ++ diff.testCases.skipped;
2411- else
2412- ++diff.testCases.passed;
2413- return diff;
2414- }
2415-
2416-}
2417-
2418-
2419-
2420-
2421-namespace Catch {
2422- namespace Detail {
2423- void registerTranslatorImpl(
2424- Detail::unique_ptr<IExceptionTranslator>&& translator ) {
2425- getMutableRegistryHub().registerTranslator(
2426- CATCH_MOVE( translator ) );
2427- }
2428- } // namespace Detail
2429-} // namespace Catch
2430-
2431-
2432-#include <ostream>
2433-
2434-namespace Catch {
2435-
2436- Version::Version
2437- ( unsigned int _majorVersion,
2438- unsigned int _minorVersion,
2439- unsigned int _patchNumber,
2440- char const * const _branchName,
2441- unsigned int _buildNumber )
2442- : majorVersion( _majorVersion ),
2443- minorVersion( _minorVersion ),
2444- patchNumber( _patchNumber ),
2445- branchName( _branchName ),
2446- buildNumber( _buildNumber )
2447- {}
2448-
2449- std::ostream& operator << ( std::ostream& os, Version const& version ) {
2450- os << version.majorVersion << '.'
2451- << version.minorVersion << '.'
2452- << version.patchNumber;
2453- // branchName is never null -> 0th char is \0 if it is empty
2454- if (version.branchName[0]) {
2455- os << '-' << version.branchName
2456- << '.' << version.buildNumber;
2457- }
2458- return os;
2459- }
2460-
2461- Version const& libraryVersion() {
2462- static Version version( 3, 11, 0, "", 0 );
2463- return version;
2464- }
2465-
2466-}
2467-
2468-
2469-
2470-
2471-namespace Catch {
2472-
2473- const char* GeneratorException::what() const noexcept {
2474- return m_msg;
2475- }
2476-
2477-} // end namespace Catch
2478-
2479-
2480-
2481-
2482-namespace Catch {
2483-
2484- IGeneratorTracker::~IGeneratorTracker() = default;
2485-
2486-namespace Generators {
2487-
2488-namespace Detail {
2489-
2490- [[noreturn]]
2491- void throw_generator_exception(char const* msg) {
2492- Catch::throw_exception(GeneratorException{ msg });
2493- }
2494-} // end namespace Detail
2495-
2496- GeneratorUntypedBase::~GeneratorUntypedBase() = default;
2497-
2498- IGeneratorTracker* acquireGeneratorTracker(StringRef generatorName, SourceLineInfo const& lineInfo ) {
2499- return getResultCapture().acquireGeneratorTracker( generatorName, lineInfo );
2500- }
2501-
2502- IGeneratorTracker* createGeneratorTracker( StringRef generatorName,
2503- SourceLineInfo lineInfo,
2504- GeneratorBasePtr&& generator ) {
2505- return getResultCapture().createGeneratorTracker(
2506- generatorName, lineInfo, CATCH_MOVE( generator ) );
2507- }
2508-
2509-} // namespace Generators
2510-} // namespace Catch
2511-
2512-
2513-
2514-
2515-#include <random>
2516-
2517-namespace Catch {
2518- namespace Generators {
2519- namespace Detail {
2520- std::uint32_t getSeed() { return sharedRng()(); }
2521- } // namespace Detail
2522-
2523- struct RandomFloatingGenerator<long double>::PImpl {
2524- PImpl( long double a, long double b, uint32_t seed ):
2525- rng( seed ), dist( a, b ) {}
2526-
2527- Catch::SimplePcg32 rng;
2528- std::uniform_real_distribution<long double> dist;
2529- };
2530-
2531- RandomFloatingGenerator<long double>::RandomFloatingGenerator(
2532- long double a, long double b, std::uint32_t seed) :
2533- m_pimpl(Catch::Detail::make_unique<PImpl>(a, b, seed)) {
2534- static_cast<void>( next() );
2535- }
2536-
2537- RandomFloatingGenerator<long double>::~RandomFloatingGenerator() =
2538- default;
2539- bool RandomFloatingGenerator<long double>::next() {
2540- m_current_number = m_pimpl->dist( m_pimpl->rng );
2541- return true;
2542- }
2543- } // namespace Generators
2544-} // namespace Catch
2545-
2546-
2547-
2548-
2549-namespace Catch {
2550- namespace Detail {
2551- void missingCaptureInstance() {
2552- CATCH_INTERNAL_ERROR( "No result capture instance" );
2553- }
2554- } // namespace Detail
2555-
2556- IResultCapture::~IResultCapture() = default;
2557-} // namespace Catch
2558-
2559-
2560-
2561-
2562-namespace Catch {
2563- IConfig::~IConfig() = default;
2564-}
2565-
2566-
2567-
2568-
2569-namespace Catch {
2570- IExceptionTranslator::~IExceptionTranslator() = default;
2571- IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() = default;
2572-}
2573-
2574-
2575-
2576-#include <string>
2577-
2578-namespace Catch {
2579- namespace Generators {
2580-
2581- bool GeneratorUntypedBase::countedNext() {
2582- auto ret = next();
2583- if ( ret ) {
2584- m_stringReprCache.clear();
2585- ++m_currentElementIndex;
2586- }
2587- return ret;
2588- }
2589-
2590- StringRef GeneratorUntypedBase::currentElementAsString() const {
2591- if ( m_stringReprCache.empty() ) {
2592- m_stringReprCache = stringifyImpl();
2593- }
2594- return m_stringReprCache;
2595- }
2596-
2597- } // namespace Generators
2598-} // namespace Catch
2599-
2600-
2601-
2602-
2603-namespace Catch {
2604- IRegistryHub::~IRegistryHub() = default;
2605- IMutableRegistryHub::~IMutableRegistryHub() = default;
2606-}
2607-
2608-
2609-
2610-#include <cassert>
2611-
2612-namespace Catch {
2613-
2614- ReporterConfig::ReporterConfig(
2615- IConfig const* _fullConfig,
2616- Detail::unique_ptr<IStream> _stream,
2617- ColourMode colourMode,
2618- std::map<std::string, std::string> customOptions ):
2619- m_stream( CATCH_MOVE(_stream) ),
2620- m_fullConfig( _fullConfig ),
2621- m_colourMode( colourMode ),
2622- m_customOptions( CATCH_MOVE( customOptions ) ) {}
2623-
2624- Detail::unique_ptr<IStream> ReporterConfig::takeStream() && {
2625- assert( m_stream );
2626- return CATCH_MOVE( m_stream );
2627- }
2628- IConfig const * ReporterConfig::fullConfig() const { return m_fullConfig; }
2629- ColourMode ReporterConfig::colourMode() const { return m_colourMode; }
2630-
2631- std::map<std::string, std::string> const&
2632- ReporterConfig::customOptions() const {
2633- return m_customOptions;
2634- }
2635-
2636- ReporterConfig::~ReporterConfig() = default;
2637-
2638- AssertionStats::AssertionStats( AssertionResult const& _assertionResult,
2639- std::vector<MessageInfo> const& _infoMessages,
2640- Totals const& _totals )
2641- : assertionResult( _assertionResult ),
2642- infoMessages( _infoMessages ),
2643- totals( _totals )
2644- {
2645- if( assertionResult.hasMessage() ) {
2646- // Copy message into messages list.
2647- // !TBD This should have been done earlier, somewhere
2648- MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() );
2649- builder.m_info.message = static_cast<std::string>(assertionResult.getMessage());
2650-
2651- infoMessages.push_back( CATCH_MOVE(builder.m_info) );
2652- }
2653- }
2654-
2655- SectionStats::SectionStats( SectionInfo&& _sectionInfo,
2656- Counts const& _assertions,
2657- double _durationInSeconds,
2658- bool _missingAssertions )
2659- : sectionInfo( CATCH_MOVE(_sectionInfo) ),
2660- assertions( _assertions ),
2661- durationInSeconds( _durationInSeconds ),
2662- missingAssertions( _missingAssertions )
2663- {}
2664-
2665-
2666- TestCaseStats::TestCaseStats( TestCaseInfo const& _testInfo,
2667- Totals const& _totals,
2668- std::string&& _stdOut,
2669- std::string&& _stdErr,
2670- bool _aborting )
2671- : testInfo( &_testInfo ),
2672- totals( _totals ),
2673- stdOut( CATCH_MOVE(_stdOut) ),
2674- stdErr( CATCH_MOVE(_stdErr) ),
2675- aborting( _aborting )
2676- {}
2677-
2678-
2679- TestRunStats::TestRunStats( TestRunInfo const& _runInfo,
2680- Totals const& _totals,
2681- bool _aborting )
2682- : runInfo( _runInfo ),
2683- totals( _totals ),
2684- aborting( _aborting )
2685- {}
2686-
2687- IEventListener::~IEventListener() = default;
2688-
2689-} // end namespace Catch
2690-
2691-
2692-
2693-
2694-namespace Catch {
2695- IReporterFactory::~IReporterFactory() = default;
2696- EventListenerFactory::~EventListenerFactory() = default;
2697-}
2698-
2699-
2700-
2701-
2702-namespace Catch {
2703- ITestCaseRegistry::~ITestCaseRegistry() = default;
2704-}
2705-
2706-
2707-
2708-namespace Catch {
2709-
2710- AssertionHandler::AssertionHandler
2711- ( StringRef macroName,
2712- SourceLineInfo const& lineInfo,
2713- StringRef capturedExpression,
2714- ResultDisposition::Flags resultDisposition )
2715- : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition },
2716- m_resultCapture( getResultCapture() )
2717- {
2718- m_resultCapture.notifyAssertionStarted( m_assertionInfo );
2719- }
2720-
2721- void AssertionHandler::handleExpr( ITransientExpression const& expr ) {
2722- m_resultCapture.handleExpr( m_assertionInfo, expr, m_reaction );
2723- }
2724- void AssertionHandler::handleMessage(ResultWas::OfType resultType, std::string&& message) {
2725- m_resultCapture.handleMessage( m_assertionInfo, resultType, CATCH_MOVE(message), m_reaction );
2726- }
2727-
2728- auto AssertionHandler::allowThrows() const -> bool {
2729- return getCurrentContext().getConfig()->allowThrows();
2730- }
2731-
2732- void AssertionHandler::complete() {
2733- m_completed = true;
2734- if( m_reaction.shouldDebugBreak ) {
2735-
2736- // If you find your debugger stopping you here then go one level up on the
2737- // call-stack for the code that caused it (typically a failed assertion)
2738-
2739- // (To go back to the test and change execution, jump over the throw, next)
2740- CATCH_BREAK_INTO_DEBUGGER();
2741- }
2742- if (m_reaction.shouldThrow) {
2743- throw_test_failure_exception();
2744- }
2745- if ( m_reaction.shouldSkip ) {
2746- throw_test_skip_exception();
2747- }
2748- }
2749-
2750- void AssertionHandler::handleUnexpectedInflightException() {
2751- m_resultCapture.handleUnexpectedInflightException( m_assertionInfo, Catch::translateActiveException(), m_reaction );
2752- }
2753-
2754- void AssertionHandler::handleExceptionThrownAsExpected() {
2755- m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);
2756- }
2757- void AssertionHandler::handleExceptionNotThrownAsExpected() {
2758- m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);
2759- }
2760-
2761- void AssertionHandler::handleUnexpectedExceptionNotThrown() {
2762- m_resultCapture.handleUnexpectedExceptionNotThrown( m_assertionInfo, m_reaction );
2763- }
2764-
2765- void AssertionHandler::handleThrowingCallSkipped() {
2766- m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);
2767- }
2768-
2769- // This is the overload that takes a string and infers the Equals matcher from it
2770- // The more general overload, that takes any string matcher, is in catch_capture_matchers.cpp
2771- void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str ) {
2772- handleExceptionMatchExpr( handler, Matchers::Equals( str ) );
2773- }
2774-
2775-} // namespace Catch
2776-
2777-
2778-
2779-
2780-#include <algorithm>
2781-
2782-namespace Catch {
2783- namespace Detail {
2784-
2785- bool CaseInsensitiveLess::operator()( StringRef lhs,
2786- StringRef rhs ) const {
2787- return std::lexicographical_compare(
2788- lhs.begin(), lhs.end(),
2789- rhs.begin(), rhs.end(),
2790- []( char l, char r ) { return toLower( l ) < toLower( r ); } );
2791- }
2792-
2793- bool
2794- CaseInsensitiveEqualTo::operator()( StringRef lhs,
2795- StringRef rhs ) const {
2796- return std::equal(
2797- lhs.begin(), lhs.end(),
2798- rhs.begin(), rhs.end(),
2799- []( char l, char r ) { return toLower( l ) == toLower( r ); } );
2800- }
2801-
2802- } // namespace Detail
2803-} // namespace Catch
2804-
2805-
2806-
2807-
2808-#include <algorithm>
2809-#include <ostream>
2810-
2811-namespace {
2812- bool isOptPrefix( char c ) {
2813- return c == '-'
2814-#ifdef CATCH_PLATFORM_WINDOWS
2815- || c == '/'
2816-#endif
2817- ;
2818- }
2819-
2820- Catch::StringRef normaliseOpt( Catch::StringRef optName ) {
2821- if ( optName[0] == '-'
2822-#if defined(CATCH_PLATFORM_WINDOWS)
2823- || optName[0] == '/'
2824-#endif
2825- ) {
2826- return optName.substr( 1, optName.size() );
2827- }
2828-
2829- return optName;
2830- }
2831-
2832- static size_t find_first_separator(Catch::StringRef sr) {
2833- auto is_separator = []( char c ) {
2834- return c == ' ' || c == ':' || c == '=';
2835- };
2836- size_t pos = 0;
2837- while (pos < sr.size()) {
2838- if (is_separator(sr[pos])) { return pos; }
2839- ++pos;
2840- }
2841-
2842- return Catch::StringRef::npos;
2843- }
2844-
2845-} // namespace
2846-
2847-namespace Catch {
2848- namespace Clara {
2849- namespace Detail {
2850-
2851- void TokenStream::loadBuffer() {
2852- m_tokenBuffer.clear();
2853-
2854- // Skip any empty strings
2855- while ( it != itEnd && it->empty() ) {
2856- ++it;
2857- }
2858-
2859- if ( it != itEnd ) {
2860- StringRef next = *it;
2861- if ( isOptPrefix( next[0] ) ) {
2862- auto delimiterPos = find_first_separator(next);
2863- if ( delimiterPos != StringRef::npos ) {
2864- m_tokenBuffer.push_back(
2865- { TokenType::Option,
2866- next.substr( 0, delimiterPos ) } );
2867- m_tokenBuffer.push_back(
2868- { TokenType::Argument,
2869- next.substr( delimiterPos + 1, next.size() ) } );
2870- } else {
2871- if ( next.size() > 1 && next[1] != '-' && next.size() > 2 ) {
2872- // Combined short args, e.g. "-ab" for "-a -b"
2873- for ( size_t i = 1; i < next.size(); ++i ) {
2874- m_tokenBuffer.push_back(
2875- { TokenType::Option,
2876- next.substr( i, 1 ) } );
2877- }
2878- } else {
2879- m_tokenBuffer.push_back(
2880- { TokenType::Option, next } );
2881- }
2882- }
2883- } else {
2884- m_tokenBuffer.push_back(
2885- { TokenType::Argument, next } );
2886- }
2887- }
2888- }
2889-
2890- TokenStream::TokenStream( Args const& args ):
2891- TokenStream( args.m_args.begin(), args.m_args.end() ) {}
2892-
2893- TokenStream::TokenStream( Iterator it_, Iterator itEnd_ ):
2894- it( it_ ), itEnd( itEnd_ ) {
2895- loadBuffer();
2896- }
2897-
2898- TokenStream& TokenStream::operator++() {
2899- if ( m_tokenBuffer.size() >= 2 ) {
2900- m_tokenBuffer.erase( m_tokenBuffer.begin() );
2901- } else {
2902- if ( it != itEnd )
2903- ++it;
2904- loadBuffer();
2905- }
2906- return *this;
2907- }
2908-
2909- ParserResult convertInto( std::string const& source,
2910- std::string& target ) {
2911- target = source;
2912- return ParserResult::ok( ParseResultType::Matched );
2913- }
2914-
2915- ParserResult convertInto( std::string const& source,
2916- bool& target ) {
2917- std::string srcLC = toLower( source );
2918-
2919- if ( srcLC == "y" || srcLC == "1" || srcLC == "true" ||
2920- srcLC == "yes" || srcLC == "on" ) {
2921- target = true;
2922- } else if ( srcLC == "n" || srcLC == "0" || srcLC == "false" ||
2923- srcLC == "no" || srcLC == "off" ) {
2924- target = false;
2925- } else {
2926- return ParserResult::runtimeError(
2927- "Expected a boolean value but did not recognise: '" +
2928- source + '\'' );
2929- }
2930- return ParserResult::ok( ParseResultType::Matched );
2931- }
2932-
2933- size_t ParserBase::cardinality() const { return 1; }
2934-
2935- InternalParseResult ParserBase::parse( Args const& args ) const {
2936- return parse( static_cast<std::string>(args.exeName()), TokenStream( args ) );
2937- }
2938-
2939- ParseState::ParseState( ParseResultType type,
2940- TokenStream remainingTokens ):
2941- m_type( type ), m_remainingTokens( CATCH_MOVE(remainingTokens) ) {}
2942-
2943- ParserResult BoundFlagRef::setFlag( bool flag ) {
2944- m_ref = flag;
2945- return ParserResult::ok( ParseResultType::Matched );
2946- }
2947-
2948- ResultBase::~ResultBase() = default;
2949-
2950- bool BoundRef::isContainer() const { return false; }
2951-
2952- bool BoundRef::isFlag() const { return false; }
2953-
2954- bool BoundFlagRefBase::isFlag() const { return true; }
2955-
2956-} // namespace Detail
2957-
2958- Detail::InternalParseResult Arg::parse(std::string const&,
2959- Detail::TokenStream tokens) const {
2960- auto validationResult = validate();
2961- if (!validationResult)
2962- return Detail::InternalParseResult(validationResult);
2963-
2964- auto token = *tokens;
2965- if (token.type != Detail::TokenType::Argument)
2966- return Detail::InternalParseResult::ok(Detail::ParseState(
2967- ParseResultType::NoMatch, CATCH_MOVE(tokens)));
2968-
2969- assert(!m_ref->isFlag());
2970- auto valueRef =
2971- static_cast<Detail::BoundValueRefBase*>(m_ref.get());
2972-
2973- auto result = valueRef->setValue(static_cast<std::string>(token.token));
2974- if ( !result )
2975- return Detail::InternalParseResult( result );
2976- else
2977- return Detail::InternalParseResult::ok(
2978- Detail::ParseState( ParseResultType::Matched,
2979- CATCH_MOVE( ++tokens ) ) );
2980- }
2981-
2982- Opt::Opt(bool& ref) :
2983- ParserRefImpl(std::make_shared<Detail::BoundFlagRef>(ref)) {}
2984-
2985- Detail::HelpColumns Opt::getHelpColumns() const {
2986- ReusableStringStream oss;
2987- bool first = true;
2988- for (auto const& opt : m_optNames) {
2989- if (first)
2990- first = false;
2991- else
2992- oss << ", ";
2993- oss << opt;
2994- }
2995- if (!m_hint.empty())
2996- oss << " <" << m_hint << '>';
2997- return { oss.str(), m_description };
2998- }
2999-
3000- bool Opt::isMatch(StringRef optToken) const {
3001- auto normalisedToken = normaliseOpt(optToken);
3002- for (auto const& name : m_optNames) {
3003- if (normaliseOpt(name) == normalisedToken)
3004- return true;
3005- }
3006- return false;
3007- }
3008-
3009- Detail::InternalParseResult Opt::parse(std::string const&,
3010- Detail::TokenStream tokens) const {
3011- auto validationResult = validate();
3012- if (!validationResult)
3013- return Detail::InternalParseResult(validationResult);
3014-
3015- if (tokens &&
3016- tokens->type == Detail::TokenType::Option) {
3017- auto const& token = *tokens;
3018- if (isMatch(token.token)) {
3019- if (m_ref->isFlag()) {
3020- auto flagRef =
3021- static_cast<Detail::BoundFlagRefBase*>(
3022- m_ref.get());
3023- auto result = flagRef->setFlag(true);
3024- if (!result)
3025- return Detail::InternalParseResult(result);
3026- if (result.value() ==
3027- ParseResultType::ShortCircuitAll)
3028- return Detail::InternalParseResult::ok(Detail::ParseState(
3029- result.value(), CATCH_MOVE(tokens)));
3030- } else {
3031- auto valueRef =
3032- static_cast<Detail::BoundValueRefBase*>(
3033- m_ref.get());
3034- ++tokens;
3035- if (!tokens)
3036- return Detail::InternalParseResult::runtimeError(
3037- "Expected argument following " +
3038- token.token);
3039- auto const& argToken = *tokens;
3040- if (argToken.type != Detail::TokenType::Argument)
3041- return Detail::InternalParseResult::runtimeError(
3042- "Expected argument following " +
3043- token.token);
3044- const auto result = valueRef->setValue(static_cast<std::string>(argToken.token));
3045- if (!result)
3046- return Detail::InternalParseResult(result);
3047- if (result.value() ==
3048- ParseResultType::ShortCircuitAll)
3049- return Detail::InternalParseResult::ok(Detail::ParseState(
3050- result.value(), CATCH_MOVE(tokens)));
3051- }
3052- return Detail::InternalParseResult::ok(Detail::ParseState(
3053- ParseResultType::Matched, CATCH_MOVE(++tokens)));
3054- }
3055- }
3056- return Detail::InternalParseResult::ok(
3057- Detail::ParseState(ParseResultType::NoMatch, CATCH_MOVE(tokens)));
3058- }
3059-
3060- Detail::Result Opt::validate() const {
3061- if (m_optNames.empty())
3062- return Detail::Result::logicError("No options supplied to Opt");
3063- for (auto const& name : m_optNames) {
3064- if (name.empty())
3065- return Detail::Result::logicError(
3066- "Option name cannot be empty");
3067-#ifdef CATCH_PLATFORM_WINDOWS
3068- if (name[0] != '-' && name[0] != '/')
3069- return Detail::Result::logicError(
3070- "Option name must begin with '-' or '/'");
3071-#else
3072- if (name[0] != '-')
3073- return Detail::Result::logicError(
3074- "Option name must begin with '-'");
3075-#endif
3076- }
3077- return ParserRefImpl::validate();
3078- }
3079-
3080- ExeName::ExeName() :
3081- m_name(std::make_shared<std::string>("<executable>")) {}
3082-
3083- ExeName::ExeName(std::string& ref) : ExeName() {
3084- m_ref = std::make_shared<Detail::BoundValueRef<std::string>>(ref);
3085- }
3086-
3087- Detail::InternalParseResult
3088- ExeName::parse(std::string const&,
3089- Detail::TokenStream tokens) const {
3090- return Detail::InternalParseResult::ok(
3091- Detail::ParseState(ParseResultType::NoMatch, CATCH_MOVE(tokens)));
3092- }
3093-
3094- ParserResult ExeName::set(std::string const& newName) {
3095- auto lastSlash = newName.find_last_of("\\/");
3096- auto filename = (lastSlash == std::string::npos)
3097- ? newName
3098- : newName.substr(lastSlash + 1);
3099-
3100- *m_name = filename;
3101- if (m_ref)
3102- return m_ref->setValue(filename);
3103- else
3104- return ParserResult::ok(ParseResultType::Matched);
3105- }
3106-
3107-
3108-
3109-
3110- Parser& Parser::operator|=( Parser const& other ) {
3111- m_options.insert( m_options.end(),
3112- other.m_options.begin(),
3113- other.m_options.end() );
3114- m_args.insert(
3115- m_args.end(), other.m_args.begin(), other.m_args.end() );
3116- return *this;
3117- }
3118-
3119- std::vector<Detail::HelpColumns> Parser::getHelpColumns() const {
3120- std::vector<Detail::HelpColumns> cols;
3121- cols.reserve( m_options.size() );
3122- for ( auto const& o : m_options ) {
3123- cols.push_back(o.getHelpColumns());
3124- }
3125- return cols;
3126- }
3127-
3128- void Parser::writeToStream( std::ostream& os ) const {
3129- if ( !m_exeName.name().empty() ) {
3130- os << "usage:\n"
3131- << " " << m_exeName.name() << ' ';
3132- bool required = true, first = true;
3133- for ( auto const& arg : m_args ) {
3134- if ( first )
3135- first = false;
3136- else
3137- os << ' ';
3138- if ( arg.isOptional() && required ) {
3139- os << '[';
3140- required = false;
3141- }
3142- os << '<' << arg.hint() << '>';
3143- if ( arg.cardinality() == 0 )
3144- os << " ... ";
3145- }
3146- if ( !required )
3147- os << ']';
3148- if ( !m_options.empty() )
3149- os << " options";
3150- os << "\n\nwhere options are:\n";
3151- }
3152-
3153- auto rows = getHelpColumns();
3154- size_t consoleWidth = CATCH_CONFIG_CONSOLE_WIDTH;
3155- size_t optWidth = 0;
3156- for ( auto const& cols : rows )
3157- optWidth = ( std::max )( optWidth, cols.left.size() + 2 );
3158-
3159- optWidth = ( std::min )( optWidth, consoleWidth / 2 );
3160-
3161- for ( auto& cols : rows ) {
3162- auto row = TextFlow::Column( CATCH_MOVE(cols.left) )
3163- .width( optWidth )
3164- .indent( 2 ) +
3165- TextFlow::Spacer( 4 ) +
3166- TextFlow::Column( static_cast<std::string>(cols.descriptions) )
3167- .width( consoleWidth - 7 - optWidth );
3168- os << row << '\n';
3169- }
3170- }
3171-
3172- Detail::Result Parser::validate() const {
3173- for ( auto const& opt : m_options ) {
3174- auto result = opt.validate();
3175- if ( !result )
3176- return result;
3177- }
3178- for ( auto const& arg : m_args ) {
3179- auto result = arg.validate();
3180- if ( !result )
3181- return result;
3182- }
3183- return Detail::Result::ok();
3184- }
3185-
3186- Detail::InternalParseResult
3187- Parser::parse( std::string const& exeName,
3188- Detail::TokenStream tokens ) const {
3189-
3190- struct ParserInfo {
3191- ParserBase const* parser = nullptr;
3192- size_t count = 0;
3193- };
3194- std::vector<ParserInfo> parseInfos;
3195- parseInfos.reserve( m_options.size() + m_args.size() );
3196- for ( auto const& opt : m_options ) {
3197- parseInfos.push_back( { &opt, 0 } );
3198- }
3199- for ( auto const& arg : m_args ) {
3200- parseInfos.push_back( { &arg, 0 } );
3201- }
3202-
3203- m_exeName.set( exeName );
3204-
3205- auto result = Detail::InternalParseResult::ok(
3206- Detail::ParseState( ParseResultType::NoMatch, CATCH_MOVE(tokens) ) );
3207- while ( result.value().remainingTokens() ) {
3208- bool tokenParsed = false;
3209-
3210- for ( auto& parseInfo : parseInfos ) {
3211- if ( parseInfo.parser->cardinality() == 0 ||
3212- parseInfo.count < parseInfo.parser->cardinality() ) {
3213- result = parseInfo.parser->parse(
3214- exeName, CATCH_MOVE(result).value().remainingTokens() );
3215- if ( !result )
3216- return result;
3217- if ( result.value().type() !=
3218- ParseResultType::NoMatch ) {
3219- tokenParsed = true;
3220- ++parseInfo.count;
3221- break;
3222- }
3223- }
3224- }
3225-
3226- if ( result.value().type() == ParseResultType::ShortCircuitAll )
3227- return result;
3228- if ( !tokenParsed )
3229- return Detail::InternalParseResult::runtimeError(
3230- "Unrecognised token: " +
3231- result.value().remainingTokens()->token );
3232- }
3233- // !TBD Check missing required options
3234- return result;
3235- }
3236-
3237- Args::Args(int argc, char const* const* argv) :
3238- m_exeName(argv[0]), m_args(argv + 1, argv + argc) {}
3239-
3240- Args::Args(std::initializer_list<StringRef> args) :
3241- m_exeName(*args.begin()),
3242- m_args(args.begin() + 1, args.end()) {}
3243-
3244-
3245- Help::Help( bool& showHelpFlag ):
3246- Opt( [&]( bool flag ) {
3247- showHelpFlag = flag;
3248- return ParserResult::ok( ParseResultType::ShortCircuitAll );
3249- } ) {
3250- static_cast<Opt&> ( *this )(
3251- "display usage information" )["-?"]["-h"]["--help"]
3252- .optional();
3253- }
3254-
3255- } // namespace Clara
3256-} // namespace Catch
3257-
3258-
3259-
3260-
3261-#include <fstream>
3262-#include <string>
3263-
3264-namespace Catch {
3265-
3266- Clara::Parser makeCommandLineParser( ConfigData& config ) {
3267-
3268- using namespace Clara;
3269-
3270- auto const setWarning = [&]( std::string const& warning ) {
3271- if ( warning == "NoAssertions" ) {
3272- config.warnings = static_cast<WarnAbout::What>(config.warnings | WarnAbout::NoAssertions);
3273- return ParserResult::ok( ParseResultType::Matched );
3274- } else if ( warning == "UnmatchedTestSpec" ) {
3275- config.warnings = static_cast<WarnAbout::What>(config.warnings | WarnAbout::UnmatchedTestSpec);
3276- return ParserResult::ok( ParseResultType::Matched );
3277- }
3278-
3279- return ParserResult ::runtimeError(
3280- "Unrecognised warning option: '" + warning + '\'' );
3281- };
3282- auto const loadTestNamesFromFile = [&]( std::string const& filename ) {
3283- std::ifstream f( filename.c_str() );
3284- if( !f.is_open() )
3285- return ParserResult::runtimeError( "Unable to load input file: '" + filename + '\'' );
3286-
3287- std::string line;
3288- while( std::getline( f, line ) ) {
3289- line = trim(line);
3290- if( !line.empty() && !startsWith( line, '#' ) ) {
3291- if( !startsWith( line, '"' ) )
3292- line = '"' + CATCH_MOVE(line) + '"';
3293- config.testsOrTags.push_back( line );
3294- config.testsOrTags.emplace_back( "," );
3295- }
3296- }
3297- //Remove comma in the end
3298- if(!config.testsOrTags.empty())
3299- config.testsOrTags.erase( config.testsOrTags.end()-1 );
3300-
3301- return ParserResult::ok( ParseResultType::Matched );
3302- };
3303- auto const setTestOrder = [&]( std::string const& order ) {
3304- if( startsWith( "declared", order ) )
3305- config.runOrder = TestRunOrder::Declared;
3306- else if( startsWith( "lexical", order ) )
3307- config.runOrder = TestRunOrder::LexicographicallySorted;
3308- else if( startsWith( "random", order ) )
3309- config.runOrder = TestRunOrder::Randomized;
3310- else
3311- return ParserResult::runtimeError( "Unrecognised ordering: '" + order + '\'' );
3312- return ParserResult::ok( ParseResultType::Matched );
3313- };
3314- auto const setRngSeed = [&]( std::string const& seed ) {
3315- if( seed == "time" ) {
3316- config.rngSeed = generateRandomSeed(GenerateFrom::Time);
3317- return ParserResult::ok(ParseResultType::Matched);
3318- } else if (seed == "random-device") {
3319- config.rngSeed = generateRandomSeed(GenerateFrom::RandomDevice);
3320- return ParserResult::ok(ParseResultType::Matched);
3321- }
3322-
3323- // TODO: ideally we should be parsing uint32_t directly
3324- // fix this later when we add new parse overload
3325- auto parsedSeed = parseUInt( seed, 0 );
3326- if ( !parsedSeed ) {
3327- return ParserResult::runtimeError( "Could not parse '" + seed + "' as seed" );
3328- }
3329- config.rngSeed = *parsedSeed;
3330- return ParserResult::ok( ParseResultType::Matched );
3331- };
3332- auto const setDefaultColourMode = [&]( std::string const& colourMode ) {
3333- Optional<ColourMode> maybeMode = Catch::Detail::stringToColourMode(toLower( colourMode ));
3334- if ( !maybeMode ) {
3335- return ParserResult::runtimeError(
3336- "colour mode must be one of: default, ansi, win32, "
3337- "or none. '" +
3338- colourMode + "' is not recognised" );
3339- }
3340- auto mode = *maybeMode;
3341- if ( !isColourImplAvailable( mode ) ) {
3342- return ParserResult::runtimeError(
3343- "colour mode '" + colourMode +
3344- "' is not supported in this binary" );
3345- }
3346- config.defaultColourMode = mode;
3347- return ParserResult::ok( ParseResultType::Matched );
3348- };
3349- auto const setWaitForKeypress = [&]( std::string const& keypress ) {
3350- auto keypressLc = toLower( keypress );
3351- if (keypressLc == "never")
3352- config.waitForKeypress = WaitForKeypress::Never;
3353- else if( keypressLc == "start" )
3354- config.waitForKeypress = WaitForKeypress::BeforeStart;
3355- else if( keypressLc == "exit" )
3356- config.waitForKeypress = WaitForKeypress::BeforeExit;
3357- else if( keypressLc == "both" )
3358- config.waitForKeypress = WaitForKeypress::BeforeStartAndExit;
3359- else
3360- return ParserResult::runtimeError( "keypress argument must be one of: never, start, exit or both. '" + keypress + "' not recognised" );
3361- return ParserResult::ok( ParseResultType::Matched );
3362- };
3363- auto const setVerbosity = [&]( std::string const& verbosity ) {
3364- auto lcVerbosity = toLower( verbosity );
3365- if( lcVerbosity == "quiet" )
3366- config.verbosity = Verbosity::Quiet;
3367- else if( lcVerbosity == "normal" )
3368- config.verbosity = Verbosity::Normal;
3369- else if( lcVerbosity == "high" )
3370- config.verbosity = Verbosity::High;
3371- else
3372- return ParserResult::runtimeError( "Unrecognised verbosity, '" + verbosity + '\'' );
3373- return ParserResult::ok( ParseResultType::Matched );
3374- };
3375- auto const setReporter = [&]( std::string const& userReporterSpec ) {
3376- if ( userReporterSpec.empty() ) {
3377- return ParserResult::runtimeError( "Received empty reporter spec." );
3378- }
3379-
3380- Optional<ReporterSpec> parsed =
3381- parseReporterSpec( userReporterSpec );
3382- if ( !parsed ) {
3383- return ParserResult::runtimeError(
3384- "Could not parse reporter spec '" + userReporterSpec +
3385- "'" );
3386- }
3387-
3388- auto const& reporterSpec = *parsed;
3389-
3390- auto const& factories =
3391- getRegistryHub().getReporterRegistry().getFactories();
3392- auto result = factories.find( reporterSpec.name() );
3393-
3394- if ( result == factories.end() ) {
3395- return ParserResult::runtimeError(
3396- "Unrecognized reporter, '" + reporterSpec.name() +
3397- "'. Check available with --list-reporters" );
3398- }
3399-
3400-
3401- const bool hadOutputFile = reporterSpec.outputFile().some();
3402- config.reporterSpecifications.push_back( CATCH_MOVE( *parsed ) );
3403- // It would be enough to check this only once at the very end, but
3404- // there is not a place where we could call this check, so do it
3405- // every time it could fail. For valid inputs, this is still called
3406- // at most once.
3407- if (!hadOutputFile) {
3408- int n_reporters_without_file = 0;
3409- for (auto const& spec : config.reporterSpecifications) {
3410- if (spec.outputFile().none()) {
3411- n_reporters_without_file++;
3412- }
3413- }
3414- if (n_reporters_without_file > 1) {
3415- return ParserResult::runtimeError( "Only one reporter may have unspecified output file." );
3416- }
3417- }
3418-
3419- return ParserResult::ok( ParseResultType::Matched );
3420- };
3421- auto const setShardCount = [&]( std::string const& shardCount ) {
3422- auto parsedCount = parseUInt( shardCount );
3423- if ( !parsedCount ) {
3424- return ParserResult::runtimeError(
3425- "Could not parse '" + shardCount + "' as shard count" );
3426- }
3427- if ( *parsedCount == 0 ) {
3428- return ParserResult::runtimeError(
3429- "Shard count must be positive" );
3430- }
3431- config.shardCount = *parsedCount;
3432- return ParserResult::ok( ParseResultType::Matched );
3433- };
3434-
3435- auto const setShardIndex = [&](std::string const& shardIndex) {
3436- auto parsedIndex = parseUInt( shardIndex );
3437- if ( !parsedIndex ) {
3438- return ParserResult::runtimeError(
3439- "Could not parse '" + shardIndex + "' as shard index" );
3440- }
3441- config.shardIndex = *parsedIndex;
3442- return ParserResult::ok( ParseResultType::Matched );
3443- };
3444-
3445- auto cli
3446- = ExeName( config.processName )
3447- | Help( config.showHelp )
3448- | Opt( config.showSuccessfulTests )
3449- ["-s"]["--success"]
3450- ( "include successful tests in output" )
3451- | Opt( config.shouldDebugBreak )
3452- ["-b"]["--break"]
3453- ( "break into debugger on failure" )
3454- | Opt( config.noThrow )
3455- ["-e"]["--nothrow"]
3456- ( "skip exception tests" )
3457- | Opt( config.showInvisibles )
3458- ["-i"]["--invisibles"]
3459- ( "show invisibles (tabs, newlines)" )
3460- | Opt( config.defaultOutputFilename, "filename" )
3461- ["-o"]["--out"]
3462- ( "default output filename" )
3463- | Opt( accept_many, setReporter, "name[::key=value]*" )
3464- ["-r"]["--reporter"]
3465- ( "reporter to use (defaults to console)" )
3466- | Opt( config.name, "name" )
3467- ["-n"]["--name"]
3468- ( "suite name" )
3469- | Opt( [&]( bool ){ config.abortAfter = 1; } )
3470- ["-a"]["--abort"]
3471- ( "abort at first failure" )
3472- | Opt( [&]( int x ){ config.abortAfter = x; }, "no. failures" )
3473- ["-x"]["--abortx"]
3474- ( "abort after x failures" )
3475- | Opt( accept_many, setWarning, "warning name" )
3476- ["-w"]["--warn"]
3477- ( "enable warnings" )
3478- | Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" )
3479- ["-d"]["--durations"]
3480- ( "show test durations" )
3481- | Opt( config.minDuration, "seconds" )
3482- ["-D"]["--min-duration"]
3483- ( "show test durations for tests taking at least the given number of seconds" )
3484- | Opt( loadTestNamesFromFile, "filename" )
3485- ["-f"]["--input-file"]
3486- ( "load test names to run from a file" )
3487- | Opt( config.filenamesAsTags )
3488- ["-#"]["--filenames-as-tags"]
3489- ( "adds a tag for the filename" )
3490- | Opt( config.sectionsToRun, "section name" )
3491- ["-c"]["--section"]
3492- ( "specify section to run" )
3493- | Opt( setVerbosity, "quiet|normal|high" )
3494- ["-v"]["--verbosity"]
3495- ( "set output verbosity" )
3496- | Opt( config.listTests )
3497- ["--list-tests"]
3498- ( "list all/matching test cases" )
3499- | Opt( config.listTags )
3500- ["--list-tags"]
3501- ( "list all/matching tags" )
3502- | Opt( config.listReporters )
3503- ["--list-reporters"]
3504- ( "list all available reporters" )
3505- | Opt( config.listListeners )
3506- ["--list-listeners"]
3507- ( "list all listeners" )
3508- | Opt( setTestOrder, "decl|lex|rand" )
3509- ["--order"]
3510- ( "test case order (defaults to decl)" )
3511- | Opt( setRngSeed, "'time'|'random-device'|number" )
3512- ["--rng-seed"]
3513- ( "set a specific seed for random numbers" )
3514- | Opt( setDefaultColourMode, "ansi|win32|none|default" )
3515- ["--colour-mode"]
3516- ( "what color mode should be used as default" )
3517- | Opt( config.libIdentify )
3518- ["--libidentify"]
3519- ( "report name and version according to libidentify standard" )
3520- | Opt( setWaitForKeypress, "never|start|exit|both" )
3521- ["--wait-for-keypress"]
3522- ( "waits for a keypress before exiting" )
3523- | Opt( config.skipBenchmarks)
3524- ["--skip-benchmarks"]
3525- ( "disable running benchmarks")
3526- | Opt( config.benchmarkSamples, "samples" )
3527- ["--benchmark-samples"]
3528- ( "number of samples to collect (default: 100)" )
3529- | Opt( config.benchmarkResamples, "resamples" )
3530- ["--benchmark-resamples"]
3531- ( "number of resamples for the bootstrap (default: 100000)" )
3532- | Opt( config.benchmarkConfidenceInterval, "confidence interval" )
3533- ["--benchmark-confidence-interval"]
3534- ( "confidence interval for the bootstrap (between 0 and 1, default: 0.95)" )
3535- | Opt( config.benchmarkNoAnalysis )
3536- ["--benchmark-no-analysis"]
3537- ( "perform only measurements; do not perform any analysis" )
3538- | Opt( config.benchmarkWarmupTime, "benchmarkWarmupTime" )
3539- ["--benchmark-warmup-time"]
3540- ( "amount of time in milliseconds spent on warming up each test (default: 100)" )
3541- | Opt( setShardCount, "shard count" )
3542- ["--shard-count"]
3543- ( "split the tests to execute into this many groups" )
3544- | Opt( setShardIndex, "shard index" )
3545- ["--shard-index"]
3546- ( "index of the group of tests to execute (see --shard-count)" )
3547- | Opt( config.allowZeroTests )
3548- ["--allow-running-no-tests"]
3549- ( "Treat 'No tests run' as a success" )
3550- | Opt( config.prematureExitGuardFilePath, "path" )
3551- ["--premature-exit-guard-file"]
3552- ( "create a file before running tests and delete it during clean exit" )
3553- | Arg( config.testsOrTags, "test name|pattern|tags" )
3554- ( "which test or tests to use" );
3555-
3556- return cli;
3557- }
3558-
3559-} // end namespace Catch
3560-
3561-
3562-#if defined(__clang__)
3563-# pragma clang diagnostic push
3564-# pragma clang diagnostic ignored "-Wexit-time-destructors"
3565-#endif
3566-
3567-
3568-
3569-#include <cassert>
3570-#include <ostream>
3571-#include <utility>
3572-
3573-namespace Catch {
3574-
3575- ColourImpl::~ColourImpl() = default;
3576-
3577- ColourImpl::ColourGuard ColourImpl::guardColour( Colour::Code colourCode ) {
3578- return ColourGuard(colourCode, this );
3579- }
3580-
3581- void ColourImpl::ColourGuard::engageImpl( std::ostream& stream ) {
3582- assert( &stream == &m_colourImpl->m_stream->stream() &&
3583- "Engaging colour guard for different stream than used by the "
3584- "parent colour implementation" );
3585- static_cast<void>( stream );
3586-
3587- m_engaged = true;
3588- m_colourImpl->use( m_code );
3589- }
3590-
3591- ColourImpl::ColourGuard::ColourGuard( Colour::Code code,
3592- ColourImpl const* colour ):
3593- m_colourImpl( colour ), m_code( code ) {
3594- }
3595- ColourImpl::ColourGuard::ColourGuard( ColourGuard&& rhs ) noexcept:
3596- m_colourImpl( rhs.m_colourImpl ),
3597- m_code( rhs.m_code ),
3598- m_engaged( rhs.m_engaged ) {
3599- rhs.m_engaged = false;
3600- }
3601- ColourImpl::ColourGuard&
3602- ColourImpl::ColourGuard::operator=( ColourGuard&& rhs ) noexcept {
3603- using std::swap;
3604- swap( m_colourImpl, rhs.m_colourImpl );
3605- swap( m_code, rhs.m_code );
3606- swap( m_engaged, rhs.m_engaged );
3607-
3608- return *this;
3609- }
3610- ColourImpl::ColourGuard::~ColourGuard() {
3611- if ( m_engaged ) {
3612- m_colourImpl->use( Colour::None );
3613- }
3614- }
3615-
3616- ColourImpl::ColourGuard&
3617- ColourImpl::ColourGuard::engage( std::ostream& stream ) & {
3618- engageImpl( stream );
3619- return *this;
3620- }
3621-
3622- ColourImpl::ColourGuard&&
3623- ColourImpl::ColourGuard::engage( std::ostream& stream ) && {
3624- engageImpl( stream );
3625- return CATCH_MOVE(*this);
3626- }
3627-
3628- namespace {
3629- //! A do-nothing implementation of colour, used as fallback for unknown
3630- //! platforms, and when the user asks to deactivate all colours.
3631- class NoColourImpl final : public ColourImpl {
3632- public:
3633- NoColourImpl( IStream* stream ): ColourImpl( stream ) {}
3634-
3635- private:
3636- void use( Colour::Code ) const override {}
3637- };
3638- } // namespace
3639-
3640-
3641-} // namespace Catch
3642-
3643-
3644-#if defined ( CATCH_CONFIG_COLOUR_WIN32 ) /////////////////////////////////////////
3645-
3646-namespace Catch {
3647-namespace {
3648-
3649- class Win32ColourImpl final : public ColourImpl {
3650- public:
3651- Win32ColourImpl(IStream* stream):
3652- ColourImpl(stream) {
3653- CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
3654- GetConsoleScreenBufferInfo( GetStdHandle( STD_OUTPUT_HANDLE ),
3655- &csbiInfo );
3656- originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY );
3657- originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY );
3658- }
3659-
3660- static bool useImplementationForStream(IStream const& stream) {
3661- // Win32 text colour APIs can only be used on console streams
3662- // We cannot check that the output hasn't been redirected,
3663- // so we just check that the original stream is console stream.
3664- return stream.isConsole();
3665- }
3666-
3667- private:
3668- void use( Colour::Code _colourCode ) const override {
3669- switch( _colourCode ) {
3670- case Colour::None: return setTextAttribute( originalForegroundAttributes );
3671- case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
3672- case Colour::Red: return setTextAttribute( FOREGROUND_RED );
3673- case Colour::Green: return setTextAttribute( FOREGROUND_GREEN );
3674- case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE );
3675- case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN );
3676- case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN );
3677- case Colour::Grey: return setTextAttribute( 0 );
3678-
3679- case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY );
3680- case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED );
3681- case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN );
3682- case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
3683- case Colour::BrightYellow: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN );
3684-
3685- case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" );
3686-
3687- default:
3688- CATCH_ERROR( "Unknown colour requested" );
3689- }
3690- }
3691-
3692- void setTextAttribute( WORD _textAttribute ) const {
3693- SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ),
3694- _textAttribute |
3695- originalBackgroundAttributes );
3696- }
3697- WORD originalForegroundAttributes;
3698- WORD originalBackgroundAttributes;
3699- };
3700-
3701-} // end anon namespace
3702-} // end namespace Catch
3703-
3704-#endif // Windows/ ANSI/ None
3705-
3706-
3707-#if defined( CATCH_PLATFORM_LINUX ) \
3708- || defined( CATCH_PLATFORM_MAC ) \
3709- || defined( __GLIBC__ ) \
3710- || defined( __FreeBSD__ ) \
3711- || defined( CATCH_PLATFORM_QNX )
3712-# define CATCH_INTERNAL_HAS_ISATTY
3713-# include <unistd.h>
3714-#endif
3715-
3716-namespace Catch {
3717-namespace {
3718-
3719- class ANSIColourImpl final : public ColourImpl {
3720- public:
3721- ANSIColourImpl( IStream* stream ): ColourImpl( stream ) {}
3722-
3723- static bool useImplementationForStream(IStream const& stream) {
3724- // This is kinda messy due to trying to support a bunch of
3725- // different platforms at once.
3726- // The basic idea is that if we are asked to do autodetection (as
3727- // opposed to being told to use posixy colours outright), then we
3728- // only want to use the colours if we are writing to console.
3729- // However, console might be redirected, so we make an attempt at
3730- // checking for that on platforms where we know how to do that.
3731- bool useColour = stream.isConsole();
3732-#if defined( CATCH_INTERNAL_HAS_ISATTY ) && \
3733- !( defined( __DJGPP__ ) && defined( __STRICT_ANSI__ ) )
3734- ErrnoGuard _; // for isatty
3735- useColour = useColour && isatty( STDOUT_FILENO );
3736-# endif
3737-# if defined( CATCH_PLATFORM_MAC ) || defined( CATCH_PLATFORM_IPHONE )
3738- useColour = useColour && !isDebuggerActive();
3739-# endif
3740-
3741- return useColour;
3742- }
3743-
3744- private:
3745- void use( Colour::Code _colourCode ) const override {
3746- auto setColour = [&out =
3747- m_stream->stream()]( char const* escapeCode ) {
3748- // The escape sequence must be flushed to console, otherwise
3749- // if stdin and stderr are intermixed, we'd get accidentally
3750- // coloured output.
3751- out << '\033' << escapeCode << std::flush;
3752- };
3753- switch( _colourCode ) {
3754- case Colour::None:
3755- case Colour::White: return setColour( "[0m" );
3756- case Colour::Red: return setColour( "[0;31m" );
3757- case Colour::Green: return setColour( "[0;32m" );
3758- case Colour::Blue: return setColour( "[0;34m" );
3759- case Colour::Cyan: return setColour( "[0;36m" );
3760- case Colour::Yellow: return setColour( "[0;33m" );
3761- case Colour::Grey: return setColour( "[1;30m" );
3762-
3763- case Colour::LightGrey: return setColour( "[0;37m" );
3764- case Colour::BrightRed: return setColour( "[1;31m" );
3765- case Colour::BrightGreen: return setColour( "[1;32m" );
3766- case Colour::BrightWhite: return setColour( "[1;37m" );
3767- case Colour::BrightYellow: return setColour( "[1;33m" );
3768-
3769- case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" );
3770- default: CATCH_INTERNAL_ERROR( "Unknown colour requested" );
3771- }
3772- }
3773- };
3774-
3775-} // end anon namespace
3776-} // end namespace Catch
3777-
3778-namespace Catch {
3779-
3780- Detail::unique_ptr<ColourImpl> makeColourImpl( ColourMode colourSelection,
3781- IStream* stream ) {
3782-#if defined( CATCH_CONFIG_COLOUR_WIN32 )
3783- if ( colourSelection == ColourMode::Win32 ) {
3784- return Detail::make_unique<Win32ColourImpl>( stream );
3785- }
3786-#endif
3787- if ( colourSelection == ColourMode::ANSI ) {
3788- return Detail::make_unique<ANSIColourImpl>( stream );
3789- }
3790- if ( colourSelection == ColourMode::None ) {
3791- return Detail::make_unique<NoColourImpl>( stream );
3792- }
3793-
3794- if ( colourSelection == ColourMode::PlatformDefault) {
3795-#if defined( CATCH_CONFIG_COLOUR_WIN32 )
3796- if ( Win32ColourImpl::useImplementationForStream( *stream ) ) {
3797- return Detail::make_unique<Win32ColourImpl>( stream );
3798- }
3799-#endif
3800- if ( ANSIColourImpl::useImplementationForStream( *stream ) ) {
3801- return Detail::make_unique<ANSIColourImpl>( stream );
3802- }
3803- return Detail::make_unique<NoColourImpl>( stream );
3804- }
3805-
3806- CATCH_ERROR( "Could not create colour impl for selection " << static_cast<int>(colourSelection) );
3807- }
3808-
3809- bool isColourImplAvailable( ColourMode colourSelection ) {
3810- switch ( colourSelection ) {
3811-#if defined( CATCH_CONFIG_COLOUR_WIN32 )
3812- case ColourMode::Win32:
3813-#endif
3814- case ColourMode::ANSI:
3815- case ColourMode::None:
3816- case ColourMode::PlatformDefault:
3817- return true;
3818- default:
3819- return false;
3820- }
3821- }
3822-
3823-
3824-} // end namespace Catch
3825-
3826-#if defined(__clang__)
3827-# pragma clang diagnostic pop
3828-#endif
3829-
3830-
3831-
3832-
3833-namespace Catch {
3834-
3835- Context Context::currentContext;
3836-
3837- Context& getCurrentMutableContext() {
3838- return Context::currentContext;
3839- }
3840-
3841- SimplePcg32& sharedRng() {
3842- static SimplePcg32 s_rng;
3843- return s_rng;
3844- }
3845-
3846-}
3847-
3848-
3849-
3850-
3851-
3852-#include <ostream>
3853-
3854-#if defined(CATCH_CONFIG_ANDROID_LOGWRITE)
3855-#include <android/log.h>
3856-
3857- namespace Catch {
3858- void writeToDebugConsole( std::string const& text ) {
3859- __android_log_write( ANDROID_LOG_DEBUG, "Catch", text.c_str() );
3860- }
3861- }
3862-
3863-#elif defined(CATCH_PLATFORM_WINDOWS)
3864-
3865- namespace Catch {
3866- void writeToDebugConsole( std::string const& text ) {
3867- ::OutputDebugStringA( text.c_str() );
3868- }
3869- }
3870-
3871-#else
3872-
3873- namespace Catch {
3874- void writeToDebugConsole( std::string const& text ) {
3875- // !TBD: Need a version for Mac/ XCode and other IDEs
3876- Catch::cout() << text;
3877- }
3878- }
3879-
3880-#endif // Platform
3881-
3882-
3883-
3884-#if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE)
3885-
3886-# include <cassert>
3887-# include <sys/types.h>
3888-# include <unistd.h>
3889-# include <cstddef>
3890-# include <ostream>
3891-
3892-#ifdef __apple_build_version__
3893- // These headers will only compile with AppleClang (XCode)
3894- // For other compilers (Clang, GCC, ... ) we need to exclude them
3895-# include <sys/sysctl.h>
3896-#endif
3897-
3898- namespace Catch {
3899- #ifdef __apple_build_version__
3900- // The following function is taken directly from the following technical note:
3901- // https://developer.apple.com/library/archive/qa/qa1361/_index.html
3902-
3903- // Returns true if the current process is being debugged (either
3904- // running under the debugger or has a debugger attached post facto).
3905- bool isDebuggerActive(){
3906- int mib[4];
3907- struct kinfo_proc info;
3908- std::size_t size;
3909-
3910- // Initialize the flags so that, if sysctl fails for some bizarre
3911- // reason, we get a predictable result.
3912-
3913- info.kp_proc.p_flag = 0;
3914-
3915- // Initialize mib, which tells sysctl the info we want, in this case
3916- // we're looking for information about a specific process ID.
3917-
3918- mib[0] = CTL_KERN;
3919- mib[1] = KERN_PROC;
3920- mib[2] = KERN_PROC_PID;
3921- mib[3] = getpid();
3922-
3923- // Call sysctl.
3924-
3925- size = sizeof(info);
3926- if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, nullptr, 0) != 0 ) {
3927- Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n\n" << std::flush;
3928- return false;
3929- }
3930-
3931- // We're being debugged if the P_TRACED flag is set.
3932-
3933- return ( (info.kp_proc.p_flag & P_TRACED) != 0 );
3934- }
3935- #else
3936- bool isDebuggerActive() {
3937- // We need to find another way to determine this for non-appleclang compilers on macOS
3938- return false;
3939- }
3940- #endif
3941- } // namespace Catch
3942-
3943-#elif defined(CATCH_PLATFORM_LINUX) || defined(CATCH_PLATFORM_QNX)
3944- #include <fstream>
3945- #include <string>
3946-
3947- namespace Catch{
3948- // The standard POSIX way of detecting a debugger is to attempt to
3949- // ptrace() the process, but this needs to be done from a child and not
3950- // this process itself to still allow attaching to this process later
3951- // if wanted, so is rather heavy. Under Linux we have the PID of the
3952- // "debugger" (which doesn't need to be gdb, of course, it could also
3953- // be strace, for example) in /proc/$PID/status, so just get it from
3954- // there instead.
3955- bool isDebuggerActive(){
3956- // Libstdc++ has a bug, where std::ifstream sets errno to 0
3957- // This way our users can properly assert over errno values
3958- ErrnoGuard guard;
3959- std::ifstream in("/proc/self/status");
3960- for( std::string line; std::getline(in, line); ) {
3961- static const int PREFIX_LEN = 11;
3962- if( line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0 ) {
3963- // We're traced if the PID is not 0 and no other PID starts
3964- // with 0 digit, so it's enough to check for just a single
3965- // character.
3966- return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0';
3967- }
3968- }
3969-
3970- return false;
3971- }
3972- } // namespace Catch
3973-#elif defined(_MSC_VER)
3974- extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
3975- namespace Catch {
3976- bool isDebuggerActive() {
3977- return IsDebuggerPresent() != 0;
3978- }
3979- }
3980-#elif defined(__MINGW32__)
3981- extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
3982- namespace Catch {
3983- bool isDebuggerActive() {
3984- return IsDebuggerPresent() != 0;
3985- }
3986- }
3987-#else
3988- namespace Catch {
3989- bool isDebuggerActive() { return false; }
3990- }
3991-#endif // Platform
3992-
3993-
3994-
3995-
3996-namespace Catch {
3997-
3998- void ITransientExpression::streamReconstructedExpression(
3999- std::ostream& os ) const {
4000- // We can't make this function pure virtual to keep ITransientExpression
4001- // constexpr, so we write error message instead
4002- os << "Some class derived from ITransientExpression without overriding streamReconstructedExpression";
4003- }
4004-
4005- void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ) {
4006- if( lhs.size() + rhs.size() < 40 &&
4007- lhs.find('\n') == std::string::npos &&
4008- rhs.find('\n') == std::string::npos )
4009- os << lhs << ' ' << op << ' ' << rhs;
4010- else
4011- os << lhs << '\n' << op << '\n' << rhs;
4012- }
4013-}
4014-
4015-
4016-
4017-#include <stdexcept>
4018-
4019-
4020-namespace Catch {
4021-#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER)
4022- [[noreturn]]
4023- void throw_exception(std::exception const& e) {
4024- Catch::cerr() << "Catch will terminate because it needed to throw an exception.\n"
4025- << "The message was: " << e.what() << '\n';
4026- std::terminate();
4027- }
4028-#endif
4029-
4030- [[noreturn]]
4031- void throw_logic_error(std::string const& msg) {
4032- throw_exception(std::logic_error(msg));
4033- }
4034-
4035- [[noreturn]]
4036- void throw_domain_error(std::string const& msg) {
4037- throw_exception(std::domain_error(msg));
4038- }
4039-
4040- [[noreturn]]
4041- void throw_runtime_error(std::string const& msg) {
4042- throw_exception(std::runtime_error(msg));
4043- }
4044-
4045-
4046-
4047-} // namespace Catch;
4048-
4049-
4050-
4051-#include <cassert>
4052-
4053-namespace Catch {
4054-
4055- IMutableEnumValuesRegistry::~IMutableEnumValuesRegistry() = default;
4056-
4057- namespace Detail {
4058-
4059- namespace {
4060- // Extracts the actual name part of an enum instance
4061- // In other words, it returns the Blue part of Bikeshed::Colour::Blue
4062- StringRef extractInstanceName(StringRef enumInstance) {
4063- // Find last occurrence of ":"
4064- size_t name_start = enumInstance.size();
4065- while (name_start > 0 && enumInstance[name_start - 1] != ':') {
4066- --name_start;
4067- }
4068- return enumInstance.substr(name_start, enumInstance.size() - name_start);
4069- }
4070- }
4071-
4072- std::vector<StringRef> parseEnums( StringRef enums ) {
4073- auto enumValues = splitStringRef( enums, ',' );
4074- std::vector<StringRef> parsed;
4075- parsed.reserve( enumValues.size() );
4076- for( auto const& enumValue : enumValues ) {
4077- parsed.push_back(trim(extractInstanceName(enumValue)));
4078- }
4079- return parsed;
4080- }
4081-
4082- EnumInfo::~EnumInfo() = default;
4083-
4084- StringRef EnumInfo::lookup( int value ) const {
4085- for( auto const& valueToName : m_values ) {
4086- if( valueToName.first == value )
4087- return valueToName.second;
4088- }
4089- return "{** unexpected enum value **}"_sr;
4090- }
4091-
4092- Catch::Detail::unique_ptr<EnumInfo> makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ) {
4093- auto enumInfo = Catch::Detail::make_unique<EnumInfo>();
4094- enumInfo->m_name = enumName;
4095- enumInfo->m_values.reserve( values.size() );
4096-
4097- const auto valueNames = Catch::Detail::parseEnums( allValueNames );
4098- assert( valueNames.size() == values.size() );
4099- std::size_t i = 0;
4100- for( auto value : values )
4101- enumInfo->m_values.emplace_back(value, valueNames[i++]);
4102-
4103- return enumInfo;
4104- }
4105-
4106- EnumInfo const& EnumValuesRegistry::registerEnum( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ) {
4107- m_enumInfos.push_back(makeEnumInfo(enumName, allValueNames, values));
4108- return *m_enumInfos.back();
4109- }
4110-
4111- } // Detail
4112-} // Catch
4113-
4114-
4115-
4116-
4117-
4118-#include <cerrno>
4119-
4120-namespace Catch {
4121- ErrnoGuard::ErrnoGuard():m_oldErrno(errno){}
4122- ErrnoGuard::~ErrnoGuard() { errno = m_oldErrno; }
4123-}
4124-
4125-
4126-
4127-#include <exception>
4128-
4129-namespace Catch {
4130-
4131-#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
4132- namespace {
4133- static std::string tryTranslators(
4134- std::vector<
4135- Detail::unique_ptr<IExceptionTranslator const>> const& translators ) {
4136- if ( translators.empty() ) {
4137- std::rethrow_exception( std::current_exception() );
4138- } else {
4139- return translators[0]->translate( translators.begin() + 1,
4140- translators.end() );
4141- }
4142- }
4143-
4144- }
4145-#endif //!defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
4146-
4147- ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() = default;
4148-
4149- void ExceptionTranslatorRegistry::registerTranslator( Detail::unique_ptr<IExceptionTranslator>&& translator ) {
4150- m_translators.push_back( CATCH_MOVE( translator ) );
4151- }
4152-
4153-#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
4154- std::string ExceptionTranslatorRegistry::translateActiveException() const {
4155- // Compiling a mixed mode project with MSVC means that CLR
4156- // exceptions will be caught in (...) as well. However, these do
4157- // do not fill-in std::current_exception and thus lead to crash
4158- // when attempting rethrow.
4159- // /EHa switch also causes structured exceptions to be caught
4160- // here, but they fill-in current_exception properly, so
4161- // at worst the output should be a little weird, instead of
4162- // causing a crash.
4163- if ( std::current_exception() == nullptr ) {
4164- return "Non C++ exception. Possibly a CLR exception.";
4165- }
4166-
4167- // First we try user-registered translators. If none of them can
4168- // handle the exception, it will be rethrown handled by our defaults.
4169- try {
4170- return tryTranslators(m_translators);
4171- }
4172- // To avoid having to handle TFE explicitly everywhere, we just
4173- // rethrow it so that it goes back up the caller.
4174- catch( TestFailureException& ) {
4175- return "{ nested assertion failed }";
4176- }
4177- catch( TestSkipException& ) {
4178- return "{ nested SKIP() called }";
4179- }
4180- catch( std::exception const& ex ) {
4181- return ex.what();
4182- }
4183- catch( std::string const& msg ) {
4184- return msg;
4185- }
4186- catch( const char* msg ) {
4187- return msg;
4188- }
4189- catch(...) {
4190- return "Unknown exception";
4191- }
4192- }
4193-
4194-#else // ^^ Exceptions are enabled // Exceptions are disabled vv
4195- std::string ExceptionTranslatorRegistry::translateActiveException() const {
4196- CATCH_INTERNAL_ERROR("Attempted to translate active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
4197- }
4198-#endif
4199-
4200-}
4201-
4202-
4203-
4204-/** \file
4205- * This file provides platform specific implementations of FatalConditionHandler
4206- *
4207- * This means that there is a lot of conditional compilation, and platform
4208- * specific code. Currently, Catch2 supports a dummy handler (if no
4209- * handler is desired), and 2 platform specific handlers:
4210- * * Windows' SEH
4211- * * POSIX signals
4212- *
4213- * Consequently, various pieces of code below are compiled if either of
4214- * the platform specific handlers is enabled, or if none of them are
4215- * enabled. It is assumed that both cannot be enabled at the same time,
4216- * and doing so should cause a compilation error.
4217- *
4218- * If another platform specific handler is added, the compile guards
4219- * below will need to be updated taking these assumptions into account.
4220- */
4221-
4222-
4223-
4224-#include <algorithm>
4225-
4226-#if !defined( CATCH_CONFIG_WINDOWS_SEH ) && !defined( CATCH_CONFIG_POSIX_SIGNALS )
4227-
4228-namespace Catch {
4229-
4230- // If neither SEH nor signal handling is required, the handler impls
4231- // do not have to do anything, and can be empty.
4232- void FatalConditionHandler::engage_platform() {}
4233- void FatalConditionHandler::disengage_platform() noexcept {}
4234- FatalConditionHandler::FatalConditionHandler() = default;
4235- FatalConditionHandler::~FatalConditionHandler() = default;
4236-
4237-} // end namespace Catch
4238-
4239-#endif // !CATCH_CONFIG_WINDOWS_SEH && !CATCH_CONFIG_POSIX_SIGNALS
4240-
4241-#if defined( CATCH_CONFIG_WINDOWS_SEH ) && defined( CATCH_CONFIG_POSIX_SIGNALS )
4242-#error "Inconsistent configuration: Windows' SEH handling and POSIX signals cannot be enabled at the same time"
4243-#endif // CATCH_CONFIG_WINDOWS_SEH && CATCH_CONFIG_POSIX_SIGNALS
4244-
4245-#if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS )
4246-
4247-namespace {
4248- //! Signals fatal error message to the run context
4249- void reportFatal( char const * const message ) {
4250- Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message );
4251- }
4252-
4253- //! Minimal size Catch2 needs for its own fatal error handling.
4254- //! Picked empirically, so it might not be sufficient on all
4255- //! platforms, and for all configurations.
4256- constexpr std::size_t minStackSizeForErrors = 32 * 1024;
4257-} // end unnamed namespace
4258-
4259-#endif // CATCH_CONFIG_WINDOWS_SEH || CATCH_CONFIG_POSIX_SIGNALS
4260-
4261-#if defined( CATCH_CONFIG_WINDOWS_SEH )
4262-
4263-namespace Catch {
4264-
4265- struct SignalDefs { DWORD id; const char* name; };
4266-
4267- // There is no 1-1 mapping between signals and windows exceptions.
4268- // Windows can easily distinguish between SO and SigSegV,
4269- // but SigInt, SigTerm, etc are handled differently.
4270- static constexpr SignalDefs signalDefs[] = {
4271- { EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal" },
4272- { EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" },
4273- { EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" },
4274- { EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" },
4275- };
4276-
4277- // Since we do not support multiple instantiations, we put these
4278- // into global variables and rely on cleaning them up in outlined
4279- // constructors/destructors
4280- static LPTOP_LEVEL_EXCEPTION_FILTER previousTopLevelExceptionFilter = nullptr;
4281-
4282-
4283- static LONG CALLBACK topLevelExceptionFilter(PEXCEPTION_POINTERS ExceptionInfo) {
4284- for (auto const& def : signalDefs) {
4285- if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) {
4286- reportFatal(def.name);
4287- }
4288- }
4289- // If a filter was previously registered, invoke it
4290- if (previousTopLevelExceptionFilter) {
4291- return previousTopLevelExceptionFilter(ExceptionInfo);
4292- }
4293- // Otherwise, pass along all exceptions.
4294- // This stops us from eating debugger breaks etc.
4295- return EXCEPTION_CONTINUE_SEARCH;
4296- }
4297-
4298- // For MSVC, we reserve part of the stack memory for handling
4299- // memory overflow structured exception.
4300- FatalConditionHandler::FatalConditionHandler() {
4301- ULONG guaranteeSize = static_cast<ULONG>(minStackSizeForErrors);
4302- if (!SetThreadStackGuarantee(&guaranteeSize)) {
4303- // We do not want to fully error out, because needing
4304- // the stack reserve should be rare enough anyway.
4305- Catch::cerr()
4306- << "Failed to reserve piece of stack."
4307- << " Stack overflows will not be reported successfully.";
4308- }
4309- }
4310-
4311- // We do not attempt to unset the stack guarantee, because
4312- // Windows does not support lowering the stack size guarantee.
4313- FatalConditionHandler::~FatalConditionHandler() = default;
4314-
4315-
4316- void FatalConditionHandler::engage_platform() {
4317- // Register as a the top level exception filter.
4318- previousTopLevelExceptionFilter = SetUnhandledExceptionFilter(topLevelExceptionFilter);
4319- }
4320-
4321- void FatalConditionHandler::disengage_platform() noexcept {
4322- if (SetUnhandledExceptionFilter(previousTopLevelExceptionFilter) != topLevelExceptionFilter) {
4323- Catch::cerr()
4324- << "Unexpected SEH unhandled exception filter on disengage."
4325- << " The filter was restored, but might be rolled back unexpectedly.";
4326- }
4327- previousTopLevelExceptionFilter = nullptr;
4328- }
4329-
4330-} // end namespace Catch
4331-
4332-#endif // CATCH_CONFIG_WINDOWS_SEH
4333-
4334-#if defined( CATCH_CONFIG_POSIX_SIGNALS )
4335-
4336-#include <signal.h>
4337-
4338-namespace Catch {
4339-
4340- struct SignalDefs {
4341- int id;
4342- const char* name;
4343- };
4344-
4345- static constexpr SignalDefs signalDefs[] = {
4346- { SIGINT, "SIGINT - Terminal interrupt signal" },
4347- { SIGILL, "SIGILL - Illegal instruction signal" },
4348- { SIGFPE, "SIGFPE - Floating point error signal" },
4349- { SIGSEGV, "SIGSEGV - Segmentation violation signal" },
4350- { SIGTERM, "SIGTERM - Termination request signal" },
4351- { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" }
4352- };
4353-
4354-// Older GCCs trigger -Wmissing-field-initializers for T foo = {}
4355-// which is zero initialization, but not explicit. We want to avoid
4356-// that.
4357-#if defined(__GNUC__)
4358-# pragma GCC diagnostic push
4359-# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
4360-#endif
4361-
4362- static char* altStackMem = nullptr;
4363- static std::size_t altStackSize = 0;
4364- static stack_t oldSigStack{};
4365- static struct sigaction oldSigActions[sizeof(signalDefs) / sizeof(SignalDefs)]{};
4366-
4367- static void restorePreviousSignalHandlers() noexcept {
4368- // We set signal handlers back to the previous ones. Hopefully
4369- // nobody overwrote them in the meantime, and doesn't expect
4370- // their signal handlers to live past ours given that they
4371- // installed them after ours..
4372- for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) {
4373- sigaction(signalDefs[i].id, &oldSigActions[i], nullptr);
4374- }
4375- // Return the old stack
4376- sigaltstack(&oldSigStack, nullptr);
4377- }
4378-
4379- static void handleSignal( int sig ) {
4380- char const * name = "<unknown signal>";
4381- for (auto const& def : signalDefs) {
4382- if (sig == def.id) {
4383- name = def.name;
4384- break;
4385- }
4386- }
4387- // We need to restore previous signal handlers and let them do
4388- // their thing, so that the users can have the debugger break
4389- // when a signal is raised, and so on.
4390- restorePreviousSignalHandlers();
4391- reportFatal( name );
4392- raise( sig );
4393- }
4394-
4395- FatalConditionHandler::FatalConditionHandler() {
4396- assert(!altStackMem && "Cannot initialize POSIX signal handler when one already exists");
4397- if (altStackSize == 0) {
4398- altStackSize = std::max(static_cast<size_t>(SIGSTKSZ), minStackSizeForErrors);
4399- }
4400- altStackMem = new char[altStackSize]();
4401- }
4402-
4403- FatalConditionHandler::~FatalConditionHandler() {
4404- delete[] altStackMem;
4405- // We signal that another instance can be constructed by zeroing
4406- // out the pointer.
4407- altStackMem = nullptr;
4408- }
4409-
4410- void FatalConditionHandler::engage_platform() {
4411- stack_t sigStack;
4412- sigStack.ss_sp = altStackMem;
4413- sigStack.ss_size = altStackSize;
4414- sigStack.ss_flags = 0;
4415- sigaltstack(&sigStack, &oldSigStack);
4416- struct sigaction sa = { };
4417-
4418- sa.sa_handler = handleSignal;
4419- sa.sa_flags = SA_ONSTACK;
4420- for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) {
4421- sigaction(signalDefs[i].id, &sa, &oldSigActions[i]);
4422- }
4423- }
4424-
4425-#if defined(__GNUC__)
4426-# pragma GCC diagnostic pop
4427-#endif
4428-
4429-
4430- void FatalConditionHandler::disengage_platform() noexcept {
4431- restorePreviousSignalHandlers();
4432- }
4433-
4434-} // end namespace Catch
4435-
4436-#endif // CATCH_CONFIG_POSIX_SIGNALS
4437-
4438-
4439-
4440-
4441-#include <cstring>
4442-
4443-namespace Catch {
4444- namespace Detail {
4445-
4446- uint32_t convertToBits(float f) {
4447- static_assert(sizeof(float) == sizeof(uint32_t), "Important ULP matcher assumption violated");
4448- uint32_t i;
4449- std::memcpy(&i, &f, sizeof(f));
4450- return i;
4451- }
4452-
4453- uint64_t convertToBits(double d) {
4454- static_assert(sizeof(double) == sizeof(uint64_t), "Important ULP matcher assumption violated");
4455- uint64_t i;
4456- std::memcpy(&i, &d, sizeof(d));
4457- return i;
4458- }
4459-
4460-#if defined( __GNUC__ ) || defined( __clang__ )
4461-# pragma GCC diagnostic push
4462-# pragma GCC diagnostic ignored "-Wfloat-equal"
4463-#endif
4464- bool directCompare( float lhs, float rhs ) { return lhs == rhs; }
4465- bool directCompare( double lhs, double rhs ) { return lhs == rhs; }
4466-#if defined( __GNUC__ ) || defined( __clang__ )
4467-# pragma GCC diagnostic pop
4468-#endif
4469-
4470-
4471- } // end namespace Detail
4472-} // end namespace Catch
4473-
4474-
4475-
4476-
4477-
4478-
4479-#include <cstdlib>
4480-
4481-namespace Catch {
4482- namespace Detail {
4483-
4484-#if !defined (CATCH_CONFIG_GETENV)
4485- char const* getEnv( char const* ) { return nullptr; }
4486-#else
4487-
4488- char const* getEnv( char const* varName ) {
4489-# if defined( _MSC_VER )
4490-# pragma warning( push )
4491-# pragma warning( disable : 4996 ) // use getenv_s instead of getenv
4492-# endif
4493-
4494- return std::getenv( varName );
4495-
4496-# if defined( _MSC_VER )
4497-# pragma warning( pop )
4498-# endif
4499- }
4500-#endif
4501-} // namespace Detail
4502-} // namespace Catch
4503-
4504-
4505-
4506-
4507-#include <cstdio>
4508-#include <fstream>
4509-
4510-namespace Catch {
4511-
4512- Catch::IStream::~IStream() = default;
4513-
4514-namespace Detail {
4515- namespace {
4516- template<typename WriterF, std::size_t bufferSize=256>
4517- class StreamBufImpl final : public std::streambuf {
4518- char data[bufferSize];
4519- WriterF m_writer;
4520-
4521- public:
4522- StreamBufImpl() {
4523- setp( data, data + sizeof(data) );
4524- }
4525-
4526- ~StreamBufImpl() noexcept override {
4527- StreamBufImpl::sync();
4528- }
4529-
4530- private:
4531- int overflow( int c ) override {
4532- sync();
4533-
4534- if( c != EOF ) {
4535- if( pbase() == epptr() )
4536- m_writer( std::string( 1, static_cast<char>( c ) ) );
4537- else
4538- sputc( static_cast<char>( c ) );
4539- }
4540- return 0;
4541- }
4542-
4543- int sync() override {
4544- if( pbase() != pptr() ) {
4545- m_writer( std::string( pbase(), static_cast<std::string::size_type>( pptr() - pbase() ) ) );
4546- setp( pbase(), epptr() );
4547- }
4548- return 0;
4549- }
4550- };
4551-
4552- ///////////////////////////////////////////////////////////////////////////
4553-
4554- struct OutputDebugWriter {
4555-
4556- void operator()( std::string const& str ) {
4557- if ( !str.empty() ) {
4558- writeToDebugConsole( str );
4559- }
4560- }
4561- };
4562-
4563- ///////////////////////////////////////////////////////////////////////////
4564-
4565- class FileStream final : public IStream {
4566- std::ofstream m_ofs;
4567- public:
4568- FileStream( std::string const& filename ) {
4569- m_ofs.open( filename.c_str() );
4570- CATCH_ENFORCE( !m_ofs.fail(), "Unable to open file: '" << filename << '\'' );
4571- m_ofs << std::unitbuf;
4572- }
4573- public: // IStream
4574- std::ostream& stream() override {
4575- return m_ofs;
4576- }
4577- };
4578-
4579- ///////////////////////////////////////////////////////////////////////////
4580-
4581- class CoutStream final : public IStream {
4582- std::ostream m_os;
4583- public:
4584- // Store the streambuf from cout up-front because
4585- // cout may get redirected when running tests
4586- CoutStream() : m_os( Catch::cout().rdbuf() ) {}
4587-
4588- public: // IStream
4589- std::ostream& stream() override { return m_os; }
4590- bool isConsole() const override { return true; }
4591- };
4592-
4593- class CerrStream : public IStream {
4594- std::ostream m_os;
4595-
4596- public:
4597- // Store the streambuf from cerr up-front because
4598- // cout may get redirected when running tests
4599- CerrStream(): m_os( Catch::cerr().rdbuf() ) {}
4600-
4601- public: // IStream
4602- std::ostream& stream() override { return m_os; }
4603- bool isConsole() const override { return true; }
4604- };
4605-
4606- ///////////////////////////////////////////////////////////////////////////
4607-
4608- class DebugOutStream final : public IStream {
4609- Detail::unique_ptr<StreamBufImpl<OutputDebugWriter>> m_streamBuf;
4610- std::ostream m_os;
4611- public:
4612- DebugOutStream()
4613- : m_streamBuf( Detail::make_unique<StreamBufImpl<OutputDebugWriter>>() ),
4614- m_os( m_streamBuf.get() )
4615- {}
4616-
4617- public: // IStream
4618- std::ostream& stream() override { return m_os; }
4619- };
4620-
4621- } // unnamed namespace
4622-} // namespace Detail
4623-
4624- ///////////////////////////////////////////////////////////////////////////
4625-
4626- auto makeStream( std::string const& filename ) -> Detail::unique_ptr<IStream> {
4627- if ( filename.empty() || filename == "-" ) {
4628- return Detail::make_unique<Detail::CoutStream>();
4629- }
4630- if( filename[0] == '%' ) {
4631- if ( filename == "%debug" ) {
4632- return Detail::make_unique<Detail::DebugOutStream>();
4633- } else if ( filename == "%stderr" ) {
4634- return Detail::make_unique<Detail::CerrStream>();
4635- } else if ( filename == "%stdout" ) {
4636- return Detail::make_unique<Detail::CoutStream>();
4637- } else {
4638- CATCH_ERROR( "Unrecognised stream: '" << filename << '\'' );
4639- }
4640- }
4641- return Detail::make_unique<Detail::FileStream>( filename );
4642- }
4643-
4644-}
4645-
4646-
4647-
4648-namespace Catch {
4649-
4650- namespace {
4651- static bool needsEscape( char c ) {
4652- return c == '"' || c == '\\' || c == '\b' || c == '\f' ||
4653- c == '\n' || c == '\r' || c == '\t';
4654- }
4655-
4656- static Catch::StringRef makeEscapeStringRef( char c ) {
4657- if ( c == '"' ) {
4658- return "\\\""_sr;
4659- } else if ( c == '\\' ) {
4660- return "\\\\"_sr;
4661- } else if ( c == '\b' ) {
4662- return "\\b"_sr;
4663- } else if ( c == '\f' ) {
4664- return "\\f"_sr;
4665- } else if ( c == '\n' ) {
4666- return "\\n"_sr;
4667- } else if ( c == '\r' ) {
4668- return "\\r"_sr;
4669- } else if ( c == '\t' ) {
4670- return "\\t"_sr;
4671- }
4672- Catch::Detail::Unreachable();
4673- }
4674- } // namespace
4675-
4676- void JsonUtils::indent( std::ostream& os, std::uint64_t level ) {
4677- for ( std::uint64_t i = 0; i < level; ++i ) {
4678- os << " ";
4679- }
4680- }
4681- void JsonUtils::appendCommaNewline( std::ostream& os,
4682- bool& should_comma,
4683- std::uint64_t level ) {
4684- if ( should_comma ) { os << ','; }
4685- should_comma = true;
4686- os << '\n';
4687- indent( os, level );
4688- }
4689-
4690- JsonObjectWriter::JsonObjectWriter( std::ostream& os ):
4691- JsonObjectWriter{ os, 0 } {}
4692-
4693- JsonObjectWriter::JsonObjectWriter( std::ostream& os,
4694- std::uint64_t indent_level ):
4695- m_os{ os }, m_indent_level{ indent_level } {
4696- m_os << '{';
4697- }
4698- JsonObjectWriter::JsonObjectWriter( JsonObjectWriter&& source ) noexcept:
4699- m_os{ source.m_os },
4700- m_indent_level{ source.m_indent_level },
4701- m_should_comma{ source.m_should_comma },
4702- m_active{ source.m_active } {
4703- source.m_active = false;
4704- }
4705-
4706- JsonObjectWriter::~JsonObjectWriter() {
4707- if ( !m_active ) { return; }
4708-
4709- m_os << '\n';
4710- JsonUtils::indent( m_os, m_indent_level );
4711- m_os << '}';
4712- }
4713-
4714- JsonValueWriter JsonObjectWriter::write( StringRef key ) {
4715- JsonUtils::appendCommaNewline(
4716- m_os, m_should_comma, m_indent_level + 1 );
4717-
4718- m_os << '"' << key << "\": ";
4719- return JsonValueWriter{ m_os, m_indent_level + 1 };
4720- }
4721-
4722- JsonArrayWriter::JsonArrayWriter( std::ostream& os ):
4723- JsonArrayWriter{ os, 0 } {}
4724- JsonArrayWriter::JsonArrayWriter( std::ostream& os,
4725- std::uint64_t indent_level ):
4726- m_os{ os }, m_indent_level{ indent_level } {
4727- m_os << '[';
4728- }
4729- JsonArrayWriter::JsonArrayWriter( JsonArrayWriter&& source ) noexcept:
4730- m_os{ source.m_os },
4731- m_indent_level{ source.m_indent_level },
4732- m_should_comma{ source.m_should_comma },
4733- m_active{ source.m_active } {
4734- source.m_active = false;
4735- }
4736- JsonArrayWriter::~JsonArrayWriter() {
4737- if ( !m_active ) { return; }
4738-
4739- m_os << '\n';
4740- JsonUtils::indent( m_os, m_indent_level );
4741- m_os << ']';
4742- }
4743-
4744- JsonObjectWriter JsonArrayWriter::writeObject() {
4745- JsonUtils::appendCommaNewline(
4746- m_os, m_should_comma, m_indent_level + 1 );
4747- return JsonObjectWriter{ m_os, m_indent_level + 1 };
4748- }
4749-
4750- JsonArrayWriter JsonArrayWriter::writeArray() {
4751- JsonUtils::appendCommaNewline(
4752- m_os, m_should_comma, m_indent_level + 1 );
4753- return JsonArrayWriter{ m_os, m_indent_level + 1 };
4754- }
4755-
4756- JsonArrayWriter& JsonArrayWriter::write( bool value ) {
4757- return writeImpl( value );
4758- }
4759-
4760- JsonValueWriter::JsonValueWriter( std::ostream& os ):
4761- JsonValueWriter{ os, 0 } {}
4762-
4763- JsonValueWriter::JsonValueWriter( std::ostream& os,
4764- std::uint64_t indent_level ):
4765- m_os{ os }, m_indent_level{ indent_level } {}
4766-
4767- JsonObjectWriter JsonValueWriter::writeObject() && {
4768- return JsonObjectWriter{ m_os, m_indent_level };
4769- }
4770-
4771- JsonArrayWriter JsonValueWriter::writeArray() && {
4772- return JsonArrayWriter{ m_os, m_indent_level };
4773- }
4774-
4775- void JsonValueWriter::write( Catch::StringRef value ) && {
4776- writeImpl( value, true );
4777- }
4778-
4779- void JsonValueWriter::write( bool value ) && {
4780- writeImpl( value ? "true"_sr : "false"_sr, false );
4781- }
4782-
4783- void JsonValueWriter::writeImpl( Catch::StringRef value, bool quote ) {
4784- if ( quote ) { m_os << '"'; }
4785- size_t current_start = 0;
4786- for ( size_t i = 0; i < value.size(); ++i ) {
4787- if ( needsEscape( value[i] ) ) {
4788- if ( current_start < i ) {
4789- m_os << value.substr( current_start, i - current_start );
4790- }
4791- m_os << makeEscapeStringRef( value[i] );
4792- current_start = i + 1;
4793- }
4794- }
4795- if ( current_start < value.size() ) {
4796- m_os << value.substr( current_start, value.size() - current_start );
4797- }
4798- if ( quote ) { m_os << '"'; }
4799- }
4800-
4801-} // namespace Catch
4802-
4803-
4804-
4805-
4806-namespace Catch {
4807-
4808- auto operator << (std::ostream& os, LazyExpression const& lazyExpr) -> std::ostream& {
4809- if (lazyExpr.m_isNegated)
4810- os << '!';
4811-
4812- if (lazyExpr) {
4813- if (lazyExpr.m_isNegated && lazyExpr.m_transientExpression->isBinaryExpression())
4814- os << '(' << *lazyExpr.m_transientExpression << ')';
4815- else
4816- os << *lazyExpr.m_transientExpression;
4817- } else {
4818- os << "{** error - unchecked empty expression requested **}";
4819- }
4820- return os;
4821- }
4822-
4823-} // namespace Catch
4824-
4825-
4826-
4827-
4828-#ifdef CATCH_CONFIG_WINDOWS_CRTDBG
4829-#include <crtdbg.h>
4830-
4831-namespace Catch {
4832-
4833- LeakDetector::LeakDetector() {
4834- int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
4835- flag |= _CRTDBG_LEAK_CHECK_DF;
4836- flag |= _CRTDBG_ALLOC_MEM_DF;
4837- _CrtSetDbgFlag(flag);
4838- _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
4839- _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
4840- // Change this to leaking allocation's number to break there
4841- _CrtSetBreakAlloc(-1);
4842- }
4843-}
4844-
4845-#else // ^^ Windows crt debug heap enabled // Windows crt debug heap disabled vv
4846-
4847- Catch::LeakDetector::LeakDetector() = default;
4848-
4849-#endif // CATCH_CONFIG_WINDOWS_CRTDBG
4850-
4851-Catch::LeakDetector::~LeakDetector() {
4852- Catch::cleanUp();
4853-}
4854-
4855-
4856-
4857-
4858-namespace Catch {
4859- namespace {
4860-
4861- void listTests(IEventListener& reporter, IConfig const& config) {
4862- auto const& testSpec = config.testSpec();
4863- auto matchedTestCases = filterTests(getAllTestCasesSorted(config), testSpec, config);
4864- reporter.listTests(matchedTestCases);
4865- }
4866-
4867- void listTags(IEventListener& reporter, IConfig const& config) {
4868- auto const& testSpec = config.testSpec();
4869- std::vector<TestCaseHandle> matchedTestCases = filterTests(getAllTestCasesSorted(config), testSpec, config);
4870-
4871- std::map<StringRef, TagInfo, Detail::CaseInsensitiveLess> tagCounts;
4872- for (auto const& testCase : matchedTestCases) {
4873- for (auto const& tagName : testCase.getTestCaseInfo().tags) {
4874- auto it = tagCounts.find(tagName.original);
4875- if (it == tagCounts.end())
4876- it = tagCounts.insert(std::make_pair(tagName.original, TagInfo())).first;
4877- it->second.add(tagName.original);
4878- }
4879- }
4880-
4881- std::vector<TagInfo> infos; infos.reserve(tagCounts.size());
4882- for (auto& tagc : tagCounts) {
4883- infos.push_back(CATCH_MOVE(tagc.second));
4884- }
4885-
4886- reporter.listTags(infos);
4887- }
4888-
4889- void listReporters(IEventListener& reporter) {
4890- std::vector<ReporterDescription> descriptions;
4891-
4892- auto const& factories = getRegistryHub().getReporterRegistry().getFactories();
4893- descriptions.reserve(factories.size());
4894- for (auto const& fac : factories) {
4895- descriptions.push_back({ fac.first, fac.second->getDescription() });
4896- }
4897-
4898- reporter.listReporters(descriptions);
4899- }
4900-
4901- void listListeners(IEventListener& reporter) {
4902- std::vector<ListenerDescription> descriptions;
4903-
4904- auto const& factories =
4905- getRegistryHub().getReporterRegistry().getListeners();
4906- descriptions.reserve( factories.size() );
4907- for ( auto const& fac : factories ) {
4908- descriptions.push_back( { fac->getName(), fac->getDescription() } );
4909- }
4910-
4911- reporter.listListeners( descriptions );
4912- }
4913-
4914- } // end anonymous namespace
4915-
4916- void TagInfo::add( StringRef spelling ) {
4917- ++count;
4918- spellings.insert( spelling );
4919- }
4920-
4921- std::string TagInfo::all() const {
4922- // 2 per tag for brackets '[' and ']'
4923- size_t size = spellings.size() * 2;
4924- for (auto const& spelling : spellings) {
4925- size += spelling.size();
4926- }
4927-
4928- std::string out; out.reserve(size);
4929- for (auto const& spelling : spellings) {
4930- out += '[';
4931- out += spelling;
4932- out += ']';
4933- }
4934- return out;
4935- }
4936-
4937- bool list( IEventListener& reporter, Config const& config ) {
4938- bool listed = false;
4939- if (config.listTests()) {
4940- listed = true;
4941- listTests(reporter, config);
4942- }
4943- if (config.listTags()) {
4944- listed = true;
4945- listTags(reporter, config);
4946- }
4947- if (config.listReporters()) {
4948- listed = true;
4949- listReporters(reporter);
4950- }
4951- if ( config.listListeners() ) {
4952- listed = true;
4953- listListeners( reporter );
4954- }
4955- return listed;
4956- }
4957-
4958-} // end namespace Catch
4959-
4960-
4961-
4962-namespace Catch {
4963- CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
4964- CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
4965- static const LeakDetector leakDetector;
4966- CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
4967-}
4968-
4969-// Allow users of amalgamated .cpp file to remove our main and provide their own.
4970-#if !defined(CATCH_AMALGAMATED_CUSTOM_MAIN)
4971-
4972-#if defined(CATCH_CONFIG_WCHAR) && defined(CATCH_PLATFORM_WINDOWS) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN)
4973-// Standard C/C++ Win32 Unicode wmain entry point
4974-extern "C" int __cdecl wmain (int argc, wchar_t * argv[], wchar_t * []) {
4975-#else
4976-// Standard C/C++ main entry point
4977-int main (int argc, char * argv[]) {
4978-#endif
4979-
4980- // We want to force the linker not to discard the global variable
4981- // and its constructor, as it (optionally) registers leak detector
4982- (void)&Catch::leakDetector;
4983-
4984- return Catch::Session().run( argc, argv );
4985-}
4986-
4987-#endif // !defined(CATCH_AMALGAMATED_CUSTOM_MAIN
4988-
4989-
4990-
4991-
4992-namespace Catch {
4993-
4994- MessageInfo::MessageInfo( StringRef _macroName,
4995- SourceLineInfo const& _lineInfo,
4996- ResultWas::OfType _type )
4997- : macroName( _macroName ),
4998- lineInfo( _lineInfo ),
4999- type( _type ),
5000- sequence( ++globalCount )
5001- {}
5002-
5003- // Messages are owned by their individual threads, so the counter should be thread-local as well.
5004- // Alternative consideration: atomic, so threads don't share IDs and things are easier to debug.
5005- thread_local unsigned int MessageInfo::globalCount = 0;
5006-
5007-} // end namespace Catch
5008-
5009-
5010-
5011-#include <cstdio>
5012-#include <cstring>
5013-#include <iosfwd>
5014-#include <sstream>
5015-
5016-#if defined( CATCH_CONFIG_NEW_CAPTURE )
5017-# if defined( _MSC_VER )
5018-# include <io.h> //_dup and _dup2
5019-# define dup _dup
5020-# define dup2 _dup2
5021-# define fileno _fileno
5022-# else
5023-# include <unistd.h> // dup and dup2
5024-# endif
5025-#endif
5026-
5027-namespace Catch {
5028-
5029- namespace {
5030- //! A no-op implementation, used if no reporter wants output
5031- //! redirection.
5032- class NoopRedirect : public OutputRedirect {
5033- void activateImpl() override {}
5034- void deactivateImpl() override {}
5035- std::string getStdout() override { return {}; }
5036- std::string getStderr() override { return {}; }
5037- void clearBuffers() override {}
5038- };
5039-
5040- /**
5041- * Redirects specific stream's rdbuf with another's.
5042- *
5043- * Redirection can be stopped and started on-demand, assumes
5044- * that the underlying stream's rdbuf aren't changed by other
5045- * users.
5046- */
5047- class RedirectedStreamNew {
5048- std::ostream& m_originalStream;
5049- std::ostream& m_redirectionStream;
5050- std::streambuf* m_prevBuf;
5051-
5052- public:
5053- RedirectedStreamNew( std::ostream& originalStream,
5054- std::ostream& redirectionStream ):
5055- m_originalStream( originalStream ),
5056- m_redirectionStream( redirectionStream ),
5057- m_prevBuf( m_originalStream.rdbuf() ) {}
5058-
5059- void startRedirect() {
5060- m_originalStream.rdbuf( m_redirectionStream.rdbuf() );
5061- }
5062- void stopRedirect() { m_originalStream.rdbuf( m_prevBuf ); }
5063- };
5064-
5065- /**
5066- * Redirects the `std::cout`, `std::cerr`, `std::clog` streams,
5067- * but does not touch the actual `stdout`/`stderr` file descriptors.
5068- */
5069- class StreamRedirect : public OutputRedirect {
5070- ReusableStringStream m_redirectedOut, m_redirectedErr;
5071- RedirectedStreamNew m_cout, m_cerr, m_clog;
5072-
5073- public:
5074- StreamRedirect():
5075- m_cout( Catch::cout(), m_redirectedOut.get() ),
5076- m_cerr( Catch::cerr(), m_redirectedErr.get() ),
5077- m_clog( Catch::clog(), m_redirectedErr.get() ) {}
5078-
5079- void activateImpl() override {
5080- m_cout.startRedirect();
5081- m_cerr.startRedirect();
5082- m_clog.startRedirect();
5083- }
5084- void deactivateImpl() override {
5085- m_cout.stopRedirect();
5086- m_cerr.stopRedirect();
5087- m_clog.stopRedirect();
5088- }
5089- std::string getStdout() override { return m_redirectedOut.str(); }
5090- std::string getStderr() override { return m_redirectedErr.str(); }
5091- void clearBuffers() override {
5092- m_redirectedOut.str( "" );
5093- m_redirectedErr.str( "" );
5094- }
5095- };
5096-
5097-#if defined( CATCH_CONFIG_NEW_CAPTURE )
5098-
5099- // Windows's implementation of std::tmpfile is terrible (it tries
5100- // to create a file inside system folder, thus requiring elevated
5101- // privileges for the binary), so we have to use tmpnam(_s) and
5102- // create the file ourselves there.
5103- class TempFile {
5104- public:
5105- TempFile( TempFile const& ) = delete;
5106- TempFile& operator=( TempFile const& ) = delete;
5107- TempFile( TempFile&& ) = delete;
5108- TempFile& operator=( TempFile&& ) = delete;
5109-
5110-# if defined( _MSC_VER )
5111- TempFile() {
5112- if ( tmpnam_s( m_buffer ) ) {
5113- CATCH_RUNTIME_ERROR( "Could not get a temp filename" );
5114- }
5115- if ( fopen_s( &m_file, m_buffer, "wb+" ) ) {
5116- char buffer[100];
5117- if ( strerror_s( buffer, errno ) ) {
5118- CATCH_RUNTIME_ERROR(
5119- "Could not translate errno to a string" );
5120- }
5121- CATCH_RUNTIME_ERROR( "Could not open the temp file: '"
5122- << m_buffer
5123- << "' because: " << buffer );
5124- }
5125- }
5126-# else
5127- TempFile() {
5128- m_file = std::tmpfile();
5129- if ( !m_file ) {
5130- CATCH_RUNTIME_ERROR( "Could not create a temp file." );
5131- }
5132- }
5133-# endif
5134-
5135- ~TempFile() {
5136- // TBD: What to do about errors here?
5137- std::fclose( m_file );
5138- // We manually create the file on Windows only, on Linux
5139- // it will be autodeleted
5140-# if defined( _MSC_VER )
5141- std::remove( m_buffer );
5142-# endif
5143- }
5144-
5145- std::FILE* getFile() { return m_file; }
5146- std::string getContents() {
5147- ReusableStringStream sstr;
5148- constexpr long buffer_size = 100;
5149- char buffer[buffer_size + 1] = {};
5150- long current_pos = ftell( m_file );
5151- CATCH_ENFORCE( current_pos >= 0,
5152- "ftell failed, errno: " << errno );
5153- std::rewind( m_file );
5154- while ( current_pos > 0 ) {
5155- auto read_characters =
5156- std::fread( buffer,
5157- 1,
5158- std::min( buffer_size, current_pos ),
5159- m_file );
5160- buffer[read_characters] = '\0';
5161- sstr << buffer;
5162- current_pos -= static_cast<long>( read_characters );
5163- }
5164- return sstr.str();
5165- }
5166-
5167- void clear() { std::rewind( m_file ); }
5168-
5169- private:
5170- std::FILE* m_file = nullptr;
5171- char m_buffer[L_tmpnam] = { 0 };
5172- };
5173-
5174- /**
5175- * Redirects the actual `stdout`/`stderr` file descriptors.
5176- *
5177- * Works by replacing the file descriptors numbered 1 and 2
5178- * with an open temporary file.
5179- */
5180- class FileRedirect : public OutputRedirect {
5181- TempFile m_outFile, m_errFile;
5182- int m_originalOut = -1;
5183- int m_originalErr = -1;
5184-
5185- // Flushes cout/cerr/clog streams and stdout/stderr FDs
5186- void flushEverything() {
5187- Catch::cout() << std::flush;
5188- fflush( stdout );
5189- // Since we support overriding these streams, we flush cerr
5190- // even though std::cerr is unbuffered
5191- Catch::cerr() << std::flush;
5192- Catch::clog() << std::flush;
5193- fflush( stderr );
5194- }
5195-
5196- public:
5197- FileRedirect():
5198- m_originalOut( dup( fileno( stdout ) ) ),
5199- m_originalErr( dup( fileno( stderr ) ) ) {
5200- CATCH_ENFORCE( m_originalOut >= 0, "Could not dup stdout" );
5201- CATCH_ENFORCE( m_originalErr >= 0, "Could not dup stderr" );
5202- }
5203-
5204- std::string getStdout() override { return m_outFile.getContents(); }
5205- std::string getStderr() override { return m_errFile.getContents(); }
5206- void clearBuffers() override {
5207- m_outFile.clear();
5208- m_errFile.clear();
5209- }
5210-
5211- void activateImpl() override {
5212- // We flush before starting redirect, to ensure that we do
5213- // not capture the end of message sent before activation.
5214- flushEverything();
5215-
5216- int ret;
5217- ret = dup2( fileno( m_outFile.getFile() ), fileno( stdout ) );
5218- CATCH_ENFORCE( ret >= 0,
5219- "dup2 to stdout has failed, errno: " << errno );
5220- ret = dup2( fileno( m_errFile.getFile() ), fileno( stderr ) );
5221- CATCH_ENFORCE( ret >= 0,
5222- "dup2 to stderr has failed, errno: " << errno );
5223- }
5224- void deactivateImpl() override {
5225- // We flush before ending redirect, to ensure that we
5226- // capture all messages sent while the redirect was active.
5227- flushEverything();
5228-
5229- int ret;
5230- ret = dup2( m_originalOut, fileno( stdout ) );
5231- CATCH_ENFORCE(
5232- ret >= 0,
5233- "dup2 of original stdout has failed, errno: " << errno );
5234- ret = dup2( m_originalErr, fileno( stderr ) );
5235- CATCH_ENFORCE(
5236- ret >= 0,
5237- "dup2 of original stderr has failed, errno: " << errno );
5238- }
5239- };
5240-
5241-#endif // CATCH_CONFIG_NEW_CAPTURE
5242-
5243- } // end namespace
5244-
5245- bool isRedirectAvailable( OutputRedirect::Kind kind ) {
5246- switch ( kind ) {
5247- // These two are always available
5248- case OutputRedirect::None:
5249- case OutputRedirect::Streams:
5250- return true;
5251-#if defined( CATCH_CONFIG_NEW_CAPTURE )
5252- case OutputRedirect::FileDescriptors:
5253- return true;
5254-#endif
5255- default:
5256- return false;
5257- }
5258- }
5259-
5260- Detail::unique_ptr<OutputRedirect> makeOutputRedirect( bool actual ) {
5261- if ( actual ) {
5262- // TODO: Clean this up later
5263-#if defined( CATCH_CONFIG_NEW_CAPTURE )
5264- return Detail::make_unique<FileRedirect>();
5265-#else
5266- return Detail::make_unique<StreamRedirect>();
5267-#endif
5268- } else {
5269- return Detail::make_unique<NoopRedirect>();
5270- }
5271- }
5272-
5273- RedirectGuard scopedActivate( OutputRedirect& redirectImpl ) {
5274- return RedirectGuard( true, redirectImpl );
5275- }
5276-
5277- RedirectGuard scopedDeactivate( OutputRedirect& redirectImpl ) {
5278- return RedirectGuard( false, redirectImpl );
5279- }
5280-
5281- OutputRedirect::~OutputRedirect() = default;
5282-
5283- RedirectGuard::RedirectGuard( bool activate, OutputRedirect& redirectImpl ):
5284- m_redirect( &redirectImpl ),
5285- m_activate( activate ),
5286- m_previouslyActive( redirectImpl.isActive() ) {
5287-
5288- // Skip cases where there is no actual state change.
5289- if ( m_activate == m_previouslyActive ) { return; }
5290-
5291- if ( m_activate ) {
5292- m_redirect->activate();
5293- } else {
5294- m_redirect->deactivate();
5295- }
5296- }
5297-
5298- RedirectGuard::~RedirectGuard() noexcept( false ) {
5299- if ( m_moved ) { return; }
5300- // Skip cases where there is no actual state change.
5301- if ( m_activate == m_previouslyActive ) { return; }
5302-
5303- if ( m_activate ) {
5304- m_redirect->deactivate();
5305- } else {
5306- m_redirect->activate();
5307- }
5308- }
5309-
5310- RedirectGuard::RedirectGuard( RedirectGuard&& rhs ) noexcept:
5311- m_redirect( rhs.m_redirect ),
5312- m_activate( rhs.m_activate ),
5313- m_previouslyActive( rhs.m_previouslyActive ),
5314- m_moved( false ) {
5315- rhs.m_moved = true;
5316- }
5317-
5318- RedirectGuard& RedirectGuard::operator=( RedirectGuard&& rhs ) noexcept {
5319- m_redirect = rhs.m_redirect;
5320- m_activate = rhs.m_activate;
5321- m_previouslyActive = rhs.m_previouslyActive;
5322- m_moved = false;
5323- rhs.m_moved = true;
5324- return *this;
5325- }
5326-
5327-} // namespace Catch
5328-
5329-#if defined( CATCH_CONFIG_NEW_CAPTURE )
5330-# if defined( _MSC_VER )
5331-# undef dup
5332-# undef dup2
5333-# undef fileno
5334-# endif
5335-#endif
5336-
5337-
5338-
5339-
5340-#include <limits>
5341-#include <stdexcept>
5342-
5343-namespace Catch {
5344-
5345- Optional<unsigned int> parseUInt(std::string const& input, int base) {
5346- auto trimmed = trim( input );
5347- // std::stoull is annoying and accepts numbers starting with '-',
5348- // it just negates them into unsigned int
5349- if ( trimmed.empty() || trimmed[0] == '-' ) {
5350- return {};
5351- }
5352-
5353- CATCH_TRY {
5354- size_t pos = 0;
5355- const auto ret = std::stoull( trimmed, &pos, base );
5356-
5357- // We did not consume the whole input, so there is an issue
5358- // This can be bunch of different stuff, like multiple numbers
5359- // in the input, or invalid digits/characters and so on. Either
5360- // way, we do not want to return the partially parsed result.
5361- if ( pos != trimmed.size() ) {
5362- return {};
5363- }
5364- // Too large
5365- if ( ret > std::numeric_limits<unsigned int>::max() ) {
5366- return {};
5367- }
5368- return static_cast<unsigned int>(ret);
5369- }
5370- CATCH_CATCH_ANON( std::invalid_argument const& ) {
5371- // no conversion could be performed
5372- }
5373- CATCH_CATCH_ANON( std::out_of_range const& ) {
5374- // the input does not fit into an unsigned long long
5375- }
5376- return {};
5377- }
5378-
5379-} // namespace Catch
5380-
5381-
5382-
5383-
5384-#include <cmath>
5385-
5386-namespace Catch {
5387-
5388-#if !defined(CATCH_CONFIG_POLYFILL_ISNAN)
5389- bool isnan(float f) {
5390- return std::isnan(f);
5391- }
5392- bool isnan(double d) {
5393- return std::isnan(d);
5394- }
5395-#else
5396- // For now we only use this for embarcadero
5397- bool isnan(float f) {
5398- return std::_isnan(f);
5399- }
5400- bool isnan(double d) {
5401- return std::_isnan(d);
5402- }
5403-#endif
5404-
5405-#if !defined( CATCH_CONFIG_GLOBAL_NEXTAFTER )
5406- float nextafter( float x, float y ) { return std::nextafter( x, y ); }
5407- double nextafter( double x, double y ) { return std::nextafter( x, y ); }
5408-#else
5409- float nextafter( float x, float y ) { return ::nextafterf( x, y ); }
5410- double nextafter( double x, double y ) { return ::nextafter( x, y ); }
5411-#endif
5412-
5413-} // end namespace Catch
5414-
5415-
5416-
5417-#if defined( __clang__ )
5418-# define CATCH2_CLANG_NO_SANITIZE_INTEGER \
5419- __attribute__( ( no_sanitize( "unsigned-integer-overflow" ) ) )
5420-#else
5421-# define CATCH2_CLANG_NO_SANITIZE_INTEGER
5422-#endif
5423-namespace Catch {
5424-
5425-namespace {
5426-
5427-#if defined(_MSC_VER)
5428-#pragma warning(push)
5429-#pragma warning(disable:4146) // we negate uint32 during the rotate
5430-#endif
5431- // Safe rotr implementation thanks to John Regehr
5432- CATCH2_CLANG_NO_SANITIZE_INTEGER
5433- uint32_t rotate_right(uint32_t val, uint32_t count) {
5434- const uint32_t mask = 31;
5435- count &= mask;
5436- return (val >> count) | (val << (-count & mask));
5437- }
5438-
5439-#if defined(_MSC_VER)
5440-#pragma warning(pop)
5441-#endif
5442-
5443-}
5444-
5445-
5446- SimplePcg32::SimplePcg32(result_type seed_) {
5447- seed(seed_);
5448- }
5449-
5450-
5451- void SimplePcg32::seed(result_type seed_) {
5452- m_state = 0;
5453- (*this)();
5454- m_state += seed_;
5455- (*this)();
5456- }
5457-
5458- void SimplePcg32::discard(uint64_t skip) {
5459- // We could implement this to run in O(log n) steps, but this
5460- // should suffice for our use case.
5461- for (uint64_t s = 0; s < skip; ++s) {
5462- static_cast<void>((*this)());
5463- }
5464- }
5465-
5466- CATCH2_CLANG_NO_SANITIZE_INTEGER
5467- SimplePcg32::result_type SimplePcg32::operator()() {
5468- // prepare the output value
5469- const uint32_t xorshifted = static_cast<uint32_t>(((m_state >> 18u) ^ m_state) >> 27u);
5470- const auto output = rotate_right(xorshifted, static_cast<uint32_t>(m_state >> 59u));
5471-
5472- // advance state
5473- m_state = m_state * 6364136223846793005ULL + s_inc;
5474-
5475- return output;
5476- }
5477-
5478- bool operator==(SimplePcg32 const& lhs, SimplePcg32 const& rhs) {
5479- return lhs.m_state == rhs.m_state;
5480- }
5481-
5482- bool operator!=(SimplePcg32 const& lhs, SimplePcg32 const& rhs) {
5483- return lhs.m_state != rhs.m_state;
5484- }
5485-}
5486-
5487-
5488-
5489-
5490-
5491-#include <ctime>
5492-#include <random>
5493-
5494-namespace Catch {
5495-
5496- std::uint32_t generateRandomSeed( GenerateFrom from ) {
5497- switch ( from ) {
5498- case GenerateFrom::Time:
5499- return static_cast<std::uint32_t>( std::time( nullptr ) );
5500-
5501- case GenerateFrom::Default:
5502- case GenerateFrom::RandomDevice: {
5503- std::random_device rd;
5504- return Detail::fillBitsFrom<std::uint32_t>( rd );
5505- }
5506-
5507- default:
5508- CATCH_ERROR("Unknown generation method");
5509- }
5510- }
5511-
5512-} // end namespace Catch
5513-
5514-
5515-
5516-
5517-namespace Catch {
5518- struct ReporterRegistry::ReporterRegistryImpl {
5519- std::vector<Detail::unique_ptr<EventListenerFactory>> listeners;
5520- std::map<std::string, IReporterFactoryPtr, Detail::CaseInsensitiveLess>
5521- factories;
5522- };
5523-
5524- ReporterRegistry::ReporterRegistry():
5525- m_impl( Detail::make_unique<ReporterRegistryImpl>() ) {
5526- // Because it is impossible to move out of initializer list,
5527- // we have to add the elements manually
5528- m_impl->factories["Automake"] =
5529- Detail::make_unique<ReporterFactory<AutomakeReporter>>();
5530- m_impl->factories["compact"] =
5531- Detail::make_unique<ReporterFactory<CompactReporter>>();
5532- m_impl->factories["console"] =
5533- Detail::make_unique<ReporterFactory<ConsoleReporter>>();
5534- m_impl->factories["JUnit"] =
5535- Detail::make_unique<ReporterFactory<JunitReporter>>();
5536- m_impl->factories["SonarQube"] =
5537- Detail::make_unique<ReporterFactory<SonarQubeReporter>>();
5538- m_impl->factories["TAP"] =
5539- Detail::make_unique<ReporterFactory<TAPReporter>>();
5540- m_impl->factories["TeamCity"] =
5541- Detail::make_unique<ReporterFactory<TeamCityReporter>>();
5542- m_impl->factories["XML"] =
5543- Detail::make_unique<ReporterFactory<XmlReporter>>();
5544- m_impl->factories["JSON"] =
5545- Detail::make_unique<ReporterFactory<JsonReporter>>();
5546- }
5547-
5548- ReporterRegistry::~ReporterRegistry() = default;
5549-
5550- IEventListenerPtr
5551- ReporterRegistry::create( std::string const& name,
5552- ReporterConfig&& config ) const {
5553- auto it = m_impl->factories.find( name );
5554- if ( it == m_impl->factories.end() ) return nullptr;
5555- return it->second->create( CATCH_MOVE( config ) );
5556- }
5557-
5558- void ReporterRegistry::registerReporter( std::string const& name,
5559- IReporterFactoryPtr factory ) {
5560- CATCH_ENFORCE( name.find( "::" ) == name.npos,
5561- "'::' is not allowed in reporter name: '" + name +
5562- '\'' );
5563- auto ret = m_impl->factories.emplace( name, CATCH_MOVE( factory ) );
5564- CATCH_ENFORCE( ret.second,
5565- "reporter using '" + name +
5566- "' as name was already registered" );
5567- }
5568- void ReporterRegistry::registerListener(
5569- Detail::unique_ptr<EventListenerFactory> factory ) {
5570- m_impl->listeners.push_back( CATCH_MOVE( factory ) );
5571- }
5572-
5573- std::map<std::string,
5574- IReporterFactoryPtr,
5575- Detail::CaseInsensitiveLess> const&
5576- ReporterRegistry::getFactories() const {
5577- return m_impl->factories;
5578- }
5579-
5580- std::vector<Detail::unique_ptr<EventListenerFactory>> const&
5581- ReporterRegistry::getListeners() const {
5582- return m_impl->listeners;
5583- }
5584-} // namespace Catch
5585-
5586-
5587-
5588-
5589-
5590-#include <algorithm>
5591-
5592-namespace Catch {
5593-
5594- namespace {
5595- struct kvPair {
5596- StringRef key, value;
5597- };
5598-
5599- kvPair splitKVPair(StringRef kvString) {
5600- auto splitPos = static_cast<size_t>(
5601- std::find( kvString.begin(), kvString.end(), '=' ) -
5602- kvString.begin() );
5603-
5604- return { kvString.substr( 0, splitPos ),
5605- kvString.substr( splitPos + 1, kvString.size() ) };
5606- }
5607- }
5608-
5609- namespace Detail {
5610- std::vector<std::string> splitReporterSpec( StringRef reporterSpec ) {
5611- static constexpr auto separator = "::";
5612- static constexpr size_t separatorSize = 2;
5613-
5614- size_t separatorPos = 0;
5615- auto findNextSeparator = [&reporterSpec]( size_t startPos ) {
5616- static_assert(
5617- separatorSize == 2,
5618- "The code below currently assumes 2 char separator" );
5619-
5620- auto currentPos = startPos;
5621- do {
5622- while ( currentPos < reporterSpec.size() &&
5623- reporterSpec[currentPos] != separator[0] ) {
5624- ++currentPos;
5625- }
5626- if ( currentPos + 1 < reporterSpec.size() &&
5627- reporterSpec[currentPos + 1] == separator[1] ) {
5628- return currentPos;
5629- }
5630- ++currentPos;
5631- } while ( currentPos < reporterSpec.size() );
5632-
5633- return static_cast<size_t>( -1 );
5634- };
5635-
5636- std::vector<std::string> parts;
5637-
5638- while ( separatorPos < reporterSpec.size() ) {
5639- const auto nextSeparator = findNextSeparator( separatorPos );
5640- parts.push_back( static_cast<std::string>( reporterSpec.substr(
5641- separatorPos, nextSeparator - separatorPos ) ) );
5642-
5643- if ( nextSeparator == static_cast<size_t>( -1 ) ) {
5644- break;
5645- }
5646- separatorPos = nextSeparator + separatorSize;
5647- }
5648-
5649- // Handle a separator at the end.
5650- // This is not a valid spec, but we want to do validation in a
5651- // centralized place
5652- if ( separatorPos == reporterSpec.size() ) {
5653- parts.emplace_back();
5654- }
5655-
5656- return parts;
5657- }
5658-
5659- Optional<ColourMode> stringToColourMode( StringRef colourMode ) {
5660- if ( colourMode == "default" ) {
5661- return ColourMode::PlatformDefault;
5662- } else if ( colourMode == "ansi" ) {
5663- return ColourMode::ANSI;
5664- } else if ( colourMode == "win32" ) {
5665- return ColourMode::Win32;
5666- } else if ( colourMode == "none" ) {
5667- return ColourMode::None;
5668- } else {
5669- return {};
5670- }
5671- }
5672- } // namespace Detail
5673-
5674-
5675- bool operator==( ReporterSpec const& lhs, ReporterSpec const& rhs ) {
5676- return lhs.m_name == rhs.m_name &&
5677- lhs.m_outputFileName == rhs.m_outputFileName &&
5678- lhs.m_colourMode == rhs.m_colourMode &&
5679- lhs.m_customOptions == rhs.m_customOptions;
5680- }
5681-
5682- Optional<ReporterSpec> parseReporterSpec( StringRef reporterSpec ) {
5683- auto parts = Detail::splitReporterSpec( reporterSpec );
5684-
5685- assert( parts.size() > 0 && "Split should never return empty vector" );
5686-
5687- std::map<std::string, std::string> kvPairs;
5688- Optional<std::string> outputFileName;
5689- Optional<ColourMode> colourMode;
5690-
5691- // First part is always reporter name, so we skip it
5692- for ( size_t i = 1; i < parts.size(); ++i ) {
5693- auto kv = splitKVPair( parts[i] );
5694- auto key = kv.key, value = kv.value;
5695-
5696- if ( key.empty() || value.empty() ) { // NOLINT(bugprone-branch-clone)
5697- return {};
5698- } else if ( key[0] == 'X' ) {
5699- // This is a reporter-specific option, we don't check these
5700- // apart from basic sanity checks
5701- if ( key.size() == 1 ) {
5702- return {};
5703- }
5704-
5705- auto ret = kvPairs.emplace( std::string(kv.key), std::string(kv.value) );
5706- if ( !ret.second ) {
5707- // Duplicated key. We might want to handle this differently,
5708- // e.g. by overwriting the existing value?
5709- return {};
5710- }
5711- } else if ( key == "out" ) {
5712- // Duplicated key
5713- if ( outputFileName ) {
5714- return {};
5715- }
5716- outputFileName = static_cast<std::string>( value );
5717- } else if ( key == "colour-mode" ) {
5718- // Duplicated key
5719- if ( colourMode ) {
5720- return {};
5721- }
5722- colourMode = Detail::stringToColourMode( value );
5723- // Parsing failed
5724- if ( !colourMode ) {
5725- return {};
5726- }
5727- } else {
5728- // Unrecognized option
5729- return {};
5730- }
5731- }
5732-
5733- return ReporterSpec{ CATCH_MOVE( parts[0] ),
5734- CATCH_MOVE( outputFileName ),
5735- CATCH_MOVE( colourMode ),
5736- CATCH_MOVE( kvPairs ) };
5737- }
5738-
5739-ReporterSpec::ReporterSpec(
5740- std::string name,
5741- Optional<std::string> outputFileName,
5742- Optional<ColourMode> colourMode,
5743- std::map<std::string, std::string> customOptions ):
5744- m_name( CATCH_MOVE( name ) ),
5745- m_outputFileName( CATCH_MOVE( outputFileName ) ),
5746- m_colourMode( CATCH_MOVE( colourMode ) ),
5747- m_customOptions( CATCH_MOVE( customOptions ) ) {}
5748-
5749-} // namespace Catch
5750-
5751-
5752-
5753-#include <cstdio>
5754-#include <sstream>
5755-#include <tuple>
5756-#include <vector>
5757-
5758-namespace Catch {
5759-
5760- // This class encapsulates the idea of a pool of ostringstreams that can be reused.
5761- struct StringStreams {
5762- std::vector<Detail::unique_ptr<std::ostringstream>> m_streams;
5763- std::vector<std::size_t> m_unused;
5764- std::ostringstream m_referenceStream; // Used for copy state/ flags from
5765- Detail::Mutex m_mutex;
5766-
5767- auto add() -> std::pair<std::size_t, std::ostringstream*> {
5768- Detail::LockGuard _( m_mutex );
5769- if( m_unused.empty() ) {
5770- m_streams.push_back( Detail::make_unique<std::ostringstream>() );
5771- return { m_streams.size()-1, m_streams.back().get() };
5772- }
5773- else {
5774- auto index = m_unused.back();
5775- m_unused.pop_back();
5776- return { index, m_streams[index].get() };
5777- }
5778- }
5779-
5780- void release( std::size_t index, std::ostream* originalPtr ) {
5781- assert( originalPtr );
5782- originalPtr->copyfmt( m_referenceStream ); // Restore initial flags and other state
5783-
5784- Detail::LockGuard _( m_mutex );
5785- assert( originalPtr == m_streams[index].get() && "Mismatch between release index and stream ptr" );
5786- m_unused.push_back( index );
5787- }
5788- };
5789-
5790- ReusableStringStream::ReusableStringStream() {
5791- std::tie( m_index, m_oss ) =
5792- Singleton<StringStreams>::getMutable().add();
5793- }
5794-
5795- ReusableStringStream::~ReusableStringStream() {
5796- static_cast<std::ostringstream*>( m_oss )->str("");
5797- m_oss->clear();
5798- Singleton<StringStreams>::getMutable().release( m_index, m_oss );
5799- }
5800-
5801- std::string ReusableStringStream::str() const {
5802- return static_cast<std::ostringstream*>( m_oss )->str();
5803- }
5804-
5805- void ReusableStringStream::str( std::string const& str ) {
5806- static_cast<std::ostringstream*>( m_oss )->str( str );
5807- }
5808-
5809-
5810-}
5811-
5812-
5813-
5814-
5815-#include <cassert>
5816-#include <algorithm>
5817-
5818-namespace Catch {
5819-
5820- namespace Generators {
5821- namespace {
5822- struct GeneratorTracker final : TestCaseTracking::TrackerBase,
5823- IGeneratorTracker {
5824- GeneratorBasePtr m_generator;
5825-
5826- GeneratorTracker(
5827- TestCaseTracking::NameAndLocation&& nameAndLocation,
5828- TrackerContext& ctx,
5829- ITracker* parent ):
5830- TrackerBase( CATCH_MOVE( nameAndLocation ), ctx, parent ) {}
5831-
5832- static GeneratorTracker*
5833- acquire( TrackerContext& ctx,
5834- TestCaseTracking::NameAndLocationRef const&
5835- nameAndLocation ) {
5836- GeneratorTracker* tracker;
5837-
5838- ITracker& currentTracker = ctx.currentTracker();
5839- // Under specific circumstances, the generator we want
5840- // to acquire is also the current tracker. If this is
5841- // the case, we have to avoid looking through current
5842- // tracker's children, and instead return the current
5843- // tracker.
5844- // A case where this check is important is e.g.
5845- // for (int i = 0; i < 5; ++i) {
5846- // int n = GENERATE(1, 2);
5847- // }
5848- //
5849- // without it, the code above creates 5 nested generators.
5850- if ( currentTracker.nameAndLocation() == nameAndLocation ) {
5851- auto thisTracker = currentTracker.parent()->findChild(
5852- nameAndLocation );
5853- assert( thisTracker );
5854- assert( thisTracker->isGeneratorTracker() );
5855- tracker = static_cast<GeneratorTracker*>( thisTracker );
5856- } else if ( ITracker* childTracker =
5857- currentTracker.findChild(
5858- nameAndLocation ) ) {
5859- assert( childTracker );
5860- assert( childTracker->isGeneratorTracker() );
5861- tracker =
5862- static_cast<GeneratorTracker*>( childTracker );
5863- } else {
5864- return nullptr;
5865- }
5866-
5867- if ( !tracker->isComplete() ) { tracker->open(); }
5868-
5869- return tracker;
5870- }
5871-
5872- // TrackerBase interface
5873- bool isGeneratorTracker() const override { return true; }
5874- auto hasGenerator() const -> bool override {
5875- return !!m_generator;
5876- }
5877- void close() override {
5878- TrackerBase::close();
5879- // If a generator has a child (it is followed by a section)
5880- // and none of its children have started, then we must wait
5881- // until later to start consuming its values.
5882- // This catches cases where `GENERATE` is placed between two
5883- // `SECTION`s.
5884- // **The check for m_children.empty cannot be removed**.
5885- // doing so would break `GENERATE` _not_ followed by
5886- // `SECTION`s.
5887- const bool should_wait_for_child = [&]() {
5888- // No children -> nobody to wait for
5889- if ( m_children.empty() ) { return false; }
5890- // If at least one child started executing, don't wait
5891- if ( std::find_if(
5892- m_children.begin(),
5893- m_children.end(),
5894- []( TestCaseTracking::ITrackerPtr const&
5895- tracker ) {
5896- return tracker->hasStarted();
5897- } ) != m_children.end() ) {
5898- return false;
5899- }
5900-
5901- // No children have started. We need to check if they
5902- // _can_ start, and thus we should wait for them, or
5903- // they cannot start (due to filters), and we shouldn't
5904- // wait for them
5905- ITracker* parent = m_parent;
5906- // This is safe: there is always at least one section
5907- // tracker in a test case tracking tree
5908- while ( !parent->isSectionTracker() ) {
5909- parent = parent->parent();
5910- }
5911- assert( parent &&
5912- "Missing root (test case) level section" );
5913-
5914- auto const& parentSection =
5915- static_cast<SectionTracker const&>( *parent );
5916- auto const& filters = parentSection.getFilters();
5917- // No filters -> no restrictions on running sections
5918- if ( filters.empty() ) { return true; }
5919-
5920- for ( auto const& child : m_children ) {
5921- if ( child->isSectionTracker() &&
5922- std::find( filters.begin(),
5923- filters.end(),
5924- static_cast<SectionTracker const&>(
5925- *child )
5926- .trimmedName() ) !=
5927- filters.end() ) {
5928- return true;
5929- }
5930- }
5931- return false;
5932- }();
5933-
5934- // This check is a bit tricky, because m_generator->next()
5935- // has a side-effect, where it consumes generator's current
5936- // value, but we do not want to invoke the side-effect if
5937- // this generator is still waiting for any child to start.
5938- assert( m_generator && "Tracker without generator" );
5939- if ( should_wait_for_child ||
5940- ( m_runState == CompletedSuccessfully &&
5941- m_generator->countedNext() ) ) {
5942- m_children.clear();
5943- m_runState = Executing;
5944- }
5945- }
5946-
5947- // IGeneratorTracker interface
5948- auto getGenerator() const -> GeneratorBasePtr const& override {
5949- return m_generator;
5950- }
5951- void setGenerator( GeneratorBasePtr&& generator ) override {
5952- m_generator = CATCH_MOVE( generator );
5953- }
5954- };
5955- } // namespace
5956- }
5957-
5958- namespace Detail {
5959- // Assertions are owned by the thread that is executing them.
5960- // This allows for lock-free progress in common cases where we
5961- // do not need to send the assertion events to the reporter.
5962- // This also implies that messages are owned by their respective
5963- // threads, and should not be shared across different threads.
5964- //
5965- // This implies that various pieces of metadata referring to last
5966- // assertion result/source location/message handling, etc
5967- // should also be thread local. For now we just use naked globals
5968- // below, in the future we will want to allocate piece of memory
5969- // from heap, to avoid consuming too much thread-local storage.
5970-
5971- // This is used for the "if" part of CHECKED_IF/CHECKED_ELSE
5972- static thread_local bool g_lastAssertionPassed = false;
5973-
5974- // This is the source location for last encountered macro. It is
5975- // used to provide the users with more precise location of error
5976- // when an unexpected exception/fatal error happens.
5977- static thread_local SourceLineInfo g_lastKnownLineInfo("DummyLocation", static_cast<size_t>(-1));
5978-
5979- // Should we clear message scopes before sending off the messages to
5980- // reporter? Set in `assertionPassedFastPath` to avoid doing the full
5981- // clear there for performance reasons.
5982- static thread_local bool g_clearMessageScopes = false;
5983-
5984- CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
5985- CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
5986- // Actual messages to be provided to the reporter
5987- static thread_local std::vector<MessageInfo> g_messages;
5988-
5989- // Owners for the UNSCOPED_X information macro
5990- static thread_local std::vector<ScopedMessage> g_messageScopes;
5991- CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
5992-
5993- } // namespace Detail
5994-
5995- RunContext::RunContext(IConfig const* _config, IEventListenerPtr&& reporter)
5996- : m_runInfo(_config->name()),
5997- m_config(_config),
5998- m_reporter(CATCH_MOVE(reporter)),
5999- m_outputRedirect( makeOutputRedirect( m_reporter->getPreferences().shouldRedirectStdOut ) ),
6000- m_abortAfterXFailedAssertions( m_config->abortAfter() ),
6001- m_reportAssertionStarting( m_reporter->getPreferences().shouldReportAllAssertionStarts ),
6002- m_includeSuccessfulResults( m_config->includeSuccessfulResults() || m_reporter->getPreferences().shouldReportAllAssertions ),
6003- m_shouldDebugBreak( m_config->shouldDebugBreak() )
6004- {
6005- getCurrentMutableContext().setResultCapture( this );
6006- m_reporter->testRunStarting(m_runInfo);
6007- }
6008-
6009- RunContext::~RunContext() {
6010- updateTotalsFromAtomics();
6011- m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, aborting()));
6012- }
6013-
6014- Totals RunContext::runTest(TestCaseHandle const& testCase) {
6015- updateTotalsFromAtomics();
6016- const Totals prevTotals = m_totals;
6017-
6018- auto const& testInfo = testCase.getTestCaseInfo();
6019- m_reporter->testCaseStarting(testInfo);
6020- testCase.prepareTestCase();
6021- m_activeTestCase = &testCase;
6022-
6023-
6024- ITracker& rootTracker = m_trackerContext.startRun();
6025- assert(rootTracker.isSectionTracker());
6026- static_cast<SectionTracker&>(rootTracker).addInitialFilters(m_config->getSectionsToRun());
6027-
6028- // We intentionally only seed the internal RNG once per test case,
6029- // before it is first invoked. The reason for that is a complex
6030- // interplay of generator/section implementation details and the
6031- // Random*Generator types.
6032- //
6033- // The issue boils down to us needing to seed the Random*Generators
6034- // with different seed each, so that they return different sequences
6035- // of random numbers. We do this by giving them a number from the
6036- // shared RNG instance as their seed.
6037- //
6038- // However, this runs into an issue if the reseeding happens each
6039- // time the test case is entered (as opposed to first time only),
6040- // because multiple generators could get the same seed, e.g. in
6041- // ```cpp
6042- // TEST_CASE() {
6043- // auto i = GENERATE(take(10, random(0, 100));
6044- // SECTION("A") {
6045- // auto j = GENERATE(take(10, random(0, 100));
6046- // }
6047- // SECTION("B") {
6048- // auto k = GENERATE(take(10, random(0, 100));
6049- // }
6050- // }
6051- // ```
6052- // `i` and `j` would properly return values from different sequences,
6053- // but `i` and `k` would return the same sequence, because their seed
6054- // would be the same.
6055- // (The reason their seeds would be the same is that the generator
6056- // for k would be initialized when the test case is entered the second
6057- // time, after the shared RNG instance was reset to the same value
6058- // it had when the generator for i was initialized.)
6059- seedRng( *m_config );
6060-
6061- uint64_t testRuns = 0;
6062- std::string redirectedCout;
6063- std::string redirectedCerr;
6064- do {
6065- m_trackerContext.startCycle();
6066- m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocationRef(testInfo.name, testInfo.lineInfo));
6067-
6068- m_reporter->testCasePartialStarting(testInfo, testRuns);
6069-
6070- updateTotalsFromAtomics();
6071- const auto beforeRunTotals = m_totals;
6072- runCurrentTest();
6073- std::string oneRunCout = m_outputRedirect->getStdout();
6074- std::string oneRunCerr = m_outputRedirect->getStderr();
6075- m_outputRedirect->clearBuffers();
6076- redirectedCout += oneRunCout;
6077- redirectedCerr += oneRunCerr;
6078-
6079- updateTotalsFromAtomics();
6080- const auto singleRunTotals = m_totals.delta(beforeRunTotals);
6081- auto statsForOneRun = TestCaseStats(testInfo, singleRunTotals, CATCH_MOVE(oneRunCout), CATCH_MOVE(oneRunCerr), aborting());
6082- m_reporter->testCasePartialEnded(statsForOneRun, testRuns);
6083-
6084- ++testRuns;
6085- } while (!m_testCaseTracker->isSuccessfullyCompleted() && !aborting());
6086-
6087- Totals deltaTotals = m_totals.delta(prevTotals);
6088- if (testInfo.expectedToFail() && deltaTotals.testCases.passed > 0) {
6089- deltaTotals.assertions.failed++;
6090- deltaTotals.testCases.passed--;
6091- deltaTotals.testCases.failed++;
6092- }
6093- m_totals.testCases += deltaTotals.testCases;
6094- testCase.tearDownTestCase();
6095- m_reporter->testCaseEnded(TestCaseStats(testInfo,
6096- deltaTotals,
6097- CATCH_MOVE(redirectedCout),
6098- CATCH_MOVE(redirectedCerr),
6099- aborting()));
6100-
6101- m_activeTestCase = nullptr;
6102- m_testCaseTracker = nullptr;
6103-
6104- return deltaTotals;
6105- }
6106-
6107-
6108- void RunContext::assertionEnded(AssertionResult&& result) {
6109- Detail::g_lastKnownLineInfo = result.m_info.lineInfo;
6110- if (result.getResultType() == ResultWas::Ok) {
6111- m_atomicAssertionCount.passed++;
6112- Detail::g_lastAssertionPassed = true;
6113- } else if (result.getResultType() == ResultWas::ExplicitSkip) {
6114- m_atomicAssertionCount.skipped++;
6115- Detail::g_lastAssertionPassed = true;
6116- } else if (!result.succeeded()) {
6117- Detail::g_lastAssertionPassed = false;
6118- if (result.isOk()) {
6119- }
6120- else if( m_activeTestCase->getTestCaseInfo().okToFail() ) // Read from a shared state established before the threads could start, this is fine
6121- m_atomicAssertionCount.failedButOk++;
6122- else
6123- m_atomicAssertionCount.failed++;
6124- }
6125- else {
6126- Detail::g_lastAssertionPassed = true;
6127- }
6128-
6129- if ( Detail::g_clearMessageScopes ) {
6130- Detail::g_messageScopes.clear();
6131- Detail::g_clearMessageScopes = false;
6132- }
6133-
6134- // From here, we are touching shared state and need mutex.
6135- Detail::LockGuard lock( m_assertionMutex );
6136- {
6137- auto _ = scopedDeactivate( *m_outputRedirect );
6138- updateTotalsFromAtomics();
6139- m_reporter->assertionEnded( AssertionStats( result, Detail::g_messages, m_totals ) );
6140- }
6141-
6142- if ( result.getResultType() != ResultWas::Warning ) {
6143- Detail::g_messageScopes.clear();
6144- }
6145-
6146- // Reset working state. assertion info will be reset after
6147- // populateReaction is run if it is needed
6148- m_lastResult = CATCH_MOVE( result );
6149- }
6150-
6151- void RunContext::notifyAssertionStarted( AssertionInfo const& info ) {
6152- if (m_reportAssertionStarting) {
6153- Detail::LockGuard lock( m_assertionMutex );
6154- auto _ = scopedDeactivate( *m_outputRedirect );
6155- m_reporter->assertionStarting( info );
6156- }
6157- }
6158-
6159- bool RunContext::sectionStarted( StringRef sectionName,
6160- SourceLineInfo const& sectionLineInfo,
6161- Counts& assertions ) {
6162- ITracker& sectionTracker =
6163- SectionTracker::acquire( m_trackerContext,
6164- TestCaseTracking::NameAndLocationRef(
6165- sectionName, sectionLineInfo ) );
6166-
6167- if (!sectionTracker.isOpen())
6168- return false;
6169- m_activeSections.push_back(§ionTracker);
6170-
6171- SectionInfo sectionInfo( sectionLineInfo, static_cast<std::string>(sectionName) );
6172- Detail::g_lastKnownLineInfo = sectionLineInfo;
6173-
6174- {
6175- auto _ = scopedDeactivate( *m_outputRedirect );
6176- m_reporter->sectionStarting( sectionInfo );
6177- }
6178-
6179- updateTotalsFromAtomics();
6180- assertions = m_totals.assertions;
6181-
6182- return true;
6183- }
6184- IGeneratorTracker*
6185- RunContext::acquireGeneratorTracker( StringRef generatorName,
6186- SourceLineInfo const& lineInfo ) {
6187- auto* tracker = Generators::GeneratorTracker::acquire(
6188- m_trackerContext,
6189- TestCaseTracking::NameAndLocationRef(
6190- generatorName, lineInfo ) );
6191- Detail::g_lastKnownLineInfo = lineInfo;
6192- return tracker;
6193- }
6194-
6195- IGeneratorTracker* RunContext::createGeneratorTracker(
6196- StringRef generatorName,
6197- SourceLineInfo lineInfo,
6198- Generators::GeneratorBasePtr&& generator ) {
6199-
6200- auto nameAndLoc = TestCaseTracking::NameAndLocation( static_cast<std::string>( generatorName ), lineInfo );
6201- auto& currentTracker = m_trackerContext.currentTracker();
6202- assert(
6203- currentTracker.nameAndLocation() != nameAndLoc &&
6204- "Trying to create tracker for a generator that already has one" );
6205-
6206- auto newTracker = Catch::Detail::make_unique<Generators::GeneratorTracker>(
6207- CATCH_MOVE(nameAndLoc), m_trackerContext, ¤tTracker );
6208- auto ret = newTracker.get();
6209- currentTracker.addChild( CATCH_MOVE( newTracker ) );
6210-
6211- ret->setGenerator( CATCH_MOVE( generator ) );
6212- ret->open();
6213- return ret;
6214- }
6215-
6216- bool RunContext::testForMissingAssertions(Counts& assertions) {
6217- if (assertions.total() != 0)
6218- return false;
6219- if (!m_config->warnAboutMissingAssertions())
6220- return false;
6221- if (m_trackerContext.currentTracker().hasChildren())
6222- return false;
6223- m_atomicAssertionCount.failed++;
6224- assertions.failed++;
6225- return true;
6226- }
6227-
6228- void RunContext::sectionEnded(SectionEndInfo&& endInfo) {
6229- updateTotalsFromAtomics();
6230- Counts assertions = m_totals.assertions - endInfo.prevAssertions;
6231- bool missingAssertions = testForMissingAssertions(assertions);
6232-
6233- if (!m_activeSections.empty()) {
6234- m_activeSections.back()->close();
6235- m_activeSections.pop_back();
6236- }
6237-
6238- {
6239- auto _ = scopedDeactivate( *m_outputRedirect );
6240- m_reporter->sectionEnded(
6241- SectionStats( CATCH_MOVE( endInfo.sectionInfo ),
6242- assertions,
6243- endInfo.durationInSeconds,
6244- missingAssertions ) );
6245- }
6246- }
6247-
6248- void RunContext::sectionEndedEarly(SectionEndInfo&& endInfo) {
6249- if ( m_unfinishedSections.empty() ) {
6250- m_activeSections.back()->fail();
6251- } else {
6252- m_activeSections.back()->close();
6253- }
6254- m_activeSections.pop_back();
6255-
6256- m_unfinishedSections.push_back(CATCH_MOVE(endInfo));
6257- }
6258-
6259- void RunContext::benchmarkPreparing( StringRef name ) {
6260- auto _ = scopedDeactivate( *m_outputRedirect );
6261- m_reporter->benchmarkPreparing( name );
6262- }
6263- void RunContext::benchmarkStarting( BenchmarkInfo const& info ) {
6264- auto _ = scopedDeactivate( *m_outputRedirect );
6265- m_reporter->benchmarkStarting( info );
6266- }
6267- void RunContext::benchmarkEnded( BenchmarkStats<> const& stats ) {
6268- auto _ = scopedDeactivate( *m_outputRedirect );
6269- m_reporter->benchmarkEnded( stats );
6270- }
6271- void RunContext::benchmarkFailed( StringRef error ) {
6272- auto _ = scopedDeactivate( *m_outputRedirect );
6273- m_reporter->benchmarkFailed( error );
6274- }
6275-
6276- std::string RunContext::getCurrentTestName() const {
6277- return m_activeTestCase
6278- ? m_activeTestCase->getTestCaseInfo().name
6279- : std::string();
6280- }
6281-
6282- const AssertionResult * RunContext::getLastResult() const {
6283- // m_lastResult is updated inside the assertion slow-path, under
6284- // a mutex, so the read needs to happen under mutex as well.
6285-
6286- // TBD: The last result only makes sense if it is a thread-local
6287- // thing, because the answer is different per thread, like
6288- // last line info, whether last assertion passed, and so on.
6289- //
6290- // However, the last result was also never updated in the
6291- // assertion fast path, so it was always somewhat broken,
6292- // and since IResultCapture::getLastResult is deprecated,
6293- // we will leave it as is, until it is finally removed.
6294- Detail::LockGuard _( m_assertionMutex );
6295- return &(*m_lastResult);
6296- }
6297-
6298- void RunContext::exceptionEarlyReported() {
6299- m_shouldReportUnexpected = false;
6300- }
6301-
6302- void RunContext::handleFatalErrorCondition( StringRef message ) {
6303- // We lock only when touching the reporters directly, to avoid
6304- // deadlocks when we call into other functions that also want
6305- // to lock the mutex before touching reporters.
6306- //
6307- // This does mean that we allow other threads to run while handling
6308- // a fatal error, but this is all a best effort attempt anyway.
6309- {
6310- Detail::LockGuard lock( m_assertionMutex );
6311- // TODO: scoped deactivate here? Just give up and do best effort?
6312- // the deactivation can break things further, OTOH so can the
6313- // capture
6314- auto _ = scopedDeactivate( *m_outputRedirect );
6315-
6316- // First notify reporter that bad things happened
6317- m_reporter->fatalErrorEncountered( message );
6318- }
6319-
6320- // Don't rebuild the result -- the stringification itself can cause more fatal errors
6321- // Instead, fake a result data.
6322- AssertionResultData tempResult( ResultWas::FatalErrorCondition, { false } );
6323- tempResult.message = static_cast<std::string>(message);
6324- AssertionResult result( makeDummyAssertionInfo(),
6325- CATCH_MOVE( tempResult ) );
6326-
6327- assertionEnded(CATCH_MOVE(result) );
6328-
6329-
6330- // At this point we touch sections/test cases from this thread
6331- // to try and end them. Technically that is not supported when
6332- // using multiple threads, but the worst thing that can happen
6333- // is that the process aborts harder :-D
6334- Detail::LockGuard lock( m_assertionMutex );
6335-
6336- // Best effort cleanup for sections that have not been destructed yet
6337- // Since this is a fatal error, we have not had and won't have the opportunity to destruct them properly
6338- while (!m_activeSections.empty()) {
6339- auto const& nl = m_activeSections.back()->nameAndLocation();
6340- SectionEndInfo endInfo{ SectionInfo(nl.location, nl.name), {}, 0.0 };
6341- sectionEndedEarly(CATCH_MOVE(endInfo));
6342- }
6343- handleUnfinishedSections();
6344-
6345- // Recreate section for test case (as we will lose the one that was in scope)
6346- auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
6347- SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name);
6348-
6349- Counts assertions;
6350- assertions.failed = 1;
6351- SectionStats testCaseSectionStats(CATCH_MOVE(testCaseSection), assertions, 0, false);
6352- m_reporter->sectionEnded( testCaseSectionStats );
6353-
6354- auto const& testInfo = m_activeTestCase->getTestCaseInfo();
6355-
6356- Totals deltaTotals;
6357- deltaTotals.testCases.failed = 1;
6358- deltaTotals.assertions.failed = 1;
6359- m_reporter->testCaseEnded(TestCaseStats(testInfo,
6360- deltaTotals,
6361- std::string(),
6362- std::string(),
6363- false));
6364- m_totals.testCases.failed++;
6365- updateTotalsFromAtomics();
6366- m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, false));
6367- }
6368-
6369- bool RunContext::lastAssertionPassed() {
6370- return Detail::g_lastAssertionPassed;
6371- }
6372-
6373- void RunContext::assertionPassedFastPath(SourceLineInfo lineInfo) {
6374- // We want to save the line info for better experience with unexpected assertions
6375- Detail::g_lastKnownLineInfo = lineInfo;
6376- ++m_atomicAssertionCount.passed;
6377- Detail::g_lastAssertionPassed = true;
6378- Detail::g_clearMessageScopes = true;
6379- }
6380-
6381- void RunContext::updateTotalsFromAtomics() {
6382- m_totals.assertions = Counts{
6383- m_atomicAssertionCount.passed,
6384- m_atomicAssertionCount.failed,
6385- m_atomicAssertionCount.failedButOk,
6386- m_atomicAssertionCount.skipped,
6387- };
6388- }
6389-
6390- bool RunContext::aborting() const {
6391- return m_atomicAssertionCount.failed >= m_abortAfterXFailedAssertions;
6392- }
6393-
6394- void RunContext::runCurrentTest() {
6395- auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
6396- SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name);
6397- m_reporter->sectionStarting(testCaseSection);
6398- updateTotalsFromAtomics();
6399- Counts prevAssertions = m_totals.assertions;
6400- double duration = 0;
6401- m_shouldReportUnexpected = true;
6402- Detail::g_lastKnownLineInfo = testCaseInfo.lineInfo;
6403-
6404- Timer timer;
6405- CATCH_TRY {
6406- {
6407- auto _ = scopedActivate( *m_outputRedirect );
6408- timer.start();
6409- invokeActiveTestCase();
6410- }
6411- duration = timer.getElapsedSeconds();
6412- } CATCH_CATCH_ANON (TestFailureException&) {
6413- // This just means the test was aborted due to failure
6414- } CATCH_CATCH_ANON (TestSkipException&) {
6415- // This just means the test was explicitly skipped
6416- } CATCH_CATCH_ALL {
6417- // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions
6418- // are reported without translation at the point of origin.
6419- if ( m_shouldReportUnexpected ) {
6420- AssertionReaction dummyReaction;
6421- handleUnexpectedInflightException( makeDummyAssertionInfo(),
6422- translateActiveException(),
6423- dummyReaction );
6424- }
6425- }
6426- updateTotalsFromAtomics();
6427- Counts assertions = m_totals.assertions - prevAssertions;
6428- bool missingAssertions = testForMissingAssertions(assertions);
6429-
6430- m_testCaseTracker->close();
6431- handleUnfinishedSections();
6432- Detail::g_messageScopes.clear();
6433- // TBD: At this point, m_messages should be empty. Do we want to
6434- // assert that this is true, or keep the defensive clear call?
6435- Detail::g_messages.clear();
6436-
6437- SectionStats testCaseSectionStats(CATCH_MOVE(testCaseSection), assertions, duration, missingAssertions);
6438- m_reporter->sectionEnded(testCaseSectionStats);
6439- }
6440-
6441- void RunContext::invokeActiveTestCase() {
6442- // We need to engage a handler for signals/structured exceptions
6443- // before running the tests themselves, or the binary can crash
6444- // without failed test being reported.
6445- FatalConditionHandlerGuard _(&m_fatalConditionhandler);
6446- // We keep having issue where some compilers warn about an unused
6447- // variable, even though the type has non-trivial constructor and
6448- // destructor. This is annoying and ugly, but it makes them stfu.
6449- (void)_;
6450-
6451- m_activeTestCase->invoke();
6452- }
6453-
6454- void RunContext::handleUnfinishedSections() {
6455- // If sections ended prematurely due to an exception we stored their
6456- // infos here so we can tear them down outside the unwind process.
6457- for ( auto it = m_unfinishedSections.rbegin(),
6458- itEnd = m_unfinishedSections.rend();
6459- it != itEnd;
6460- ++it ) {
6461- sectionEnded( CATCH_MOVE( *it ) );
6462- }
6463- m_unfinishedSections.clear();
6464- }
6465-
6466- void RunContext::handleExpr(
6467- AssertionInfo const& info,
6468- ITransientExpression const& expr,
6469- AssertionReaction& reaction
6470- ) {
6471- bool negated = isFalseTest( info.resultDisposition );
6472- bool result = expr.getResult() != negated;
6473-
6474- if( result ) {
6475- if (!m_includeSuccessfulResults) {
6476- assertionPassedFastPath(info.lineInfo);
6477- }
6478- else {
6479- reportExpr(info, ResultWas::Ok, &expr, negated);
6480- }
6481- }
6482- else {
6483- reportExpr(info, ResultWas::ExpressionFailed, &expr, negated );
6484- populateReaction(
6485- reaction, info.resultDisposition & ResultDisposition::Normal );
6486- }
6487- }
6488- void RunContext::reportExpr(
6489- AssertionInfo const &info,
6490- ResultWas::OfType resultType,
6491- ITransientExpression const *expr,
6492- bool negated ) {
6493-
6494- Detail::g_lastKnownLineInfo = info.lineInfo;
6495- AssertionResultData data( resultType, LazyExpression( negated ) );
6496-
6497- AssertionResult assertionResult{ info, CATCH_MOVE( data ) };
6498- assertionResult.m_resultData.lazyExpression.m_transientExpression = expr;
6499-
6500- assertionEnded( CATCH_MOVE(assertionResult) );
6501- }
6502-
6503- void RunContext::handleMessage(
6504- AssertionInfo const& info,
6505- ResultWas::OfType resultType,
6506- std::string&& message,
6507- AssertionReaction& reaction
6508- ) {
6509- Detail::g_lastKnownLineInfo = info.lineInfo;
6510-
6511- AssertionResultData data( resultType, LazyExpression( false ) );
6512- data.message = CATCH_MOVE( message );
6513- AssertionResult assertionResult{ info,
6514- CATCH_MOVE( data ) };
6515-
6516- const auto isOk = assertionResult.isOk();
6517- assertionEnded( CATCH_MOVE(assertionResult) );
6518- if ( !isOk ) {
6519- populateReaction(
6520- reaction, info.resultDisposition & ResultDisposition::Normal );
6521- } else if ( resultType == ResultWas::ExplicitSkip ) {
6522- // TODO: Need to handle this explicitly, as ExplicitSkip is
6523- // considered "OK"
6524- reaction.shouldSkip = true;
6525- }
6526- }
6527-
6528- void RunContext::handleUnexpectedExceptionNotThrown(
6529- AssertionInfo const& info,
6530- AssertionReaction& reaction
6531- ) {
6532- handleNonExpr(info, Catch::ResultWas::DidntThrowException, reaction);
6533- }
6534-
6535- void RunContext::handleUnexpectedInflightException(
6536- AssertionInfo const& info,
6537- std::string&& message,
6538- AssertionReaction& reaction
6539- ) {
6540- Detail::g_lastKnownLineInfo = info.lineInfo;
6541-
6542- AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) );
6543- data.message = CATCH_MOVE(message);
6544- AssertionResult assertionResult{ info, CATCH_MOVE(data) };
6545- assertionEnded( CATCH_MOVE(assertionResult) );
6546- populateReaction( reaction,
6547- info.resultDisposition & ResultDisposition::Normal );
6548- }
6549-
6550- void RunContext::populateReaction( AssertionReaction& reaction,
6551- bool has_normal_disposition ) {
6552- reaction.shouldDebugBreak = m_shouldDebugBreak;
6553- reaction.shouldThrow = aborting() || has_normal_disposition;
6554- }
6555-
6556- AssertionInfo RunContext::makeDummyAssertionInfo() {
6557- const bool testCaseJustStarted =
6558- Detail::g_lastKnownLineInfo ==
6559- m_activeTestCase->getTestCaseInfo().lineInfo;
6560-
6561- return AssertionInfo{
6562- testCaseJustStarted ? "TEST_CASE"_sr : StringRef(),
6563- Detail::g_lastKnownLineInfo,
6564- testCaseJustStarted ? StringRef() : "{Unknown expression after the reported line}"_sr,
6565- ResultDisposition::Normal
6566- };
6567- }
6568-
6569- void RunContext::handleIncomplete(
6570- AssertionInfo const& info
6571- ) {
6572- using namespace std::string_literals;
6573- Detail::g_lastKnownLineInfo = info.lineInfo;
6574-
6575- AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) );
6576- data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"s;
6577- AssertionResult assertionResult{ info, CATCH_MOVE( data ) };
6578- assertionEnded( CATCH_MOVE(assertionResult) );
6579- }
6580-
6581- void RunContext::handleNonExpr(
6582- AssertionInfo const &info,
6583- ResultWas::OfType resultType,
6584- AssertionReaction &reaction
6585- ) {
6586- AssertionResultData data( resultType, LazyExpression( false ) );
6587- AssertionResult assertionResult{ info, CATCH_MOVE( data ) };
6588-
6589- const auto isOk = assertionResult.isOk();
6590- if ( isOk && !m_includeSuccessfulResults ) {
6591- assertionPassedFastPath( info.lineInfo );
6592- return;
6593- }
6594-
6595- assertionEnded( CATCH_MOVE(assertionResult) );
6596- if ( !isOk ) {
6597- populateReaction(
6598- reaction, info.resultDisposition & ResultDisposition::Normal );
6599- }
6600- }
6601-
6602- void IResultCapture::pushScopedMessage( MessageInfo&& message ) {
6603- Detail::g_messages.push_back( CATCH_MOVE( message ) );
6604- }
6605-
6606- void IResultCapture::popScopedMessage( unsigned int messageId ) {
6607- // Note: On average, it would probably be better to look for the message
6608- // backwards. However, we do not expect to have to deal with more
6609- // messages than low single digits, so the optimization is tiny,
6610- // and we would have to hand-write the loop to avoid terrible
6611- // codegen of reverse iterators in debug mode.
6612- Detail::g_messages.erase( std::find_if( Detail::g_messages.begin(),
6613- Detail::g_messages.end(),
6614- [=]( MessageInfo const& msg ) {
6615- return msg.sequence ==
6616- messageId;
6617- } ) );
6618- }
6619-
6620- void IResultCapture::emplaceUnscopedMessage( MessageBuilder&& builder ) {
6621- Detail::g_messageScopes.emplace_back( CATCH_MOVE( builder ) );
6622- }
6623-
6624- void seedRng(IConfig const& config) {
6625- sharedRng().seed(config.rngSeed());
6626- }
6627-
6628- unsigned int rngSeed() {
6629- return getCurrentContext().getConfig()->rngSeed();
6630- }
6631-
6632-}
6633-
6634-
6635-
6636-namespace Catch {
6637-
6638- Section::Section( SectionInfo&& info ):
6639- m_info( CATCH_MOVE( info ) ),
6640- m_sectionIncluded(
6641- getResultCapture().sectionStarted( m_info.name, m_info.lineInfo, m_assertions ) ) {
6642- // Non-"included" sections will not use the timing information
6643- // anyway, so don't bother with the potential syscall.
6644- if (m_sectionIncluded) {
6645- m_timer.start();
6646- }
6647- }
6648-
6649- Section::Section( SourceLineInfo const& _lineInfo,
6650- StringRef _name,
6651- const char* const ):
6652- m_info( { "invalid", static_cast<std::size_t>( -1 ) }, std::string{} ),
6653- m_sectionIncluded(
6654- getResultCapture().sectionStarted( _name, _lineInfo, m_assertions ) ) {
6655- // We delay initialization the SectionInfo member until we know
6656- // this section needs it, so we avoid allocating std::string for name.
6657- // We also delay timer start to avoid the potential syscall unless we
6658- // will actually use the result.
6659- if ( m_sectionIncluded ) {
6660- m_info.name = static_cast<std::string>( _name );
6661- m_info.lineInfo = _lineInfo;
6662- m_timer.start();
6663- }
6664- }
6665-
6666- Section::~Section() {
6667- if( m_sectionIncluded ) {
6668- SectionEndInfo endInfo{ CATCH_MOVE(m_info), m_assertions, m_timer.getElapsedSeconds() };
6669- if ( uncaught_exceptions() ) {
6670- getResultCapture().sectionEndedEarly( CATCH_MOVE(endInfo) );
6671- } else {
6672- getResultCapture().sectionEnded( CATCH_MOVE( endInfo ) );
6673- }
6674- }
6675- }
6676-
6677- // This indicates whether the section should be executed or not
6678- Section::operator bool() const {
6679- return m_sectionIncluded;
6680- }
6681-
6682-
6683-} // end namespace Catch
6684-
6685-
6686-
6687-#include <vector>
6688-
6689-namespace Catch {
6690-
6691- namespace {
6692- static auto getSingletons() -> std::vector<ISingleton*>*& {
6693- static std::vector<ISingleton*>* g_singletons = nullptr;
6694- if( !g_singletons )
6695- g_singletons = new std::vector<ISingleton*>();
6696- return g_singletons;
6697- }
6698- }
6699-
6700- ISingleton::~ISingleton() = default;
6701-
6702- void addSingleton(ISingleton* singleton ) {
6703- getSingletons()->push_back( singleton );
6704- }
6705- void cleanupSingletons() {
6706- auto& singletons = getSingletons();
6707- for( auto singleton : *singletons )
6708- delete singleton;
6709- delete singletons;
6710- singletons = nullptr;
6711- }
6712-
6713-} // namespace Catch
6714-
6715-
6716-
6717-#include <cstring>
6718-#include <ostream>
6719-
6720-namespace Catch {
6721-
6722- bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const noexcept {
6723- return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0);
6724- }
6725- bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const noexcept {
6726- // We can assume that the same file will usually have the same pointer.
6727- // Thus, if the pointers are the same, there is no point in calling the strcmp
6728- return line < other.line || ( line == other.line && file != other.file && (std::strcmp(file, other.file) < 0));
6729- }
6730-
6731- std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) {
6732-#ifndef __GNUG__
6733- os << info.file << '(' << info.line << ')';
6734-#else
6735- os << info.file << ':' << info.line;
6736-#endif
6737- return os;
6738- }
6739-
6740-} // end namespace Catch
6741-
6742-
6743-
6744-
6745-namespace Catch {
6746-#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
6747- void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept {
6748- CATCH_TRY {
6749- m_exceptions.push_back(exception);
6750- } CATCH_CATCH_ALL {
6751- // If we run out of memory during start-up there's really not a lot more we can do about it
6752- std::terminate();
6753- }
6754- }
6755-
6756- std::vector<std::exception_ptr> const& StartupExceptionRegistry::getExceptions() const noexcept {
6757- return m_exceptions;
6758- }
6759-#endif
6760-
6761-} // end namespace Catch
6762-
6763-
6764-
6765-
6766-
6767-#include <iostream>
6768-
6769-namespace Catch {
6770-
6771-// If you #define this you must implement these functions
6772-#if !defined( CATCH_CONFIG_NOSTDOUT )
6773- std::ostream& cout() { return std::cout; }
6774- std::ostream& cerr() { return std::cerr; }
6775- std::ostream& clog() { return std::clog; }
6776-#endif
6777-
6778-} // namespace Catch
6779-
6780-
6781-
6782-#include <ostream>
6783-#include <cstring>
6784-#include <cctype>
6785-#include <vector>
6786-
6787-namespace Catch {
6788-
6789- bool startsWith( std::string const& s, std::string const& prefix ) {
6790- return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin());
6791- }
6792- bool startsWith( StringRef s, char prefix ) {
6793- return !s.empty() && s[0] == prefix;
6794- }
6795- bool endsWith( std::string const& s, std::string const& suffix ) {
6796- return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin());
6797- }
6798- bool endsWith( std::string const& s, char suffix ) {
6799- return !s.empty() && s[s.size()-1] == suffix;
6800- }
6801- bool contains( std::string const& s, std::string const& infix ) {
6802- return s.find( infix ) != std::string::npos;
6803- }
6804- void toLowerInPlace( std::string& s ) {
6805- for ( char& c : s ) {
6806- c = toLower( c );
6807- }
6808- }
6809- std::string toLower( std::string const& s ) {
6810- std::string lc = s;
6811- toLowerInPlace( lc );
6812- return lc;
6813- }
6814- char toLower(char c) {
6815- return static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
6816- }
6817-
6818- std::string trim( std::string const& str ) {
6819- static char const* whitespaceChars = "\n\r\t ";
6820- std::string::size_type start = str.find_first_not_of( whitespaceChars );
6821- std::string::size_type end = str.find_last_not_of( whitespaceChars );
6822-
6823- return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string();
6824- }
6825-
6826- StringRef trim(StringRef ref) {
6827- const auto is_ws = [](char c) {
6828- return c == ' ' || c == '\t' || c == '\n' || c == '\r';
6829- };
6830- size_t real_begin = 0;
6831- while (real_begin < ref.size() && is_ws(ref[real_begin])) { ++real_begin; }
6832- size_t real_end = ref.size();
6833- while (real_end > real_begin && is_ws(ref[real_end - 1])) { --real_end; }
6834-
6835- return ref.substr(real_begin, real_end - real_begin);
6836- }
6837-
6838- bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) {
6839- std::size_t i = str.find( replaceThis );
6840- if (i == std::string::npos) {
6841- return false;
6842- }
6843- std::size_t copyBegin = 0;
6844- std::string origStr = CATCH_MOVE(str);
6845- str.clear();
6846- // There is at least one replacement, so reserve with the best guess
6847- // we can make without actually counting the number of occurrences.
6848- str.reserve(origStr.size() - replaceThis.size() + withThis.size());
6849- do {
6850- str.append(origStr, copyBegin, i-copyBegin );
6851- str += withThis;
6852- copyBegin = i + replaceThis.size();
6853- if( copyBegin < origStr.size() )
6854- i = origStr.find( replaceThis, copyBegin );
6855- else
6856- i = std::string::npos;
6857- } while( i != std::string::npos );
6858- if ( copyBegin < origStr.size() ) {
6859- str.append(origStr, copyBegin, origStr.size() );
6860- }
6861- return true;
6862- }
6863-
6864- std::vector<StringRef> splitStringRef( StringRef str, char delimiter ) {
6865- std::vector<StringRef> subStrings;
6866- std::size_t start = 0;
6867- for(std::size_t pos = 0; pos < str.size(); ++pos ) {
6868- if( str[pos] == delimiter ) {
6869- if( pos - start > 1 )
6870- subStrings.push_back( str.substr( start, pos-start ) );
6871- start = pos+1;
6872- }
6873- }
6874- if( start < str.size() )
6875- subStrings.push_back( str.substr( start, str.size()-start ) );
6876- return subStrings;
6877- }
6878-
6879- std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) {
6880- os << pluraliser.m_count << ' ' << pluraliser.m_label;
6881- if( pluraliser.m_count != 1 )
6882- os << 's';
6883- return os;
6884- }
6885-
6886-}
6887-
6888-
6889-
6890-#include <algorithm>
6891-#include <ostream>
6892-#include <cstring>
6893-
6894-namespace Catch {
6895- StringRef::StringRef( char const* rawChars ) noexcept
6896- : StringRef( rawChars, std::strlen(rawChars) )
6897- {}
6898-
6899-
6900- bool StringRef::operator<(StringRef rhs) const noexcept {
6901- if (m_size < rhs.m_size) {
6902- return strncmp(m_start, rhs.m_start, m_size) <= 0;
6903- }
6904- return strncmp(m_start, rhs.m_start, rhs.m_size) < 0;
6905- }
6906-
6907- int StringRef::compare( StringRef rhs ) const {
6908- auto cmpResult =
6909- strncmp( m_start, rhs.m_start, std::min( m_size, rhs.m_size ) );
6910-
6911- // This means that strncmp found a difference before the strings
6912- // ended, and we can return it directly
6913- if ( cmpResult != 0 ) {
6914- return cmpResult;
6915- }
6916-
6917- // If strings are equal up to length, then their comparison results on
6918- // their size
6919- if ( m_size < rhs.m_size ) {
6920- return -1;
6921- } else if ( m_size > rhs.m_size ) {
6922- return 1;
6923- } else {
6924- return 0;
6925- }
6926- }
6927-
6928- auto operator << ( std::ostream& os, StringRef str ) -> std::ostream& {
6929- return os.write(str.data(), static_cast<std::streamsize>(str.size()));
6930- }
6931-
6932- std::string operator+(StringRef lhs, StringRef rhs) {
6933- std::string ret;
6934- ret.reserve(lhs.size() + rhs.size());
6935- ret += lhs;
6936- ret += rhs;
6937- return ret;
6938- }
6939-
6940- auto operator+=( std::string& lhs, StringRef rhs ) -> std::string& {
6941- lhs.append(rhs.data(), rhs.size());
6942- return lhs;
6943- }
6944-
6945-} // namespace Catch
6946-
6947-
6948-
6949-namespace Catch {
6950-
6951- TagAliasRegistry::~TagAliasRegistry() = default;
6952-
6953- TagAlias const* TagAliasRegistry::find( std::string const& alias ) const {
6954- auto it = m_registry.find( alias );
6955- if( it != m_registry.end() )
6956- return &(it->second);
6957- else
6958- return nullptr;
6959- }
6960-
6961- std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const {
6962- std::string expandedTestSpec = unexpandedTestSpec;
6963- for( auto const& registryKvp : m_registry ) {
6964- std::size_t pos = expandedTestSpec.find( registryKvp.first );
6965- if( pos != std::string::npos ) {
6966- expandedTestSpec = expandedTestSpec.substr( 0, pos ) +
6967- registryKvp.second.tag +
6968- expandedTestSpec.substr( pos + registryKvp.first.size() );
6969- }
6970- }
6971- return expandedTestSpec;
6972- }
6973-
6974- void TagAliasRegistry::add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) {
6975- CATCH_ENFORCE( startsWith(alias, "[@") && endsWith(alias, ']'),
6976- "error: tag alias, '" << alias << "' is not of the form [@alias name].\n" << lineInfo );
6977-
6978- CATCH_ENFORCE( m_registry.insert(std::make_pair(alias, TagAlias(tag, lineInfo))).second,
6979- "error: tag alias, '" << alias << "' already registered.\n"
6980- << "\tFirst seen at: " << find(alias)->lineInfo << "\n"
6981- << "\tRedefined at: " << lineInfo );
6982- }
6983-
6984- ITagAliasRegistry::~ITagAliasRegistry() = default;
6985-
6986- ITagAliasRegistry const& ITagAliasRegistry::get() {
6987- return getRegistryHub().getTagAliasRegistry();
6988- }
6989-
6990-} // end namespace Catch
6991-
6992-
6993-
6994-
6995-namespace Catch {
6996- TestCaseInfoHasher::TestCaseInfoHasher( hash_t seed ): m_seed( seed ) {}
6997-
6998- uint32_t TestCaseInfoHasher::operator()( TestCaseInfo const& t ) const {
6999- // FNV-1a hash algorithm that is designed for uniqueness:
7000- const hash_t prime = 1099511628211u;
7001- hash_t hash = 14695981039346656037u;
7002- for ( const char c : t.name ) {
7003- hash ^= c;
7004- hash *= prime;
7005- }
7006- for ( const char c : t.className ) {
7007- hash ^= c;
7008- hash *= prime;
7009- }
7010- for ( const Tag& tag : t.tags ) {
7011- for ( const char c : tag.original ) {
7012- hash ^= c;
7013- hash *= prime;
7014- }
7015- }
7016- hash ^= m_seed;
7017- hash *= prime;
7018- const uint32_t low{ static_cast<uint32_t>( hash ) };
7019- const uint32_t high{ static_cast<uint32_t>( hash >> 32 ) };
7020- return low * high;
7021- }
7022-} // namespace Catch
7023-
7024-
7025-
7026-
7027-#include <algorithm>
7028-#include <set>
7029-
7030-namespace Catch {
7031-
7032- namespace {
7033- static void enforceNoDuplicateTestCases(
7034- std::vector<TestCaseHandle> const& tests ) {
7035- auto testInfoCmp = []( TestCaseInfo const* lhs,
7036- TestCaseInfo const* rhs ) {
7037- return *lhs < *rhs;
7038- };
7039- std::set<TestCaseInfo const*, decltype( testInfoCmp )&> seenTests(
7040- testInfoCmp );
7041- for ( auto const& test : tests ) {
7042- const auto infoPtr = &test.getTestCaseInfo();
7043- const auto prev = seenTests.insert( infoPtr );
7044- CATCH_ENFORCE( prev.second,
7045- "error: test case \""
7046- << infoPtr->name << "\", with tags \""
7047- << infoPtr->tagsAsString()
7048- << "\" already defined.\n"
7049- << "\tFirst seen at "
7050- << ( *prev.first )->lineInfo << "\n"
7051- << "\tRedefined at " << infoPtr->lineInfo );
7052- }
7053- }
7054-
7055- static bool matchTest( TestCaseHandle const& testCase,
7056- TestSpec const& testSpec,
7057- IConfig const& config ) {
7058- return testSpec.matches( testCase.getTestCaseInfo() ) &&
7059- isThrowSafe( testCase, config );
7060- }
7061-
7062- } // end unnamed namespace
7063-
7064- std::vector<TestCaseHandle> sortTests( IConfig const& config, std::vector<TestCaseHandle> const& unsortedTestCases ) {
7065- switch (config.runOrder()) {
7066- case TestRunOrder::Declared:
7067- return unsortedTestCases;
7068-
7069- case TestRunOrder::LexicographicallySorted: {
7070- std::vector<TestCaseHandle> sorted = unsortedTestCases;
7071- std::sort(
7072- sorted.begin(),
7073- sorted.end(),
7074- []( TestCaseHandle const& lhs, TestCaseHandle const& rhs ) {
7075- return lhs.getTestCaseInfo() < rhs.getTestCaseInfo();
7076- }
7077- );
7078- return sorted;
7079- }
7080- case TestRunOrder::Randomized: {
7081- using TestWithHash = std::pair<TestCaseInfoHasher::hash_t, TestCaseHandle>;
7082-
7083- TestCaseInfoHasher h{ config.rngSeed() };
7084- std::vector<TestWithHash> indexed_tests;
7085- indexed_tests.reserve(unsortedTestCases.size());
7086-
7087- for (auto const& handle : unsortedTestCases) {
7088- indexed_tests.emplace_back(h(handle.getTestCaseInfo()), handle);
7089- }
7090-
7091- std::sort( indexed_tests.begin(),
7092- indexed_tests.end(),
7093- []( TestWithHash const& lhs, TestWithHash const& rhs ) {
7094- if ( lhs.first == rhs.first ) {
7095- return lhs.second.getTestCaseInfo() <
7096- rhs.second.getTestCaseInfo();
7097- }
7098- return lhs.first < rhs.first;
7099- } );
7100-
7101- std::vector<TestCaseHandle> randomized;
7102- randomized.reserve(indexed_tests.size());
7103-
7104- for (auto const& indexed : indexed_tests) {
7105- randomized.push_back(indexed.second);
7106- }
7107-
7108- return randomized;
7109- }
7110- }
7111-
7112- CATCH_INTERNAL_ERROR("Unknown test order value!");
7113- }
7114-
7115- bool isThrowSafe( TestCaseHandle const& testCase, IConfig const& config ) {
7116- return !testCase.getTestCaseInfo().throws() || config.allowThrows();
7117- }
7118-
7119- std::vector<TestCaseHandle> filterTests( std::vector<TestCaseHandle> const& testCases, TestSpec const& testSpec, IConfig const& config ) {
7120- std::vector<TestCaseHandle> filtered;
7121- filtered.reserve( testCases.size() );
7122- for (auto const& testCase : testCases) {
7123- if ((!testSpec.hasFilters() && !testCase.getTestCaseInfo().isHidden()) ||
7124- (testSpec.hasFilters() && matchTest(testCase, testSpec, config))) {
7125- filtered.push_back(testCase);
7126- }
7127- }
7128- return createShard(filtered, config.shardCount(), config.shardIndex());
7129- }
7130- std::vector<TestCaseHandle> const& getAllTestCasesSorted( IConfig const& config ) {
7131- return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config );
7132- }
7133-
7134- TestRegistry::~TestRegistry() = default;
7135-
7136- void TestRegistry::registerTest(Detail::unique_ptr<TestCaseInfo> testInfo, Detail::unique_ptr<ITestInvoker> testInvoker) {
7137- m_handles.emplace_back(testInfo.get(), testInvoker.get());
7138- m_viewed_test_infos.push_back(testInfo.get());
7139- m_owned_test_infos.push_back(CATCH_MOVE(testInfo));
7140- m_invokers.push_back(CATCH_MOVE(testInvoker));
7141- }
7142-
7143- std::vector<TestCaseInfo*> const& TestRegistry::getAllInfos() const {
7144- return m_viewed_test_infos;
7145- }
7146-
7147- std::vector<TestCaseHandle> const& TestRegistry::getAllTests() const {
7148- return m_handles;
7149- }
7150- std::vector<TestCaseHandle> const& TestRegistry::getAllTestsSorted( IConfig const& config ) const {
7151- if( m_sortedFunctions.empty() )
7152- enforceNoDuplicateTestCases( m_handles );
7153-
7154- if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) {
7155- m_sortedFunctions = sortTests( config, m_handles );
7156- m_currentSortOrder = config.runOrder();
7157- }
7158- return m_sortedFunctions;
7159- }
7160-
7161-} // end namespace Catch
7162-
7163-
7164-
7165-
7166-#include <algorithm>
7167-#include <cassert>
7168-
7169-#if defined(__clang__)
7170-# pragma clang diagnostic push
7171-# pragma clang diagnostic ignored "-Wexit-time-destructors"
7172-#endif
7173-
7174-namespace Catch {
7175-namespace TestCaseTracking {
7176-
7177- NameAndLocation::NameAndLocation( std::string&& _name, SourceLineInfo const& _location )
7178- : name( CATCH_MOVE(_name) ),
7179- location( _location )
7180- {}
7181-
7182-
7183- ITracker::~ITracker() = default;
7184-
7185- void ITracker::markAsNeedingAnotherRun() {
7186- m_runState = NeedsAnotherRun;
7187- }
7188-
7189- void ITracker::addChild( ITrackerPtr&& child ) {
7190- m_children.push_back( CATCH_MOVE(child) );
7191- }
7192-
7193- ITracker* ITracker::findChild( NameAndLocationRef const& nameAndLocation ) {
7194- auto it = std::find_if(
7195- m_children.begin(),
7196- m_children.end(),
7197- [&nameAndLocation]( ITrackerPtr const& tracker ) {
7198- auto const& tnameAndLoc = tracker->nameAndLocation();
7199- if ( tnameAndLoc.location.line !=
7200- nameAndLocation.location.line ) {
7201- return false;
7202- }
7203- return tnameAndLoc == nameAndLocation;
7204- } );
7205- return ( it != m_children.end() ) ? it->get() : nullptr;
7206- }
7207-
7208- bool ITracker::isSectionTracker() const { return false; }
7209- bool ITracker::isGeneratorTracker() const { return false; }
7210-
7211- bool ITracker::isOpen() const {
7212- return m_runState != NotStarted && !isComplete();
7213- }
7214-
7215- bool ITracker::hasStarted() const { return m_runState != NotStarted; }
7216-
7217- void ITracker::openChild() {
7218- if (m_runState != ExecutingChildren) {
7219- m_runState = ExecutingChildren;
7220- if (m_parent) {
7221- m_parent->openChild();
7222- }
7223- }
7224- }
7225-
7226- ITracker& TrackerContext::startRun() {
7227- using namespace std::string_literals;
7228- m_rootTracker = Catch::Detail::make_unique<SectionTracker>(
7229- NameAndLocation( "{root}"s, CATCH_INTERNAL_LINEINFO ),
7230- *this,
7231- nullptr );
7232- m_currentTracker = nullptr;
7233- m_runState = Executing;
7234- return *m_rootTracker;
7235- }
7236-
7237- void TrackerContext::completeCycle() {
7238- m_runState = CompletedCycle;
7239- }
7240-
7241- bool TrackerContext::completedCycle() const {
7242- return m_runState == CompletedCycle;
7243- }
7244- void TrackerContext::setCurrentTracker( ITracker* tracker ) {
7245- m_currentTracker = tracker;
7246- }
7247-
7248-
7249- TrackerBase::TrackerBase( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent ):
7250- ITracker(CATCH_MOVE(nameAndLocation), parent),
7251- m_ctx( ctx )
7252- {}
7253-
7254- bool TrackerBase::isComplete() const {
7255- return m_runState == CompletedSuccessfully || m_runState == Failed;
7256- }
7257-
7258- void TrackerBase::open() {
7259- m_runState = Executing;
7260- moveToThis();
7261- if( m_parent )
7262- m_parent->openChild();
7263- }
7264-
7265- void TrackerBase::close() {
7266-
7267- // Close any still open children (e.g. generators)
7268- while( &m_ctx.currentTracker() != this )
7269- m_ctx.currentTracker().close();
7270-
7271- switch( m_runState ) {
7272- case NeedsAnotherRun:
7273- break;
7274-
7275- case Executing:
7276- m_runState = CompletedSuccessfully;
7277- break;
7278- case ExecutingChildren:
7279- if( std::all_of(m_children.begin(), m_children.end(), [](ITrackerPtr const& t){ return t->isComplete(); }) )
7280- m_runState = CompletedSuccessfully;
7281- break;
7282-
7283- case NotStarted:
7284- case CompletedSuccessfully:
7285- case Failed:
7286- CATCH_INTERNAL_ERROR( "Illogical state: " << m_runState );
7287-
7288- default:
7289- CATCH_INTERNAL_ERROR( "Unknown state: " << m_runState );
7290- }
7291- moveToParent();
7292- m_ctx.completeCycle();
7293- }
7294- void TrackerBase::fail() {
7295- m_runState = Failed;
7296- if( m_parent )
7297- m_parent->markAsNeedingAnotherRun();
7298- moveToParent();
7299- m_ctx.completeCycle();
7300- }
7301-
7302- void TrackerBase::moveToParent() {
7303- assert( m_parent );
7304- m_ctx.setCurrentTracker( m_parent );
7305- }
7306- void TrackerBase::moveToThis() {
7307- m_ctx.setCurrentTracker( this );
7308- }
7309-
7310- SectionTracker::SectionTracker( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent )
7311- : TrackerBase( CATCH_MOVE(nameAndLocation), ctx, parent ),
7312- m_trimmed_name(trim(StringRef(ITracker::nameAndLocation().name)))
7313- {
7314- if( parent ) {
7315- while ( !parent->isSectionTracker() ) {
7316- parent = parent->parent();
7317- }
7318-
7319- SectionTracker& parentSection = static_cast<SectionTracker&>( *parent );
7320- addNextFilters( parentSection.m_filters );
7321- }
7322- }
7323-
7324- bool SectionTracker::isComplete() const {
7325- bool complete = true;
7326-
7327- if (m_filters.empty()
7328- || m_filters[0].empty()
7329- || std::find(m_filters.begin(), m_filters.end(), m_trimmed_name) != m_filters.end()) {
7330- complete = TrackerBase::isComplete();
7331- }
7332- return complete;
7333- }
7334-
7335- bool SectionTracker::isSectionTracker() const { return true; }
7336-
7337- SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocationRef const& nameAndLocation ) {
7338- SectionTracker* tracker;
7339-
7340- ITracker& currentTracker = ctx.currentTracker();
7341- if ( ITracker* childTracker =
7342- currentTracker.findChild( nameAndLocation ) ) {
7343- assert( childTracker );
7344- assert( childTracker->isSectionTracker() );
7345- tracker = static_cast<SectionTracker*>( childTracker );
7346- } else {
7347- auto newTracker = Catch::Detail::make_unique<SectionTracker>(
7348- NameAndLocation{ static_cast<std::string>(nameAndLocation.name),
7349- nameAndLocation.location },
7350- ctx,
7351- ¤tTracker );
7352- tracker = newTracker.get();
7353- currentTracker.addChild( CATCH_MOVE( newTracker ) );
7354- }
7355-
7356- if ( !ctx.completedCycle() ) {
7357- tracker->tryOpen();
7358- }
7359-
7360- return *tracker;
7361- }
7362-
7363- void SectionTracker::tryOpen() {
7364- if( !isComplete() )
7365- open();
7366- }
7367-
7368- void SectionTracker::addInitialFilters( std::vector<std::string> const& filters ) {
7369- if( !filters.empty() ) {
7370- m_filters.reserve( m_filters.size() + filters.size() + 2 );
7371- m_filters.emplace_back(StringRef{}); // Root - should never be consulted
7372- m_filters.emplace_back(StringRef{}); // Test Case - not a section filter
7373- m_filters.insert( m_filters.end(), filters.begin(), filters.end() );
7374- }
7375- }
7376- void SectionTracker::addNextFilters( std::vector<StringRef> const& filters ) {
7377- if( filters.size() > 1 )
7378- m_filters.insert( m_filters.end(), filters.begin()+1, filters.end() );
7379- }
7380-
7381- StringRef SectionTracker::trimmedName() const {
7382- return m_trimmed_name;
7383- }
7384-
7385-} // namespace TestCaseTracking
7386-
7387-} // namespace Catch
7388-
7389-#if defined(__clang__)
7390-# pragma clang diagnostic pop
7391-#endif
7392-
7393-
7394-
7395-
7396-namespace Catch {
7397-
7398- void throw_test_failure_exception() {
7399-#if !defined( CATCH_CONFIG_DISABLE_EXCEPTIONS )
7400- throw TestFailureException{};
7401-#else
7402- CATCH_ERROR( "Test failure requires aborting test!" );
7403-#endif
7404- }
7405-
7406- void throw_test_skip_exception() {
7407-#if !defined( CATCH_CONFIG_DISABLE_EXCEPTIONS )
7408- throw Catch::TestSkipException();
7409-#else
7410- CATCH_ERROR( "Explicitly skipping tests during runtime requires exceptions" );
7411-#endif
7412- }
7413-
7414-} // namespace Catch
7415-
7416-
7417-
7418-#include <algorithm>
7419-#include <iterator>
7420-
7421-namespace Catch {
7422- void ITestInvoker::prepareTestCase() {}
7423- void ITestInvoker::tearDownTestCase() {}
7424- ITestInvoker::~ITestInvoker() = default;
7425-
7426- namespace {
7427- static StringRef extractClassName( StringRef classOrMethodName ) {
7428- if ( !startsWith( classOrMethodName, '&' ) ) {
7429- return classOrMethodName;
7430- }
7431-
7432- // Remove the leading '&' to avoid having to special case it later
7433- const auto methodName =
7434- classOrMethodName.substr( 1, classOrMethodName.size() );
7435-
7436- auto reverseStart = std::make_reverse_iterator( methodName.end() );
7437- auto reverseEnd = std::make_reverse_iterator( methodName.begin() );
7438-
7439- // We make a simplifying assumption that ":" is only present
7440- // in the input as part of "::" from C++ typenames (this is
7441- // relatively safe assumption because the input is generated
7442- // as stringification of type through preprocessor).
7443- auto lastColons = std::find( reverseStart, reverseEnd, ':' ) + 1;
7444- auto secondLastColons =
7445- std::find( lastColons + 1, reverseEnd, ':' );
7446-
7447- auto const startIdx = reverseEnd - secondLastColons;
7448- auto const classNameSize = secondLastColons - lastColons - 1;
7449-
7450- return methodName.substr(
7451- static_cast<std::size_t>( startIdx ),
7452- static_cast<std::size_t>( classNameSize ) );
7453- }
7454-
7455- class TestInvokerAsFunction final : public ITestInvoker {
7456- using TestType = void ( * )();
7457- TestType m_testAsFunction;
7458-
7459- public:
7460- constexpr TestInvokerAsFunction( TestType testAsFunction ) noexcept:
7461- m_testAsFunction( testAsFunction ) {}
7462-
7463- void invoke() const override { m_testAsFunction(); }
7464- };
7465-
7466- } // namespace
7467-
7468- Detail::unique_ptr<ITestInvoker> makeTestInvoker( void(*testAsFunction)() ) {
7469- return Detail::make_unique<TestInvokerAsFunction>( testAsFunction );
7470- }
7471-
7472- AutoReg::AutoReg( Detail::unique_ptr<ITestInvoker> invoker, SourceLineInfo const& lineInfo, StringRef classOrMethod, NameAndTags const& nameAndTags ) noexcept {
7473- CATCH_TRY {
7474- getMutableRegistryHub()
7475- .registerTest(
7476- makeTestCaseInfo(
7477- extractClassName( classOrMethod ),
7478- nameAndTags,
7479- lineInfo),
7480- CATCH_MOVE(invoker)
7481- );
7482- } CATCH_CATCH_ALL {
7483- // Do not throw when constructing global objects, instead register the exception to be processed later
7484- getMutableRegistryHub().registerStartupException();
7485- }
7486- }
7487-}
7488-
7489-
7490-
7491-
7492-
7493-namespace Catch {
7494-
7495- TestSpecParser::TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {}
7496-
7497- TestSpecParser& TestSpecParser::parse( std::string const& arg ) {
7498- m_mode = None;
7499- m_exclusion = false;
7500- m_arg = m_tagAliases->expandAliases( arg );
7501- m_escapeChars.clear();
7502- m_substring.reserve(m_arg.size());
7503- m_patternName.reserve(m_arg.size());
7504- m_realPatternPos = 0;
7505-
7506- for( m_pos = 0; m_pos < m_arg.size(); ++m_pos )
7507- //if visitChar fails
7508- if( !visitChar( m_arg[m_pos] ) ){
7509- m_testSpec.m_invalidSpecs.push_back(arg);
7510- break;
7511- }
7512- endMode();
7513- return *this;
7514- }
7515- TestSpec TestSpecParser::testSpec() {
7516- addFilter();
7517- return CATCH_MOVE(m_testSpec);
7518- }
7519- bool TestSpecParser::visitChar( char c ) {
7520- if( (m_mode != EscapedName) && (c == '\\') ) {
7521- escape();
7522- addCharToPattern(c);
7523- return true;
7524- }else if((m_mode != EscapedName) && (c == ',') ) {
7525- return separate();
7526- }
7527-
7528- switch( m_mode ) {
7529- case None:
7530- if( processNoneChar( c ) )
7531- return true;
7532- break;
7533- case Name:
7534- processNameChar( c );
7535- break;
7536- case EscapedName:
7537- endMode();
7538- addCharToPattern(c);
7539- return true;
7540- default:
7541- case Tag:
7542- case QuotedName:
7543- if( processOtherChar( c ) )
7544- return true;
7545- break;
7546- }
7547-
7548- m_substring += c;
7549- if( !isControlChar( c ) ) {
7550- m_patternName += c;
7551- m_realPatternPos++;
7552- }
7553- return true;
7554- }
7555- // Two of the processing methods return true to signal the caller to return
7556- // without adding the given character to the current pattern strings
7557- bool TestSpecParser::processNoneChar( char c ) {
7558- switch( c ) {
7559- case ' ':
7560- return true;
7561- case '~':
7562- m_exclusion = true;
7563- return false;
7564- case '[':
7565- startNewMode( Tag );
7566- return false;
7567- case '"':
7568- startNewMode( QuotedName );
7569- return false;
7570- default:
7571- startNewMode( Name );
7572- return false;
7573- }
7574- }
7575- void TestSpecParser::processNameChar( char c ) {
7576- if( c == '[' ) {
7577- if( m_substring == "exclude:" )
7578- m_exclusion = true;
7579- else
7580- endMode();
7581- startNewMode( Tag );
7582- }
7583- }
7584- bool TestSpecParser::processOtherChar( char c ) {
7585- if( !isControlChar( c ) )
7586- return false;
7587- m_substring += c;
7588- endMode();
7589- return true;
7590- }
7591- void TestSpecParser::startNewMode( Mode mode ) {
7592- m_mode = mode;
7593- }
7594- void TestSpecParser::endMode() {
7595- switch( m_mode ) {
7596- case Name:
7597- case QuotedName:
7598- return addNamePattern();
7599- case Tag:
7600- return addTagPattern();
7601- case EscapedName:
7602- revertBackToLastMode();
7603- return;
7604- case None:
7605- default:
7606- return startNewMode( None );
7607- }
7608- }
7609- void TestSpecParser::escape() {
7610- saveLastMode();
7611- m_mode = EscapedName;
7612- m_escapeChars.push_back(m_realPatternPos);
7613- }
7614- bool TestSpecParser::isControlChar( char c ) const {
7615- switch( m_mode ) {
7616- default:
7617- return false;
7618- case None:
7619- return c == '~';
7620- case Name:
7621- return c == '[';
7622- case EscapedName:
7623- return true;
7624- case QuotedName:
7625- return c == '"';
7626- case Tag:
7627- return c == '[' || c == ']';
7628- }
7629- }
7630-
7631- void TestSpecParser::addFilter() {
7632- if( !m_currentFilter.m_required.empty() || !m_currentFilter.m_forbidden.empty() ) {
7633- m_testSpec.m_filters.push_back( CATCH_MOVE(m_currentFilter) );
7634- m_currentFilter = TestSpec::Filter();
7635- }
7636- }
7637-
7638- void TestSpecParser::saveLastMode() {
7639- lastMode = m_mode;
7640- }
7641-
7642- void TestSpecParser::revertBackToLastMode() {
7643- m_mode = lastMode;
7644- }
7645-
7646- bool TestSpecParser::separate() {
7647- if( (m_mode==QuotedName) || (m_mode==Tag) ){
7648- //invalid argument, signal failure to previous scope.
7649- m_mode = None;
7650- m_pos = m_arg.size();
7651- m_substring.clear();
7652- m_patternName.clear();
7653- m_realPatternPos = 0;
7654- return false;
7655- }
7656- endMode();
7657- addFilter();
7658- return true; //success
7659- }
7660-
7661- std::string TestSpecParser::preprocessPattern() {
7662- std::string token = m_patternName;
7663- for (std::size_t i = 0; i < m_escapeChars.size(); ++i)
7664- token = token.substr(0, m_escapeChars[i] - i) + token.substr(m_escapeChars[i] - i + 1);
7665- m_escapeChars.clear();
7666- if (startsWith(token, "exclude:")) {
7667- m_exclusion = true;
7668- token = token.substr(8);
7669- }
7670-
7671- m_patternName.clear();
7672- m_realPatternPos = 0;
7673-
7674- return token;
7675- }
7676-
7677- void TestSpecParser::addNamePattern() {
7678- auto token = preprocessPattern();
7679-
7680- if (!token.empty()) {
7681- if (m_exclusion) {
7682- m_currentFilter.m_forbidden.emplace_back(Detail::make_unique<TestSpec::NamePattern>(token, m_substring));
7683- } else {
7684- m_currentFilter.m_required.emplace_back(Detail::make_unique<TestSpec::NamePattern>(token, m_substring));
7685- }
7686- }
7687- m_substring.clear();
7688- m_exclusion = false;
7689- m_mode = None;
7690- }
7691-
7692- void TestSpecParser::addTagPattern() {
7693- auto token = preprocessPattern();
7694-
7695- if (!token.empty()) {
7696- // If the tag pattern is the "hide and tag" shorthand (e.g. [.foo])
7697- // we have to create a separate hide tag and shorten the real one
7698- if (token.size() > 1 && token[0] == '.') {
7699- token.erase(token.begin());
7700- if (m_exclusion) {
7701- m_currentFilter.m_forbidden.emplace_back(Detail::make_unique<TestSpec::TagPattern>(".", m_substring));
7702- } else {
7703- m_currentFilter.m_required.emplace_back(Detail::make_unique<TestSpec::TagPattern>(".", m_substring));
7704- }
7705- }
7706- if (m_exclusion) {
7707- m_currentFilter.m_forbidden.emplace_back(Detail::make_unique<TestSpec::TagPattern>(token, m_substring));
7708- } else {
7709- m_currentFilter.m_required.emplace_back(Detail::make_unique<TestSpec::TagPattern>(token, m_substring));
7710- }
7711- }
7712- m_substring.clear();
7713- m_exclusion = false;
7714- m_mode = None;
7715- }
7716-
7717-} // namespace Catch
7718-
7719-
7720-
7721-#include <algorithm>
7722-#include <cstring>
7723-#include <ostream>
7724-
7725-namespace {
7726- bool isWhitespace( char c ) {
7727- return c == ' ' || c == '\t' || c == '\n' || c == '\r';
7728- }
7729-
7730- bool isBreakableBefore( char c ) {
7731- static const char chars[] = "[({<|";
7732- return std::memchr( chars, c, sizeof( chars ) - 1 ) != nullptr;
7733- }
7734-
7735- bool isBreakableAfter( char c ) {
7736- static const char chars[] = "])}>.,:;*+-=&/\\";
7737- return std::memchr( chars, c, sizeof( chars ) - 1 ) != nullptr;
7738- }
7739-
7740-} // namespace
7741-
7742-namespace Catch {
7743- namespace TextFlow {
7744- void AnsiSkippingString::preprocessString() {
7745- for ( auto it = m_string.begin(); it != m_string.end(); ) {
7746- // try to read through an ansi sequence
7747- while ( it != m_string.end() && *it == '\033' &&
7748- it + 1 != m_string.end() && *( it + 1 ) == '[' ) {
7749- auto cursor = it + 2;
7750- while ( cursor != m_string.end() &&
7751- ( isdigit( *cursor ) || *cursor == ';' ) ) {
7752- ++cursor;
7753- }
7754- if ( cursor == m_string.end() || *cursor != 'm' ) {
7755- break;
7756- }
7757- // 'm' -> 0xff
7758- *cursor = AnsiSkippingString::sentinel;
7759- // if we've read an ansi sequence, set the iterator and
7760- // return to the top of the loop
7761- it = cursor + 1;
7762- }
7763- if ( it != m_string.end() ) {
7764- ++m_size;
7765- ++it;
7766- }
7767- }
7768- }
7769-
7770- AnsiSkippingString::AnsiSkippingString( std::string const& text ):
7771- m_string( text ) {
7772- preprocessString();
7773- }
7774-
7775- AnsiSkippingString::AnsiSkippingString( std::string&& text ):
7776- m_string( CATCH_MOVE( text ) ) {
7777- preprocessString();
7778- }
7779-
7780- AnsiSkippingString::const_iterator AnsiSkippingString::begin() const {
7781- return const_iterator( m_string );
7782- }
7783-
7784- AnsiSkippingString::const_iterator AnsiSkippingString::end() const {
7785- return const_iterator( m_string, const_iterator::EndTag{} );
7786- }
7787-
7788- std::string AnsiSkippingString::substring( const_iterator begin,
7789- const_iterator end ) const {
7790- // There's one caveat here to an otherwise simple substring: when
7791- // making a begin iterator we might have skipped ansi sequences at
7792- // the start. If `begin` here is a begin iterator, skipped over
7793- // initial ansi sequences, we'll use the true beginning of the
7794- // string. Lastly: We need to transform any chars we replaced with
7795- // 0xff back to 'm'
7796- auto str = std::string( begin == this->begin() ? m_string.begin()
7797- : begin.m_it,
7798- end.m_it );
7799- std::transform( str.begin(), str.end(), str.begin(), []( char c ) {
7800- return c == AnsiSkippingString::sentinel ? 'm' : c;
7801- } );
7802- return str;
7803- }
7804-
7805- void AnsiSkippingString::const_iterator::tryParseAnsiEscapes() {
7806- // check if we've landed on an ansi sequence, and if so read through
7807- // it
7808- while ( m_it != m_string->end() && *m_it == '\033' &&
7809- m_it + 1 != m_string->end() && *( m_it + 1 ) == '[' ) {
7810- auto cursor = m_it + 2;
7811- while ( cursor != m_string->end() &&
7812- ( isdigit( *cursor ) || *cursor == ';' ) ) {
7813- ++cursor;
7814- }
7815- if ( cursor == m_string->end() ||
7816- *cursor != AnsiSkippingString::sentinel ) {
7817- break;
7818- }
7819- // if we've read an ansi sequence, set the iterator and
7820- // return to the top of the loop
7821- m_it = cursor + 1;
7822- }
7823- }
7824-
7825- void AnsiSkippingString::const_iterator::advance() {
7826- assert( m_it != m_string->end() );
7827- m_it++;
7828- tryParseAnsiEscapes();
7829- }
7830-
7831- void AnsiSkippingString::const_iterator::unadvance() {
7832- assert( m_it != m_string->begin() );
7833- m_it--;
7834- // if *m_it is 0xff, scan back to the \033 and then m_it-- once more
7835- // (and repeat check)
7836- while ( *m_it == AnsiSkippingString::sentinel ) {
7837- while ( *m_it != '\033' ) {
7838- assert( m_it != m_string->begin() );
7839- m_it--;
7840- }
7841- // if this happens, we must have been a begin iterator that had
7842- // skipped over ansi sequences at the start of a string
7843- assert( m_it != m_string->begin() );
7844- assert( *m_it == '\033' );
7845- m_it--;
7846- }
7847- }
7848-
7849- static bool isBoundary( AnsiSkippingString const& line,
7850- AnsiSkippingString::const_iterator it ) {
7851- return it == line.end() ||
7852- ( isWhitespace( *it ) &&
7853- !isWhitespace( *it.oneBefore() ) ) ||
7854- isBreakableBefore( *it ) ||
7855- isBreakableAfter( *it.oneBefore() );
7856- }
7857-
7858- void Column::const_iterator::calcLength() {
7859- m_addHyphen = false;
7860- m_parsedTo = m_lineStart;
7861- AnsiSkippingString const& current_line = m_column.m_string;
7862-
7863- if ( m_parsedTo == current_line.end() ) {
7864- m_lineEnd = m_parsedTo;
7865- return;
7866- }
7867-
7868- assert( m_lineStart != current_line.end() );
7869- if ( *m_lineStart == '\n' ) { ++m_parsedTo; }
7870-
7871- const auto maxLineLength = m_column.m_width - indentSize();
7872- std::size_t lineLength = 0;
7873- while ( m_parsedTo != current_line.end() &&
7874- lineLength < maxLineLength && *m_parsedTo != '\n' ) {
7875- ++m_parsedTo;
7876- ++lineLength;
7877- }
7878-
7879- // If we encountered a newline before the column is filled,
7880- // then we linebreak at the newline and consider this line
7881- // finished.
7882- if ( lineLength < maxLineLength ) {
7883- m_lineEnd = m_parsedTo;
7884- } else {
7885- // Look for a natural linebreak boundary in the column
7886- // (We look from the end, so that the first found boundary is
7887- // the right one)
7888- m_lineEnd = m_parsedTo;
7889- while ( lineLength > 0 &&
7890- !isBoundary( current_line, m_lineEnd ) ) {
7891- --lineLength;
7892- --m_lineEnd;
7893- }
7894- while ( lineLength > 0 &&
7895- isWhitespace( *m_lineEnd.oneBefore() ) ) {
7896- --lineLength;
7897- --m_lineEnd;
7898- }
7899-
7900- // If we found one, then that is where we linebreak, otherwise
7901- // we have to split text with a hyphen
7902- if ( lineLength == 0 ) {
7903- m_addHyphen = true;
7904- m_lineEnd = m_parsedTo.oneBefore();
7905- }
7906- }
7907- }
7908-
7909- size_t Column::const_iterator::indentSize() const {
7910- auto initial = m_lineStart == m_column.m_string.begin()
7911- ? m_column.m_initialIndent
7912- : std::string::npos;
7913- return initial == std::string::npos ? m_column.m_indent : initial;
7914- }
7915-
7916- std::string Column::const_iterator::addIndentAndSuffix(
7917- AnsiSkippingString::const_iterator start,
7918- AnsiSkippingString::const_iterator end ) const {
7919- std::string ret;
7920- const auto desired_indent = indentSize();
7921- // ret.reserve( desired_indent + (end - start) + m_addHyphen );
7922- ret.append( desired_indent, ' ' );
7923- // ret.append( start, end );
7924- ret += m_column.m_string.substring( start, end );
7925- if ( m_addHyphen ) { ret.push_back( '-' ); }
7926-
7927- return ret;
7928- }
7929-
7930- Column::const_iterator::const_iterator( Column const& column ):
7931- m_column( column ),
7932- m_lineStart( column.m_string.begin() ),
7933- m_lineEnd( column.m_string.begin() ),
7934- m_parsedTo( column.m_string.begin() ) {
7935- assert( m_column.m_width > m_column.m_indent );
7936- assert( m_column.m_initialIndent == std::string::npos ||
7937- m_column.m_width > m_column.m_initialIndent );
7938- calcLength();
7939- if ( m_lineStart == m_lineEnd ) {
7940- m_lineStart = m_column.m_string.end();
7941- }
7942- }
7943-
7944- std::string Column::const_iterator::operator*() const {
7945- assert( m_lineStart <= m_parsedTo );
7946- return addIndentAndSuffix( m_lineStart, m_lineEnd );
7947- }
7948-
7949- Column::const_iterator& Column::const_iterator::operator++() {
7950- m_lineStart = m_lineEnd;
7951- AnsiSkippingString const& current_line = m_column.m_string;
7952- if ( m_lineStart != current_line.end() && *m_lineStart == '\n' ) {
7953- m_lineStart++;
7954- } else {
7955- while ( m_lineStart != current_line.end() &&
7956- isWhitespace( *m_lineStart ) ) {
7957- ++m_lineStart;
7958- }
7959- }
7960-
7961- if ( m_lineStart != current_line.end() ) { calcLength(); }
7962- return *this;
7963- }
7964-
7965- Column::const_iterator Column::const_iterator::operator++( int ) {
7966- const_iterator prev( *this );
7967- operator++();
7968- return prev;
7969- }
7970-
7971- std::ostream& operator<<( std::ostream& os, Column const& col ) {
7972- bool first = true;
7973- for ( auto line : col ) {
7974- if ( first ) {
7975- first = false;
7976- } else {
7977- os << '\n';
7978- }
7979- os << line;
7980- }
7981- return os;
7982- }
7983-
7984- Column Spacer( size_t spaceWidth ) {
7985- Column ret{ "" };
7986- ret.width( spaceWidth );
7987- return ret;
7988- }
7989-
7990- Columns::iterator::iterator( Columns const& columns, EndTag ):
7991- m_columns( columns.m_columns ), m_activeIterators( 0 ) {
7992-
7993- m_iterators.reserve( m_columns.size() );
7994- for ( auto const& col : m_columns ) {
7995- m_iterators.push_back( col.end() );
7996- }
7997- }
7998-
7999- Columns::iterator::iterator( Columns const& columns ):
8000- m_columns( columns.m_columns ),
8001- m_activeIterators( m_columns.size() ) {
8002-
8003- m_iterators.reserve( m_columns.size() );
8004- for ( auto const& col : m_columns ) {
8005- m_iterators.push_back( col.begin() );
8006- }
8007- }
8008-
8009- std::string Columns::iterator::operator*() const {
8010- std::string row, padding;
8011-
8012- for ( size_t i = 0; i < m_columns.size(); ++i ) {
8013- const auto width = m_columns[i].width();
8014- if ( m_iterators[i] != m_columns[i].end() ) {
8015- std::string col = *m_iterators[i];
8016- row += padding;
8017- row += col;
8018-
8019- padding.clear();
8020- if ( col.size() < width ) {
8021- padding.append( width - col.size(), ' ' );
8022- }
8023- } else {
8024- padding.append( width, ' ' );
8025- }
8026- }
8027- return row;
8028- }
8029-
8030- Columns::iterator& Columns::iterator::operator++() {
8031- for ( size_t i = 0; i < m_columns.size(); ++i ) {
8032- if ( m_iterators[i] != m_columns[i].end() ) {
8033- ++m_iterators[i];
8034- }
8035- }
8036- return *this;
8037- }
8038-
8039- Columns::iterator Columns::iterator::operator++( int ) {
8040- iterator prev( *this );
8041- operator++();
8042- return prev;
8043- }
8044-
8045- std::ostream& operator<<( std::ostream& os, Columns const& cols ) {
8046- bool first = true;
8047- for ( auto line : cols ) {
8048- if ( first ) {
8049- first = false;
8050- } else {
8051- os << '\n';
8052- }
8053- os << line;
8054- }
8055- return os;
8056- }
8057-
8058- Columns operator+( Column const& lhs, Column const& rhs ) {
8059- Columns cols;
8060- cols += lhs;
8061- cols += rhs;
8062- return cols;
8063- }
8064- Columns operator+( Column&& lhs, Column&& rhs ) {
8065- Columns cols;
8066- cols += CATCH_MOVE( lhs );
8067- cols += CATCH_MOVE( rhs );
8068- return cols;
8069- }
8070-
8071- Columns& operator+=( Columns& lhs, Column const& rhs ) {
8072- lhs.m_columns.push_back( rhs );
8073- return lhs;
8074- }
8075- Columns& operator+=( Columns& lhs, Column&& rhs ) {
8076- lhs.m_columns.push_back( CATCH_MOVE( rhs ) );
8077- return lhs;
8078- }
8079- Columns operator+( Columns const& lhs, Column const& rhs ) {
8080- auto combined( lhs );
8081- combined += rhs;
8082- return combined;
8083- }
8084- Columns operator+( Columns&& lhs, Column&& rhs ) {
8085- lhs += CATCH_MOVE( rhs );
8086- return CATCH_MOVE( lhs );
8087- }
8088-
8089- } // namespace TextFlow
8090-} // namespace Catch
8091-
8092-
8093-
8094-
8095-#include <exception>
8096-
8097-namespace Catch {
8098- bool uncaught_exceptions() {
8099-#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
8100- return false;
8101-#elif defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
8102- return std::uncaught_exceptions() > 0;
8103-#else
8104- return std::uncaught_exception();
8105-#endif
8106- }
8107-} // end namespace Catch
8108-
8109-
8110-
8111-namespace Catch {
8112-
8113- WildcardPattern::WildcardPattern( std::string const& pattern,
8114- CaseSensitive caseSensitivity )
8115- : m_caseSensitivity( caseSensitivity ),
8116- m_pattern( normaliseString( pattern ) )
8117- {
8118- if( startsWith( m_pattern, '*' ) ) {
8119- m_pattern = m_pattern.substr( 1 );
8120- m_wildcard = WildcardAtStart;
8121- }
8122- if( endsWith( m_pattern, '*' ) ) {
8123- m_pattern = m_pattern.substr( 0, m_pattern.size()-1 );
8124- m_wildcard = static_cast<WildcardPosition>( m_wildcard | WildcardAtEnd );
8125- }
8126- }
8127-
8128- bool WildcardPattern::matches( std::string const& str ) const {
8129- switch( m_wildcard ) {
8130- case NoWildcard:
8131- return m_pattern == normaliseString( str );
8132- case WildcardAtStart:
8133- return endsWith( normaliseString( str ), m_pattern );
8134- case WildcardAtEnd:
8135- return startsWith( normaliseString( str ), m_pattern );
8136- case WildcardAtBothEnds:
8137- return contains( normaliseString( str ), m_pattern );
8138- default:
8139- CATCH_INTERNAL_ERROR( "Unknown enum" );
8140- }
8141- }
8142-
8143- std::string WildcardPattern::normaliseString( std::string const& str ) const {
8144- return trim( m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str );
8145- }
8146-}
8147-
8148-
8149-// Note: swapping these two includes around causes MSVC to error out
8150-// while in /permissive- mode. No, I don't know why.
8151-// Tested on VS 2019, 18.{3, 4}.x
8152-
8153-#include <cstdint>
8154-#include <iomanip>
8155-#include <type_traits>
8156-
8157-namespace Catch {
8158-
8159-namespace {
8160-
8161- size_t trailingBytes(unsigned char c) {
8162- if ((c & 0xE0) == 0xC0) {
8163- return 2;
8164- }
8165- if ((c & 0xF0) == 0xE0) {
8166- return 3;
8167- }
8168- if ((c & 0xF8) == 0xF0) {
8169- return 4;
8170- }
8171- CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered");
8172- }
8173-
8174- uint32_t headerValue(unsigned char c) {
8175- if ((c & 0xE0) == 0xC0) {
8176- return c & 0x1F;
8177- }
8178- if ((c & 0xF0) == 0xE0) {
8179- return c & 0x0F;
8180- }
8181- if ((c & 0xF8) == 0xF0) {
8182- return c & 0x07;
8183- }
8184- CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered");
8185- }
8186-
8187- void hexEscapeChar(std::ostream& os, unsigned char c) {
8188- std::ios_base::fmtflags f(os.flags());
8189- os << "\\x"_sr
8190- << std::uppercase << std::hex << std::setfill('0') << std::setw(2)
8191- << static_cast<int>(c);
8192- os.flags(f);
8193- }
8194-
8195- constexpr bool shouldNewline(XmlFormatting fmt) {
8196- return !!(static_cast<std::underlying_type_t<XmlFormatting>>(fmt & XmlFormatting::Newline));
8197- }
8198-
8199- constexpr bool shouldIndent(XmlFormatting fmt) {
8200- return !!(static_cast<std::underlying_type_t<XmlFormatting>>(fmt & XmlFormatting::Indent));
8201- }
8202-
8203-} // anonymous namespace
8204-
8205- void XmlEncode::encodeTo( std::ostream& os ) const {
8206- // Apostrophe escaping not necessary if we always use " to write attributes
8207- // (see: http://www.w3.org/TR/xml/#syntax)
8208- size_t last_start = 0;
8209- auto write_to = [&]( size_t idx ) {
8210- if ( last_start < idx ) {
8211- os << m_str.substr( last_start, idx - last_start );
8212- }
8213- last_start = idx + 1;
8214- };
8215-
8216- for ( std::size_t idx = 0; idx < m_str.size(); ++idx ) {
8217- unsigned char c = static_cast<unsigned char>( m_str[idx] );
8218- switch ( c ) {
8219- case '<':
8220- write_to( idx );
8221- os << "<"_sr;
8222- break;
8223- case '&':
8224- write_to( idx );
8225- os << "&"_sr;
8226- break;
8227-
8228- case '>':
8229- // See: http://www.w3.org/TR/xml/#syntax
8230- if ( idx > 2 && m_str[idx - 1] == ']' && m_str[idx - 2] == ']' ) {
8231- write_to( idx );
8232- os << ">"_sr;
8233- }
8234- break;
8235-
8236- case '\"':
8237- if ( m_forWhat == ForAttributes ) {
8238- write_to( idx );
8239- os << """_sr;
8240- }
8241- break;
8242-
8243- default:
8244- // Check for control characters and invalid utf-8
8245-
8246- // Escape control characters in standard ascii
8247- // see
8248- // http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0
8249- if ( c < 0x09 || ( c > 0x0D && c < 0x20 ) || c == 0x7F ) {
8250- write_to( idx );
8251- hexEscapeChar( os, c );
8252- break;
8253- }
8254-
8255- // Plain ASCII: Write it to stream
8256- if ( c < 0x7F ) {
8257- break;
8258- }
8259-
8260- // UTF-8 territory
8261- // Check if the encoding is valid and if it is not, hex escape
8262- // bytes. Important: We do not check the exact decoded values for
8263- // validity, only the encoding format First check that this bytes is
8264- // a valid lead byte: This means that it is not encoded as 1111 1XXX
8265- // Or as 10XX XXXX
8266- if ( c < 0xC0 || c >= 0xF8 ) {
8267- write_to( idx );
8268- hexEscapeChar( os, c );
8269- break;
8270- }
8271-
8272- auto encBytes = trailingBytes( c );
8273- // Are there enough bytes left to avoid accessing out-of-bounds
8274- // memory?
8275- if ( idx + encBytes - 1 >= m_str.size() ) {
8276- write_to( idx );
8277- hexEscapeChar( os, c );
8278- break;
8279- }
8280- // The header is valid, check data
8281- // The next encBytes bytes must together be a valid utf-8
8282- // This means: bitpattern 10XX XXXX and the extracted value is sane
8283- // (ish)
8284- bool valid = true;
8285- uint32_t value = headerValue( c );
8286- for ( std::size_t n = 1; n < encBytes; ++n ) {
8287- unsigned char nc = static_cast<unsigned char>( m_str[idx + n] );
8288- valid &= ( ( nc & 0xC0 ) == 0x80 );
8289- value = ( value << 6 ) | ( nc & 0x3F );
8290- }
8291-
8292- if (
8293- // Wrong bit pattern of following bytes
8294- ( !valid ) ||
8295- // Overlong encodings
8296- ( value < 0x80 ) ||
8297- ( 0x80 <= value && value < 0x800 && encBytes > 2 ) ||
8298- ( 0x800 < value && value < 0x10000 && encBytes > 3 ) ||
8299- // Encoded value out of range
8300- ( value >= 0x110000 ) ) {
8301- write_to( idx );
8302- hexEscapeChar( os, c );
8303- break;
8304- }
8305-
8306- // If we got here, this is in fact a valid(ish) utf-8 sequence
8307- idx += encBytes - 1;
8308- break;
8309- }
8310- }
8311-
8312- write_to( m_str.size() );
8313- }
8314-
8315- std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) {
8316- xmlEncode.encodeTo( os );
8317- return os;
8318- }
8319-
8320- XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer, XmlFormatting fmt )
8321- : m_writer( writer ),
8322- m_fmt(fmt)
8323- {}
8324-
8325- XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) noexcept
8326- : m_writer( other.m_writer ),
8327- m_fmt(other.m_fmt)
8328- {
8329- other.m_writer = nullptr;
8330- other.m_fmt = XmlFormatting::None;
8331- }
8332- XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) noexcept {
8333- if ( m_writer ) {
8334- m_writer->endElement();
8335- }
8336- m_writer = other.m_writer;
8337- other.m_writer = nullptr;
8338- m_fmt = other.m_fmt;
8339- other.m_fmt = XmlFormatting::None;
8340- return *this;
8341- }
8342-
8343-
8344- XmlWriter::ScopedElement::~ScopedElement() {
8345- if (m_writer) {
8346- m_writer->endElement(m_fmt);
8347- }
8348- }
8349-
8350- XmlWriter::ScopedElement&
8351- XmlWriter::ScopedElement::writeText( StringRef text, XmlFormatting fmt ) {
8352- m_writer->writeText( text, fmt );
8353- return *this;
8354- }
8355-
8356- XmlWriter::ScopedElement&
8357- XmlWriter::ScopedElement::writeAttribute( StringRef name,
8358- StringRef attribute ) {
8359- m_writer->writeAttribute( name, attribute );
8360- return *this;
8361- }
8362-
8363-
8364- XmlWriter::XmlWriter( std::ostream& os ) : m_os( os )
8365- {
8366- writeDeclaration();
8367- }
8368-
8369- XmlWriter::~XmlWriter() {
8370- while (!m_tags.empty()) {
8371- endElement();
8372- }
8373- newlineIfNecessary();
8374- }
8375-
8376- XmlWriter& XmlWriter::startElement( std::string const& name, XmlFormatting fmt ) {
8377- ensureTagClosed();
8378- newlineIfNecessary();
8379- if (shouldIndent(fmt)) {
8380- m_os << m_indent;
8381- m_indent += " ";
8382- }
8383- m_os << '<' << name;
8384- m_tags.push_back( name );
8385- m_tagIsOpen = true;
8386- applyFormatting(fmt);
8387- return *this;
8388- }
8389-
8390- XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name, XmlFormatting fmt ) {
8391- ScopedElement scoped( this, fmt );
8392- startElement( name, fmt );
8393- return scoped;
8394- }
8395-
8396- XmlWriter& XmlWriter::endElement(XmlFormatting fmt) {
8397- m_indent = m_indent.substr(0, m_indent.size() - 2);
8398-
8399- if( m_tagIsOpen ) {
8400- m_os << "/>";
8401- m_tagIsOpen = false;
8402- } else {
8403- newlineIfNecessary();
8404- if (shouldIndent(fmt)) {
8405- m_os << m_indent;
8406- }
8407- m_os << "</" << m_tags.back() << '>';
8408- }
8409- m_os << std::flush;
8410- applyFormatting(fmt);
8411- m_tags.pop_back();
8412- return *this;
8413- }
8414-
8415- XmlWriter& XmlWriter::writeAttribute( StringRef name,
8416- StringRef attribute ) {
8417- if( !name.empty() && !attribute.empty() )
8418- m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"';
8419- return *this;
8420- }
8421-
8422- XmlWriter& XmlWriter::writeAttribute( StringRef name, bool attribute ) {
8423- writeAttribute(name, (attribute ? "true"_sr : "false"_sr));
8424- return *this;
8425- }
8426-
8427- XmlWriter& XmlWriter::writeAttribute( StringRef name,
8428- char const* attribute ) {
8429- writeAttribute( name, StringRef( attribute ) );
8430- return *this;
8431- }
8432-
8433- XmlWriter& XmlWriter::writeText( StringRef text, XmlFormatting fmt ) {
8434- CATCH_ENFORCE(!m_tags.empty(), "Cannot write text as top level element");
8435- if( !text.empty() ){
8436- bool tagWasOpen = m_tagIsOpen;
8437- ensureTagClosed();
8438- if (tagWasOpen && shouldIndent(fmt)) {
8439- m_os << m_indent;
8440- }
8441- m_os << XmlEncode( text, XmlEncode::ForTextNodes );
8442- applyFormatting(fmt);
8443- }
8444- return *this;
8445- }
8446-
8447- XmlWriter& XmlWriter::writeComment( StringRef text, XmlFormatting fmt ) {
8448- ensureTagClosed();
8449- if (shouldIndent(fmt)) {
8450- m_os << m_indent;
8451- }
8452- m_os << "<!-- " << text << " -->";
8453- applyFormatting(fmt);
8454- return *this;
8455- }
8456-
8457- void XmlWriter::writeStylesheetRef( StringRef url ) {
8458- m_os << R"(<?xml-stylesheet type="text/xsl" href=")" << url << R"("?>)" << '\n';
8459- }
8460-
8461- void XmlWriter::ensureTagClosed() {
8462- if( m_tagIsOpen ) {
8463- m_os << '>' << std::flush;
8464- newlineIfNecessary();
8465- m_tagIsOpen = false;
8466- }
8467- }
8468-
8469- void XmlWriter::applyFormatting(XmlFormatting fmt) {
8470- m_needsNewline = shouldNewline(fmt);
8471- }
8472-
8473- void XmlWriter::writeDeclaration() {
8474- m_os << R"(<?xml version="1.0" encoding="UTF-8"?>)" << '\n';
8475- }
8476-
8477- void XmlWriter::newlineIfNecessary() {
8478- if( m_needsNewline ) {
8479- m_os << '\n' << std::flush;
8480- m_needsNewline = false;
8481- }
8482- }
8483-}
8484-
8485-
8486-
8487-
8488-
8489-namespace Catch {
8490-namespace Matchers {
8491-
8492- std::string MatcherUntypedBase::toString() const {
8493- if (m_cachedToString.empty()) {
8494- m_cachedToString = describe();
8495- }
8496- return m_cachedToString;
8497- }
8498-
8499- MatcherUntypedBase::~MatcherUntypedBase() = default;
8500-
8501-} // namespace Matchers
8502-} // namespace Catch
8503-
8504-
8505-
8506-
8507-namespace Catch {
8508-namespace Matchers {
8509-
8510- std::string IsEmptyMatcher::describe() const {
8511- return "is empty";
8512- }
8513-
8514- std::string HasSizeMatcher::describe() const {
8515- ReusableStringStream sstr;
8516- sstr << "has size == " << m_target_size;
8517- return sstr.str();
8518- }
8519-
8520- IsEmptyMatcher IsEmpty() {
8521- return {};
8522- }
8523-
8524- HasSizeMatcher SizeIs(std::size_t sz) {
8525- return HasSizeMatcher{ sz };
8526- }
8527-
8528-} // end namespace Matchers
8529-} // end namespace Catch
8530-
8531-
8532-
8533-namespace Catch {
8534-namespace Matchers {
8535-
8536-bool ExceptionMessageMatcher::match(std::exception const& ex) const {
8537- return ex.what() == m_message;
8538-}
8539-
8540-std::string ExceptionMessageMatcher::describe() const {
8541- return "exception message matches \"" + m_message + '"';
8542-}
8543-
8544-ExceptionMessageMatcher Message(std::string const& message) {
8545- return ExceptionMessageMatcher(message);
8546-}
8547-
8548-} // namespace Matchers
8549-} // namespace Catch
8550-
8551-
8552-
8553-#include <algorithm>
8554-#include <cmath>
8555-#include <cstdlib>
8556-#include <cstdint>
8557-#include <sstream>
8558-#include <iomanip>
8559-#include <limits>
8560-
8561-
8562-namespace Catch {
8563-namespace {
8564-
8565- template <typename FP>
8566- bool almostEqualUlps(FP lhs, FP rhs, uint64_t maxUlpDiff) {
8567- // Comparison with NaN should always be false.
8568- // This way we can rule it out before getting into the ugly details
8569- if (Catch::isnan(lhs) || Catch::isnan(rhs)) {
8570- return false;
8571- }
8572-
8573- // This should also handle positive and negative zeros, infinities
8574- const auto ulpDist = ulpDistance(lhs, rhs);
8575-
8576- return ulpDist <= maxUlpDiff;
8577- }
8578-
8579-
8580-template <typename FP>
8581-FP step(FP start, FP direction, uint64_t steps) {
8582- for (uint64_t i = 0; i < steps; ++i) {
8583- start = Catch::nextafter(start, direction);
8584- }
8585- return start;
8586-}
8587-
8588-// Performs equivalent check of std::fabs(lhs - rhs) <= margin
8589-// But without the subtraction to allow for INFINITY in comparison
8590-bool marginComparison(double lhs, double rhs, double margin) {
8591- return (lhs + margin >= rhs) && (rhs + margin >= lhs);
8592-}
8593-
8594-template <typename FloatingPoint>
8595-void write(std::ostream& out, FloatingPoint num) {
8596- out << std::scientific
8597- << std::setprecision(std::numeric_limits<FloatingPoint>::max_digits10 - 1)
8598- << num;
8599-}
8600-
8601-} // end anonymous namespace
8602-
8603-namespace Matchers {
8604-namespace Detail {
8605-
8606- enum class FloatingPointKind : uint8_t {
8607- Float,
8608- Double
8609- };
8610-
8611-} // end namespace Detail
8612-
8613-
8614- WithinAbsMatcher::WithinAbsMatcher(double target, double margin)
8615- :m_target{ target }, m_margin{ margin } {
8616- CATCH_ENFORCE(margin >= 0, "Invalid margin: " << margin << '.'
8617- << " Margin has to be non-negative.");
8618- }
8619-
8620- // Performs equivalent check of std::fabs(lhs - rhs) <= margin
8621- // But without the subtraction to allow for INFINITY in comparison
8622- bool WithinAbsMatcher::match(double const& matchee) const {
8623- return (matchee + m_margin >= m_target) && (m_target + m_margin >= matchee);
8624- }
8625-
8626- std::string WithinAbsMatcher::describe() const {
8627- return "is within " + ::Catch::Detail::stringify(m_margin) + " of " + ::Catch::Detail::stringify(m_target);
8628- }
8629-
8630-
8631- WithinUlpsMatcher::WithinUlpsMatcher(double target, uint64_t ulps, Detail::FloatingPointKind baseType)
8632- :m_target{ target }, m_ulps{ ulps }, m_type{ baseType } {
8633- CATCH_ENFORCE(m_type == Detail::FloatingPointKind::Double
8634- || m_ulps < (std::numeric_limits<uint32_t>::max)(),
8635- "Provided ULP is impossibly large for a float comparison.");
8636- CATCH_ENFORCE( std::numeric_limits<double>::is_iec559,
8637- "WithinUlp matcher only supports platforms with "
8638- "IEEE-754 compatible floating point representation" );
8639- }
8640-
8641-#if defined(__clang__)
8642-#pragma clang diagnostic push
8643-// Clang <3.5 reports on the default branch in the switch below
8644-#pragma clang diagnostic ignored "-Wunreachable-code"
8645-#endif
8646-
8647- bool WithinUlpsMatcher::match(double const& matchee) const {
8648- switch (m_type) {
8649- case Detail::FloatingPointKind::Float:
8650- return almostEqualUlps<float>(static_cast<float>(matchee), static_cast<float>(m_target), m_ulps);
8651- case Detail::FloatingPointKind::Double:
8652- return almostEqualUlps<double>(matchee, m_target, m_ulps);
8653- default:
8654- CATCH_INTERNAL_ERROR( "Unknown Detail::FloatingPointKind value" );
8655- }
8656- }
8657-
8658-#if defined(__clang__)
8659-#pragma clang diagnostic pop
8660-#endif
8661-
8662- std::string WithinUlpsMatcher::describe() const {
8663- std::stringstream ret;
8664-
8665- ret << "is within " << m_ulps << " ULPs of ";
8666-
8667- if (m_type == Detail::FloatingPointKind::Float) {
8668- write(ret, static_cast<float>(m_target));
8669- ret << 'f';
8670- } else {
8671- write(ret, m_target);
8672- }
8673-
8674- ret << " ([";
8675- if (m_type == Detail::FloatingPointKind::Double) {
8676- write( ret,
8677- step( m_target,
8678- -std::numeric_limits<double>::infinity(),
8679- m_ulps ) );
8680- ret << ", ";
8681- write( ret,
8682- step( m_target,
8683- std::numeric_limits<double>::infinity(),
8684- m_ulps ) );
8685- } else {
8686- // We have to cast INFINITY to float because of MinGW, see #1782
8687- write( ret,
8688- step( static_cast<float>( m_target ),
8689- -std::numeric_limits<float>::infinity(),
8690- m_ulps ) );
8691- ret << ", ";
8692- write( ret,
8693- step( static_cast<float>( m_target ),
8694- std::numeric_limits<float>::infinity(),
8695- m_ulps ) );
8696- }
8697- ret << "])";
8698-
8699- return ret.str();
8700- }
8701-
8702- WithinRelMatcher::WithinRelMatcher(double target, double epsilon):
8703- m_target(target),
8704- m_epsilon(epsilon){
8705- CATCH_ENFORCE(m_epsilon >= 0., "Relative comparison with epsilon < 0 does not make sense.");
8706- CATCH_ENFORCE(m_epsilon < 1., "Relative comparison with epsilon >= 1 does not make sense.");
8707- }
8708-
8709- bool WithinRelMatcher::match(double const& matchee) const {
8710- const auto relMargin = m_epsilon * (std::max)(std::fabs(matchee), std::fabs(m_target));
8711- return marginComparison(matchee, m_target,
8712- std::isinf(relMargin)? 0 : relMargin);
8713- }
8714-
8715- std::string WithinRelMatcher::describe() const {
8716- Catch::ReusableStringStream sstr;
8717- sstr << "and " << ::Catch::Detail::stringify(m_target) << " are within " << m_epsilon * 100. << "% of each other";
8718- return sstr.str();
8719- }
8720-
8721-
8722-WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff) {
8723- return WithinUlpsMatcher(target, maxUlpDiff, Detail::FloatingPointKind::Double);
8724-}
8725-
8726-WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff) {
8727- return WithinUlpsMatcher(target, maxUlpDiff, Detail::FloatingPointKind::Float);
8728-}
8729-
8730-WithinAbsMatcher WithinAbs(double target, double margin) {
8731- return WithinAbsMatcher(target, margin);
8732-}
8733-
8734-WithinRelMatcher WithinRel(double target, double eps) {
8735- return WithinRelMatcher(target, eps);
8736-}
8737-
8738-WithinRelMatcher WithinRel(double target) {
8739- return WithinRelMatcher(target, std::numeric_limits<double>::epsilon() * 100);
8740-}
8741-
8742-WithinRelMatcher WithinRel(float target, float eps) {
8743- return WithinRelMatcher(target, eps);
8744-}
8745-
8746-WithinRelMatcher WithinRel(float target) {
8747- return WithinRelMatcher(target, std::numeric_limits<float>::epsilon() * 100);
8748-}
8749-
8750-
8751-
8752-bool IsNaNMatcher::match( double const& matchee ) const {
8753- return std::isnan( matchee );
8754-}
8755-
8756-std::string IsNaNMatcher::describe() const {
8757- using namespace std::string_literals;
8758- return "is NaN"s;
8759-}
8760-
8761-IsNaNMatcher IsNaN() { return IsNaNMatcher(); }
8762-
8763- } // namespace Matchers
8764-} // namespace Catch
8765-
8766-
8767-
8768-
8769-std::string Catch::Matchers::Detail::finalizeDescription(const std::string& desc) {
8770- if (desc.empty()) {
8771- return "matches undescribed predicate";
8772- } else {
8773- return "matches predicate: \"" + desc + '"';
8774- }
8775-}
8776-
8777-
8778-
8779-namespace Catch {
8780- namespace Matchers {
8781- std::string AllTrueMatcher::describe() const { return "contains only true"; }
8782-
8783- AllTrueMatcher AllTrue() { return AllTrueMatcher{}; }
8784-
8785- std::string NoneTrueMatcher::describe() const { return "contains no true"; }
8786-
8787- NoneTrueMatcher NoneTrue() { return NoneTrueMatcher{}; }
8788-
8789- std::string AnyTrueMatcher::describe() const { return "contains at least one true"; }
8790-
8791- AnyTrueMatcher AnyTrue() { return AnyTrueMatcher{}; }
8792- } // namespace Matchers
8793-} // namespace Catch
8794-
8795-
8796-
8797-#include <regex>
8798-
8799-namespace Catch {
8800-namespace Matchers {
8801-
8802- CasedString::CasedString( std::string const& str, CaseSensitive caseSensitivity )
8803- : m_caseSensitivity( caseSensitivity ),
8804- m_str( adjustString( str ) )
8805- {}
8806- std::string CasedString::adjustString( std::string const& str ) const {
8807- return m_caseSensitivity == CaseSensitive::No
8808- ? toLower( str )
8809- : str;
8810- }
8811- StringRef CasedString::caseSensitivitySuffix() const {
8812- return m_caseSensitivity == CaseSensitive::Yes
8813- ? StringRef()
8814- : " (case insensitive)"_sr;
8815- }
8816-
8817-
8818- StringMatcherBase::StringMatcherBase( StringRef operation, CasedString const& comparator )
8819- : m_comparator( comparator ),
8820- m_operation( operation ) {
8821- }
8822-
8823- std::string StringMatcherBase::describe() const {
8824- std::string description;
8825- description.reserve(5 + m_operation.size() + m_comparator.m_str.size() +
8826- m_comparator.caseSensitivitySuffix().size());
8827- description += m_operation;
8828- description += ": \"";
8829- description += m_comparator.m_str;
8830- description += '"';
8831- description += m_comparator.caseSensitivitySuffix();
8832- return description;
8833- }
8834-
8835- StringEqualsMatcher::StringEqualsMatcher( CasedString const& comparator ) : StringMatcherBase( "equals"_sr, comparator ) {}
8836-
8837- bool StringEqualsMatcher::match( std::string const& source ) const {
8838- return m_comparator.adjustString( source ) == m_comparator.m_str;
8839- }
8840-
8841-
8842- StringContainsMatcher::StringContainsMatcher( CasedString const& comparator ) : StringMatcherBase( "contains"_sr, comparator ) {}
8843-
8844- bool StringContainsMatcher::match( std::string const& source ) const {
8845- return contains( m_comparator.adjustString( source ), m_comparator.m_str );
8846- }
8847-
8848-
8849- StartsWithMatcher::StartsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "starts with"_sr, comparator ) {}
8850-
8851- bool StartsWithMatcher::match( std::string const& source ) const {
8852- return startsWith( m_comparator.adjustString( source ), m_comparator.m_str );
8853- }
8854-
8855-
8856- EndsWithMatcher::EndsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "ends with"_sr, comparator ) {}
8857-
8858- bool EndsWithMatcher::match( std::string const& source ) const {
8859- return endsWith( m_comparator.adjustString( source ), m_comparator.m_str );
8860- }
8861-
8862-
8863-
8864- RegexMatcher::RegexMatcher(std::string regex, CaseSensitive caseSensitivity): m_regex(CATCH_MOVE(regex)), m_caseSensitivity(caseSensitivity) {}
8865-
8866- bool RegexMatcher::match(std::string const& matchee) const {
8867- auto flags = std::regex::ECMAScript; // ECMAScript is the default syntax option anyway
8868- if (m_caseSensitivity == CaseSensitive::No) {
8869- flags |= std::regex::icase;
8870- }
8871- auto reg = std::regex(m_regex, flags);
8872- return std::regex_match(matchee, reg);
8873- }
8874-
8875- std::string RegexMatcher::describe() const {
8876- return "matches " + ::Catch::Detail::stringify(m_regex) + ((m_caseSensitivity == CaseSensitive::Yes)? " case sensitively" : " case insensitively");
8877- }
8878-
8879-
8880- StringEqualsMatcher Equals( std::string const& str, CaseSensitive caseSensitivity ) {
8881- return StringEqualsMatcher( CasedString( str, caseSensitivity) );
8882- }
8883- StringContainsMatcher ContainsSubstring( std::string const& str, CaseSensitive caseSensitivity ) {
8884- return StringContainsMatcher( CasedString( str, caseSensitivity) );
8885- }
8886- EndsWithMatcher EndsWith( std::string const& str, CaseSensitive caseSensitivity ) {
8887- return EndsWithMatcher( CasedString( str, caseSensitivity) );
8888- }
8889- StartsWithMatcher StartsWith( std::string const& str, CaseSensitive caseSensitivity ) {
8890- return StartsWithMatcher( CasedString( str, caseSensitivity) );
8891- }
8892-
8893- RegexMatcher Matches(std::string const& regex, CaseSensitive caseSensitivity) {
8894- return RegexMatcher(regex, caseSensitivity);
8895- }
8896-
8897-} // namespace Matchers
8898-} // namespace Catch
8899-
8900-
8901-
8902-namespace Catch {
8903-namespace Matchers {
8904- MatcherGenericBase::~MatcherGenericBase() = default;
8905-
8906- namespace Detail {
8907-
8908- std::string describe_multi_matcher(StringRef combine, std::string const* descriptions_begin, std::string const* descriptions_end) {
8909- std::string description;
8910- std::size_t combined_size = 4;
8911- for ( auto desc = descriptions_begin; desc != descriptions_end; ++desc ) {
8912- combined_size += desc->size();
8913- }
8914- combined_size += static_cast<size_t>(descriptions_end - descriptions_begin - 1) * combine.size();
8915-
8916- description.reserve(combined_size);
8917-
8918- description += "( ";
8919- bool first = true;
8920- for( auto desc = descriptions_begin; desc != descriptions_end; ++desc ) {
8921- if( first )
8922- first = false;
8923- else
8924- description += combine;
8925- description += *desc;
8926- }
8927- description += " )";
8928- return description;
8929- }
8930-
8931- } // namespace Detail
8932-} // namespace Matchers
8933-} // namespace Catch
8934-
8935-
8936-
8937-
8938-namespace Catch {
8939-
8940- // This is the general overload that takes a any string matcher
8941- // There is another overload, in catch_assertionhandler.h/.cpp, that only takes a string and infers
8942- // the Equals matcher (so the header does not mention matchers)
8943- void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher ) {
8944- std::string exceptionMessage = Catch::translateActiveException();
8945- MatchExpr<std::string, StringMatcher const&> expr( CATCH_MOVE(exceptionMessage), matcher );
8946- handler.handleExpr( expr );
8947- }
8948-
8949-} // namespace Catch
8950-
8951-
8952-
8953-#include <ostream>
8954-
8955-namespace Catch {
8956-
8957- AutomakeReporter::~AutomakeReporter() = default;
8958-
8959- void AutomakeReporter::testCaseEnded(TestCaseStats const& _testCaseStats) {
8960- // Possible values to emit are PASS, XFAIL, SKIP, FAIL, XPASS and ERROR.
8961- m_stream << ":test-result: ";
8962- if ( _testCaseStats.totals.testCases.skipped > 0 ) {
8963- m_stream << "SKIP";
8964- } else if (_testCaseStats.totals.assertions.allPassed()) {
8965- m_stream << "PASS";
8966- } else if (_testCaseStats.totals.assertions.allOk()) {
8967- m_stream << "XFAIL";
8968- } else {
8969- m_stream << "FAIL";
8970- }
8971- m_stream << ' ' << _testCaseStats.testInfo->name << '\n';
8972- StreamingReporterBase::testCaseEnded(_testCaseStats);
8973- }
8974-
8975- void AutomakeReporter::skipTest(TestCaseInfo const& testInfo) {
8976- m_stream << ":test-result: SKIP " << testInfo.name << '\n';
8977- }
8978-
8979-} // end namespace Catch
8980-
8981-
8982-
8983-
8984-
8985-
8986-namespace Catch {
8987- ReporterBase::ReporterBase( ReporterConfig&& config ):
8988- IEventListener( config.fullConfig() ),
8989- m_wrapped_stream( CATCH_MOVE(config).takeStream() ),
8990- m_stream( m_wrapped_stream->stream() ),
8991- m_colour( makeColourImpl( config.colourMode(), m_wrapped_stream.get() ) ),
8992- m_customOptions( config.customOptions() )
8993- {}
8994-
8995- ReporterBase::~ReporterBase() = default;
8996-
8997- void ReporterBase::listReporters(
8998- std::vector<ReporterDescription> const& descriptions ) {
8999- defaultListReporters(m_stream, descriptions, m_config->verbosity());
9000- }
9001-
9002- void ReporterBase::listListeners(
9003- std::vector<ListenerDescription> const& descriptions ) {
9004- defaultListListeners( m_stream, descriptions );
9005- }
9006-
9007- void ReporterBase::listTests(std::vector<TestCaseHandle> const& tests) {
9008- defaultListTests(m_stream,
9009- m_colour.get(),
9010- tests,
9011- m_config->hasTestFilters(),
9012- m_config->verbosity());
9013- }
9014-
9015- void ReporterBase::listTags(std::vector<TagInfo> const& tags) {
9016- defaultListTags( m_stream, tags, m_config->hasTestFilters() );
9017- }
9018-
9019-} // namespace Catch
9020-
9021-
9022-
9023-
9024-#include <ostream>
9025-
9026-namespace Catch {
9027-namespace {
9028-
9029- // Colour::LightGrey
9030- static constexpr Colour::Code compactDimColour = Colour::FileName;
9031-
9032-#ifdef CATCH_PLATFORM_MAC
9033- static constexpr Catch::StringRef compactFailedString = "FAILED"_sr;
9034- static constexpr Catch::StringRef compactPassedString = "PASSED"_sr;
9035-#else
9036- static constexpr Catch::StringRef compactFailedString = "failed"_sr;
9037- static constexpr Catch::StringRef compactPassedString = "passed"_sr;
9038-#endif
9039-
9040-// Implementation of CompactReporter formatting
9041-class AssertionPrinter {
9042-public:
9043- AssertionPrinter& operator= (AssertionPrinter const&) = delete;
9044- AssertionPrinter(AssertionPrinter const&) = delete;
9045- AssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages, ColourImpl* colourImpl_)
9046- : stream(_stream)
9047- , result(_stats.assertionResult)
9048- , messages(_stats.infoMessages)
9049- , itMessage(_stats.infoMessages.begin())
9050- , printInfoMessages(_printInfoMessages)
9051- , colourImpl(colourImpl_)
9052- {}
9053-
9054- void print() {
9055- printSourceInfo();
9056-
9057- itMessage = messages.begin();
9058-
9059- switch (result.getResultType()) {
9060- case ResultWas::Ok:
9061- printResultType(Colour::ResultSuccess, compactPassedString);
9062- printOriginalExpression();
9063- printReconstructedExpression();
9064- if (!result.hasExpression())
9065- printRemainingMessages(Colour::None);
9066- else
9067- printRemainingMessages();
9068- break;
9069- case ResultWas::ExpressionFailed:
9070- if (result.isOk())
9071- printResultType(Colour::ResultSuccess, compactFailedString + " - but was ok"_sr);
9072- else
9073- printResultType(Colour::Error, compactFailedString);
9074- printOriginalExpression();
9075- printReconstructedExpression();
9076- printRemainingMessages();
9077- break;
9078- case ResultWas::ThrewException:
9079- printResultType(Colour::Error, compactFailedString);
9080- printIssue("unexpected exception with message:");
9081- printMessage();
9082- printExpressionWas();
9083- printRemainingMessages();
9084- break;
9085- case ResultWas::FatalErrorCondition:
9086- printResultType(Colour::Error, compactFailedString);
9087- printIssue("fatal error condition with message:");
9088- printMessage();
9089- printExpressionWas();
9090- printRemainingMessages();
9091- break;
9092- case ResultWas::DidntThrowException:
9093- printResultType(Colour::Error, compactFailedString);
9094- printIssue("expected exception, got none");
9095- printExpressionWas();
9096- printRemainingMessages();
9097- break;
9098- case ResultWas::Info:
9099- printResultType(Colour::None, "info"_sr);
9100- printMessage();
9101- printRemainingMessages();
9102- break;
9103- case ResultWas::Warning:
9104- printResultType(Colour::None, "warning"_sr);
9105- printMessage();
9106- printRemainingMessages();
9107- break;
9108- case ResultWas::ExplicitFailure:
9109- printResultType(Colour::Error, compactFailedString);
9110- printIssue("explicitly");
9111- printRemainingMessages(Colour::None);
9112- break;
9113- case ResultWas::ExplicitSkip:
9114- printResultType(Colour::Skip, "skipped"_sr);
9115- printMessage();
9116- printRemainingMessages();
9117- break;
9118- // These cases are here to prevent compiler warnings
9119- case ResultWas::Unknown:
9120- case ResultWas::FailureBit:
9121- case ResultWas::Exception:
9122- printResultType(Colour::Error, "** internal error **");
9123- break;
9124- }
9125- }
9126-
9127-private:
9128- void printSourceInfo() const {
9129- stream << colourImpl->guardColour( Colour::FileName )
9130- << result.getSourceInfo() << ':';
9131- }
9132-
9133- void printResultType(Colour::Code colour, StringRef passOrFail) const {
9134- if (!passOrFail.empty()) {
9135- stream << colourImpl->guardColour(colour) << ' ' << passOrFail;
9136- stream << ':';
9137- }
9138- }
9139-
9140- void printIssue(char const* issue) const {
9141- stream << ' ' << issue;
9142- }
9143-
9144- void printExpressionWas() {
9145- if (result.hasExpression()) {
9146- stream << ';';
9147- {
9148- stream << colourImpl->guardColour(compactDimColour) << " expression was:";
9149- }
9150- printOriginalExpression();
9151- }
9152- }
9153-
9154- void printOriginalExpression() const {
9155- if (result.hasExpression()) {
9156- stream << ' ' << result.getExpression();
9157- }
9158- }
9159-
9160- void printReconstructedExpression() const {
9161- if (result.hasExpandedExpression()) {
9162- stream << colourImpl->guardColour(compactDimColour) << " for: ";
9163- stream << result.getExpandedExpression();
9164- }
9165- }
9166-
9167- void printMessage() {
9168- if (itMessage != messages.end()) {
9169- stream << " '" << itMessage->message << '\'';
9170- ++itMessage;
9171- }
9172- }
9173-
9174- void printRemainingMessages(Colour::Code colour = compactDimColour) {
9175- if (itMessage == messages.end())
9176- return;
9177-
9178- const auto itEnd = messages.cend();
9179- const auto N = static_cast<std::size_t>(itEnd - itMessage);
9180-
9181- stream << colourImpl->guardColour( colour ) << " with "
9182- << pluralise( N, "message"_sr ) << ':';
9183-
9184- while (itMessage != itEnd) {
9185- // If this assertion is a warning ignore any INFO messages
9186- if (printInfoMessages || itMessage->type != ResultWas::Info) {
9187- printMessage();
9188- if (itMessage != itEnd) {
9189- stream << colourImpl->guardColour(compactDimColour) << " and";
9190- }
9191- continue;
9192- }
9193- ++itMessage;
9194- }
9195- }
9196-
9197-private:
9198- std::ostream& stream;
9199- AssertionResult const& result;
9200- std::vector<MessageInfo> const& messages;
9201- std::vector<MessageInfo>::const_iterator itMessage;
9202- bool printInfoMessages;
9203- ColourImpl* colourImpl;
9204-};
9205-
9206-} // anon namespace
9207-
9208- std::string CompactReporter::getDescription() {
9209- return "Reports test results on a single line, suitable for IDEs";
9210- }
9211-
9212- void CompactReporter::noMatchingTestCases( StringRef unmatchedSpec ) {
9213- m_stream << "No test cases matched '" << unmatchedSpec << "'\n";
9214- }
9215-
9216- void CompactReporter::testRunStarting( TestRunInfo const& ) {
9217- if ( m_config->testSpec().hasFilters() ) {
9218- m_stream << m_colour->guardColour( Colour::BrightYellow )
9219- << "Filters: "
9220- << m_config->testSpec()
9221- << '\n';
9222- }
9223- m_stream << "RNG seed: " << getSeed() << '\n'
9224- << std::flush;
9225- }
9226-
9227- void CompactReporter::assertionEnded( AssertionStats const& _assertionStats ) {
9228- AssertionResult const& result = _assertionStats.assertionResult;
9229-
9230- bool printInfoMessages = true;
9231-
9232- // Drop out if result was successful and we're not printing those
9233- if( !m_config->includeSuccessfulResults() && result.isOk() ) {
9234- if( result.getResultType() != ResultWas::Warning && result.getResultType() != ResultWas::ExplicitSkip )
9235- return;
9236- printInfoMessages = false;
9237- }
9238-
9239- AssertionPrinter printer( m_stream, _assertionStats, printInfoMessages, m_colour.get() );
9240- printer.print();
9241-
9242- m_stream << '\n' << std::flush;
9243- }
9244-
9245- void CompactReporter::sectionEnded(SectionStats const& _sectionStats) {
9246- double dur = _sectionStats.durationInSeconds;
9247- if ( shouldShowDuration( *m_config, dur ) ) {
9248- m_stream << getFormattedDuration( dur ) << " s: " << _sectionStats.sectionInfo.name << '\n' << std::flush;
9249- }
9250- }
9251-
9252- void CompactReporter::testRunEnded( TestRunStats const& _testRunStats ) {
9253- printTestRunTotals( m_stream, *m_colour, _testRunStats.totals );
9254- m_stream << "\n\n" << std::flush;
9255- StreamingReporterBase::testRunEnded( _testRunStats );
9256- }
9257-
9258- CompactReporter::~CompactReporter() = default;
9259-
9260-} // end namespace Catch
9261-
9262-
9263-
9264-
9265-#include <cstdio>
9266-
9267-#if defined(_MSC_VER)
9268-#pragma warning(push)
9269-#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch
9270- // Note that 4062 (not all labels are handled and default is missing) is enabled
9271-#endif
9272-
9273-#if defined(__clang__)
9274-# pragma clang diagnostic push
9275-// For simplicity, benchmarking-only helpers are always enabled
9276-# pragma clang diagnostic ignored "-Wunused-function"
9277-#endif
9278-
9279-
9280-
9281-namespace Catch {
9282-
9283-namespace {
9284-
9285-// Formatter impl for ConsoleReporter
9286-class ConsoleAssertionPrinter {
9287-public:
9288- ConsoleAssertionPrinter& operator= (ConsoleAssertionPrinter const&) = delete;
9289- ConsoleAssertionPrinter(ConsoleAssertionPrinter const&) = delete;
9290- ConsoleAssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, ColourImpl* colourImpl_, bool _printInfoMessages)
9291- : stream(_stream),
9292- stats(_stats),
9293- result(_stats.assertionResult),
9294- colour(Colour::None),
9295- messages(_stats.infoMessages),
9296- colourImpl(colourImpl_),
9297- printInfoMessages(_printInfoMessages) {
9298- switch (result.getResultType()) {
9299- case ResultWas::Ok:
9300- colour = Colour::Success;
9301- passOrFail = "PASSED"_sr;
9302- //if( result.hasMessage() )
9303- if (messages.size() == 1)
9304- messageLabel = "with message"_sr;
9305- if (messages.size() > 1)
9306- messageLabel = "with messages"_sr;
9307- break;
9308- case ResultWas::ExpressionFailed:
9309- if (result.isOk()) {
9310- colour = Colour::Success;
9311- passOrFail = "FAILED - but was ok"_sr;
9312- } else {
9313- colour = Colour::Error;
9314- passOrFail = "FAILED"_sr;
9315- }
9316- if (messages.size() == 1)
9317- messageLabel = "with message"_sr;
9318- if (messages.size() > 1)
9319- messageLabel = "with messages"_sr;
9320- break;
9321- case ResultWas::ThrewException:
9322- colour = Colour::Error;
9323- passOrFail = "FAILED"_sr;
9324- // todo switch
9325- switch (messages.size()) { case 0:
9326- messageLabel = "due to unexpected exception with "_sr;
9327- break;
9328- case 1:
9329- messageLabel = "due to unexpected exception with message"_sr;
9330- break;
9331- default:
9332- messageLabel = "due to unexpected exception with messages"_sr;
9333- break;
9334- }
9335- break;
9336- case ResultWas::FatalErrorCondition:
9337- colour = Colour::Error;
9338- passOrFail = "FAILED"_sr;
9339- messageLabel = "due to a fatal error condition"_sr;
9340- break;
9341- case ResultWas::DidntThrowException:
9342- colour = Colour::Error;
9343- passOrFail = "FAILED"_sr;
9344- messageLabel = "because no exception was thrown where one was expected"_sr;
9345- break;
9346- case ResultWas::Info:
9347- messageLabel = "info"_sr;
9348- break;
9349- case ResultWas::Warning:
9350- messageLabel = "warning"_sr;
9351- break;
9352- case ResultWas::ExplicitFailure:
9353- passOrFail = "FAILED"_sr;
9354- colour = Colour::Error;
9355- if (messages.size() == 1)
9356- messageLabel = "explicitly with message"_sr;
9357- if (messages.size() > 1)
9358- messageLabel = "explicitly with messages"_sr;
9359- break;
9360- case ResultWas::ExplicitSkip:
9361- colour = Colour::Skip;
9362- passOrFail = "SKIPPED"_sr;
9363- if (messages.size() == 1)
9364- messageLabel = "explicitly with message"_sr;
9365- if (messages.size() > 1)
9366- messageLabel = "explicitly with messages"_sr;
9367- break;
9368- // These cases are here to prevent compiler warnings
9369- case ResultWas::Unknown:
9370- case ResultWas::FailureBit:
9371- case ResultWas::Exception:
9372- passOrFail = "** internal error **"_sr;
9373- colour = Colour::Error;
9374- break;
9375- }
9376- }
9377-
9378- void print() const {
9379- printSourceInfo();
9380- if (stats.totals.assertions.total() > 0) {
9381- printResultType();
9382- printOriginalExpression();
9383- printReconstructedExpression();
9384- } else {
9385- stream << '\n';
9386- }
9387- printMessage();
9388- }
9389-
9390-private:
9391- void printResultType() const {
9392- if (!passOrFail.empty()) {
9393- stream << colourImpl->guardColour(colour) << passOrFail << ":\n";
9394- }
9395- }
9396- void printOriginalExpression() const {
9397- if (result.hasExpression()) {
9398- stream << colourImpl->guardColour( Colour::OriginalExpression )
9399- << " " << result.getExpressionInMacro() << '\n';
9400- }
9401- }
9402- void printReconstructedExpression() const {
9403- if (result.hasExpandedExpression()) {
9404- stream << "with expansion:\n";
9405- stream << colourImpl->guardColour( Colour::ReconstructedExpression )
9406- << TextFlow::Column( result.getExpandedExpression() )
9407- .indent( 2 )
9408- << '\n';
9409- }
9410- }
9411- void printMessage() const {
9412- if (!messageLabel.empty())
9413- stream << messageLabel << ':' << '\n';
9414- for (auto const& msg : messages) {
9415- // If this assertion is a warning ignore any INFO messages
9416- if (printInfoMessages || msg.type != ResultWas::Info)
9417- stream << TextFlow::Column(msg.message).indent(2) << '\n';
9418- }
9419- }
9420- void printSourceInfo() const {
9421- stream << colourImpl->guardColour( Colour::FileName )
9422- << result.getSourceInfo() << ": ";
9423- }
9424-
9425- std::ostream& stream;
9426- AssertionStats const& stats;
9427- AssertionResult const& result;
9428- Colour::Code colour;
9429- StringRef passOrFail;
9430- StringRef messageLabel;
9431- std::vector<MessageInfo> const& messages;
9432- ColourImpl* colourImpl;
9433- bool printInfoMessages;
9434-};
9435-
9436-std::size_t makeRatio( std::uint64_t number, std::uint64_t total ) {
9437- const auto ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number / total : 0;
9438- return (ratio == 0 && number > 0) ? 1 : static_cast<std::size_t>(ratio);
9439-}
9440-
9441-std::size_t&
9442-findMax( std::size_t& i, std::size_t& j, std::size_t& k, std::size_t& l ) {
9443- if (i > j && i > k && i > l)
9444- return i;
9445- else if (j > k && j > l)
9446- return j;
9447- else if (k > l)
9448- return k;
9449- else
9450- return l;
9451-}
9452-
9453-struct ColumnBreak {};
9454-struct RowBreak {};
9455-struct OutputFlush {};
9456-
9457-class Duration {
9458- enum class Unit : uint8_t {
9459- Auto,
9460- Nanoseconds,
9461- Microseconds,
9462- Milliseconds,
9463- Seconds,
9464- Minutes
9465- };
9466- static const uint64_t s_nanosecondsInAMicrosecond = 1000;
9467- static const uint64_t s_nanosecondsInAMillisecond = 1000 * s_nanosecondsInAMicrosecond;
9468- static const uint64_t s_nanosecondsInASecond = 1000 * s_nanosecondsInAMillisecond;
9469- static const uint64_t s_nanosecondsInAMinute = 60 * s_nanosecondsInASecond;
9470-
9471- double m_inNanoseconds;
9472- Unit m_units;
9473-
9474-public:
9475- explicit Duration(double inNanoseconds, Unit units = Unit::Auto)
9476- : m_inNanoseconds(inNanoseconds),
9477- m_units(units) {
9478- if (m_units == Unit::Auto) {
9479- if (m_inNanoseconds < s_nanosecondsInAMicrosecond)
9480- m_units = Unit::Nanoseconds;
9481- else if (m_inNanoseconds < s_nanosecondsInAMillisecond)
9482- m_units = Unit::Microseconds;
9483- else if (m_inNanoseconds < s_nanosecondsInASecond)
9484- m_units = Unit::Milliseconds;
9485- else if (m_inNanoseconds < s_nanosecondsInAMinute)
9486- m_units = Unit::Seconds;
9487- else
9488- m_units = Unit::Minutes;
9489- }
9490-
9491- }
9492-
9493- auto value() const -> double {
9494- switch (m_units) {
9495- case Unit::Microseconds:
9496- return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMicrosecond);
9497- case Unit::Milliseconds:
9498- return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMillisecond);
9499- case Unit::Seconds:
9500- return m_inNanoseconds / static_cast<double>(s_nanosecondsInASecond);
9501- case Unit::Minutes:
9502- return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMinute);
9503- default:
9504- return m_inNanoseconds;
9505- }
9506- }
9507- StringRef unitsAsString() const {
9508- switch (m_units) {
9509- case Unit::Nanoseconds:
9510- return "ns"_sr;
9511- case Unit::Microseconds:
9512- return "us"_sr;
9513- case Unit::Milliseconds:
9514- return "ms"_sr;
9515- case Unit::Seconds:
9516- return "s"_sr;
9517- case Unit::Minutes:
9518- return "m"_sr;
9519- default:
9520- return "** internal error **"_sr;
9521- }
9522-
9523- }
9524- friend auto operator << (std::ostream& os, Duration const& duration) -> std::ostream& {
9525- return os << duration.value() << ' ' << duration.unitsAsString();
9526- }
9527-};
9528-} // end anon namespace
9529-
9530-enum class Justification : uint8_t {
9531- Left,
9532- Right
9533-};
9534-
9535-struct ColumnInfo {
9536- std::string name;
9537- std::size_t width;
9538- Justification justification;
9539-};
9540-
9541-class TablePrinter {
9542- std::ostream& m_os;
9543- std::vector<ColumnInfo> m_columnInfos;
9544- ReusableStringStream m_oss;
9545- int m_currentColumn = -1;
9546- bool m_isOpen = false;
9547-
9548-public:
9549- TablePrinter( std::ostream& os, std::vector<ColumnInfo> columnInfos )
9550- : m_os( os ),
9551- m_columnInfos( CATCH_MOVE( columnInfos ) ) {}
9552-
9553- auto columnInfos() const -> std::vector<ColumnInfo> const& {
9554- return m_columnInfos;
9555- }
9556-
9557- void open() {
9558- if (!m_isOpen) {
9559- m_isOpen = true;
9560- *this << RowBreak();
9561-
9562- TextFlow::Columns headerCols;
9563- for (auto const& info : m_columnInfos) {
9564- assert(info.width > 2);
9565- headerCols += TextFlow::Column(info.name).width(info.width - 2);
9566- headerCols += TextFlow::Spacer( 2 );
9567- }
9568- m_os << headerCols << '\n';
9569-
9570- m_os << lineOfChars('-') << '\n';
9571- }
9572- }
9573- void close() {
9574- if (m_isOpen) {
9575- *this << RowBreak();
9576- m_os << '\n' << std::flush;
9577- m_isOpen = false;
9578- }
9579- }
9580-
9581- template<typename T>
9582- friend TablePrinter& operator<< (TablePrinter& tp, T const& value) {
9583- tp.m_oss << value;
9584- return tp;
9585- }
9586-
9587- friend TablePrinter& operator<< (TablePrinter& tp, ColumnBreak) {
9588- auto colStr = tp.m_oss.str();
9589- const auto strSize = colStr.size();
9590- tp.m_oss.str("");
9591- tp.open();
9592- if (tp.m_currentColumn == static_cast<int>(tp.m_columnInfos.size() - 1)) {
9593- tp.m_currentColumn = -1;
9594- tp.m_os << '\n';
9595- }
9596- tp.m_currentColumn++;
9597-
9598- auto colInfo = tp.m_columnInfos[tp.m_currentColumn];
9599- auto padding = (strSize + 1 < colInfo.width)
9600- ? std::string(colInfo.width - (strSize + 1), ' ')
9601- : std::string();
9602- if (colInfo.justification == Justification::Left)
9603- tp.m_os << colStr << padding << ' ';
9604- else
9605- tp.m_os << padding << colStr << ' ';
9606- return tp;
9607- }
9608-
9609- friend TablePrinter& operator<< (TablePrinter& tp, RowBreak) {
9610- if (tp.m_currentColumn > 0) {
9611- tp.m_os << '\n';
9612- tp.m_currentColumn = -1;
9613- }
9614- return tp;
9615- }
9616-
9617- friend TablePrinter& operator<<(TablePrinter& tp, OutputFlush) {
9618- tp.m_os << std::flush;
9619- return tp;
9620- }
9621-};
9622-
9623-ConsoleReporter::ConsoleReporter(ReporterConfig&& config):
9624- StreamingReporterBase( CATCH_MOVE( config ) ),
9625- m_tablePrinter(Detail::make_unique<TablePrinter>(m_stream,
9626- [&config]() -> std::vector<ColumnInfo> {
9627- if (config.fullConfig()->benchmarkNoAnalysis())
9628- {
9629- return{
9630- { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 43, Justification::Left },
9631- { " samples", 14, Justification::Right },
9632- { " iterations", 14, Justification::Right },
9633- { " mean", 14, Justification::Right }
9634- };
9635- }
9636- else
9637- {
9638- return{
9639- { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 43, Justification::Left },
9640- { "samples mean std dev", 14, Justification::Right },
9641- { "iterations low mean low std dev", 14, Justification::Right },
9642- { "est run time high mean high std dev", 14, Justification::Right }
9643- };
9644- }
9645- }())) {
9646- m_preferences.shouldReportAllAssertionStarts = false;
9647-}
9648-
9649-ConsoleReporter::~ConsoleReporter() = default;
9650-
9651-std::string ConsoleReporter::getDescription() {
9652- return "Reports test results as plain lines of text";
9653-}
9654-
9655-void ConsoleReporter::noMatchingTestCases( StringRef unmatchedSpec ) {
9656- m_stream << "No test cases matched '" << unmatchedSpec << "'\n";
9657-}
9658-
9659-void ConsoleReporter::reportInvalidTestSpec( StringRef arg ) {
9660- m_stream << "Invalid Filter: " << arg << '\n';
9661-}
9662-
9663-void ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) {
9664- AssertionResult const& result = _assertionStats.assertionResult;
9665-
9666- bool includeResults = m_config->includeSuccessfulResults() || !result.isOk();
9667-
9668- // Drop out if result was successful but we're not printing them.
9669- // TODO: Make configurable whether skips should be printed
9670- if (!includeResults && result.getResultType() != ResultWas::Warning && result.getResultType() != ResultWas::ExplicitSkip)
9671- return;
9672-
9673- lazyPrint();
9674-
9675- ConsoleAssertionPrinter printer(m_stream, _assertionStats, m_colour.get(), includeResults);
9676- printer.print();
9677- m_stream << '\n' << std::flush;
9678-}
9679-
9680-void ConsoleReporter::sectionStarting(SectionInfo const& _sectionInfo) {
9681- m_tablePrinter->close();
9682- m_headerPrinted = false;
9683- StreamingReporterBase::sectionStarting(_sectionInfo);
9684-}
9685-void ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) {
9686- m_tablePrinter->close();
9687- if (_sectionStats.missingAssertions) {
9688- lazyPrint();
9689- auto guard =
9690- m_colour->guardColour( Colour::ResultError ).engage( m_stream );
9691- if (m_sectionStack.size() > 1)
9692- m_stream << "\nNo assertions in section";
9693- else
9694- m_stream << "\nNo assertions in test case";
9695- m_stream << " '" << _sectionStats.sectionInfo.name << "'\n\n" << std::flush;
9696- }
9697- double dur = _sectionStats.durationInSeconds;
9698- if (shouldShowDuration(*m_config, dur)) {
9699- m_stream << getFormattedDuration(dur) << " s: " << _sectionStats.sectionInfo.name << '\n' << std::flush;
9700- }
9701- if (m_headerPrinted) {
9702- m_headerPrinted = false;
9703- }
9704- StreamingReporterBase::sectionEnded(_sectionStats);
9705-}
9706-
9707-void ConsoleReporter::benchmarkPreparing( StringRef name ) {
9708- lazyPrintWithoutClosingBenchmarkTable();
9709-
9710- auto nameCol = TextFlow::Column( static_cast<std::string>( name ) )
9711- .width( m_tablePrinter->columnInfos()[0].width - 2 );
9712-
9713- bool firstLine = true;
9714- for (auto line : nameCol) {
9715- if (!firstLine)
9716- (*m_tablePrinter) << ColumnBreak() << ColumnBreak() << ColumnBreak();
9717- else
9718- firstLine = false;
9719-
9720- (*m_tablePrinter) << line << ColumnBreak();
9721- }
9722-}
9723-
9724-void ConsoleReporter::benchmarkStarting(BenchmarkInfo const& info) {
9725- (*m_tablePrinter) << info.samples << ColumnBreak()
9726- << info.iterations << ColumnBreak();
9727- if ( !m_config->benchmarkNoAnalysis() ) {
9728- ( *m_tablePrinter )
9729- << Duration( info.estimatedDuration ) << ColumnBreak();
9730- }
9731- ( *m_tablePrinter ) << OutputFlush{};
9732-}
9733-void ConsoleReporter::benchmarkEnded(BenchmarkStats<> const& stats) {
9734- if (m_config->benchmarkNoAnalysis())
9735- {
9736- (*m_tablePrinter) << Duration(stats.mean.point.count()) << ColumnBreak();
9737- }
9738- else
9739- {
9740- (*m_tablePrinter) << ColumnBreak()
9741- << Duration(stats.mean.point.count()) << ColumnBreak()
9742- << Duration(stats.mean.lower_bound.count()) << ColumnBreak()
9743- << Duration(stats.mean.upper_bound.count()) << ColumnBreak() << ColumnBreak()
9744- << Duration(stats.standardDeviation.point.count()) << ColumnBreak()
9745- << Duration(stats.standardDeviation.lower_bound.count()) << ColumnBreak()
9746- << Duration(stats.standardDeviation.upper_bound.count()) << ColumnBreak() << ColumnBreak() << ColumnBreak() << ColumnBreak() << ColumnBreak();
9747- }
9748-}
9749-
9750-void ConsoleReporter::benchmarkFailed( StringRef error ) {
9751- auto guard = m_colour->guardColour( Colour::Red ).engage( m_stream );
9752- (*m_tablePrinter)
9753- << "Benchmark failed (" << error << ')'
9754- << ColumnBreak() << RowBreak();
9755-}
9756-
9757-void ConsoleReporter::testCaseEnded(TestCaseStats const& _testCaseStats) {
9758- m_tablePrinter->close();
9759- StreamingReporterBase::testCaseEnded(_testCaseStats);
9760- m_headerPrinted = false;
9761-}
9762-void ConsoleReporter::testRunEnded(TestRunStats const& _testRunStats) {
9763- printTotalsDivider(_testRunStats.totals);
9764- printTestRunTotals( m_stream, *m_colour, _testRunStats.totals );
9765- m_stream << '\n' << std::flush;
9766- StreamingReporterBase::testRunEnded(_testRunStats);
9767-}
9768-void ConsoleReporter::testRunStarting(TestRunInfo const& _testRunInfo) {
9769- StreamingReporterBase::testRunStarting(_testRunInfo);
9770- if ( m_config->testSpec().hasFilters() ) {
9771- m_stream << m_colour->guardColour( Colour::BrightYellow ) << "Filters: "
9772- << m_config->testSpec() << '\n';
9773- }
9774- m_stream << "Randomness seeded to: " << getSeed() << '\n'
9775- << std::flush;
9776-}
9777-
9778-void ConsoleReporter::lazyPrint() {
9779-
9780- m_tablePrinter->close();
9781- lazyPrintWithoutClosingBenchmarkTable();
9782-}
9783-
9784-void ConsoleReporter::lazyPrintWithoutClosingBenchmarkTable() {
9785-
9786- if ( !m_testRunInfoPrinted ) {
9787- lazyPrintRunInfo();
9788- }
9789- if (!m_headerPrinted) {
9790- printTestCaseAndSectionHeader();
9791- m_headerPrinted = true;
9792- }
9793-}
9794-void ConsoleReporter::lazyPrintRunInfo() {
9795- m_stream << '\n'
9796- << lineOfChars( '~' ) << '\n'
9797- << m_colour->guardColour( Colour::SecondaryText )
9798- << currentTestRunInfo.name << " is a Catch2 v" << libraryVersion()
9799- << " host application.\n"
9800- << "Run with -? for options\n\n";
9801-
9802- m_testRunInfoPrinted = true;
9803-}
9804-void ConsoleReporter::printTestCaseAndSectionHeader() {
9805- assert(!m_sectionStack.empty());
9806- printOpenHeader(currentTestCaseInfo->name);
9807-
9808- if (m_sectionStack.size() > 1) {
9809- auto guard = m_colour->guardColour( Colour::Headers ).engage( m_stream );
9810-
9811- auto
9812- it = m_sectionStack.begin() + 1, // Skip first section (test case)
9813- itEnd = m_sectionStack.end();
9814- for (; it != itEnd; ++it)
9815- printHeaderString(it->name, 2);
9816- }
9817-
9818- SourceLineInfo lineInfo = m_sectionStack.back().lineInfo;
9819-
9820-
9821- m_stream << lineOfChars( '-' ) << '\n'
9822- << m_colour->guardColour( Colour::FileName ) << lineInfo << '\n'
9823- << lineOfChars( '.' ) << "\n\n"
9824- << std::flush;
9825-}
9826-
9827-void ConsoleReporter::printClosedHeader(std::string const& _name) {
9828- printOpenHeader(_name);
9829- m_stream << lineOfChars('.') << '\n';
9830-}
9831-void ConsoleReporter::printOpenHeader(std::string const& _name) {
9832- m_stream << lineOfChars('-') << '\n';
9833- {
9834- auto guard = m_colour->guardColour( Colour::Headers ).engage( m_stream );
9835- printHeaderString(_name);
9836- }
9837-}
9838-
9839-void ConsoleReporter::printHeaderString(std::string const& _string, std::size_t indent) {
9840- // We want to get a bit fancy with line breaking here, so that subsequent
9841- // lines start after ":" if one is present, e.g.
9842- // ```
9843- // blablabla: Fancy
9844- // linebreaking
9845- // ```
9846- // but we also want to avoid problems with overly long indentation causing
9847- // the text to take up too many lines, e.g.
9848- // ```
9849- // blablabla: F
9850- // a
9851- // n
9852- // c
9853- // y
9854- // .
9855- // .
9856- // .
9857- // ```
9858- // So we limit the prefix indentation check to first quarter of the possible
9859- // width
9860- std::size_t idx = _string.find( ": " );
9861- if ( idx != std::string::npos && idx < CATCH_CONFIG_CONSOLE_WIDTH / 4 ) {
9862- idx += 2;
9863- } else {
9864- idx = 0;
9865- }
9866- m_stream << TextFlow::Column( _string )
9867- .indent( indent + idx )
9868- .initialIndent( indent )
9869- << '\n';
9870-}
9871-
9872-void ConsoleReporter::printTotalsDivider(Totals const& totals) {
9873- if (totals.testCases.total() > 0) {
9874- std::size_t failedRatio = makeRatio(totals.testCases.failed, totals.testCases.total());
9875- std::size_t failedButOkRatio = makeRatio(totals.testCases.failedButOk, totals.testCases.total());
9876- std::size_t passedRatio = makeRatio(totals.testCases.passed, totals.testCases.total());
9877- std::size_t skippedRatio = makeRatio(totals.testCases.skipped, totals.testCases.total());
9878- while (failedRatio + failedButOkRatio + passedRatio + skippedRatio < CATCH_CONFIG_CONSOLE_WIDTH - 1)
9879- findMax(failedRatio, failedButOkRatio, passedRatio, skippedRatio)++;
9880- while (failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH - 1)
9881- findMax(failedRatio, failedButOkRatio, passedRatio, skippedRatio)--;
9882-
9883- m_stream << m_colour->guardColour( Colour::Error )
9884- << std::string( failedRatio, '=' )
9885- << m_colour->guardColour( Colour::ResultExpectedFailure )
9886- << std::string( failedButOkRatio, '=' );
9887- if ( totals.testCases.allPassed() ) {
9888- m_stream << m_colour->guardColour( Colour::ResultSuccess )
9889- << std::string( passedRatio, '=' );
9890- } else {
9891- m_stream << m_colour->guardColour( Colour::Success )
9892- << std::string( passedRatio, '=' );
9893- }
9894- m_stream << m_colour->guardColour( Colour::Skip )
9895- << std::string( skippedRatio, '=' );
9896- } else {
9897- m_stream << m_colour->guardColour( Colour::Warning )
9898- << std::string( CATCH_CONFIG_CONSOLE_WIDTH - 1, '=' );
9899- }
9900- m_stream << '\n';
9901-}
9902-
9903-} // end namespace Catch
9904-
9905-#if defined(_MSC_VER)
9906-#pragma warning(pop)
9907-#endif
9908-
9909-#if defined(__clang__)
9910-# pragma clang diagnostic pop
9911-#endif
9912-
9913-
9914-
9915-
9916-#include <algorithm>
9917-#include <cassert>
9918-
9919-namespace Catch {
9920- namespace {
9921- struct BySectionInfo {
9922- BySectionInfo( SectionInfo const& other ): m_other( other ) {}
9923- BySectionInfo( BySectionInfo const& other ) = default;
9924- bool operator()(
9925- Detail::unique_ptr<CumulativeReporterBase::SectionNode> const&
9926- node ) const {
9927- return (
9928- ( node->stats.sectionInfo.name == m_other.name ) &&
9929- ( node->stats.sectionInfo.lineInfo == m_other.lineInfo ) );
9930- }
9931- void operator=( BySectionInfo const& ) = delete;
9932-
9933- private:
9934- SectionInfo const& m_other;
9935- };
9936-
9937- } // namespace
9938-
9939- namespace Detail {
9940- AssertionOrBenchmarkResult::AssertionOrBenchmarkResult(
9941- AssertionStats const& assertion ):
9942- m_assertion( assertion ) {}
9943-
9944- AssertionOrBenchmarkResult::AssertionOrBenchmarkResult(
9945- BenchmarkStats<> const& benchmark ):
9946- m_benchmark( benchmark ) {}
9947-
9948- bool AssertionOrBenchmarkResult::isAssertion() const {
9949- return m_assertion.some();
9950- }
9951- bool AssertionOrBenchmarkResult::isBenchmark() const {
9952- return m_benchmark.some();
9953- }
9954-
9955- AssertionStats const& AssertionOrBenchmarkResult::asAssertion() const {
9956- assert(m_assertion.some());
9957-
9958- return *m_assertion;
9959- }
9960- BenchmarkStats<> const& AssertionOrBenchmarkResult::asBenchmark() const {
9961- assert(m_benchmark.some());
9962-
9963- return *m_benchmark;
9964- }
9965-
9966- }
9967-
9968- CumulativeReporterBase::~CumulativeReporterBase() = default;
9969-
9970- void CumulativeReporterBase::benchmarkEnded(BenchmarkStats<> const& benchmarkStats) {
9971- m_sectionStack.back()->assertionsAndBenchmarks.emplace_back(benchmarkStats);
9972- }
9973-
9974- void
9975- CumulativeReporterBase::sectionStarting( SectionInfo const& sectionInfo ) {
9976- // We need a copy, because SectionStats expect to take ownership
9977- SectionStats incompleteStats( SectionInfo(sectionInfo), Counts(), 0, false );
9978- SectionNode* node;
9979- if ( m_sectionStack.empty() ) {
9980- if ( !m_rootSection ) {
9981- m_rootSection =
9982- Detail::make_unique<SectionNode>( incompleteStats );
9983- }
9984- node = m_rootSection.get();
9985- } else {
9986- SectionNode& parentNode = *m_sectionStack.back();
9987- auto it = std::find_if( parentNode.childSections.begin(),
9988- parentNode.childSections.end(),
9989- BySectionInfo( sectionInfo ) );
9990- if ( it == parentNode.childSections.end() ) {
9991- auto newNode =
9992- Detail::make_unique<SectionNode>( incompleteStats );
9993- node = newNode.get();
9994- parentNode.childSections.push_back( CATCH_MOVE( newNode ) );
9995- } else {
9996- node = it->get();
9997- }
9998- }
9999-
10000- m_deepestSection = node;
10001- m_sectionStack.push_back( node );
10002- }
10003-
10004- void CumulativeReporterBase::assertionEnded(
10005- AssertionStats const& assertionStats ) {
10006- assert( !m_sectionStack.empty() );
10007- // AssertionResult holds a pointer to a temporary DecomposedExpression,
10008- // which getExpandedExpression() calls to build the expression string.
10009- // Our section stack copy of the assertionResult will likely outlive the
10010- // temporary, so it must be expanded or discarded now to avoid calling
10011- // a destroyed object later.
10012- if ( m_shouldStoreFailedAssertions &&
10013- !assertionStats.assertionResult.isOk() ) {
10014- static_cast<void>(
10015- assertionStats.assertionResult.getExpandedExpression() );
10016- }
10017- if ( m_shouldStoreSuccesfulAssertions &&
10018- assertionStats.assertionResult.isOk() ) {
10019- static_cast<void>(
10020- assertionStats.assertionResult.getExpandedExpression() );
10021- }
10022- SectionNode& sectionNode = *m_sectionStack.back();
10023- sectionNode.assertionsAndBenchmarks.emplace_back( assertionStats );
10024- }
10025-
10026- void CumulativeReporterBase::sectionEnded( SectionStats const& sectionStats ) {
10027- assert( !m_sectionStack.empty() );
10028- SectionNode& node = *m_sectionStack.back();
10029- node.stats = sectionStats;
10030- m_sectionStack.pop_back();
10031- }
10032-
10033- void CumulativeReporterBase::testCaseEnded(
10034- TestCaseStats const& testCaseStats ) {
10035- auto node = Detail::make_unique<TestCaseNode>( testCaseStats );
10036- assert( m_sectionStack.size() == 0 );
10037- node->children.push_back( CATCH_MOVE(m_rootSection) );
10038- m_testCases.push_back( CATCH_MOVE(node) );
10039-
10040- assert( m_deepestSection );
10041- m_deepestSection->stdOut = testCaseStats.stdOut;
10042- m_deepestSection->stdErr = testCaseStats.stdErr;
10043- }
10044-
10045-
10046- void CumulativeReporterBase::testRunEnded( TestRunStats const& testRunStats ) {
10047- assert(!m_testRun && "CumulativeReporterBase assumes there can only be one test run");
10048- m_testRun = Detail::make_unique<TestRunNode>( testRunStats );
10049- m_testRun->children.swap( m_testCases );
10050- testRunEndedCumulative();
10051- }
10052-
10053- bool CumulativeReporterBase::SectionNode::hasAnyAssertions() const {
10054- return std::any_of(
10055- assertionsAndBenchmarks.begin(),
10056- assertionsAndBenchmarks.end(),
10057- []( Detail::AssertionOrBenchmarkResult const& res ) {
10058- return res.isAssertion();
10059- } );
10060- }
10061-
10062-} // end namespace Catch
10063-
10064-
10065-
10066-
10067-namespace Catch {
10068-
10069- void EventListenerBase::fatalErrorEncountered( StringRef ) {}
10070-
10071- void EventListenerBase::benchmarkPreparing( StringRef ) {}
10072- void EventListenerBase::benchmarkStarting( BenchmarkInfo const& ) {}
10073- void EventListenerBase::benchmarkEnded( BenchmarkStats<> const& ) {}
10074- void EventListenerBase::benchmarkFailed( StringRef ) {}
10075-
10076- void EventListenerBase::assertionStarting( AssertionInfo const& ) {}
10077-
10078- void EventListenerBase::assertionEnded( AssertionStats const& ) {}
10079- void EventListenerBase::listReporters(
10080- std::vector<ReporterDescription> const& ) {}
10081- void EventListenerBase::listListeners(
10082- std::vector<ListenerDescription> const& ) {}
10083- void EventListenerBase::listTests( std::vector<TestCaseHandle> const& ) {}
10084- void EventListenerBase::listTags( std::vector<TagInfo> const& ) {}
10085- void EventListenerBase::noMatchingTestCases( StringRef ) {}
10086- void EventListenerBase::reportInvalidTestSpec( StringRef ) {}
10087- void EventListenerBase::testRunStarting( TestRunInfo const& ) {}
10088- void EventListenerBase::testCaseStarting( TestCaseInfo const& ) {}
10089- void EventListenerBase::testCasePartialStarting(TestCaseInfo const&, uint64_t) {}
10090- void EventListenerBase::sectionStarting( SectionInfo const& ) {}
10091- void EventListenerBase::sectionEnded( SectionStats const& ) {}
10092- void EventListenerBase::testCasePartialEnded(TestCaseStats const&, uint64_t) {}
10093- void EventListenerBase::testCaseEnded( TestCaseStats const& ) {}
10094- void EventListenerBase::testRunEnded( TestRunStats const& ) {}
10095- void EventListenerBase::skipTest( TestCaseInfo const& ) {}
10096-} // namespace Catch
10097-
10098-
10099-
10100-
10101-#include <algorithm>
10102-#include <cfloat>
10103-#include <cmath>
10104-#include <cstdio>
10105-#include <ostream>
10106-#include <iomanip>
10107-
10108-namespace Catch {
10109-
10110- namespace {
10111- void listTestNamesOnly(std::ostream& out,
10112- std::vector<TestCaseHandle> const& tests) {
10113- for (auto const& test : tests) {
10114- auto const& testCaseInfo = test.getTestCaseInfo();
10115-
10116- if (startsWith(testCaseInfo.name, '#')) {
10117- out << '"' << testCaseInfo.name << '"';
10118- } else {
10119- out << testCaseInfo.name;
10120- }
10121-
10122- out << '\n';
10123- }
10124- out << std::flush;
10125- }
10126- } // end unnamed namespace
10127-
10128-
10129- // Because formatting using c++ streams is stateful, drop down to C is
10130- // required Alternatively we could use stringstream, but its performance
10131- // is... not good.
10132- std::string getFormattedDuration( double duration ) {
10133- // Max exponent + 1 is required to represent the whole part
10134- // + 1 for decimal point
10135- // + 3 for the 3 decimal places
10136- // + 1 for null terminator
10137- const std::size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1;
10138- char buffer[maxDoubleSize];
10139-
10140- // Save previous errno, to prevent sprintf from overwriting it
10141- ErrnoGuard guard;
10142-#ifdef _MSC_VER
10143- size_t printedLength = static_cast<size_t>(
10144- sprintf_s( buffer, "%.3f", duration ) );
10145-#else
10146- size_t printedLength = static_cast<size_t>(
10147- std::snprintf( buffer, maxDoubleSize, "%.3f", duration ) );
10148-#endif
10149- return std::string( buffer, printedLength );
10150- }
10151-
10152- bool shouldShowDuration( IConfig const& config, double duration ) {
10153- if ( config.showDurations() == ShowDurations::Always ) {
10154- return true;
10155- }
10156- if ( config.showDurations() == ShowDurations::Never ) {
10157- return false;
10158- }
10159- const double min = config.minDuration();
10160- return min >= 0 && duration >= min;
10161- }
10162-
10163- std::string serializeFilters( std::vector<std::string> const& filters ) {
10164- // We add a ' ' separator between each filter
10165- size_t serialized_size = filters.size() - 1;
10166- for (auto const& filter : filters) {
10167- serialized_size += filter.size();
10168- }
10169-
10170- std::string serialized;
10171- serialized.reserve(serialized_size);
10172- bool first = true;
10173-
10174- for (auto const& filter : filters) {
10175- if (!first) {
10176- serialized.push_back(' ');
10177- }
10178- first = false;
10179- serialized.append(filter);
10180- }
10181-
10182- return serialized;
10183- }
10184-
10185- std::ostream& operator<<( std::ostream& out, lineOfChars value ) {
10186- for ( size_t idx = 0; idx < CATCH_CONFIG_CONSOLE_WIDTH - 1; ++idx ) {
10187- out.put( value.c );
10188- }
10189- return out;
10190- }
10191-
10192- void
10193- defaultListReporters( std::ostream& out,
10194- std::vector<ReporterDescription> const& descriptions,
10195- Verbosity verbosity ) {
10196- out << "Available reporters:\n";
10197- const auto maxNameLen =
10198- std::max_element( descriptions.begin(),
10199- descriptions.end(),
10200- []( ReporterDescription const& lhs,
10201- ReporterDescription const& rhs ) {
10202- return lhs.name.size() < rhs.name.size();
10203- } )
10204- ->name.size();
10205-
10206- for ( auto const& desc : descriptions ) {
10207- if ( verbosity == Verbosity::Quiet ) {
10208- out << TextFlow::Column( desc.name )
10209- .indent( 2 )
10210- .width( 5 + maxNameLen )
10211- << '\n';
10212- } else {
10213- out << TextFlow::Column( desc.name + ':' )
10214- .indent( 2 )
10215- .width( 5 + maxNameLen ) +
10216- TextFlow::Column( desc.description )
10217- .initialIndent( 0 )
10218- .indent( 2 )
10219- .width( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen - 8 )
10220- << '\n';
10221- }
10222- }
10223- out << '\n' << std::flush;
10224- }
10225-
10226- void defaultListListeners( std::ostream& out,
10227- std::vector<ListenerDescription> const& descriptions ) {
10228- out << "Registered listeners:\n";
10229-
10230- if(descriptions.empty()) {
10231- return;
10232- }
10233-
10234- const auto maxNameLen =
10235- std::max_element( descriptions.begin(),
10236- descriptions.end(),
10237- []( ListenerDescription const& lhs,
10238- ListenerDescription const& rhs ) {
10239- return lhs.name.size() < rhs.name.size();
10240- } )
10241- ->name.size();
10242-
10243- for ( auto const& desc : descriptions ) {
10244- out << TextFlow::Column( static_cast<std::string>( desc.name ) +
10245- ':' )
10246- .indent( 2 )
10247- .width( maxNameLen + 5 ) +
10248- TextFlow::Column( desc.description )
10249- .initialIndent( 0 )
10250- .indent( 2 )
10251- .width( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen - 8 )
10252- << '\n';
10253- }
10254-
10255- out << '\n' << std::flush;
10256- }
10257-
10258- void defaultListTags( std::ostream& out,
10259- std::vector<TagInfo> const& tags,
10260- bool isFiltered ) {
10261- if ( isFiltered ) {
10262- out << "Tags for matching test cases:\n";
10263- } else {
10264- out << "All available tags:\n";
10265- }
10266-
10267- // minimum whitespace to pad tag counts, possibly overwritten below
10268- size_t maxTagCountLen = 2;
10269-
10270- // determine necessary padding for tag count column
10271- if ( ! tags.empty() ) {
10272- const auto maxTagCount =
10273- std::max_element( tags.begin(),
10274- tags.end(),
10275- []( auto const& lhs, auto const& rhs ) {
10276- return lhs.count < rhs.count;
10277- } )
10278- ->count;
10279-
10280- // more padding necessary for 3+ digits
10281- if (maxTagCount >= 100) {
10282- auto numDigits = 1 + std::floor( std::log10( maxTagCount ) );
10283- maxTagCountLen = static_cast<size_t>( numDigits );
10284- }
10285- }
10286-
10287- for ( auto const& tagCount : tags ) {
10288- ReusableStringStream rss;
10289- rss << " " << std::setw( maxTagCountLen ) << tagCount.count << " ";
10290- auto str = rss.str();
10291- auto wrapper = TextFlow::Column( tagCount.all() )
10292- .initialIndent( 0 )
10293- .indent( str.size() )
10294- .width( CATCH_CONFIG_CONSOLE_WIDTH - 10 );
10295- out << str << wrapper << '\n';
10296- }
10297- out << pluralise(tags.size(), "tag"_sr) << "\n\n" << std::flush;
10298- }
10299-
10300- void defaultListTests(std::ostream& out, ColourImpl* streamColour, std::vector<TestCaseHandle> const& tests, bool isFiltered, Verbosity verbosity) {
10301- // We special case this to provide the equivalent of old
10302- // `--list-test-names-only`, which could then be used by the
10303- // `--input-file` option.
10304- if (verbosity == Verbosity::Quiet) {
10305- listTestNamesOnly(out, tests);
10306- return;
10307- }
10308-
10309- if (isFiltered) {
10310- out << "Matching test cases:\n";
10311- } else {
10312- out << "All available test cases:\n";
10313- }
10314-
10315- for (auto const& test : tests) {
10316- auto const& testCaseInfo = test.getTestCaseInfo();
10317- Colour::Code colour = testCaseInfo.isHidden()
10318- ? Colour::SecondaryText
10319- : Colour::None;
10320- auto colourGuard = streamColour->guardColour( colour ).engage( out );
10321-
10322- out << TextFlow::Column(testCaseInfo.name).indent(2) << '\n';
10323- if (verbosity >= Verbosity::High) {
10324- out << TextFlow::Column(Catch::Detail::stringify(testCaseInfo.lineInfo)).indent(4) << '\n';
10325- }
10326- if (!testCaseInfo.tags.empty() &&
10327- verbosity > Verbosity::Quiet) {
10328- out << TextFlow::Column(testCaseInfo.tagsAsString()).indent(6) << '\n';
10329- }
10330- }
10331-
10332- if (isFiltered) {
10333- out << pluralise(tests.size(), "matching test case"_sr);
10334- } else {
10335- out << pluralise(tests.size(), "test case"_sr);
10336- }
10337- out << "\n\n" << std::flush;
10338- }
10339-
10340- namespace {
10341- class SummaryColumn {
10342- public:
10343- SummaryColumn( std::string suffix, Colour::Code colour ):
10344- m_suffix( CATCH_MOVE( suffix ) ), m_colour( colour ) {}
10345-
10346- SummaryColumn&& addRow( std::uint64_t count ) && {
10347- std::string row = std::to_string(count);
10348- auto const new_width = std::max( m_width, row.size() );
10349- if ( new_width > m_width ) {
10350- for ( auto& oldRow : m_rows ) {
10351- oldRow.insert( 0, new_width - m_width, ' ' );
10352- }
10353- } else {
10354- row.insert( 0, m_width - row.size(), ' ' );
10355- }
10356- m_width = new_width;
10357- m_rows.push_back( row );
10358- return std::move( *this );
10359- }
10360-
10361- std::string const& getSuffix() const { return m_suffix; }
10362- Colour::Code getColour() const { return m_colour; }
10363- std::string const& getRow( std::size_t index ) const {
10364- return m_rows[index];
10365- }
10366-
10367- private:
10368- std::string m_suffix;
10369- Colour::Code m_colour;
10370- std::size_t m_width = 0;
10371- std::vector<std::string> m_rows;
10372- };
10373-
10374- void printSummaryRow( std::ostream& stream,
10375- ColourImpl& colour,
10376- StringRef label,
10377- std::vector<SummaryColumn> const& cols,
10378- std::size_t row ) {
10379- for ( auto const& col : cols ) {
10380- auto const& value = col.getRow( row );
10381- auto const& suffix = col.getSuffix();
10382- if ( suffix.empty() ) {
10383- stream << label << ": ";
10384- if ( value != "0" ) {
10385- stream << value;
10386- } else {
10387- stream << colour.guardColour( Colour::Warning )
10388- << "- none -";
10389- }
10390- } else if ( value != "0" ) {
10391- stream << colour.guardColour( Colour::LightGrey ) << " | "
10392- << colour.guardColour( col.getColour() ) << value
10393- << ' ' << suffix;
10394- }
10395- }
10396- stream << '\n';
10397- }
10398- } // namespace
10399-
10400- void printTestRunTotals( std::ostream& stream,
10401- ColourImpl& streamColour,
10402- Totals const& totals ) {
10403- if ( totals.testCases.total() == 0 ) {
10404- stream << streamColour.guardColour( Colour::Warning )
10405- << "No tests ran\n";
10406- return;
10407- }
10408-
10409- if ( totals.assertions.total() > 0 && totals.testCases.allPassed() ) {
10410- stream << streamColour.guardColour( Colour::ResultSuccess )
10411- << "All tests passed";
10412- stream << " ("
10413- << pluralise( totals.assertions.passed, "assertion"_sr )
10414- << " in "
10415- << pluralise( totals.testCases.passed, "test case"_sr )
10416- << ')' << '\n';
10417- return;
10418- }
10419-
10420- std::vector<SummaryColumn> columns;
10421- // Don't include "skipped assertions" in total count
10422- const auto totalAssertionCount =
10423- totals.assertions.total() - totals.assertions.skipped;
10424- columns.push_back( SummaryColumn( "", Colour::None )
10425- .addRow( totals.testCases.total() )
10426- .addRow( totalAssertionCount ) );
10427- columns.push_back( SummaryColumn( "passed", Colour::Success )
10428- .addRow( totals.testCases.passed )
10429- .addRow( totals.assertions.passed ) );
10430- columns.push_back( SummaryColumn( "failed", Colour::ResultError )
10431- .addRow( totals.testCases.failed )
10432- .addRow( totals.assertions.failed ) );
10433- columns.push_back( SummaryColumn( "skipped", Colour::Skip )
10434- .addRow( totals.testCases.skipped )
10435- // Don't print "skipped assertions"
10436- .addRow( 0 ) );
10437- columns.push_back(
10438- SummaryColumn( "failed as expected", Colour::ResultExpectedFailure )
10439- .addRow( totals.testCases.failedButOk )
10440- .addRow( totals.assertions.failedButOk ) );
10441- printSummaryRow( stream, streamColour, "test cases"_sr, columns, 0 );
10442- printSummaryRow( stream, streamColour, "assertions"_sr, columns, 1 );
10443- }
10444-
10445-} // namespace Catch
10446-
10447-
10448-//
10449-
10450-namespace Catch {
10451- namespace {
10452- void writeSourceInfo( JsonObjectWriter& writer,
10453- SourceLineInfo const& sourceInfo ) {
10454- auto source_location_writer =
10455- writer.write( "source-location"_sr ).writeObject();
10456- source_location_writer.write( "filename"_sr )
10457- .write( sourceInfo.file );
10458- source_location_writer.write( "line"_sr ).write( sourceInfo.line );
10459- }
10460-
10461- void writeTags( JsonArrayWriter writer, std::vector<Tag> const& tags ) {
10462- for ( auto const& tag : tags ) {
10463- writer.write( tag.original );
10464- }
10465- }
10466-
10467- void writeProperties( JsonArrayWriter writer,
10468- TestCaseInfo const& info ) {
10469- if ( info.isHidden() ) { writer.write( "is-hidden"_sr ); }
10470- if ( info.okToFail() ) { writer.write( "ok-to-fail"_sr ); }
10471- if ( info.expectedToFail() ) {
10472- writer.write( "expected-to-fail"_sr );
10473- }
10474- if ( info.throws() ) { writer.write( "throws"_sr ); }
10475- }
10476-
10477- } // namespace
10478-
10479- JsonReporter::JsonReporter( ReporterConfig&& config ):
10480- StreamingReporterBase{ CATCH_MOVE( config ) } {
10481-
10482- m_preferences.shouldRedirectStdOut = true;
10483- // TBD: Do we want to report all assertions? XML reporter does
10484- // not, but for machine-parseable reporters I think the answer
10485- // should be yes.
10486- m_preferences.shouldReportAllAssertions = true;
10487- // We only handle assertions when they end
10488- m_preferences.shouldReportAllAssertionStarts = false;
10489-
10490- m_objectWriters.emplace( m_stream );
10491- m_writers.emplace( Writer::Object );
10492- auto& writer = m_objectWriters.top();
10493-
10494- writer.write( "version"_sr ).write( 1 );
10495-
10496- {
10497- auto metadata_writer = writer.write( "metadata"_sr ).writeObject();
10498- metadata_writer.write( "name"_sr ).write( m_config->name() );
10499- metadata_writer.write( "rng-seed"_sr ).write( m_config->rngSeed() );
10500- metadata_writer.write( "catch2-version"_sr )
10501- .write( libraryVersion() );
10502- if ( m_config->testSpec().hasFilters() ) {
10503- metadata_writer.write( "filters"_sr )
10504- .write( m_config->testSpec() );
10505- }
10506- }
10507- }
10508-
10509- JsonReporter::~JsonReporter() {
10510- endListing();
10511- // TODO: Ensure this closes the top level object, add asserts
10512- assert( m_writers.size() == 1 && "Only the top level object should be open" );
10513- assert( m_writers.top() == Writer::Object );
10514- endObject();
10515- m_stream << '\n' << std::flush;
10516- assert( m_writers.empty() );
10517- }
10518-
10519- JsonArrayWriter& JsonReporter::startArray() {
10520- m_arrayWriters.emplace( m_arrayWriters.top().writeArray() );
10521- m_writers.emplace( Writer::Array );
10522- return m_arrayWriters.top();
10523- }
10524- JsonArrayWriter& JsonReporter::startArray( StringRef key ) {
10525- m_arrayWriters.emplace(
10526- m_objectWriters.top().write( key ).writeArray() );
10527- m_writers.emplace( Writer::Array );
10528- return m_arrayWriters.top();
10529- }
10530-
10531- JsonObjectWriter& JsonReporter::startObject() {
10532- m_objectWriters.emplace( m_arrayWriters.top().writeObject() );
10533- m_writers.emplace( Writer::Object );
10534- return m_objectWriters.top();
10535- }
10536- JsonObjectWriter& JsonReporter::startObject( StringRef key ) {
10537- m_objectWriters.emplace(
10538- m_objectWriters.top().write( key ).writeObject() );
10539- m_writers.emplace( Writer::Object );
10540- return m_objectWriters.top();
10541- }
10542-
10543- void JsonReporter::endObject() {
10544- assert( isInside( Writer::Object ) );
10545- m_objectWriters.pop();
10546- m_writers.pop();
10547- }
10548- void JsonReporter::endArray() {
10549- assert( isInside( Writer::Array ) );
10550- m_arrayWriters.pop();
10551- m_writers.pop();
10552- }
10553-
10554- bool JsonReporter::isInside( Writer writer ) {
10555- return !m_writers.empty() && m_writers.top() == writer;
10556- }
10557-
10558- void JsonReporter::startListing() {
10559- if ( !m_startedListing ) { startObject( "listings"_sr ); }
10560- m_startedListing = true;
10561- }
10562- void JsonReporter::endListing() {
10563- if ( m_startedListing ) { endObject(); }
10564- m_startedListing = false;
10565- }
10566-
10567- std::string JsonReporter::getDescription() {
10568- return "Outputs listings as JSON. Test listing is Work-in-Progress!";
10569- }
10570-
10571- void JsonReporter::testRunStarting( TestRunInfo const& runInfo ) {
10572- StreamingReporterBase::testRunStarting( runInfo );
10573- endListing();
10574-
10575- assert( isInside( Writer::Object ) );
10576- startObject( "test-run"_sr );
10577- startArray( "test-cases"_sr );
10578- }
10579-
10580- static void writeCounts( JsonObjectWriter&& writer, Counts const& counts ) {
10581- writer.write( "passed"_sr ).write( counts.passed );
10582- writer.write( "failed"_sr ).write( counts.failed );
10583- writer.write( "fail-but-ok"_sr ).write( counts.failedButOk );
10584- writer.write( "skipped"_sr ).write( counts.skipped );
10585- }
10586-
10587- void JsonReporter::testRunEnded(TestRunStats const& runStats) {
10588- assert( isInside( Writer::Array ) );
10589- // End "test-cases"
10590- endArray();
10591-
10592- {
10593- auto totals =
10594- m_objectWriters.top().write( "totals"_sr ).writeObject();
10595- writeCounts( totals.write( "assertions"_sr ).writeObject(),
10596- runStats.totals.assertions );
10597- writeCounts( totals.write( "test-cases"_sr ).writeObject(),
10598- runStats.totals.testCases );
10599- }
10600-
10601- // End the "test-run" object
10602- endObject();
10603- }
10604-
10605- void JsonReporter::testCaseStarting( TestCaseInfo const& tcInfo ) {
10606- StreamingReporterBase::testCaseStarting( tcInfo );
10607-
10608- assert( isInside( Writer::Array ) &&
10609- "We should be in the 'test-cases' array" );
10610- startObject();
10611- // "test-info" prelude
10612- {
10613- auto testInfo =
10614- m_objectWriters.top().write( "test-info"_sr ).writeObject();
10615- // TODO: handle testName vs className!!
10616- testInfo.write( "name"_sr ).write( tcInfo.name );
10617- writeSourceInfo(testInfo, tcInfo.lineInfo);
10618- writeTags( testInfo.write( "tags"_sr ).writeArray(), tcInfo.tags );
10619- writeProperties( testInfo.write( "properties"_sr ).writeArray(),
10620- tcInfo );
10621- }
10622-
10623-
10624- // Start the array for individual test runs (testCasePartial pairs)
10625- startArray( "runs"_sr );
10626- }
10627-
10628- void JsonReporter::testCaseEnded( TestCaseStats const& tcStats ) {
10629- StreamingReporterBase::testCaseEnded( tcStats );
10630-
10631- // We need to close the 'runs' array before finishing the test case
10632- assert( isInside( Writer::Array ) );
10633- endArray();
10634-
10635- {
10636- auto totals =
10637- m_objectWriters.top().write( "totals"_sr ).writeObject();
10638- writeCounts( totals.write( "assertions"_sr ).writeObject(),
10639- tcStats.totals.assertions );
10640- // We do not write the test case totals, because there will always be just one test case here.
10641- // TODO: overall "result" -> success, skip, fail here? Or in partial result?
10642- }
10643- // We do not write out stderr/stdout, because we instead wrote those out in partial runs
10644-
10645- // TODO: aborting?
10646-
10647- // And we also close this test case's object
10648- assert( isInside( Writer::Object ) );
10649- endObject();
10650- }
10651-
10652- void JsonReporter::testCasePartialStarting( TestCaseInfo const& /*tcInfo*/,
10653- uint64_t index ) {
10654- startObject();
10655- m_objectWriters.top().write( "run-idx"_sr ).write( index );
10656- startArray( "path"_sr );
10657- // TODO: we want to delay most of the printing to the 'root' section
10658- // TODO: childSection key name?
10659- }
10660-
10661- void JsonReporter::testCasePartialEnded( TestCaseStats const& tcStats,
10662- uint64_t /*index*/ ) {
10663- // Fixme: the top level section handles this.
10664- //// path object
10665- endArray();
10666- if ( !tcStats.stdOut.empty() ) {
10667- m_objectWriters.top()
10668- .write( "captured-stdout"_sr )
10669- .write( tcStats.stdOut );
10670- }
10671- if ( !tcStats.stdErr.empty() ) {
10672- m_objectWriters.top()
10673- .write( "captured-stderr"_sr )
10674- .write( tcStats.stdErr );
10675- }
10676- {
10677- auto totals =
10678- m_objectWriters.top().write( "totals"_sr ).writeObject();
10679- writeCounts( totals.write( "assertions"_sr ).writeObject(),
10680- tcStats.totals.assertions );
10681- // We do not write the test case totals, because there will
10682- // always be just one test case here.
10683- // TODO: overall "result" -> success, skip, fail here? Or in
10684- // partial result?
10685- }
10686- // TODO: aborting?
10687- // run object
10688- endObject();
10689- }
10690-
10691- void JsonReporter::sectionStarting( SectionInfo const& sectionInfo ) {
10692- assert( isInside( Writer::Array ) &&
10693- "Section should always start inside an object" );
10694- // We want to nest top level sections, even though it shares name
10695- // and source loc with the TEST_CASE
10696- auto& sectionObject = startObject();
10697- sectionObject.write( "kind"_sr ).write( "section"_sr );
10698- sectionObject.write( "name"_sr ).write( sectionInfo.name );
10699- writeSourceInfo( m_objectWriters.top(), sectionInfo.lineInfo );
10700-
10701-
10702- // TBD: Do we want to create this event lazily? It would become
10703- // rather complex, but we could do it, and it would look
10704- // better for empty sections. OTOH, empty sections should
10705- // be rare.
10706- startArray( "path"_sr );
10707- }
10708- void JsonReporter::sectionEnded( SectionStats const& /*sectionStats */) {
10709- // End the subpath array
10710- endArray();
10711- // TODO: metadata
10712- // TODO: what info do we have here?
10713-
10714- // End the section object
10715- endObject();
10716- }
10717-
10718- void JsonReporter::assertionEnded( AssertionStats const& assertionStats ) {
10719- // TODO: There is lot of different things to handle here, but
10720- // we can fill it in later, after we show that the basic
10721- // outline and streaming reporter impl works well enough.
10722- //if ( !m_config->includeSuccessfulResults()
10723- // && assertionStats.assertionResult.isOk() ) {
10724- // return;
10725- //}
10726- assert( isInside( Writer::Array ) );
10727- auto assertionObject = m_arrayWriters.top().writeObject();
10728-
10729- assertionObject.write( "kind"_sr ).write( "assertion"_sr );
10730- writeSourceInfo( assertionObject,
10731- assertionStats.assertionResult.getSourceInfo() );
10732- assertionObject.write( "status"_sr )
10733- .write( assertionStats.assertionResult.isOk() );
10734- // TODO: handling of result.
10735- // TODO: messages
10736- // TODO: totals?
10737- }
10738-
10739-
10740- void JsonReporter::benchmarkPreparing( StringRef name ) { (void)name; }
10741- void JsonReporter::benchmarkStarting( BenchmarkInfo const& ) {}
10742- void JsonReporter::benchmarkEnded( BenchmarkStats<> const& ) {}
10743- void JsonReporter::benchmarkFailed( StringRef error ) { (void)error; }
10744-
10745- void JsonReporter::listReporters(
10746- std::vector<ReporterDescription> const& descriptions ) {
10747- startListing();
10748-
10749- auto writer =
10750- m_objectWriters.top().write( "reporters"_sr ).writeArray();
10751- for ( auto const& desc : descriptions ) {
10752- auto desc_writer = writer.writeObject();
10753- desc_writer.write( "name"_sr ).write( desc.name );
10754- desc_writer.write( "description"_sr ).write( desc.description );
10755- }
10756- }
10757- void JsonReporter::listListeners(
10758- std::vector<ListenerDescription> const& descriptions ) {
10759- startListing();
10760-
10761- auto writer =
10762- m_objectWriters.top().write( "listeners"_sr ).writeArray();
10763-
10764- for ( auto const& desc : descriptions ) {
10765- auto desc_writer = writer.writeObject();
10766- desc_writer.write( "name"_sr ).write( desc.name );
10767- desc_writer.write( "description"_sr ).write( desc.description );
10768- }
10769- }
10770- void JsonReporter::listTests( std::vector<TestCaseHandle> const& tests ) {
10771- startListing();
10772-
10773- auto writer = m_objectWriters.top().write( "tests"_sr ).writeArray();
10774-
10775- for ( auto const& test : tests ) {
10776- auto desc_writer = writer.writeObject();
10777- auto const& info = test.getTestCaseInfo();
10778-
10779- desc_writer.write( "name"_sr ).write( info.name );
10780- desc_writer.write( "class-name"_sr ).write( info.className );
10781- {
10782- auto tag_writer = desc_writer.write( "tags"_sr ).writeArray();
10783- for ( auto const& tag : info.tags ) {
10784- tag_writer.write( tag.original );
10785- }
10786- }
10787- writeSourceInfo( desc_writer, info.lineInfo );
10788- }
10789- }
10790- void JsonReporter::listTags( std::vector<TagInfo> const& tags ) {
10791- startListing();
10792-
10793- auto writer = m_objectWriters.top().write( "tags"_sr ).writeArray();
10794- for ( auto const& tag : tags ) {
10795- auto tag_writer = writer.writeObject();
10796- {
10797- auto aliases_writer =
10798- tag_writer.write( "aliases"_sr ).writeArray();
10799- for ( auto alias : tag.spellings ) {
10800- aliases_writer.write( alias );
10801- }
10802- }
10803- tag_writer.write( "count"_sr ).write( tag.count );
10804- }
10805- }
10806-} // namespace Catch
10807-
10808-
10809-
10810-
10811-#include <cassert>
10812-#include <ctime>
10813-#include <algorithm>
10814-#include <iomanip>
10815-
10816-namespace Catch {
10817-
10818- namespace {
10819- std::string getCurrentTimestamp() {
10820- time_t rawtime;
10821- std::time(&rawtime);
10822-
10823- std::tm timeInfo = {};
10824-#if defined (_MSC_VER) || defined (__MINGW32__)
10825- gmtime_s(&timeInfo, &rawtime);
10826-#elif defined (CATCH_PLATFORM_PLAYSTATION)
10827- gmtime_s(&rawtime, &timeInfo);
10828-#elif defined (__IAR_SYSTEMS_ICC__)
10829- timeInfo = *std::gmtime(&rawtime);
10830-#else
10831- gmtime_r(&rawtime, &timeInfo);
10832-#endif
10833-
10834- auto const timeStampSize = sizeof("2017-01-16T17:06:45Z");
10835- char timeStamp[timeStampSize];
10836- const char * const fmt = "%Y-%m-%dT%H:%M:%SZ";
10837-
10838- std::strftime(timeStamp, timeStampSize, fmt, &timeInfo);
10839-
10840- return std::string(timeStamp, timeStampSize - 1);
10841- }
10842-
10843- std::string fileNameTag(std::vector<Tag> const& tags) {
10844- auto it = std::find_if(begin(tags),
10845- end(tags),
10846- [] (Tag const& tag) {
10847- return tag.original.size() > 0
10848- && tag.original[0] == '#'; });
10849- if (it != tags.end()) {
10850- return static_cast<std::string>(
10851- it->original.substr(1, it->original.size() - 1)
10852- );
10853- }
10854- return std::string();
10855- }
10856-
10857- // Formats the duration in seconds to 3 decimal places.
10858- // This is done because some genius defined Maven Surefire schema
10859- // in a way that only accepts 3 decimal places, and tools like
10860- // Jenkins use that schema for validation JUnit reporter output.
10861- std::string formatDuration( double seconds ) {
10862- ReusableStringStream rss;
10863- rss << std::fixed << std::setprecision( 3 ) << seconds;
10864- return rss.str();
10865- }
10866-
10867- static void normalizeNamespaceMarkers(std::string& str) {
10868- std::size_t pos = str.find( "::" );
10869- while ( pos != std::string::npos ) {
10870- str.replace( pos, 2, "." );
10871- pos += 1;
10872- pos = str.find( "::", pos );
10873- }
10874- }
10875-
10876- } // anonymous namespace
10877-
10878- JunitReporter::JunitReporter( ReporterConfig&& _config )
10879- : CumulativeReporterBase( CATCH_MOVE(_config) ),
10880- xml( m_stream )
10881- {
10882- m_preferences.shouldRedirectStdOut = true;
10883- m_preferences.shouldReportAllAssertions = false;
10884- m_preferences.shouldReportAllAssertionStarts = false;
10885- m_shouldStoreSuccesfulAssertions = false;
10886- }
10887-
10888- std::string JunitReporter::getDescription() {
10889- return "Reports test results in an XML format that looks like Ant's junitreport target";
10890- }
10891-
10892- void JunitReporter::testRunStarting( TestRunInfo const& runInfo ) {
10893- CumulativeReporterBase::testRunStarting( runInfo );
10894- xml.startElement( "testsuites" );
10895- suiteTimer.start();
10896- stdOutForSuite.clear();
10897- stdErrForSuite.clear();
10898- unexpectedExceptions = 0;
10899- }
10900-
10901- void JunitReporter::testCaseStarting( TestCaseInfo const& testCaseInfo ) {
10902- m_okToFail = testCaseInfo.okToFail();
10903- }
10904-
10905- void JunitReporter::assertionEnded( AssertionStats const& assertionStats ) {
10906- if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail )
10907- unexpectedExceptions++;
10908- CumulativeReporterBase::assertionEnded( assertionStats );
10909- }
10910-
10911- void JunitReporter::testCaseEnded( TestCaseStats const& testCaseStats ) {
10912- stdOutForSuite += testCaseStats.stdOut;
10913- stdErrForSuite += testCaseStats.stdErr;
10914- CumulativeReporterBase::testCaseEnded( testCaseStats );
10915- }
10916-
10917- void JunitReporter::testRunEndedCumulative() {
10918- const auto suiteTime = suiteTimer.getElapsedSeconds();
10919- writeRun( *m_testRun, suiteTime );
10920- xml.endElement();
10921- }
10922-
10923- void JunitReporter::writeRun( TestRunNode const& testRunNode, double suiteTime ) {
10924- XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" );
10925-
10926- TestRunStats const& stats = testRunNode.value;
10927- xml.writeAttribute( "name"_sr, stats.runInfo.name );
10928- xml.writeAttribute( "errors"_sr, unexpectedExceptions );
10929- xml.writeAttribute( "failures"_sr, stats.totals.assertions.failed-unexpectedExceptions );
10930- xml.writeAttribute( "skipped"_sr, stats.totals.assertions.skipped );
10931- xml.writeAttribute( "tests"_sr, stats.totals.assertions.total() );
10932- xml.writeAttribute( "hostname"_sr, "tbd"_sr ); // !TBD
10933- if( m_config->showDurations() == ShowDurations::Never )
10934- xml.writeAttribute( "time"_sr, ""_sr );
10935- else
10936- xml.writeAttribute( "time"_sr, formatDuration( suiteTime ) );
10937- xml.writeAttribute( "timestamp"_sr, getCurrentTimestamp() );
10938-
10939- // Write properties
10940- {
10941- auto properties = xml.scopedElement("properties");
10942- xml.scopedElement("property")
10943- .writeAttribute("name"_sr, "random-seed"_sr)
10944- .writeAttribute("value"_sr, m_config->rngSeed());
10945- if (m_config->testSpec().hasFilters()) {
10946- xml.scopedElement("property")
10947- .writeAttribute("name"_sr, "filters"_sr)
10948- .writeAttribute("value"_sr, m_config->testSpec());
10949- }
10950- }
10951-
10952- // Write test cases
10953- for( auto const& child : testRunNode.children )
10954- writeTestCase( *child );
10955-
10956- xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite ), XmlFormatting::Newline );
10957- xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite ), XmlFormatting::Newline );
10958- }
10959-
10960- void JunitReporter::writeTestCase( TestCaseNode const& testCaseNode ) {
10961- TestCaseStats const& stats = testCaseNode.value;
10962-
10963- // All test cases have exactly one section - which represents the
10964- // test case itself. That section may have 0-n nested sections
10965- assert( testCaseNode.children.size() == 1 );
10966- SectionNode const& rootSection = *testCaseNode.children.front();
10967-
10968- std::string className =
10969- static_cast<std::string>( stats.testInfo->className );
10970-
10971- if( className.empty() ) {
10972- className = fileNameTag(stats.testInfo->tags);
10973- if ( className.empty() ) {
10974- className = "global";
10975- }
10976- }
10977-
10978- if ( !m_config->name().empty() )
10979- className = static_cast<std::string>(m_config->name()) + '.' + className;
10980-
10981- normalizeNamespaceMarkers(className);
10982-
10983- writeSection( className, "", rootSection, stats.testInfo->okToFail() );
10984- }
10985-
10986- void JunitReporter::writeSection( std::string const& className,
10987- std::string const& rootName,
10988- SectionNode const& sectionNode,
10989- bool testOkToFail) {
10990- std::string name = trim( sectionNode.stats.sectionInfo.name );
10991- if( !rootName.empty() )
10992- name = rootName + '/' + name;
10993-
10994- if ( sectionNode.stats.assertions.total() > 0
10995- || !sectionNode.stdOut.empty()
10996- || !sectionNode.stdErr.empty() ) {
10997- XmlWriter::ScopedElement e = xml.scopedElement( "testcase" );
10998- if( className.empty() ) {
10999- xml.writeAttribute( "classname"_sr, name );
11000- xml.writeAttribute( "name"_sr, "root"_sr );
11001- }
11002- else {
11003- xml.writeAttribute( "classname"_sr, className );
11004- xml.writeAttribute( "name"_sr, name );
11005- }
11006- xml.writeAttribute( "time"_sr, formatDuration( sectionNode.stats.durationInSeconds ) );
11007- // This is not ideal, but it should be enough to mimic gtest's
11008- // junit output.
11009- // Ideally the JUnit reporter would also handle `skipTest`
11010- // events and write those out appropriately.
11011- xml.writeAttribute( "status"_sr, "run"_sr );
11012-
11013- if (sectionNode.stats.assertions.failedButOk) {
11014- xml.scopedElement("skipped")
11015- .writeAttribute("message", "TEST_CASE tagged with !mayfail");
11016- }
11017-
11018- writeAssertions( sectionNode );
11019-
11020-
11021- if( !sectionNode.stdOut.empty() )
11022- xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), XmlFormatting::Newline );
11023- if( !sectionNode.stdErr.empty() )
11024- xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), XmlFormatting::Newline );
11025- }
11026- for( auto const& childNode : sectionNode.childSections )
11027- if( className.empty() )
11028- writeSection( name, "", *childNode, testOkToFail );
11029- else
11030- writeSection( className, name, *childNode, testOkToFail );
11031- }
11032-
11033- void JunitReporter::writeAssertions( SectionNode const& sectionNode ) {
11034- for (auto const& assertionOrBenchmark : sectionNode.assertionsAndBenchmarks) {
11035- if (assertionOrBenchmark.isAssertion()) {
11036- writeAssertion(assertionOrBenchmark.asAssertion());
11037- }
11038- }
11039- }
11040-
11041- void JunitReporter::writeAssertion( AssertionStats const& stats ) {
11042- AssertionResult const& result = stats.assertionResult;
11043- if ( !result.isOk() ||
11044- result.getResultType() == ResultWas::ExplicitSkip ) {
11045- std::string elementName;
11046- switch( result.getResultType() ) {
11047- case ResultWas::ThrewException:
11048- case ResultWas::FatalErrorCondition:
11049- elementName = "error";
11050- break;
11051- case ResultWas::ExplicitFailure:
11052- case ResultWas::ExpressionFailed:
11053- case ResultWas::DidntThrowException:
11054- elementName = "failure";
11055- break;
11056- case ResultWas::ExplicitSkip:
11057- elementName = "skipped";
11058- break;
11059- // We should never see these here:
11060- case ResultWas::Info:
11061- case ResultWas::Warning:
11062- case ResultWas::Ok:
11063- case ResultWas::Unknown:
11064- case ResultWas::FailureBit:
11065- case ResultWas::Exception:
11066- elementName = "internalError";
11067- break;
11068- }
11069-
11070- XmlWriter::ScopedElement e = xml.scopedElement( elementName );
11071-
11072- xml.writeAttribute( "message"_sr, result.getExpression() );
11073- xml.writeAttribute( "type"_sr, result.getTestMacroName() );
11074-
11075- ReusableStringStream rss;
11076- if ( result.getResultType() == ResultWas::ExplicitSkip ) {
11077- rss << "SKIPPED\n";
11078- } else {
11079- rss << "FAILED" << ":\n";
11080- if (result.hasExpression()) {
11081- rss << " ";
11082- rss << result.getExpressionInMacro();
11083- rss << '\n';
11084- }
11085- if (result.hasExpandedExpression()) {
11086- rss << "with expansion:\n";
11087- rss << TextFlow::Column(result.getExpandedExpression()).indent(2) << '\n';
11088- }
11089- }
11090-
11091- if( result.hasMessage() )
11092- rss << result.getMessage() << '\n';
11093- for( auto const& msg : stats.infoMessages )
11094- if( msg.type == ResultWas::Info )
11095- rss << msg.message << '\n';
11096-
11097- rss << "at " << result.getSourceInfo();
11098- xml.writeText( rss.str(), XmlFormatting::Newline );
11099- }
11100- }
11101-
11102-} // end namespace Catch
11103-
11104-
11105-
11106-
11107-#include <ostream>
11108-
11109-namespace Catch {
11110- void MultiReporter::updatePreferences(IEventListener const& reporterish) {
11111- m_preferences.shouldRedirectStdOut |=
11112- reporterish.getPreferences().shouldRedirectStdOut;
11113- m_preferences.shouldReportAllAssertions |=
11114- reporterish.getPreferences().shouldReportAllAssertions;
11115- m_preferences.shouldReportAllAssertionStarts |=
11116- reporterish.getPreferences().shouldReportAllAssertionStarts;
11117- }
11118-
11119- void MultiReporter::addListener( IEventListenerPtr&& listener ) {
11120- updatePreferences(*listener);
11121- m_reporterLikes.insert(m_reporterLikes.begin() + m_insertedListeners, CATCH_MOVE(listener) );
11122- ++m_insertedListeners;
11123- }
11124-
11125- void MultiReporter::addReporter( IEventListenerPtr&& reporter ) {
11126- updatePreferences(*reporter);
11127-
11128- // We will need to output the captured stdout if there are reporters
11129- // that do not want it captured.
11130- // We do not consider listeners, because it is generally assumed that
11131- // listeners are output-transparent, even though they can ask for stdout
11132- // capture to do something with it.
11133- m_haveNoncapturingReporters |= !reporter->getPreferences().shouldRedirectStdOut;
11134-
11135- // Reporters can always be placed to the back without breaking the
11136- // reporting order
11137- m_reporterLikes.push_back( CATCH_MOVE( reporter ) );
11138- }
11139-
11140- void MultiReporter::noMatchingTestCases( StringRef unmatchedSpec ) {
11141- for ( auto& reporterish : m_reporterLikes ) {
11142- reporterish->noMatchingTestCases( unmatchedSpec );
11143- }
11144- }
11145-
11146- void MultiReporter::fatalErrorEncountered( StringRef error ) {
11147- for ( auto& reporterish : m_reporterLikes ) {
11148- reporterish->fatalErrorEncountered( error );
11149- }
11150- }
11151-
11152- void MultiReporter::reportInvalidTestSpec( StringRef arg ) {
11153- for ( auto& reporterish : m_reporterLikes ) {
11154- reporterish->reportInvalidTestSpec( arg );
11155- }
11156- }
11157-
11158- void MultiReporter::benchmarkPreparing( StringRef name ) {
11159- for (auto& reporterish : m_reporterLikes) {
11160- reporterish->benchmarkPreparing(name);
11161- }
11162- }
11163- void MultiReporter::benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) {
11164- for ( auto& reporterish : m_reporterLikes ) {
11165- reporterish->benchmarkStarting( benchmarkInfo );
11166- }
11167- }
11168- void MultiReporter::benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) {
11169- for ( auto& reporterish : m_reporterLikes ) {
11170- reporterish->benchmarkEnded( benchmarkStats );
11171- }
11172- }
11173-
11174- void MultiReporter::benchmarkFailed( StringRef error ) {
11175- for (auto& reporterish : m_reporterLikes) {
11176- reporterish->benchmarkFailed(error);
11177- }
11178- }
11179-
11180- void MultiReporter::testRunStarting( TestRunInfo const& testRunInfo ) {
11181- for ( auto& reporterish : m_reporterLikes ) {
11182- reporterish->testRunStarting( testRunInfo );
11183- }
11184- }
11185-
11186- void MultiReporter::testCaseStarting( TestCaseInfo const& testInfo ) {
11187- for ( auto& reporterish : m_reporterLikes ) {
11188- reporterish->testCaseStarting( testInfo );
11189- }
11190- }
11191-
11192- void
11193- MultiReporter::testCasePartialStarting( TestCaseInfo const& testInfo,
11194- uint64_t partNumber ) {
11195- for ( auto& reporterish : m_reporterLikes ) {
11196- reporterish->testCasePartialStarting( testInfo, partNumber );
11197- }
11198- }
11199-
11200- void MultiReporter::sectionStarting( SectionInfo const& sectionInfo ) {
11201- for ( auto& reporterish : m_reporterLikes ) {
11202- reporterish->sectionStarting( sectionInfo );
11203- }
11204- }
11205-
11206- void MultiReporter::assertionStarting( AssertionInfo const& assertionInfo ) {
11207- for ( auto& reporterish : m_reporterLikes ) {
11208- reporterish->assertionStarting( assertionInfo );
11209- }
11210- }
11211-
11212- void MultiReporter::assertionEnded( AssertionStats const& assertionStats ) {
11213- const bool reportByDefault =
11214- assertionStats.assertionResult.getResultType() != ResultWas::Ok ||
11215- m_config->includeSuccessfulResults();
11216-
11217- for ( auto & reporterish : m_reporterLikes ) {
11218- if ( reportByDefault ||
11219- reporterish->getPreferences().shouldReportAllAssertions ) {
11220- reporterish->assertionEnded( assertionStats );
11221- }
11222- }
11223- }
11224-
11225- void MultiReporter::sectionEnded( SectionStats const& sectionStats ) {
11226- for ( auto& reporterish : m_reporterLikes ) {
11227- reporterish->sectionEnded( sectionStats );
11228- }
11229- }
11230-
11231- void MultiReporter::testCasePartialEnded( TestCaseStats const& testStats,
11232- uint64_t partNumber ) {
11233- if ( m_preferences.shouldRedirectStdOut &&
11234- m_haveNoncapturingReporters ) {
11235- if ( !testStats.stdOut.empty() ) {
11236- Catch::cout() << testStats.stdOut << std::flush;
11237- }
11238- if ( !testStats.stdErr.empty() ) {
11239- Catch::cerr() << testStats.stdErr << std::flush;
11240- }
11241- }
11242-
11243- for ( auto& reporterish : m_reporterLikes ) {
11244- reporterish->testCasePartialEnded( testStats, partNumber );
11245- }
11246- }
11247-
11248- void MultiReporter::testCaseEnded( TestCaseStats const& testCaseStats ) {
11249- for ( auto& reporterish : m_reporterLikes ) {
11250- reporterish->testCaseEnded( testCaseStats );
11251- }
11252- }
11253-
11254- void MultiReporter::testRunEnded( TestRunStats const& testRunStats ) {
11255- for ( auto& reporterish : m_reporterLikes ) {
11256- reporterish->testRunEnded( testRunStats );
11257- }
11258- }
11259-
11260-
11261- void MultiReporter::skipTest( TestCaseInfo const& testInfo ) {
11262- for ( auto& reporterish : m_reporterLikes ) {
11263- reporterish->skipTest( testInfo );
11264- }
11265- }
11266-
11267- void MultiReporter::listReporters(std::vector<ReporterDescription> const& descriptions) {
11268- for (auto& reporterish : m_reporterLikes) {
11269- reporterish->listReporters(descriptions);
11270- }
11271- }
11272-
11273- void MultiReporter::listListeners(
11274- std::vector<ListenerDescription> const& descriptions ) {
11275- for ( auto& reporterish : m_reporterLikes ) {
11276- reporterish->listListeners( descriptions );
11277- }
11278- }
11279-
11280- void MultiReporter::listTests(std::vector<TestCaseHandle> const& tests) {
11281- for (auto& reporterish : m_reporterLikes) {
11282- reporterish->listTests(tests);
11283- }
11284- }
11285-
11286- void MultiReporter::listTags(std::vector<TagInfo> const& tags) {
11287- for (auto& reporterish : m_reporterLikes) {
11288- reporterish->listTags(tags);
11289- }
11290- }
11291-
11292-} // end namespace Catch
11293-
11294-
11295-
11296-
11297-
11298-namespace Catch {
11299- namespace Detail {
11300-
11301- void registerReporterImpl( std::string const& name,
11302- IReporterFactoryPtr reporterPtr ) {
11303- CATCH_TRY {
11304- getMutableRegistryHub().registerReporter(
11305- name, CATCH_MOVE( reporterPtr ) );
11306- }
11307- CATCH_CATCH_ALL {
11308- // Do not throw when constructing global objects, instead
11309- // register the exception to be processed later
11310- getMutableRegistryHub().registerStartupException();
11311- }
11312- }
11313-
11314- void registerListenerImpl( Detail::unique_ptr<EventListenerFactory> listenerFactory ) {
11315- getMutableRegistryHub().registerListener( CATCH_MOVE(listenerFactory) );
11316- }
11317-
11318-
11319- } // namespace Detail
11320-} // namespace Catch
11321-
11322-
11323-
11324-
11325-#include <map>
11326-
11327-namespace Catch {
11328-
11329- namespace {
11330- std::string createMetadataString(IConfig const& config) {
11331- ReusableStringStream sstr;
11332- if ( config.testSpec().hasFilters() ) {
11333- sstr << "filters='"
11334- << config.testSpec()
11335- << "' ";
11336- }
11337- sstr << "rng-seed=" << config.rngSeed();
11338- return sstr.str();
11339- }
11340- }
11341-
11342- void SonarQubeReporter::testRunStarting(TestRunInfo const& testRunInfo) {
11343- CumulativeReporterBase::testRunStarting(testRunInfo);
11344-
11345- xml.writeComment( createMetadataString( *m_config ) );
11346- xml.startElement("testExecutions");
11347- xml.writeAttribute("version"_sr, '1');
11348- }
11349-
11350- void SonarQubeReporter::writeRun( TestRunNode const& runNode ) {
11351- std::map<StringRef, std::vector<TestCaseNode const*>> testsPerFile;
11352-
11353- for ( auto const& child : runNode.children ) {
11354- testsPerFile[child->value.testInfo->lineInfo.file].push_back(
11355- child.get() );
11356- }
11357-
11358- for ( auto const& kv : testsPerFile ) {
11359- writeTestFile( kv.first, kv.second );
11360- }
11361- }
11362-
11363- void SonarQubeReporter::writeTestFile(StringRef filename, std::vector<TestCaseNode const*> const& testCaseNodes) {
11364- XmlWriter::ScopedElement e = xml.scopedElement("file");
11365- xml.writeAttribute("path"_sr, filename);
11366-
11367- for (auto const& child : testCaseNodes)
11368- writeTestCase(*child);
11369- }
11370-
11371- void SonarQubeReporter::writeTestCase(TestCaseNode const& testCaseNode) {
11372- // All test cases have exactly one section - which represents the
11373- // test case itself. That section may have 0-n nested sections
11374- assert(testCaseNode.children.size() == 1);
11375- SectionNode const& rootSection = *testCaseNode.children.front();
11376- writeSection("", rootSection, testCaseNode.value.testInfo->okToFail());
11377- }
11378-
11379- void SonarQubeReporter::writeSection(std::string const& rootName, SectionNode const& sectionNode, bool okToFail) {
11380- std::string name = trim(sectionNode.stats.sectionInfo.name);
11381- if (!rootName.empty())
11382- name = rootName + '/' + name;
11383-
11384- if ( sectionNode.stats.assertions.total() > 0
11385- || !sectionNode.stdOut.empty()
11386- || !sectionNode.stdErr.empty() ) {
11387- XmlWriter::ScopedElement e = xml.scopedElement("testCase");
11388- xml.writeAttribute("name"_sr, name);
11389- xml.writeAttribute("duration"_sr, static_cast<long>(sectionNode.stats.durationInSeconds * 1000));
11390-
11391- writeAssertions(sectionNode, okToFail);
11392- }
11393-
11394- for (auto const& childNode : sectionNode.childSections)
11395- writeSection(name, *childNode, okToFail);
11396- }
11397-
11398- void SonarQubeReporter::writeAssertions(SectionNode const& sectionNode, bool okToFail) {
11399- for (auto const& assertionOrBenchmark : sectionNode.assertionsAndBenchmarks) {
11400- if (assertionOrBenchmark.isAssertion()) {
11401- writeAssertion(assertionOrBenchmark.asAssertion(), okToFail);
11402- }
11403- }
11404- }
11405-
11406- void SonarQubeReporter::writeAssertion(AssertionStats const& stats, bool okToFail) {
11407- AssertionResult const& result = stats.assertionResult;
11408- if ( !result.isOk() ||
11409- result.getResultType() == ResultWas::ExplicitSkip ) {
11410- std::string elementName;
11411- if (okToFail) {
11412- elementName = "skipped";
11413- } else {
11414- switch (result.getResultType()) {
11415- case ResultWas::ThrewException:
11416- case ResultWas::FatalErrorCondition:
11417- elementName = "error";
11418- break;
11419- case ResultWas::ExplicitFailure:
11420- case ResultWas::ExpressionFailed:
11421- case ResultWas::DidntThrowException:
11422- elementName = "failure";
11423- break;
11424- case ResultWas::ExplicitSkip:
11425- elementName = "skipped";
11426- break;
11427- // We should never see these here:
11428- case ResultWas::Info:
11429- case ResultWas::Warning:
11430- case ResultWas::Ok:
11431- case ResultWas::Unknown:
11432- case ResultWas::FailureBit:
11433- case ResultWas::Exception:
11434- elementName = "internalError";
11435- break;
11436- }
11437- }
11438-
11439- XmlWriter::ScopedElement e = xml.scopedElement(elementName);
11440-
11441- ReusableStringStream messageRss;
11442- messageRss << result.getTestMacroName() << '(' << result.getExpression() << ')';
11443- xml.writeAttribute("message"_sr, messageRss.str());
11444-
11445- ReusableStringStream textRss;
11446- if ( result.getResultType() == ResultWas::ExplicitSkip ) {
11447- textRss << "SKIPPED\n";
11448- } else {
11449- textRss << "FAILED:\n";
11450- if (result.hasExpression()) {
11451- textRss << '\t' << result.getExpressionInMacro() << '\n';
11452- }
11453- if (result.hasExpandedExpression()) {
11454- textRss << "with expansion:\n\t" << result.getExpandedExpression() << '\n';
11455- }
11456- }
11457-
11458- if (result.hasMessage())
11459- textRss << result.getMessage() << '\n';
11460-
11461- for (auto const& msg : stats.infoMessages)
11462- if (msg.type == ResultWas::Info)
11463- textRss << msg.message << '\n';
11464-
11465- textRss << "at " << result.getSourceInfo();
11466- xml.writeText(textRss.str(), XmlFormatting::Newline);
11467- }
11468- }
11469-
11470-} // end namespace Catch
11471-
11472-
11473-
11474-namespace Catch {
11475-
11476- StreamingReporterBase::~StreamingReporterBase() = default;
11477-
11478- void
11479- StreamingReporterBase::testRunStarting( TestRunInfo const& _testRunInfo ) {
11480- currentTestRunInfo = _testRunInfo;
11481- }
11482-
11483- void StreamingReporterBase::testRunEnded( TestRunStats const& ) {
11484- currentTestCaseInfo = nullptr;
11485- }
11486-
11487-} // end namespace Catch
11488-
11489-
11490-
11491-#include <algorithm>
11492-#include <ostream>
11493-
11494-namespace Catch {
11495-
11496- namespace {
11497- // Yes, this has to be outside the class and namespaced by naming.
11498- // Making older compiler happy is hard.
11499- static constexpr StringRef tapFailedString = "not ok"_sr;
11500- static constexpr StringRef tapPassedString = "ok"_sr;
11501- static constexpr Colour::Code tapDimColour = Colour::FileName;
11502-
11503- class TapAssertionPrinter {
11504- public:
11505- TapAssertionPrinter& operator= (TapAssertionPrinter const&) = delete;
11506- TapAssertionPrinter(TapAssertionPrinter const&) = delete;
11507- TapAssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, std::size_t _counter, ColourImpl* colour_)
11508- : stream(_stream)
11509- , result(_stats.assertionResult)
11510- , messages(_stats.infoMessages)
11511- , itMessage(_stats.infoMessages.begin())
11512- , printInfoMessages(true)
11513- , counter(_counter)
11514- , colourImpl( colour_ ) {}
11515-
11516- void print() {
11517- itMessage = messages.begin();
11518-
11519- switch (result.getResultType()) {
11520- case ResultWas::Ok:
11521- printResultType(tapPassedString);
11522- printOriginalExpression();
11523- printReconstructedExpression();
11524- if (!result.hasExpression())
11525- printRemainingMessages(Colour::None);
11526- else
11527- printRemainingMessages();
11528- break;
11529- case ResultWas::ExpressionFailed:
11530- if (result.isOk()) {
11531- printResultType(tapPassedString);
11532- } else {
11533- printResultType(tapFailedString);
11534- }
11535- printOriginalExpression();
11536- printReconstructedExpression();
11537- if (result.isOk()) {
11538- printIssue(" # TODO");
11539- }
11540- printRemainingMessages();
11541- break;
11542- case ResultWas::ThrewException:
11543- printResultType(tapFailedString);
11544- printIssue("unexpected exception with message:"_sr);
11545- printMessage();
11546- printExpressionWas();
11547- printRemainingMessages();
11548- break;
11549- case ResultWas::FatalErrorCondition:
11550- printResultType(tapFailedString);
11551- printIssue("fatal error condition with message:"_sr);
11552- printMessage();
11553- printExpressionWas();
11554- printRemainingMessages();
11555- break;
11556- case ResultWas::DidntThrowException:
11557- printResultType(tapFailedString);
11558- printIssue("expected exception, got none"_sr);
11559- printExpressionWas();
11560- printRemainingMessages();
11561- break;
11562- case ResultWas::Info:
11563- printResultType("info"_sr);
11564- printMessage();
11565- printRemainingMessages();
11566- break;
11567- case ResultWas::Warning:
11568- printResultType("warning"_sr);
11569- printMessage();
11570- printRemainingMessages();
11571- break;
11572- case ResultWas::ExplicitFailure:
11573- printResultType(tapFailedString);
11574- printIssue("explicitly"_sr);
11575- printRemainingMessages(Colour::None);
11576- break;
11577- case ResultWas::ExplicitSkip:
11578- printResultType(tapPassedString);
11579- printIssue(" # SKIP"_sr);
11580- printMessage();
11581- printRemainingMessages();
11582- break;
11583- // These cases are here to prevent compiler warnings
11584- case ResultWas::Unknown:
11585- case ResultWas::FailureBit:
11586- case ResultWas::Exception:
11587- printResultType("** internal error **"_sr);
11588- break;
11589- }
11590- }
11591-
11592- private:
11593- void printResultType(StringRef passOrFail) const {
11594- if (!passOrFail.empty()) {
11595- stream << passOrFail << ' ' << counter << " -";
11596- }
11597- }
11598-
11599- void printIssue(StringRef issue) const {
11600- stream << ' ' << issue;
11601- }
11602-
11603- void printExpressionWas() {
11604- if (result.hasExpression()) {
11605- stream << ';';
11606- stream << colourImpl->guardColour( tapDimColour )
11607- << " expression was:";
11608- printOriginalExpression();
11609- }
11610- }
11611-
11612- void printOriginalExpression() const {
11613- if (result.hasExpression()) {
11614- stream << ' ' << result.getExpression();
11615- }
11616- }
11617-
11618- void printReconstructedExpression() const {
11619- if (result.hasExpandedExpression()) {
11620- stream << colourImpl->guardColour( tapDimColour ) << " for: ";
11621-
11622- std::string expr = result.getExpandedExpression();
11623- std::replace(expr.begin(), expr.end(), '\n', ' ');
11624- stream << expr;
11625- }
11626- }
11627-
11628- void printMessage() {
11629- if (itMessage != messages.end()) {
11630- stream << " '" << itMessage->message << '\'';
11631- ++itMessage;
11632- }
11633- }
11634-
11635- void printRemainingMessages(Colour::Code colour = tapDimColour) {
11636- if (itMessage == messages.end()) {
11637- return;
11638- }
11639-
11640- // using messages.end() directly (or auto) yields compilation error:
11641- std::vector<MessageInfo>::const_iterator itEnd = messages.end();
11642- const std::size_t N = static_cast<std::size_t>(itEnd - itMessage);
11643-
11644- stream << colourImpl->guardColour( colour ) << " with "
11645- << pluralise( N, "message"_sr ) << ':';
11646-
11647- for (; itMessage != itEnd; ) {
11648- // If this assertion is a warning ignore any INFO messages
11649- if (printInfoMessages || itMessage->type != ResultWas::Info) {
11650- stream << " '" << itMessage->message << '\'';
11651- if (++itMessage != itEnd) {
11652- stream << colourImpl->guardColour(tapDimColour) << " and";
11653- }
11654- }
11655- }
11656- }
11657-
11658- private:
11659- std::ostream& stream;
11660- AssertionResult const& result;
11661- std::vector<MessageInfo> const& messages;
11662- std::vector<MessageInfo>::const_iterator itMessage;
11663- bool printInfoMessages;
11664- std::size_t counter;
11665- ColourImpl* colourImpl;
11666- };
11667-
11668- } // End anonymous namespace
11669-
11670- void TAPReporter::testRunStarting( TestRunInfo const& ) {
11671- if ( m_config->testSpec().hasFilters() ) {
11672- m_stream << "# filters: " << m_config->testSpec() << '\n';
11673- }
11674- m_stream << "# rng-seed: " << m_config->rngSeed() << '\n'
11675- << std::flush;
11676- }
11677-
11678- void TAPReporter::noMatchingTestCases( StringRef unmatchedSpec ) {
11679- m_stream << "# No test cases matched '" << unmatchedSpec << "'\n";
11680- }
11681-
11682- void TAPReporter::assertionEnded(AssertionStats const& _assertionStats) {
11683- ++counter;
11684-
11685- m_stream << "# " << currentTestCaseInfo->name << '\n';
11686- TapAssertionPrinter printer(m_stream, _assertionStats, counter, m_colour.get());
11687- printer.print();
11688-
11689- m_stream << '\n' << std::flush;
11690- }
11691-
11692- void TAPReporter::testRunEnded(TestRunStats const& _testRunStats) {
11693- m_stream << "1.." << _testRunStats.totals.assertions.total();
11694- if (_testRunStats.totals.testCases.total() == 0) {
11695- m_stream << " # Skipped: No tests ran.";
11696- }
11697- m_stream << "\n\n" << std::flush;
11698- StreamingReporterBase::testRunEnded(_testRunStats);
11699- }
11700-
11701-
11702-
11703-
11704-} // end namespace Catch
11705-
11706-
11707-
11708-
11709-#include <cassert>
11710-#include <ostream>
11711-
11712-namespace Catch {
11713-
11714- namespace {
11715- // if string has a : in first line will set indent to follow it on
11716- // subsequent lines
11717- void printHeaderString(std::ostream& os, std::string const& _string, std::size_t indent = 0) {
11718- std::size_t i = _string.find(": ");
11719- if (i != std::string::npos)
11720- i += 2;
11721- else
11722- i = 0;
11723- os << TextFlow::Column(_string)
11724- .indent(indent + i)
11725- .initialIndent(indent) << '\n';
11726- }
11727-
11728- std::string escape(StringRef str) {
11729- std::string escaped = static_cast<std::string>(str);
11730- replaceInPlace(escaped, "|", "||");
11731- replaceInPlace(escaped, "'", "|'");
11732- replaceInPlace(escaped, "\n", "|n");
11733- replaceInPlace(escaped, "\r", "|r");
11734- replaceInPlace(escaped, "[", "|[");
11735- replaceInPlace(escaped, "]", "|]");
11736- return escaped;
11737- }
11738- } // end anonymous namespace
11739-
11740-
11741- TeamCityReporter::~TeamCityReporter() = default;
11742-
11743- void TeamCityReporter::testRunStarting( TestRunInfo const& runInfo ) {
11744- m_stream << "##teamcity[testSuiteStarted name='" << escape( runInfo.name )
11745- << "']\n";
11746- }
11747-
11748- void TeamCityReporter::testRunEnded( TestRunStats const& runStats ) {
11749- m_stream << "##teamcity[testSuiteFinished name='"
11750- << escape( runStats.runInfo.name ) << "']\n";
11751- }
11752-
11753- void TeamCityReporter::assertionEnded(AssertionStats const& assertionStats) {
11754- AssertionResult const& result = assertionStats.assertionResult;
11755- if ( !result.isOk() ||
11756- result.getResultType() == ResultWas::ExplicitSkip ) {
11757-
11758- ReusableStringStream msg;
11759- if (!m_headerPrintedForThisSection)
11760- printSectionHeader(msg.get());
11761- m_headerPrintedForThisSection = true;
11762-
11763- msg << result.getSourceInfo() << '\n';
11764-
11765- switch (result.getResultType()) {
11766- case ResultWas::ExpressionFailed:
11767- msg << "expression failed";
11768- break;
11769- case ResultWas::ThrewException:
11770- msg << "unexpected exception";
11771- break;
11772- case ResultWas::FatalErrorCondition:
11773- msg << "fatal error condition";
11774- break;
11775- case ResultWas::DidntThrowException:
11776- msg << "no exception was thrown where one was expected";
11777- break;
11778- case ResultWas::ExplicitFailure:
11779- msg << "explicit failure";
11780- break;
11781- case ResultWas::ExplicitSkip:
11782- msg << "explicit skip";
11783- break;
11784-
11785- // We shouldn't get here because of the isOk() test
11786- case ResultWas::Ok:
11787- case ResultWas::Info:
11788- case ResultWas::Warning:
11789- CATCH_ERROR("Internal error in TeamCity reporter");
11790- // These cases are here to prevent compiler warnings
11791- case ResultWas::Unknown:
11792- case ResultWas::FailureBit:
11793- case ResultWas::Exception:
11794- CATCH_ERROR("Not implemented");
11795- }
11796- if (assertionStats.infoMessages.size() == 1)
11797- msg << " with message:";
11798- if (assertionStats.infoMessages.size() > 1)
11799- msg << " with messages:";
11800- for (auto const& messageInfo : assertionStats.infoMessages)
11801- msg << "\n \"" << messageInfo.message << '"';
11802-
11803-
11804- if (result.hasExpression()) {
11805- msg <<
11806- "\n " << result.getExpressionInMacro() << "\n"
11807- "with expansion:\n"
11808- " " << result.getExpandedExpression() << '\n';
11809- }
11810-
11811- if ( result.getResultType() == ResultWas::ExplicitSkip ) {
11812- m_stream << "##teamcity[testIgnored";
11813- } else if ( currentTestCaseInfo->okToFail() ) {
11814- msg << "- failure ignore as test marked as 'ok to fail'\n";
11815- m_stream << "##teamcity[testIgnored";
11816- } else {
11817- m_stream << "##teamcity[testFailed";
11818- }
11819- m_stream << " name='" << escape( currentTestCaseInfo->name ) << '\''
11820- << " message='" << escape( msg.str() ) << '\'' << "]\n";
11821- }
11822- m_stream.flush();
11823- }
11824-
11825- void TeamCityReporter::testCaseStarting(TestCaseInfo const& testInfo) {
11826- m_testTimer.start();
11827- StreamingReporterBase::testCaseStarting(testInfo);
11828- m_stream << "##teamcity[testStarted name='"
11829- << escape(testInfo.name) << "']\n";
11830- m_stream.flush();
11831- }
11832-
11833- void TeamCityReporter::testCaseEnded(TestCaseStats const& testCaseStats) {
11834- StreamingReporterBase::testCaseEnded(testCaseStats);
11835- auto const& testCaseInfo = *testCaseStats.testInfo;
11836- if (!testCaseStats.stdOut.empty())
11837- m_stream << "##teamcity[testStdOut name='"
11838- << escape(testCaseInfo.name)
11839- << "' out='" << escape(testCaseStats.stdOut) << "']\n";
11840- if (!testCaseStats.stdErr.empty())
11841- m_stream << "##teamcity[testStdErr name='"
11842- << escape(testCaseInfo.name)
11843- << "' out='" << escape(testCaseStats.stdErr) << "']\n";
11844- m_stream << "##teamcity[testFinished name='"
11845- << escape(testCaseInfo.name) << "' duration='"
11846- << m_testTimer.getElapsedMilliseconds() << "']\n";
11847- m_stream.flush();
11848- }
11849-
11850- void TeamCityReporter::printSectionHeader(std::ostream& os) {
11851- assert(!m_sectionStack.empty());
11852-
11853- if (m_sectionStack.size() > 1) {
11854- os << lineOfChars('-') << '\n';
11855-
11856- std::vector<SectionInfo>::const_iterator
11857- it = m_sectionStack.begin() + 1, // Skip first section (test case)
11858- itEnd = m_sectionStack.end();
11859- for (; it != itEnd; ++it)
11860- printHeaderString(os, it->name);
11861- os << lineOfChars('-') << '\n';
11862- }
11863-
11864- SourceLineInfo lineInfo = m_sectionStack.front().lineInfo;
11865-
11866- os << lineInfo << '\n';
11867- os << lineOfChars('.') << "\n\n";
11868- }
11869-
11870-} // end namespace Catch
11871-
11872-
11873-
11874-
11875-#if defined(_MSC_VER)
11876-#pragma warning(push)
11877-#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch
11878- // Note that 4062 (not all labels are handled
11879- // and default is missing) is enabled
11880-#endif
11881-
11882-namespace Catch {
11883- XmlReporter::XmlReporter( ReporterConfig&& _config )
11884- : StreamingReporterBase( CATCH_MOVE(_config) ),
11885- m_xml(m_stream)
11886- {
11887- m_preferences.shouldRedirectStdOut = true;
11888- m_preferences.shouldReportAllAssertions = true;
11889- m_preferences.shouldReportAllAssertionStarts = false;
11890- }
11891-
11892- XmlReporter::~XmlReporter() = default;
11893-
11894- std::string XmlReporter::getDescription() {
11895- return "Reports test results as an XML document";
11896- }
11897-
11898- std::string XmlReporter::getStylesheetRef() const {
11899- return std::string();
11900- }
11901-
11902- void XmlReporter::writeSourceInfo( SourceLineInfo const& sourceInfo ) {
11903- m_xml
11904- .writeAttribute( "filename"_sr, sourceInfo.file )
11905- .writeAttribute( "line"_sr, sourceInfo.line );
11906- }
11907-
11908- void XmlReporter::testRunStarting( TestRunInfo const& testInfo ) {
11909- StreamingReporterBase::testRunStarting( testInfo );
11910- std::string stylesheetRef = getStylesheetRef();
11911- if( !stylesheetRef.empty() )
11912- m_xml.writeStylesheetRef( stylesheetRef );
11913- m_xml.startElement("Catch2TestRun")
11914- .writeAttribute("name"_sr, m_config->name())
11915- .writeAttribute("rng-seed"_sr, m_config->rngSeed())
11916- .writeAttribute("xml-format-version"_sr, 3)
11917- .writeAttribute("catch2-version"_sr, libraryVersion());
11918- if ( m_config->testSpec().hasFilters() ) {
11919- m_xml.writeAttribute( "filters"_sr, m_config->testSpec() );
11920- }
11921- }
11922-
11923- void XmlReporter::testCaseStarting( TestCaseInfo const& testInfo ) {
11924- StreamingReporterBase::testCaseStarting(testInfo);
11925- m_xml.startElement( "TestCase" )
11926- .writeAttribute( "name"_sr, trim( StringRef(testInfo.name) ) )
11927- .writeAttribute( "tags"_sr, testInfo.tagsAsString() );
11928-
11929- writeSourceInfo( testInfo.lineInfo );
11930-
11931- if ( m_config->showDurations() == ShowDurations::Always )
11932- m_testCaseTimer.start();
11933- m_xml.ensureTagClosed();
11934- }
11935-
11936- void XmlReporter::sectionStarting( SectionInfo const& sectionInfo ) {
11937- StreamingReporterBase::sectionStarting( sectionInfo );
11938- if( m_sectionDepth++ > 0 ) {
11939- m_xml.startElement( "Section" )
11940- .writeAttribute( "name"_sr, trim( StringRef(sectionInfo.name) ) );
11941- writeSourceInfo( sectionInfo.lineInfo );
11942- m_xml.ensureTagClosed();
11943- }
11944- }
11945-
11946- void XmlReporter::assertionEnded( AssertionStats const& assertionStats ) {
11947-
11948- AssertionResult const& result = assertionStats.assertionResult;
11949-
11950- bool includeResults = m_config->includeSuccessfulResults() || !result.isOk();
11951-
11952- if( includeResults || result.getResultType() == ResultWas::Warning ) {
11953- // Print any info messages in <Info> tags.
11954- for( auto const& msg : assertionStats.infoMessages ) {
11955- if( msg.type == ResultWas::Info && includeResults ) {
11956- auto t = m_xml.scopedElement( "Info" );
11957- writeSourceInfo( msg.lineInfo );
11958- t.writeText( msg.message );
11959- } else if ( msg.type == ResultWas::Warning ) {
11960- auto t = m_xml.scopedElement( "Warning" );
11961- writeSourceInfo( msg.lineInfo );
11962- t.writeText( msg.message );
11963- }
11964- }
11965- }
11966-
11967- // Drop out if result was successful but we're not printing them.
11968- if ( !includeResults && result.getResultType() != ResultWas::Warning &&
11969- result.getResultType() != ResultWas::ExplicitSkip ) {
11970- return;
11971- }
11972-
11973- // Print the expression if there is one.
11974- if( result.hasExpression() ) {
11975- m_xml.startElement( "Expression" )
11976- .writeAttribute( "success"_sr, result.succeeded() )
11977- .writeAttribute( "type"_sr, result.getTestMacroName() );
11978-
11979- writeSourceInfo( result.getSourceInfo() );
11980-
11981- m_xml.scopedElement( "Original" )
11982- .writeText( result.getExpression() );
11983- m_xml.scopedElement( "Expanded" )
11984- .writeText( result.getExpandedExpression() );
11985- }
11986-
11987- // And... Print a result applicable to each result type.
11988- switch( result.getResultType() ) {
11989- case ResultWas::ThrewException:
11990- m_xml.startElement( "Exception" );
11991- writeSourceInfo( result.getSourceInfo() );
11992- m_xml.writeText( result.getMessage() );
11993- m_xml.endElement();
11994- break;
11995- case ResultWas::FatalErrorCondition:
11996- m_xml.startElement( "FatalErrorCondition" );
11997- writeSourceInfo( result.getSourceInfo() );
11998- m_xml.writeText( result.getMessage() );
11999- m_xml.endElement();
12000- break;
12001- case ResultWas::Info:
12002- m_xml.scopedElement( "Info" )
12003- .writeText( result.getMessage() );
12004- break;
12005- case ResultWas::Warning:
12006- // Warning will already have been written
12007- break;
12008- case ResultWas::ExplicitFailure:
12009- m_xml.startElement( "Failure" );
12010- writeSourceInfo( result.getSourceInfo() );
12011- m_xml.writeText( result.getMessage() );
12012- m_xml.endElement();
12013- break;
12014- case ResultWas::ExplicitSkip:
12015- m_xml.startElement( "Skip" );
12016- writeSourceInfo( result.getSourceInfo() );
12017- m_xml.writeText( result.getMessage() );
12018- m_xml.endElement();
12019- break;
12020- default:
12021- break;
12022- }
12023-
12024- if( result.hasExpression() )
12025- m_xml.endElement();
12026- }
12027-
12028- void XmlReporter::sectionEnded( SectionStats const& sectionStats ) {
12029- StreamingReporterBase::sectionEnded( sectionStats );
12030- if ( --m_sectionDepth > 0 ) {
12031- {
12032- XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" );
12033- e.writeAttribute( "successes"_sr, sectionStats.assertions.passed );
12034- e.writeAttribute( "failures"_sr, sectionStats.assertions.failed );
12035- e.writeAttribute( "expectedFailures"_sr, sectionStats.assertions.failedButOk );
12036- e.writeAttribute( "skipped"_sr, sectionStats.assertions.skipped > 0 );
12037-
12038- if ( m_config->showDurations() == ShowDurations::Always )
12039- e.writeAttribute( "durationInSeconds"_sr, sectionStats.durationInSeconds );
12040- }
12041- // Ends assertion tag
12042- m_xml.endElement();
12043- }
12044- }
12045-
12046- void XmlReporter::testCaseEnded( TestCaseStats const& testCaseStats ) {
12047- StreamingReporterBase::testCaseEnded( testCaseStats );
12048- XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" );
12049- e.writeAttribute( "success"_sr, testCaseStats.totals.assertions.allOk() );
12050- e.writeAttribute( "skips"_sr, testCaseStats.totals.assertions.skipped );
12051-
12052- if ( m_config->showDurations() == ShowDurations::Always )
12053- e.writeAttribute( "durationInSeconds"_sr, m_testCaseTimer.getElapsedSeconds() );
12054- if( !testCaseStats.stdOut.empty() )
12055- m_xml.scopedElement( "StdOut" ).writeText( trim( StringRef(testCaseStats.stdOut) ), XmlFormatting::Newline );
12056- if( !testCaseStats.stdErr.empty() )
12057- m_xml.scopedElement( "StdErr" ).writeText( trim( StringRef(testCaseStats.stdErr) ), XmlFormatting::Newline );
12058-
12059- m_xml.endElement();
12060- }
12061-
12062- void XmlReporter::testRunEnded( TestRunStats const& testRunStats ) {
12063- StreamingReporterBase::testRunEnded( testRunStats );
12064- m_xml.scopedElement( "OverallResults" )
12065- .writeAttribute( "successes"_sr, testRunStats.totals.assertions.passed )
12066- .writeAttribute( "failures"_sr, testRunStats.totals.assertions.failed )
12067- .writeAttribute( "expectedFailures"_sr, testRunStats.totals.assertions.failedButOk )
12068- .writeAttribute( "skips"_sr, testRunStats.totals.assertions.skipped );
12069- m_xml.scopedElement( "OverallResultsCases")
12070- .writeAttribute( "successes"_sr, testRunStats.totals.testCases.passed )
12071- .writeAttribute( "failures"_sr, testRunStats.totals.testCases.failed )
12072- .writeAttribute( "expectedFailures"_sr, testRunStats.totals.testCases.failedButOk )
12073- .writeAttribute( "skips"_sr, testRunStats.totals.testCases.skipped );
12074- m_xml.endElement();
12075- }
12076-
12077- void XmlReporter::benchmarkPreparing( StringRef name ) {
12078- m_xml.startElement("BenchmarkResults")
12079- .writeAttribute("name"_sr, name);
12080- }
12081-
12082- void XmlReporter::benchmarkStarting(BenchmarkInfo const &info) {
12083- m_xml.writeAttribute("samples"_sr, info.samples)
12084- .writeAttribute("resamples"_sr, info.resamples)
12085- .writeAttribute("iterations"_sr, info.iterations)
12086- .writeAttribute("clockResolution"_sr, info.clockResolution)
12087- .writeAttribute("estimatedDuration"_sr, info.estimatedDuration)
12088- .writeComment("All values in nano seconds"_sr);
12089- }
12090-
12091- void XmlReporter::benchmarkEnded(BenchmarkStats<> const& benchmarkStats) {
12092- m_xml.scopedElement("mean")
12093- .writeAttribute("value"_sr, benchmarkStats.mean.point.count())
12094- .writeAttribute("lowerBound"_sr, benchmarkStats.mean.lower_bound.count())
12095- .writeAttribute("upperBound"_sr, benchmarkStats.mean.upper_bound.count())
12096- .writeAttribute("ci"_sr, benchmarkStats.mean.confidence_interval);
12097- m_xml.scopedElement("standardDeviation")
12098- .writeAttribute("value"_sr, benchmarkStats.standardDeviation.point.count())
12099- .writeAttribute("lowerBound"_sr, benchmarkStats.standardDeviation.lower_bound.count())
12100- .writeAttribute("upperBound"_sr, benchmarkStats.standardDeviation.upper_bound.count())
12101- .writeAttribute("ci"_sr, benchmarkStats.standardDeviation.confidence_interval);
12102- m_xml.scopedElement("outliers")
12103- .writeAttribute("variance"_sr, benchmarkStats.outlierVariance)
12104- .writeAttribute("lowMild"_sr, benchmarkStats.outliers.low_mild)
12105- .writeAttribute("lowSevere"_sr, benchmarkStats.outliers.low_severe)
12106- .writeAttribute("highMild"_sr, benchmarkStats.outliers.high_mild)
12107- .writeAttribute("highSevere"_sr, benchmarkStats.outliers.high_severe);
12108- m_xml.endElement();
12109- }
12110-
12111- void XmlReporter::benchmarkFailed(StringRef error) {
12112- m_xml.scopedElement("failed").
12113- writeAttribute("message"_sr, error);
12114- m_xml.endElement();
12115- }
12116-
12117- void XmlReporter::listReporters(std::vector<ReporterDescription> const& descriptions) {
12118- auto outerTag = m_xml.scopedElement("AvailableReporters");
12119- for (auto const& reporter : descriptions) {
12120- auto inner = m_xml.scopedElement("Reporter");
12121- m_xml.startElement("Name", XmlFormatting::Indent)
12122- .writeText(reporter.name, XmlFormatting::None)
12123- .endElement(XmlFormatting::Newline);
12124- m_xml.startElement("Description", XmlFormatting::Indent)
12125- .writeText(reporter.description, XmlFormatting::None)
12126- .endElement(XmlFormatting::Newline);
12127- }
12128- }
12129-
12130- void XmlReporter::listListeners(std::vector<ListenerDescription> const& descriptions) {
12131- auto outerTag = m_xml.scopedElement( "RegisteredListeners" );
12132- for ( auto const& listener : descriptions ) {
12133- auto inner = m_xml.scopedElement( "Listener" );
12134- m_xml.startElement( "Name", XmlFormatting::Indent )
12135- .writeText( listener.name, XmlFormatting::None )
12136- .endElement( XmlFormatting::Newline );
12137- m_xml.startElement( "Description", XmlFormatting::Indent )
12138- .writeText( listener.description, XmlFormatting::None )
12139- .endElement( XmlFormatting::Newline );
12140- }
12141- }
12142-
12143- void XmlReporter::listTests(std::vector<TestCaseHandle> const& tests) {
12144- auto outerTag = m_xml.scopedElement("MatchingTests");
12145- for (auto const& test : tests) {
12146- auto innerTag = m_xml.scopedElement("TestCase");
12147- auto const& testInfo = test.getTestCaseInfo();
12148- m_xml.startElement("Name", XmlFormatting::Indent)
12149- .writeText(testInfo.name, XmlFormatting::None)
12150- .endElement(XmlFormatting::Newline);
12151- m_xml.startElement("ClassName", XmlFormatting::Indent)
12152- .writeText(testInfo.className, XmlFormatting::None)
12153- .endElement(XmlFormatting::Newline);
12154- m_xml.startElement("Tags", XmlFormatting::Indent)
12155- .writeText(testInfo.tagsAsString(), XmlFormatting::None)
12156- .endElement(XmlFormatting::Newline);
12157-
12158- auto sourceTag = m_xml.scopedElement("SourceInfo");
12159- m_xml.startElement("File", XmlFormatting::Indent)
12160- .writeText(testInfo.lineInfo.file, XmlFormatting::None)
12161- .endElement(XmlFormatting::Newline);
12162- m_xml.startElement("Line", XmlFormatting::Indent)
12163- .writeText(std::to_string(testInfo.lineInfo.line), XmlFormatting::None)
12164- .endElement(XmlFormatting::Newline);
12165- }
12166- }
12167-
12168- void XmlReporter::listTags(std::vector<TagInfo> const& tags) {
12169- auto outerTag = m_xml.scopedElement("TagsFromMatchingTests");
12170- for (auto const& tag : tags) {
12171- auto innerTag = m_xml.scopedElement("Tag");
12172- m_xml.startElement("Count", XmlFormatting::Indent)
12173- .writeText(std::to_string(tag.count), XmlFormatting::None)
12174- .endElement(XmlFormatting::Newline);
12175- auto aliasTag = m_xml.scopedElement("Aliases");
12176- for (auto const& alias : tag.spellings) {
12177- m_xml.startElement("Alias", XmlFormatting::Indent)
12178- .writeText(alias, XmlFormatting::None)
12179- .endElement(XmlFormatting::Newline);
12180- }
12181- }
12182- }
12183-
12184-} // end namespace Catch
12185-
12186-#if defined(_MSC_VER)
12187-#pragma warning(pop)
12188-#endif
12189diff --git a/include/catch_amalgamated.hpp b/include/catch_amalgamated.hpp
12190deleted file mode 100644
12191index d5eb1bb..0000000
12192--- a/include/catch_amalgamated.hpp
12193+++ /dev/null
12194@@ -1,14314 +0,0 @@
12195-
12196-// Copyright Catch2 Authors
12197-// Distributed under the Boost Software License, Version 1.0.
12198-// (See accompanying file LICENSE.txt or copy at
12199-// https://www.boost.org/LICENSE_1_0.txt)
12200-
12201-// SPDX-License-Identifier: BSL-1.0
12202-
12203-// Catch v3.11.0
12204-// Generated: 2025-09-30 10:49:11.225746
12205-// ----------------------------------------------------------
12206-// This file is an amalgamation of multiple different files.
12207-// You probably shouldn't edit it directly.
12208-// ----------------------------------------------------------
12209-#ifndef CATCH_AMALGAMATED_HPP_INCLUDED
12210-#define CATCH_AMALGAMATED_HPP_INCLUDED
12211-
12212-
12213-/** \file
12214- * This is a convenience header for Catch2. It includes **all** of Catch2 headers.
12215- *
12216- * Generally the Catch2 users should use specific includes they need,
12217- * but this header can be used instead for ease-of-experimentation, or
12218- * just plain convenience, at the cost of (significantly) increased
12219- * compilation times.
12220- *
12221- * When a new header is added to either the top level folder, or to the
12222- * corresponding internal subfolder, it should be added here. Headers
12223- * added to the various subparts (e.g. matchers, generators, etc...),
12224- * should go their respective catch-all headers.
12225- */
12226-
12227-#ifndef CATCH_ALL_HPP_INCLUDED
12228-#define CATCH_ALL_HPP_INCLUDED
12229-
12230-
12231-
12232-/** \file
12233- * This is a convenience header for Catch2's benchmarking. It includes
12234- * **all** of Catch2 headers related to benchmarking.
12235- *
12236- * Generally the Catch2 users should use specific includes they need,
12237- * but this header can be used instead for ease-of-experimentation, or
12238- * just plain convenience, at the cost of (significantly) increased
12239- * compilation times.
12240- *
12241- * When a new header is added to either the `benchmark` folder, or to
12242- * the corresponding internal (detail) subfolder, it should be added here.
12243- */
12244-
12245-#ifndef CATCH_BENCHMARK_ALL_HPP_INCLUDED
12246-#define CATCH_BENCHMARK_ALL_HPP_INCLUDED
12247-
12248-
12249-
12250-// Adapted from donated nonius code.
12251-
12252-#ifndef CATCH_BENCHMARK_HPP_INCLUDED
12253-#define CATCH_BENCHMARK_HPP_INCLUDED
12254-
12255-
12256-
12257-#ifndef CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED
12258-#define CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED
12259-
12260-// Detect a number of compiler features - by compiler
12261-// The following features are defined:
12262-//
12263-// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported?
12264-// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported?
12265-// CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled?
12266-// ****************
12267-// Note to maintainers: if new toggles are added please document them
12268-// in configuration.md, too
12269-// ****************
12270-
12271-// In general each macro has a _NO_<feature name> form
12272-// (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature.
12273-// Many features, at point of detection, define an _INTERNAL_ macro, so they
12274-// can be combined, en-mass, with the _NO_ forms later.
12275-
12276-
12277-
12278-#ifndef CATCH_PLATFORM_HPP_INCLUDED
12279-#define CATCH_PLATFORM_HPP_INCLUDED
12280-
12281-// See e.g.:
12282-// https://opensource.apple.com/source/CarbonHeaders/CarbonHeaders-18.1/TargetConditionals.h.auto.html
12283-#ifdef __APPLE__
12284-# ifndef __has_extension
12285-# define __has_extension(x) 0
12286-# endif
12287-# include <TargetConditionals.h>
12288-# if (defined(TARGET_OS_OSX) && TARGET_OS_OSX == 1) || \
12289- (defined(TARGET_OS_MAC) && TARGET_OS_MAC == 1)
12290-# define CATCH_PLATFORM_MAC
12291-# elif (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE == 1)
12292-# define CATCH_PLATFORM_IPHONE
12293-# endif
12294-
12295-#elif defined(linux) || defined(__linux) || defined(__linux__)
12296-# define CATCH_PLATFORM_LINUX
12297-
12298-#elif defined(__QNX__)
12299-# define CATCH_PLATFORM_QNX
12300-
12301-#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__)
12302-# define CATCH_PLATFORM_WINDOWS
12303-
12304-# if defined( WINAPI_FAMILY ) && ( WINAPI_FAMILY == WINAPI_FAMILY_APP )
12305-# define CATCH_PLATFORM_WINDOWS_UWP
12306-# endif
12307-
12308-#elif defined(__ORBIS__) || defined(__PROSPERO__)
12309-# define CATCH_PLATFORM_PLAYSTATION
12310-
12311-#endif
12312-
12313-#endif // CATCH_PLATFORM_HPP_INCLUDED
12314-
12315-#ifdef __cplusplus
12316-
12317-# if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
12318-# define CATCH_CPP17_OR_GREATER
12319-# endif
12320-
12321-# if (__cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)
12322-# define CATCH_CPP20_OR_GREATER
12323-# endif
12324-
12325-#endif
12326-
12327-// Only GCC compiler should be used in this block, so other compilers trying to
12328-// mask themselves as GCC should be ignored.
12329-#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__) && !defined(__NVCOMPILER)
12330-# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" )
12331-# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" )
12332-
12333-// This only works on GCC 9+. so we have to also add a global suppression of Wparentheses
12334-// for older versions of GCC.
12335-# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
12336- _Pragma( "GCC diagnostic ignored \"-Wparentheses\"" )
12337-
12338-# define CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT \
12339- _Pragma( "GCC diagnostic ignored \"-Wunused-result\"" )
12340-
12341-# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
12342- _Pragma( "GCC diagnostic ignored \"-Wunused-variable\"" )
12343-
12344-# define CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \
12345- _Pragma( "GCC diagnostic ignored \"-Wuseless-cast\"" )
12346-
12347-# define CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \
12348- _Pragma( "GCC diagnostic ignored \"-Wshadow\"" )
12349-
12350-# define CATCH_INTERNAL_CONFIG_USE_BUILTIN_CONSTANT_P
12351-
12352-#endif
12353-
12354-#if defined(__NVCOMPILER)
12355-# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "diag push" )
12356-# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "diag pop" )
12357-# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS _Pragma( "diag_suppress declared_but_not_referenced" )
12358-#endif
12359-
12360-#if defined(__CUDACC__) && !defined(__clang__)
12361-# ifdef __NVCC_DIAG_PRAGMA_SUPPORT__
12362-// New pragmas introduced in CUDA 11.5+
12363-# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "nv_diagnostic push" )
12364-# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "nv_diagnostic pop" )
12365-# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS _Pragma( "nv_diag_suppress 177" )
12366-# else
12367-# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS _Pragma( "diag_suppress 177" )
12368-# endif
12369-#endif
12370-
12371-// clang-cl defines _MSC_VER as well as __clang__, which could cause the
12372-// start/stop internal suppression macros to be double defined.
12373-#if defined(__clang__) && !defined(_MSC_VER)
12374-# define CATCH_INTERNAL_CONFIG_USE_BUILTIN_CONSTANT_P
12375-# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" )
12376-# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" )
12377-#endif // __clang__ && !_MSC_VER
12378-
12379-#if defined(__clang__)
12380-
12381-# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
12382- _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \
12383- _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"")
12384-
12385-# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
12386- _Pragma( "clang diagnostic ignored \"-Wparentheses\"" )
12387-
12388-# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
12389- _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" )
12390-
12391-# if (__clang_major__ >= 20)
12392-# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
12393- _Pragma( "clang diagnostic ignored \"-Wvariadic-macro-arguments-omitted\"" )
12394-# elif (__clang_major__ == 19)
12395-# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
12396- _Pragma( "clang diagnostic ignored \"-Wc++20-extensions\"" )
12397-# else
12398-# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS
12399- _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" )
12400-# endif
12401-
12402-# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
12403- _Pragma( "clang diagnostic ignored \"-Wunused-template\"" )
12404-
12405-# define CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS \
12406- _Pragma( "clang diagnostic ignored \"-Wcomma\"" )
12407-
12408-# define CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \
12409- _Pragma( "clang diagnostic ignored \"-Wshadow\"" )
12410-
12411-#endif // __clang__
12412-
12413-// As of this writing, IBM XL's implementation of __builtin_constant_p has a bug
12414-// which results in calls to destructors being emitted for each temporary,
12415-// without a matching initialization. In practice, this can result in something
12416-// like `std::string::~string` being called on an uninitialized value.
12417-//
12418-// For example, this code will likely segfault under IBM XL:
12419-// ```
12420-// REQUIRE(std::string("12") + "34" == "1234")
12421-// ```
12422-//
12423-// Similarly, NVHPC's implementation of `__builtin_constant_p` has a bug which
12424-// results in calls to the immediately evaluated lambda expressions to be
12425-// reported as unevaluated lambdas.
12426-// https://developer.nvidia.com/nvidia_bug/3321845.
12427-//
12428-// Therefore, `CATCH_INTERNAL_IGNORE_BUT_WARN` is not implemented.
12429-#if defined( __ibmxl__ ) || defined( __CUDACC__ ) || defined( __NVCOMPILER )
12430-# define CATCH_INTERNAL_CONFIG_NO_USE_BUILTIN_CONSTANT_P
12431-#endif
12432-
12433-
12434-
12435-////////////////////////////////////////////////////////////////////////////////
12436-// We know some environments not to support full POSIX signals
12437-#if defined( CATCH_PLATFORM_WINDOWS ) || \
12438- defined( CATCH_PLATFORM_PLAYSTATION ) || \
12439- defined( __CYGWIN__ ) || \
12440- defined( __QNX__ ) || \
12441- defined( __EMSCRIPTEN__ ) || \
12442- defined( __DJGPP__ ) || \
12443- defined( __OS400__ )
12444-# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS
12445-#else
12446-# define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS
12447-#endif
12448-
12449-////////////////////////////////////////////////////////////////////////////////
12450-// Assume that some platforms do not support getenv.
12451-#if defined( CATCH_PLATFORM_WINDOWS_UWP ) || \
12452- defined( CATCH_PLATFORM_PLAYSTATION ) || \
12453- defined( _GAMING_XBOX )
12454-# define CATCH_INTERNAL_CONFIG_NO_GETENV
12455-#else
12456-# define CATCH_INTERNAL_CONFIG_GETENV
12457-#endif
12458-
12459-////////////////////////////////////////////////////////////////////////////////
12460-// Android somehow still does not support std::to_string
12461-#if defined(__ANDROID__)
12462-# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING
12463-#endif
12464-
12465-////////////////////////////////////////////////////////////////////////////////
12466-// Not all Windows environments support SEH properly
12467-#if defined(__MINGW32__)
12468-# define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH
12469-#endif
12470-
12471-////////////////////////////////////////////////////////////////////////////////
12472-// PS4
12473-#if defined(__ORBIS__)
12474-# define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE
12475-#endif
12476-
12477-////////////////////////////////////////////////////////////////////////////////
12478-// Cygwin
12479-#ifdef __CYGWIN__
12480-
12481-// Required for some versions of Cygwin to declare gettimeofday
12482-// see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin
12483-# define _BSD_SOURCE
12484-// some versions of cygwin (most) do not support std::to_string. Use the libstd check.
12485-// https://gcc.gnu.org/onlinedocs/gcc-4.8.2/libstdc++/api/a01053_source.html line 2812-2813
12486-# if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \
12487- && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF))
12488-
12489-# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING
12490-
12491-# endif
12492-#endif // __CYGWIN__
12493-
12494-////////////////////////////////////////////////////////////////////////////////
12495-// Visual C++
12496-#if defined(_MSC_VER)
12497-
12498-// We want to defer to nvcc-specific warning suppression if we are compiled
12499-// with nvcc masquerading for MSVC.
12500-# if !defined( __CUDACC__ )
12501-# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
12502- __pragma( warning( push ) )
12503-# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
12504- __pragma( warning( pop ) )
12505-# endif
12506-
12507-// Universal Windows platform does not support SEH
12508-# if !defined(CATCH_PLATFORM_WINDOWS_UWP)
12509-# define CATCH_INTERNAL_CONFIG_WINDOWS_SEH
12510-# endif
12511-
12512-// Only some Windows platform families support the console
12513-# if defined(WINAPI_FAMILY_PARTITION)
12514-# if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
12515-# define CATCH_INTERNAL_CONFIG_NO_COLOUR_WIN32
12516-# endif
12517-# endif
12518-
12519-// MSVC traditional preprocessor needs some workaround for __VA_ARGS__
12520-// _MSVC_TRADITIONAL == 0 means new conformant preprocessor
12521-// _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor
12522-# if !defined(__clang__) // Handle Clang masquerading for msvc
12523-# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL)
12524-# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
12525-# endif // MSVC_TRADITIONAL
12526-# endif // __clang__
12527-
12528-#endif // _MSC_VER
12529-
12530-#if defined(_REENTRANT) || defined(_MSC_VER)
12531-// Enable async processing, as -pthread is specified or no additional linking is required
12532-# define CATCH_INTERNAL_CONFIG_USE_ASYNC
12533-#endif // _MSC_VER
12534-
12535-////////////////////////////////////////////////////////////////////////////////
12536-// Check if we are compiled with -fno-exceptions or equivalent
12537-#if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND)
12538-# define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED
12539-#endif
12540-
12541-
12542-////////////////////////////////////////////////////////////////////////////////
12543-// Embarcadero C++Build
12544-#if defined(__BORLANDC__)
12545- #define CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN
12546-#endif
12547-
12548-////////////////////////////////////////////////////////////////////////////////
12549-
12550-// RTX is a special version of Windows that is real time.
12551-// This means that it is detected as Windows, but does not provide
12552-// the same set of capabilities as real Windows does.
12553-#if defined(UNDER_RTSS) || defined(RTX64_BUILD)
12554- #define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH
12555- #define CATCH_INTERNAL_CONFIG_NO_ASYNC
12556- #define CATCH_INTERNAL_CONFIG_NO_COLOUR_WIN32
12557-#endif
12558-
12559-#if !defined(_GLIBCXX_USE_C99_MATH_TR1)
12560-#define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER
12561-#endif
12562-
12563-// Various stdlib support checks that require __has_include
12564-#if defined(__has_include)
12565- // Check if string_view is available and usable
12566- #if __has_include(<string_view>) && defined(CATCH_CPP17_OR_GREATER)
12567- # define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW
12568- #endif
12569-
12570- // Check if optional is available and usable
12571- # if __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)
12572- # define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL
12573- # endif // __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)
12574-
12575- // Check if byte is available and usable
12576- # if __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER)
12577- # include <cstddef>
12578- # if defined(__cpp_lib_byte) && (__cpp_lib_byte > 0)
12579- # define CATCH_INTERNAL_CONFIG_CPP17_BYTE
12580- # endif
12581- # endif // __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER)
12582-
12583- // Check if variant is available and usable
12584- # if __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
12585- # if defined(__clang__) && (__clang_major__ < 8)
12586- // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852
12587- // fix should be in clang 8, workaround in libstdc++ 8.2
12588- # include <ciso646>
12589- # if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
12590- # define CATCH_CONFIG_NO_CPP17_VARIANT
12591- # else
12592- # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT
12593- # endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
12594- # else
12595- # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT
12596- # endif // defined(__clang__) && (__clang_major__ < 8)
12597- # endif // __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
12598-#endif // defined(__has_include)
12599-
12600-
12601-#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)
12602-# define CATCH_CONFIG_WINDOWS_SEH
12603-#endif
12604-// This is set by default, because we assume that unix compilers are posix-signal-compatible by default.
12605-#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)
12606-# define CATCH_CONFIG_POSIX_SIGNALS
12607-#endif
12608-
12609-#if defined(CATCH_INTERNAL_CONFIG_GETENV) && !defined(CATCH_INTERNAL_CONFIG_NO_GETENV) && !defined(CATCH_CONFIG_NO_GETENV) && !defined(CATCH_CONFIG_GETENV)
12610-# define CATCH_CONFIG_GETENV
12611-#endif
12612-
12613-#if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING)
12614-# define CATCH_CONFIG_CPP11_TO_STRING
12615-#endif
12616-
12617-#if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL)
12618-# define CATCH_CONFIG_CPP17_OPTIONAL
12619-#endif
12620-
12621-#if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW)
12622-# define CATCH_CONFIG_CPP17_STRING_VIEW
12623-#endif
12624-
12625-#if defined(CATCH_INTERNAL_CONFIG_CPP17_VARIANT) && !defined(CATCH_CONFIG_NO_CPP17_VARIANT) && !defined(CATCH_CONFIG_CPP17_VARIANT)
12626-# define CATCH_CONFIG_CPP17_VARIANT
12627-#endif
12628-
12629-#if defined(CATCH_INTERNAL_CONFIG_CPP17_BYTE) && !defined(CATCH_CONFIG_NO_CPP17_BYTE) && !defined(CATCH_CONFIG_CPP17_BYTE)
12630-# define CATCH_CONFIG_CPP17_BYTE
12631-#endif
12632-
12633-
12634-#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT)
12635-# define CATCH_INTERNAL_CONFIG_NEW_CAPTURE
12636-#endif
12637-
12638-#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)
12639-# define CATCH_CONFIG_NEW_CAPTURE
12640-#endif
12641-
12642-#if !defined( CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED ) && \
12643- !defined( CATCH_CONFIG_DISABLE_EXCEPTIONS ) && \
12644- !defined( CATCH_CONFIG_NO_DISABLE_EXCEPTIONS )
12645-# define CATCH_CONFIG_DISABLE_EXCEPTIONS
12646-#endif
12647-
12648-#if defined(CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_NO_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_POLYFILL_ISNAN)
12649-# define CATCH_CONFIG_POLYFILL_ISNAN
12650-#endif
12651-
12652-#if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC) && !defined(CATCH_INTERNAL_CONFIG_NO_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC)
12653-# define CATCH_CONFIG_USE_ASYNC
12654-#endif
12655-
12656-#if defined(CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_NO_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_GLOBAL_NEXTAFTER)
12657-# define CATCH_CONFIG_GLOBAL_NEXTAFTER
12658-#endif
12659-
12660-
12661-// The goal of this macro is to avoid evaluation of the arguments, but
12662-// still have the compiler warn on problems inside...
12663-#if defined( CATCH_INTERNAL_CONFIG_USE_BUILTIN_CONSTANT_P ) && \
12664- !defined( CATCH_INTERNAL_CONFIG_NO_USE_BUILTIN_CONSTANT_P ) && !defined(CATCH_CONFIG_USE_BUILTIN_CONSTANT_P)
12665-#define CATCH_CONFIG_USE_BUILTIN_CONSTANT_P
12666-#endif
12667-
12668-#if defined( CATCH_CONFIG_USE_BUILTIN_CONSTANT_P ) && \
12669- !defined( CATCH_CONFIG_NO_USE_BUILTIN_CONSTANT_P )
12670-# define CATCH_INTERNAL_IGNORE_BUT_WARN( ... ) \
12671- (void)__builtin_constant_p( __VA_ARGS__ ) /* NOLINT(cppcoreguidelines-pro-type-vararg, \
12672- hicpp-vararg) */
12673-#else
12674-# define CATCH_INTERNAL_IGNORE_BUT_WARN( ... )
12675-#endif
12676-
12677-// Even if we do not think the compiler has that warning, we still have
12678-// to provide a macro that can be used by the code.
12679-#if !defined(CATCH_INTERNAL_START_WARNINGS_SUPPRESSION)
12680-# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
12681-#endif
12682-#if !defined(CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION)
12683-# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
12684-#endif
12685-#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS)
12686-# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS
12687-#endif
12688-#if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS)
12689-# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
12690-#endif
12691-#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT)
12692-# define CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT
12693-#endif
12694-#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS)
12695-# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS
12696-#endif
12697-#if !defined(CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS)
12698-# define CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS
12699-#endif
12700-#if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS)
12701-# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS
12702-#endif
12703-#if !defined( CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS )
12704-# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS
12705-#endif
12706-#if !defined( CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS )
12707-# define CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS
12708-#endif
12709-#if !defined( CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS )
12710-# define CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS
12711-#endif
12712-
12713-#if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10)
12714-# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS
12715-#elif defined(__clang__) && (__clang_major__ < 5)
12716-# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS
12717-#endif
12718-
12719-
12720-#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
12721-#define CATCH_TRY if ((true))
12722-#define CATCH_CATCH_ALL if ((false))
12723-#define CATCH_CATCH_ANON(type) if ((false))
12724-#else
12725-#define CATCH_TRY try
12726-#define CATCH_CATCH_ALL catch (...)
12727-#define CATCH_CATCH_ANON(type) catch (type)
12728-#endif
12729-
12730-#if defined(CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_NO_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR)
12731-#define CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
12732-#endif
12733-
12734-#if defined( CATCH_PLATFORM_WINDOWS ) && \
12735- !defined( CATCH_CONFIG_COLOUR_WIN32 ) && \
12736- !defined( CATCH_CONFIG_NO_COLOUR_WIN32 ) && \
12737- !defined( CATCH_INTERNAL_CONFIG_NO_COLOUR_WIN32 )
12738-# define CATCH_CONFIG_COLOUR_WIN32
12739-#endif
12740-
12741-#if defined( CATCH_CONFIG_SHARED_LIBRARY ) && defined( _MSC_VER ) && \
12742- !defined( CATCH_CONFIG_STATIC )
12743-# ifdef Catch2_EXPORTS
12744-# define CATCH_EXPORT //__declspec( dllexport ) // not needed
12745-# else
12746-# define CATCH_EXPORT __declspec( dllimport )
12747-# endif
12748-#else
12749-# define CATCH_EXPORT
12750-#endif
12751-
12752-#endif // CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED
12753-
12754-
12755-#ifndef CATCH_CONTEXT_HPP_INCLUDED
12756-#define CATCH_CONTEXT_HPP_INCLUDED
12757-
12758-
12759-namespace Catch {
12760-
12761- class IResultCapture;
12762- class IConfig;
12763-
12764- class Context {
12765- IConfig const* m_config = nullptr;
12766- IResultCapture* m_resultCapture = nullptr;
12767-
12768- CATCH_EXPORT static Context currentContext;
12769- friend Context& getCurrentMutableContext();
12770- friend Context const& getCurrentContext();
12771-
12772- public:
12773- constexpr IResultCapture* getResultCapture() const {
12774- return m_resultCapture;
12775- }
12776- constexpr IConfig const* getConfig() const { return m_config; }
12777- constexpr void setResultCapture( IResultCapture* resultCapture ) {
12778- m_resultCapture = resultCapture;
12779- }
12780- constexpr void setConfig( IConfig const* config ) { m_config = config; }
12781- };
12782-
12783- Context& getCurrentMutableContext();
12784-
12785- inline Context const& getCurrentContext() {
12786- return Context::currentContext;
12787- }
12788-
12789- class SimplePcg32;
12790- SimplePcg32& sharedRng();
12791-}
12792-
12793-#endif // CATCH_CONTEXT_HPP_INCLUDED
12794-
12795-
12796-#ifndef CATCH_MOVE_AND_FORWARD_HPP_INCLUDED
12797-#define CATCH_MOVE_AND_FORWARD_HPP_INCLUDED
12798-
12799-#include <type_traits>
12800-
12801-//! Replacement for std::move with better compile time performance
12802-#define CATCH_MOVE(...) static_cast<std::remove_reference_t<decltype(__VA_ARGS__)>&&>(__VA_ARGS__)
12803-
12804-//! Replacement for std::forward with better compile time performance
12805-#define CATCH_FORWARD(...) static_cast<decltype(__VA_ARGS__)&&>(__VA_ARGS__)
12806-
12807-#endif // CATCH_MOVE_AND_FORWARD_HPP_INCLUDED
12808-
12809-
12810-#ifndef CATCH_TEST_FAILURE_EXCEPTION_HPP_INCLUDED
12811-#define CATCH_TEST_FAILURE_EXCEPTION_HPP_INCLUDED
12812-
12813-namespace Catch {
12814-
12815- //! Used to signal that an assertion macro failed
12816- struct TestFailureException{};
12817- //! Used to signal that the remainder of a test should be skipped
12818- struct TestSkipException {};
12819-
12820- /**
12821- * Outlines throwing of `TestFailureException` into a single TU
12822- *
12823- * Also handles `CATCH_CONFIG_DISABLE_EXCEPTIONS` for callers.
12824- */
12825- [[noreturn]] void throw_test_failure_exception();
12826-
12827- /**
12828- * Outlines throwing of `TestSkipException` into a single TU
12829- *
12830- * Also handles `CATCH_CONFIG_DISABLE_EXCEPTIONS` for callers.
12831- */
12832- [[noreturn]] void throw_test_skip_exception();
12833-
12834-} // namespace Catch
12835-
12836-#endif // CATCH_TEST_FAILURE_EXCEPTION_HPP_INCLUDED
12837-
12838-
12839-#ifndef CATCH_UNIQUE_NAME_HPP_INCLUDED
12840-#define CATCH_UNIQUE_NAME_HPP_INCLUDED
12841-
12842-
12843-
12844-
12845-/** \file
12846- * Wrapper for the CONFIG configuration option
12847- *
12848- * When generating internal unique names, there are two options. Either
12849- * we mix in the current line number, or mix in an incrementing number.
12850- * We prefer the latter, using `__COUNTER__`, but users might want to
12851- * use the former.
12852- */
12853-
12854-#ifndef CATCH_CONFIG_COUNTER_HPP_INCLUDED
12855-#define CATCH_CONFIG_COUNTER_HPP_INCLUDED
12856-
12857-
12858-#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L )
12859- #define CATCH_INTERNAL_CONFIG_COUNTER
12860-#endif
12861-
12862-#if defined( CATCH_INTERNAL_CONFIG_COUNTER ) && \
12863- !defined( CATCH_CONFIG_NO_COUNTER ) && \
12864- !defined( CATCH_CONFIG_COUNTER )
12865-# define CATCH_CONFIG_COUNTER
12866-#endif
12867-
12868-
12869-#endif // CATCH_CONFIG_COUNTER_HPP_INCLUDED
12870-#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line
12871-#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line )
12872-#ifdef CATCH_CONFIG_COUNTER
12873-# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ )
12874-#else
12875-# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ )
12876-#endif
12877-
12878-#endif // CATCH_UNIQUE_NAME_HPP_INCLUDED
12879-
12880-
12881-#ifndef CATCH_INTERFACES_CAPTURE_HPP_INCLUDED
12882-#define CATCH_INTERFACES_CAPTURE_HPP_INCLUDED
12883-
12884-#include <string>
12885-
12886-
12887-
12888-#ifndef CATCH_STRINGREF_HPP_INCLUDED
12889-#define CATCH_STRINGREF_HPP_INCLUDED
12890-
12891-#include <cstddef>
12892-#include <string>
12893-#include <iosfwd>
12894-#include <cassert>
12895-
12896-#include <cstring>
12897-
12898-namespace Catch {
12899-
12900- /// A non-owning string class (similar to the forthcoming std::string_view)
12901- /// Note that, because a StringRef may be a substring of another string,
12902- /// it may not be null terminated.
12903- class StringRef {
12904- public:
12905- using size_type = std::size_t;
12906- using const_iterator = const char*;
12907-
12908- static constexpr size_type npos{ static_cast<size_type>( -1 ) };
12909-
12910- private:
12911- static constexpr char const* const s_empty = "";
12912-
12913- char const* m_start = s_empty;
12914- size_type m_size = 0;
12915-
12916- public: // construction
12917- constexpr StringRef() noexcept = default;
12918-
12919- StringRef( char const* rawChars ) noexcept;
12920-
12921- constexpr StringRef( char const* rawChars, size_type size ) noexcept
12922- : m_start( rawChars ),
12923- m_size( size )
12924- {}
12925-
12926- StringRef( std::string const& stdString ) noexcept
12927- : m_start( stdString.c_str() ),
12928- m_size( stdString.size() )
12929- {}
12930-
12931- explicit operator std::string() const {
12932- return std::string(m_start, m_size);
12933- }
12934-
12935- public: // operators
12936- auto operator == ( StringRef other ) const noexcept -> bool {
12937- return m_size == other.m_size
12938- && (std::memcmp( m_start, other.m_start, m_size ) == 0);
12939- }
12940- auto operator != (StringRef other) const noexcept -> bool {
12941- return !(*this == other);
12942- }
12943-
12944- constexpr auto operator[] ( size_type index ) const noexcept -> char {
12945- assert(index < m_size);
12946- return m_start[index];
12947- }
12948-
12949- bool operator<(StringRef rhs) const noexcept;
12950-
12951- public: // named queries
12952- constexpr auto empty() const noexcept -> bool {
12953- return m_size == 0;
12954- }
12955- constexpr auto size() const noexcept -> size_type {
12956- return m_size;
12957- }
12958-
12959- // Returns a substring of [start, start + length).
12960- // If start + length > size(), then the substring is [start, size()).
12961- // If start > size(), then the substring is empty.
12962- constexpr StringRef substr(size_type start, size_type length) const noexcept {
12963- if (start < m_size) {
12964- const auto shortened_size = m_size - start;
12965- return StringRef(m_start + start, (shortened_size < length) ? shortened_size : length);
12966- } else {
12967- return StringRef();
12968- }
12969- }
12970-
12971- // Returns the current start pointer. May not be null-terminated.
12972- constexpr char const* data() const noexcept {
12973- return m_start;
12974- }
12975-
12976- constexpr const_iterator begin() const { return m_start; }
12977- constexpr const_iterator end() const { return m_start + m_size; }
12978-
12979-
12980- friend std::string& operator += (std::string& lhs, StringRef rhs);
12981- friend std::ostream& operator << (std::ostream& os, StringRef str);
12982- friend std::string operator+(StringRef lhs, StringRef rhs);
12983-
12984- /**
12985- * Provides a three-way comparison with rhs
12986- *
12987- * Returns negative number if lhs < rhs, 0 if lhs == rhs, and a positive
12988- * number if lhs > rhs
12989- */
12990- int compare( StringRef rhs ) const;
12991- };
12992-
12993-
12994- constexpr auto operator ""_sr( char const* rawChars, std::size_t size ) noexcept -> StringRef {
12995- return StringRef( rawChars, size );
12996- }
12997-} // namespace Catch
12998-
12999-constexpr auto operator ""_catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef {
13000- return Catch::StringRef( rawChars, size );
13001-}
13002-
13003-#endif // CATCH_STRINGREF_HPP_INCLUDED
13004-
13005-
13006-#ifndef CATCH_RESULT_TYPE_HPP_INCLUDED
13007-#define CATCH_RESULT_TYPE_HPP_INCLUDED
13008-
13009-namespace Catch {
13010-
13011- // ResultWas::OfType enum
13012- struct ResultWas { enum OfType {
13013- Unknown = -1,
13014- Ok = 0,
13015- Info = 1,
13016- Warning = 2,
13017- // TODO: Should explicit skip be considered "not OK" (cf. isOk)? I.e., should it have the failure bit?
13018- ExplicitSkip = 4,
13019-
13020- FailureBit = 0x10,
13021-
13022- ExpressionFailed = FailureBit | 1,
13023- ExplicitFailure = FailureBit | 2,
13024-
13025- Exception = 0x100 | FailureBit,
13026-
13027- ThrewException = Exception | 1,
13028- DidntThrowException = Exception | 2,
13029-
13030- FatalErrorCondition = 0x200 | FailureBit
13031-
13032- }; };
13033-
13034- constexpr bool isOk( ResultWas::OfType resultType ) {
13035- return ( resultType & ResultWas::FailureBit ) == 0;
13036- }
13037- constexpr bool isJustInfo( int flags ) { return flags == ResultWas::Info; }
13038-
13039-
13040- // ResultDisposition::Flags enum
13041- struct ResultDisposition { enum Flags {
13042- Normal = 0x01,
13043-
13044- ContinueOnFailure = 0x02, // Failures fail test, but execution continues
13045- FalseTest = 0x04, // Prefix expression with !
13046- SuppressFail = 0x08 // Failures are reported but do not fail the test
13047- }; };
13048-
13049- constexpr ResultDisposition::Flags operator|( ResultDisposition::Flags lhs,
13050- ResultDisposition::Flags rhs ) {
13051- return static_cast<ResultDisposition::Flags>( static_cast<int>( lhs ) |
13052- static_cast<int>( rhs ) );
13053- }
13054-
13055- constexpr bool isFalseTest( int flags ) {
13056- return ( flags & ResultDisposition::FalseTest ) != 0;
13057- }
13058- constexpr bool shouldSuppressFailure( int flags ) {
13059- return ( flags & ResultDisposition::SuppressFail ) != 0;
13060- }
13061-
13062-} // end namespace Catch
13063-
13064-#endif // CATCH_RESULT_TYPE_HPP_INCLUDED
13065-
13066-
13067-#ifndef CATCH_UNIQUE_PTR_HPP_INCLUDED
13068-#define CATCH_UNIQUE_PTR_HPP_INCLUDED
13069-
13070-#include <cassert>
13071-#include <type_traits>
13072-
13073-
13074-namespace Catch {
13075-namespace Detail {
13076- /**
13077- * A reimplementation of `std::unique_ptr` for improved compilation performance
13078- *
13079- * Does not support arrays nor custom deleters.
13080- */
13081- template <typename T>
13082- class unique_ptr {
13083- T* m_ptr;
13084- public:
13085- constexpr unique_ptr(std::nullptr_t = nullptr):
13086- m_ptr{}
13087- {}
13088- explicit constexpr unique_ptr(T* ptr):
13089- m_ptr(ptr)
13090- {}
13091-
13092- template <typename U, typename = std::enable_if_t<std::is_base_of<T, U>::value>>
13093- unique_ptr(unique_ptr<U>&& from):
13094- m_ptr(from.release())
13095- {}
13096-
13097- template <typename U, typename = std::enable_if_t<std::is_base_of<T, U>::value>>
13098- unique_ptr& operator=(unique_ptr<U>&& from) {
13099- reset(from.release());
13100-
13101- return *this;
13102- }
13103-
13104- unique_ptr(unique_ptr const&) = delete;
13105- unique_ptr& operator=(unique_ptr const&) = delete;
13106-
13107- unique_ptr(unique_ptr&& rhs) noexcept:
13108- m_ptr(rhs.m_ptr) {
13109- rhs.m_ptr = nullptr;
13110- }
13111- unique_ptr& operator=(unique_ptr&& rhs) noexcept {
13112- reset(rhs.release());
13113-
13114- return *this;
13115- }
13116-
13117- ~unique_ptr() {
13118- delete m_ptr;
13119- }
13120-
13121- T& operator*() {
13122- assert(m_ptr);
13123- return *m_ptr;
13124- }
13125- T const& operator*() const {
13126- assert(m_ptr);
13127- return *m_ptr;
13128- }
13129- T* operator->() noexcept {
13130- assert(m_ptr);
13131- return m_ptr;
13132- }
13133- T const* operator->() const noexcept {
13134- assert(m_ptr);
13135- return m_ptr;
13136- }
13137-
13138- T* get() { return m_ptr; }
13139- T const* get() const { return m_ptr; }
13140-
13141- void reset(T* ptr = nullptr) {
13142- delete m_ptr;
13143- m_ptr = ptr;
13144- }
13145-
13146- T* release() {
13147- auto temp = m_ptr;
13148- m_ptr = nullptr;
13149- return temp;
13150- }
13151-
13152- explicit operator bool() const {
13153- return m_ptr != nullptr;
13154- }
13155-
13156- friend void swap(unique_ptr& lhs, unique_ptr& rhs) {
13157- auto temp = lhs.m_ptr;
13158- lhs.m_ptr = rhs.m_ptr;
13159- rhs.m_ptr = temp;
13160- }
13161- };
13162-
13163- //! Specialization to cause compile-time error for arrays
13164- template <typename T>
13165- class unique_ptr<T[]>;
13166-
13167- template <typename T, typename... Args>
13168- unique_ptr<T> make_unique(Args&&... args) {
13169- return unique_ptr<T>(new T(CATCH_FORWARD(args)...));
13170- }
13171-
13172-
13173-} // end namespace Detail
13174-} // end namespace Catch
13175-
13176-#endif // CATCH_UNIQUE_PTR_HPP_INCLUDED
13177-
13178-
13179-#ifndef CATCH_BENCHMARK_STATS_FWD_HPP_INCLUDED
13180-#define CATCH_BENCHMARK_STATS_FWD_HPP_INCLUDED
13181-
13182-
13183-
13184-// Adapted from donated nonius code.
13185-
13186-#ifndef CATCH_CLOCK_HPP_INCLUDED
13187-#define CATCH_CLOCK_HPP_INCLUDED
13188-
13189-#include <chrono>
13190-
13191-namespace Catch {
13192- namespace Benchmark {
13193- using IDuration = std::chrono::nanoseconds;
13194- using FDuration = std::chrono::duration<double, std::nano>;
13195-
13196- template <typename Clock>
13197- using TimePoint = typename Clock::time_point;
13198-
13199- using default_clock = std::chrono::steady_clock;
13200- } // namespace Benchmark
13201-} // namespace Catch
13202-
13203-#endif // CATCH_CLOCK_HPP_INCLUDED
13204-
13205-namespace Catch {
13206-
13207- // We cannot forward declare the type with default template argument
13208- // multiple times, so it is split out into a separate header so that
13209- // we can prevent multiple declarations in dependees
13210- template <typename Duration = Benchmark::FDuration>
13211- struct BenchmarkStats;
13212-
13213-} // end namespace Catch
13214-
13215-#endif // CATCH_BENCHMARK_STATS_FWD_HPP_INCLUDED
13216-
13217-namespace Catch {
13218-
13219- class AssertionResult;
13220- struct AssertionInfo;
13221- struct SectionInfo;
13222- struct SectionEndInfo;
13223- struct MessageInfo;
13224- struct MessageBuilder;
13225- struct Counts;
13226- struct AssertionReaction;
13227- struct SourceLineInfo;
13228-
13229- class ITransientExpression;
13230- class IGeneratorTracker;
13231-
13232- struct BenchmarkInfo;
13233-
13234- namespace Generators {
13235- class GeneratorUntypedBase;
13236- using GeneratorBasePtr = Catch::Detail::unique_ptr<GeneratorUntypedBase>;
13237- }
13238-
13239-
13240- class IResultCapture {
13241- public:
13242- virtual ~IResultCapture();
13243-
13244- virtual void notifyAssertionStarted( AssertionInfo const& info ) = 0;
13245- virtual bool sectionStarted( StringRef sectionName,
13246- SourceLineInfo const& sectionLineInfo,
13247- Counts& assertions ) = 0;
13248- virtual void sectionEnded( SectionEndInfo&& endInfo ) = 0;
13249- virtual void sectionEndedEarly( SectionEndInfo&& endInfo ) = 0;
13250-
13251- virtual IGeneratorTracker*
13252- acquireGeneratorTracker( StringRef generatorName,
13253- SourceLineInfo const& lineInfo ) = 0;
13254- virtual IGeneratorTracker*
13255- createGeneratorTracker( StringRef generatorName,
13256- SourceLineInfo lineInfo,
13257- Generators::GeneratorBasePtr&& generator ) = 0;
13258-
13259- virtual void benchmarkPreparing( StringRef name ) = 0;
13260- virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0;
13261- virtual void benchmarkEnded( BenchmarkStats<> const& stats ) = 0;
13262- virtual void benchmarkFailed( StringRef error ) = 0;
13263-
13264- static void pushScopedMessage( MessageInfo&& message );
13265- static void popScopedMessage( unsigned int messageId );
13266- static void emplaceUnscopedMessage( MessageBuilder&& builder );
13267-
13268- virtual void handleFatalErrorCondition( StringRef message ) = 0;
13269-
13270- virtual void handleExpr
13271- ( AssertionInfo const& info,
13272- ITransientExpression const& expr,
13273- AssertionReaction& reaction ) = 0;
13274- virtual void handleMessage
13275- ( AssertionInfo const& info,
13276- ResultWas::OfType resultType,
13277- std::string&& message,
13278- AssertionReaction& reaction ) = 0;
13279- virtual void handleUnexpectedExceptionNotThrown
13280- ( AssertionInfo const& info,
13281- AssertionReaction& reaction ) = 0;
13282- virtual void handleUnexpectedInflightException
13283- ( AssertionInfo const& info,
13284- std::string&& message,
13285- AssertionReaction& reaction ) = 0;
13286- virtual void handleIncomplete
13287- ( AssertionInfo const& info ) = 0;
13288- virtual void handleNonExpr
13289- ( AssertionInfo const &info,
13290- ResultWas::OfType resultType,
13291- AssertionReaction &reaction ) = 0;
13292-
13293-
13294- virtual bool lastAssertionPassed() = 0;
13295-
13296- // Deprecated, do not use:
13297- virtual std::string getCurrentTestName() const = 0;
13298- virtual const AssertionResult* getLastResult() const = 0;
13299- virtual void exceptionEarlyReported() = 0;
13300- };
13301-
13302- namespace Detail {
13303- [[noreturn]]
13304- void missingCaptureInstance();
13305- }
13306- inline IResultCapture& getResultCapture() {
13307- if (auto* capture = getCurrentContext().getResultCapture()) {
13308- return *capture;
13309- } else {
13310- Detail::missingCaptureInstance();
13311- }
13312- }
13313-
13314-}
13315-
13316-#endif // CATCH_INTERFACES_CAPTURE_HPP_INCLUDED
13317-
13318-
13319-#ifndef CATCH_INTERFACES_CONFIG_HPP_INCLUDED
13320-#define CATCH_INTERFACES_CONFIG_HPP_INCLUDED
13321-
13322-
13323-
13324-#ifndef CATCH_NONCOPYABLE_HPP_INCLUDED
13325-#define CATCH_NONCOPYABLE_HPP_INCLUDED
13326-
13327-namespace Catch {
13328- namespace Detail {
13329-
13330- //! Deriving classes become noncopyable and nonmovable
13331- class NonCopyable {
13332- public:
13333- NonCopyable( NonCopyable const& ) = delete;
13334- NonCopyable( NonCopyable&& ) = delete;
13335- NonCopyable& operator=( NonCopyable const& ) = delete;
13336- NonCopyable& operator=( NonCopyable&& ) = delete;
13337-
13338- protected:
13339- NonCopyable() noexcept = default;
13340- };
13341-
13342- } // namespace Detail
13343-} // namespace Catch
13344-
13345-#endif // CATCH_NONCOPYABLE_HPP_INCLUDED
13346-
13347-#include <chrono>
13348-#include <string>
13349-#include <vector>
13350-
13351-namespace Catch {
13352-
13353- enum class Verbosity {
13354- Quiet = 0,
13355- Normal,
13356- High
13357- };
13358-
13359- struct WarnAbout { enum What {
13360- Nothing = 0x00,
13361- //! A test case or leaf section did not run any assertions
13362- NoAssertions = 0x01,
13363- //! A command line test spec matched no test cases
13364- UnmatchedTestSpec = 0x02,
13365- }; };
13366-
13367- enum class ShowDurations {
13368- DefaultForReporter,
13369- Always,
13370- Never
13371- };
13372- enum class TestRunOrder {
13373- Declared,
13374- LexicographicallySorted,
13375- Randomized
13376- };
13377- enum class ColourMode : std::uint8_t {
13378- //! Let Catch2 pick implementation based on platform detection
13379- PlatformDefault,
13380- //! Use ANSI colour code escapes
13381- ANSI,
13382- //! Use Win32 console colour API
13383- Win32,
13384- //! Don't use any colour
13385- None
13386- };
13387- struct WaitForKeypress { enum When {
13388- Never,
13389- BeforeStart = 1,
13390- BeforeExit = 2,
13391- BeforeStartAndExit = BeforeStart | BeforeExit
13392- }; };
13393-
13394- class TestSpec;
13395- class IStream;
13396-
13397- class IConfig : public Detail::NonCopyable {
13398- public:
13399- virtual ~IConfig();
13400-
13401- virtual bool allowThrows() const = 0;
13402- virtual StringRef name() const = 0;
13403- virtual bool includeSuccessfulResults() const = 0;
13404- virtual bool shouldDebugBreak() const = 0;
13405- virtual bool warnAboutMissingAssertions() const = 0;
13406- virtual bool warnAboutUnmatchedTestSpecs() const = 0;
13407- virtual bool zeroTestsCountAsSuccess() const = 0;
13408- virtual int abortAfter() const = 0;
13409- virtual bool showInvisibles() const = 0;
13410- virtual ShowDurations showDurations() const = 0;
13411- virtual double minDuration() const = 0;
13412- virtual TestSpec const& testSpec() const = 0;
13413- virtual bool hasTestFilters() const = 0;
13414- virtual std::vector<std::string> const& getTestsOrTags() const = 0;
13415- virtual TestRunOrder runOrder() const = 0;
13416- virtual uint32_t rngSeed() const = 0;
13417- virtual unsigned int shardCount() const = 0;
13418- virtual unsigned int shardIndex() const = 0;
13419- virtual ColourMode defaultColourMode() const = 0;
13420- virtual std::vector<std::string> const& getSectionsToRun() const = 0;
13421- virtual Verbosity verbosity() const = 0;
13422-
13423- virtual bool skipBenchmarks() const = 0;
13424- virtual bool benchmarkNoAnalysis() const = 0;
13425- virtual unsigned int benchmarkSamples() const = 0;
13426- virtual double benchmarkConfidenceInterval() const = 0;
13427- virtual unsigned int benchmarkResamples() const = 0;
13428- virtual std::chrono::milliseconds benchmarkWarmupTime() const = 0;
13429- };
13430-}
13431-
13432-#endif // CATCH_INTERFACES_CONFIG_HPP_INCLUDED
13433-
13434-
13435-#ifndef CATCH_INTERFACES_REGISTRY_HUB_HPP_INCLUDED
13436-#define CATCH_INTERFACES_REGISTRY_HUB_HPP_INCLUDED
13437-
13438-
13439-#include <string>
13440-
13441-namespace Catch {
13442-
13443- class TestCaseHandle;
13444- struct TestCaseInfo;
13445- class ITestCaseRegistry;
13446- class IExceptionTranslatorRegistry;
13447- class IExceptionTranslator;
13448- class ReporterRegistry;
13449- class IReporterFactory;
13450- class ITagAliasRegistry;
13451- class ITestInvoker;
13452- class IMutableEnumValuesRegistry;
13453- struct SourceLineInfo;
13454-
13455- class StartupExceptionRegistry;
13456- class EventListenerFactory;
13457-
13458- using IReporterFactoryPtr = Detail::unique_ptr<IReporterFactory>;
13459-
13460- class IRegistryHub {
13461- public:
13462- virtual ~IRegistryHub(); // = default
13463-
13464- virtual ReporterRegistry const& getReporterRegistry() const = 0;
13465- virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0;
13466- virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0;
13467- virtual IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const = 0;
13468-
13469-
13470- virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0;
13471- };
13472-
13473- class IMutableRegistryHub {
13474- public:
13475- virtual ~IMutableRegistryHub(); // = default
13476- virtual void registerReporter( std::string const& name, IReporterFactoryPtr factory ) = 0;
13477- virtual void registerListener( Detail::unique_ptr<EventListenerFactory> factory ) = 0;
13478- virtual void registerTest(Detail::unique_ptr<TestCaseInfo>&& testInfo, Detail::unique_ptr<ITestInvoker>&& invoker) = 0;
13479- virtual void registerTranslator( Detail::unique_ptr<IExceptionTranslator>&& translator ) = 0;
13480- virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0;
13481- virtual void registerStartupException() noexcept = 0;
13482- virtual IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() = 0;
13483- };
13484-
13485- IRegistryHub const& getRegistryHub();
13486- IMutableRegistryHub& getMutableRegistryHub();
13487- void cleanUp();
13488- std::string translateActiveException();
13489-
13490-}
13491-
13492-#endif // CATCH_INTERFACES_REGISTRY_HUB_HPP_INCLUDED
13493-
13494-
13495-#ifndef CATCH_BENCHMARK_STATS_HPP_INCLUDED
13496-#define CATCH_BENCHMARK_STATS_HPP_INCLUDED
13497-
13498-
13499-
13500-// Adapted from donated nonius code.
13501-
13502-#ifndef CATCH_ESTIMATE_HPP_INCLUDED
13503-#define CATCH_ESTIMATE_HPP_INCLUDED
13504-
13505-namespace Catch {
13506- namespace Benchmark {
13507- template <typename Type>
13508- struct Estimate {
13509- Type point;
13510- Type lower_bound;
13511- Type upper_bound;
13512- double confidence_interval;
13513- };
13514- } // namespace Benchmark
13515-} // namespace Catch
13516-
13517-#endif // CATCH_ESTIMATE_HPP_INCLUDED
13518-
13519-
13520-// Adapted from donated nonius code.
13521-
13522-#ifndef CATCH_OUTLIER_CLASSIFICATION_HPP_INCLUDED
13523-#define CATCH_OUTLIER_CLASSIFICATION_HPP_INCLUDED
13524-
13525-namespace Catch {
13526- namespace Benchmark {
13527- struct OutlierClassification {
13528- int samples_seen = 0;
13529- int low_severe = 0; // more than 3 times IQR below Q1
13530- int low_mild = 0; // 1.5 to 3 times IQR below Q1
13531- int high_mild = 0; // 1.5 to 3 times IQR above Q3
13532- int high_severe = 0; // more than 3 times IQR above Q3
13533-
13534- constexpr int total() const {
13535- return low_severe + low_mild + high_mild + high_severe;
13536- }
13537- };
13538- } // namespace Benchmark
13539-} // namespace Catch
13540-
13541-#endif // CATCH_OUTLIERS_CLASSIFICATION_HPP_INCLUDED
13542-// The fwd decl & default specialization needs to be seen by VS2017 before
13543-// BenchmarkStats itself, or VS2017 will report compilation error.
13544-
13545-#include <string>
13546-#include <vector>
13547-
13548-namespace Catch {
13549-
13550- struct BenchmarkInfo {
13551- std::string name;
13552- double estimatedDuration;
13553- int iterations;
13554- unsigned int samples;
13555- unsigned int resamples;
13556- double clockResolution;
13557- double clockCost;
13558- };
13559-
13560- // We need to keep template parameter for backwards compatibility,
13561- // but we also do not want to use the template paraneter.
13562- template <class Dummy>
13563- struct BenchmarkStats {
13564- BenchmarkInfo info;
13565-
13566- std::vector<Benchmark::FDuration> samples;
13567- Benchmark::Estimate<Benchmark::FDuration> mean;
13568- Benchmark::Estimate<Benchmark::FDuration> standardDeviation;
13569- Benchmark::OutlierClassification outliers;
13570- double outlierVariance;
13571- };
13572-
13573-
13574-} // end namespace Catch
13575-
13576-#endif // CATCH_BENCHMARK_STATS_HPP_INCLUDED
13577-
13578-
13579-// Adapted from donated nonius code.
13580-
13581-#ifndef CATCH_ENVIRONMENT_HPP_INCLUDED
13582-#define CATCH_ENVIRONMENT_HPP_INCLUDED
13583-
13584-
13585-namespace Catch {
13586- namespace Benchmark {
13587- struct EnvironmentEstimate {
13588- FDuration mean;
13589- OutlierClassification outliers;
13590- };
13591- struct Environment {
13592- EnvironmentEstimate clock_resolution;
13593- EnvironmentEstimate clock_cost;
13594- };
13595- } // namespace Benchmark
13596-} // namespace Catch
13597-
13598-#endif // CATCH_ENVIRONMENT_HPP_INCLUDED
13599-
13600-
13601-// Adapted from donated nonius code.
13602-
13603-#ifndef CATCH_EXECUTION_PLAN_HPP_INCLUDED
13604-#define CATCH_EXECUTION_PLAN_HPP_INCLUDED
13605-
13606-
13607-
13608-// Adapted from donated nonius code.
13609-
13610-#ifndef CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED
13611-#define CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED
13612-
13613-
13614-
13615-// Adapted from donated nonius code.
13616-
13617-#ifndef CATCH_CHRONOMETER_HPP_INCLUDED
13618-#define CATCH_CHRONOMETER_HPP_INCLUDED
13619-
13620-
13621-
13622-// Adapted from donated nonius code.
13623-
13624-#ifndef CATCH_OPTIMIZER_HPP_INCLUDED
13625-#define CATCH_OPTIMIZER_HPP_INCLUDED
13626-
13627-#if defined(_MSC_VER) || defined(__IAR_SYSTEMS_ICC__)
13628-# include <atomic> // atomic_thread_fence
13629-#endif
13630-
13631-
13632-#include <type_traits>
13633-
13634-namespace Catch {
13635- namespace Benchmark {
13636-#if defined(__GNUC__) || defined(__clang__)
13637- template <typename T>
13638- inline void keep_memory(T* p) {
13639- asm volatile("" : : "g"(p) : "memory");
13640- }
13641- inline void keep_memory() {
13642- asm volatile("" : : : "memory");
13643- }
13644-
13645- namespace Detail {
13646- inline void optimizer_barrier() { keep_memory(); }
13647- } // namespace Detail
13648-#elif defined(_MSC_VER) || defined(__IAR_SYSTEMS_ICC__)
13649-
13650-#if defined(_MSVC_VER)
13651-#pragma optimize("", off)
13652-#elif defined(__IAR_SYSTEMS_ICC__)
13653-// For IAR the pragma only affects the following function
13654-#pragma optimize=disable
13655-#endif
13656- template <typename T>
13657- inline void keep_memory(T* p) {
13658- // thanks @milleniumbug
13659- *reinterpret_cast<char volatile*>(p) = *reinterpret_cast<char const volatile*>(p);
13660- }
13661- // TODO equivalent keep_memory()
13662-#if defined(_MSVC_VER)
13663-#pragma optimize("", on)
13664-#endif
13665-
13666- namespace Detail {
13667- inline void optimizer_barrier() {
13668- std::atomic_thread_fence(std::memory_order_seq_cst);
13669- }
13670- } // namespace Detail
13671-
13672-#endif
13673-
13674- template <typename T>
13675- inline void deoptimize_value(T&& x) {
13676- keep_memory(&x);
13677- }
13678-
13679- template <typename Fn, typename... Args>
13680- inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> std::enable_if_t<!std::is_same<void, decltype(fn(args...))>::value> {
13681- deoptimize_value(CATCH_FORWARD(fn) (CATCH_FORWARD(args)...));
13682- }
13683-
13684- template <typename Fn, typename... Args>
13685- inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> std::enable_if_t<std::is_same<void, decltype(fn(args...))>::value> {
13686- CATCH_FORWARD((fn)) (CATCH_FORWARD(args)...);
13687- }
13688- } // namespace Benchmark
13689-} // namespace Catch
13690-
13691-#endif // CATCH_OPTIMIZER_HPP_INCLUDED
13692-
13693-
13694-#ifndef CATCH_META_HPP_INCLUDED
13695-#define CATCH_META_HPP_INCLUDED
13696-
13697-#include <type_traits>
13698-
13699-namespace Catch {
13700- template <typename>
13701- struct true_given : std::true_type {};
13702-
13703- struct is_callable_tester {
13704- template <typename Fun, typename... Args>
13705- static true_given<decltype(std::declval<Fun>()(std::declval<Args>()...))> test(int);
13706- template <typename...>
13707- static std::false_type test(...);
13708- };
13709-
13710- template <typename T>
13711- struct is_callable;
13712-
13713- template <typename Fun, typename... Args>
13714- struct is_callable<Fun(Args...)> : decltype(is_callable_tester::test<Fun, Args...>(0)) {};
13715-
13716-
13717-#if defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703
13718- // std::result_of is deprecated in C++17 and removed in C++20. Hence, it is
13719- // replaced with std::invoke_result here.
13720- template <typename Func, typename... U>
13721- using FunctionReturnType = std::remove_reference_t<std::remove_cv_t<std::invoke_result_t<Func, U...>>>;
13722-#else
13723- template <typename Func, typename... U>
13724- using FunctionReturnType = std::remove_reference_t<std::remove_cv_t<std::result_of_t<Func(U...)>>>;
13725-#endif
13726-
13727-} // namespace Catch
13728-
13729-namespace mpl_{
13730- struct na;
13731-}
13732-
13733-#endif // CATCH_META_HPP_INCLUDED
13734-
13735-namespace Catch {
13736- namespace Benchmark {
13737- namespace Detail {
13738- struct ChronometerConcept {
13739- virtual void start() = 0;
13740- virtual void finish() = 0;
13741- virtual ~ChronometerConcept(); // = default;
13742-
13743- ChronometerConcept() = default;
13744- ChronometerConcept(ChronometerConcept const&) = default;
13745- ChronometerConcept& operator=(ChronometerConcept const&) = default;
13746- };
13747- template <typename Clock>
13748- struct ChronometerModel final : public ChronometerConcept {
13749- void start() override { started = Clock::now(); }
13750- void finish() override { finished = Clock::now(); }
13751-
13752- IDuration elapsed() const {
13753- return std::chrono::duration_cast<std::chrono::nanoseconds>(
13754- finished - started );
13755- }
13756-
13757- TimePoint<Clock> started;
13758- TimePoint<Clock> finished;
13759- };
13760- } // namespace Detail
13761-
13762- struct Chronometer {
13763- public:
13764- template <typename Fun>
13765- void measure(Fun&& fun) { measure(CATCH_FORWARD(fun), is_callable<Fun(int)>()); }
13766-
13767- int runs() const { return repeats; }
13768-
13769- Chronometer(Detail::ChronometerConcept& meter, int repeats_)
13770- : impl(&meter)
13771- , repeats(repeats_) {}
13772-
13773- private:
13774- template <typename Fun>
13775- void measure(Fun&& fun, std::false_type) {
13776- measure([&fun](int) { return fun(); }, std::true_type());
13777- }
13778-
13779- template <typename Fun>
13780- void measure(Fun&& fun, std::true_type) {
13781- Detail::optimizer_barrier();
13782- impl->start();
13783- for (int i = 0; i < repeats; ++i) invoke_deoptimized(fun, i);
13784- impl->finish();
13785- Detail::optimizer_barrier();
13786- }
13787-
13788- Detail::ChronometerConcept* impl;
13789- int repeats;
13790- };
13791- } // namespace Benchmark
13792-} // namespace Catch
13793-
13794-#endif // CATCH_CHRONOMETER_HPP_INCLUDED
13795-
13796-#include <type_traits>
13797-
13798-namespace Catch {
13799- namespace Benchmark {
13800- namespace Detail {
13801- template <typename T, typename U>
13802- static constexpr bool is_related_v = std::is_same<std::decay_t<T>, std::decay_t<U>>::value;
13803-
13804- /// We need to reinvent std::function because every piece of code that might add overhead
13805- /// in a measurement context needs to have consistent performance characteristics so that we
13806- /// can account for it in the measurement.
13807- /// Implementations of std::function with optimizations that aren't always applicable, like
13808- /// small buffer optimizations, are not uncommon.
13809- /// This is effectively an implementation of std::function without any such optimizations;
13810- /// it may be slow, but it is consistently slow.
13811- struct BenchmarkFunction {
13812- private:
13813- struct callable {
13814- virtual void call(Chronometer meter) const = 0;
13815- virtual ~callable(); // = default;
13816-
13817- callable() = default;
13818- callable(callable&&) = default;
13819- callable& operator=(callable&&) = default;
13820- };
13821- template <typename Fun>
13822- struct model : public callable {
13823- model(Fun&& fun_) : fun(CATCH_MOVE(fun_)) {}
13824- model(Fun const& fun_) : fun(fun_) {}
13825-
13826- void call(Chronometer meter) const override {
13827- call(meter, is_callable<Fun(Chronometer)>());
13828- }
13829- void call(Chronometer meter, std::true_type) const {
13830- fun(meter);
13831- }
13832- void call(Chronometer meter, std::false_type) const {
13833- meter.measure(fun);
13834- }
13835-
13836- Fun fun;
13837- };
13838-
13839- public:
13840- BenchmarkFunction();
13841-
13842- template <typename Fun,
13843- std::enable_if_t<!is_related_v<Fun, BenchmarkFunction>, int> = 0>
13844- BenchmarkFunction(Fun&& fun)
13845- : f(new model<std::decay_t<Fun>>(CATCH_FORWARD(fun))) {}
13846-
13847- BenchmarkFunction( BenchmarkFunction&& that ) noexcept:
13848- f( CATCH_MOVE( that.f ) ) {}
13849-
13850- BenchmarkFunction&
13851- operator=( BenchmarkFunction&& that ) noexcept {
13852- f = CATCH_MOVE( that.f );
13853- return *this;
13854- }
13855-
13856- void operator()(Chronometer meter) const { f->call(meter); }
13857-
13858- private:
13859- Catch::Detail::unique_ptr<callable> f;
13860- };
13861- } // namespace Detail
13862- } // namespace Benchmark
13863-} // namespace Catch
13864-
13865-#endif // CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED
13866-
13867-
13868-// Adapted from donated nonius code.
13869-
13870-#ifndef CATCH_REPEAT_HPP_INCLUDED
13871-#define CATCH_REPEAT_HPP_INCLUDED
13872-
13873-#include <type_traits>
13874-
13875-namespace Catch {
13876- namespace Benchmark {
13877- namespace Detail {
13878- template <typename Fun>
13879- struct repeater {
13880- void operator()(int k) const {
13881- for (int i = 0; i < k; ++i) {
13882- fun();
13883- }
13884- }
13885- Fun fun;
13886- };
13887- template <typename Fun>
13888- repeater<std::decay_t<Fun>> repeat(Fun&& fun) {
13889- return { CATCH_FORWARD(fun) };
13890- }
13891- } // namespace Detail
13892- } // namespace Benchmark
13893-} // namespace Catch
13894-
13895-#endif // CATCH_REPEAT_HPP_INCLUDED
13896-
13897-
13898-// Adapted from donated nonius code.
13899-
13900-#ifndef CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED
13901-#define CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED
13902-
13903-
13904-
13905-// Adapted from donated nonius code.
13906-
13907-#ifndef CATCH_MEASURE_HPP_INCLUDED
13908-#define CATCH_MEASURE_HPP_INCLUDED
13909-
13910-
13911-
13912-// Adapted from donated nonius code.
13913-
13914-#ifndef CATCH_COMPLETE_INVOKE_HPP_INCLUDED
13915-#define CATCH_COMPLETE_INVOKE_HPP_INCLUDED
13916-
13917-
13918-namespace Catch {
13919- namespace Benchmark {
13920- namespace Detail {
13921- template <typename T>
13922- struct CompleteType { using type = T; };
13923- template <>
13924- struct CompleteType<void> { struct type {}; };
13925-
13926- template <typename T>
13927- using CompleteType_t = typename CompleteType<T>::type;
13928-
13929- template <typename Result>
13930- struct CompleteInvoker {
13931- template <typename Fun, typename... Args>
13932- static Result invoke(Fun&& fun, Args&&... args) {
13933- return CATCH_FORWARD(fun)(CATCH_FORWARD(args)...);
13934- }
13935- };
13936- template <>
13937- struct CompleteInvoker<void> {
13938- template <typename Fun, typename... Args>
13939- static CompleteType_t<void> invoke(Fun&& fun, Args&&... args) {
13940- CATCH_FORWARD(fun)(CATCH_FORWARD(args)...);
13941- return {};
13942- }
13943- };
13944-
13945- // invoke and not return void :(
13946- template <typename Fun, typename... Args>
13947- CompleteType_t<FunctionReturnType<Fun, Args...>> complete_invoke(Fun&& fun, Args&&... args) {
13948- return CompleteInvoker<FunctionReturnType<Fun, Args...>>::invoke(CATCH_FORWARD(fun), CATCH_FORWARD(args)...);
13949- }
13950-
13951- } // namespace Detail
13952-
13953- template <typename Fun>
13954- Detail::CompleteType_t<FunctionReturnType<Fun>> user_code(Fun&& fun) {
13955- return Detail::complete_invoke(CATCH_FORWARD(fun));
13956- }
13957- } // namespace Benchmark
13958-} // namespace Catch
13959-
13960-#endif // CATCH_COMPLETE_INVOKE_HPP_INCLUDED
13961-
13962-
13963-// Adapted from donated nonius code.
13964-
13965-#ifndef CATCH_TIMING_HPP_INCLUDED
13966-#define CATCH_TIMING_HPP_INCLUDED
13967-
13968-
13969-namespace Catch {
13970- namespace Benchmark {
13971- template <typename Result>
13972- struct Timing {
13973- IDuration elapsed;
13974- Result result;
13975- int iterations;
13976- };
13977- template <typename Func, typename... Args>
13978- using TimingOf = Timing<Detail::CompleteType_t<FunctionReturnType<Func, Args...>>>;
13979- } // namespace Benchmark
13980-} // namespace Catch
13981-
13982-#endif // CATCH_TIMING_HPP_INCLUDED
13983-
13984-namespace Catch {
13985- namespace Benchmark {
13986- namespace Detail {
13987- template <typename Clock, typename Fun, typename... Args>
13988- TimingOf<Fun, Args...> measure(Fun&& fun, Args&&... args) {
13989- auto start = Clock::now();
13990- auto&& r = Detail::complete_invoke(CATCH_FORWARD(fun), CATCH_FORWARD(args)...);
13991- auto end = Clock::now();
13992- auto delta = end - start;
13993- return { delta, CATCH_FORWARD(r), 1 };
13994- }
13995- } // namespace Detail
13996- } // namespace Benchmark
13997-} // namespace Catch
13998-
13999-#endif // CATCH_MEASURE_HPP_INCLUDED
14000-
14001-#include <type_traits>
14002-
14003-namespace Catch {
14004- namespace Benchmark {
14005- namespace Detail {
14006- template <typename Clock, typename Fun>
14007- TimingOf<Fun, int> measure_one(Fun&& fun, int iters, std::false_type) {
14008- return Detail::measure<Clock>(fun, iters);
14009- }
14010- template <typename Clock, typename Fun>
14011- TimingOf<Fun, Chronometer> measure_one(Fun&& fun, int iters, std::true_type) {
14012- Detail::ChronometerModel<Clock> meter;
14013- auto&& result = Detail::complete_invoke(fun, Chronometer(meter, iters));
14014-
14015- return { meter.elapsed(), CATCH_MOVE(result), iters };
14016- }
14017-
14018- template <typename Clock, typename Fun>
14019- using run_for_at_least_argument_t = std::conditional_t<is_callable<Fun(Chronometer)>::value, Chronometer, int>;
14020-
14021-
14022- [[noreturn]]
14023- void throw_optimized_away_error();
14024-
14025- template <typename Clock, typename Fun>
14026- TimingOf<Fun, run_for_at_least_argument_t<Clock, Fun>>
14027- run_for_at_least(IDuration how_long,
14028- const int initial_iterations,
14029- Fun&& fun) {
14030- auto iters = initial_iterations;
14031- while (iters < (1 << 30)) {
14032- auto&& Timing = measure_one<Clock>(fun, iters, is_callable<Fun(Chronometer)>());
14033-
14034- if (Timing.elapsed >= how_long) {
14035- return { Timing.elapsed, CATCH_MOVE(Timing.result), iters };
14036- }
14037- iters *= 2;
14038- }
14039- throw_optimized_away_error();
14040- }
14041- } // namespace Detail
14042- } // namespace Benchmark
14043-} // namespace Catch
14044-
14045-#endif // CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED
14046-
14047-#include <vector>
14048-
14049-namespace Catch {
14050- namespace Benchmark {
14051- struct ExecutionPlan {
14052- int iterations_per_sample;
14053- FDuration estimated_duration;
14054- Detail::BenchmarkFunction benchmark;
14055- FDuration warmup_time;
14056- int warmup_iterations;
14057-
14058- template <typename Clock>
14059- std::vector<FDuration> run(const IConfig &cfg, Environment env) const {
14060- // warmup a bit
14061- Detail::run_for_at_least<Clock>(
14062- std::chrono::duration_cast<IDuration>( warmup_time ),
14063- warmup_iterations,
14064- Detail::repeat( []() { return Clock::now(); } )
14065- );
14066-
14067- std::vector<FDuration> times;
14068- const auto num_samples = cfg.benchmarkSamples();
14069- times.reserve( num_samples );
14070- for ( size_t i = 0; i < num_samples; ++i ) {
14071- Detail::ChronometerModel<Clock> model;
14072- this->benchmark( Chronometer( model, iterations_per_sample ) );
14073- auto sample_time = model.elapsed() - env.clock_cost.mean;
14074- if ( sample_time < FDuration::zero() ) {
14075- sample_time = FDuration::zero();
14076- }
14077- times.push_back(sample_time / iterations_per_sample);
14078- }
14079- return times;
14080- }
14081- };
14082- } // namespace Benchmark
14083-} // namespace Catch
14084-
14085-#endif // CATCH_EXECUTION_PLAN_HPP_INCLUDED
14086-
14087-
14088-// Adapted from donated nonius code.
14089-
14090-#ifndef CATCH_ESTIMATE_CLOCK_HPP_INCLUDED
14091-#define CATCH_ESTIMATE_CLOCK_HPP_INCLUDED
14092-
14093-
14094-
14095-// Adapted from donated nonius code.
14096-
14097-#ifndef CATCH_STATS_HPP_INCLUDED
14098-#define CATCH_STATS_HPP_INCLUDED
14099-
14100-
14101-#include <vector>
14102-
14103-namespace Catch {
14104- namespace Benchmark {
14105- namespace Detail {
14106- using sample = std::vector<double>;
14107-
14108- double weighted_average_quantile( int k,
14109- int q,
14110- double* first,
14111- double* last );
14112-
14113- OutlierClassification
14114- classify_outliers( double const* first, double const* last );
14115-
14116- double mean( double const* first, double const* last );
14117-
14118- double normal_cdf( double x );
14119-
14120- double erfc_inv(double x);
14121-
14122- double normal_quantile(double p);
14123-
14124- Estimate<double>
14125- bootstrap( double confidence_level,
14126- double* first,
14127- double* last,
14128- sample const& resample,
14129- double ( *estimator )( double const*, double const* ) );
14130-
14131- struct bootstrap_analysis {
14132- Estimate<double> mean;
14133- Estimate<double> standard_deviation;
14134- double outlier_variance;
14135- };
14136-
14137- bootstrap_analysis analyse_samples(double confidence_level,
14138- unsigned int n_resamples,
14139- double* first,
14140- double* last);
14141- } // namespace Detail
14142- } // namespace Benchmark
14143-} // namespace Catch
14144-
14145-#endif // CATCH_STATS_HPP_INCLUDED
14146-
14147-#include <algorithm>
14148-#include <vector>
14149-#include <cmath>
14150-
14151-namespace Catch {
14152- namespace Benchmark {
14153- namespace Detail {
14154- template <typename Clock>
14155- std::vector<double> resolution(int k) {
14156- const size_t points = static_cast<size_t>( k + 1 );
14157- // To avoid overhead from the branch inside vector::push_back,
14158- // we allocate them all and then overwrite.
14159- std::vector<TimePoint<Clock>> times(points);
14160- for ( auto& time : times ) {
14161- time = Clock::now();
14162- }
14163-
14164- std::vector<double> deltas;
14165- deltas.reserve(static_cast<size_t>(k));
14166- for ( size_t idx = 1; idx < points; ++idx ) {
14167- deltas.push_back( static_cast<double>(
14168- ( times[idx] - times[idx - 1] ).count() ) );
14169- }
14170-
14171- return deltas;
14172- }
14173-
14174- constexpr auto warmup_iterations = 10000;
14175- constexpr auto warmup_time = std::chrono::milliseconds(100);
14176- constexpr auto minimum_ticks = 1000;
14177- constexpr auto warmup_seed = 10000;
14178- constexpr auto clock_resolution_estimation_time = std::chrono::milliseconds(500);
14179- constexpr auto clock_cost_estimation_time_limit = std::chrono::seconds(1);
14180- constexpr auto clock_cost_estimation_tick_limit = 100000;
14181- constexpr auto clock_cost_estimation_time = std::chrono::milliseconds(10);
14182- constexpr auto clock_cost_estimation_iterations = 10000;
14183-
14184- template <typename Clock>
14185- int warmup() {
14186- return run_for_at_least<Clock>(warmup_time, warmup_seed, &resolution<Clock>)
14187- .iterations;
14188- }
14189- template <typename Clock>
14190- EnvironmentEstimate estimate_clock_resolution(int iterations) {
14191- auto r = run_for_at_least<Clock>(clock_resolution_estimation_time, iterations, &resolution<Clock>)
14192- .result;
14193- return {
14194- FDuration(mean(r.data(), r.data() + r.size())),
14195- classify_outliers(r.data(), r.data() + r.size()),
14196- };
14197- }
14198- template <typename Clock>
14199- EnvironmentEstimate estimate_clock_cost(FDuration resolution) {
14200- auto time_limit = (std::min)(
14201- resolution * clock_cost_estimation_tick_limit,
14202- FDuration(clock_cost_estimation_time_limit));
14203- auto time_clock = [](int k) {
14204- return Detail::measure<Clock>([k] {
14205- for (int i = 0; i < k; ++i) {
14206- volatile auto ignored = Clock::now();
14207- (void)ignored;
14208- }
14209- }).elapsed;
14210- };
14211- time_clock(1);
14212- int iters = clock_cost_estimation_iterations;
14213- auto&& r = run_for_at_least<Clock>(clock_cost_estimation_time, iters, time_clock);
14214- std::vector<double> times;
14215- int nsamples = static_cast<int>(std::ceil(time_limit / r.elapsed));
14216- times.reserve(static_cast<size_t>(nsamples));
14217- for ( int s = 0; s < nsamples; ++s ) {
14218- times.push_back( static_cast<double>(
14219- ( time_clock( r.iterations ) / r.iterations )
14220- .count() ) );
14221- }
14222- return {
14223- FDuration(mean(times.data(), times.data() + times.size())),
14224- classify_outliers(times.data(), times.data() + times.size()),
14225- };
14226- }
14227-
14228- template <typename Clock>
14229- Environment measure_environment() {
14230-#if defined(__clang__)
14231-# pragma clang diagnostic push
14232-# pragma clang diagnostic ignored "-Wexit-time-destructors"
14233-#endif
14234- static Catch::Detail::unique_ptr<Environment> env;
14235-#if defined(__clang__)
14236-# pragma clang diagnostic pop
14237-#endif
14238- if (env) {
14239- return *env;
14240- }
14241-
14242- auto iters = Detail::warmup<Clock>();
14243- auto resolution = Detail::estimate_clock_resolution<Clock>(iters);
14244- auto cost = Detail::estimate_clock_cost<Clock>(resolution.mean);
14245-
14246- env = Catch::Detail::make_unique<Environment>( Environment{resolution, cost} );
14247- return *env;
14248- }
14249- } // namespace Detail
14250- } // namespace Benchmark
14251-} // namespace Catch
14252-
14253-#endif // CATCH_ESTIMATE_CLOCK_HPP_INCLUDED
14254-
14255-
14256-// Adapted from donated nonius code.
14257-
14258-#ifndef CATCH_ANALYSE_HPP_INCLUDED
14259-#define CATCH_ANALYSE_HPP_INCLUDED
14260-
14261-
14262-
14263-// Adapted from donated nonius code.
14264-
14265-#ifndef CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED
14266-#define CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED
14267-
14268-
14269-#include <vector>
14270-
14271-namespace Catch {
14272- namespace Benchmark {
14273- struct SampleAnalysis {
14274- std::vector<FDuration> samples;
14275- Estimate<FDuration> mean;
14276- Estimate<FDuration> standard_deviation;
14277- OutlierClassification outliers;
14278- double outlier_variance;
14279- };
14280- } // namespace Benchmark
14281-} // namespace Catch
14282-
14283-#endif // CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED
14284-
14285-
14286-namespace Catch {
14287- class IConfig;
14288-
14289- namespace Benchmark {
14290- namespace Detail {
14291- SampleAnalysis analyse(const IConfig &cfg, FDuration* first, FDuration* last);
14292- } // namespace Detail
14293- } // namespace Benchmark
14294-} // namespace Catch
14295-
14296-#endif // CATCH_ANALYSE_HPP_INCLUDED
14297-
14298-#include <algorithm>
14299-#include <chrono>
14300-#include <exception>
14301-#include <string>
14302-#include <cmath>
14303-
14304-namespace Catch {
14305- namespace Benchmark {
14306- struct Benchmark {
14307- Benchmark(std::string&& benchmarkName)
14308- : name(CATCH_MOVE(benchmarkName)) {}
14309-
14310- template <class FUN>
14311- Benchmark(std::string&& benchmarkName , FUN &&func)
14312- : fun(CATCH_MOVE(func)), name(CATCH_MOVE(benchmarkName)) {}
14313-
14314- template <typename Clock>
14315- ExecutionPlan prepare(const IConfig &cfg, Environment env) {
14316- auto min_time = env.clock_resolution.mean * Detail::minimum_ticks;
14317- auto run_time = std::max(min_time, std::chrono::duration_cast<decltype(min_time)>(cfg.benchmarkWarmupTime()));
14318- auto&& test = Detail::run_for_at_least<Clock>(std::chrono::duration_cast<IDuration>(run_time), 1, fun);
14319- int new_iters = static_cast<int>(std::ceil(min_time * test.iterations / test.elapsed));
14320- return { new_iters, test.elapsed / test.iterations * new_iters * cfg.benchmarkSamples(), CATCH_MOVE(fun), std::chrono::duration_cast<FDuration>(cfg.benchmarkWarmupTime()), Detail::warmup_iterations };
14321- }
14322-
14323- template <typename Clock = default_clock>
14324- void run() {
14325- static_assert( Clock::is_steady,
14326- "Benchmarking clock should be steady" );
14327- auto const* cfg = getCurrentContext().getConfig();
14328-
14329- auto env = Detail::measure_environment<Clock>();
14330-
14331- getResultCapture().benchmarkPreparing(name);
14332- CATCH_TRY{
14333- auto plan = user_code([&] {
14334- return prepare<Clock>(*cfg, env);
14335- });
14336-
14337- BenchmarkInfo info {
14338- CATCH_MOVE(name),
14339- plan.estimated_duration.count(),
14340- plan.iterations_per_sample,
14341- cfg->benchmarkSamples(),
14342- cfg->benchmarkResamples(),
14343- env.clock_resolution.mean.count(),
14344- env.clock_cost.mean.count()
14345- };
14346-
14347- getResultCapture().benchmarkStarting(info);
14348-
14349- auto samples = user_code([&] {
14350- return plan.template run<Clock>(*cfg, env);
14351- });
14352-
14353- auto analysis = Detail::analyse(*cfg, samples.data(), samples.data() + samples.size());
14354- BenchmarkStats<> stats{ CATCH_MOVE(info), CATCH_MOVE(analysis.samples), analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance };
14355- getResultCapture().benchmarkEnded(stats);
14356- } CATCH_CATCH_ALL {
14357- getResultCapture().benchmarkFailed(translateActiveException());
14358- // We let the exception go further up so that the
14359- // test case is marked as failed.
14360- std::rethrow_exception(std::current_exception());
14361- }
14362- }
14363-
14364- // sets lambda to be used in fun *and* executes benchmark!
14365- template <typename Fun, std::enable_if_t<!Detail::is_related_v<Fun, Benchmark>, int> = 0>
14366- Benchmark & operator=(Fun func) {
14367- auto const* cfg = getCurrentContext().getConfig();
14368- if (!cfg->skipBenchmarks()) {
14369- fun = Detail::BenchmarkFunction(func);
14370- run();
14371- }
14372- return *this;
14373- }
14374-
14375- explicit operator bool() {
14376- return true;
14377- }
14378-
14379- private:
14380- Detail::BenchmarkFunction fun;
14381- std::string name;
14382- };
14383- }
14384-} // namespace Catch
14385-
14386-#define INTERNAL_CATCH_GET_1_ARG(arg1, arg2, ...) arg1
14387-#define INTERNAL_CATCH_GET_2_ARG(arg1, arg2, ...) arg2
14388-
14389-#define INTERNAL_CATCH_BENCHMARK(BenchmarkName, name, benchmarkIndex)\
14390- if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \
14391- BenchmarkName = [&](int benchmarkIndex)
14392-
14393-#define INTERNAL_CATCH_BENCHMARK_ADVANCED(BenchmarkName, name)\
14394- if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \
14395- BenchmarkName = [&]
14396-
14397-#if defined(CATCH_CONFIG_PREFIX_ALL)
14398-
14399-#define CATCH_BENCHMARK(...) \
14400- INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(CATCH2_INTERNAL_BENCHMARK_), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,))
14401-#define CATCH_BENCHMARK_ADVANCED(name) \
14402- INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(CATCH2_INTERNAL_BENCHMARK_), name)
14403-
14404-#else
14405-
14406-#define BENCHMARK(...) \
14407- INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(CATCH2_INTERNAL_BENCHMARK_), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,))
14408-#define BENCHMARK_ADVANCED(name) \
14409- INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(CATCH2_INTERNAL_BENCHMARK_), name)
14410-
14411-#endif
14412-
14413-#endif // CATCH_BENCHMARK_HPP_INCLUDED
14414-
14415-
14416-// Adapted from donated nonius code.
14417-
14418-#ifndef CATCH_CONSTRUCTOR_HPP_INCLUDED
14419-#define CATCH_CONSTRUCTOR_HPP_INCLUDED
14420-
14421-
14422-#include <type_traits>
14423-
14424-namespace Catch {
14425- namespace Benchmark {
14426- namespace Detail {
14427- template <typename T, bool Destruct>
14428- struct ObjectStorage
14429- {
14430- ObjectStorage() = default;
14431-
14432- ObjectStorage(const ObjectStorage& other)
14433- {
14434- new(&data) T(other.stored_object());
14435- }
14436-
14437- ObjectStorage(ObjectStorage&& other)
14438- {
14439- new(data) T(CATCH_MOVE(other.stored_object()));
14440- }
14441-
14442- ~ObjectStorage() { destruct_on_exit<T>(); }
14443-
14444- template <typename... Args>
14445- void construct(Args&&... args)
14446- {
14447- new (data) T(CATCH_FORWARD(args)...);
14448- }
14449-
14450- template <bool AllowManualDestruction = !Destruct>
14451- std::enable_if_t<AllowManualDestruction> destruct()
14452- {
14453- stored_object().~T();
14454- }
14455-
14456- private:
14457- // If this is a constructor benchmark, destruct the underlying object
14458- template <typename U>
14459- void destruct_on_exit(std::enable_if_t<Destruct, U>* = nullptr) { destruct<true>(); }
14460- // Otherwise, don't
14461- template <typename U>
14462- void destruct_on_exit(std::enable_if_t<!Destruct, U>* = nullptr) { }
14463-
14464-#if defined( __GNUC__ ) && __GNUC__ <= 6
14465-# pragma GCC diagnostic push
14466-# pragma GCC diagnostic ignored "-Wstrict-aliasing"
14467-#endif
14468- T& stored_object() { return *reinterpret_cast<T*>( data ); }
14469-
14470- T const& stored_object() const {
14471- return *reinterpret_cast<T const*>( data );
14472- }
14473-#if defined( __GNUC__ ) && __GNUC__ <= 6
14474-# pragma GCC diagnostic pop
14475-#endif
14476-
14477- alignas( T ) unsigned char data[sizeof( T )]{};
14478- };
14479- } // namespace Detail
14480-
14481- template <typename T>
14482- using storage_for = Detail::ObjectStorage<T, true>;
14483-
14484- template <typename T>
14485- using destructable_object = Detail::ObjectStorage<T, false>;
14486- } // namespace Benchmark
14487-} // namespace Catch
14488-
14489-#endif // CATCH_CONSTRUCTOR_HPP_INCLUDED
14490-
14491-#endif // CATCH_BENCHMARK_ALL_HPP_INCLUDED
14492-
14493-
14494-#ifndef CATCH_APPROX_HPP_INCLUDED
14495-#define CATCH_APPROX_HPP_INCLUDED
14496-
14497-
14498-
14499-#ifndef CATCH_TOSTRING_HPP_INCLUDED
14500-#define CATCH_TOSTRING_HPP_INCLUDED
14501-
14502-
14503-#include <vector>
14504-#include <cstddef>
14505-#include <type_traits>
14506-#include <string>
14507-
14508-
14509-
14510-
14511-/** \file
14512- * Wrapper for the WCHAR configuration option
14513- *
14514- * We want to support platforms that do not provide `wchar_t`, so we
14515- * sometimes have to disable providing wchar_t overloads through Catch2,
14516- * e.g. the StringMaker specialization for `std::wstring`.
14517- */
14518-
14519-#ifndef CATCH_CONFIG_WCHAR_HPP_INCLUDED
14520-#define CATCH_CONFIG_WCHAR_HPP_INCLUDED
14521-
14522-
14523-// We assume that WCHAR should be enabled by default, and only disabled
14524-// for a shortlist (so far only DJGPP) of compilers.
14525-
14526-#if defined(__DJGPP__)
14527-# define CATCH_INTERNAL_CONFIG_NO_WCHAR
14528-#endif // __DJGPP__
14529-
14530-#if !defined( CATCH_INTERNAL_CONFIG_NO_WCHAR ) && \
14531- !defined( CATCH_CONFIG_NO_WCHAR ) && \
14532- !defined( CATCH_CONFIG_WCHAR )
14533-# define CATCH_CONFIG_WCHAR
14534-#endif
14535-
14536-#endif // CATCH_CONFIG_WCHAR_HPP_INCLUDED
14537-
14538-
14539-#ifndef CATCH_REUSABLE_STRING_STREAM_HPP_INCLUDED
14540-#define CATCH_REUSABLE_STRING_STREAM_HPP_INCLUDED
14541-
14542-
14543-#include <iosfwd>
14544-#include <cstddef>
14545-#include <ostream>
14546-#include <string>
14547-
14548-namespace Catch {
14549-
14550- class ReusableStringStream : Detail::NonCopyable {
14551- std::size_t m_index;
14552- std::ostream* m_oss;
14553- public:
14554- ReusableStringStream();
14555- ~ReusableStringStream();
14556-
14557- //! Returns the serialized state
14558- std::string str() const;
14559- //! Sets internal state to `str`
14560- void str(std::string const& str);
14561-
14562-#if defined(__GNUC__) && !defined(__clang__)
14563-#pragma GCC diagnostic push
14564-// Old versions of GCC do not understand -Wnonnull-compare
14565-#pragma GCC diagnostic ignored "-Wpragmas"
14566-// Streaming a function pointer triggers Waddress and Wnonnull-compare
14567-// on GCC, because it implicitly converts it to bool and then decides
14568-// that the check it uses (a? true : false) is tautological and cannot
14569-// be null...
14570-#pragma GCC diagnostic ignored "-Waddress"
14571-#pragma GCC diagnostic ignored "-Wnonnull-compare"
14572-#endif
14573-
14574- template<typename T>
14575- auto operator << ( T const& value ) -> ReusableStringStream& {
14576- *m_oss << value;
14577- return *this;
14578- }
14579-
14580-#if defined(__GNUC__) && !defined(__clang__)
14581-#pragma GCC diagnostic pop
14582-#endif
14583- auto get() -> std::ostream& { return *m_oss; }
14584- };
14585-}
14586-
14587-#endif // CATCH_REUSABLE_STRING_STREAM_HPP_INCLUDED
14588-
14589-
14590-#ifndef CATCH_VOID_TYPE_HPP_INCLUDED
14591-#define CATCH_VOID_TYPE_HPP_INCLUDED
14592-
14593-
14594-namespace Catch {
14595- namespace Detail {
14596-
14597- template <typename...>
14598- struct make_void { using type = void; };
14599-
14600- template <typename... Ts>
14601- using void_t = typename make_void<Ts...>::type;
14602-
14603- } // namespace Detail
14604-} // namespace Catch
14605-
14606-
14607-#endif // CATCH_VOID_TYPE_HPP_INCLUDED
14608-
14609-
14610-#ifndef CATCH_INTERFACES_ENUM_VALUES_REGISTRY_HPP_INCLUDED
14611-#define CATCH_INTERFACES_ENUM_VALUES_REGISTRY_HPP_INCLUDED
14612-
14613-
14614-#include <vector>
14615-
14616-namespace Catch {
14617-
14618- namespace Detail {
14619- struct EnumInfo {
14620- StringRef m_name;
14621- std::vector<std::pair<int, StringRef>> m_values;
14622-
14623- ~EnumInfo();
14624-
14625- StringRef lookup( int value ) const;
14626- };
14627- } // namespace Detail
14628-
14629- class IMutableEnumValuesRegistry {
14630- public:
14631- virtual ~IMutableEnumValuesRegistry(); // = default;
14632-
14633- virtual Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::vector<int> const& values ) = 0;
14634-
14635- template<typename E>
14636- Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::initializer_list<E> values ) {
14637- static_assert(sizeof(int) >= sizeof(E), "Cannot serialize enum to int");
14638- std::vector<int> intValues;
14639- intValues.reserve( values.size() );
14640- for( auto enumValue : values )
14641- intValues.push_back( static_cast<int>( enumValue ) );
14642- return registerEnum( enumName, allEnums, intValues );
14643- }
14644- };
14645-
14646-} // Catch
14647-
14648-#endif // CATCH_INTERFACES_ENUM_VALUES_REGISTRY_HPP_INCLUDED
14649-
14650-#ifdef CATCH_CONFIG_CPP17_STRING_VIEW
14651-#include <string_view>
14652-#endif
14653-
14654-#ifdef _MSC_VER
14655-#pragma warning(push)
14656-#pragma warning(disable:4180) // We attempt to stream a function (address) by const&, which MSVC complains about but is harmless
14657-#endif
14658-
14659-// We need a dummy global operator<< so we can bring it into Catch namespace later
14660-struct Catch_global_namespace_dummy{};
14661-std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy);
14662-
14663-namespace Catch {
14664- // Bring in global namespace operator<< for ADL lookup in
14665- // `IsStreamInsertable` below.
14666- using ::operator<<;
14667-
14668- namespace Detail {
14669-
14670- inline std::size_t catch_strnlen(const char *str, std::size_t n) {
14671- auto ret = std::char_traits<char>::find(str, n, '\0');
14672- if (ret != nullptr) {
14673- return static_cast<std::size_t>(ret - str);
14674- }
14675- return n;
14676- }
14677-
14678- constexpr StringRef unprintableString = "{?}"_sr;
14679-
14680- //! Encases `string in quotes, and optionally escapes invisibles
14681- std::string convertIntoString( StringRef string, bool escapeInvisibles );
14682-
14683- //! Encases `string` in quotes, and escapes invisibles if user requested
14684- //! it via CLI
14685- std::string convertIntoString( StringRef string );
14686-
14687- std::string rawMemoryToString( const void *object, std::size_t size );
14688-
14689- template<typename T>
14690- std::string rawMemoryToString( const T& object ) {
14691- return rawMemoryToString( &object, sizeof(object) );
14692- }
14693-
14694- template<typename T,typename = void>
14695- static constexpr bool IsStreamInsertable_v = false;
14696-
14697- template <typename T>
14698- static constexpr bool IsStreamInsertable_v<
14699- T,
14700- decltype( void( std::declval<std::ostream&>() << std::declval<T>() ) )> =
14701- true;
14702-
14703- template<typename E>
14704- std::string convertUnknownEnumToString( E e );
14705-
14706- template<typename T>
14707- std::enable_if_t<
14708- !std::is_enum<T>::value && !std::is_base_of<std::exception, T>::value,
14709- std::string> convertUnstreamable( T const& ) {
14710- return std::string(Detail::unprintableString);
14711- }
14712- template<typename T>
14713- std::enable_if_t<
14714- !std::is_enum<T>::value && std::is_base_of<std::exception, T>::value,
14715- std::string> convertUnstreamable(T const& ex) {
14716- return ex.what();
14717- }
14718-
14719-
14720- template<typename T>
14721- std::enable_if_t<
14722- std::is_enum<T>::value,
14723- std::string> convertUnstreamable( T const& value ) {
14724- return convertUnknownEnumToString( value );
14725- }
14726-
14727-#if defined(_MANAGED)
14728- //! Convert a CLR string to a utf8 std::string
14729- template<typename T>
14730- std::string clrReferenceToString( T^ ref ) {
14731- if (ref == nullptr)
14732- return std::string("null");
14733- auto bytes = System::Text::Encoding::UTF8->GetBytes(ref->ToString());
14734- cli::pin_ptr<System::Byte> p = &bytes[0];
14735- return std::string(reinterpret_cast<char const *>(p), bytes->Length);
14736- }
14737-#endif
14738-
14739- } // namespace Detail
14740-
14741-
14742- template <typename T, typename = void>
14743- struct StringMaker {
14744- template <typename Fake = T>
14745- static
14746- std::enable_if_t<::Catch::Detail::IsStreamInsertable_v<Fake>, std::string>
14747- convert(const Fake& value) {
14748- ReusableStringStream rss;
14749- // NB: call using the function-like syntax to avoid ambiguity with
14750- // user-defined templated operator<< under clang.
14751- rss.operator<<(value);
14752- return rss.str();
14753- }
14754-
14755- template <typename Fake = T>
14756- static
14757- std::enable_if_t<!::Catch::Detail::IsStreamInsertable_v<Fake>, std::string>
14758- convert( const Fake& value ) {
14759-#if !defined(CATCH_CONFIG_FALLBACK_STRINGIFIER)
14760- return Detail::convertUnstreamable(value);
14761-#else
14762- return CATCH_CONFIG_FALLBACK_STRINGIFIER(value);
14763-#endif
14764- }
14765- };
14766-
14767- namespace Detail {
14768-
14769- std::string makeExceptionHappenedString();
14770-
14771- // This function dispatches all stringification requests inside of Catch.
14772- // Should be preferably called fully qualified, like ::Catch::Detail::stringify
14773- template <typename T>
14774- std::string stringify( const T& e ) {
14775- CATCH_TRY {
14776- return ::Catch::StringMaker<
14777- std::remove_cv_t<std::remove_reference_t<T>>>::convert( e );
14778- }
14779- CATCH_CATCH_ALL { return makeExceptionHappenedString(); }
14780- }
14781-
14782- template<typename E>
14783- std::string convertUnknownEnumToString( E e ) {
14784- return ::Catch::Detail::stringify(static_cast<std::underlying_type_t<E>>(e));
14785- }
14786-
14787-#if defined(_MANAGED)
14788- template <typename T>
14789- std::string stringify( T^ e ) {
14790- return ::Catch::StringMaker<T^>::convert(e);
14791- }
14792-#endif
14793-
14794- } // namespace Detail
14795-
14796- // Some predefined specializations
14797-
14798- template<>
14799- struct StringMaker<std::string> {
14800- static std::string convert(const std::string& str);
14801- };
14802-
14803-#ifdef CATCH_CONFIG_CPP17_STRING_VIEW
14804- template<>
14805- struct StringMaker<std::string_view> {
14806- static std::string convert(std::string_view str);
14807- };
14808-#endif
14809-
14810- template<>
14811- struct StringMaker<char const *> {
14812- static std::string convert(char const * str);
14813- };
14814- template<>
14815- struct StringMaker<char *> {
14816- static std::string convert(char * str);
14817- };
14818-
14819-#if defined(CATCH_CONFIG_WCHAR)
14820- template<>
14821- struct StringMaker<std::wstring> {
14822- static std::string convert(const std::wstring& wstr);
14823- };
14824-
14825-# ifdef CATCH_CONFIG_CPP17_STRING_VIEW
14826- template<>
14827- struct StringMaker<std::wstring_view> {
14828- static std::string convert(std::wstring_view str);
14829- };
14830-# endif
14831-
14832- template<>
14833- struct StringMaker<wchar_t const *> {
14834- static std::string convert(wchar_t const * str);
14835- };
14836- template<>
14837- struct StringMaker<wchar_t *> {
14838- static std::string convert(wchar_t * str);
14839- };
14840-#endif // CATCH_CONFIG_WCHAR
14841-
14842- template<size_t SZ>
14843- struct StringMaker<char[SZ]> {
14844- static std::string convert(char const* str) {
14845- return Detail::convertIntoString(
14846- StringRef( str, Detail::catch_strnlen( str, SZ ) ) );
14847- }
14848- };
14849- template<size_t SZ>
14850- struct StringMaker<signed char[SZ]> {
14851- static std::string convert(signed char const* str) {
14852- auto reinterpreted = reinterpret_cast<char const*>(str);
14853- return Detail::convertIntoString(
14854- StringRef(reinterpreted, Detail::catch_strnlen(reinterpreted, SZ)));
14855- }
14856- };
14857- template<size_t SZ>
14858- struct StringMaker<unsigned char[SZ]> {
14859- static std::string convert(unsigned char const* str) {
14860- auto reinterpreted = reinterpret_cast<char const*>(str);
14861- return Detail::convertIntoString(
14862- StringRef(reinterpreted, Detail::catch_strnlen(reinterpreted, SZ)));
14863- }
14864- };
14865-
14866-#if defined(CATCH_CONFIG_CPP17_BYTE)
14867- template<>
14868- struct StringMaker<std::byte> {
14869- static std::string convert(std::byte value);
14870- };
14871-#endif // defined(CATCH_CONFIG_CPP17_BYTE)
14872- template<>
14873- struct StringMaker<int> {
14874- static std::string convert(int value);
14875- };
14876- template<>
14877- struct StringMaker<long> {
14878- static std::string convert(long value);
14879- };
14880- template<>
14881- struct StringMaker<long long> {
14882- static std::string convert(long long value);
14883- };
14884- template<>
14885- struct StringMaker<unsigned int> {
14886- static std::string convert(unsigned int value);
14887- };
14888- template<>
14889- struct StringMaker<unsigned long> {
14890- static std::string convert(unsigned long value);
14891- };
14892- template<>
14893- struct StringMaker<unsigned long long> {
14894- static std::string convert(unsigned long long value);
14895- };
14896-
14897- template<>
14898- struct StringMaker<bool> {
14899- static std::string convert(bool b) {
14900- using namespace std::string_literals;
14901- return b ? "true"s : "false"s;
14902- }
14903- };
14904-
14905- template<>
14906- struct StringMaker<char> {
14907- static std::string convert(char c);
14908- };
14909- template<>
14910- struct StringMaker<signed char> {
14911- static std::string convert(signed char value);
14912- };
14913- template<>
14914- struct StringMaker<unsigned char> {
14915- static std::string convert(unsigned char value);
14916- };
14917-
14918- template<>
14919- struct StringMaker<std::nullptr_t> {
14920- static std::string convert(std::nullptr_t) {
14921- using namespace std::string_literals;
14922- return "nullptr"s;
14923- }
14924- };
14925-
14926- template<>
14927- struct StringMaker<float> {
14928- static std::string convert(float value);
14929- CATCH_EXPORT static int precision;
14930- };
14931-
14932- template<>
14933- struct StringMaker<double> {
14934- static std::string convert(double value);
14935- CATCH_EXPORT static int precision;
14936- };
14937-
14938- template <typename T>
14939- struct StringMaker<T*> {
14940- template <typename U>
14941- static std::string convert(U* p) {
14942- if (p) {
14943- return ::Catch::Detail::rawMemoryToString(p);
14944- } else {
14945- return "nullptr";
14946- }
14947- }
14948- };
14949-
14950- template <typename R, typename C>
14951- struct StringMaker<R C::*> {
14952- static std::string convert(R C::* p) {
14953- if (p) {
14954- return ::Catch::Detail::rawMemoryToString(p);
14955- } else {
14956- return "nullptr";
14957- }
14958- }
14959- };
14960-
14961-#if defined(_MANAGED)
14962- template <typename T>
14963- struct StringMaker<T^> {
14964- static std::string convert( T^ ref ) {
14965- return ::Catch::Detail::clrReferenceToString(ref);
14966- }
14967- };
14968-#endif
14969-
14970- namespace Detail {
14971- template<typename InputIterator, typename Sentinel = InputIterator>
14972- std::string rangeToString(InputIterator first, Sentinel last) {
14973- ReusableStringStream rss;
14974- rss << "{ ";
14975- if (first != last) {
14976- rss << ::Catch::Detail::stringify(*first);
14977- for (++first; first != last; ++first)
14978- rss << ", " << ::Catch::Detail::stringify(*first);
14979- }
14980- rss << " }";
14981- return rss.str();
14982- }
14983- }
14984-
14985-} // namespace Catch
14986-
14987-//////////////////////////////////////////////////////
14988-// Separate std-lib types stringification, so it can be selectively enabled
14989-// This means that we do not bring in their headers
14990-
14991-#if defined(CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS)
14992-# define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
14993-# define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER
14994-# define CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
14995-# define CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER
14996-#endif
14997-
14998-// Separate std::pair specialization
14999-#if defined(CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER)
15000-#include <utility>
15001-namespace Catch {
15002- template<typename T1, typename T2>
15003- struct StringMaker<std::pair<T1, T2> > {
15004- static std::string convert(const std::pair<T1, T2>& pair) {
15005- ReusableStringStream rss;
15006- rss << "{ "
15007- << ::Catch::Detail::stringify(pair.first)
15008- << ", "
15009- << ::Catch::Detail::stringify(pair.second)
15010- << " }";
15011- return rss.str();
15012- }
15013- };
15014-}
15015-#endif // CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
15016-
15017-#if defined(CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_OPTIONAL)
15018-#include <optional>
15019-namespace Catch {
15020- template<typename T>
15021- struct StringMaker<std::optional<T> > {
15022- static std::string convert(const std::optional<T>& optional) {
15023- if (optional.has_value()) {
15024- return ::Catch::Detail::stringify(*optional);
15025- } else {
15026- return "{ }";
15027- }
15028- }
15029- };
15030- template <>
15031- struct StringMaker<std::nullopt_t> {
15032- static std::string convert(const std::nullopt_t&) {
15033- return "{ }";
15034- }
15035- };
15036-}
15037-#endif // CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER
15038-
15039-// Separate std::tuple specialization
15040-#if defined(CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER)
15041-#include <tuple>
15042-namespace Catch {
15043- namespace Detail {
15044- template<
15045- typename Tuple,
15046- std::size_t N = 0,
15047- bool = (N < std::tuple_size<Tuple>::value)
15048- >
15049- struct TupleElementPrinter {
15050- static void print(const Tuple& tuple, std::ostream& os) {
15051- os << (N ? ", " : " ")
15052- << ::Catch::Detail::stringify(std::get<N>(tuple));
15053- TupleElementPrinter<Tuple, N + 1>::print(tuple, os);
15054- }
15055- };
15056-
15057- template<
15058- typename Tuple,
15059- std::size_t N
15060- >
15061- struct TupleElementPrinter<Tuple, N, false> {
15062- static void print(const Tuple&, std::ostream&) {}
15063- };
15064-
15065- }
15066-
15067-
15068- template<typename ...Types>
15069- struct StringMaker<std::tuple<Types...>> {
15070- static std::string convert(const std::tuple<Types...>& tuple) {
15071- ReusableStringStream rss;
15072- rss << '{';
15073- Detail::TupleElementPrinter<std::tuple<Types...>>::print(tuple, rss.get());
15074- rss << " }";
15075- return rss.str();
15076- }
15077- };
15078-}
15079-#endif // CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER
15080-
15081-#if defined(CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_VARIANT)
15082-#include <variant>
15083-namespace Catch {
15084- template<>
15085- struct StringMaker<std::monostate> {
15086- static std::string convert(const std::monostate&) {
15087- return "{ }";
15088- }
15089- };
15090-
15091- template<typename... Elements>
15092- struct StringMaker<std::variant<Elements...>> {
15093- static std::string convert(const std::variant<Elements...>& variant) {
15094- if (variant.valueless_by_exception()) {
15095- return "{valueless variant}";
15096- } else {
15097- return std::visit(
15098- [](const auto& value) {
15099- return ::Catch::Detail::stringify(value);
15100- },
15101- variant
15102- );
15103- }
15104- }
15105- };
15106-}
15107-#endif // CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
15108-
15109-namespace Catch {
15110- // Import begin/ end from std here
15111- using std::begin;
15112- using std::end;
15113-
15114- namespace Detail {
15115- template <typename T, typename = void>
15116- struct is_range_impl : std::false_type {};
15117-
15118- template <typename T>
15119- struct is_range_impl<T, void_t<decltype(begin(std::declval<T>()))>> : std::true_type {};
15120- } // namespace Detail
15121-
15122- template <typename T>
15123- struct is_range : Detail::is_range_impl<T> {};
15124-
15125-#if defined(_MANAGED) // Managed types are never ranges
15126- template <typename T>
15127- struct is_range<T^> {
15128- static const bool value = false;
15129- };
15130-#endif
15131-
15132- template<typename Range>
15133- std::string rangeToString( Range const& range ) {
15134- return ::Catch::Detail::rangeToString( begin( range ), end( range ) );
15135- }
15136-
15137- // Handle vector<bool> specially
15138- template<typename Allocator>
15139- std::string rangeToString( std::vector<bool, Allocator> const& v ) {
15140- ReusableStringStream rss;
15141- rss << "{ ";
15142- bool first = true;
15143- for( bool b : v ) {
15144- if( first )
15145- first = false;
15146- else
15147- rss << ", ";
15148- rss << ::Catch::Detail::stringify( b );
15149- }
15150- rss << " }";
15151- return rss.str();
15152- }
15153-
15154- template<typename R>
15155- struct StringMaker<R, std::enable_if_t<is_range<R>::value && !::Catch::Detail::IsStreamInsertable_v<R>>> {
15156- static std::string convert( R const& range ) {
15157- return rangeToString( range );
15158- }
15159- };
15160-
15161- template <typename T, size_t SZ>
15162- struct StringMaker<T[SZ]> {
15163- static std::string convert(T const(&arr)[SZ]) {
15164- return rangeToString(arr);
15165- }
15166- };
15167-
15168-
15169-} // namespace Catch
15170-
15171-// Separate std::chrono::duration specialization
15172-#include <ctime>
15173-#include <ratio>
15174-#include <chrono>
15175-
15176-
15177-namespace Catch {
15178-
15179-template <class Ratio>
15180-struct ratio_string {
15181- static std::string symbol() {
15182- Catch::ReusableStringStream rss;
15183- rss << '[' << Ratio::num << '/'
15184- << Ratio::den << ']';
15185- return rss.str();
15186- }
15187-};
15188-
15189-template <>
15190-struct ratio_string<std::atto> {
15191- static char symbol() { return 'a'; }
15192-};
15193-template <>
15194-struct ratio_string<std::femto> {
15195- static char symbol() { return 'f'; }
15196-};
15197-template <>
15198-struct ratio_string<std::pico> {
15199- static char symbol() { return 'p'; }
15200-};
15201-template <>
15202-struct ratio_string<std::nano> {
15203- static char symbol() { return 'n'; }
15204-};
15205-template <>
15206-struct ratio_string<std::micro> {
15207- static char symbol() { return 'u'; }
15208-};
15209-template <>
15210-struct ratio_string<std::milli> {
15211- static char symbol() { return 'm'; }
15212-};
15213-
15214- ////////////
15215- // std::chrono::duration specializations
15216- template<typename Value, typename Ratio>
15217- struct StringMaker<std::chrono::duration<Value, Ratio>> {
15218- static std::string convert(std::chrono::duration<Value, Ratio> const& duration) {
15219- ReusableStringStream rss;
15220- rss << duration.count() << ' ' << ratio_string<Ratio>::symbol() << 's';
15221- return rss.str();
15222- }
15223- };
15224- template<typename Value>
15225- struct StringMaker<std::chrono::duration<Value, std::ratio<1>>> {
15226- static std::string convert(std::chrono::duration<Value, std::ratio<1>> const& duration) {
15227- ReusableStringStream rss;
15228- rss << duration.count() << " s";
15229- return rss.str();
15230- }
15231- };
15232- template<typename Value>
15233- struct StringMaker<std::chrono::duration<Value, std::ratio<60>>> {
15234- static std::string convert(std::chrono::duration<Value, std::ratio<60>> const& duration) {
15235- ReusableStringStream rss;
15236- rss << duration.count() << " m";
15237- return rss.str();
15238- }
15239- };
15240- template<typename Value>
15241- struct StringMaker<std::chrono::duration<Value, std::ratio<3600>>> {
15242- static std::string convert(std::chrono::duration<Value, std::ratio<3600>> const& duration) {
15243- ReusableStringStream rss;
15244- rss << duration.count() << " h";
15245- return rss.str();
15246- }
15247- };
15248-
15249- ////////////
15250- // std::chrono::time_point specialization
15251- // Generic time_point cannot be specialized, only std::chrono::time_point<system_clock>
15252- template<typename Clock, typename Duration>
15253- struct StringMaker<std::chrono::time_point<Clock, Duration>> {
15254- static std::string convert(std::chrono::time_point<Clock, Duration> const& time_point) {
15255- return ::Catch::Detail::stringify(time_point.time_since_epoch()) + " since epoch";
15256- }
15257- };
15258- // std::chrono::time_point<system_clock> specialization
15259- template<typename Duration>
15260- struct StringMaker<std::chrono::time_point<std::chrono::system_clock, Duration>> {
15261- static std::string convert(std::chrono::time_point<std::chrono::system_clock, Duration> const& time_point) {
15262- const auto systemish = std::chrono::time_point_cast<
15263- std::chrono::system_clock::duration>( time_point );
15264- const auto as_time_t = std::chrono::system_clock::to_time_t( systemish );
15265-
15266-#ifdef _MSC_VER
15267- std::tm timeInfo = {};
15268- const auto err = gmtime_s( &timeInfo, &as_time_t );
15269- if ( err ) {
15270- return "gmtime from provided timepoint has failed. This "
15271- "happens e.g. with pre-1970 dates using Microsoft libc";
15272- }
15273-#else
15274- std::tm* timeInfo = std::gmtime( &as_time_t );
15275-#endif
15276-
15277- auto const timeStampSize = sizeof("2017-01-16T17:06:45Z");
15278- char timeStamp[timeStampSize];
15279- const char * const fmt = "%Y-%m-%dT%H:%M:%SZ";
15280-
15281-#ifdef _MSC_VER
15282- std::strftime(timeStamp, timeStampSize, fmt, &timeInfo);
15283-#else
15284- std::strftime(timeStamp, timeStampSize, fmt, timeInfo);
15285-#endif
15286- return std::string(timeStamp, timeStampSize - 1);
15287- }
15288- };
15289-}
15290-
15291-
15292-#define INTERNAL_CATCH_REGISTER_ENUM( enumName, ... ) \
15293-namespace Catch { \
15294- template<> struct StringMaker<enumName> { \
15295- static std::string convert( enumName value ) { \
15296- static const auto& enumInfo = ::Catch::getMutableRegistryHub().getMutableEnumValuesRegistry().registerEnum( #enumName, #__VA_ARGS__, { __VA_ARGS__ } ); \
15297- return static_cast<std::string>(enumInfo.lookup( static_cast<int>( value ) )); \
15298- } \
15299- }; \
15300-}
15301-
15302-#define CATCH_REGISTER_ENUM( enumName, ... ) INTERNAL_CATCH_REGISTER_ENUM( enumName, __VA_ARGS__ )
15303-
15304-#ifdef _MSC_VER
15305-#pragma warning(pop)
15306-#endif
15307-
15308-#endif // CATCH_TOSTRING_HPP_INCLUDED
15309-
15310-#include <type_traits>
15311-
15312-namespace Catch {
15313-
15314- class Approx {
15315- private:
15316- bool equalityComparisonImpl(double other) const;
15317- // Sets and validates the new margin (margin >= 0)
15318- void setMargin(double margin);
15319- // Sets and validates the new epsilon (0 < epsilon < 1)
15320- void setEpsilon(double epsilon);
15321-
15322- public:
15323- explicit Approx ( double value );
15324-
15325- static Approx custom();
15326-
15327- Approx operator-() const;
15328-
15329- template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
15330- Approx operator()( T const& value ) const {
15331- Approx approx( static_cast<double>(value) );
15332- approx.m_epsilon = m_epsilon;
15333- approx.m_margin = m_margin;
15334- approx.m_scale = m_scale;
15335- return approx;
15336- }
15337-
15338- template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
15339- explicit Approx( T const& value ): Approx(static_cast<double>(value))
15340- {}
15341-
15342-
15343- template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
15344- friend bool operator == ( const T& lhs, Approx const& rhs ) {
15345- auto lhs_v = static_cast<double>(lhs);
15346- return rhs.equalityComparisonImpl(lhs_v);
15347- }
15348-
15349- template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
15350- friend bool operator == ( Approx const& lhs, const T& rhs ) {
15351- return operator==( rhs, lhs );
15352- }
15353-
15354- template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
15355- friend bool operator != ( T const& lhs, Approx const& rhs ) {
15356- return !operator==( lhs, rhs );
15357- }
15358-
15359- template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
15360- friend bool operator != ( Approx const& lhs, T const& rhs ) {
15361- return !operator==( rhs, lhs );
15362- }
15363-
15364- template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
15365- friend bool operator <= ( T const& lhs, Approx const& rhs ) {
15366- return static_cast<double>(lhs) < rhs.m_value || lhs == rhs;
15367- }
15368-
15369- template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
15370- friend bool operator <= ( Approx const& lhs, T const& rhs ) {
15371- return lhs.m_value < static_cast<double>(rhs) || lhs == rhs;
15372- }
15373-
15374- template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
15375- friend bool operator >= ( T const& lhs, Approx const& rhs ) {
15376- return static_cast<double>(lhs) > rhs.m_value || lhs == rhs;
15377- }
15378-
15379- template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
15380- friend bool operator >= ( Approx const& lhs, T const& rhs ) {
15381- return lhs.m_value > static_cast<double>(rhs) || lhs == rhs;
15382- }
15383-
15384- template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
15385- Approx& epsilon( T const& newEpsilon ) {
15386- const auto epsilonAsDouble = static_cast<double>(newEpsilon);
15387- setEpsilon(epsilonAsDouble);
15388- return *this;
15389- }
15390-
15391- template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
15392- Approx& margin( T const& newMargin ) {
15393- const auto marginAsDouble = static_cast<double>(newMargin);
15394- setMargin(marginAsDouble);
15395- return *this;
15396- }
15397-
15398- template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
15399- Approx& scale( T const& newScale ) {
15400- m_scale = static_cast<double>(newScale);
15401- return *this;
15402- }
15403-
15404- std::string toString() const;
15405-
15406- private:
15407- double m_epsilon;
15408- double m_margin;
15409- double m_scale;
15410- double m_value;
15411- };
15412-
15413-namespace literals {
15414- Approx operator ""_a(long double val);
15415- Approx operator ""_a(unsigned long long val);
15416-} // end namespace literals
15417-
15418-template<>
15419-struct StringMaker<Catch::Approx> {
15420- static std::string convert(Catch::Approx const& value);
15421-};
15422-
15423-} // end namespace Catch
15424-
15425-#endif // CATCH_APPROX_HPP_INCLUDED
15426-
15427-
15428-#ifndef CATCH_ASSERTION_INFO_HPP_INCLUDED
15429-#define CATCH_ASSERTION_INFO_HPP_INCLUDED
15430-
15431-
15432-
15433-#ifndef CATCH_SOURCE_LINE_INFO_HPP_INCLUDED
15434-#define CATCH_SOURCE_LINE_INFO_HPP_INCLUDED
15435-
15436-#include <cstddef>
15437-#include <iosfwd>
15438-
15439-namespace Catch {
15440-
15441- struct SourceLineInfo {
15442-
15443- SourceLineInfo() = delete;
15444- constexpr SourceLineInfo( char const* _file, std::size_t _line ) noexcept:
15445- file( _file ),
15446- line( _line )
15447- {}
15448-
15449- bool operator == ( SourceLineInfo const& other ) const noexcept;
15450- bool operator < ( SourceLineInfo const& other ) const noexcept;
15451-
15452- char const* file;
15453- std::size_t line;
15454-
15455- friend std::ostream& operator << (std::ostream& os, SourceLineInfo const& info);
15456- };
15457-}
15458-
15459-#define CATCH_INTERNAL_LINEINFO \
15460- ::Catch::SourceLineInfo( __FILE__, static_cast<std::size_t>( __LINE__ ) )
15461-
15462-#endif // CATCH_SOURCE_LINE_INFO_HPP_INCLUDED
15463-
15464-namespace Catch {
15465-
15466- struct AssertionInfo {
15467- // AssertionInfo() = delete;
15468-
15469- StringRef macroName;
15470- SourceLineInfo lineInfo;
15471- StringRef capturedExpression;
15472- ResultDisposition::Flags resultDisposition;
15473- };
15474-
15475-} // end namespace Catch
15476-
15477-#endif // CATCH_ASSERTION_INFO_HPP_INCLUDED
15478-
15479-
15480-#ifndef CATCH_ASSERTION_RESULT_HPP_INCLUDED
15481-#define CATCH_ASSERTION_RESULT_HPP_INCLUDED
15482-
15483-
15484-
15485-#ifndef CATCH_LAZY_EXPR_HPP_INCLUDED
15486-#define CATCH_LAZY_EXPR_HPP_INCLUDED
15487-
15488-#include <iosfwd>
15489-
15490-namespace Catch {
15491-
15492- class ITransientExpression;
15493-
15494- class LazyExpression {
15495- friend class AssertionHandler;
15496- friend struct AssertionStats;
15497- friend class RunContext;
15498-
15499- ITransientExpression const* m_transientExpression = nullptr;
15500- bool m_isNegated;
15501- public:
15502- constexpr LazyExpression( bool isNegated ):
15503- m_isNegated(isNegated)
15504- {}
15505- constexpr LazyExpression(LazyExpression const& other) = default;
15506- LazyExpression& operator = ( LazyExpression const& ) = delete;
15507-
15508- constexpr explicit operator bool() const {
15509- return m_transientExpression != nullptr;
15510- }
15511-
15512- friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&;
15513- };
15514-
15515-} // namespace Catch
15516-
15517-#endif // CATCH_LAZY_EXPR_HPP_INCLUDED
15518-
15519-#include <string>
15520-
15521-namespace Catch {
15522-
15523- struct AssertionResultData
15524- {
15525- AssertionResultData() = delete;
15526-
15527- AssertionResultData( ResultWas::OfType _resultType, LazyExpression const& _lazyExpression );
15528-
15529- std::string message;
15530- mutable std::string reconstructedExpression;
15531- LazyExpression lazyExpression;
15532- ResultWas::OfType resultType;
15533-
15534- std::string reconstructExpression() const;
15535- };
15536-
15537- class AssertionResult {
15538- public:
15539- AssertionResult() = delete;
15540- AssertionResult( AssertionInfo const& info, AssertionResultData&& data );
15541-
15542- bool isOk() const;
15543- bool succeeded() const;
15544- ResultWas::OfType getResultType() const;
15545- bool hasExpression() const;
15546- bool hasMessage() const;
15547- std::string getExpression() const;
15548- std::string getExpressionInMacro() const;
15549- bool hasExpandedExpression() const;
15550- std::string getExpandedExpression() const;
15551- StringRef getMessage() const;
15552- SourceLineInfo getSourceInfo() const;
15553- StringRef getTestMacroName() const;
15554-
15555- //protected:
15556- AssertionInfo m_info;
15557- AssertionResultData m_resultData;
15558- };
15559-
15560-} // end namespace Catch
15561-
15562-#endif // CATCH_ASSERTION_RESULT_HPP_INCLUDED
15563-
15564-
15565-#ifndef CATCH_CASE_SENSITIVE_HPP_INCLUDED
15566-#define CATCH_CASE_SENSITIVE_HPP_INCLUDED
15567-
15568-namespace Catch {
15569-
15570- enum class CaseSensitive { Yes, No };
15571-
15572-} // namespace Catch
15573-
15574-#endif // CATCH_CASE_SENSITIVE_HPP_INCLUDED
15575-
15576-
15577-#ifndef CATCH_CONFIG_HPP_INCLUDED
15578-#define CATCH_CONFIG_HPP_INCLUDED
15579-
15580-
15581-
15582-#ifndef CATCH_TEST_SPEC_HPP_INCLUDED
15583-#define CATCH_TEST_SPEC_HPP_INCLUDED
15584-
15585-#ifdef __clang__
15586-#pragma clang diagnostic push
15587-#pragma clang diagnostic ignored "-Wpadded"
15588-#endif
15589-
15590-
15591-
15592-#ifndef CATCH_WILDCARD_PATTERN_HPP_INCLUDED
15593-#define CATCH_WILDCARD_PATTERN_HPP_INCLUDED
15594-
15595-
15596-#include <string>
15597-
15598-namespace Catch
15599-{
15600- class WildcardPattern {
15601- enum WildcardPosition {
15602- NoWildcard = 0,
15603- WildcardAtStart = 1,
15604- WildcardAtEnd = 2,
15605- WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd
15606- };
15607-
15608- public:
15609-
15610- WildcardPattern( std::string const& pattern, CaseSensitive caseSensitivity );
15611- bool matches( std::string const& str ) const;
15612-
15613- private:
15614- std::string normaliseString( std::string const& str ) const;
15615- CaseSensitive m_caseSensitivity;
15616- WildcardPosition m_wildcard = NoWildcard;
15617- std::string m_pattern;
15618- };
15619-}
15620-
15621-#endif // CATCH_WILDCARD_PATTERN_HPP_INCLUDED
15622-
15623-#include <iosfwd>
15624-#include <string>
15625-#include <vector>
15626-
15627-namespace Catch {
15628-
15629- class IConfig;
15630- struct TestCaseInfo;
15631- class TestCaseHandle;
15632-
15633- class TestSpec {
15634-
15635- class Pattern {
15636- public:
15637- explicit Pattern( std::string const& name );
15638- virtual ~Pattern();
15639- virtual bool matches( TestCaseInfo const& testCase ) const = 0;
15640- std::string const& name() const;
15641- private:
15642- virtual void serializeTo( std::ostream& out ) const = 0;
15643- // Writes string that would be reparsed into the pattern
15644- friend std::ostream& operator<<(std::ostream& out,
15645- Pattern const& pattern) {
15646- pattern.serializeTo( out );
15647- return out;
15648- }
15649-
15650- std::string const m_name;
15651- };
15652-
15653- class NamePattern : public Pattern {
15654- public:
15655- explicit NamePattern( std::string const& name, std::string const& filterString );
15656- bool matches( TestCaseInfo const& testCase ) const override;
15657- private:
15658- void serializeTo( std::ostream& out ) const override;
15659-
15660- WildcardPattern m_wildcardPattern;
15661- };
15662-
15663- class TagPattern : public Pattern {
15664- public:
15665- explicit TagPattern( std::string const& tag, std::string const& filterString );
15666- bool matches( TestCaseInfo const& testCase ) const override;
15667- private:
15668- void serializeTo( std::ostream& out ) const override;
15669-
15670- std::string m_tag;
15671- };
15672-
15673- struct Filter {
15674- std::vector<Detail::unique_ptr<Pattern>> m_required;
15675- std::vector<Detail::unique_ptr<Pattern>> m_forbidden;
15676-
15677- //! Serializes this filter into a string that would be parsed into
15678- //! an equivalent filter
15679- void serializeTo( std::ostream& out ) const;
15680- friend std::ostream& operator<<(std::ostream& out, Filter const& f) {
15681- f.serializeTo( out );
15682- return out;
15683- }
15684-
15685- bool matches( TestCaseInfo const& testCase ) const;
15686- };
15687-
15688- static std::string extractFilterName( Filter const& filter );
15689-
15690- public:
15691- struct FilterMatch {
15692- std::string name;
15693- std::vector<TestCaseHandle const*> tests;
15694- };
15695- using Matches = std::vector<FilterMatch>;
15696- using vectorStrings = std::vector<std::string>;
15697-
15698- bool hasFilters() const;
15699- bool matches( TestCaseInfo const& testCase ) const;
15700- Matches matchesByFilter( std::vector<TestCaseHandle> const& testCases, IConfig const& config ) const;
15701- const vectorStrings & getInvalidSpecs() const;
15702-
15703- private:
15704- std::vector<Filter> m_filters;
15705- std::vector<std::string> m_invalidSpecs;
15706-
15707- friend class TestSpecParser;
15708- //! Serializes this test spec into a string that would be parsed into
15709- //! equivalent test spec
15710- void serializeTo( std::ostream& out ) const;
15711- friend std::ostream& operator<<(std::ostream& out,
15712- TestSpec const& spec) {
15713- spec.serializeTo( out );
15714- return out;
15715- }
15716- };
15717-}
15718-
15719-#ifdef __clang__
15720-#pragma clang diagnostic pop
15721-#endif
15722-
15723-#endif // CATCH_TEST_SPEC_HPP_INCLUDED
15724-
15725-
15726-#ifndef CATCH_OPTIONAL_HPP_INCLUDED
15727-#define CATCH_OPTIONAL_HPP_INCLUDED
15728-
15729-
15730-#include <cassert>
15731-
15732-namespace Catch {
15733-
15734- // An optional type
15735- template<typename T>
15736- class Optional {
15737- public:
15738- Optional(): nullableValue( nullptr ) {}
15739- ~Optional() { reset(); }
15740-
15741- Optional( T const& _value ):
15742- nullableValue( new ( storage ) T( _value ) ) {}
15743- Optional( T&& _value ):
15744- nullableValue( new ( storage ) T( CATCH_MOVE( _value ) ) ) {}
15745-
15746- Optional& operator=( T const& _value ) {
15747- reset();
15748- nullableValue = new ( storage ) T( _value );
15749- return *this;
15750- }
15751- Optional& operator=( T&& _value ) {
15752- reset();
15753- nullableValue = new ( storage ) T( CATCH_MOVE( _value ) );
15754- return *this;
15755- }
15756-
15757- Optional( Optional const& _other ):
15758- nullableValue( _other ? new ( storage ) T( *_other ) : nullptr ) {}
15759- Optional( Optional&& _other ):
15760- nullableValue( _other ? new ( storage ) T( CATCH_MOVE( *_other ) )
15761- : nullptr ) {}
15762-
15763- Optional& operator=( Optional const& _other ) {
15764- if ( &_other != this ) {
15765- reset();
15766- if ( _other ) { nullableValue = new ( storage ) T( *_other ); }
15767- }
15768- return *this;
15769- }
15770- Optional& operator=( Optional&& _other ) {
15771- if ( &_other != this ) {
15772- reset();
15773- if ( _other ) {
15774- nullableValue = new ( storage ) T( CATCH_MOVE( *_other ) );
15775- }
15776- }
15777- return *this;
15778- }
15779-
15780- void reset() {
15781- if ( nullableValue ) { nullableValue->~T(); }
15782- nullableValue = nullptr;
15783- }
15784-
15785- T& operator*() {
15786- assert(nullableValue);
15787- return *nullableValue;
15788- }
15789- T const& operator*() const {
15790- assert(nullableValue);
15791- return *nullableValue;
15792- }
15793- T* operator->() {
15794- assert(nullableValue);
15795- return nullableValue;
15796- }
15797- const T* operator->() const {
15798- assert(nullableValue);
15799- return nullableValue;
15800- }
15801-
15802- T valueOr( T const& defaultValue ) const {
15803- return nullableValue ? *nullableValue : defaultValue;
15804- }
15805-
15806- bool some() const { return nullableValue != nullptr; }
15807- bool none() const { return nullableValue == nullptr; }
15808-
15809- bool operator !() const { return nullableValue == nullptr; }
15810- explicit operator bool() const {
15811- return some();
15812- }
15813-
15814- friend bool operator==(Optional const& a, Optional const& b) {
15815- if (a.none() && b.none()) {
15816- return true;
15817- } else if (a.some() && b.some()) {
15818- return *a == *b;
15819- } else {
15820- return false;
15821- }
15822- }
15823- friend bool operator!=(Optional const& a, Optional const& b) {
15824- return !( a == b );
15825- }
15826-
15827- private:
15828- T* nullableValue;
15829- alignas(alignof(T)) char storage[sizeof(T)];
15830- };
15831-
15832-} // end namespace Catch
15833-
15834-#endif // CATCH_OPTIONAL_HPP_INCLUDED
15835-
15836-
15837-#ifndef CATCH_RANDOM_SEED_GENERATION_HPP_INCLUDED
15838-#define CATCH_RANDOM_SEED_GENERATION_HPP_INCLUDED
15839-
15840-#include <cstdint>
15841-
15842-namespace Catch {
15843-
15844- enum class GenerateFrom {
15845- Time,
15846- RandomDevice,
15847- //! Currently equivalent to RandomDevice, but can change at any point
15848- Default
15849- };
15850-
15851- std::uint32_t generateRandomSeed(GenerateFrom from);
15852-
15853-} // end namespace Catch
15854-
15855-#endif // CATCH_RANDOM_SEED_GENERATION_HPP_INCLUDED
15856-
15857-
15858-#ifndef CATCH_REPORTER_SPEC_PARSER_HPP_INCLUDED
15859-#define CATCH_REPORTER_SPEC_PARSER_HPP_INCLUDED
15860-
15861-
15862-#include <map>
15863-#include <string>
15864-#include <vector>
15865-
15866-namespace Catch {
15867-
15868- enum class ColourMode : std::uint8_t;
15869-
15870- namespace Detail {
15871- //! Splits the reporter spec into reporter name and kv-pair options
15872- std::vector<std::string> splitReporterSpec( StringRef reporterSpec );
15873-
15874- Optional<ColourMode> stringToColourMode( StringRef colourMode );
15875- }
15876-
15877- /**
15878- * Structured reporter spec that a reporter can be created from
15879- *
15880- * Parsing has been validated, but semantics have not. This means e.g.
15881- * that the colour mode is known to Catch2, but it might not be
15882- * compiled into the binary, and the output filename might not be
15883- * openable.
15884- */
15885- class ReporterSpec {
15886- std::string m_name;
15887- Optional<std::string> m_outputFileName;
15888- Optional<ColourMode> m_colourMode;
15889- std::map<std::string, std::string> m_customOptions;
15890-
15891- friend bool operator==( ReporterSpec const& lhs,
15892- ReporterSpec const& rhs );
15893- friend bool operator!=( ReporterSpec const& lhs,
15894- ReporterSpec const& rhs ) {
15895- return !( lhs == rhs );
15896- }
15897-
15898- public:
15899- ReporterSpec(
15900- std::string name,
15901- Optional<std::string> outputFileName,
15902- Optional<ColourMode> colourMode,
15903- std::map<std::string, std::string> customOptions );
15904-
15905- std::string const& name() const { return m_name; }
15906-
15907- Optional<std::string> const& outputFile() const {
15908- return m_outputFileName;
15909- }
15910-
15911- Optional<ColourMode> const& colourMode() const { return m_colourMode; }
15912-
15913- std::map<std::string, std::string> const& customOptions() const {
15914- return m_customOptions;
15915- }
15916- };
15917-
15918- /**
15919- * Parses provided reporter spec string into
15920- *
15921- * Returns empty optional on errors, e.g.
15922- * * field that is not first and not a key+value pair
15923- * * duplicated keys in kv pair
15924- * * unknown catch reporter option
15925- * * empty key/value in an custom kv pair
15926- * * ...
15927- */
15928- Optional<ReporterSpec> parseReporterSpec( StringRef reporterSpec );
15929-
15930-}
15931-
15932-#endif // CATCH_REPORTER_SPEC_PARSER_HPP_INCLUDED
15933-
15934-#include <chrono>
15935-#include <map>
15936-#include <string>
15937-#include <vector>
15938-
15939-namespace Catch {
15940-
15941- class IStream;
15942-
15943- /**
15944- * `ReporterSpec` but with the defaults filled in.
15945- *
15946- * Like `ReporterSpec`, the semantics are unchecked.
15947- */
15948- struct ProcessedReporterSpec {
15949- std::string name;
15950- std::string outputFilename;
15951- ColourMode colourMode;
15952- std::map<std::string, std::string> customOptions;
15953- friend bool operator==( ProcessedReporterSpec const& lhs,
15954- ProcessedReporterSpec const& rhs );
15955- friend bool operator!=( ProcessedReporterSpec const& lhs,
15956- ProcessedReporterSpec const& rhs ) {
15957- return !( lhs == rhs );
15958- }
15959- };
15960-
15961- struct ConfigData {
15962-
15963- bool listTests = false;
15964- bool listTags = false;
15965- bool listReporters = false;
15966- bool listListeners = false;
15967-
15968- bool showSuccessfulTests = false;
15969- bool shouldDebugBreak = false;
15970- bool noThrow = false;
15971- bool showHelp = false;
15972- bool showInvisibles = false;
15973- bool filenamesAsTags = false;
15974- bool libIdentify = false;
15975- bool allowZeroTests = false;
15976-
15977- int abortAfter = -1;
15978- uint32_t rngSeed = generateRandomSeed(GenerateFrom::Default);
15979-
15980- unsigned int shardCount = 1;
15981- unsigned int shardIndex = 0;
15982-
15983- bool skipBenchmarks = false;
15984- bool benchmarkNoAnalysis = false;
15985- unsigned int benchmarkSamples = 100;
15986- double benchmarkConfidenceInterval = 0.95;
15987- unsigned int benchmarkResamples = 100'000;
15988- std::chrono::milliseconds::rep benchmarkWarmupTime = 100;
15989-
15990- Verbosity verbosity = Verbosity::Normal;
15991- WarnAbout::What warnings = WarnAbout::Nothing;
15992- ShowDurations showDurations = ShowDurations::DefaultForReporter;
15993- double minDuration = -1;
15994- TestRunOrder runOrder = TestRunOrder::Randomized;
15995- ColourMode defaultColourMode = ColourMode::PlatformDefault;
15996- WaitForKeypress::When waitForKeypress = WaitForKeypress::Never;
15997-
15998- std::string defaultOutputFilename;
15999- std::string name;
16000- std::string processName;
16001- std::vector<ReporterSpec> reporterSpecifications;
16002-
16003- std::vector<std::string> testsOrTags;
16004- std::vector<std::string> sectionsToRun;
16005-
16006- std::string prematureExitGuardFilePath;
16007- };
16008-
16009-
16010- class Config : public IConfig {
16011- public:
16012-
16013- Config() = default;
16014- Config( ConfigData const& data );
16015- ~Config() override; // = default in the cpp file
16016-
16017- bool listTests() const;
16018- bool listTags() const;
16019- bool listReporters() const;
16020- bool listListeners() const;
16021-
16022- std::vector<ReporterSpec> const& getReporterSpecs() const;
16023- std::vector<ProcessedReporterSpec> const&
16024- getProcessedReporterSpecs() const;
16025-
16026- std::vector<std::string> const& getTestsOrTags() const override;
16027- std::vector<std::string> const& getSectionsToRun() const override;
16028-
16029- TestSpec const& testSpec() const override;
16030- bool hasTestFilters() const override;
16031-
16032- bool showHelp() const;
16033-
16034- std::string const& getExitGuardFilePath() const;
16035-
16036- // IConfig interface
16037- bool allowThrows() const override;
16038- StringRef name() const override;
16039- bool includeSuccessfulResults() const override;
16040- bool warnAboutMissingAssertions() const override;
16041- bool warnAboutUnmatchedTestSpecs() const override;
16042- bool zeroTestsCountAsSuccess() const override;
16043- ShowDurations showDurations() const override;
16044- double minDuration() const override;
16045- TestRunOrder runOrder() const override;
16046- uint32_t rngSeed() const override;
16047- unsigned int shardCount() const override;
16048- unsigned int shardIndex() const override;
16049- ColourMode defaultColourMode() const override;
16050- bool shouldDebugBreak() const override;
16051- int abortAfter() const override;
16052- bool showInvisibles() const override;
16053- Verbosity verbosity() const override;
16054- bool skipBenchmarks() const override;
16055- bool benchmarkNoAnalysis() const override;
16056- unsigned int benchmarkSamples() const override;
16057- double benchmarkConfidenceInterval() const override;
16058- unsigned int benchmarkResamples() const override;
16059- std::chrono::milliseconds benchmarkWarmupTime() const override;
16060-
16061- private:
16062- // Reads Bazel env vars and applies them to the config
16063- void readBazelEnvVars();
16064-
16065- ConfigData m_data;
16066- std::vector<ProcessedReporterSpec> m_processedReporterSpecs;
16067- TestSpec m_testSpec;
16068- bool m_hasTestFilters = false;
16069- };
16070-} // end namespace Catch
16071-
16072-#endif // CATCH_CONFIG_HPP_INCLUDED
16073-
16074-
16075-#ifndef CATCH_GET_RANDOM_SEED_HPP_INCLUDED
16076-#define CATCH_GET_RANDOM_SEED_HPP_INCLUDED
16077-
16078-#include <cstdint>
16079-
16080-namespace Catch {
16081- //! Returns Catch2's current RNG seed.
16082- std::uint32_t getSeed();
16083-}
16084-
16085-#endif // CATCH_GET_RANDOM_SEED_HPP_INCLUDED
16086-
16087-
16088-#ifndef CATCH_MESSAGE_HPP_INCLUDED
16089-#define CATCH_MESSAGE_HPP_INCLUDED
16090-
16091-
16092-
16093-
16094-/** \file
16095- * Wrapper for the CATCH_CONFIG_PREFIX_MESSAGES configuration option
16096- *
16097- * CATCH_CONFIG_PREFIX_ALL can be used to avoid clashes with other macros
16098- * by prepending CATCH_. This may not be desirable if the only clashes are with
16099- * logger macros such as INFO and WARN. In this cases
16100- * CATCH_CONFIG_PREFIX_MESSAGES can be used to only prefix a small subset
16101- * of relevant macros.
16102- *
16103- */
16104-
16105-#ifndef CATCH_CONFIG_PREFIX_MESSAGES_HPP_INCLUDED
16106-#define CATCH_CONFIG_PREFIX_MESSAGES_HPP_INCLUDED
16107-
16108-
16109-#if defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_PREFIX_MESSAGES)
16110- #define CATCH_CONFIG_PREFIX_MESSAGES
16111-#endif
16112-
16113-#endif // CATCH_CONFIG_PREFIX_MESSAGES_HPP_INCLUDED
16114-
16115-
16116-#ifndef CATCH_STREAM_END_STOP_HPP_INCLUDED
16117-#define CATCH_STREAM_END_STOP_HPP_INCLUDED
16118-
16119-
16120-namespace Catch {
16121-
16122- // Use this in variadic streaming macros to allow
16123- // << +StreamEndStop
16124- // as well as
16125- // << stuff +StreamEndStop
16126- struct StreamEndStop {
16127- constexpr StringRef operator+() const { return StringRef(); }
16128-
16129- template <typename T>
16130- constexpr friend T const& operator+( T const& value, StreamEndStop ) {
16131- return value;
16132- }
16133- };
16134-
16135-} // namespace Catch
16136-
16137-#endif // CATCH_STREAM_END_STOP_HPP_INCLUDED
16138-
16139-
16140-#ifndef CATCH_MESSAGE_INFO_HPP_INCLUDED
16141-#define CATCH_MESSAGE_INFO_HPP_INCLUDED
16142-
16143-
16144-
16145-#ifndef CATCH_DEPRECATION_MACRO_HPP_INCLUDED
16146-#define CATCH_DEPRECATION_MACRO_HPP_INCLUDED
16147-
16148-
16149-#if !defined( CATCH_CONFIG_NO_DEPRECATION_ANNOTATIONS )
16150-# define DEPRECATED( msg ) [[deprecated( msg )]]
16151-#else
16152-# define DEPRECATED( msg )
16153-#endif
16154-
16155-#endif // CATCH_DEPRECATION_MACRO_HPP_INCLUDED
16156-
16157-#include <string>
16158-
16159-namespace Catch {
16160-
16161- struct MessageInfo {
16162- MessageInfo( StringRef _macroName,
16163- SourceLineInfo const& _lineInfo,
16164- ResultWas::OfType _type );
16165-
16166- StringRef macroName;
16167- std::string message;
16168- SourceLineInfo lineInfo;
16169- ResultWas::OfType type;
16170- // The "ID" of the message, used to know when to remove it from reporter context.
16171- unsigned int sequence;
16172-
16173- DEPRECATED( "Explicitly use the 'sequence' member instead" )
16174- bool operator == (MessageInfo const& other) const {
16175- return sequence == other.sequence;
16176- }
16177- DEPRECATED( "Explicitly use the 'sequence' member instead" )
16178- bool operator < (MessageInfo const& other) const {
16179- return sequence < other.sequence;
16180- }
16181- private:
16182- static thread_local unsigned int globalCount;
16183- };
16184-
16185-} // end namespace Catch
16186-
16187-#endif // CATCH_MESSAGE_INFO_HPP_INCLUDED
16188-
16189-#include <string>
16190-#include <vector>
16191-
16192-namespace Catch {
16193-
16194- struct SourceLineInfo;
16195- class IResultCapture;
16196-
16197- struct MessageStream {
16198-
16199- template<typename T>
16200- MessageStream& operator << ( T const& value ) {
16201- m_stream << value;
16202- return *this;
16203- }
16204-
16205- ReusableStringStream m_stream;
16206- };
16207-
16208- struct MessageBuilder : MessageStream {
16209- MessageBuilder( StringRef macroName,
16210- SourceLineInfo const& lineInfo,
16211- ResultWas::OfType type ):
16212- m_info(macroName, lineInfo, type) {}
16213-
16214- template<typename T>
16215- MessageBuilder&& operator << ( T const& value ) && {
16216- m_stream << value;
16217- return CATCH_MOVE(*this);
16218- }
16219-
16220- MessageInfo m_info;
16221- };
16222-
16223- class ScopedMessage {
16224- public:
16225- explicit ScopedMessage( MessageBuilder&& builder );
16226- ScopedMessage( ScopedMessage& duplicate ) = delete;
16227- ScopedMessage( ScopedMessage&& old ) noexcept;
16228- ~ScopedMessage();
16229-
16230- unsigned int m_messageId;
16231- bool m_moved = false;
16232- };
16233-
16234- class Capturer {
16235- std::vector<MessageInfo> m_messages;
16236- size_t m_captured = 0;
16237- public:
16238- Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names );
16239-
16240- Capturer(Capturer const&) = delete;
16241- Capturer& operator=(Capturer const&) = delete;
16242-
16243- ~Capturer();
16244-
16245- void captureValue( size_t index, std::string const& value );
16246-
16247- template<typename T>
16248- void captureValues( size_t index, T const& value ) {
16249- captureValue( index, Catch::Detail::stringify( value ) );
16250- }
16251-
16252- template<typename T, typename... Ts>
16253- void captureValues( size_t index, T const& value, Ts const&... values ) {
16254- captureValue( index, Catch::Detail::stringify(value) );
16255- captureValues( index+1, values... );
16256- }
16257- };
16258-
16259-} // end namespace Catch
16260-
16261-///////////////////////////////////////////////////////////////////////////////
16262-#define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \
16263- do { \
16264- Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::StringRef(), resultDisposition ); \
16265- catchAssertionHandler.handleMessage( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \
16266- catchAssertionHandler.complete(); \
16267- } while( false )
16268-
16269-///////////////////////////////////////////////////////////////////////////////
16270-#define INTERNAL_CATCH_CAPTURE( varName, macroName, ... ) \
16271- Catch::Capturer varName( macroName##_catch_sr, \
16272- CATCH_INTERNAL_LINEINFO, \
16273- Catch::ResultWas::Info, \
16274- #__VA_ARGS__##_catch_sr ); \
16275- varName.captureValues( 0, __VA_ARGS__ )
16276-
16277-///////////////////////////////////////////////////////////////////////////////
16278-#define INTERNAL_CATCH_INFO( macroName, log ) \
16279- const Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log )
16280-
16281-///////////////////////////////////////////////////////////////////////////////
16282-#define INTERNAL_CATCH_UNSCOPED_INFO( macroName, log ) \
16283- Catch::IResultCapture::emplaceUnscopedMessage( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log )
16284-
16285-
16286-#if defined(CATCH_CONFIG_PREFIX_MESSAGES) && !defined(CATCH_CONFIG_DISABLE)
16287-
16288- #define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg )
16289- #define CATCH_UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "CATCH_UNSCOPED_INFO", msg )
16290- #define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
16291- #define CATCH_CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CATCH_CAPTURE", __VA_ARGS__ )
16292-
16293-#elif defined(CATCH_CONFIG_PREFIX_MESSAGES) && defined(CATCH_CONFIG_DISABLE)
16294-
16295- #define CATCH_INFO( msg ) (void)(0)
16296- #define CATCH_UNSCOPED_INFO( msg ) (void)(0)
16297- #define CATCH_WARN( msg ) (void)(0)
16298- #define CATCH_CAPTURE( ... ) (void)(0)
16299-
16300-#elif !defined(CATCH_CONFIG_PREFIX_MESSAGES) && !defined(CATCH_CONFIG_DISABLE)
16301-
16302- #define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg )
16303- #define UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "UNSCOPED_INFO", msg )
16304- #define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
16305- #define CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CAPTURE", __VA_ARGS__ )
16306-
16307-#elif !defined(CATCH_CONFIG_PREFIX_MESSAGES) && defined(CATCH_CONFIG_DISABLE)
16308-
16309- #define INFO( msg ) (void)(0)
16310- #define UNSCOPED_INFO( msg ) (void)(0)
16311- #define WARN( msg ) (void)(0)
16312- #define CAPTURE( ... ) (void)(0)
16313-
16314-#endif // end of user facing macro declarations
16315-
16316-
16317-
16318-
16319-#endif // CATCH_MESSAGE_HPP_INCLUDED
16320-
16321-
16322-#ifndef CATCH_SECTION_INFO_HPP_INCLUDED
16323-#define CATCH_SECTION_INFO_HPP_INCLUDED
16324-
16325-
16326-
16327-#ifndef CATCH_TOTALS_HPP_INCLUDED
16328-#define CATCH_TOTALS_HPP_INCLUDED
16329-
16330-#include <cstdint>
16331-
16332-namespace Catch {
16333-
16334- struct Counts {
16335- Counts operator - ( Counts const& other ) const;
16336- Counts& operator += ( Counts const& other );
16337-
16338- std::uint64_t total() const;
16339- bool allPassed() const;
16340- bool allOk() const;
16341-
16342- std::uint64_t passed = 0;
16343- std::uint64_t failed = 0;
16344- std::uint64_t failedButOk = 0;
16345- std::uint64_t skipped = 0;
16346- };
16347-
16348- struct Totals {
16349-
16350- Totals operator - ( Totals const& other ) const;
16351- Totals& operator += ( Totals const& other );
16352-
16353- Totals delta( Totals const& prevTotals ) const;
16354-
16355- Counts assertions;
16356- Counts testCases;
16357- };
16358-}
16359-
16360-#endif // CATCH_TOTALS_HPP_INCLUDED
16361-
16362-#include <string>
16363-
16364-namespace Catch {
16365-
16366- struct SectionInfo {
16367- // The last argument is ignored, so that people can write
16368- // SECTION("ShortName", "Proper description that is long") and
16369- // still use the `-c` flag comfortably.
16370- SectionInfo( SourceLineInfo const& _lineInfo, std::string _name,
16371- const char* const = nullptr ):
16372- name(CATCH_MOVE(_name)),
16373- lineInfo(_lineInfo)
16374- {}
16375-
16376- std::string name;
16377- SourceLineInfo lineInfo;
16378- };
16379-
16380- struct SectionEndInfo {
16381- SectionInfo sectionInfo;
16382- Counts prevAssertions;
16383- double durationInSeconds;
16384- };
16385-
16386-} // end namespace Catch
16387-
16388-#endif // CATCH_SECTION_INFO_HPP_INCLUDED
16389-
16390-
16391-#ifndef CATCH_SESSION_HPP_INCLUDED
16392-#define CATCH_SESSION_HPP_INCLUDED
16393-
16394-
16395-
16396-#ifndef CATCH_COMMANDLINE_HPP_INCLUDED
16397-#define CATCH_COMMANDLINE_HPP_INCLUDED
16398-
16399-
16400-
16401-#ifndef CATCH_CLARA_HPP_INCLUDED
16402-#define CATCH_CLARA_HPP_INCLUDED
16403-
16404-#if defined( __clang__ )
16405-# pragma clang diagnostic push
16406-# pragma clang diagnostic ignored "-Wweak-vtables"
16407-# pragma clang diagnostic ignored "-Wshadow"
16408-# pragma clang diagnostic ignored "-Wdeprecated"
16409-#endif
16410-
16411-#if defined( __GNUC__ )
16412-# pragma GCC diagnostic push
16413-# pragma GCC diagnostic ignored "-Wsign-conversion"
16414-#endif
16415-
16416-#ifndef CLARA_CONFIG_OPTIONAL_TYPE
16417-# ifdef __has_include
16418-# if __has_include( <optional>) && __cplusplus >= 201703L
16419-# include <optional>
16420-# define CLARA_CONFIG_OPTIONAL_TYPE std::optional
16421-# endif
16422-# endif
16423-#endif
16424-
16425-
16426-#include <cassert>
16427-#include <memory>
16428-#include <ostream>
16429-#include <sstream>
16430-#include <string>
16431-#include <type_traits>
16432-#include <vector>
16433-
16434-namespace Catch {
16435- namespace Clara {
16436-
16437- class Args;
16438- class Parser;
16439-
16440- // enum of result types from a parse
16441- enum class ParseResultType {
16442- Matched,
16443- NoMatch,
16444- ShortCircuitAll,
16445- ShortCircuitSame
16446- };
16447-
16448- struct accept_many_t {};
16449- constexpr accept_many_t accept_many {};
16450-
16451- namespace Detail {
16452- struct fake_arg {
16453- template <typename T>
16454- operator T();
16455- };
16456-
16457- template <typename F, typename = void>
16458- static constexpr bool is_unary_function_v = false;
16459-
16460- template <typename F>
16461- static constexpr bool is_unary_function_v<
16462- F,
16463- Catch::Detail::void_t<decltype( std::declval<F>()(
16464- fake_arg() ) )>> = true;
16465-
16466- // Traits for extracting arg and return type of lambdas (for single
16467- // argument lambdas)
16468- template <typename L>
16469- struct UnaryLambdaTraits
16470- : UnaryLambdaTraits<decltype( &L::operator() )> {};
16471-
16472- template <typename ClassT, typename ReturnT, typename... Args>
16473- struct UnaryLambdaTraits<ReturnT ( ClassT::* )( Args... ) const> {
16474- static const bool isValid = false;
16475- };
16476-
16477- template <typename ClassT, typename ReturnT, typename ArgT>
16478- struct UnaryLambdaTraits<ReturnT ( ClassT::* )( ArgT ) const> {
16479- static const bool isValid = true;
16480- using ArgType = std::remove_const_t<std::remove_reference_t<ArgT>>;
16481- using ReturnType = ReturnT;
16482- };
16483-
16484- class TokenStream;
16485-
16486- // Wraps a token coming from a token stream. These may not directly
16487- // correspond to strings as a single string may encode an option +
16488- // its argument if the : or = form is used
16489- enum class TokenType { Option, Argument };
16490- struct Token {
16491- TokenType type;
16492- StringRef token;
16493- };
16494-
16495- // Abstracts iterators into args as a stream of tokens, with option
16496- // arguments uniformly handled
16497- class TokenStream {
16498- using Iterator = std::vector<StringRef>::const_iterator;
16499- Iterator it;
16500- Iterator itEnd;
16501- std::vector<Token> m_tokenBuffer;
16502- void loadBuffer();
16503-
16504- public:
16505- explicit TokenStream( Args const& args );
16506- TokenStream( Iterator it, Iterator itEnd );
16507-
16508- explicit operator bool() const {
16509- return !m_tokenBuffer.empty() || it != itEnd;
16510- }
16511-
16512- size_t count() const {
16513- return m_tokenBuffer.size() + ( itEnd - it );
16514- }
16515-
16516- Token operator*() const {
16517- assert( !m_tokenBuffer.empty() );
16518- return m_tokenBuffer.front();
16519- }
16520-
16521- Token const* operator->() const {
16522- assert( !m_tokenBuffer.empty() );
16523- return &m_tokenBuffer.front();
16524- }
16525-
16526- TokenStream& operator++();
16527- };
16528-
16529- //! Denotes type of a parsing result
16530- enum class ResultType {
16531- Ok, ///< No errors
16532- LogicError, ///< Error in user-specified arguments for
16533- ///< construction
16534- RuntimeError ///< Error in parsing inputs
16535- };
16536-
16537- class ResultBase {
16538- protected:
16539- ResultBase( ResultType type ): m_type( type ) {}
16540- virtual ~ResultBase(); // = default;
16541-
16542-
16543- ResultBase(ResultBase const&) = default;
16544- ResultBase& operator=(ResultBase const&) = default;
16545- ResultBase(ResultBase&&) = default;
16546- ResultBase& operator=(ResultBase&&) = default;
16547-
16548- virtual void enforceOk() const = 0;
16549-
16550- ResultType m_type;
16551- };
16552-
16553- template <typename T>
16554- class ResultValueBase : public ResultBase {
16555- public:
16556- T const& value() const& {
16557- enforceOk();
16558- return m_value;
16559- }
16560- T&& value() && {
16561- enforceOk();
16562- return CATCH_MOVE( m_value );
16563- }
16564-
16565- protected:
16566- ResultValueBase( ResultType type ): ResultBase( type ) {}
16567-
16568- ResultValueBase( ResultValueBase const& other ):
16569- ResultBase( other ) {
16570- if ( m_type == ResultType::Ok )
16571- new ( &m_value ) T( other.m_value );
16572- }
16573- ResultValueBase( ResultValueBase&& other ):
16574- ResultBase( other ) {
16575- if ( m_type == ResultType::Ok )
16576- new ( &m_value ) T( CATCH_MOVE(other.m_value) );
16577- }
16578-
16579-
16580- ResultValueBase( ResultType, T const& value ):
16581- ResultBase( ResultType::Ok ) {
16582- new ( &m_value ) T( value );
16583- }
16584- ResultValueBase( ResultType, T&& value ):
16585- ResultBase( ResultType::Ok ) {
16586- new ( &m_value ) T( CATCH_MOVE(value) );
16587- }
16588-
16589- ResultValueBase& operator=( ResultValueBase const& other ) {
16590- if ( m_type == ResultType::Ok )
16591- m_value.~T();
16592- ResultBase::operator=( other );
16593- if ( m_type == ResultType::Ok )
16594- new ( &m_value ) T( other.m_value );
16595- return *this;
16596- }
16597- ResultValueBase& operator=( ResultValueBase&& other ) {
16598- if ( m_type == ResultType::Ok ) m_value.~T();
16599- ResultBase::operator=( other );
16600- if ( m_type == ResultType::Ok )
16601- new ( &m_value ) T( CATCH_MOVE(other.m_value) );
16602- return *this;
16603- }
16604-
16605-
16606- ~ResultValueBase() override {
16607- if ( m_type == ResultType::Ok )
16608- m_value.~T();
16609- }
16610-
16611- union {
16612- T m_value;
16613- };
16614- };
16615-
16616- template <> class ResultValueBase<void> : public ResultBase {
16617- protected:
16618- using ResultBase::ResultBase;
16619- };
16620-
16621- template <typename T = void>
16622- class BasicResult : public ResultValueBase<T> {
16623- public:
16624- template <typename U>
16625- explicit BasicResult( BasicResult<U> const& other ):
16626- ResultValueBase<T>( other.type() ),
16627- m_errorMessage( other.errorMessage() ) {
16628- assert( type() != ResultType::Ok );
16629- }
16630-
16631- template <typename U>
16632- static auto ok( U&& value ) -> BasicResult {
16633- return { ResultType::Ok, CATCH_FORWARD(value) };
16634- }
16635- static auto ok() -> BasicResult { return { ResultType::Ok }; }
16636- static auto logicError( std::string&& message )
16637- -> BasicResult {
16638- return { ResultType::LogicError, CATCH_MOVE(message) };
16639- }
16640- static auto runtimeError( std::string&& message )
16641- -> BasicResult {
16642- return { ResultType::RuntimeError, CATCH_MOVE(message) };
16643- }
16644-
16645- explicit operator bool() const {
16646- return m_type == ResultType::Ok;
16647- }
16648- auto type() const -> ResultType { return m_type; }
16649- auto errorMessage() const -> std::string const& {
16650- return m_errorMessage;
16651- }
16652-
16653- protected:
16654- void enforceOk() const override {
16655-
16656- // Errors shouldn't reach this point, but if they do
16657- // the actual error message will be in m_errorMessage
16658- assert( m_type != ResultType::LogicError );
16659- assert( m_type != ResultType::RuntimeError );
16660- if ( m_type != ResultType::Ok )
16661- std::abort();
16662- }
16663-
16664- std::string
16665- m_errorMessage; // Only populated if resultType is an error
16666-
16667- BasicResult( ResultType type,
16668- std::string&& message ):
16669- ResultValueBase<T>( type ), m_errorMessage( CATCH_MOVE(message) ) {
16670- assert( m_type != ResultType::Ok );
16671- }
16672-
16673- using ResultValueBase<T>::ResultValueBase;
16674- using ResultBase::m_type;
16675- };
16676-
16677- class ParseState {
16678- public:
16679- ParseState( ParseResultType type,
16680- TokenStream remainingTokens );
16681-
16682- ParseResultType type() const { return m_type; }
16683- TokenStream const& remainingTokens() const& {
16684- return m_remainingTokens;
16685- }
16686- TokenStream&& remainingTokens() && {
16687- return CATCH_MOVE( m_remainingTokens );
16688- }
16689-
16690- private:
16691- ParseResultType m_type;
16692- TokenStream m_remainingTokens;
16693- };
16694-
16695- using Result = BasicResult<void>;
16696- using ParserResult = BasicResult<ParseResultType>;
16697- using InternalParseResult = BasicResult<ParseState>;
16698-
16699- struct HelpColumns {
16700- std::string left;
16701- StringRef descriptions;
16702- };
16703-
16704- template <typename T>
16705- ParserResult convertInto( std::string const& source, T& target ) {
16706- std::stringstream ss( source );
16707- ss >> target;
16708- if ( ss.fail() ) {
16709- return ParserResult::runtimeError(
16710- "Unable to convert '" + source +
16711- "' to destination type" );
16712- } else {
16713- return ParserResult::ok( ParseResultType::Matched );
16714- }
16715- }
16716- ParserResult convertInto( std::string const& source,
16717- std::string& target );
16718- ParserResult convertInto( std::string const& source, bool& target );
16719-
16720-#ifdef CLARA_CONFIG_OPTIONAL_TYPE
16721- template <typename T>
16722- auto convertInto( std::string const& source,
16723- CLARA_CONFIG_OPTIONAL_TYPE<T>& target )
16724- -> ParserResult {
16725- T temp;
16726- auto result = convertInto( source, temp );
16727- if ( result )
16728- target = CATCH_MOVE( temp );
16729- return result;
16730- }
16731-#endif // CLARA_CONFIG_OPTIONAL_TYPE
16732-
16733- struct BoundRef : Catch::Detail::NonCopyable {
16734- virtual ~BoundRef() = default;
16735- virtual bool isContainer() const;
16736- virtual bool isFlag() const;
16737- };
16738- struct BoundValueRefBase : BoundRef {
16739- virtual auto setValue( std::string const& arg )
16740- -> ParserResult = 0;
16741- };
16742- struct BoundFlagRefBase : BoundRef {
16743- virtual auto setFlag( bool flag ) -> ParserResult = 0;
16744- bool isFlag() const override;
16745- };
16746-
16747- template <typename T> struct BoundValueRef : BoundValueRefBase {
16748- T& m_ref;
16749-
16750- explicit BoundValueRef( T& ref ): m_ref( ref ) {}
16751-
16752- ParserResult setValue( std::string const& arg ) override {
16753- return convertInto( arg, m_ref );
16754- }
16755- };
16756-
16757- template <typename T>
16758- struct BoundValueRef<std::vector<T>> : BoundValueRefBase {
16759- std::vector<T>& m_ref;
16760-
16761- explicit BoundValueRef( std::vector<T>& ref ): m_ref( ref ) {}
16762-
16763- auto isContainer() const -> bool override { return true; }
16764-
16765- auto setValue( std::string const& arg )
16766- -> ParserResult override {
16767- T temp;
16768- auto result = convertInto( arg, temp );
16769- if ( result )
16770- m_ref.push_back( temp );
16771- return result;
16772- }
16773- };
16774-
16775- struct BoundFlagRef : BoundFlagRefBase {
16776- bool& m_ref;
16777-
16778- explicit BoundFlagRef( bool& ref ): m_ref( ref ) {}
16779-
16780- ParserResult setFlag( bool flag ) override;
16781- };
16782-
16783- template <typename ReturnType> struct LambdaInvoker {
16784- static_assert(
16785- std::is_same<ReturnType, ParserResult>::value,
16786- "Lambda must return void or clara::ParserResult" );
16787-
16788- template <typename L, typename ArgType>
16789- static auto invoke( L const& lambda, ArgType const& arg )
16790- -> ParserResult {
16791- return lambda( arg );
16792- }
16793- };
16794-
16795- template <> struct LambdaInvoker<void> {
16796- template <typename L, typename ArgType>
16797- static auto invoke( L const& lambda, ArgType const& arg )
16798- -> ParserResult {
16799- lambda( arg );
16800- return ParserResult::ok( ParseResultType::Matched );
16801- }
16802- };
16803-
16804- template <typename ArgType, typename L>
16805- auto invokeLambda( L const& lambda, std::string const& arg )
16806- -> ParserResult {
16807- ArgType temp{};
16808- auto result = convertInto( arg, temp );
16809- return !result ? result
16810- : LambdaInvoker<typename UnaryLambdaTraits<
16811- L>::ReturnType>::invoke( lambda, temp );
16812- }
16813-
16814- template <typename L> struct BoundLambda : BoundValueRefBase {
16815- L m_lambda;
16816-
16817- static_assert(
16818- UnaryLambdaTraits<L>::isValid,
16819- "Supplied lambda must take exactly one argument" );
16820- explicit BoundLambda( L const& lambda ): m_lambda( lambda ) {}
16821-
16822- auto setValue( std::string const& arg )
16823- -> ParserResult override {
16824- return invokeLambda<typename UnaryLambdaTraits<L>::ArgType>(
16825- m_lambda, arg );
16826- }
16827- };
16828-
16829- template <typename L> struct BoundManyLambda : BoundLambda<L> {
16830- explicit BoundManyLambda( L const& lambda ): BoundLambda<L>( lambda ) {}
16831- bool isContainer() const override { return true; }
16832- };
16833-
16834- template <typename L> struct BoundFlagLambda : BoundFlagRefBase {
16835- L m_lambda;
16836-
16837- static_assert(
16838- UnaryLambdaTraits<L>::isValid,
16839- "Supplied lambda must take exactly one argument" );
16840- static_assert(
16841- std::is_same<typename UnaryLambdaTraits<L>::ArgType,
16842- bool>::value,
16843- "flags must be boolean" );
16844-
16845- explicit BoundFlagLambda( L const& lambda ):
16846- m_lambda( lambda ) {}
16847-
16848- auto setFlag( bool flag ) -> ParserResult override {
16849- return LambdaInvoker<typename UnaryLambdaTraits<
16850- L>::ReturnType>::invoke( m_lambda, flag );
16851- }
16852- };
16853-
16854- enum class Optionality { Optional, Required };
16855-
16856- class ParserBase {
16857- public:
16858- virtual ~ParserBase() = default;
16859- virtual auto validate() const -> Result { return Result::ok(); }
16860- virtual auto parse( std::string const& exeName,
16861- TokenStream tokens ) const
16862- -> InternalParseResult = 0;
16863- virtual size_t cardinality() const;
16864-
16865- InternalParseResult parse( Args const& args ) const;
16866- };
16867-
16868- template <typename DerivedT>
16869- class ComposableParserImpl : public ParserBase {
16870- public:
16871- template <typename T>
16872- auto operator|( T const& other ) const -> Parser;
16873- };
16874-
16875- // Common code and state for Args and Opts
16876- template <typename DerivedT>
16877- class ParserRefImpl : public ComposableParserImpl<DerivedT> {
16878- protected:
16879- Optionality m_optionality = Optionality::Optional;
16880- std::shared_ptr<BoundRef> m_ref;
16881- StringRef m_hint;
16882- StringRef m_description;
16883-
16884- explicit ParserRefImpl( std::shared_ptr<BoundRef> const& ref ):
16885- m_ref( ref ) {}
16886-
16887- public:
16888- template <typename LambdaT>
16889- ParserRefImpl( accept_many_t,
16890- LambdaT const& ref,
16891- StringRef hint ):
16892- m_ref( std::make_shared<BoundManyLambda<LambdaT>>( ref ) ),
16893- m_hint( hint ) {}
16894-
16895- template <typename T,
16896- typename = typename std::enable_if_t<
16897- !Detail::is_unary_function_v<T>>>
16898- ParserRefImpl( T& ref, StringRef hint ):
16899- m_ref( std::make_shared<BoundValueRef<T>>( ref ) ),
16900- m_hint( hint ) {}
16901-
16902- template <typename LambdaT,
16903- typename = typename std::enable_if_t<
16904- Detail::is_unary_function_v<LambdaT>>>
16905- ParserRefImpl( LambdaT const& ref, StringRef hint ):
16906- m_ref( std::make_shared<BoundLambda<LambdaT>>( ref ) ),
16907- m_hint( hint ) {}
16908-
16909- DerivedT& operator()( StringRef description ) & {
16910- m_description = description;
16911- return static_cast<DerivedT&>( *this );
16912- }
16913- DerivedT&& operator()( StringRef description ) && {
16914- m_description = description;
16915- return static_cast<DerivedT&&>( *this );
16916- }
16917-
16918- auto optional() -> DerivedT& {
16919- m_optionality = Optionality::Optional;
16920- return static_cast<DerivedT&>( *this );
16921- }
16922-
16923- auto required() -> DerivedT& {
16924- m_optionality = Optionality::Required;
16925- return static_cast<DerivedT&>( *this );
16926- }
16927-
16928- auto isOptional() const -> bool {
16929- return m_optionality == Optionality::Optional;
16930- }
16931-
16932- auto cardinality() const -> size_t override {
16933- if ( m_ref->isContainer() )
16934- return 0;
16935- else
16936- return 1;
16937- }
16938-
16939- StringRef hint() const { return m_hint; }
16940- };
16941-
16942- } // namespace detail
16943-
16944-
16945- // A parser for arguments
16946- class Arg : public Detail::ParserRefImpl<Arg> {
16947- public:
16948- using ParserRefImpl::ParserRefImpl;
16949- using ParserBase::parse;
16950-
16951- Detail::InternalParseResult
16952- parse(std::string const&,
16953- Detail::TokenStream tokens) const override;
16954- };
16955-
16956- // A parser for options
16957- class Opt : public Detail::ParserRefImpl<Opt> {
16958- protected:
16959- std::vector<StringRef> m_optNames;
16960-
16961- public:
16962- template <typename LambdaT>
16963- explicit Opt(LambdaT const& ref) :
16964- ParserRefImpl(
16965- std::make_shared<Detail::BoundFlagLambda<LambdaT>>(ref)) {}
16966-
16967- explicit Opt(bool& ref);
16968-
16969- template <typename LambdaT,
16970- typename = typename std::enable_if_t<
16971- Detail::is_unary_function_v<LambdaT>>>
16972- Opt( LambdaT const& ref, StringRef hint ):
16973- ParserRefImpl( ref, hint ) {}
16974-
16975- template <typename LambdaT>
16976- Opt( accept_many_t, LambdaT const& ref, StringRef hint ):
16977- ParserRefImpl( accept_many, ref, hint ) {}
16978-
16979- template <typename T,
16980- typename = typename std::enable_if_t<
16981- !Detail::is_unary_function_v<T>>>
16982- Opt( T& ref, StringRef hint ):
16983- ParserRefImpl( ref, hint ) {}
16984-
16985- Opt& operator[]( StringRef optName ) & {
16986- m_optNames.push_back(optName);
16987- return *this;
16988- }
16989- Opt&& operator[]( StringRef optName ) && {
16990- m_optNames.push_back( optName );
16991- return CATCH_MOVE(*this);
16992- }
16993-
16994- Detail::HelpColumns getHelpColumns() const;
16995-
16996- bool isMatch(StringRef optToken) const;
16997-
16998- using ParserBase::parse;
16999-
17000- Detail::InternalParseResult
17001- parse(std::string const&,
17002- Detail::TokenStream tokens) const override;
17003-
17004- Detail::Result validate() const override;
17005- };
17006-
17007- // Specifies the name of the executable
17008- class ExeName : public Detail::ComposableParserImpl<ExeName> {
17009- std::shared_ptr<std::string> m_name;
17010- std::shared_ptr<Detail::BoundValueRefBase> m_ref;
17011-
17012- public:
17013- ExeName();
17014- explicit ExeName(std::string& ref);
17015-
17016- template <typename LambdaT>
17017- explicit ExeName(LambdaT const& lambda) : ExeName() {
17018- m_ref = std::make_shared<Detail::BoundLambda<LambdaT>>(lambda);
17019- }
17020-
17021- // The exe name is not parsed out of the normal tokens, but is
17022- // handled specially
17023- Detail::InternalParseResult
17024- parse(std::string const&,
17025- Detail::TokenStream tokens) const override;
17026-
17027- std::string const& name() const { return *m_name; }
17028- Detail::ParserResult set(std::string const& newName);
17029- };
17030-
17031-
17032- // A Combined parser
17033- class Parser : Detail::ParserBase {
17034- mutable ExeName m_exeName;
17035- std::vector<Opt> m_options;
17036- std::vector<Arg> m_args;
17037-
17038- public:
17039-
17040- auto operator|=(ExeName const& exeName) -> Parser& {
17041- m_exeName = exeName;
17042- return *this;
17043- }
17044-
17045- auto operator|=(Arg const& arg) -> Parser& {
17046- m_args.push_back(arg);
17047- return *this;
17048- }
17049-
17050- friend Parser& operator|=( Parser& p, Opt const& opt ) {
17051- p.m_options.push_back( opt );
17052- return p;
17053- }
17054- friend Parser& operator|=( Parser& p, Opt&& opt ) {
17055- p.m_options.push_back( CATCH_MOVE(opt) );
17056- return p;
17057- }
17058-
17059- Parser& operator|=(Parser const& other);
17060-
17061- template <typename T>
17062- friend Parser operator|( Parser const& p, T&& rhs ) {
17063- Parser temp( p );
17064- temp |= rhs;
17065- return temp;
17066- }
17067-
17068- template <typename T>
17069- friend Parser operator|( Parser&& p, T&& rhs ) {
17070- p |= CATCH_FORWARD(rhs);
17071- return CATCH_MOVE(p);
17072- }
17073-
17074- std::vector<Detail::HelpColumns> getHelpColumns() const;
17075-
17076- void writeToStream(std::ostream& os) const;
17077-
17078- friend auto operator<<(std::ostream& os, Parser const& parser)
17079- -> std::ostream& {
17080- parser.writeToStream(os);
17081- return os;
17082- }
17083-
17084- Detail::Result validate() const override;
17085-
17086- using ParserBase::parse;
17087- Detail::InternalParseResult
17088- parse(std::string const& exeName,
17089- Detail::TokenStream tokens) const override;
17090- };
17091-
17092- /**
17093- * Wrapper over argc + argv, assumes that the inputs outlive it
17094- */
17095- class Args {
17096- friend Detail::TokenStream;
17097- StringRef m_exeName;
17098- std::vector<StringRef> m_args;
17099-
17100- public:
17101- Args(int argc, char const* const* argv);
17102- // Helper constructor for testing
17103- Args(std::initializer_list<StringRef> args);
17104-
17105- StringRef exeName() const { return m_exeName; }
17106- };
17107-
17108-
17109- // Convenience wrapper for option parser that specifies the help option
17110- struct Help : Opt {
17111- Help(bool& showHelpFlag);
17112- };
17113-
17114- // Result type for parser operation
17115- using Detail::ParserResult;
17116-
17117- namespace Detail {
17118- template <typename DerivedT>
17119- template <typename T>
17120- Parser
17121- ComposableParserImpl<DerivedT>::operator|(T const& other) const {
17122- return Parser() | static_cast<DerivedT const&>(*this) | other;
17123- }
17124- }
17125-
17126- } // namespace Clara
17127-} // namespace Catch
17128-
17129-#if defined( __clang__ )
17130-# pragma clang diagnostic pop
17131-#endif
17132-
17133-#if defined( __GNUC__ )
17134-# pragma GCC diagnostic pop
17135-#endif
17136-
17137-#endif // CATCH_CLARA_HPP_INCLUDED
17138-
17139-namespace Catch {
17140-
17141- struct ConfigData;
17142-
17143- Clara::Parser makeCommandLineParser( ConfigData& config );
17144-
17145-} // end namespace Catch
17146-
17147-#endif // CATCH_COMMANDLINE_HPP_INCLUDED
17148-
17149-namespace Catch {
17150-
17151- // TODO: Use C++17 `inline` variables
17152- constexpr int UnspecifiedErrorExitCode = 1;
17153- constexpr int NoTestsRunExitCode = 2;
17154- constexpr int UnmatchedTestSpecExitCode = 3;
17155- constexpr int AllTestsSkippedExitCode = 4;
17156- constexpr int InvalidTestSpecExitCode = 5;
17157- constexpr int TestFailureExitCode = 42;
17158-
17159- class Session : Detail::NonCopyable {
17160- public:
17161-
17162- Session();
17163- ~Session();
17164-
17165- void showHelp() const;
17166- void libIdentify();
17167-
17168- int applyCommandLine( int argc, char const * const * argv );
17169- #if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE)
17170- int applyCommandLine( int argc, wchar_t const * const * argv );
17171- #endif
17172-
17173- void useConfigData( ConfigData const& configData );
17174-
17175- template<typename CharT>
17176- int run(int argc, CharT const * const argv[]) {
17177- if (m_startupExceptions)
17178- return 1;
17179- int returnCode = applyCommandLine(argc, argv);
17180- if (returnCode == 0)
17181- returnCode = run();
17182- return returnCode;
17183- }
17184-
17185- int run();
17186-
17187- Clara::Parser const& cli() const;
17188- void cli( Clara::Parser const& newParser );
17189- ConfigData& configData();
17190- Config& config();
17191- private:
17192- int runInternal();
17193-
17194- Clara::Parser m_cli;
17195- ConfigData m_configData;
17196- Detail::unique_ptr<Config> m_config;
17197- bool m_startupExceptions = false;
17198- };
17199-
17200-} // end namespace Catch
17201-
17202-#endif // CATCH_SESSION_HPP_INCLUDED
17203-
17204-
17205-#ifndef CATCH_TAG_ALIAS_HPP_INCLUDED
17206-#define CATCH_TAG_ALIAS_HPP_INCLUDED
17207-
17208-
17209-#include <string>
17210-
17211-namespace Catch {
17212-
17213- struct TagAlias {
17214- TagAlias(std::string const& _tag, SourceLineInfo _lineInfo):
17215- tag(_tag),
17216- lineInfo(_lineInfo)
17217- {}
17218-
17219- std::string tag;
17220- SourceLineInfo lineInfo;
17221- };
17222-
17223-} // end namespace Catch
17224-
17225-#endif // CATCH_TAG_ALIAS_HPP_INCLUDED
17226-
17227-
17228-#ifndef CATCH_TAG_ALIAS_AUTOREGISTRAR_HPP_INCLUDED
17229-#define CATCH_TAG_ALIAS_AUTOREGISTRAR_HPP_INCLUDED
17230-
17231-
17232-namespace Catch {
17233-
17234- struct RegistrarForTagAliases {
17235- RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo );
17236- };
17237-
17238-} // end namespace Catch
17239-
17240-#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \
17241- CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
17242- CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
17243- namespace{ const Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \
17244- CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
17245-
17246-#endif // CATCH_TAG_ALIAS_AUTOREGISTRAR_HPP_INCLUDED
17247-
17248-
17249-#ifndef CATCH_TEMPLATE_TEST_MACROS_HPP_INCLUDED
17250-#define CATCH_TEMPLATE_TEST_MACROS_HPP_INCLUDED
17251-
17252-// We need this suppression to leak, because it took until GCC 10
17253-// for the front end to handle local suppression via _Pragma properly
17254-// inside templates (so `TEMPLATE_TEST_CASE` and co).
17255-// **THIS IS DIFFERENT FOR STANDARD TESTS, WHERE GCC 9 IS SUFFICIENT**
17256-#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && __GNUC__ < 10
17257-#pragma GCC diagnostic ignored "-Wparentheses"
17258-#endif
17259-
17260-
17261-
17262-
17263-#ifndef CATCH_TEST_MACROS_HPP_INCLUDED
17264-#define CATCH_TEST_MACROS_HPP_INCLUDED
17265-
17266-
17267-
17268-#ifndef CATCH_TEST_MACRO_IMPL_HPP_INCLUDED
17269-#define CATCH_TEST_MACRO_IMPL_HPP_INCLUDED
17270-
17271-
17272-
17273-#ifndef CATCH_ASSERTION_HANDLER_HPP_INCLUDED
17274-#define CATCH_ASSERTION_HANDLER_HPP_INCLUDED
17275-
17276-
17277-
17278-#ifndef CATCH_DECOMPOSER_HPP_INCLUDED
17279-#define CATCH_DECOMPOSER_HPP_INCLUDED
17280-
17281-
17282-
17283-#ifndef CATCH_COMPARE_TRAITS_HPP_INCLUDED
17284-#define CATCH_COMPARE_TRAITS_HPP_INCLUDED
17285-
17286-
17287-#include <type_traits>
17288-
17289-namespace Catch {
17290- namespace Detail {
17291-
17292-#if defined( __GNUC__ ) && !defined( __clang__ )
17293-# pragma GCC diagnostic push
17294- // GCC likes to complain about comparing bool with 0, in the decltype()
17295- // that defines the comparable traits below.
17296-# pragma GCC diagnostic ignored "-Wbool-compare"
17297- // "ordered comparison of pointer with integer zero" same as above,
17298- // but it does not have a separate warning flag to suppress
17299-# pragma GCC diagnostic ignored "-Wextra"
17300- // Did you know that comparing floats with `0` directly
17301- // is super-duper dangerous in unevaluated context?
17302-# pragma GCC diagnostic ignored "-Wfloat-equal"
17303-#endif
17304-
17305-#if defined( __clang__ )
17306-# pragma clang diagnostic push
17307- // Did you know that comparing floats with `0` directly
17308- // is super-duper dangerous in unevaluated context?
17309-# pragma clang diagnostic ignored "-Wfloat-equal"
17310-#endif
17311-
17312-#define CATCH_DEFINE_COMPARABLE_TRAIT( id, op ) \
17313- template <typename, typename, typename = void> \
17314- struct is_##id##_comparable : std::false_type {}; \
17315- template <typename T, typename U> \
17316- struct is_##id##_comparable< \
17317- T, \
17318- U, \
17319- void_t<decltype( std::declval<T>() op std::declval<U>() )>> \
17320- : std::true_type {}; \
17321- template <typename, typename = void> \
17322- struct is_##id##_0_comparable : std::false_type {}; \
17323- template <typename T> \
17324- struct is_##id##_0_comparable<T, \
17325- void_t<decltype( std::declval<T>() op 0 )>> \
17326- : std::true_type {};
17327-
17328- // We need all 6 pre-spaceship comparison ops: <, <=, >, >=, ==, !=
17329- CATCH_DEFINE_COMPARABLE_TRAIT( lt, < )
17330- CATCH_DEFINE_COMPARABLE_TRAIT( le, <= )
17331- CATCH_DEFINE_COMPARABLE_TRAIT( gt, > )
17332- CATCH_DEFINE_COMPARABLE_TRAIT( ge, >= )
17333- CATCH_DEFINE_COMPARABLE_TRAIT( eq, == )
17334- CATCH_DEFINE_COMPARABLE_TRAIT( ne, != )
17335-
17336-#undef CATCH_DEFINE_COMPARABLE_TRAIT
17337-
17338-#if defined( __GNUC__ ) && !defined( __clang__ )
17339-# pragma GCC diagnostic pop
17340-#endif
17341-#if defined( __clang__ )
17342-# pragma clang diagnostic pop
17343-#endif
17344-
17345-
17346- } // namespace Detail
17347-} // namespace Catch
17348-
17349-#endif // CATCH_COMPARE_TRAITS_HPP_INCLUDED
17350-
17351-
17352-#ifndef CATCH_LOGICAL_TRAITS_HPP_INCLUDED
17353-#define CATCH_LOGICAL_TRAITS_HPP_INCLUDED
17354-
17355-#include <type_traits>
17356-
17357-namespace Catch {
17358-namespace Detail {
17359-
17360-#if defined( __cpp_lib_logical_traits ) && __cpp_lib_logical_traits >= 201510
17361-
17362- using std::conjunction;
17363- using std::disjunction;
17364- using std::negation;
17365-
17366-#else
17367-
17368- template <class...> struct conjunction : std::true_type {};
17369- template <class B1> struct conjunction<B1> : B1 {};
17370- template <class B1, class... Bn>
17371- struct conjunction<B1, Bn...>
17372- : std::conditional_t<bool( B1::value ), conjunction<Bn...>, B1> {};
17373-
17374- template <class...> struct disjunction : std::false_type {};
17375- template <class B1> struct disjunction<B1> : B1 {};
17376- template <class B1, class... Bn>
17377- struct disjunction<B1, Bn...>
17378- : std::conditional_t<bool( B1::value ), B1, disjunction<Bn...>> {};
17379-
17380- template <class B>
17381- struct negation : std::integral_constant<bool, !bool(B::value)> {};
17382-
17383-#endif
17384-
17385-} // namespace Detail
17386-} // namespace Catch
17387-
17388-#endif // CATCH_LOGICAL_TRAITS_HPP_INCLUDED
17389-
17390-#include <type_traits>
17391-#include <iosfwd>
17392-
17393-/** \file
17394- * Why does decomposing look the way it does:
17395- *
17396- * Conceptually, decomposing is simple. We change `REQUIRE( a == b )` into
17397- * `Decomposer{} <= a == b`, so that `Decomposer{} <= a` is evaluated first,
17398- * and our custom operator is used for `a == b`, because `a` is transformed
17399- * into `ExprLhs<T&>` and then into `BinaryExpr<T&, U&>`.
17400- *
17401- * In practice, decomposing ends up a mess, because we have to support
17402- * various fun things.
17403- *
17404- * 1) Types that are only comparable with literal 0, and they do this by
17405- * comparing against a magic type with pointer constructor and deleted
17406- * other constructors. Example: `REQUIRE((a <=> b) == 0)` in libstdc++
17407- *
17408- * 2) Types that are only comparable with literal 0, and they do this by
17409- * comparing against a magic type with consteval integer constructor.
17410- * Example: `REQUIRE((a <=> b) == 0)` in current MSVC STL.
17411- *
17412- * 3) Types that have no linkage, and so we cannot form a reference to
17413- * them. Example: some implementations of traits.
17414- *
17415- * 4) Starting with C++20, when the compiler sees `a == b`, it also uses
17416- * `b == a` when constructing the overload set. For us this means that
17417- * when the compiler handles `ExprLhs<T> == b`, it also tries to resolve
17418- * the overload set for `b == ExprLhs<T>`.
17419- *
17420- * To accommodate these use cases, decomposer ended up rather complex.
17421- *
17422- * 1) These types are handled by adding SFINAE overloads to our comparison
17423- * operators, checking whether `T == U` are comparable with the given
17424- * operator, and if not, whether T (or U) are comparable with literal 0.
17425- * If yes, the overload compares T (or U) with 0 literal inline in the
17426- * definition.
17427- *
17428- * Note that for extra correctness, we check that the other type is
17429- * either an `int` (literal 0 is captured as `int` by templates), or
17430- * a `long` (some platforms use 0L for `NULL` and we want to support
17431- * that for pointer comparisons).
17432- *
17433- * 2) For these types, `is_foo_comparable<T, int>` is true, but letting
17434- * them fall into the overload that actually does `T == int` causes
17435- * compilation error. Handling them requires that the decomposition
17436- * is `constexpr`, so that P2564R3 applies and the `consteval` from
17437- * their accompanying magic type is propagated through the `constexpr`
17438- * call stack.
17439- *
17440- * However this is not enough to handle these types automatically,
17441- * because our default is to capture types by reference, to avoid
17442- * runtime copies. While these references cannot become dangling,
17443- * they outlive the constexpr context and thus the default capture
17444- * path cannot be actually constexpr.
17445- *
17446- * The solution is to capture these types by value, by explicitly
17447- * specializing `Catch::capture_by_value` for them. Catch2 provides
17448- * specialization for `std::foo_ordering`s, but users can specialize
17449- * the trait for their own types as well.
17450- *
17451- * 3) If a type has no linkage, we also cannot capture it by reference.
17452- * The solution is once again to capture them by value. We handle
17453- * the common cases by using `std::is_arithmetic` and `std::is_enum`
17454- * as the default for `Catch::capture_by_value`, but that is only a
17455- * some-effort heuristic. These combine to capture all possible bitfield
17456- * bases, and also some trait-like types. As with 2), users can
17457- * specialize `capture_by_value` for their own types as needed.
17458- *
17459- * 4) To support C++20 and make the SFINAE on our decomposing operators
17460- * work, the SFINAE has to happen in return type, rather than in
17461- * a template type. This is due to our use of logical type traits
17462- * (`conjunction`/`disjunction`/`negation`), that we use to workaround
17463- * an issue in older (9-) versions of GCC. I still blame C++20 for
17464- * this, because without the comparison order switching, the logical
17465- * traits could still be used in template type.
17466- *
17467- * There are also other side concerns, e.g. supporting both `REQUIRE(a)`
17468- * and `REQUIRE(a == b)`, or making `REQUIRE_THAT(a, IsEqual(b))` slot
17469- * nicely into the same expression handling logic, but these are rather
17470- * straightforward and add only a bit of complexity (e.g. common base
17471- * class for decomposed expressions).
17472- */
17473-
17474-#ifdef _MSC_VER
17475-#pragma warning(push)
17476-#pragma warning(disable:4389) // '==' : signed/unsigned mismatch
17477-#pragma warning(disable:4018) // more "signed/unsigned mismatch"
17478-#pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform)
17479-#pragma warning(disable:4180) // qualifier applied to function type has no meaning
17480-#pragma warning(disable:4800) // Forcing result to true or false
17481-#endif
17482-
17483-#ifdef __clang__
17484-# pragma clang diagnostic push
17485-# pragma clang diagnostic ignored "-Wsign-compare"
17486-# pragma clang diagnostic ignored "-Wnon-virtual-dtor"
17487-#elif defined __GNUC__
17488-# pragma GCC diagnostic push
17489-# pragma GCC diagnostic ignored "-Wsign-compare"
17490-# pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
17491-#endif
17492-
17493-#if defined(CATCH_CPP20_OR_GREATER) && __has_include(<compare>)
17494-# include <compare>
17495-# if defined( __cpp_lib_three_way_comparison ) && \
17496- __cpp_lib_three_way_comparison >= 201907L
17497-# define CATCH_CONFIG_CPP20_COMPARE_OVERLOADS
17498-# endif
17499-#endif
17500-
17501-namespace Catch {
17502-
17503- namespace Detail {
17504- // This was added in C++20, but we require only C++14 for now.
17505- template <typename T>
17506- using RemoveCVRef_t = std::remove_cv_t<std::remove_reference_t<T>>;
17507- }
17508-
17509- // Note: This is about as much as we can currently reasonably support.
17510- // In an ideal world, we could capture by value small trivially
17511- // copyable types, but the actual `std::is_trivially_copyable`
17512- // trait is a huge mess with standard-violating results on
17513- // GCC and Clang, which are unlikely to be fixed soon due to ABI
17514- // concerns.
17515- // `std::is_scalar` also causes issues due to the `is_pointer`
17516- // component, which causes ambiguity issues with (references-to)
17517- // function pointer. If those are resolved, we still need to
17518- // disambiguate the overload set for arrays, through explicit
17519- // overload for references to sized arrays.
17520- template <typename T>
17521- struct capture_by_value
17522- : std::integral_constant<bool,
17523- std::is_arithmetic<T>::value ||
17524- std::is_enum<T>::value> {};
17525-
17526-#if defined( CATCH_CONFIG_CPP20_COMPARE_OVERLOADS )
17527- template <>
17528- struct capture_by_value<std::strong_ordering> : std::true_type {};
17529- template <>
17530- struct capture_by_value<std::weak_ordering> : std::true_type {};
17531- template <>
17532- struct capture_by_value<std::partial_ordering> : std::true_type {};
17533-#endif
17534-
17535- template <typename T>
17536- struct always_false : std::false_type {};
17537-
17538- class ITransientExpression {
17539- bool m_isBinaryExpression;
17540- bool m_result;
17541-
17542- protected:
17543- ~ITransientExpression() = default;
17544-
17545- public:
17546- constexpr auto isBinaryExpression() const -> bool { return m_isBinaryExpression; }
17547- constexpr auto getResult() const -> bool { return m_result; }
17548- //! This function **has** to be overridden by the derived class.
17549- virtual void streamReconstructedExpression( std::ostream& os ) const;
17550-
17551- constexpr ITransientExpression( bool isBinaryExpression, bool result )
17552- : m_isBinaryExpression( isBinaryExpression ),
17553- m_result( result )
17554- {}
17555-
17556- constexpr ITransientExpression( ITransientExpression const& ) = default;
17557- constexpr ITransientExpression& operator=( ITransientExpression const& ) = default;
17558-
17559- friend std::ostream& operator<<(std::ostream& out, ITransientExpression const& expr) {
17560- expr.streamReconstructedExpression(out);
17561- return out;
17562- }
17563- };
17564-
17565- void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs );
17566-
17567- template<typename LhsT, typename RhsT>
17568- class BinaryExpr : public ITransientExpression {
17569- LhsT m_lhs;
17570- StringRef m_op;
17571- RhsT m_rhs;
17572-
17573- void streamReconstructedExpression( std::ostream &os ) const override {
17574- formatReconstructedExpression
17575- ( os, Catch::Detail::stringify( m_lhs ), m_op, Catch::Detail::stringify( m_rhs ) );
17576- }
17577-
17578- public:
17579- constexpr BinaryExpr( bool comparisonResult, LhsT lhs, StringRef op, RhsT rhs )
17580- : ITransientExpression{ true, comparisonResult },
17581- m_lhs( lhs ),
17582- m_op( op ),
17583- m_rhs( rhs )
17584- {}
17585-
17586- template<typename T>
17587- auto operator && ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
17588- static_assert(always_false<T>::value,
17589- "chained comparisons are not supported inside assertions, "
17590- "wrap the expression inside parentheses, or decompose it");
17591- }
17592-
17593- template<typename T>
17594- auto operator || ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
17595- static_assert(always_false<T>::value,
17596- "chained comparisons are not supported inside assertions, "
17597- "wrap the expression inside parentheses, or decompose it");
17598- }
17599-
17600- template<typename T>
17601- auto operator == ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
17602- static_assert(always_false<T>::value,
17603- "chained comparisons are not supported inside assertions, "
17604- "wrap the expression inside parentheses, or decompose it");
17605- }
17606-
17607- template<typename T>
17608- auto operator != ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
17609- static_assert(always_false<T>::value,
17610- "chained comparisons are not supported inside assertions, "
17611- "wrap the expression inside parentheses, or decompose it");
17612- }
17613-
17614- template<typename T>
17615- auto operator > ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
17616- static_assert(always_false<T>::value,
17617- "chained comparisons are not supported inside assertions, "
17618- "wrap the expression inside parentheses, or decompose it");
17619- }
17620-
17621- template<typename T>
17622- auto operator < ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
17623- static_assert(always_false<T>::value,
17624- "chained comparisons are not supported inside assertions, "
17625- "wrap the expression inside parentheses, or decompose it");
17626- }
17627-
17628- template<typename T>
17629- auto operator >= ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
17630- static_assert(always_false<T>::value,
17631- "chained comparisons are not supported inside assertions, "
17632- "wrap the expression inside parentheses, or decompose it");
17633- }
17634-
17635- template<typename T>
17636- auto operator <= ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
17637- static_assert(always_false<T>::value,
17638- "chained comparisons are not supported inside assertions, "
17639- "wrap the expression inside parentheses, or decompose it");
17640- }
17641- };
17642-
17643- template<typename LhsT>
17644- class UnaryExpr : public ITransientExpression {
17645- LhsT m_lhs;
17646-
17647- void streamReconstructedExpression( std::ostream &os ) const override {
17648- os << Catch::Detail::stringify( m_lhs );
17649- }
17650-
17651- public:
17652- explicit constexpr UnaryExpr( LhsT lhs )
17653- : ITransientExpression{ false, static_cast<bool>(lhs) },
17654- m_lhs( lhs )
17655- {}
17656- };
17657-
17658-
17659- template<typename LhsT>
17660- class ExprLhs {
17661- LhsT m_lhs;
17662- public:
17663- explicit constexpr ExprLhs( LhsT lhs ) : m_lhs( lhs ) {}
17664-
17665-#define CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR( id, op ) \
17666- template <typename RhsT> \
17667- constexpr friend auto operator op( ExprLhs&& lhs, RhsT&& rhs ) \
17668- -> std::enable_if_t< \
17669- Detail::conjunction<Detail::is_##id##_comparable<LhsT, RhsT>, \
17670- Detail::negation<capture_by_value< \
17671- Detail::RemoveCVRef_t<RhsT>>>>::value, \
17672- BinaryExpr<LhsT, RhsT const&>> { \
17673- return { \
17674- static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
17675- } \
17676- template <typename RhsT> \
17677- constexpr friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
17678- -> std::enable_if_t< \
17679- Detail::conjunction<Detail::is_##id##_comparable<LhsT, RhsT>, \
17680- capture_by_value<RhsT>>::value, \
17681- BinaryExpr<LhsT, RhsT>> { \
17682- return { \
17683- static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
17684- } \
17685- template <typename RhsT> \
17686- constexpr friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
17687- -> std::enable_if_t< \
17688- Detail::conjunction< \
17689- Detail::negation<Detail::is_##id##_comparable<LhsT, RhsT>>, \
17690- Detail::is_eq_0_comparable<LhsT>, \
17691- /* We allow long because we want `ptr op NULL` to be accepted */ \
17692- Detail::disjunction<std::is_same<RhsT, int>, \
17693- std::is_same<RhsT, long>>>::value, \
17694- BinaryExpr<LhsT, RhsT>> { \
17695- if ( rhs != 0 ) { throw_test_failure_exception(); } \
17696- return { \
17697- static_cast<bool>( lhs.m_lhs op 0 ), lhs.m_lhs, #op##_sr, rhs }; \
17698- } \
17699- template <typename RhsT> \
17700- constexpr friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
17701- -> std::enable_if_t< \
17702- Detail::conjunction< \
17703- Detail::negation<Detail::is_##id##_comparable<LhsT, RhsT>>, \
17704- Detail::is_eq_0_comparable<RhsT>, \
17705- /* We allow long because we want `ptr op NULL` to be accepted */ \
17706- Detail::disjunction<std::is_same<LhsT, int>, \
17707- std::is_same<LhsT, long>>>::value, \
17708- BinaryExpr<LhsT, RhsT>> { \
17709- if ( lhs.m_lhs != 0 ) { throw_test_failure_exception(); } \
17710- return { static_cast<bool>( 0 op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
17711- }
17712-
17713- CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR( eq, == )
17714- CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR( ne, != )
17715-
17716- #undef CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR
17717-
17718-
17719-#define CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR( id, op ) \
17720- template <typename RhsT> \
17721- constexpr friend auto operator op( ExprLhs&& lhs, RhsT&& rhs ) \
17722- -> std::enable_if_t< \
17723- Detail::conjunction<Detail::is_##id##_comparable<LhsT, RhsT>, \
17724- Detail::negation<capture_by_value< \
17725- Detail::RemoveCVRef_t<RhsT>>>>::value, \
17726- BinaryExpr<LhsT, RhsT const&>> { \
17727- return { \
17728- static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
17729- } \
17730- template <typename RhsT> \
17731- constexpr friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
17732- -> std::enable_if_t< \
17733- Detail::conjunction<Detail::is_##id##_comparable<LhsT, RhsT>, \
17734- capture_by_value<RhsT>>::value, \
17735- BinaryExpr<LhsT, RhsT>> { \
17736- return { \
17737- static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
17738- } \
17739- template <typename RhsT> \
17740- constexpr friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
17741- -> std::enable_if_t< \
17742- Detail::conjunction< \
17743- Detail::negation<Detail::is_##id##_comparable<LhsT, RhsT>>, \
17744- Detail::is_##id##_0_comparable<LhsT>, \
17745- std::is_same<RhsT, int>>::value, \
17746- BinaryExpr<LhsT, RhsT>> { \
17747- if ( rhs != 0 ) { throw_test_failure_exception(); } \
17748- return { \
17749- static_cast<bool>( lhs.m_lhs op 0 ), lhs.m_lhs, #op##_sr, rhs }; \
17750- } \
17751- template <typename RhsT> \
17752- constexpr friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
17753- -> std::enable_if_t< \
17754- Detail::conjunction< \
17755- Detail::negation<Detail::is_##id##_comparable<LhsT, RhsT>>, \
17756- Detail::is_##id##_0_comparable<RhsT>, \
17757- std::is_same<LhsT, int>>::value, \
17758- BinaryExpr<LhsT, RhsT>> { \
17759- if ( lhs.m_lhs != 0 ) { throw_test_failure_exception(); } \
17760- return { static_cast<bool>( 0 op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
17761- }
17762-
17763- CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR( lt, < )
17764- CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR( le, <= )
17765- CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR( gt, > )
17766- CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR( ge, >= )
17767-
17768- #undef CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR
17769-
17770-
17771-#define CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR( op ) \
17772- template <typename RhsT> \
17773- constexpr friend auto operator op( ExprLhs&& lhs, RhsT&& rhs ) \
17774- -> std::enable_if_t< \
17775- !capture_by_value<Detail::RemoveCVRef_t<RhsT>>::value, \
17776- BinaryExpr<LhsT, RhsT const&>> { \
17777- return { \
17778- static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
17779- } \
17780- template <typename RhsT> \
17781- constexpr friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
17782- -> std::enable_if_t<capture_by_value<RhsT>::value, \
17783- BinaryExpr<LhsT, RhsT>> { \
17784- return { \
17785- static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
17786- }
17787-
17788- CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR(|)
17789- CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR(&)
17790- CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR(^)
17791-
17792- #undef CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR
17793-
17794- template<typename RhsT>
17795- friend auto operator && ( ExprLhs &&, RhsT && ) -> BinaryExpr<LhsT, RhsT const&> {
17796- static_assert(always_false<RhsT>::value,
17797- "operator&& is not supported inside assertions, "
17798- "wrap the expression inside parentheses, or decompose it");
17799- }
17800-
17801- template<typename RhsT>
17802- friend auto operator || ( ExprLhs &&, RhsT && ) -> BinaryExpr<LhsT, RhsT const&> {
17803- static_assert(always_false<RhsT>::value,
17804- "operator|| is not supported inside assertions, "
17805- "wrap the expression inside parentheses, or decompose it");
17806- }
17807-
17808- constexpr auto makeUnaryExpr() const -> UnaryExpr<LhsT> {
17809- return UnaryExpr<LhsT>{ m_lhs };
17810- }
17811- };
17812-
17813- struct Decomposer {
17814- template <typename T,
17815- std::enable_if_t<!capture_by_value<Detail::RemoveCVRef_t<T>>::value,
17816- int> = 0>
17817- constexpr friend auto operator <= ( Decomposer &&, T && lhs ) -> ExprLhs<T const&> {
17818- return ExprLhs<const T&>{ lhs };
17819- }
17820-
17821- template <typename T,
17822- std::enable_if_t<capture_by_value<T>::value, int> = 0>
17823- constexpr friend auto operator <= ( Decomposer &&, T value ) -> ExprLhs<T> {
17824- return ExprLhs<T>{ value };
17825- }
17826- };
17827-
17828-} // end namespace Catch
17829-
17830-#ifdef _MSC_VER
17831-#pragma warning(pop)
17832-#endif
17833-#ifdef __clang__
17834-# pragma clang diagnostic pop
17835-#elif defined __GNUC__
17836-# pragma GCC diagnostic pop
17837-#endif
17838-
17839-#endif // CATCH_DECOMPOSER_HPP_INCLUDED
17840-
17841-#include <string>
17842-
17843-namespace Catch {
17844-
17845- struct AssertionReaction {
17846- bool shouldDebugBreak = false;
17847- bool shouldThrow = false;
17848- bool shouldSkip = false;
17849- };
17850-
17851- class AssertionHandler {
17852- AssertionInfo m_assertionInfo;
17853- AssertionReaction m_reaction;
17854- bool m_completed = false;
17855- IResultCapture& m_resultCapture;
17856-
17857- public:
17858- AssertionHandler
17859- ( StringRef macroName,
17860- SourceLineInfo const& lineInfo,
17861- StringRef capturedExpression,
17862- ResultDisposition::Flags resultDisposition );
17863- ~AssertionHandler() {
17864- if ( !m_completed ) {
17865- m_resultCapture.handleIncomplete( m_assertionInfo );
17866- }
17867- }
17868-
17869-
17870- template<typename T>
17871- constexpr void handleExpr( ExprLhs<T> const& expr ) {
17872- handleExpr( expr.makeUnaryExpr() );
17873- }
17874- void handleExpr( ITransientExpression const& expr );
17875-
17876- void handleMessage(ResultWas::OfType resultType, std::string&& message);
17877-
17878- void handleExceptionThrownAsExpected();
17879- void handleUnexpectedExceptionNotThrown();
17880- void handleExceptionNotThrownAsExpected();
17881- void handleThrowingCallSkipped();
17882- void handleUnexpectedInflightException();
17883-
17884- void complete();
17885-
17886- // query
17887- auto allowThrows() const -> bool;
17888- };
17889-
17890- void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str );
17891-
17892-} // namespace Catch
17893-
17894-#endif // CATCH_ASSERTION_HANDLER_HPP_INCLUDED
17895-
17896-
17897-#ifndef CATCH_PREPROCESSOR_INTERNAL_STRINGIFY_HPP_INCLUDED
17898-#define CATCH_PREPROCESSOR_INTERNAL_STRINGIFY_HPP_INCLUDED
17899-
17900-
17901-#if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION)
17902- #define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__##_catch_sr
17903-#else
17904- #define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION"_catch_sr
17905-#endif
17906-
17907-#endif // CATCH_PREPROCESSOR_INTERNAL_STRINGIFY_HPP_INCLUDED
17908-
17909-// We need this suppression to leak, because it took until GCC 10
17910-// for the front end to handle local suppression via _Pragma properly
17911-#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && __GNUC__ <= 9
17912- #pragma GCC diagnostic ignored "-Wparentheses"
17913-#endif
17914-
17915-#if !defined(CATCH_CONFIG_DISABLE)
17916-
17917-#if defined(CATCH_CONFIG_FAST_COMPILE) || defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
17918-
17919-///////////////////////////////////////////////////////////////////////////////
17920-// Another way to speed-up compilation is to omit local try-catch for REQUIRE*
17921-// macros.
17922-#define INTERNAL_CATCH_TRY
17923-#define INTERNAL_CATCH_CATCH( capturer )
17924-
17925-#else // CATCH_CONFIG_FAST_COMPILE
17926-
17927-#define INTERNAL_CATCH_TRY try
17928-#define INTERNAL_CATCH_CATCH( handler ) catch(...) { (handler).handleUnexpectedInflightException(); }
17929-
17930-#endif
17931-
17932-///////////////////////////////////////////////////////////////////////////////
17933-#define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \
17934- do { /* NOLINT(bugprone-infinite-loop) */ \
17935- /* The expression should not be evaluated, but warnings should hopefully be checked */ \
17936- CATCH_INTERNAL_IGNORE_BUT_WARN(__VA_ARGS__); \
17937- Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
17938- INTERNAL_CATCH_TRY { \
17939- CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
17940- CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
17941- catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); /* NOLINT(bugprone-chained-comparison) */ \
17942- CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
17943- } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
17944- catchAssertionHandler.complete(); \
17945- } 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
17946- // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&.
17947-
17948-///////////////////////////////////////////////////////////////////////////////
17949-#define INTERNAL_CATCH_IF( macroName, resultDisposition, ... ) \
17950- INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \
17951- if( Catch::getResultCapture().lastAssertionPassed() )
17952-
17953-///////////////////////////////////////////////////////////////////////////////
17954-#define INTERNAL_CATCH_ELSE( macroName, resultDisposition, ... ) \
17955- INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \
17956- if( !Catch::getResultCapture().lastAssertionPassed() )
17957-
17958-///////////////////////////////////////////////////////////////////////////////
17959-#define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \
17960- do { \
17961- Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
17962- try { \
17963- CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
17964- CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \
17965- static_cast<void>(__VA_ARGS__); \
17966- CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
17967- catchAssertionHandler.handleExceptionNotThrownAsExpected(); \
17968- } \
17969- catch( ... ) { \
17970- catchAssertionHandler.handleUnexpectedInflightException(); \
17971- } \
17972- catchAssertionHandler.complete(); \
17973- } while( false )
17974-
17975-///////////////////////////////////////////////////////////////////////////////
17976-#define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \
17977- do { \
17978- Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition); \
17979- if( catchAssertionHandler.allowThrows() ) \
17980- try { \
17981- CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
17982- CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT \
17983- CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \
17984- static_cast<void>(__VA_ARGS__); \
17985- CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
17986- catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
17987- } \
17988- catch( ... ) { \
17989- catchAssertionHandler.handleExceptionThrownAsExpected(); \
17990- } \
17991- else \
17992- catchAssertionHandler.handleThrowingCallSkipped(); \
17993- catchAssertionHandler.complete(); \
17994- } while( false )
17995-
17996-///////////////////////////////////////////////////////////////////////////////
17997-#define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \
17998- do { \
17999- Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \
18000- if( catchAssertionHandler.allowThrows() ) \
18001- try { \
18002- CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
18003- CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT \
18004- CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \
18005- static_cast<void>(expr); \
18006- CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
18007- catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
18008- } \
18009- catch( exceptionType const& ) { \
18010- catchAssertionHandler.handleExceptionThrownAsExpected(); \
18011- } \
18012- catch( ... ) { \
18013- catchAssertionHandler.handleUnexpectedInflightException(); \
18014- } \
18015- else \
18016- catchAssertionHandler.handleThrowingCallSkipped(); \
18017- catchAssertionHandler.complete(); \
18018- } while( false )
18019-
18020-
18021-
18022-///////////////////////////////////////////////////////////////////////////////
18023-// Although this is matcher-based, it can be used with just a string
18024-#define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \
18025- do { \
18026- Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
18027- if( catchAssertionHandler.allowThrows() ) \
18028- try { \
18029- CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
18030- CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT \
18031- CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \
18032- static_cast<void>(__VA_ARGS__); \
18033- CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
18034- catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
18035- } \
18036- catch( ... ) { \
18037- Catch::handleExceptionMatchExpr( catchAssertionHandler, matcher ); \
18038- } \
18039- else \
18040- catchAssertionHandler.handleThrowingCallSkipped(); \
18041- catchAssertionHandler.complete(); \
18042- } while( false )
18043-
18044-#endif // CATCH_CONFIG_DISABLE
18045-
18046-#endif // CATCH_TEST_MACRO_IMPL_HPP_INCLUDED
18047-
18048-
18049-#ifndef CATCH_SECTION_HPP_INCLUDED
18050-#define CATCH_SECTION_HPP_INCLUDED
18051-
18052-
18053-
18054-
18055-/** \file
18056- * Wrapper for the STATIC_ANALYSIS_SUPPORT configuration option
18057- *
18058- * Some of Catch2's macros can be defined differently to work better with
18059- * static analysis tools, like clang-tidy or coverity.
18060- * Currently the main use case is to show that `SECTION`s are executed
18061- * exclusively, and not all in one run of a `TEST_CASE`.
18062- */
18063-
18064-#ifndef CATCH_CONFIG_STATIC_ANALYSIS_SUPPORT_HPP_INCLUDED
18065-#define CATCH_CONFIG_STATIC_ANALYSIS_SUPPORT_HPP_INCLUDED
18066-
18067-
18068-#if defined(__clang_analyzer__) || defined(__COVERITY__)
18069- #define CATCH_INTERNAL_CONFIG_STATIC_ANALYSIS_SUPPORT
18070-#endif
18071-
18072-#if defined( CATCH_INTERNAL_CONFIG_STATIC_ANALYSIS_SUPPORT ) && \
18073- !defined( CATCH_CONFIG_NO_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT ) && \
18074- !defined( CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT )
18075-# define CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT
18076-#endif
18077-
18078-
18079-#endif // CATCH_CONFIG_STATIC_ANALYSIS_SUPPORT_HPP_INCLUDED
18080-
18081-
18082-#ifndef CATCH_TIMER_HPP_INCLUDED
18083-#define CATCH_TIMER_HPP_INCLUDED
18084-
18085-#include <cstdint>
18086-
18087-namespace Catch {
18088-
18089- class Timer {
18090- uint64_t m_nanoseconds = 0;
18091- public:
18092- void start();
18093- auto getElapsedNanoseconds() const -> uint64_t;
18094- auto getElapsedMicroseconds() const -> uint64_t;
18095- auto getElapsedMilliseconds() const -> unsigned int;
18096- auto getElapsedSeconds() const -> double;
18097- };
18098-
18099-} // namespace Catch
18100-
18101-#endif // CATCH_TIMER_HPP_INCLUDED
18102-
18103-namespace Catch {
18104-
18105- class Section : Detail::NonCopyable {
18106- public:
18107- Section( SectionInfo&& info );
18108- Section( SourceLineInfo const& _lineInfo,
18109- StringRef _name,
18110- const char* const = nullptr );
18111- ~Section();
18112-
18113- // This indicates whether the section should be executed or not
18114- explicit operator bool() const;
18115-
18116- private:
18117- SectionInfo m_info;
18118-
18119- Counts m_assertions;
18120- bool m_sectionIncluded;
18121- Timer m_timer;
18122- };
18123-
18124-} // end namespace Catch
18125-
18126-#if !defined(CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT)
18127-# define INTERNAL_CATCH_SECTION( ... ) \
18128- CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
18129- CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
18130- if ( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( \
18131- catch_internal_Section ) = \
18132- Catch::Section( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \
18133- CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
18134-
18135-# define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \
18136- CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
18137- CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
18138- if ( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( \
18139- catch_internal_Section ) = \
18140- Catch::SectionInfo( \
18141- CATCH_INTERNAL_LINEINFO, \
18142- ( Catch::ReusableStringStream() << __VA_ARGS__ ) \
18143- .str() ) ) \
18144- CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
18145-
18146-#else
18147-
18148-// These section definitions imply that at most one section at one level
18149-// will be entered (because only one section's __LINE__ can be equal to
18150-// the dummy `catchInternalSectionHint` variable from `TEST_CASE`).
18151-
18152-namespace Catch {
18153- namespace Detail {
18154- // Intentionally without linkage, as it should only be used as a dummy
18155- // symbol for static analysis.
18156- // The arguments are used as a dummy for checking warnings in the passed
18157- // expressions.
18158- int GetNewSectionHint( StringRef, const char* const = nullptr );
18159- } // namespace Detail
18160-} // namespace Catch
18161-
18162-
18163-# define INTERNAL_CATCH_SECTION( ... ) \
18164- CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
18165- CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
18166- CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \
18167- if ( [[maybe_unused]] const int catchInternalPreviousSectionHint = \
18168- catchInternalSectionHint, \
18169- catchInternalSectionHint = \
18170- Catch::Detail::GetNewSectionHint(__VA_ARGS__); \
18171- catchInternalPreviousSectionHint == __LINE__ ) \
18172- CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
18173-
18174-# define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \
18175- CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
18176- CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
18177- CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \
18178- if ( [[maybe_unused]] const int catchInternalPreviousSectionHint = \
18179- catchInternalSectionHint, \
18180- catchInternalSectionHint = Catch::Detail::GetNewSectionHint( \
18181- ( Catch::ReusableStringStream() << __VA_ARGS__ ).str()); \
18182- catchInternalPreviousSectionHint == __LINE__ ) \
18183- CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
18184-
18185-#endif
18186-
18187-
18188-#endif // CATCH_SECTION_HPP_INCLUDED
18189-
18190-
18191-#ifndef CATCH_TEST_REGISTRY_HPP_INCLUDED
18192-#define CATCH_TEST_REGISTRY_HPP_INCLUDED
18193-
18194-
18195-
18196-#ifndef CATCH_INTERFACES_TEST_INVOKER_HPP_INCLUDED
18197-#define CATCH_INTERFACES_TEST_INVOKER_HPP_INCLUDED
18198-
18199-namespace Catch {
18200-
18201- class ITestInvoker {
18202- public:
18203- virtual void prepareTestCase();
18204- virtual void tearDownTestCase();
18205- virtual void invoke() const = 0;
18206- virtual ~ITestInvoker(); // = default
18207- };
18208-
18209-} // namespace Catch
18210-
18211-#endif // CATCH_INTERFACES_TEST_INVOKER_HPP_INCLUDED
18212-
18213-
18214-#ifndef CATCH_PREPROCESSOR_REMOVE_PARENS_HPP_INCLUDED
18215-#define CATCH_PREPROCESSOR_REMOVE_PARENS_HPP_INCLUDED
18216-
18217-#define INTERNAL_CATCH_EXPAND1( param ) INTERNAL_CATCH_EXPAND2( param )
18218-#define INTERNAL_CATCH_EXPAND2( ... ) INTERNAL_CATCH_NO##__VA_ARGS__
18219-#define INTERNAL_CATCH_DEF( ... ) INTERNAL_CATCH_DEF __VA_ARGS__
18220-#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF
18221-
18222-#define INTERNAL_CATCH_REMOVE_PARENS( ... ) \
18223- INTERNAL_CATCH_EXPAND1( INTERNAL_CATCH_DEF __VA_ARGS__ )
18224-
18225-#endif // CATCH_PREPROCESSOR_REMOVE_PARENS_HPP_INCLUDED
18226-
18227-// GCC 5 and older do not properly handle disabling unused-variable warning
18228-// with a _Pragma. This means that we have to leak the suppression to the
18229-// user code as well :-(
18230-#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ <= 5
18231-#pragma GCC diagnostic ignored "-Wunused-variable"
18232-#endif
18233-
18234-
18235-
18236-namespace Catch {
18237-
18238-template<typename C>
18239-class TestInvokerAsMethod : public ITestInvoker {
18240- void (C::*m_testAsMethod)();
18241-public:
18242- constexpr TestInvokerAsMethod( void ( C::*testAsMethod )() ) noexcept:
18243- m_testAsMethod( testAsMethod ) {}
18244-
18245- void invoke() const override {
18246- C obj;
18247- (obj.*m_testAsMethod)();
18248- }
18249-};
18250-
18251-Detail::unique_ptr<ITestInvoker> makeTestInvoker( void(*testAsFunction)() );
18252-
18253-template<typename C>
18254-Detail::unique_ptr<ITestInvoker> makeTestInvoker( void (C::*testAsMethod)() ) {
18255- return Detail::make_unique<TestInvokerAsMethod<C>>( testAsMethod );
18256-}
18257-
18258-template <typename C>
18259-class TestInvokerFixture : public ITestInvoker {
18260- void ( C::*m_testAsMethod )() const;
18261- Detail::unique_ptr<C> m_fixture = nullptr;
18262-
18263-public:
18264- constexpr TestInvokerFixture( void ( C::*testAsMethod )() const ) noexcept:
18265- m_testAsMethod( testAsMethod ) {}
18266-
18267- void prepareTestCase() override {
18268- m_fixture = Detail::make_unique<C>();
18269- }
18270-
18271- void tearDownTestCase() override {
18272- m_fixture.reset();
18273- }
18274-
18275- void invoke() const override {
18276- auto* f = m_fixture.get();
18277- ( f->*m_testAsMethod )();
18278- }
18279-};
18280-
18281-template<typename C>
18282-Detail::unique_ptr<ITestInvoker> makeTestInvokerFixture( void ( C::*testAsMethod )() const ) {
18283- return Detail::make_unique<TestInvokerFixture<C>>( testAsMethod );
18284-}
18285-
18286-struct NameAndTags {
18287- constexpr NameAndTags( StringRef name_ = StringRef(),
18288- StringRef tags_ = StringRef() ) noexcept:
18289- name( name_ ), tags( tags_ ) {}
18290- StringRef name;
18291- StringRef tags;
18292-};
18293-
18294-struct AutoReg : Detail::NonCopyable {
18295- AutoReg( Detail::unique_ptr<ITestInvoker> invoker, SourceLineInfo const& lineInfo, StringRef classOrMethod, NameAndTags const& nameAndTags ) noexcept;
18296-};
18297-
18298-} // end namespace Catch
18299-
18300-#if defined(CATCH_CONFIG_DISABLE)
18301- #define INTERNAL_CATCH_TESTCASE_NO_REGISTRATION( TestName, ... ) \
18302- static inline void TestName()
18303- #define INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... ) \
18304- namespace{ \
18305- struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \
18306- void test(); \
18307- }; \
18308- } \
18309- void TestName::test()
18310-#endif
18311-
18312-
18313-#if !defined(CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT)
18314-
18315- ///////////////////////////////////////////////////////////////////////////////
18316- #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \
18317- static void TestName(); \
18318- CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
18319- CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
18320- CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
18321- namespace{ const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \
18322- CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
18323- static void TestName()
18324- #define INTERNAL_CATCH_TESTCASE( ... ) \
18325- INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), __VA_ARGS__ )
18326-
18327-#else // ^^ !CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT | vv CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT
18328-
18329-
18330-// Dummy registrator for the dumy test case macros
18331-namespace Catch {
18332- namespace Detail {
18333- struct DummyUse {
18334- DummyUse( void ( * )( int ), Catch::NameAndTags const& );
18335- };
18336- } // namespace Detail
18337-} // namespace Catch
18338-
18339-// Note that both the presence of the argument and its exact name are
18340-// necessary for the section support.
18341-
18342-// We provide a shadowed variable so that a `SECTION` inside non-`TEST_CASE`
18343-// tests can compile. The redefined `TEST_CASE` shadows this with param.
18344-static int catchInternalSectionHint = 0;
18345-
18346-# define INTERNAL_CATCH_TESTCASE2( fname, ... ) \
18347- static void fname( int ); \
18348- CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
18349- CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
18350- CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
18351- static const Catch::Detail::DummyUse INTERNAL_CATCH_UNIQUE_NAME( \
18352- dummyUser )( &(fname), Catch::NameAndTags{ __VA_ARGS__ } ); \
18353- CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \
18354- static void fname( [[maybe_unused]] int catchInternalSectionHint ) \
18355- CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
18356-# define INTERNAL_CATCH_TESTCASE( ... ) \
18357- INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( dummyFunction ), __VA_ARGS__ )
18358-
18359-
18360-#endif // CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT
18361-
18362- ///////////////////////////////////////////////////////////////////////////////
18363- #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\
18364- CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
18365- CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
18366- CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
18367- namespace{ \
18368- struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \
18369- void test(); \
18370- }; \
18371- const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( \
18372- Catch::makeTestInvoker( &TestName::test ), \
18373- CATCH_INTERNAL_LINEINFO, \
18374- #ClassName##_catch_sr, \
18375- Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \
18376- } \
18377- CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
18378- void TestName::test()
18379- #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \
18380- INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), ClassName, __VA_ARGS__ )
18381-
18382- ///////////////////////////////////////////////////////////////////////////////
18383- #define INTERNAL_CATCH_TEST_CASE_PERSISTENT_FIXTURE2( TestName, ClassName, ... ) \
18384- CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
18385- CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
18386- CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
18387- namespace { \
18388- struct TestName : INTERNAL_CATCH_REMOVE_PARENS( ClassName ) { \
18389- void test() const; \
18390- }; \
18391- const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( \
18392- Catch::makeTestInvokerFixture( &TestName::test ), \
18393- CATCH_INTERNAL_LINEINFO, \
18394- #ClassName##_catch_sr, \
18395- Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \
18396- } \
18397- CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
18398- void TestName::test() const
18399- #define INTERNAL_CATCH_TEST_CASE_PERSISTENT_FIXTURE( ClassName, ... ) \
18400- INTERNAL_CATCH_TEST_CASE_PERSISTENT_FIXTURE2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), ClassName, __VA_ARGS__ )
18401-
18402-
18403- ///////////////////////////////////////////////////////////////////////////////
18404- #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \
18405- CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
18406- CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
18407- CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
18408- namespace { \
18409- const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( \
18410- Catch::makeTestInvoker( &QualifiedMethod ), \
18411- CATCH_INTERNAL_LINEINFO, \
18412- "&" #QualifiedMethod##_catch_sr, \
18413- Catch::NameAndTags{ __VA_ARGS__ } ); \
18414- } /* NOLINT */ \
18415- CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
18416-
18417-
18418- ///////////////////////////////////////////////////////////////////////////////
18419- #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \
18420- do { \
18421- CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
18422- CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
18423- CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
18424- Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \
18425- CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
18426- } while(false)
18427-
18428-
18429-#endif // CATCH_TEST_REGISTRY_HPP_INCLUDED
18430-
18431-
18432-#ifndef CATCH_UNREACHABLE_HPP_INCLUDED
18433-#define CATCH_UNREACHABLE_HPP_INCLUDED
18434-
18435-/**\file
18436- * Polyfill `std::unreachable`
18437- *
18438- * We need something like `std::unreachable` to tell the compiler that
18439- * some macros, e.g. `FAIL` or `SKIP`, do not continue execution in normal
18440- * manner, and should handle it as such, e.g. not warn if there is no return
18441- * from non-void function after a `FAIL` or `SKIP`.
18442- */
18443-
18444-#include <exception>
18445-
18446-#if defined( __cpp_lib_unreachable ) && __cpp_lib_unreachable > 202202L
18447-# include <utility>
18448-namespace Catch {
18449- namespace Detail {
18450- using Unreachable = std::unreachable;
18451- }
18452-} // namespace Catch
18453-
18454-#else // vv If we do not have std::unreachable, we implement something similar
18455-
18456-namespace Catch {
18457- namespace Detail {
18458-
18459- [[noreturn]]
18460- inline void Unreachable() noexcept {
18461-# if defined( NDEBUG )
18462-# if defined( _MSC_VER ) && !defined( __clang__ )
18463- __assume( false );
18464-# elif defined( __GNUC__ )
18465- __builtin_unreachable();
18466-# else // vv platform without known optimization hint
18467- std::terminate();
18468-# endif
18469-# else // ^^ NDEBUG
18470- // For non-release builds, we prefer termination on bug over UB
18471- std::terminate();
18472-# endif //
18473- }
18474-
18475- } // namespace Detail
18476-} // end namespace Catch
18477-
18478-#endif
18479-
18480-#endif // CATCH_UNREACHABLE_HPP_INCLUDED
18481-
18482-
18483-// All of our user-facing macros support configuration toggle, that
18484-// forces them to be defined prefixed with CATCH_. We also like to
18485-// support another toggle that can minimize (disable) their implementation.
18486-// Given this, we have 4 different configuration options below
18487-
18488-#if defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE)
18489-
18490- #define CATCH_REQUIRE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ )
18491- #define CATCH_REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
18492-
18493- #define CATCH_REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ )
18494- #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr )
18495- #define CATCH_REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ )
18496-
18497- #define CATCH_CHECK( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
18498- #define CATCH_CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
18499- #define CATCH_CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CATCH_CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
18500- #define CATCH_CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
18501- #define CATCH_CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
18502-
18503- #define CATCH_CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
18504- #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr )
18505- #define CATCH_CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
18506-
18507- #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
18508- #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
18509- #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
18510- #define CATCH_TEST_CASE_PERSISTENT_FIXTURE( className, ... ) INTERNAL_CATCH_TEST_CASE_PERSISTENT_FIXTURE( className, __VA_ARGS__ )
18511- #define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
18512- #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
18513- #define CATCH_DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ )
18514- #define CATCH_FAIL( ... ) do { \
18515- INTERNAL_CATCH_MSG("CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ); \
18516- Catch::Detail::Unreachable(); \
18517- } while ( false )
18518- #define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
18519- #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
18520- #define CATCH_SKIP( ... ) do { \
18521- INTERNAL_CATCH_MSG( "CATCH_SKIP", Catch::ResultWas::ExplicitSkip, Catch::ResultDisposition::Normal, __VA_ARGS__ ); \
18522- Catch::Detail::Unreachable(); \
18523- } while (false)
18524-
18525-
18526- #if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE)
18527- #define CATCH_STATIC_REQUIRE( ... ) static_assert( __VA_ARGS__ , #__VA_ARGS__ ); CATCH_SUCCEED( #__VA_ARGS__ )
18528- #define CATCH_STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); CATCH_SUCCEED( #__VA_ARGS__ )
18529- #define CATCH_STATIC_CHECK( ... ) static_assert( __VA_ARGS__ , #__VA_ARGS__ ); CATCH_SUCCEED( #__VA_ARGS__ )
18530- #define CATCH_STATIC_CHECK_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); CATCH_SUCCEED( #__VA_ARGS__ )
18531- #else
18532- #define CATCH_STATIC_REQUIRE( ... ) CATCH_REQUIRE( __VA_ARGS__ )
18533- #define CATCH_STATIC_REQUIRE_FALSE( ... ) CATCH_REQUIRE_FALSE( __VA_ARGS__ )
18534- #define CATCH_STATIC_CHECK( ... ) CATCH_CHECK( __VA_ARGS__ )
18535- #define CATCH_STATIC_CHECK_FALSE( ... ) CATCH_CHECK_FALSE( __VA_ARGS__ )
18536- #endif
18537-
18538-
18539- // "BDD-style" convenience wrappers
18540- #define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ )
18541- #define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
18542- #define CATCH_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc )
18543- #define CATCH_AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc )
18544- #define CATCH_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc )
18545- #define CATCH_AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc )
18546- #define CATCH_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc )
18547- #define CATCH_AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc )
18548-
18549-#elif defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE) // ^^ prefixed, implemented | vv prefixed, disabled
18550-
18551- #define CATCH_REQUIRE( ... ) (void)(0)
18552- #define CATCH_REQUIRE_FALSE( ... ) (void)(0)
18553-
18554- #define CATCH_REQUIRE_THROWS( ... ) (void)(0)
18555- #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0)
18556- #define CATCH_REQUIRE_NOTHROW( ... ) (void)(0)
18557-
18558- #define CATCH_CHECK( ... ) (void)(0)
18559- #define CATCH_CHECK_FALSE( ... ) (void)(0)
18560- #define CATCH_CHECKED_IF( ... ) if (__VA_ARGS__)
18561- #define CATCH_CHECKED_ELSE( ... ) if (!(__VA_ARGS__))
18562- #define CATCH_CHECK_NOFAIL( ... ) (void)(0)
18563-
18564- #define CATCH_CHECK_THROWS( ... ) (void)(0)
18565- #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) (void)(0)
18566- #define CATCH_CHECK_NOTHROW( ... ) (void)(0)
18567-
18568- #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ))
18569- #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ))
18570- #define CATCH_METHOD_AS_TEST_CASE( method, ... )
18571- #define CATCH_TEST_CASE_PERSISTENT_FIXTURE( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ))
18572- #define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0)
18573- #define CATCH_SECTION( ... )
18574- #define CATCH_DYNAMIC_SECTION( ... )
18575- #define CATCH_FAIL( ... ) (void)(0)
18576- #define CATCH_FAIL_CHECK( ... ) (void)(0)
18577- #define CATCH_SUCCEED( ... ) (void)(0)
18578- #define CATCH_SKIP( ... ) (void)(0)
18579-
18580- #define CATCH_STATIC_REQUIRE( ... ) (void)(0)
18581- #define CATCH_STATIC_REQUIRE_FALSE( ... ) (void)(0)
18582- #define CATCH_STATIC_CHECK( ... ) (void)(0)
18583- #define CATCH_STATIC_CHECK_FALSE( ... ) (void)(0)
18584-
18585- // "BDD-style" convenience wrappers
18586- #define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ))
18587- #define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), className )
18588- #define CATCH_GIVEN( desc )
18589- #define CATCH_AND_GIVEN( desc )
18590- #define CATCH_WHEN( desc )
18591- #define CATCH_AND_WHEN( desc )
18592- #define CATCH_THEN( desc )
18593- #define CATCH_AND_THEN( desc )
18594-
18595-#elif !defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE) // ^^ prefixed, disabled | vv unprefixed, implemented
18596-
18597- #define REQUIRE( ... ) INTERNAL_CATCH_TEST( "REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ )
18598- #define REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
18599-
18600- #define REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ )
18601- #define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr )
18602- #define REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ )
18603-
18604- #define CHECK( ... ) INTERNAL_CATCH_TEST( "CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
18605- #define CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
18606- #define CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
18607- #define CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
18608- #define CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
18609-
18610- #define CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
18611- #define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr )
18612- #define CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
18613-
18614- #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
18615- #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
18616- #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
18617- #define TEST_CASE_PERSISTENT_FIXTURE( className, ... ) INTERNAL_CATCH_TEST_CASE_PERSISTENT_FIXTURE( className, __VA_ARGS__ )
18618- #define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
18619- #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
18620- #define DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ )
18621- #define FAIL( ... ) do { \
18622- INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ ); \
18623- Catch::Detail::Unreachable(); \
18624- } while (false)
18625- #define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
18626- #define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
18627- #define SKIP( ... ) do { \
18628- INTERNAL_CATCH_MSG( "SKIP", Catch::ResultWas::ExplicitSkip, Catch::ResultDisposition::Normal, __VA_ARGS__ ); \
18629- Catch::Detail::Unreachable(); \
18630- } while (false)
18631-
18632-
18633- #if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE)
18634- #define STATIC_REQUIRE( ... ) static_assert( __VA_ARGS__, #__VA_ARGS__ ); SUCCEED( #__VA_ARGS__ )
18635- #define STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); SUCCEED( "!(" #__VA_ARGS__ ")" )
18636- #define STATIC_CHECK( ... ) static_assert( __VA_ARGS__, #__VA_ARGS__ ); SUCCEED( #__VA_ARGS__ )
18637- #define STATIC_CHECK_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); SUCCEED( "!(" #__VA_ARGS__ ")" )
18638- #else
18639- #define STATIC_REQUIRE( ... ) REQUIRE( __VA_ARGS__ )
18640- #define STATIC_REQUIRE_FALSE( ... ) REQUIRE_FALSE( __VA_ARGS__ )
18641- #define STATIC_CHECK( ... ) CHECK( __VA_ARGS__ )
18642- #define STATIC_CHECK_FALSE( ... ) CHECK_FALSE( __VA_ARGS__ )
18643- #endif
18644-
18645- // "BDD-style" convenience wrappers
18646- #define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ )
18647- #define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
18648- #define GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc )
18649- #define AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc )
18650- #define WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc )
18651- #define AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc )
18652- #define THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc )
18653- #define AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc )
18654-
18655-#elif !defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE) // ^^ unprefixed, implemented | vv unprefixed, disabled
18656-
18657- #define REQUIRE( ... ) (void)(0)
18658- #define REQUIRE_FALSE( ... ) (void)(0)
18659-
18660- #define REQUIRE_THROWS( ... ) (void)(0)
18661- #define REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0)
18662- #define REQUIRE_NOTHROW( ... ) (void)(0)
18663-
18664- #define CHECK( ... ) (void)(0)
18665- #define CHECK_FALSE( ... ) (void)(0)
18666- #define CHECKED_IF( ... ) if (__VA_ARGS__)
18667- #define CHECKED_ELSE( ... ) if (!(__VA_ARGS__))
18668- #define CHECK_NOFAIL( ... ) (void)(0)
18669-
18670- #define CHECK_THROWS( ... ) (void)(0)
18671- #define CHECK_THROWS_AS( expr, exceptionType ) (void)(0)
18672- #define CHECK_NOTHROW( ... ) (void)(0)
18673-
18674- #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), __VA_ARGS__)
18675- #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ))
18676- #define METHOD_AS_TEST_CASE( method, ... )
18677- #define TEST_CASE_PERSISTENT_FIXTURE( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), __VA_ARGS__)
18678- #define REGISTER_TEST_CASE( Function, ... ) (void)(0)
18679- #define SECTION( ... )
18680- #define DYNAMIC_SECTION( ... )
18681- #define FAIL( ... ) (void)(0)
18682- #define FAIL_CHECK( ... ) (void)(0)
18683- #define SUCCEED( ... ) (void)(0)
18684- #define SKIP( ... ) (void)(0)
18685-
18686- #define STATIC_REQUIRE( ... ) (void)(0)
18687- #define STATIC_REQUIRE_FALSE( ... ) (void)(0)
18688- #define STATIC_CHECK( ... ) (void)(0)
18689- #define STATIC_CHECK_FALSE( ... ) (void)(0)
18690-
18691- // "BDD-style" convenience wrappers
18692- #define SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ) )
18693- #define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), className )
18694-
18695- #define GIVEN( desc )
18696- #define AND_GIVEN( desc )
18697- #define WHEN( desc )
18698- #define AND_WHEN( desc )
18699- #define THEN( desc )
18700- #define AND_THEN( desc )
18701-
18702-#endif // ^^ unprefixed, disabled
18703-
18704-// end of user facing macros
18705-
18706-#endif // CATCH_TEST_MACROS_HPP_INCLUDED
18707-
18708-
18709-#ifndef CATCH_TEMPLATE_TEST_REGISTRY_HPP_INCLUDED
18710-#define CATCH_TEMPLATE_TEST_REGISTRY_HPP_INCLUDED
18711-
18712-
18713-
18714-#ifndef CATCH_PREPROCESSOR_HPP_INCLUDED
18715-#define CATCH_PREPROCESSOR_HPP_INCLUDED
18716-
18717-
18718-#if defined(__GNUC__)
18719-// We need to silence "empty __VA_ARGS__ warning", and using just _Pragma does not work
18720-#pragma GCC system_header
18721-#endif
18722-
18723-
18724-namespace Catch {
18725- namespace Detail {
18726- template <int N>
18727- struct priority_tag : priority_tag<N - 1> {};
18728- template <>
18729- struct priority_tag<0> {};
18730- }
18731-}
18732-
18733-#define CATCH_RECURSION_LEVEL0(...) __VA_ARGS__
18734-#define CATCH_RECURSION_LEVEL1(...) CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(__VA_ARGS__)))
18735-#define CATCH_RECURSION_LEVEL2(...) CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(__VA_ARGS__)))
18736-#define CATCH_RECURSION_LEVEL3(...) CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(__VA_ARGS__)))
18737-#define CATCH_RECURSION_LEVEL4(...) CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(__VA_ARGS__)))
18738-#define CATCH_RECURSION_LEVEL5(...) CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(__VA_ARGS__)))
18739-
18740-#ifdef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
18741-#define INTERNAL_CATCH_EXPAND_VARGS(...) __VA_ARGS__
18742-// MSVC needs more evaluations
18743-#define CATCH_RECURSION_LEVEL6(...) CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(__VA_ARGS__)))
18744-#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL6(CATCH_RECURSION_LEVEL6(__VA_ARGS__))
18745-#else
18746-#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL5(__VA_ARGS__)
18747-#endif
18748-
18749-#define CATCH_REC_END(...)
18750-#define CATCH_REC_OUT
18751-
18752-#define CATCH_EMPTY()
18753-#define CATCH_DEFER(id) id CATCH_EMPTY()
18754-
18755-#define CATCH_REC_GET_END2() 0, CATCH_REC_END
18756-#define CATCH_REC_GET_END1(...) CATCH_REC_GET_END2
18757-#define CATCH_REC_GET_END(...) CATCH_REC_GET_END1
18758-#define CATCH_REC_NEXT0(test, next, ...) next CATCH_REC_OUT
18759-#define CATCH_REC_NEXT1(test, next) CATCH_DEFER ( CATCH_REC_NEXT0 ) ( test, next, 0)
18760-#define CATCH_REC_NEXT(test, next) CATCH_REC_NEXT1(CATCH_REC_GET_END test, next)
18761-
18762-#define CATCH_REC_LIST0(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ )
18763-#define CATCH_REC_LIST1(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0) ) ( f, peek, __VA_ARGS__ )
18764-#define CATCH_REC_LIST2(f, x, peek, ...) f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ )
18765-
18766-#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__ )
18767-#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__ )
18768-#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__ )
18769-
18770-// Applies the function macro `f` to each of the remaining parameters, inserts commas between the results,
18771-// and passes userdata as the first parameter to each invocation,
18772-// e.g. CATCH_REC_LIST_UD(f, x, a, b, c) evaluates to f(x, a), f(x, b), f(x, c)
18773-#define CATCH_REC_LIST_UD(f, userdata, ...) CATCH_RECURSE(CATCH_REC_LIST2_UD(f, userdata, __VA_ARGS__, ()()(), ()()(), ()()(), 0))
18774-
18775-#define CATCH_REC_LIST(f, ...) CATCH_RECURSE(CATCH_REC_LIST2(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0))
18776-
18777-#define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__)
18778-#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
18779-#define INTERNAL_CATCH_STRINGIZE2(...) #__VA_ARGS__
18780-#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param))
18781-#else
18782-// MSVC is adding extra space and needs another indirection to expand INTERNAL_CATCH_NOINTERNAL_CATCH_DEF
18783-#define INTERNAL_CATCH_STRINGIZE2(...) INTERNAL_CATCH_STRINGIZE3(__VA_ARGS__)
18784-#define INTERNAL_CATCH_STRINGIZE3(...) #__VA_ARGS__
18785-#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1)
18786-#endif
18787-
18788-#define INTERNAL_CATCH_MAKE_NAMESPACE2(...) ns_##__VA_ARGS__
18789-#define INTERNAL_CATCH_MAKE_NAMESPACE(name) INTERNAL_CATCH_MAKE_NAMESPACE2(name)
18790-
18791-#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
18792-#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS_GEN(__VA_ARGS__)>(Catch::Detail::priority_tag<1>{}))
18793-#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))
18794-#else
18795-#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) INTERNAL_CATCH_EXPAND_VARGS(decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS_GEN(__VA_ARGS__)>(Catch::Detail::priority_tag<1>{})))
18796-#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)))
18797-#endif
18798-
18799-#define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(...)\
18800- CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,__VA_ARGS__)
18801-
18802-#define INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_0) INTERNAL_CATCH_REMOVE_PARENS(_0)
18803-#define INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_0, _1) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_1)
18804-#define INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_0, _1, _2) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_1, _2)
18805-#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)
18806-#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)
18807-#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)
18808-#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)
18809-#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)
18810-#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)
18811-#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)
18812-#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)
18813-
18814-#define INTERNAL_CATCH_VA_NARGS_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N
18815-
18816-#define INTERNAL_CATCH_TYPE_GEN\
18817- template<typename...> struct TypeList {};\
18818- template<typename... Ts>\
18819- constexpr auto get_wrapper(Catch::Detail::priority_tag<1>) noexcept -> TypeList<Ts...> { return {}; }\
18820- template<template<typename...> class...> struct TemplateTypeList{};\
18821- template<template<typename...> class...Cs>\
18822- constexpr auto get_wrapper(Catch::Detail::priority_tag<1>) noexcept -> TemplateTypeList<Cs...> { return {}; }\
18823- template<typename...>\
18824- struct append;\
18825- template<typename...>\
18826- struct rewrap;\
18827- template<template<typename...> class, typename...>\
18828- struct create;\
18829- template<template<typename...> class, typename>\
18830- struct convert;\
18831- \
18832- template<typename T> \
18833- struct append<T> { using type = T; };\
18834- template< template<typename...> class L1, typename...E1, template<typename...> class L2, typename...E2, typename...Rest>\
18835- struct append<L1<E1...>, L2<E2...>, Rest...> { using type = typename append<L1<E1...,E2...>, Rest...>::type; };\
18836- template< template<typename...> class L1, typename...E1, typename...Rest>\
18837- struct append<L1<E1...>, TypeList<mpl_::na>, Rest...> { using type = L1<E1...>; };\
18838- \
18839- template< template<typename...> class Container, template<typename...> class List, typename...elems>\
18840- struct rewrap<TemplateTypeList<Container>, List<elems...>> { using type = TypeList<Container<elems...>>; };\
18841- template< template<typename...> class Container, template<typename...> class List, class...Elems, typename...Elements>\
18842- struct rewrap<TemplateTypeList<Container>, List<Elems...>, Elements...> { using type = typename append<TypeList<Container<Elems...>>, typename rewrap<TemplateTypeList<Container>, Elements...>::type>::type; };\
18843- \
18844- template<template <typename...> class Final, template< typename...> class...Containers, typename...Types>\
18845- struct create<Final, TemplateTypeList<Containers...>, TypeList<Types...>> { using type = typename append<Final<>, typename rewrap<TemplateTypeList<Containers>, Types...>::type...>::type; };\
18846- template<template <typename...> class Final, template <typename...> class List, typename...Ts>\
18847- struct convert<Final, List<Ts...>> { using type = typename append<Final<>,TypeList<Ts>...>::type; };
18848-
18849-#define INTERNAL_CATCH_NTTP_1(signature, ...)\
18850- template<INTERNAL_CATCH_REMOVE_PARENS(signature)> struct Nttp{};\
18851- template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
18852- constexpr auto get_wrapper(Catch::Detail::priority_tag<0>) noexcept -> Nttp<__VA_ARGS__> { return {}; } \
18853- template<template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...> struct NttpTemplateTypeList{};\
18854- template<template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...Cs>\
18855- constexpr auto get_wrapper(Catch::Detail::priority_tag<0>) noexcept -> NttpTemplateTypeList<Cs...> { return {}; } \
18856- \
18857- template< template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class Container, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class List, INTERNAL_CATCH_REMOVE_PARENS(signature)>\
18858- struct rewrap<NttpTemplateTypeList<Container>, List<__VA_ARGS__>> { using type = TypeList<Container<__VA_ARGS__>>; };\
18859- template< template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class Container, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class List, INTERNAL_CATCH_REMOVE_PARENS(signature), typename...Elements>\
18860- struct rewrap<NttpTemplateTypeList<Container>, List<__VA_ARGS__>, Elements...> { using type = typename append<TypeList<Container<__VA_ARGS__>>, typename rewrap<NttpTemplateTypeList<Container>, Elements...>::type>::type; };\
18861- template<template <typename...> class Final, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...Containers, typename...Types>\
18862- struct create<Final, NttpTemplateTypeList<Containers...>, TypeList<Types...>> { using type = typename append<Final<>, typename rewrap<NttpTemplateTypeList<Containers>, Types...>::type...>::type; };
18863-
18864-#define INTERNAL_CATCH_DECLARE_SIG_TEST0(TestName)
18865-#define INTERNAL_CATCH_DECLARE_SIG_TEST1(TestName, signature)\
18866- template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
18867- static void TestName()
18868-#define INTERNAL_CATCH_DECLARE_SIG_TEST_X(TestName, signature, ...)\
18869- template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
18870- static void TestName()
18871-
18872-#define INTERNAL_CATCH_DEFINE_SIG_TEST0(TestName)
18873-#define INTERNAL_CATCH_DEFINE_SIG_TEST1(TestName, signature)\
18874- template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
18875- static void TestName()
18876-#define INTERNAL_CATCH_DEFINE_SIG_TEST_X(TestName, signature,...)\
18877- template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
18878- static void TestName()
18879-
18880-#define INTERNAL_CATCH_TYPES_REGISTER(TestFunc)\
18881- template<typename... Ts>\
18882- void reg_test(TypeList<Ts...>, Catch::NameAndTags nameAndTags)\
18883- {\
18884- Catch::AutoReg( Catch::makeTestInvoker(&TestFunc<Ts...>), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), nameAndTags);\
18885- }
18886-
18887-#define INTERNAL_CATCH_NTTP_REGISTER0(TestFunc, signature, ...)
18888-#define INTERNAL_CATCH_NTTP_REGISTER(TestFunc, signature, ...)\
18889- template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
18890- void reg_test(Nttp<__VA_ARGS__>, Catch::NameAndTags nameAndTags)\
18891- {\
18892- Catch::AutoReg( Catch::makeTestInvoker(&TestFunc<__VA_ARGS__>), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), nameAndTags);\
18893- }
18894-
18895-#define INTERNAL_CATCH_NTTP_REGISTER_METHOD0(TestName, signature, ...)\
18896- template<typename Type>\
18897- void reg_test(TypeList<Type>, Catch::StringRef className, Catch::NameAndTags nameAndTags)\
18898- {\
18899- Catch::AutoReg( Catch::makeTestInvoker(&TestName<Type>::test), CATCH_INTERNAL_LINEINFO, className, nameAndTags);\
18900- }
18901-
18902-#define INTERNAL_CATCH_NTTP_REGISTER_METHOD(TestName, signature, ...)\
18903- template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
18904- void reg_test(Nttp<__VA_ARGS__>, Catch::StringRef className, Catch::NameAndTags nameAndTags)\
18905- {\
18906- Catch::AutoReg( Catch::makeTestInvoker(&TestName<__VA_ARGS__>::test), CATCH_INTERNAL_LINEINFO, className, nameAndTags);\
18907- }
18908-
18909-#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD0(TestName, ClassName)
18910-#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD1(TestName, ClassName, signature)\
18911- template<typename TestType> \
18912- struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName)<TestType> { \
18913- void test();\
18914- }
18915-
18916-#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X(TestName, ClassName, signature, ...)\
18917- template<INTERNAL_CATCH_REMOVE_PARENS(signature)> \
18918- struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName)<__VA_ARGS__> { \
18919- void test();\
18920- }
18921-
18922-#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD0(TestName)
18923-#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD1(TestName, signature)\
18924- template<typename TestType> \
18925- void INTERNAL_CATCH_MAKE_NAMESPACE(TestName)::TestName<TestType>::test()
18926-#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X(TestName, signature, ...)\
18927- template<INTERNAL_CATCH_REMOVE_PARENS(signature)> \
18928- void INTERNAL_CATCH_MAKE_NAMESPACE(TestName)::TestName<__VA_ARGS__>::test()
18929-
18930-#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
18931-#define INTERNAL_CATCH_NTTP_0
18932-#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)
18933-#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__)
18934-#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__)
18935-#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__)
18936-#define INTERNAL_CATCH_NTTP_REG_GEN(TestFunc, ...) INTERNAL_CATCH_TYPES_REGISTER(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__)
18937-#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__)
18938-#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__)
18939-#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__)
18940-#else
18941-#define INTERNAL_CATCH_NTTP_0(signature)
18942-#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__))
18943-#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__))
18944-#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__))
18945-#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__))
18946-#define INTERNAL_CATCH_NTTP_REG_GEN(TestFunc, ...) INTERNAL_CATCH_TYPES_REGISTER(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__))
18947-#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__))
18948-#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__))
18949-#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__))
18950-#endif
18951-
18952-#endif // CATCH_PREPROCESSOR_HPP_INCLUDED
18953-
18954-
18955-// GCC 5 and older do not properly handle disabling unused-variable warning
18956-// with a _Pragma. This means that we have to leak the suppression to the
18957-// user code as well :-(
18958-#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ <= 5
18959-#pragma GCC diagnostic ignored "-Wunused-variable"
18960-#endif
18961-
18962-#if defined(CATCH_CONFIG_DISABLE)
18963- #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( TestName, TestFunc, Name, Tags, Signature, ... ) \
18964- INTERNAL_CATCH_DEFINE_SIG_TEST(TestFunc, INTERNAL_CATCH_REMOVE_PARENS(Signature))
18965- #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( TestNameClass, TestName, ClassName, Name, Tags, Signature, ... ) \
18966- namespace{ \
18967- namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName) { \
18968- INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, INTERNAL_CATCH_REMOVE_PARENS(Signature));\
18969- } \
18970- } \
18971- INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature))
18972-
18973- #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
18974- #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(Name, Tags, ...) \
18975- 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__ )
18976- #else
18977- #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(Name, Tags, ...) \
18978- 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__ ) )
18979- #endif
18980-
18981- #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
18982- #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(Name, Tags, Signature, ...) \
18983- 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__ )
18984- #else
18985- #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(Name, Tags, Signature, ...) \
18986- 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__ ) )
18987- #endif
18988-
18989- #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
18990- #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( ClassName, Name, Tags,... ) \
18991- 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__ )
18992- #else
18993- #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( ClassName, Name, Tags,... ) \
18994- 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__ ) )
18995- #endif
18996-
18997- #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
18998- #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION( ClassName, Name, Tags, Signature, ... ) \
18999- 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__ )
19000- #else
19001- #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION( ClassName, Name, Tags, Signature, ... ) \
19002- 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__ ) )
19003- #endif
19004-#endif
19005-
19006-
19007- ///////////////////////////////////////////////////////////////////////////////
19008- #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_2(TestName, TestFunc, Name, Tags, Signature, ... )\
19009- CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
19010- CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
19011- CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
19012- CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
19013- CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
19014- CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS \
19015- INTERNAL_CATCH_DECLARE_SIG_TEST(TestFunc, INTERNAL_CATCH_REMOVE_PARENS(Signature));\
19016- namespace {\
19017- namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){\
19018- INTERNAL_CATCH_TYPE_GEN\
19019- INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\
19020- INTERNAL_CATCH_NTTP_REG_GEN(TestFunc,INTERNAL_CATCH_REMOVE_PARENS(Signature))\
19021- template<typename...Types> \
19022- struct TestName{\
19023- TestName(){\
19024- size_t index = 0; \
19025- 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) */\
19026- using expander = size_t[]; /* NOLINT(cppcoreguidelines-avoid-c-arrays,modernize-avoid-c-arrays,hicpp-avoid-c-arrays) */\
19027- (void)expander{(reg_test(Types{}, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++)... };/* NOLINT */ \
19028- }\
19029- };\
19030- static const int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
19031- TestName<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(__VA_ARGS__)>();\
19032- return 0;\
19033- }();\
19034- }\
19035- }\
19036- CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
19037- INTERNAL_CATCH_DEFINE_SIG_TEST(TestFunc,INTERNAL_CATCH_REMOVE_PARENS(Signature))
19038-
19039-#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
19040- #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \
19041- 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__ )
19042-#else
19043- #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \
19044- 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__ ) )
19045-#endif
19046-
19047-#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
19048- #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG(Name, Tags, Signature, ...) \
19049- 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__ )
19050-#else
19051- #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG(Name, Tags, Signature, ...) \
19052- 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__ ) )
19053-#endif
19054-
19055- #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(TestName, TestFuncName, Name, Tags, Signature, TmplTypes, TypesList) \
19056- CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
19057- CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
19058- CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
19059- CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
19060- CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
19061- CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS \
19062- template<typename TestType> static void TestFuncName(); \
19063- namespace {\
19064- namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName) { \
19065- INTERNAL_CATCH_TYPE_GEN \
19066- INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature)) \
19067- template<typename... Types> \
19068- struct TestName { \
19069- void reg_tests() { \
19070- size_t index = 0; \
19071- using expander = size_t[]; \
19072- constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\
19073- constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\
19074- constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\
19075- (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFuncName<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + '<' + types_list[index % num_types] + '>', Tags } ), index++)... };/* NOLINT */\
19076- } \
19077- }; \
19078- static const int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \
19079- using TestInit = typename create<TestName, decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>(Catch::Detail::priority_tag<1>{})), TypeList<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(INTERNAL_CATCH_REMOVE_PARENS(TypesList))>>::type; \
19080- TestInit t; \
19081- t.reg_tests(); \
19082- return 0; \
19083- }(); \
19084- } \
19085- } \
19086- CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
19087- template<typename TestType> \
19088- static void TestFuncName()
19089-
19090-#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
19091- #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\
19092- 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__)
19093-#else
19094- #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\
19095- 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__ ) )
19096-#endif
19097-
19098-#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
19099- #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG(Name, Tags, Signature, ...)\
19100- 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__)
19101-#else
19102- #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG(Name, Tags, Signature, ...)\
19103- 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__ ) )
19104-#endif
19105-
19106- #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_2(TestName, TestFunc, Name, Tags, TmplList)\
19107- CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
19108- CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
19109- CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
19110- CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
19111- CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS \
19112- template<typename TestType> static void TestFunc(); \
19113- namespace {\
19114- namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){\
19115- INTERNAL_CATCH_TYPE_GEN\
19116- template<typename... Types> \
19117- struct TestName { \
19118- void reg_tests() { \
19119- size_t index = 0; \
19120- using expander = size_t[]; \
19121- (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 */\
19122- } \
19123- };\
19124- static const int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \
19125- using TestInit = typename convert<TestName, TmplList>::type; \
19126- TestInit t; \
19127- t.reg_tests(); \
19128- return 0; \
19129- }(); \
19130- }}\
19131- CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
19132- template<typename TestType> \
19133- static void TestFunc()
19134-
19135- #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE(Name, Tags, TmplList) \
19136- 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 )
19137-
19138-
19139- #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, Signature, ... ) \
19140- CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
19141- CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
19142- CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
19143- CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
19144- CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
19145- namespace {\
19146- namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){ \
19147- INTERNAL_CATCH_TYPE_GEN\
19148- INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\
19149- INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, INTERNAL_CATCH_REMOVE_PARENS(Signature));\
19150- INTERNAL_CATCH_NTTP_REG_METHOD_GEN(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature))\
19151- template<typename...Types> \
19152- struct TestNameClass{\
19153- TestNameClass(){\
19154- size_t index = 0; \
19155- constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, __VA_ARGS__)};\
19156- using expander = size_t[];\
19157- (void)expander{(reg_test(Types{}, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++)... };/* NOLINT */ \
19158- }\
19159- };\
19160- static const int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
19161- TestNameClass<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(__VA_ARGS__)>();\
19162- return 0;\
19163- }();\
19164- }\
19165- }\
19166- CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
19167- INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature))
19168-
19169-#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
19170- #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \
19171- 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__ )
19172-#else
19173- #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \
19174- 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__ ) )
19175-#endif
19176-
19177-#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
19178- #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... ) \
19179- 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__ )
19180-#else
19181- #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... ) \
19182- 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__ ) )
19183-#endif
19184-
19185- #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2(TestNameClass, TestName, ClassName, Name, Tags, Signature, TmplTypes, TypesList)\
19186- CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
19187- CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
19188- CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
19189- CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
19190- CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
19191- template<typename TestType> \
19192- struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
19193- void test();\
19194- };\
19195- namespace {\
19196- namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestNameClass) {\
19197- INTERNAL_CATCH_TYPE_GEN \
19198- INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\
19199- template<typename...Types>\
19200- struct TestNameClass{\
19201- void reg_tests(){\
19202- std::size_t index = 0;\
19203- using expander = std::size_t[];\
19204- constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\
19205- constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\
19206- constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\
19207- (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + '<' + types_list[index % num_types] + '>', Tags } ), index++)... };/* NOLINT */ \
19208- }\
19209- };\
19210- static const int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
19211- using TestInit = typename create<TestNameClass, decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>(Catch::Detail::priority_tag<1>{})), TypeList<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(INTERNAL_CATCH_REMOVE_PARENS(TypesList))>>::type;\
19212- TestInit t;\
19213- t.reg_tests();\
19214- return 0;\
19215- }(); \
19216- }\
19217- }\
19218- CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
19219- template<typename TestType> \
19220- void TestName<TestType>::test()
19221-
19222-#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
19223- #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\
19224- 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__ )
19225-#else
19226- #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\
19227- 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__ ) )
19228-#endif
19229-
19230-#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
19231- #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... )\
19232- 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__ )
19233-#else
19234- #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... )\
19235- 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__ ) )
19236-#endif
19237-
19238- #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, TmplList) \
19239- CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
19240- CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
19241- CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
19242- CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
19243- CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS \
19244- template<typename TestType> \
19245- struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
19246- void test();\
19247- };\
19248- namespace {\
19249- namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){ \
19250- INTERNAL_CATCH_TYPE_GEN\
19251- template<typename...Types>\
19252- struct TestNameClass{\
19253- void reg_tests(){\
19254- size_t index = 0;\
19255- using expander = size_t[];\
19256- (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 */ \
19257- }\
19258- };\
19259- static const int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
19260- using TestInit = typename convert<TestNameClass, TmplList>::type;\
19261- TestInit t;\
19262- t.reg_tests();\
19263- return 0;\
19264- }(); \
19265- }}\
19266- CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
19267- template<typename TestType> \
19268- void TestName<TestType>::test()
19269-
19270-#define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD(ClassName, Name, Tags, TmplList) \
19271- 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 )
19272-
19273-
19274-#endif // CATCH_TEMPLATE_TEST_REGISTRY_HPP_INCLUDED
19275-
19276-
19277-#if defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE)
19278-
19279- #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
19280- #define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
19281- #define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ )
19282- #define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
19283- #define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
19284- #define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ )
19285- #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ )
19286- #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ )
19287- #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
19288- #define CATCH_TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE(__VA_ARGS__)
19289- #define CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ )
19290- #else
19291- #define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) )
19292- #define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ ) )
19293- #define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
19294- #define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
19295- #define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) )
19296- #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ ) )
19297- #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
19298- #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
19299- #define CATCH_TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE( __VA_ARGS__ ) )
19300- #define CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
19301- #endif
19302-
19303-#elif defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE)
19304-
19305- #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
19306- #define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__)
19307- #define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__)
19308- #define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__)
19309- #define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ )
19310- #else
19311- #define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) )
19312- #define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__) )
19313- #define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__ ) )
19314- #define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ ) )
19315- #endif
19316-
19317- // When disabled, these can be shared between proper preprocessor and MSVC preprocessor
19318- #define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
19319- #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
19320- #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
19321- #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
19322- #define CATCH_TEMPLATE_LIST_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE(__VA_ARGS__)
19323- #define CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
19324-
19325-#elif !defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE)
19326-
19327- #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
19328- #define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
19329- #define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ )
19330- #define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
19331- #define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
19332- #define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ )
19333- #define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ )
19334- #define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ )
19335- #define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
19336- #define TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE(__VA_ARGS__)
19337- #define TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ )
19338- #else
19339- #define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) )
19340- #define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ ) )
19341- #define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
19342- #define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
19343- #define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) )
19344- #define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ ) )
19345- #define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
19346- #define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
19347- #define TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE( __VA_ARGS__ ) )
19348- #define TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
19349- #endif
19350-
19351-#elif !defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE)
19352-
19353- #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
19354- #define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__)
19355- #define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__)
19356- #define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__)
19357- #define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ )
19358- #else
19359- #define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) )
19360- #define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__) )
19361- #define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__ ) )
19362- #define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ ) )
19363- #endif
19364-
19365- // When disabled, these can be shared between proper preprocessor and MSVC preprocessor
19366- #define TEMPLATE_PRODUCT_TEST_CASE( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )
19367- #define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )
19368- #define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
19369- #define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
19370- #define TEMPLATE_LIST_TEST_CASE( ... ) TEMPLATE_TEST_CASE(__VA_ARGS__)
19371- #define TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
19372-
19373-#endif // end of user facing macro declarations
19374-
19375-
19376-#endif // CATCH_TEMPLATE_TEST_MACROS_HPP_INCLUDED
19377-
19378-
19379-#ifndef CATCH_TEST_CASE_INFO_HPP_INCLUDED
19380-#define CATCH_TEST_CASE_INFO_HPP_INCLUDED
19381-
19382-
19383-
19384-#include <cstdint>
19385-#include <string>
19386-#include <vector>
19387-
19388-#ifdef __clang__
19389-#pragma clang diagnostic push
19390-#pragma clang diagnostic ignored "-Wpadded"
19391-#endif
19392-
19393-namespace Catch {
19394-
19395- /**
19396- * A **view** of a tag string that provides case insensitive comparisons
19397- *
19398- * Note that in Catch2 internals, the square brackets around tags are
19399- * not a part of tag's representation, so e.g. "[cool-tag]" is represented
19400- * as "cool-tag" internally.
19401- */
19402- struct Tag {
19403- constexpr Tag(StringRef original_):
19404- original(original_)
19405- {}
19406- StringRef original;
19407-
19408- friend bool operator< ( Tag const& lhs, Tag const& rhs );
19409- friend bool operator==( Tag const& lhs, Tag const& rhs );
19410- };
19411-
19412- class ITestInvoker;
19413- struct NameAndTags;
19414-
19415- enum class TestCaseProperties : uint8_t {
19416- None = 0,
19417- IsHidden = 1 << 1,
19418- ShouldFail = 1 << 2,
19419- MayFail = 1 << 3,
19420- Throws = 1 << 4,
19421- NonPortable = 1 << 5,
19422- Benchmark = 1 << 6
19423- };
19424-
19425- /**
19426- * Various metadata about the test case.
19427- *
19428- * A test case is uniquely identified by its (class)name and tags
19429- * combination, with source location being ignored, and other properties
19430- * being determined from tags.
19431- *
19432- * Tags are kept sorted.
19433- */
19434- struct TestCaseInfo : Detail::NonCopyable {
19435-
19436- TestCaseInfo(StringRef _className,
19437- NameAndTags const& _nameAndTags,
19438- SourceLineInfo const& _lineInfo);
19439-
19440- bool isHidden() const;
19441- bool throws() const;
19442- bool okToFail() const;
19443- bool expectedToFail() const;
19444-
19445- // Adds the tag(s) with test's filename (for the -# flag)
19446- void addFilenameTag();
19447-
19448- //! Orders by name, classname and tags
19449- friend bool operator<( TestCaseInfo const& lhs,
19450- TestCaseInfo const& rhs );
19451-
19452-
19453- std::string tagsAsString() const;
19454-
19455- std::string name;
19456- StringRef className;
19457- private:
19458- std::string backingTags;
19459- // Internally we copy tags to the backing storage and then add
19460- // refs to this storage to the tags vector.
19461- void internalAppendTag(StringRef tagString);
19462- public:
19463- std::vector<Tag> tags;
19464- SourceLineInfo lineInfo;
19465- TestCaseProperties properties = TestCaseProperties::None;
19466- };
19467-
19468- /**
19469- * Wrapper over the test case information and the test case invoker
19470- *
19471- * Does not own either, and is specifically made to be cheap
19472- * to copy around.
19473- */
19474- class TestCaseHandle {
19475- TestCaseInfo* m_info;
19476- ITestInvoker* m_invoker;
19477- public:
19478- constexpr TestCaseHandle(TestCaseInfo* info, ITestInvoker* invoker) :
19479- m_info(info), m_invoker(invoker) {}
19480-
19481- void prepareTestCase() const {
19482- m_invoker->prepareTestCase();
19483- }
19484-
19485- void tearDownTestCase() const {
19486- m_invoker->tearDownTestCase();
19487- }
19488-
19489- void invoke() const {
19490- m_invoker->invoke();
19491- }
19492-
19493- constexpr TestCaseInfo const& getTestCaseInfo() const {
19494- return *m_info;
19495- }
19496- };
19497-
19498- Detail::unique_ptr<TestCaseInfo>
19499- makeTestCaseInfo( StringRef className,
19500- NameAndTags const& nameAndTags,
19501- SourceLineInfo const& lineInfo );
19502-}
19503-
19504-#ifdef __clang__
19505-#pragma clang diagnostic pop
19506-#endif
19507-
19508-#endif // CATCH_TEST_CASE_INFO_HPP_INCLUDED
19509-
19510-
19511-#ifndef CATCH_TEST_RUN_INFO_HPP_INCLUDED
19512-#define CATCH_TEST_RUN_INFO_HPP_INCLUDED
19513-
19514-
19515-namespace Catch {
19516-
19517- struct TestRunInfo {
19518- constexpr TestRunInfo(StringRef _name) : name(_name) {}
19519- StringRef name;
19520- };
19521-
19522-} // end namespace Catch
19523-
19524-#endif // CATCH_TEST_RUN_INFO_HPP_INCLUDED
19525-
19526-
19527-#ifndef CATCH_TRANSLATE_EXCEPTION_HPP_INCLUDED
19528-#define CATCH_TRANSLATE_EXCEPTION_HPP_INCLUDED
19529-
19530-
19531-
19532-#ifndef CATCH_INTERFACES_EXCEPTION_HPP_INCLUDED
19533-#define CATCH_INTERFACES_EXCEPTION_HPP_INCLUDED
19534-
19535-
19536-#include <string>
19537-#include <vector>
19538-
19539-namespace Catch {
19540- using exceptionTranslateFunction = std::string(*)();
19541-
19542- class IExceptionTranslator;
19543- using ExceptionTranslators = std::vector<Detail::unique_ptr<IExceptionTranslator const>>;
19544-
19545- class IExceptionTranslator {
19546- public:
19547- virtual ~IExceptionTranslator(); // = default
19548- virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0;
19549- };
19550-
19551- class IExceptionTranslatorRegistry {
19552- public:
19553- virtual ~IExceptionTranslatorRegistry(); // = default
19554- virtual std::string translateActiveException() const = 0;
19555- };
19556-
19557-} // namespace Catch
19558-
19559-#endif // CATCH_INTERFACES_EXCEPTION_HPP_INCLUDED
19560-
19561-#include <exception>
19562-
19563-namespace Catch {
19564- namespace Detail {
19565- void registerTranslatorImpl(
19566- Detail::unique_ptr<IExceptionTranslator>&& translator );
19567- }
19568-
19569- class ExceptionTranslatorRegistrar {
19570- template<typename T>
19571- class ExceptionTranslator : public IExceptionTranslator {
19572- public:
19573-
19574- constexpr ExceptionTranslator( std::string(*translateFunction)( T const& ) )
19575- : m_translateFunction( translateFunction )
19576- {}
19577-
19578- std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const override {
19579-#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
19580- try {
19581- if( it == itEnd )
19582- std::rethrow_exception(std::current_exception());
19583- else
19584- return (*it)->translate( it+1, itEnd );
19585- }
19586- catch( T const& ex ) {
19587- return m_translateFunction( ex );
19588- }
19589-#else
19590- return "You should never get here!";
19591-#endif
19592- }
19593-
19594- protected:
19595- std::string(*m_translateFunction)( T const& );
19596- };
19597-
19598- public:
19599- template<typename T>
19600- ExceptionTranslatorRegistrar( std::string(*translateFunction)( T const& ) ) {
19601- Detail::registerTranslatorImpl(
19602- Detail::make_unique<ExceptionTranslator<T>>(
19603- translateFunction ) );
19604- }
19605- };
19606-
19607-} // namespace Catch
19608-
19609-///////////////////////////////////////////////////////////////////////////////
19610-#define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \
19611- static std::string translatorName( signature ); \
19612- CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
19613- CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
19614- namespace{ const Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); } \
19615- CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
19616- static std::string translatorName( signature )
19617-
19618-#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )
19619-
19620-#if defined(CATCH_CONFIG_DISABLE)
19621- #define INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( translatorName, signature) \
19622- static std::string translatorName( signature )
19623-#endif
19624-
19625-
19626-// This macro is always prefixed
19627-#if !defined(CATCH_CONFIG_DISABLE)
19628-#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature )
19629-#else
19630-#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )
19631-#endif
19632-
19633-
19634-#endif // CATCH_TRANSLATE_EXCEPTION_HPP_INCLUDED
19635-
19636-
19637-#ifndef CATCH_VERSION_HPP_INCLUDED
19638-#define CATCH_VERSION_HPP_INCLUDED
19639-
19640-#include <iosfwd>
19641-
19642-namespace Catch {
19643-
19644- // Versioning information
19645- struct Version {
19646- Version( Version const& ) = delete;
19647- Version& operator=( Version const& ) = delete;
19648- Version( unsigned int _majorVersion,
19649- unsigned int _minorVersion,
19650- unsigned int _patchNumber,
19651- char const * const _branchName,
19652- unsigned int _buildNumber );
19653-
19654- unsigned int const majorVersion;
19655- unsigned int const minorVersion;
19656- unsigned int const patchNumber;
19657-
19658- // buildNumber is only used if branchName is not null
19659- char const * const branchName;
19660- unsigned int const buildNumber;
19661-
19662- friend std::ostream& operator << ( std::ostream& os, Version const& version );
19663- };
19664-
19665- Version const& libraryVersion();
19666-}
19667-
19668-#endif // CATCH_VERSION_HPP_INCLUDED
19669-
19670-
19671-#ifndef CATCH_VERSION_MACROS_HPP_INCLUDED
19672-#define CATCH_VERSION_MACROS_HPP_INCLUDED
19673-
19674-#define CATCH_VERSION_MAJOR 3
19675-#define CATCH_VERSION_MINOR 11
19676-#define CATCH_VERSION_PATCH 0
19677-
19678-#endif // CATCH_VERSION_MACROS_HPP_INCLUDED
19679-
19680-
19681-/** \file
19682- * This is a convenience header for Catch2's Generator support. It includes
19683- * **all** of Catch2 headers related to generators.
19684- *
19685- * Generally the Catch2 users should use specific includes they need,
19686- * but this header can be used instead for ease-of-experimentation, or
19687- * just plain convenience, at the cost of (significantly) increased
19688- * compilation times.
19689- *
19690- * When a new header is added to either the `generators` folder,
19691- * or to the corresponding internal subfolder, it should be added here.
19692- */
19693-
19694-#ifndef CATCH_GENERATORS_ALL_HPP_INCLUDED
19695-#define CATCH_GENERATORS_ALL_HPP_INCLUDED
19696-
19697-
19698-
19699-#ifndef CATCH_GENERATOR_EXCEPTION_HPP_INCLUDED
19700-#define CATCH_GENERATOR_EXCEPTION_HPP_INCLUDED
19701-
19702-#include <exception>
19703-
19704-namespace Catch {
19705-
19706- // Exception type to be thrown when a Generator runs into an error,
19707- // e.g. it cannot initialize the first return value based on
19708- // runtime information
19709- class GeneratorException : public std::exception {
19710- const char* const m_msg = "";
19711-
19712- public:
19713- GeneratorException(const char* msg):
19714- m_msg(msg)
19715- {}
19716-
19717- const char* what() const noexcept final;
19718- };
19719-
19720-} // end namespace Catch
19721-
19722-#endif // CATCH_GENERATOR_EXCEPTION_HPP_INCLUDED
19723-
19724-
19725-#ifndef CATCH_GENERATORS_HPP_INCLUDED
19726-#define CATCH_GENERATORS_HPP_INCLUDED
19727-
19728-
19729-
19730-#ifndef CATCH_INTERFACES_GENERATORTRACKER_HPP_INCLUDED
19731-#define CATCH_INTERFACES_GENERATORTRACKER_HPP_INCLUDED
19732-
19733-
19734-#include <string>
19735-
19736-namespace Catch {
19737-
19738- namespace Generators {
19739- class GeneratorUntypedBase {
19740- // Caches result from `toStringImpl`, assume that when it is an
19741- // empty string, the cache is invalidated.
19742- mutable std::string m_stringReprCache;
19743-
19744- // Counts based on `next` returning true
19745- std::size_t m_currentElementIndex = 0;
19746-
19747- /**
19748- * Attempts to move the generator to the next element
19749- *
19750- * Returns true iff the move succeeded (and a valid element
19751- * can be retrieved).
19752- */
19753- virtual bool next() = 0;
19754-
19755- //! Customization point for `currentElementAsString`
19756- virtual std::string stringifyImpl() const = 0;
19757-
19758- public:
19759- GeneratorUntypedBase() = default;
19760- // Generation of copy ops is deprecated (and Clang will complain)
19761- // if there is a user destructor defined
19762- GeneratorUntypedBase(GeneratorUntypedBase const&) = default;
19763- GeneratorUntypedBase& operator=(GeneratorUntypedBase const&) = default;
19764-
19765- virtual ~GeneratorUntypedBase(); // = default;
19766-
19767- /**
19768- * Attempts to move the generator to the next element
19769- *
19770- * Serves as a non-virtual interface to `next`, so that the
19771- * top level interface can provide sanity checking and shared
19772- * features.
19773- *
19774- * As with `next`, returns true iff the move succeeded and
19775- * the generator has new valid element to provide.
19776- */
19777- bool countedNext();
19778-
19779- std::size_t currentElementIndex() const { return m_currentElementIndex; }
19780-
19781- /**
19782- * Returns generator's current element as user-friendly string.
19783- *
19784- * By default returns string equivalent to calling
19785- * `Catch::Detail::stringify` on the current element, but generators
19786- * can customize their implementation as needed.
19787- *
19788- * Not thread-safe due to internal caching.
19789- *
19790- * The returned ref is valid only until the generator instance
19791- * is destructed, or it moves onto the next element, whichever
19792- * comes first.
19793- */
19794- StringRef currentElementAsString() const;
19795- };
19796- using GeneratorBasePtr = Catch::Detail::unique_ptr<GeneratorUntypedBase>;
19797-
19798- } // namespace Generators
19799-
19800- class IGeneratorTracker {
19801- public:
19802- virtual ~IGeneratorTracker(); // = default;
19803- virtual auto hasGenerator() const -> bool = 0;
19804- virtual auto getGenerator() const -> Generators::GeneratorBasePtr const& = 0;
19805- virtual void setGenerator( Generators::GeneratorBasePtr&& generator ) = 0;
19806- };
19807-
19808-} // namespace Catch
19809-
19810-#endif // CATCH_INTERFACES_GENERATORTRACKER_HPP_INCLUDED
19811-
19812-#include <vector>
19813-#include <tuple>
19814-
19815-namespace Catch {
19816-
19817-namespace Generators {
19818-
19819-namespace Detail {
19820-
19821- //! Throws GeneratorException with the provided message
19822- [[noreturn]]
19823- void throw_generator_exception(char const * msg);
19824-
19825-} // end namespace detail
19826-
19827- template<typename T>
19828- class IGenerator : public GeneratorUntypedBase {
19829- std::string stringifyImpl() const override {
19830- return ::Catch::Detail::stringify( get() );
19831- }
19832-
19833- public:
19834- // Returns the current element of the generator
19835- //
19836- // \Precondition The generator is either freshly constructed,
19837- // or the last call to `next()` returned true
19838- virtual T const& get() const = 0;
19839- using type = T;
19840- };
19841-
19842- template <typename T>
19843- using GeneratorPtr = Catch::Detail::unique_ptr<IGenerator<T>>;
19844-
19845- template <typename T>
19846- class GeneratorWrapper final {
19847- GeneratorPtr<T> m_generator;
19848- public:
19849- //! Takes ownership of the passed pointer.
19850- GeneratorWrapper(IGenerator<T>* generator):
19851- m_generator(generator) {}
19852- GeneratorWrapper(GeneratorPtr<T> generator):
19853- m_generator(CATCH_MOVE(generator)) {}
19854-
19855- T const& get() const {
19856- return m_generator->get();
19857- }
19858- bool next() {
19859- return m_generator->countedNext();
19860- }
19861- };
19862-
19863-
19864- template<typename T>
19865- class SingleValueGenerator final : public IGenerator<T> {
19866- T m_value;
19867- public:
19868- SingleValueGenerator(T const& value) :
19869- m_value(value)
19870- {}
19871- SingleValueGenerator(T&& value):
19872- m_value(CATCH_MOVE(value))
19873- {}
19874-
19875- T const& get() const override {
19876- return m_value;
19877- }
19878- bool next() override {
19879- return false;
19880- }
19881- };
19882-
19883- template<typename T>
19884- class FixedValuesGenerator final : public IGenerator<T> {
19885- static_assert(!std::is_same<T, bool>::value,
19886- "FixedValuesGenerator does not support bools because of std::vector<bool>"
19887- "specialization, use SingleValue Generator instead.");
19888- std::vector<T> m_values;
19889- size_t m_idx = 0;
19890- public:
19891- FixedValuesGenerator( std::initializer_list<T> values ) : m_values( values ) {}
19892-
19893- T const& get() const override {
19894- return m_values[m_idx];
19895- }
19896- bool next() override {
19897- ++m_idx;
19898- return m_idx < m_values.size();
19899- }
19900- };
19901-
19902- template <typename T, typename DecayedT = std::decay_t<T>>
19903- GeneratorWrapper<DecayedT> value( T&& value ) {
19904- return GeneratorWrapper<DecayedT>(
19905- Catch::Detail::make_unique<SingleValueGenerator<DecayedT>>(
19906- CATCH_FORWARD( value ) ) );
19907- }
19908- template <typename T>
19909- GeneratorWrapper<T> values(std::initializer_list<T> values) {
19910- return GeneratorWrapper<T>(Catch::Detail::make_unique<FixedValuesGenerator<T>>(values));
19911- }
19912-
19913- template<typename T>
19914- class Generators : public IGenerator<T> {
19915- std::vector<GeneratorWrapper<T>> m_generators;
19916- size_t m_current = 0;
19917-
19918- void add_generator( GeneratorWrapper<T>&& generator ) {
19919- m_generators.emplace_back( CATCH_MOVE( generator ) );
19920- }
19921- void add_generator( T const& val ) {
19922- m_generators.emplace_back( value( val ) );
19923- }
19924- void add_generator( T&& val ) {
19925- m_generators.emplace_back( value( CATCH_MOVE( val ) ) );
19926- }
19927- template <typename U>
19928- std::enable_if_t<!std::is_same<std::decay_t<U>, T>::value>
19929- add_generator( U&& val ) {
19930- add_generator( T( CATCH_FORWARD( val ) ) );
19931- }
19932-
19933- template <typename U> void add_generators( U&& valueOrGenerator ) {
19934- add_generator( CATCH_FORWARD( valueOrGenerator ) );
19935- }
19936-
19937- template <typename U, typename... Gs>
19938- void add_generators( U&& valueOrGenerator, Gs&&... moreGenerators ) {
19939- add_generator( CATCH_FORWARD( valueOrGenerator ) );
19940- add_generators( CATCH_FORWARD( moreGenerators )... );
19941- }
19942-
19943- public:
19944- template <typename... Gs>
19945- Generators(Gs &&... moreGenerators) {
19946- m_generators.reserve(sizeof...(Gs));
19947- add_generators(CATCH_FORWARD(moreGenerators)...);
19948- }
19949-
19950- T const& get() const override {
19951- return m_generators[m_current].get();
19952- }
19953-
19954- bool next() override {
19955- if (m_current >= m_generators.size()) {
19956- return false;
19957- }
19958- const bool current_status = m_generators[m_current].next();
19959- if (!current_status) {
19960- ++m_current;
19961- }
19962- return m_current < m_generators.size();
19963- }
19964- };
19965-
19966-
19967- template <typename... Ts>
19968- GeneratorWrapper<std::tuple<std::decay_t<Ts>...>>
19969- table( std::initializer_list<std::tuple<std::decay_t<Ts>...>> tuples ) {
19970- return values<std::tuple<Ts...>>( tuples );
19971- }
19972-
19973- // Tag type to signal that a generator sequence should convert arguments to a specific type
19974- template <typename T>
19975- struct as {};
19976-
19977- template<typename T, typename... Gs>
19978- auto makeGenerators( GeneratorWrapper<T>&& generator, Gs &&... moreGenerators ) -> Generators<T> {
19979- return Generators<T>(CATCH_MOVE(generator), CATCH_FORWARD(moreGenerators)...);
19980- }
19981- template<typename T>
19982- auto makeGenerators( GeneratorWrapper<T>&& generator ) -> Generators<T> {
19983- return Generators<T>(CATCH_MOVE(generator));
19984- }
19985- template<typename T, typename... Gs>
19986- auto makeGenerators( T&& val, Gs &&... moreGenerators ) -> Generators<std::decay_t<T>> {
19987- return makeGenerators( value( CATCH_FORWARD( val ) ), CATCH_FORWARD( moreGenerators )... );
19988- }
19989- template<typename T, typename U, typename... Gs>
19990- auto makeGenerators( as<T>, U&& val, Gs &&... moreGenerators ) -> Generators<T> {
19991- return makeGenerators( value( T( CATCH_FORWARD( val ) ) ), CATCH_FORWARD( moreGenerators )... );
19992- }
19993-
19994- IGeneratorTracker* acquireGeneratorTracker( StringRef generatorName,
19995- SourceLineInfo const& lineInfo );
19996- IGeneratorTracker* createGeneratorTracker( StringRef generatorName,
19997- SourceLineInfo lineInfo,
19998- GeneratorBasePtr&& generator );
19999-
20000- template<typename L>
20001- auto generate( StringRef generatorName, SourceLineInfo const& lineInfo, L const& generatorExpression ) -> typename decltype(generatorExpression())::type {
20002- using UnderlyingType = typename decltype(generatorExpression())::type;
20003-
20004- IGeneratorTracker* tracker = acquireGeneratorTracker( generatorName, lineInfo );
20005- // Creation of tracker is delayed after generator creation, so
20006- // that constructing generator can fail without breaking everything.
20007- if (!tracker) {
20008- tracker = createGeneratorTracker(
20009- generatorName,
20010- lineInfo,
20011- Catch::Detail::make_unique<Generators<UnderlyingType>>(
20012- generatorExpression() ) );
20013- }
20014-
20015- auto const& generator = static_cast<IGenerator<UnderlyingType> const&>( *tracker->getGenerator() );
20016- return generator.get();
20017- }
20018-
20019-} // namespace Generators
20020-} // namespace Catch
20021-
20022-#define CATCH_INTERNAL_GENERATOR_STRINGIZE_IMPL( ... ) #__VA_ARGS__##_catch_sr
20023-#define CATCH_INTERNAL_GENERATOR_STRINGIZE(...) CATCH_INTERNAL_GENERATOR_STRINGIZE_IMPL(__VA_ARGS__)
20024-
20025-#define GENERATE( ... ) \
20026- Catch::Generators::generate( CATCH_INTERNAL_GENERATOR_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
20027- CATCH_INTERNAL_LINEINFO, \
20028- [ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
20029-#define GENERATE_COPY( ... ) \
20030- Catch::Generators::generate( CATCH_INTERNAL_GENERATOR_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
20031- CATCH_INTERNAL_LINEINFO, \
20032- [=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
20033-#define GENERATE_REF( ... ) \
20034- Catch::Generators::generate( CATCH_INTERNAL_GENERATOR_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
20035- CATCH_INTERNAL_LINEINFO, \
20036- [&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
20037-
20038-#endif // CATCH_GENERATORS_HPP_INCLUDED
20039-
20040-
20041-#ifndef CATCH_GENERATORS_ADAPTERS_HPP_INCLUDED
20042-#define CATCH_GENERATORS_ADAPTERS_HPP_INCLUDED
20043-
20044-
20045-#include <cassert>
20046-
20047-namespace Catch {
20048-namespace Generators {
20049-
20050- template <typename T>
20051- class TakeGenerator final : public IGenerator<T> {
20052- GeneratorWrapper<T> m_generator;
20053- size_t m_returned = 0;
20054- size_t m_target;
20055- public:
20056- TakeGenerator(size_t target, GeneratorWrapper<T>&& generator):
20057- m_generator(CATCH_MOVE(generator)),
20058- m_target(target)
20059- {
20060- assert(target != 0 && "Empty generators are not allowed");
20061- }
20062- T const& get() const override {
20063- return m_generator.get();
20064- }
20065- bool next() override {
20066- ++m_returned;
20067- if (m_returned >= m_target) {
20068- return false;
20069- }
20070-
20071- const auto success = m_generator.next();
20072- // If the underlying generator does not contain enough values
20073- // then we cut short as well
20074- if (!success) {
20075- m_returned = m_target;
20076- }
20077- return success;
20078- }
20079- };
20080-
20081- template <typename T>
20082- GeneratorWrapper<T> take(size_t target, GeneratorWrapper<T>&& generator) {
20083- return GeneratorWrapper<T>(Catch::Detail::make_unique<TakeGenerator<T>>(target, CATCH_MOVE(generator)));
20084- }
20085-
20086-
20087- template <typename T, typename Predicate>
20088- class FilterGenerator final : public IGenerator<T> {
20089- GeneratorWrapper<T> m_generator;
20090- Predicate m_predicate;
20091- static_assert(!std::is_reference<Predicate>::value, "This would most likely result in a dangling reference");
20092- public:
20093- template <typename P>
20094- FilterGenerator(P&& pred, GeneratorWrapper<T>&& generator):
20095- m_generator(CATCH_MOVE(generator)),
20096- m_predicate(CATCH_FORWARD(pred))
20097- {
20098- if (!m_predicate(m_generator.get())) {
20099- // It might happen that there are no values that pass the
20100- // filter. In that case we throw an exception.
20101- auto has_initial_value = next();
20102- if (!has_initial_value) {
20103- Detail::throw_generator_exception("No valid value found in filtered generator");
20104- }
20105- }
20106- }
20107-
20108- T const& get() const override {
20109- return m_generator.get();
20110- }
20111-
20112- bool next() override {
20113- bool success = m_generator.next();
20114- if (!success) {
20115- return false;
20116- }
20117- while (!m_predicate(m_generator.get()) && (success = m_generator.next()) == true);
20118- return success;
20119- }
20120- };
20121-
20122-
20123- template <typename T, typename Predicate>
20124- GeneratorWrapper<T> filter(Predicate&& pred, GeneratorWrapper<T>&& generator) {
20125- return GeneratorWrapper<T>(Catch::Detail::make_unique<FilterGenerator<T, typename std::remove_reference<Predicate>::type>>(CATCH_FORWARD(pred), CATCH_MOVE(generator)));
20126- }
20127-
20128- template <typename T>
20129- class RepeatGenerator final : public IGenerator<T> {
20130- static_assert(!std::is_same<T, bool>::value,
20131- "RepeatGenerator currently does not support bools"
20132- "because of std::vector<bool> specialization");
20133- GeneratorWrapper<T> m_generator;
20134- mutable std::vector<T> m_returned;
20135- size_t m_target_repeats;
20136- size_t m_current_repeat = 0;
20137- size_t m_repeat_index = 0;
20138- public:
20139- RepeatGenerator(size_t repeats, GeneratorWrapper<T>&& generator):
20140- m_generator(CATCH_MOVE(generator)),
20141- m_target_repeats(repeats)
20142- {
20143- assert(m_target_repeats > 0 && "Repeat generator must repeat at least once");
20144- }
20145-
20146- T const& get() const override {
20147- if (m_current_repeat == 0) {
20148- m_returned.push_back(m_generator.get());
20149- return m_returned.back();
20150- }
20151- return m_returned[m_repeat_index];
20152- }
20153-
20154- bool next() override {
20155- // There are 2 basic cases:
20156- // 1) We are still reading the generator
20157- // 2) We are reading our own cache
20158-
20159- // In the first case, we need to poke the underlying generator.
20160- // If it happily moves, we are left in that state, otherwise it is time to start reading from our cache
20161- if (m_current_repeat == 0) {
20162- const auto success = m_generator.next();
20163- if (!success) {
20164- ++m_current_repeat;
20165- }
20166- return m_current_repeat < m_target_repeats;
20167- }
20168-
20169- // In the second case, we need to move indices forward and check that we haven't run up against the end
20170- ++m_repeat_index;
20171- if (m_repeat_index == m_returned.size()) {
20172- m_repeat_index = 0;
20173- ++m_current_repeat;
20174- }
20175- return m_current_repeat < m_target_repeats;
20176- }
20177- };
20178-
20179- template <typename T>
20180- GeneratorWrapper<T> repeat(size_t repeats, GeneratorWrapper<T>&& generator) {
20181- return GeneratorWrapper<T>(Catch::Detail::make_unique<RepeatGenerator<T>>(repeats, CATCH_MOVE(generator)));
20182- }
20183-
20184- template <typename T, typename U, typename Func>
20185- class MapGenerator final : public IGenerator<T> {
20186- // TBD: provide static assert for mapping function, for friendly error message
20187- GeneratorWrapper<U> m_generator;
20188- Func m_function;
20189- // To avoid returning dangling reference, we have to save the values
20190- T m_cache;
20191- public:
20192- template <typename F2 = Func>
20193- MapGenerator(F2&& function, GeneratorWrapper<U>&& generator) :
20194- m_generator(CATCH_MOVE(generator)),
20195- m_function(CATCH_FORWARD(function)),
20196- m_cache(m_function(m_generator.get()))
20197- {}
20198-
20199- T const& get() const override {
20200- return m_cache;
20201- }
20202- bool next() override {
20203- const auto success = m_generator.next();
20204- if (success) {
20205- m_cache = m_function(m_generator.get());
20206- }
20207- return success;
20208- }
20209- };
20210-
20211- template <typename Func, typename U, typename T = FunctionReturnType<Func, U>>
20212- GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) {
20213- return GeneratorWrapper<T>(
20214- Catch::Detail::make_unique<MapGenerator<T, U, Func>>(CATCH_FORWARD(function), CATCH_MOVE(generator))
20215- );
20216- }
20217-
20218- template <typename T, typename U, typename Func>
20219- GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) {
20220- return GeneratorWrapper<T>(
20221- Catch::Detail::make_unique<MapGenerator<T, U, Func>>(CATCH_FORWARD(function), CATCH_MOVE(generator))
20222- );
20223- }
20224-
20225- template <typename T>
20226- class ChunkGenerator final : public IGenerator<std::vector<T>> {
20227- std::vector<T> m_chunk;
20228- size_t m_chunk_size;
20229- GeneratorWrapper<T> m_generator;
20230- bool m_used_up = false;
20231- public:
20232- ChunkGenerator(size_t size, GeneratorWrapper<T> generator) :
20233- m_chunk_size(size), m_generator(CATCH_MOVE(generator))
20234- {
20235- m_chunk.reserve(m_chunk_size);
20236- if (m_chunk_size != 0) {
20237- m_chunk.push_back(m_generator.get());
20238- for (size_t i = 1; i < m_chunk_size; ++i) {
20239- if (!m_generator.next()) {
20240- Detail::throw_generator_exception("Not enough values to initialize the first chunk");
20241- }
20242- m_chunk.push_back(m_generator.get());
20243- }
20244- }
20245- }
20246- std::vector<T> const& get() const override {
20247- return m_chunk;
20248- }
20249- bool next() override {
20250- m_chunk.clear();
20251- for (size_t idx = 0; idx < m_chunk_size; ++idx) {
20252- if (!m_generator.next()) {
20253- return false;
20254- }
20255- m_chunk.push_back(m_generator.get());
20256- }
20257- return true;
20258- }
20259- };
20260-
20261- template <typename T>
20262- GeneratorWrapper<std::vector<T>> chunk(size_t size, GeneratorWrapper<T>&& generator) {
20263- return GeneratorWrapper<std::vector<T>>(
20264- Catch::Detail::make_unique<ChunkGenerator<T>>(size, CATCH_MOVE(generator))
20265- );
20266- }
20267-
20268-} // namespace Generators
20269-} // namespace Catch
20270-
20271-
20272-#endif // CATCH_GENERATORS_ADAPTERS_HPP_INCLUDED
20273-
20274-
20275-#ifndef CATCH_GENERATORS_RANDOM_HPP_INCLUDED
20276-#define CATCH_GENERATORS_RANDOM_HPP_INCLUDED
20277-
20278-
20279-
20280-#ifndef CATCH_RANDOM_NUMBER_GENERATOR_HPP_INCLUDED
20281-#define CATCH_RANDOM_NUMBER_GENERATOR_HPP_INCLUDED
20282-
20283-#include <cstdint>
20284-
20285-namespace Catch {
20286-
20287- // This is a simple implementation of C++11 Uniform Random Number
20288- // Generator. It does not provide all operators, because Catch2
20289- // does not use it, but it should behave as expected inside stdlib's
20290- // distributions.
20291- // The implementation is based on the PCG family (http://pcg-random.org)
20292- class SimplePcg32 {
20293- using state_type = std::uint64_t;
20294- public:
20295- using result_type = std::uint32_t;
20296- static constexpr result_type (min)() {
20297- return 0;
20298- }
20299- static constexpr result_type (max)() {
20300- return static_cast<result_type>(-1);
20301- }
20302-
20303- // Provide some default initial state for the default constructor
20304- SimplePcg32():SimplePcg32(0xed743cc4U) {}
20305-
20306- explicit SimplePcg32(result_type seed_);
20307-
20308- void seed(result_type seed_);
20309- void discard(uint64_t skip);
20310-
20311- result_type operator()();
20312-
20313- private:
20314- friend bool operator==(SimplePcg32 const& lhs, SimplePcg32 const& rhs);
20315- friend bool operator!=(SimplePcg32 const& lhs, SimplePcg32 const& rhs);
20316-
20317- // In theory we also need operator<< and operator>>
20318- // In practice we do not use them, so we will skip them for now
20319-
20320-
20321- std::uint64_t m_state;
20322- // This part of the state determines which "stream" of the numbers
20323- // is chosen -- we take it as a constant for Catch2, so we only
20324- // need to deal with seeding the main state.
20325- // Picked by reading 8 bytes from `/dev/random` :-)
20326- static const std::uint64_t s_inc = (0x13ed0cc53f939476ULL << 1ULL) | 1ULL;
20327- };
20328-
20329-} // end namespace Catch
20330-
20331-#endif // CATCH_RANDOM_NUMBER_GENERATOR_HPP_INCLUDED
20332-
20333-
20334-
20335-#ifndef CATCH_UNIFORM_INTEGER_DISTRIBUTION_HPP_INCLUDED
20336-#define CATCH_UNIFORM_INTEGER_DISTRIBUTION_HPP_INCLUDED
20337-
20338-
20339-
20340-
20341-#ifndef CATCH_RANDOM_INTEGER_HELPERS_HPP_INCLUDED
20342-#define CATCH_RANDOM_INTEGER_HELPERS_HPP_INCLUDED
20343-
20344-#include <climits>
20345-#include <cstddef>
20346-#include <cstdint>
20347-#include <type_traits>
20348-
20349-// Note: We use the usual enable-disable-autodetect dance here even though
20350-// we do not support these in CMake configuration options (yet?).
20351-// It is highly unlikely that we will need to make these actually
20352-// user-configurable, but this will make it simpler if weend up needing
20353-// it, and it provides an escape hatch to the users who need it.
20354-#if defined( __SIZEOF_INT128__ )
20355-# define CATCH_CONFIG_INTERNAL_UINT128
20356-// Unlike GCC, MSVC does not polyfill umul as mulh + mul pair on ARM machines.
20357-// Currently we do not bother doing this ourselves, but we could if it became
20358-// important for perf.
20359-#elif defined( _MSC_VER ) && defined( _M_X64 )
20360-# define CATCH_CONFIG_INTERNAL_MSVC_UMUL128
20361-#endif
20362-
20363-#if defined( CATCH_CONFIG_INTERNAL_UINT128 ) && \
20364- !defined( CATCH_CONFIG_NO_UINT128 ) && \
20365- !defined( CATCH_CONFIG_UINT128 )
20366-#define CATCH_CONFIG_UINT128
20367-#endif
20368-
20369-#if defined( CATCH_CONFIG_INTERNAL_MSVC_UMUL128 ) && \
20370- !defined( CATCH_CONFIG_NO_MSVC_UMUL128 ) && \
20371- !defined( CATCH_CONFIG_MSVC_UMUL128 )
20372-# define CATCH_CONFIG_MSVC_UMUL128
20373-# include <intrin.h>
20374-#endif
20375-
20376-
20377-namespace Catch {
20378- namespace Detail {
20379-
20380- template <std::size_t>
20381- struct SizedUnsignedType;
20382-#define SizedUnsignedTypeHelper( TYPE ) \
20383- template <> \
20384- struct SizedUnsignedType<sizeof( TYPE )> { \
20385- using type = TYPE; \
20386- }
20387-
20388- SizedUnsignedTypeHelper( std::uint8_t );
20389- SizedUnsignedTypeHelper( std::uint16_t );
20390- SizedUnsignedTypeHelper( std::uint32_t );
20391- SizedUnsignedTypeHelper( std::uint64_t );
20392-#undef SizedUnsignedTypeHelper
20393-
20394- template <std::size_t sz>
20395- using SizedUnsignedType_t = typename SizedUnsignedType<sz>::type;
20396-
20397- template <typename T>
20398- using DoubleWidthUnsignedType_t = SizedUnsignedType_t<2 * sizeof( T )>;
20399-
20400- template <typename T>
20401- struct ExtendedMultResult {
20402- T upper;
20403- T lower;
20404- constexpr bool operator==( ExtendedMultResult const& rhs ) const {
20405- return upper == rhs.upper && lower == rhs.lower;
20406- }
20407- };
20408-
20409- /**
20410- * Returns 128 bit result of lhs * rhs using portable C++ code
20411- *
20412- * This implementation is almost twice as fast as naive long multiplication,
20413- * and unlike intrinsic-based approach, it supports constexpr evaluation.
20414- */
20415- constexpr ExtendedMultResult<std::uint64_t>
20416- extendedMultPortable(std::uint64_t lhs, std::uint64_t rhs) {
20417-#define CarryBits( x ) ( x >> 32 )
20418-#define Digits( x ) ( x & 0xFF'FF'FF'FF )
20419- std::uint64_t lhs_low = Digits( lhs );
20420- std::uint64_t rhs_low = Digits( rhs );
20421- std::uint64_t low_low = ( lhs_low * rhs_low );
20422- std::uint64_t high_high = CarryBits( lhs ) * CarryBits( rhs );
20423-
20424- // We add in carry bits from low-low already
20425- std::uint64_t high_low =
20426- ( CarryBits( lhs ) * rhs_low ) + CarryBits( low_low );
20427- // Note that we can add only low bits from high_low, to avoid
20428- // overflow with large inputs
20429- std::uint64_t low_high =
20430- ( lhs_low * CarryBits( rhs ) ) + Digits( high_low );
20431-
20432- return { high_high + CarryBits( high_low ) + CarryBits( low_high ),
20433- ( low_high << 32 ) | Digits( low_low ) };
20434-#undef CarryBits
20435-#undef Digits
20436- }
20437-
20438- //! Returns 128 bit result of lhs * rhs
20439- inline ExtendedMultResult<std::uint64_t>
20440- extendedMult( std::uint64_t lhs, std::uint64_t rhs ) {
20441-#if defined( CATCH_CONFIG_UINT128 )
20442- auto result = __uint128_t( lhs ) * __uint128_t( rhs );
20443- return { static_cast<std::uint64_t>( result >> 64 ),
20444- static_cast<std::uint64_t>( result ) };
20445-#elif defined( CATCH_CONFIG_MSVC_UMUL128 )
20446- std::uint64_t high;
20447- std::uint64_t low = _umul128( lhs, rhs, &high );
20448- return { high, low };
20449-#else
20450- return extendedMultPortable( lhs, rhs );
20451-#endif
20452- }
20453-
20454-
20455- template <typename UInt>
20456- constexpr ExtendedMultResult<UInt> extendedMult( UInt lhs, UInt rhs ) {
20457- static_assert( std::is_unsigned<UInt>::value,
20458- "extendedMult can only handle unsigned integers" );
20459- static_assert( sizeof( UInt ) < sizeof( std::uint64_t ),
20460- "Generic extendedMult can only handle types smaller "
20461- "than uint64_t" );
20462- using WideType = DoubleWidthUnsignedType_t<UInt>;
20463-
20464- auto result = WideType( lhs ) * WideType( rhs );
20465- return {
20466- static_cast<UInt>( result >> ( CHAR_BIT * sizeof( UInt ) ) ),
20467- static_cast<UInt>( result & UInt( -1 ) ) };
20468- }
20469-
20470-
20471- template <typename TargetType,
20472- typename Generator>
20473- std::enable_if_t<sizeof(typename Generator::result_type) >= sizeof(TargetType),
20474- TargetType> fillBitsFrom(Generator& gen) {
20475- using gresult_type = typename Generator::result_type;
20476- static_assert( std::is_unsigned<TargetType>::value, "Only unsigned integers are supported" );
20477- static_assert( Generator::min() == 0 &&
20478- Generator::max() == static_cast<gresult_type>( -1 ),
20479- "Generator must be able to output all numbers in its result type (effectively it must be a random bit generator)" );
20480-
20481- // We want to return the top bits from a generator, as they are
20482- // usually considered higher quality.
20483- constexpr auto generated_bits = sizeof( gresult_type ) * CHAR_BIT;
20484- constexpr auto return_bits = sizeof( TargetType ) * CHAR_BIT;
20485-
20486- return static_cast<TargetType>( gen() >>
20487- ( generated_bits - return_bits) );
20488- }
20489-
20490- template <typename TargetType,
20491- typename Generator>
20492- std::enable_if_t<sizeof(typename Generator::result_type) < sizeof(TargetType),
20493- TargetType> fillBitsFrom(Generator& gen) {
20494- using gresult_type = typename Generator::result_type;
20495- static_assert( std::is_unsigned<TargetType>::value,
20496- "Only unsigned integers are supported" );
20497- static_assert( Generator::min() == 0 &&
20498- Generator::max() == static_cast<gresult_type>( -1 ),
20499- "Generator must be able to output all numbers in its result type (effectively it must be a random bit generator)" );
20500-
20501- constexpr auto generated_bits = sizeof( gresult_type ) * CHAR_BIT;
20502- constexpr auto return_bits = sizeof( TargetType ) * CHAR_BIT;
20503- std::size_t filled_bits = 0;
20504- TargetType ret = 0;
20505- do {
20506- ret <<= generated_bits;
20507- ret |= gen();
20508- filled_bits += generated_bits;
20509- } while ( filled_bits < return_bits );
20510-
20511- return ret;
20512- }
20513-
20514- /*
20515- * Transposes numbers into unsigned type while keeping their ordering
20516- *
20517- * This means that signed types are changed so that the ordering is
20518- * [INT_MIN, ..., -1, 0, ..., INT_MAX], rather than order we would
20519- * get by simple casting ([0, ..., INT_MAX, INT_MIN, ..., -1])
20520- */
20521- template <typename OriginalType, typename UnsignedType>
20522- constexpr
20523- std::enable_if_t<std::is_signed<OriginalType>::value, UnsignedType>
20524- transposeToNaturalOrder( UnsignedType in ) {
20525- static_assert(
20526- sizeof( OriginalType ) == sizeof( UnsignedType ),
20527- "reordering requires the same sized types on both sides" );
20528- static_assert( std::is_unsigned<UnsignedType>::value,
20529- "Input type must be unsigned" );
20530- // Assuming 2s complement (standardized in current C++), the
20531- // positive and negative numbers are already internally ordered,
20532- // and their difference is in the top bit. Swapping it orders
20533- // them the desired way.
20534- constexpr auto highest_bit =
20535- UnsignedType( 1 ) << ( sizeof( UnsignedType ) * CHAR_BIT - 1 );
20536- return static_cast<UnsignedType>( in ^ highest_bit );
20537- }
20538-
20539-
20540-
20541- template <typename OriginalType,
20542- typename UnsignedType>
20543- constexpr
20544- std::enable_if_t<std::is_unsigned<OriginalType>::value, UnsignedType>
20545- transposeToNaturalOrder(UnsignedType in) {
20546- static_assert(
20547- sizeof( OriginalType ) == sizeof( UnsignedType ),
20548- "reordering requires the same sized types on both sides" );
20549- static_assert( std::is_unsigned<UnsignedType>::value, "Input type must be unsigned" );
20550- // No reordering is needed for unsigned -> unsigned
20551- return in;
20552- }
20553- } // namespace Detail
20554-} // namespace Catch
20555-
20556-#endif // CATCH_RANDOM_INTEGER_HELPERS_HPP_INCLUDED
20557-
20558-namespace Catch {
20559-
20560-/**
20561- * Implementation of uniform distribution on integers.
20562- *
20563- * Unlike `std::uniform_int_distribution`, this implementation supports
20564- * various 1 byte integral types, including bool (but you should not
20565- * actually use it for bools).
20566- *
20567- * The underlying algorithm is based on the one described in "Fast Random
20568- * Integer Generation in an Interval" by Daniel Lemire, but has been
20569- * optimized under the assumption of reuse of the same distribution object.
20570- */
20571-template <typename IntegerType>
20572-class uniform_integer_distribution {
20573- static_assert(std::is_integral<IntegerType>::value, "...");
20574-
20575- using UnsignedIntegerType = Detail::SizedUnsignedType_t<sizeof(IntegerType)>;
20576-
20577- // Only the left bound is stored, and we store it converted to its
20578- // unsigned image. This avoids having to do the conversions inside
20579- // the operator(), at the cost of having to do the conversion in
20580- // the a() getter. The right bound is only needed in the b() getter,
20581- // so we recompute it there from other stored data.
20582- UnsignedIntegerType m_a;
20583-
20584- // How many different values are there in [a, b]. a == b => 1, can be 0 for distribution over all values in the type.
20585- UnsignedIntegerType m_ab_distance;
20586-
20587- // We hoisted this out of the main generation function. Technically,
20588- // this means that using this distribution will be slower than Lemire's
20589- // algorithm if this distribution instance will be used only few times,
20590- // but it will be faster if it is used many times. Since Catch2 uses
20591- // distributions only to implement random generators, we assume that each
20592- // distribution will be reused many times and this is an optimization.
20593- UnsignedIntegerType m_rejection_threshold = 0;
20594-
20595- static constexpr UnsignedIntegerType computeDistance(IntegerType a, IntegerType b) {
20596- // This overflows and returns 0 if a == 0 and b == TYPE_MAX.
20597- // We handle that later when generating the number.
20598- return transposeTo(b) - transposeTo(a) + 1;
20599- }
20600-
20601- static constexpr UnsignedIntegerType computeRejectionThreshold(UnsignedIntegerType ab_distance) {
20602- // distance == 0 means that we will return all possible values from
20603- // the type's range, and that we shouldn't reject anything.
20604- if ( ab_distance == 0 ) { return 0; }
20605- return ( ~ab_distance + 1 ) % ab_distance;
20606- }
20607-
20608- static constexpr UnsignedIntegerType transposeTo(IntegerType in) {
20609- return Detail::transposeToNaturalOrder<IntegerType>(
20610- static_cast<UnsignedIntegerType>( in ) );
20611- }
20612- static constexpr IntegerType transposeBack(UnsignedIntegerType in) {
20613- return static_cast<IntegerType>(
20614- Detail::transposeToNaturalOrder<IntegerType>(in) );
20615- }
20616-
20617-public:
20618- using result_type = IntegerType;
20619-
20620- constexpr uniform_integer_distribution( IntegerType a, IntegerType b ):
20621- m_a( transposeTo(a) ),
20622- m_ab_distance( computeDistance(a, b) ),
20623- m_rejection_threshold( computeRejectionThreshold(m_ab_distance) ) {
20624- assert( a <= b );
20625- }
20626-
20627- template <typename Generator>
20628- constexpr result_type operator()( Generator& g ) {
20629- // All possible values of result_type are valid.
20630- if ( m_ab_distance == 0 ) {
20631- return transposeBack( Detail::fillBitsFrom<UnsignedIntegerType>( g ) );
20632- }
20633-
20634- auto random_number = Detail::fillBitsFrom<UnsignedIntegerType>( g );
20635- auto emul = Detail::extendedMult( random_number, m_ab_distance );
20636- // Unlike Lemire's algorithm we skip the ab_distance check, since
20637- // we precomputed the rejection threshold, which is always tighter.
20638- while (emul.lower < m_rejection_threshold) {
20639- random_number = Detail::fillBitsFrom<UnsignedIntegerType>( g );
20640- emul = Detail::extendedMult( random_number, m_ab_distance );
20641- }
20642-
20643- return transposeBack(m_a + emul.upper);
20644- }
20645-
20646- constexpr result_type a() const { return transposeBack(m_a); }
20647- constexpr result_type b() const { return transposeBack(m_ab_distance + m_a - 1); }
20648-};
20649-
20650-} // end namespace Catch
20651-
20652-#endif // CATCH_UNIFORM_INTEGER_DISTRIBUTION_HPP_INCLUDED
20653-
20654-
20655-
20656-#ifndef CATCH_UNIFORM_FLOATING_POINT_DISTRIBUTION_HPP_INCLUDED
20657-#define CATCH_UNIFORM_FLOATING_POINT_DISTRIBUTION_HPP_INCLUDED
20658-
20659-
20660-
20661-
20662-#ifndef CATCH_RANDOM_FLOATING_POINT_HELPERS_HPP_INCLUDED
20663-#define CATCH_RANDOM_FLOATING_POINT_HELPERS_HPP_INCLUDED
20664-
20665-
20666-
20667-#ifndef CATCH_POLYFILLS_HPP_INCLUDED
20668-#define CATCH_POLYFILLS_HPP_INCLUDED
20669-
20670-namespace Catch {
20671-
20672- bool isnan(float f);
20673- bool isnan(double d);
20674-
20675- float nextafter(float x, float y);
20676- double nextafter(double x, double y);
20677-
20678-}
20679-
20680-#endif // CATCH_POLYFILLS_HPP_INCLUDED
20681-
20682-#include <cassert>
20683-#include <cmath>
20684-#include <cstdint>
20685-#include <limits>
20686-#include <type_traits>
20687-
20688-namespace Catch {
20689-
20690- namespace Detail {
20691- /**
20692- * Returns the largest magnitude of 1-ULP distance inside the [a, b] range.
20693- *
20694- * Assumes `a < b`.
20695- */
20696- template <typename FloatType>
20697- FloatType gamma(FloatType a, FloatType b) {
20698- static_assert( std::is_floating_point<FloatType>::value,
20699- "gamma returns the largest ULP magnitude within "
20700- "floating point range [a, b]. This only makes sense "
20701- "for floating point types" );
20702- assert( a <= b );
20703-
20704- const auto gamma_up = Catch::nextafter( a, std::numeric_limits<FloatType>::infinity() ) - a;
20705- const auto gamma_down = b - Catch::nextafter( b, -std::numeric_limits<FloatType>::infinity() );
20706-
20707- return gamma_up < gamma_down ? gamma_down : gamma_up;
20708- }
20709-
20710- template <typename FloatingPoint>
20711- struct DistanceTypePicker;
20712- template <>
20713- struct DistanceTypePicker<float> {
20714- using type = std::uint32_t;
20715- };
20716- template <>
20717- struct DistanceTypePicker<double> {
20718- using type = std::uint64_t;
20719- };
20720-
20721- template <typename T>
20722- using DistanceType = typename DistanceTypePicker<T>::type;
20723-
20724-#if defined( __GNUC__ ) || defined( __clang__ )
20725-# pragma GCC diagnostic push
20726-# pragma GCC diagnostic ignored "-Wfloat-equal"
20727-#endif
20728- /**
20729- * Computes the number of equi-distant floats in [a, b]
20730- *
20731- * Since not every range can be split into equidistant floats
20732- * exactly, we actually compute ceil(b/distance - a/distance),
20733- * because in those cases we want to overcount.
20734- *
20735- * Uses modified Dekker's FastTwoSum algorithm to handle rounding.
20736- */
20737- template <typename FloatType>
20738- DistanceType<FloatType>
20739- count_equidistant_floats( FloatType a, FloatType b, FloatType distance ) {
20740- assert( a <= b );
20741- // We get distance as gamma for our uniform float distribution,
20742- // so this will round perfectly.
20743- const auto ag = a / distance;
20744- const auto bg = b / distance;
20745-
20746- const auto s = bg - ag;
20747- const auto err = ( std::fabs( a ) <= std::fabs( b ) )
20748- ? -ag - ( s - bg )
20749- : bg - ( s + ag );
20750- const auto ceil_s = static_cast<DistanceType<FloatType>>( std::ceil( s ) );
20751-
20752- return ( ceil_s != s ) ? ceil_s : ceil_s + ( err > 0 );
20753- }
20754-#if defined( __GNUC__ ) || defined( __clang__ )
20755-# pragma GCC diagnostic pop
20756-#endif
20757-
20758- }
20759-
20760-} // end namespace Catch
20761-
20762-#endif // CATCH_RANDOM_FLOATING_POINT_HELPERS_HPP_INCLUDED
20763-
20764-#include <cmath>
20765-#include <type_traits>
20766-
20767-namespace Catch {
20768-
20769- namespace Detail {
20770-#if defined( __GNUC__ ) || defined( __clang__ )
20771-# pragma GCC diagnostic push
20772-# pragma GCC diagnostic ignored "-Wfloat-equal"
20773-#endif
20774- // The issue with overflow only happens with maximal ULP and HUGE
20775- // distance, e.g. when generating numbers in [-inf, inf] for given
20776- // type. So we only check for the largest possible ULP in the
20777- // type, and return something that does not overflow to inf in 1 mult.
20778- constexpr std::uint64_t calculate_max_steps_in_one_go(double gamma) {
20779- if ( gamma == 1.99584030953472e+292 ) { return 9007199254740991; }
20780- return static_cast<std::uint64_t>( -1 );
20781- }
20782- constexpr std::uint32_t calculate_max_steps_in_one_go(float gamma) {
20783- if ( gamma == 2.028241e+31f ) { return 16777215; }
20784- return static_cast<std::uint32_t>( -1 );
20785- }
20786-#if defined( __GNUC__ ) || defined( __clang__ )
20787-# pragma GCC diagnostic pop
20788-#endif
20789- }
20790-
20791-/**
20792- * Implementation of uniform distribution on floating point numbers.
20793- *
20794- * Note that we support only `float` and `double` types, because these
20795- * usually mean the same thing across different platform. `long double`
20796- * varies wildly by platform and thus we cannot provide reproducible
20797- * implementation. Also note that we don't implement all parts of
20798- * distribution per standard: this distribution is not serializable, nor
20799- * can the range be arbitrarily reset.
20800- *
20801- * The implementation also uses different approach than the one taken by
20802- * `std::uniform_real_distribution`, where instead of generating a number
20803- * between [0, 1) and then multiplying the range bounds with it, we first
20804- * split the [a, b] range into a set of equidistributed floating point
20805- * numbers, and then use uniform int distribution to pick which one to
20806- * return.
20807- *
20808- * This has the advantage of guaranteeing uniformity (the multiplication
20809- * method loses uniformity due to rounding when multiplying floats), except
20810- * for small non-uniformity at one side of the interval, where we have
20811- * to deal with the fact that not every interval is splittable into
20812- * equidistributed floats.
20813- *
20814- * Based on "Drawing random floating-point numbers from an interval" by
20815- * Frederic Goualard.
20816- */
20817-template <typename FloatType>
20818-class uniform_floating_point_distribution {
20819- static_assert(std::is_floating_point<FloatType>::value, "...");
20820- static_assert(!std::is_same<FloatType, long double>::value,
20821- "We do not support long double due to inconsistent behaviour between platforms");
20822-
20823- using WidthType = Detail::DistanceType<FloatType>;
20824-
20825- FloatType m_a, m_b;
20826- FloatType m_ulp_magnitude;
20827- WidthType m_floats_in_range;
20828- uniform_integer_distribution<WidthType> m_int_dist;
20829-
20830- // In specific cases, we can overflow into `inf` when computing the
20831- // `steps * g` offset. To avoid this, we don't offset by more than this
20832- // in one multiply + addition.
20833- WidthType m_max_steps_in_one_go;
20834- // We don't want to do the magnitude check every call to `operator()`
20835- bool m_a_has_leq_magnitude;
20836-
20837-public:
20838- using result_type = FloatType;
20839-
20840- uniform_floating_point_distribution( FloatType a, FloatType b ):
20841- m_a( a ),
20842- m_b( b ),
20843- m_ulp_magnitude( Detail::gamma( m_a, m_b ) ),
20844- m_floats_in_range( Detail::count_equidistant_floats( m_a, m_b, m_ulp_magnitude ) ),
20845- m_int_dist(0, m_floats_in_range),
20846- m_max_steps_in_one_go( Detail::calculate_max_steps_in_one_go(m_ulp_magnitude)),
20847- m_a_has_leq_magnitude(std::fabs(m_a) <= std::fabs(m_b))
20848- {
20849- assert( a <= b );
20850- }
20851-
20852- template <typename Generator>
20853- result_type operator()( Generator& g ) {
20854- WidthType steps = m_int_dist( g );
20855- if ( m_a_has_leq_magnitude ) {
20856- if ( steps == m_floats_in_range ) { return m_a; }
20857- auto b = m_b;
20858- while (steps > m_max_steps_in_one_go) {
20859- b -= m_max_steps_in_one_go * m_ulp_magnitude;
20860- steps -= m_max_steps_in_one_go;
20861- }
20862- return b - steps * m_ulp_magnitude;
20863- } else {
20864- if ( steps == m_floats_in_range ) { return m_b; }
20865- auto a = m_a;
20866- while (steps > m_max_steps_in_one_go) {
20867- a += m_max_steps_in_one_go * m_ulp_magnitude;
20868- steps -= m_max_steps_in_one_go;
20869- }
20870- return a + steps * m_ulp_magnitude;
20871- }
20872- }
20873-
20874- result_type a() const { return m_a; }
20875- result_type b() const { return m_b; }
20876-};
20877-
20878-} // end namespace Catch
20879-
20880-#endif // CATCH_UNIFORM_FLOATING_POINT_DISTRIBUTION_HPP_INCLUDED
20881-
20882-namespace Catch {
20883-namespace Generators {
20884-namespace Detail {
20885- // Returns a suitable seed for a random floating generator based off
20886- // the primary internal rng. It does so by taking current value from
20887- // the rng and returning it as the seed.
20888- std::uint32_t getSeed();
20889-}
20890-
20891-template <typename Float>
20892-class RandomFloatingGenerator final : public IGenerator<Float> {
20893- Catch::SimplePcg32 m_rng;
20894- Catch::uniform_floating_point_distribution<Float> m_dist;
20895- Float m_current_number;
20896-public:
20897- RandomFloatingGenerator( Float a, Float b, std::uint32_t seed ):
20898- m_rng(seed),
20899- m_dist(a, b) {
20900- static_cast<void>(next());
20901- }
20902-
20903- Float const& get() const override {
20904- return m_current_number;
20905- }
20906- bool next() override {
20907- m_current_number = m_dist(m_rng);
20908- return true;
20909- }
20910-};
20911-
20912-template <>
20913-class RandomFloatingGenerator<long double> final : public IGenerator<long double> {
20914- // We still rely on <random> for this specialization, but we don't
20915- // want to drag it into the header.
20916- struct PImpl;
20917- Catch::Detail::unique_ptr<PImpl> m_pimpl;
20918- long double m_current_number;
20919-
20920-public:
20921- RandomFloatingGenerator( long double a, long double b, std::uint32_t seed );
20922-
20923- long double const& get() const override { return m_current_number; }
20924- bool next() override;
20925-
20926- ~RandomFloatingGenerator() override; // = default
20927-};
20928-
20929-template <typename Integer>
20930-class RandomIntegerGenerator final : public IGenerator<Integer> {
20931- Catch::SimplePcg32 m_rng;
20932- Catch::uniform_integer_distribution<Integer> m_dist;
20933- Integer m_current_number;
20934-public:
20935- RandomIntegerGenerator( Integer a, Integer b, std::uint32_t seed ):
20936- m_rng(seed),
20937- m_dist(a, b) {
20938- static_cast<void>(next());
20939- }
20940-
20941- Integer const& get() const override {
20942- return m_current_number;
20943- }
20944- bool next() override {
20945- m_current_number = m_dist(m_rng);
20946- return true;
20947- }
20948-};
20949-
20950-template <typename T>
20951-std::enable_if_t<std::is_integral<T>::value, GeneratorWrapper<T>>
20952-random(T a, T b) {
20953- return GeneratorWrapper<T>(
20954- Catch::Detail::make_unique<RandomIntegerGenerator<T>>(a, b, Detail::getSeed())
20955- );
20956-}
20957-
20958-template <typename T>
20959-std::enable_if_t<std::is_floating_point<T>::value,
20960-GeneratorWrapper<T>>
20961-random(T a, T b) {
20962- return GeneratorWrapper<T>(
20963- Catch::Detail::make_unique<RandomFloatingGenerator<T>>(a, b, Detail::getSeed())
20964- );
20965-}
20966-
20967-
20968-} // namespace Generators
20969-} // namespace Catch
20970-
20971-
20972-#endif // CATCH_GENERATORS_RANDOM_HPP_INCLUDED
20973-
20974-
20975-#ifndef CATCH_GENERATORS_RANGE_HPP_INCLUDED
20976-#define CATCH_GENERATORS_RANGE_HPP_INCLUDED
20977-
20978-
20979-#include <iterator>
20980-#include <type_traits>
20981-
20982-namespace Catch {
20983-namespace Generators {
20984-
20985-
20986-template <typename T>
20987-class RangeGenerator final : public IGenerator<T> {
20988- T m_current;
20989- T m_end;
20990- T m_step;
20991- bool m_positive;
20992-
20993-public:
20994- RangeGenerator(T const& start, T const& end, T const& step):
20995- m_current(start),
20996- m_end(end),
20997- m_step(step),
20998- m_positive(m_step > T(0))
20999- {
21000- assert(m_current != m_end && "Range start and end cannot be equal");
21001- assert(m_step != T(0) && "Step size cannot be zero");
21002- assert(((m_positive && m_current <= m_end) || (!m_positive && m_current >= m_end)) && "Step moves away from end");
21003- }
21004-
21005- RangeGenerator(T const& start, T const& end):
21006- RangeGenerator(start, end, (start < end) ? T(1) : T(-1))
21007- {}
21008-
21009- T const& get() const override {
21010- return m_current;
21011- }
21012-
21013- bool next() override {
21014- m_current += m_step;
21015- return (m_positive) ? (m_current < m_end) : (m_current > m_end);
21016- }
21017-};
21018-
21019-template <typename T>
21020-GeneratorWrapper<T> range(T const& start, T const& end, T const& step) {
21021- static_assert(std::is_arithmetic<T>::value && !std::is_same<T, bool>::value, "Type must be numeric");
21022- return GeneratorWrapper<T>(Catch::Detail::make_unique<RangeGenerator<T>>(start, end, step));
21023-}
21024-
21025-template <typename T>
21026-GeneratorWrapper<T> range(T const& start, T const& end) {
21027- static_assert(std::is_integral<T>::value && !std::is_same<T, bool>::value, "Type must be an integer");
21028- return GeneratorWrapper<T>(Catch::Detail::make_unique<RangeGenerator<T>>(start, end));
21029-}
21030-
21031-
21032-template <typename T>
21033-class IteratorGenerator final : public IGenerator<T> {
21034- static_assert(!std::is_same<T, bool>::value,
21035- "IteratorGenerator currently does not support bools"
21036- "because of std::vector<bool> specialization");
21037-
21038- std::vector<T> m_elems;
21039- size_t m_current = 0;
21040-public:
21041- template <typename InputIterator, typename InputSentinel>
21042- IteratorGenerator(InputIterator first, InputSentinel last):m_elems(first, last) {
21043- if (m_elems.empty()) {
21044- Detail::throw_generator_exception("IteratorGenerator received no valid values");
21045- }
21046- }
21047-
21048- T const& get() const override {
21049- return m_elems[m_current];
21050- }
21051-
21052- bool next() override {
21053- ++m_current;
21054- return m_current != m_elems.size();
21055- }
21056-};
21057-
21058-template <typename InputIterator,
21059- typename InputSentinel,
21060- typename ResultType = std::remove_const_t<typename std::iterator_traits<InputIterator>::value_type>>
21061-GeneratorWrapper<ResultType> from_range(InputIterator from, InputSentinel to) {
21062- return GeneratorWrapper<ResultType>(Catch::Detail::make_unique<IteratorGenerator<ResultType>>(from, to));
21063-}
21064-
21065-template <typename Container>
21066-auto from_range(Container const& cnt) {
21067- using std::begin;
21068- using std::end;
21069- return from_range( begin( cnt ), end( cnt ) );
21070-}
21071-
21072-
21073-} // namespace Generators
21074-} // namespace Catch
21075-
21076-
21077-#endif // CATCH_GENERATORS_RANGE_HPP_INCLUDED
21078-
21079-#endif // CATCH_GENERATORS_ALL_HPP_INCLUDED
21080-
21081-
21082-/** \file
21083- * This is a convenience header for Catch2's interfaces. It includes
21084- * **all** of Catch2 headers related to interfaces.
21085- *
21086- * Generally the Catch2 users should use specific includes they need,
21087- * but this header can be used instead for ease-of-experimentation, or
21088- * just plain convenience, at the cost of somewhat increased compilation
21089- * times.
21090- *
21091- * When a new header is added to either the `interfaces` folder, or to
21092- * the corresponding internal subfolder, it should be added here.
21093- */
21094-
21095-
21096-#ifndef CATCH_INTERFACES_ALL_HPP_INCLUDED
21097-#define CATCH_INTERFACES_ALL_HPP_INCLUDED
21098-
21099-
21100-
21101-#ifndef CATCH_INTERFACES_REPORTER_HPP_INCLUDED
21102-#define CATCH_INTERFACES_REPORTER_HPP_INCLUDED
21103-
21104-
21105-#include <map>
21106-#include <string>
21107-#include <vector>
21108-
21109-namespace Catch {
21110-
21111- struct ReporterDescription;
21112- struct ListenerDescription;
21113- struct TagInfo;
21114- struct TestCaseInfo;
21115- class TestCaseHandle;
21116- class IConfig;
21117- class IStream;
21118- enum class ColourMode : std::uint8_t;
21119-
21120- struct ReporterConfig {
21121- ReporterConfig( IConfig const* _fullConfig,
21122- Detail::unique_ptr<IStream> _stream,
21123- ColourMode colourMode,
21124- std::map<std::string, std::string> customOptions );
21125-
21126- ReporterConfig( ReporterConfig&& ) = default;
21127- ReporterConfig& operator=( ReporterConfig&& ) = default;
21128- ~ReporterConfig(); // = default
21129-
21130- Detail::unique_ptr<IStream> takeStream() &&;
21131- IConfig const* fullConfig() const;
21132- ColourMode colourMode() const;
21133- std::map<std::string, std::string> const& customOptions() const;
21134-
21135- private:
21136- Detail::unique_ptr<IStream> m_stream;
21137- IConfig const* m_fullConfig;
21138- ColourMode m_colourMode;
21139- std::map<std::string, std::string> m_customOptions;
21140- };
21141-
21142- struct AssertionStats {
21143- AssertionStats( AssertionResult const& _assertionResult,
21144- std::vector<MessageInfo> const& _infoMessages,
21145- Totals const& _totals );
21146-
21147- AssertionStats( AssertionStats const& ) = default;
21148- AssertionStats( AssertionStats && ) = default;
21149- AssertionStats& operator = ( AssertionStats const& ) = delete;
21150- AssertionStats& operator = ( AssertionStats && ) = delete;
21151-
21152- AssertionResult assertionResult;
21153- std::vector<MessageInfo> infoMessages;
21154- Totals totals;
21155- };
21156-
21157- struct SectionStats {
21158- SectionStats( SectionInfo&& _sectionInfo,
21159- Counts const& _assertions,
21160- double _durationInSeconds,
21161- bool _missingAssertions );
21162-
21163- SectionInfo sectionInfo;
21164- Counts assertions;
21165- double durationInSeconds;
21166- bool missingAssertions;
21167- };
21168-
21169- struct TestCaseStats {
21170- TestCaseStats( TestCaseInfo const& _testInfo,
21171- Totals const& _totals,
21172- std::string&& _stdOut,
21173- std::string&& _stdErr,
21174- bool _aborting );
21175-
21176- TestCaseInfo const * testInfo;
21177- Totals totals;
21178- std::string stdOut;
21179- std::string stdErr;
21180- bool aborting;
21181- };
21182-
21183- struct TestRunStats {
21184- TestRunStats( TestRunInfo const& _runInfo,
21185- Totals const& _totals,
21186- bool _aborting );
21187-
21188- TestRunInfo runInfo;
21189- Totals totals;
21190- bool aborting;
21191- };
21192-
21193- //! By setting up its preferences, a reporter can modify Catch2's behaviour
21194- //! in some regards, e.g. it can request Catch2 to capture writes to
21195- //! stdout/stderr during test execution, and pass them to the reporter.
21196- struct ReporterPreferences {
21197- //! Catch2 should redirect writes to stdout and pass them to the
21198- //! reporter
21199- bool shouldRedirectStdOut = false;
21200- //! Catch2 should call `Reporter::assertionEnded` even for passing
21201- //! assertions
21202- bool shouldReportAllAssertions = false;
21203- //! Catch2 should call `Reporter::assertionStarting` for all assertions
21204- // Defaults to true for backwards compatibility, but none of our current
21205- // reporters actually want this, and it enables a fast path in assertion
21206- // handling.
21207- bool shouldReportAllAssertionStarts = true;
21208- };
21209-
21210- /**
21211- * The common base for all reporters and event listeners
21212- *
21213- * Implementing classes must also implement:
21214- *
21215- * //! User-friendly description of the reporter/listener type
21216- * static std::string getDescription()
21217- *
21218- * Generally shouldn't be derived from by users of Catch2 directly,
21219- * instead they should derive from one of the utility bases that
21220- * derive from this class.
21221- */
21222- class IEventListener {
21223- protected:
21224- //! Derived classes can set up their preferences here
21225- ReporterPreferences m_preferences;
21226- //! The test run's config as filled in from CLI and defaults
21227- IConfig const* m_config;
21228-
21229- public:
21230- IEventListener( IConfig const* config ): m_config( config ) {}
21231-
21232- virtual ~IEventListener(); // = default;
21233-
21234- // Implementing class must also provide the following static methods:
21235- // static std::string getDescription();
21236-
21237- ReporterPreferences const& getPreferences() const {
21238- return m_preferences;
21239- }
21240-
21241- //! Called when no test cases match provided test spec
21242- virtual void noMatchingTestCases( StringRef unmatchedSpec ) = 0;
21243- //! Called for all invalid test specs from the cli
21244- virtual void reportInvalidTestSpec( StringRef invalidArgument ) = 0;
21245-
21246- /**
21247- * Called once in a testing run before tests are started
21248- *
21249- * Not called if tests won't be run (e.g. only listing will happen)
21250- */
21251- virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0;
21252-
21253- //! Called _once_ for each TEST_CASE, no matter how many times it is entered
21254- virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0;
21255- //! Called _every time_ a TEST_CASE is entered, including repeats (due to sections)
21256- virtual void testCasePartialStarting( TestCaseInfo const& testInfo, uint64_t partNumber ) = 0;
21257- //! Called when a `SECTION` is being entered. Not called for skipped sections
21258- virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0;
21259-
21260- //! Called when user-code is being probed before the actual benchmark runs
21261- virtual void benchmarkPreparing( StringRef benchmarkName ) = 0;
21262- //! Called after probe but before the user-code is being benchmarked
21263- virtual void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) = 0;
21264- //! Called with the benchmark results if benchmark successfully finishes
21265- virtual void benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) = 0;
21266- //! Called if running the benchmarks fails for any reason
21267- virtual void benchmarkFailed( StringRef benchmarkName ) = 0;
21268-
21269- //! Called before assertion success/failure is evaluated
21270- virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0;
21271-
21272- //! Called after assertion was fully evaluated
21273- virtual void assertionEnded( AssertionStats const& assertionStats ) = 0;
21274-
21275- //! Called after a `SECTION` has finished running
21276- virtual void sectionEnded( SectionStats const& sectionStats ) = 0;
21277- //! Called _every time_ a TEST_CASE is entered, including repeats (due to sections)
21278- virtual void testCasePartialEnded(TestCaseStats const& testCaseStats, uint64_t partNumber ) = 0;
21279- //! Called _once_ for each TEST_CASE, no matter how many times it is entered
21280- virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0;
21281- /**
21282- * Called once after all tests in a testing run are finished
21283- *
21284- * Not called if tests weren't run (e.g. only listings happened)
21285- */
21286- virtual void testRunEnded( TestRunStats const& testRunStats ) = 0;
21287-
21288- /**
21289- * Called with test cases that are skipped due to the test run aborting.
21290- * NOT called for test cases that are explicitly skipped using the `SKIP` macro.
21291- *
21292- * Deprecated - will be removed in the next major release.
21293- */
21294- virtual void skipTest( TestCaseInfo const& testInfo ) = 0;
21295-
21296- //! Called if a fatal error (signal/structured exception) occurred
21297- virtual void fatalErrorEncountered( StringRef error ) = 0;
21298-
21299- //! Writes out information about provided reporters using reporter-specific format
21300- virtual void listReporters(std::vector<ReporterDescription> const& descriptions) = 0;
21301- //! Writes out the provided listeners descriptions using reporter-specific format
21302- virtual void listListeners(std::vector<ListenerDescription> const& descriptions) = 0;
21303- //! Writes out information about provided tests using reporter-specific format
21304- virtual void listTests(std::vector<TestCaseHandle> const& tests) = 0;
21305- //! Writes out information about the provided tags using reporter-specific format
21306- virtual void listTags(std::vector<TagInfo> const& tags) = 0;
21307- };
21308- using IEventListenerPtr = Detail::unique_ptr<IEventListener>;
21309-
21310-} // end namespace Catch
21311-
21312-#endif // CATCH_INTERFACES_REPORTER_HPP_INCLUDED
21313-
21314-
21315-#ifndef CATCH_INTERFACES_REPORTER_FACTORY_HPP_INCLUDED
21316-#define CATCH_INTERFACES_REPORTER_FACTORY_HPP_INCLUDED
21317-
21318-
21319-#include <string>
21320-
21321-namespace Catch {
21322-
21323- struct ReporterConfig;
21324- class IConfig;
21325- class IEventListener;
21326- using IEventListenerPtr = Detail::unique_ptr<IEventListener>;
21327-
21328-
21329- class IReporterFactory {
21330- public:
21331- virtual ~IReporterFactory(); // = default
21332-
21333- virtual IEventListenerPtr
21334- create( ReporterConfig&& config ) const = 0;
21335- virtual std::string getDescription() const = 0;
21336- };
21337- using IReporterFactoryPtr = Detail::unique_ptr<IReporterFactory>;
21338-
21339- class EventListenerFactory {
21340- public:
21341- virtual ~EventListenerFactory(); // = default
21342- virtual IEventListenerPtr create( IConfig const* config ) const = 0;
21343- //! Return a meaningful name for the listener, e.g. its type name
21344- virtual StringRef getName() const = 0;
21345- //! Return listener's description if available
21346- virtual std::string getDescription() const = 0;
21347- };
21348-} // namespace Catch
21349-
21350-#endif // CATCH_INTERFACES_REPORTER_FACTORY_HPP_INCLUDED
21351-
21352-
21353-#ifndef CATCH_INTERFACES_TAG_ALIAS_REGISTRY_HPP_INCLUDED
21354-#define CATCH_INTERFACES_TAG_ALIAS_REGISTRY_HPP_INCLUDED
21355-
21356-#include <string>
21357-
21358-namespace Catch {
21359-
21360- struct TagAlias;
21361-
21362- class ITagAliasRegistry {
21363- public:
21364- virtual ~ITagAliasRegistry(); // = default
21365- // Nullptr if not present
21366- virtual TagAlias const* find( std::string const& alias ) const = 0;
21367- virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0;
21368-
21369- static ITagAliasRegistry const& get();
21370- };
21371-
21372-} // end namespace Catch
21373-
21374-#endif // CATCH_INTERFACES_TAG_ALIAS_REGISTRY_HPP_INCLUDED
21375-
21376-
21377-#ifndef CATCH_INTERFACES_TESTCASE_HPP_INCLUDED
21378-#define CATCH_INTERFACES_TESTCASE_HPP_INCLUDED
21379-
21380-#include <vector>
21381-
21382-namespace Catch {
21383-
21384- struct TestCaseInfo;
21385- class TestCaseHandle;
21386- class IConfig;
21387-
21388- class ITestCaseRegistry {
21389- public:
21390- virtual ~ITestCaseRegistry(); // = default
21391- // TODO: this exists only for adding filenames to test cases -- let's expose this in a saner way later
21392- virtual std::vector<TestCaseInfo* > const& getAllInfos() const = 0;
21393- virtual std::vector<TestCaseHandle> const& getAllTests() const = 0;
21394- virtual std::vector<TestCaseHandle> const& getAllTestsSorted( IConfig const& config ) const = 0;
21395- };
21396-
21397-}
21398-
21399-#endif // CATCH_INTERFACES_TESTCASE_HPP_INCLUDED
21400-
21401-#endif // CATCH_INTERFACES_ALL_HPP_INCLUDED
21402-
21403-
21404-#ifndef CATCH_CASE_INSENSITIVE_COMPARISONS_HPP_INCLUDED
21405-#define CATCH_CASE_INSENSITIVE_COMPARISONS_HPP_INCLUDED
21406-
21407-
21408-namespace Catch {
21409- namespace Detail {
21410- //! Provides case-insensitive `op<` semantics when called
21411- struct CaseInsensitiveLess {
21412- bool operator()( StringRef lhs,
21413- StringRef rhs ) const;
21414- };
21415-
21416- //! Provides case-insensitive `op==` semantics when called
21417- struct CaseInsensitiveEqualTo {
21418- bool operator()( StringRef lhs,
21419- StringRef rhs ) const;
21420- };
21421-
21422- } // namespace Detail
21423-} // namespace Catch
21424-
21425-#endif // CATCH_CASE_INSENSITIVE_COMPARISONS_HPP_INCLUDED
21426-
21427-
21428-
21429-/** \file
21430- * Wrapper for ANDROID_LOGWRITE configuration option
21431- *
21432- * We want to default to enabling it when compiled for android, but
21433- * users of the library should also be able to disable it if they want
21434- * to.
21435- */
21436-
21437-#ifndef CATCH_CONFIG_ANDROID_LOGWRITE_HPP_INCLUDED
21438-#define CATCH_CONFIG_ANDROID_LOGWRITE_HPP_INCLUDED
21439-
21440-
21441-#if defined(__ANDROID__)
21442-# define CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE
21443-#endif
21444-
21445-
21446-#if defined( CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE ) && \
21447- !defined( CATCH_CONFIG_NO_ANDROID_LOGWRITE ) && \
21448- !defined( CATCH_CONFIG_ANDROID_LOGWRITE )
21449-# define CATCH_CONFIG_ANDROID_LOGWRITE
21450-#endif
21451-
21452-#endif // CATCH_CONFIG_ANDROID_LOGWRITE_HPP_INCLUDED
21453-
21454-
21455-
21456-/** \file
21457- * Wrapper for UNCAUGHT_EXCEPTIONS configuration option
21458- *
21459- * For some functionality, Catch2 requires to know whether there is
21460- * an active exception. Because `std::uncaught_exception` is deprecated
21461- * in C++17, we want to use `std::uncaught_exceptions` if possible.
21462- */
21463-
21464-#ifndef CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP_INCLUDED
21465-#define CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP_INCLUDED
21466-
21467-
21468-#if defined(_MSC_VER)
21469-# if _MSC_VER >= 1900 // Visual Studio 2015 or newer
21470-# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
21471-# endif
21472-#endif
21473-
21474-
21475-#include <exception>
21476-
21477-#if defined(__cpp_lib_uncaught_exceptions) \
21478- && !defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
21479-
21480-# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
21481-#endif // __cpp_lib_uncaught_exceptions
21482-
21483-
21484-#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) \
21485- && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) \
21486- && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
21487-
21488-# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
21489-#endif
21490-
21491-
21492-#endif // CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP_INCLUDED
21493-
21494-
21495-#ifndef CATCH_CONSOLE_COLOUR_HPP_INCLUDED
21496-#define CATCH_CONSOLE_COLOUR_HPP_INCLUDED
21497-
21498-
21499-#include <iosfwd>
21500-#include <cstdint>
21501-
21502-namespace Catch {
21503-
21504- enum class ColourMode : std::uint8_t;
21505- class IStream;
21506-
21507- struct Colour {
21508- enum Code {
21509- None = 0,
21510-
21511- White,
21512- Red,
21513- Green,
21514- Blue,
21515- Cyan,
21516- Yellow,
21517- Grey,
21518-
21519- Bright = 0x10,
21520-
21521- BrightRed = Bright | Red,
21522- BrightGreen = Bright | Green,
21523- LightGrey = Bright | Grey,
21524- BrightWhite = Bright | White,
21525- BrightYellow = Bright | Yellow,
21526-
21527- // By intention
21528- FileName = LightGrey,
21529- Warning = BrightYellow,
21530- ResultError = BrightRed,
21531- ResultSuccess = BrightGreen,
21532- ResultExpectedFailure = Warning,
21533-
21534- Error = BrightRed,
21535- Success = Green,
21536- Skip = LightGrey,
21537-
21538- OriginalExpression = Cyan,
21539- ReconstructedExpression = BrightYellow,
21540-
21541- SecondaryText = LightGrey,
21542- Headers = White
21543- };
21544- };
21545-
21546- class ColourImpl {
21547- protected:
21548- //! The associated stream of this ColourImpl instance
21549- IStream* m_stream;
21550- public:
21551- ColourImpl( IStream* stream ): m_stream( stream ) {}
21552-
21553- //! RAII wrapper around writing specific colour of text using specific
21554- //! colour impl into a stream.
21555- class ColourGuard {
21556- ColourImpl const* m_colourImpl;
21557- Colour::Code m_code;
21558- bool m_engaged = false;
21559-
21560- public:
21561- //! Does **not** engage the guard/start the colour
21562- ColourGuard( Colour::Code code,
21563- ColourImpl const* colour );
21564-
21565- ColourGuard( ColourGuard const& rhs ) = delete;
21566- ColourGuard& operator=( ColourGuard const& rhs ) = delete;
21567-
21568- ColourGuard( ColourGuard&& rhs ) noexcept;
21569- ColourGuard& operator=( ColourGuard&& rhs ) noexcept;
21570-
21571- //! Removes colour _if_ the guard was engaged
21572- ~ColourGuard();
21573-
21574- /**
21575- * Explicitly engages colour for given stream.
21576- *
21577- * The API based on operator<< should be preferred.
21578- */
21579- ColourGuard& engage( std::ostream& stream ) &;
21580- /**
21581- * Explicitly engages colour for given stream.
21582- *
21583- * The API based on operator<< should be preferred.
21584- */
21585- ColourGuard&& engage( std::ostream& stream ) &&;
21586-
21587- private:
21588- //! Engages the guard and starts using colour
21589- friend std::ostream& operator<<( std::ostream& lhs,
21590- ColourGuard& guard ) {
21591- guard.engageImpl( lhs );
21592- return lhs;
21593- }
21594- //! Engages the guard and starts using colour
21595- friend std::ostream& operator<<( std::ostream& lhs,
21596- ColourGuard&& guard) {
21597- guard.engageImpl( lhs );
21598- return lhs;
21599- }
21600-
21601- void engageImpl( std::ostream& stream );
21602-
21603- };
21604-
21605- virtual ~ColourImpl(); // = default
21606- /**
21607- * Creates a guard object for given colour and this colour impl
21608- *
21609- * **Important:**
21610- * the guard starts disengaged, and has to be engaged explicitly.
21611- */
21612- ColourGuard guardColour( Colour::Code colourCode );
21613-
21614- private:
21615- virtual void use( Colour::Code colourCode ) const = 0;
21616- };
21617-
21618- //! Provides ColourImpl based on global config and target compilation platform
21619- Detail::unique_ptr<ColourImpl> makeColourImpl( ColourMode colourSelection,
21620- IStream* stream );
21621-
21622- //! Checks if specific colour impl has been compiled into the binary
21623- bool isColourImplAvailable( ColourMode colourSelection );
21624-
21625-} // end namespace Catch
21626-
21627-#endif // CATCH_CONSOLE_COLOUR_HPP_INCLUDED
21628-
21629-
21630-#ifndef CATCH_CONSOLE_WIDTH_HPP_INCLUDED
21631-#define CATCH_CONSOLE_WIDTH_HPP_INCLUDED
21632-
21633-// This include must be kept so that user's configured value for CONSOLE_WIDTH
21634-// is used before we attempt to provide a default value
21635-
21636-#ifndef CATCH_CONFIG_CONSOLE_WIDTH
21637-#define CATCH_CONFIG_CONSOLE_WIDTH 80
21638-#endif
21639-
21640-#endif // CATCH_CONSOLE_WIDTH_HPP_INCLUDED
21641-
21642-
21643-#ifndef CATCH_CONTAINER_NONMEMBERS_HPP_INCLUDED
21644-#define CATCH_CONTAINER_NONMEMBERS_HPP_INCLUDED
21645-
21646-
21647-#include <cstddef>
21648-#include <initializer_list>
21649-
21650-// We want a simple polyfill over `std::empty`, `std::size` and so on
21651-// for C++14 or C++ libraries with incomplete support.
21652-// We also have to handle that MSVC std lib will happily provide these
21653-// under older standards.
21654-#if defined(CATCH_CPP17_OR_GREATER) || defined(_MSC_VER)
21655-
21656-// We are already using this header either way, so there shouldn't
21657-// be much additional overhead in including it to get the feature
21658-// test macros
21659-#include <string>
21660-
21661-# if !defined(__cpp_lib_nonmember_container_access)
21662-# define CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS
21663-# endif
21664-
21665-#else
21666-#define CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS
21667-#endif
21668-
21669-
21670-
21671-namespace Catch {
21672-namespace Detail {
21673-
21674-#if defined(CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS)
21675- template <typename Container>
21676- constexpr auto empty(Container const& cont) -> decltype(cont.empty()) {
21677- return cont.empty();
21678- }
21679- template <typename T, std::size_t N>
21680- constexpr bool empty(const T (&)[N]) noexcept {
21681- // GCC < 7 does not support the const T(&)[] parameter syntax
21682- // so we have to ignore the length explicitly
21683- (void)N;
21684- return false;
21685- }
21686- template <typename T>
21687- constexpr bool empty(std::initializer_list<T> list) noexcept {
21688- return list.size() > 0;
21689- }
21690-
21691-
21692- template <typename Container>
21693- constexpr auto size(Container const& cont) -> decltype(cont.size()) {
21694- return cont.size();
21695- }
21696- template <typename T, std::size_t N>
21697- constexpr std::size_t size(const T(&)[N]) noexcept {
21698- return N;
21699- }
21700-#endif // CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS
21701-
21702-} // end namespace Detail
21703-} // end namespace Catch
21704-
21705-
21706-
21707-#endif // CATCH_CONTAINER_NONMEMBERS_HPP_INCLUDED
21708-
21709-
21710-#ifndef CATCH_DEBUG_CONSOLE_HPP_INCLUDED
21711-#define CATCH_DEBUG_CONSOLE_HPP_INCLUDED
21712-
21713-#include <string>
21714-
21715-namespace Catch {
21716- void writeToDebugConsole( std::string const& text );
21717-}
21718-
21719-#endif // CATCH_DEBUG_CONSOLE_HPP_INCLUDED
21720-
21721-
21722-#ifndef CATCH_DEBUGGER_HPP_INCLUDED
21723-#define CATCH_DEBUGGER_HPP_INCLUDED
21724-
21725-
21726-namespace Catch {
21727- bool isDebuggerActive();
21728-}
21729-
21730-#if !defined( CATCH_TRAP ) && defined( __clang__ ) && defined( __has_builtin )
21731-# if __has_builtin( __builtin_debugtrap )
21732-# define CATCH_TRAP() __builtin_debugtrap()
21733-# endif
21734-#endif
21735-
21736-#if !defined( CATCH_TRAP ) && defined( _MSC_VER )
21737-# define CATCH_TRAP() __debugbreak()
21738-#endif
21739-
21740-#if !defined(CATCH_TRAP) // If we couldn't use compiler-specific impl from above, we get into platform-specific options
21741-#ifdef CATCH_PLATFORM_MAC
21742-
21743- #if defined(__i386__) || defined(__x86_64__)
21744- #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */
21745- #elif defined(__aarch64__)
21746- #define CATCH_TRAP() __asm__(".inst 0xd43e0000")
21747- #elif defined(__POWERPC__)
21748- #define CATCH_TRAP() __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \
21749- : : : "memory","r0","r3","r4" ) /* NOLINT */
21750- #endif
21751-
21752-#elif defined(CATCH_PLATFORM_IPHONE)
21753-
21754- // use inline assembler
21755- #if defined(__i386__) || defined(__x86_64__)
21756- #define CATCH_TRAP() __asm__("int $3")
21757- #elif defined(__aarch64__)
21758- #define CATCH_TRAP() __asm__(".inst 0xd4200000")
21759- #elif defined(__arm__) && !defined(__thumb__)
21760- #define CATCH_TRAP() __asm__(".inst 0xe7f001f0")
21761- #elif defined(__arm__) && defined(__thumb__)
21762- #define CATCH_TRAP() __asm__(".inst 0xde01")
21763- #endif
21764-
21765-#elif defined(CATCH_PLATFORM_LINUX) || defined(CATCH_PLATFORM_QNX)
21766- // If we can use inline assembler, do it because this allows us to break
21767- // directly at the location of the failing check instead of breaking inside
21768- // raise() called from it, i.e. one stack frame below.
21769- #if defined(__GNUC__) && (defined(__i386) || defined(__x86_64))
21770- #define CATCH_TRAP() asm volatile ("int $3") /* NOLINT */
21771- #else // Fall back to the generic way.
21772- #include <signal.h>
21773-
21774- #define CATCH_TRAP() raise(SIGTRAP)
21775- #endif
21776-#elif defined(__MINGW32__)
21777- extern "C" __declspec(dllimport) void __stdcall DebugBreak();
21778- #define CATCH_TRAP() DebugBreak()
21779-#endif
21780-#endif // ^^ CATCH_TRAP is not defined yet, so we define it
21781-
21782-
21783-#if !defined(CATCH_BREAK_INTO_DEBUGGER)
21784- #if defined(CATCH_TRAP)
21785- #define CATCH_BREAK_INTO_DEBUGGER() []{ if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } }()
21786- #else
21787- #define CATCH_BREAK_INTO_DEBUGGER() []{}()
21788- #endif
21789-#endif
21790-
21791-#endif // CATCH_DEBUGGER_HPP_INCLUDED
21792-
21793-
21794-#ifndef CATCH_ENFORCE_HPP_INCLUDED
21795-#define CATCH_ENFORCE_HPP_INCLUDED
21796-
21797-
21798-#include <exception> // for `std::exception` in no-exception configuration
21799-
21800-namespace Catch {
21801-#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
21802- template <typename Ex>
21803- [[noreturn]]
21804- void throw_exception(Ex const& e) {
21805- throw e;
21806- }
21807-#else // ^^ Exceptions are enabled // Exceptions are disabled vv
21808- [[noreturn]]
21809- void throw_exception(std::exception const& e);
21810-#endif
21811-
21812- [[noreturn]]
21813- void throw_logic_error(std::string const& msg);
21814- [[noreturn]]
21815- void throw_domain_error(std::string const& msg);
21816- [[noreturn]]
21817- void throw_runtime_error(std::string const& msg);
21818-
21819-} // namespace Catch;
21820-
21821-#define CATCH_MAKE_MSG(...) \
21822- (Catch::ReusableStringStream() << __VA_ARGS__).str()
21823-
21824-#define CATCH_INTERNAL_ERROR(...) \
21825- Catch::throw_logic_error(CATCH_MAKE_MSG( CATCH_INTERNAL_LINEINFO << ": Internal Catch2 error: " << __VA_ARGS__))
21826-
21827-#define CATCH_ERROR(...) \
21828- Catch::throw_domain_error(CATCH_MAKE_MSG( __VA_ARGS__ ))
21829-
21830-#define CATCH_RUNTIME_ERROR(...) \
21831- Catch::throw_runtime_error(CATCH_MAKE_MSG( __VA_ARGS__ ))
21832-
21833-#define CATCH_ENFORCE( condition, ... ) \
21834- do{ if( !(condition) ) CATCH_ERROR( __VA_ARGS__ ); } while(false)
21835-
21836-
21837-#endif // CATCH_ENFORCE_HPP_INCLUDED
21838-
21839-
21840-#ifndef CATCH_ENUM_VALUES_REGISTRY_HPP_INCLUDED
21841-#define CATCH_ENUM_VALUES_REGISTRY_HPP_INCLUDED
21842-
21843-
21844-#include <vector>
21845-
21846-namespace Catch {
21847-
21848- namespace Detail {
21849-
21850- Catch::Detail::unique_ptr<EnumInfo> makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int> const& values );
21851-
21852- class EnumValuesRegistry : public IMutableEnumValuesRegistry {
21853-
21854- std::vector<Catch::Detail::unique_ptr<EnumInfo>> m_enumInfos;
21855-
21856- EnumInfo const& registerEnum( StringRef enumName, StringRef allValueNames, std::vector<int> const& values) override;
21857- };
21858-
21859- std::vector<StringRef> parseEnums( StringRef enums );
21860-
21861- } // Detail
21862-
21863-} // Catch
21864-
21865-#endif // CATCH_ENUM_VALUES_REGISTRY_HPP_INCLUDED
21866-
21867-
21868-#ifndef CATCH_ERRNO_GUARD_HPP_INCLUDED
21869-#define CATCH_ERRNO_GUARD_HPP_INCLUDED
21870-
21871-namespace Catch {
21872-
21873- //! Simple RAII class that stores the value of `errno`
21874- //! at construction and restores it at destruction.
21875- class ErrnoGuard {
21876- public:
21877- // Keep these outlined to avoid dragging in macros from <cerrno>
21878-
21879- ErrnoGuard();
21880- ~ErrnoGuard();
21881- private:
21882- int m_oldErrno;
21883- };
21884-
21885-}
21886-
21887-#endif // CATCH_ERRNO_GUARD_HPP_INCLUDED
21888-
21889-
21890-#ifndef CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED
21891-#define CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED
21892-
21893-
21894-#include <string>
21895-
21896-namespace Catch {
21897-
21898- class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry {
21899- public:
21900- ~ExceptionTranslatorRegistry() override;
21901- void registerTranslator( Detail::unique_ptr<IExceptionTranslator>&& translator );
21902- std::string translateActiveException() const override;
21903-
21904- private:
21905- ExceptionTranslators m_translators;
21906- };
21907-}
21908-
21909-#endif // CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED
21910-
21911-
21912-#ifndef CATCH_FATAL_CONDITION_HANDLER_HPP_INCLUDED
21913-#define CATCH_FATAL_CONDITION_HANDLER_HPP_INCLUDED
21914-
21915-#include <cassert>
21916-
21917-namespace Catch {
21918-
21919- /**
21920- * Wrapper for platform-specific fatal error (signals/SEH) handlers
21921- *
21922- * Tries to be cooperative with other handlers, and not step over
21923- * other handlers. This means that unknown structured exceptions
21924- * are passed on, previous signal handlers are called, and so on.
21925- *
21926- * Can only be instantiated once, and assumes that once a signal
21927- * is caught, the binary will end up terminating. Thus, there
21928- */
21929- class FatalConditionHandler {
21930- bool m_started = false;
21931-
21932- // Install/disengage implementation for specific platform.
21933- // Should be if-defed to work on current platform, can assume
21934- // engage-disengage 1:1 pairing.
21935- void engage_platform();
21936- void disengage_platform() noexcept;
21937- public:
21938- // Should also have platform-specific implementations as needed
21939- FatalConditionHandler();
21940- ~FatalConditionHandler();
21941-
21942- void engage() {
21943- assert(!m_started && "Handler cannot be installed twice.");
21944- m_started = true;
21945- engage_platform();
21946- }
21947-
21948- void disengage() noexcept {
21949- assert(m_started && "Handler cannot be uninstalled without being installed first");
21950- m_started = false;
21951- disengage_platform();
21952- }
21953- };
21954-
21955- //! Simple RAII guard for (dis)engaging the FatalConditionHandler
21956- class FatalConditionHandlerGuard {
21957- FatalConditionHandler* m_handler;
21958- public:
21959- FatalConditionHandlerGuard(FatalConditionHandler* handler):
21960- m_handler(handler) {
21961- m_handler->engage();
21962- }
21963- ~FatalConditionHandlerGuard() {
21964- m_handler->disengage();
21965- }
21966- };
21967-
21968-} // end namespace Catch
21969-
21970-#endif // CATCH_FATAL_CONDITION_HANDLER_HPP_INCLUDED
21971-
21972-
21973-#ifndef CATCH_FLOATING_POINT_HELPERS_HPP_INCLUDED
21974-#define CATCH_FLOATING_POINT_HELPERS_HPP_INCLUDED
21975-
21976-
21977-#include <cassert>
21978-#include <cmath>
21979-#include <cstdint>
21980-#include <utility>
21981-#include <limits>
21982-
21983-namespace Catch {
21984- namespace Detail {
21985-
21986- uint32_t convertToBits(float f);
21987- uint64_t convertToBits(double d);
21988-
21989- // Used when we know we want == comparison of two doubles
21990- // to centralize warning suppression
21991- bool directCompare( float lhs, float rhs );
21992- bool directCompare( double lhs, double rhs );
21993-
21994- } // end namespace Detail
21995-
21996-
21997-
21998-#if defined( __GNUC__ ) || defined( __clang__ )
21999-# pragma GCC diagnostic push
22000- // We do a bunch of direct compensations of floating point numbers,
22001- // because we know what we are doing and actually do want the direct
22002- // comparison behaviour.
22003-# pragma GCC diagnostic ignored "-Wfloat-equal"
22004-#endif
22005-
22006- /**
22007- * Calculates the ULP distance between two floating point numbers
22008- *
22009- * The ULP distance of two floating point numbers is the count of
22010- * valid floating point numbers representable between them.
22011- *
22012- * There are some exceptions between how this function counts the
22013- * distance, and the interpretation of the standard as implemented.
22014- * by e.g. `nextafter`. For this function it always holds that:
22015- * * `(x == y) => ulpDistance(x, y) == 0` (so `ulpDistance(-0, 0) == 0`)
22016- * * `ulpDistance(maxFinite, INF) == 1`
22017- * * `ulpDistance(x, -x) == 2 * ulpDistance(x, 0)`
22018- *
22019- * \pre `!isnan( lhs )`
22020- * \pre `!isnan( rhs )`
22021- * \pre floating point numbers are represented in IEEE-754 format
22022- */
22023- template <typename FP>
22024- uint64_t ulpDistance( FP lhs, FP rhs ) {
22025- assert( std::numeric_limits<FP>::is_iec559 &&
22026- "ulpDistance assumes IEEE-754 format for floating point types" );
22027- assert( !Catch::isnan( lhs ) &&
22028- "Distance between NaN and number is not meaningful" );
22029- assert( !Catch::isnan( rhs ) &&
22030- "Distance between NaN and number is not meaningful" );
22031-
22032- // We want X == Y to imply 0 ULP distance even if X and Y aren't
22033- // bit-equal (-0 and 0), or X - Y != 0 (same sign infinities).
22034- if ( lhs == rhs ) { return 0; }
22035-
22036- // We need a properly typed positive zero for type inference.
22037- static constexpr FP positive_zero{};
22038-
22039- // We want to ensure that +/- 0 is always represented as positive zero
22040- if ( lhs == positive_zero ) { lhs = positive_zero; }
22041- if ( rhs == positive_zero ) { rhs = positive_zero; }
22042-
22043- // If arguments have different signs, we can handle them by summing
22044- // how far are they from 0 each.
22045- if ( std::signbit( lhs ) != std::signbit( rhs ) ) {
22046- return ulpDistance( std::abs( lhs ), positive_zero ) +
22047- ulpDistance( std::abs( rhs ), positive_zero );
22048- }
22049-
22050- // When both lhs and rhs are of the same sign, we can just
22051- // read the numbers bitwise as integers, and then subtract them
22052- // (assuming IEEE).
22053- uint64_t lc = Detail::convertToBits( lhs );
22054- uint64_t rc = Detail::convertToBits( rhs );
22055-
22056- // The ulp distance between two numbers is symmetric, so to avoid
22057- // dealing with overflows we want the bigger converted number on the lhs
22058- if ( lc < rc ) {
22059- std::swap( lc, rc );
22060- }
22061-
22062- return lc - rc;
22063- }
22064-
22065-#if defined( __GNUC__ ) || defined( __clang__ )
22066-# pragma GCC diagnostic pop
22067-#endif
22068-
22069-
22070-} // end namespace Catch
22071-
22072-#endif // CATCH_FLOATING_POINT_HELPERS_HPP_INCLUDED
22073-
22074-
22075-#ifndef CATCH_GETENV_HPP_INCLUDED
22076-#define CATCH_GETENV_HPP_INCLUDED
22077-
22078-namespace Catch {
22079-namespace Detail {
22080-
22081- //! Wrapper over `std::getenv` that compiles on UWP (and always returns nullptr there)
22082- char const* getEnv(char const* varName);
22083-
22084-}
22085-}
22086-
22087-#endif // CATCH_GETENV_HPP_INCLUDED
22088-
22089-
22090-#ifndef CATCH_IS_PERMUTATION_HPP_INCLUDED
22091-#define CATCH_IS_PERMUTATION_HPP_INCLUDED
22092-
22093-#include <iterator>
22094-#include <type_traits>
22095-
22096-namespace Catch {
22097- namespace Detail {
22098-
22099- template <typename ForwardIter,
22100- typename Sentinel,
22101- typename T,
22102- typename Comparator>
22103- constexpr
22104- ForwardIter find_sentinel( ForwardIter start,
22105- Sentinel sentinel,
22106- T const& value,
22107- Comparator cmp ) {
22108- while ( start != sentinel ) {
22109- if ( cmp( *start, value ) ) { break; }
22110- ++start;
22111- }
22112- return start;
22113- }
22114-
22115- template <typename ForwardIter,
22116- typename Sentinel,
22117- typename T,
22118- typename Comparator>
22119- constexpr
22120- std::ptrdiff_t count_sentinel( ForwardIter start,
22121- Sentinel sentinel,
22122- T const& value,
22123- Comparator cmp ) {
22124- std::ptrdiff_t count = 0;
22125- while ( start != sentinel ) {
22126- if ( cmp( *start, value ) ) { ++count; }
22127- ++start;
22128- }
22129- return count;
22130- }
22131-
22132- template <typename ForwardIter, typename Sentinel>
22133- constexpr
22134- std::enable_if_t<!std::is_same<ForwardIter, Sentinel>::value,
22135- std::ptrdiff_t>
22136- sentinel_distance( ForwardIter iter, const Sentinel sentinel ) {
22137- std::ptrdiff_t dist = 0;
22138- while ( iter != sentinel ) {
22139- ++iter;
22140- ++dist;
22141- }
22142- return dist;
22143- }
22144-
22145- template <typename ForwardIter>
22146- constexpr std::ptrdiff_t sentinel_distance( ForwardIter first,
22147- ForwardIter last ) {
22148- return std::distance( first, last );
22149- }
22150-
22151- template <typename ForwardIter1,
22152- typename Sentinel1,
22153- typename ForwardIter2,
22154- typename Sentinel2,
22155- typename Comparator>
22156- constexpr bool check_element_counts( ForwardIter1 first_1,
22157- const Sentinel1 end_1,
22158- ForwardIter2 first_2,
22159- const Sentinel2 end_2,
22160- Comparator cmp ) {
22161- auto cursor = first_1;
22162- while ( cursor != end_1 ) {
22163- if ( find_sentinel( first_1, cursor, *cursor, cmp ) ==
22164- cursor ) {
22165- // we haven't checked this element yet
22166- const auto count_in_range_2 =
22167- count_sentinel( first_2, end_2, *cursor, cmp );
22168- // Not a single instance in 2nd range, so it cannot be a
22169- // permutation of 1st range
22170- if ( count_in_range_2 == 0 ) { return false; }
22171-
22172- const auto count_in_range_1 =
22173- count_sentinel( cursor, end_1, *cursor, cmp );
22174- if ( count_in_range_1 != count_in_range_2 ) {
22175- return false;
22176- }
22177- }
22178-
22179- ++cursor;
22180- }
22181-
22182- return true;
22183- }
22184-
22185- template <typename ForwardIter1,
22186- typename Sentinel1,
22187- typename ForwardIter2,
22188- typename Sentinel2,
22189- typename Comparator>
22190- constexpr bool is_permutation( ForwardIter1 first_1,
22191- const Sentinel1 end_1,
22192- ForwardIter2 first_2,
22193- const Sentinel2 end_2,
22194- Comparator cmp ) {
22195- // TODO: no optimization for stronger iterators, because we would also have to constrain on sentinel vs not sentinel types
22196- // TODO: Comparator has to be "both sides", e.g. a == b => b == a
22197- // This skips shared prefix of the two ranges
22198- while (first_1 != end_1 && first_2 != end_2 && cmp(*first_1, *first_2)) {
22199- ++first_1;
22200- ++first_2;
22201- }
22202-
22203- // We need to handle case where at least one of the ranges has no more elements
22204- if (first_1 == end_1 || first_2 == end_2) {
22205- return first_1 == end_1 && first_2 == end_2;
22206- }
22207-
22208- // pair counting is n**2, so we pay linear walk to compare the sizes first
22209- auto dist_1 = sentinel_distance( first_1, end_1 );
22210- auto dist_2 = sentinel_distance( first_2, end_2 );
22211-
22212- if (dist_1 != dist_2) { return false; }
22213-
22214- // Since we do not try to handle stronger iterators pair (e.g.
22215- // bidir) optimally, the only thing left to do is to check counts in
22216- // the remaining ranges.
22217- return check_element_counts( first_1, end_1, first_2, end_2, cmp );
22218- }
22219-
22220- } // namespace Detail
22221-} // namespace Catch
22222-
22223-#endif // CATCH_IS_PERMUTATION_HPP_INCLUDED
22224-
22225-
22226-#ifndef CATCH_ISTREAM_HPP_INCLUDED
22227-#define CATCH_ISTREAM_HPP_INCLUDED
22228-
22229-
22230-#include <iosfwd>
22231-#include <string>
22232-
22233-namespace Catch {
22234-
22235- class IStream {
22236- public:
22237- virtual ~IStream(); // = default
22238- virtual std::ostream& stream() = 0;
22239- /**
22240- * Best guess on whether the instance is writing to a console (e.g. via stdout/stderr)
22241- *
22242- * This is useful for e.g. Win32 colour support, because the Win32
22243- * API manipulates console directly, unlike POSIX escape codes,
22244- * that can be written anywhere.
22245- *
22246- * Due to variety of ways to change where the stdout/stderr is
22247- * _actually_ being written, users should always assume that
22248- * the answer might be wrong.
22249- */
22250- virtual bool isConsole() const { return false; }
22251- };
22252-
22253- /**
22254- * Creates a stream wrapper that writes to specific file.
22255- *
22256- * Also recognizes 4 special filenames
22257- * * `-` for stdout
22258- * * `%stdout` for stdout
22259- * * `%stderr` for stderr
22260- * * `%debug` for platform specific debugging output
22261- *
22262- * \throws if passed an unrecognized %-prefixed stream
22263- */
22264- auto makeStream( std::string const& filename ) -> Detail::unique_ptr<IStream>;
22265-
22266-}
22267-
22268-#endif // CATCH_STREAM_HPP_INCLUDED
22269-
22270-
22271-#ifndef CATCH_JSONWRITER_HPP_INCLUDED
22272-#define CATCH_JSONWRITER_HPP_INCLUDED
22273-
22274-
22275-#include <cstdint>
22276-#include <sstream>
22277-
22278-namespace Catch {
22279- class JsonObjectWriter;
22280- class JsonArrayWriter;
22281-
22282- struct JsonUtils {
22283- static void indent( std::ostream& os, std::uint64_t level );
22284- static void appendCommaNewline( std::ostream& os,
22285- bool& should_comma,
22286- std::uint64_t level );
22287- };
22288-
22289- class JsonValueWriter {
22290- public:
22291- JsonValueWriter( std::ostream& os );
22292- JsonValueWriter( std::ostream& os, std::uint64_t indent_level );
22293-
22294- JsonObjectWriter writeObject() &&;
22295- JsonArrayWriter writeArray() &&;
22296-
22297- template <typename T>
22298- void write( T const& value ) && {
22299- writeImpl( value, !std::is_arithmetic<T>::value );
22300- }
22301- void write( StringRef value ) &&;
22302- void write( bool value ) &&;
22303-
22304- private:
22305- void writeImpl( StringRef value, bool quote );
22306-
22307- // Without this SFINAE, this overload is a better match
22308- // for `std::string`, `char const*`, `char const[N]` args.
22309- // While it would still work, it would cause code bloat
22310- // and multiple iteration over the strings
22311- template <typename T,
22312- typename = typename std::enable_if_t<
22313- !std::is_convertible<T, StringRef>::value>>
22314- void writeImpl( T const& value, bool quote_value ) {
22315- m_sstream << value;
22316- writeImpl( m_sstream.str(), quote_value );
22317- }
22318-
22319- std::ostream& m_os;
22320- std::stringstream m_sstream;
22321- std::uint64_t m_indent_level;
22322- };
22323-
22324- class JsonObjectWriter {
22325- public:
22326- JsonObjectWriter( std::ostream& os );
22327- JsonObjectWriter( std::ostream& os, std::uint64_t indent_level );
22328-
22329- JsonObjectWriter( JsonObjectWriter&& source ) noexcept;
22330- JsonObjectWriter& operator=( JsonObjectWriter&& source ) = delete;
22331-
22332- ~JsonObjectWriter();
22333-
22334- JsonValueWriter write( StringRef key );
22335-
22336- private:
22337- std::ostream& m_os;
22338- std::uint64_t m_indent_level;
22339- bool m_should_comma = false;
22340- bool m_active = true;
22341- };
22342-
22343- class JsonArrayWriter {
22344- public:
22345- JsonArrayWriter( std::ostream& os );
22346- JsonArrayWriter( std::ostream& os, std::uint64_t indent_level );
22347-
22348- JsonArrayWriter( JsonArrayWriter&& source ) noexcept;
22349- JsonArrayWriter& operator=( JsonArrayWriter&& source ) = delete;
22350-
22351- ~JsonArrayWriter();
22352-
22353- JsonObjectWriter writeObject();
22354- JsonArrayWriter writeArray();
22355-
22356- template <typename T>
22357- JsonArrayWriter& write( T const& value ) {
22358- return writeImpl( value );
22359- }
22360-
22361- JsonArrayWriter& write( bool value );
22362-
22363- private:
22364- template <typename T>
22365- JsonArrayWriter& writeImpl( T const& value ) {
22366- JsonUtils::appendCommaNewline(
22367- m_os, m_should_comma, m_indent_level + 1 );
22368- JsonValueWriter{ m_os }.write( value );
22369-
22370- return *this;
22371- }
22372-
22373- std::ostream& m_os;
22374- std::uint64_t m_indent_level;
22375- bool m_should_comma = false;
22376- bool m_active = true;
22377- };
22378-
22379-} // namespace Catch
22380-
22381-#endif // CATCH_JSONWRITER_HPP_INCLUDED
22382-
22383-
22384-#ifndef CATCH_LEAK_DETECTOR_HPP_INCLUDED
22385-#define CATCH_LEAK_DETECTOR_HPP_INCLUDED
22386-
22387-namespace Catch {
22388-
22389- struct LeakDetector {
22390- LeakDetector();
22391- ~LeakDetector();
22392- };
22393-
22394-}
22395-#endif // CATCH_LEAK_DETECTOR_HPP_INCLUDED
22396-
22397-
22398-#ifndef CATCH_LIST_HPP_INCLUDED
22399-#define CATCH_LIST_HPP_INCLUDED
22400-
22401-
22402-#include <set>
22403-#include <string>
22404-
22405-
22406-namespace Catch {
22407-
22408- class IEventListener;
22409- class Config;
22410-
22411-
22412- struct ReporterDescription {
22413- std::string name, description;
22414- };
22415- struct ListenerDescription {
22416- StringRef name;
22417- std::string description;
22418- };
22419-
22420- struct TagInfo {
22421- void add(StringRef spelling);
22422- std::string all() const;
22423-
22424- std::set<StringRef> spellings;
22425- std::size_t count = 0;
22426- };
22427-
22428- bool list( IEventListener& reporter, Config const& config );
22429-
22430-} // end namespace Catch
22431-
22432-#endif // CATCH_LIST_HPP_INCLUDED
22433-
22434-
22435-#ifndef CATCH_OUTPUT_REDIRECT_HPP_INCLUDED
22436-#define CATCH_OUTPUT_REDIRECT_HPP_INCLUDED
22437-
22438-
22439-#include <cassert>
22440-#include <string>
22441-
22442-namespace Catch {
22443-
22444- class OutputRedirect {
22445- bool m_redirectActive = false;
22446- virtual void activateImpl() = 0;
22447- virtual void deactivateImpl() = 0;
22448- public:
22449- enum Kind {
22450- //! No redirect (noop implementation)
22451- None,
22452- //! Redirect std::cout/std::cerr/std::clog streams internally
22453- Streams,
22454- //! Redirect the stdout/stderr file descriptors into files
22455- FileDescriptors,
22456- };
22457-
22458- virtual ~OutputRedirect(); // = default;
22459-
22460- // TODO: Do we want to check that redirect is not active before retrieving the output?
22461- virtual std::string getStdout() = 0;
22462- virtual std::string getStderr() = 0;
22463- virtual void clearBuffers() = 0;
22464- bool isActive() const { return m_redirectActive; }
22465- void activate() {
22466- assert( !m_redirectActive && "redirect is already active" );
22467- activateImpl();
22468- m_redirectActive = true;
22469- }
22470- void deactivate() {
22471- assert( m_redirectActive && "redirect is not active" );
22472- deactivateImpl();
22473- m_redirectActive = false;
22474- }
22475- };
22476-
22477- bool isRedirectAvailable( OutputRedirect::Kind kind);
22478- Detail::unique_ptr<OutputRedirect> makeOutputRedirect( bool actual );
22479-
22480- class RedirectGuard {
22481- OutputRedirect* m_redirect;
22482- bool m_activate;
22483- bool m_previouslyActive;
22484- bool m_moved = false;
22485-
22486- public:
22487- RedirectGuard( bool activate, OutputRedirect& redirectImpl );
22488- ~RedirectGuard() noexcept( false );
22489-
22490- RedirectGuard( RedirectGuard const& ) = delete;
22491- RedirectGuard& operator=( RedirectGuard const& ) = delete;
22492-
22493- // C++14 needs move-able guards to return them from functions
22494- RedirectGuard( RedirectGuard&& rhs ) noexcept;
22495- RedirectGuard& operator=( RedirectGuard&& rhs ) noexcept;
22496- };
22497-
22498- RedirectGuard scopedActivate( OutputRedirect& redirectImpl );
22499- RedirectGuard scopedDeactivate( OutputRedirect& redirectImpl );
22500-
22501-} // end namespace Catch
22502-
22503-#endif // CATCH_OUTPUT_REDIRECT_HPP_INCLUDED
22504-
22505-
22506-#ifndef CATCH_PARSE_NUMBERS_HPP_INCLUDED
22507-#define CATCH_PARSE_NUMBERS_HPP_INCLUDED
22508-
22509-
22510-#include <string>
22511-
22512-namespace Catch {
22513-
22514- /**
22515- * Parses unsigned int from the input, using provided base
22516- *
22517- * Effectively a wrapper around std::stoul but with better error checking
22518- * e.g. "-1" is rejected, instead of being parsed as UINT_MAX.
22519- */
22520- Optional<unsigned int> parseUInt(std::string const& input, int base = 10);
22521-}
22522-
22523-#endif // CATCH_PARSE_NUMBERS_HPP_INCLUDED
22524-
22525-
22526-#ifndef CATCH_REPORTER_REGISTRY_HPP_INCLUDED
22527-#define CATCH_REPORTER_REGISTRY_HPP_INCLUDED
22528-
22529-
22530-#include <map>
22531-#include <string>
22532-#include <vector>
22533-
22534-namespace Catch {
22535-
22536- class IEventListener;
22537- using IEventListenerPtr = Detail::unique_ptr<IEventListener>;
22538- class IReporterFactory;
22539- using IReporterFactoryPtr = Detail::unique_ptr<IReporterFactory>;
22540- struct ReporterConfig;
22541- class EventListenerFactory;
22542-
22543- class ReporterRegistry {
22544- struct ReporterRegistryImpl;
22545- Detail::unique_ptr<ReporterRegistryImpl> m_impl;
22546-
22547- public:
22548- ReporterRegistry();
22549- ~ReporterRegistry(); // = default;
22550-
22551- IEventListenerPtr create( std::string const& name,
22552- ReporterConfig&& config ) const;
22553-
22554- void registerReporter( std::string const& name,
22555- IReporterFactoryPtr factory );
22556-
22557- void
22558- registerListener( Detail::unique_ptr<EventListenerFactory> factory );
22559-
22560- std::map<std::string,
22561- IReporterFactoryPtr,
22562- Detail::CaseInsensitiveLess> const&
22563- getFactories() const;
22564-
22565- std::vector<Detail::unique_ptr<EventListenerFactory>> const&
22566- getListeners() const;
22567- };
22568-
22569-} // end namespace Catch
22570-
22571-#endif // CATCH_REPORTER_REGISTRY_HPP_INCLUDED
22572-
22573-
22574-#ifndef CATCH_RUN_CONTEXT_HPP_INCLUDED
22575-#define CATCH_RUN_CONTEXT_HPP_INCLUDED
22576-
22577-
22578-
22579-#ifndef CATCH_TEST_CASE_TRACKER_HPP_INCLUDED
22580-#define CATCH_TEST_CASE_TRACKER_HPP_INCLUDED
22581-
22582-
22583-#include <string>
22584-#include <vector>
22585-
22586-namespace Catch {
22587-namespace TestCaseTracking {
22588-
22589- struct NameAndLocation {
22590- std::string name;
22591- SourceLineInfo location;
22592-
22593- NameAndLocation( std::string&& _name, SourceLineInfo const& _location );
22594- friend bool operator==(NameAndLocation const& lhs, NameAndLocation const& rhs) {
22595- // This is a very cheap check that should have a very high hit rate.
22596- // If we get to SourceLineInfo::operator==, we will redo it, but the
22597- // cost of repeating is trivial at that point (we will be paying
22598- // multiple strcmp/memcmps at that point).
22599- if ( lhs.location.line != rhs.location.line ) { return false; }
22600- return lhs.name == rhs.name && lhs.location == rhs.location;
22601- }
22602- friend bool operator!=(NameAndLocation const& lhs,
22603- NameAndLocation const& rhs) {
22604- return !( lhs == rhs );
22605- }
22606- };
22607-
22608- /**
22609- * This is a variant of `NameAndLocation` that does not own the name string
22610- *
22611- * This avoids extra allocations when trying to locate a tracker by its
22612- * name and location, as long as we make sure that trackers only keep
22613- * around the owning variant.
22614- */
22615- struct NameAndLocationRef {
22616- StringRef name;
22617- SourceLineInfo location;
22618-
22619- constexpr NameAndLocationRef( StringRef name_,
22620- SourceLineInfo location_ ):
22621- name( name_ ), location( location_ ) {}
22622-
22623- friend bool operator==( NameAndLocation const& lhs,
22624- NameAndLocationRef const& rhs ) {
22625- // This is a very cheap check that should have a very high hit rate.
22626- // If we get to SourceLineInfo::operator==, we will redo it, but the
22627- // cost of repeating is trivial at that point (we will be paying
22628- // multiple strcmp/memcmps at that point).
22629- if ( lhs.location.line != rhs.location.line ) { return false; }
22630- return StringRef( lhs.name ) == rhs.name &&
22631- lhs.location == rhs.location;
22632- }
22633- friend bool operator==( NameAndLocationRef const& lhs,
22634- NameAndLocation const& rhs ) {
22635- return rhs == lhs;
22636- }
22637- };
22638-
22639- class ITracker;
22640-
22641- using ITrackerPtr = Catch::Detail::unique_ptr<ITracker>;
22642-
22643- class ITracker {
22644- NameAndLocation m_nameAndLocation;
22645-
22646- using Children = std::vector<ITrackerPtr>;
22647-
22648- protected:
22649- enum CycleState {
22650- NotStarted,
22651- Executing,
22652- ExecutingChildren,
22653- NeedsAnotherRun,
22654- CompletedSuccessfully,
22655- Failed
22656- };
22657-
22658- ITracker* m_parent = nullptr;
22659- Children m_children;
22660- CycleState m_runState = NotStarted;
22661-
22662- public:
22663- ITracker( NameAndLocation&& nameAndLoc, ITracker* parent ):
22664- m_nameAndLocation( CATCH_MOVE(nameAndLoc) ),
22665- m_parent( parent )
22666- {}
22667-
22668-
22669- // static queries
22670- NameAndLocation const& nameAndLocation() const {
22671- return m_nameAndLocation;
22672- }
22673- ITracker* parent() const {
22674- return m_parent;
22675- }
22676-
22677- virtual ~ITracker(); // = default
22678-
22679-
22680- // dynamic queries
22681-
22682- //! Returns true if tracker run to completion (successfully or not)
22683- virtual bool isComplete() const = 0;
22684- //! Returns true if tracker run to completion successfully
22685- bool isSuccessfullyCompleted() const {
22686- return m_runState == CompletedSuccessfully;
22687- }
22688- //! Returns true if tracker has started but hasn't been completed
22689- bool isOpen() const;
22690- //! Returns true iff tracker has started
22691- bool hasStarted() const;
22692-
22693- // actions
22694- virtual void close() = 0; // Successfully complete
22695- virtual void fail() = 0;
22696- void markAsNeedingAnotherRun();
22697-
22698- //! Register a nested ITracker
22699- void addChild( ITrackerPtr&& child );
22700- /**
22701- * Returns ptr to specific child if register with this tracker.
22702- *
22703- * Returns nullptr if not found.
22704- */
22705- ITracker* findChild( NameAndLocationRef const& nameAndLocation );
22706- //! Have any children been added?
22707- bool hasChildren() const {
22708- return !m_children.empty();
22709- }
22710-
22711-
22712- //! Marks tracker as executing a child, doing se recursively up the tree
22713- void openChild();
22714-
22715- /**
22716- * Returns true if the instance is a section tracker
22717- *
22718- * Subclasses should override to true if they are, replaces RTTI
22719- * for internal debug checks.
22720- */
22721- virtual bool isSectionTracker() const;
22722- /**
22723- * Returns true if the instance is a generator tracker
22724- *
22725- * Subclasses should override to true if they are, replaces RTTI
22726- * for internal debug checks.
22727- */
22728- virtual bool isGeneratorTracker() const;
22729- };
22730-
22731- class TrackerContext {
22732-
22733- enum RunState {
22734- NotStarted,
22735- Executing,
22736- CompletedCycle
22737- };
22738-
22739- ITrackerPtr m_rootTracker;
22740- ITracker* m_currentTracker = nullptr;
22741- RunState m_runState = NotStarted;
22742-
22743- public:
22744-
22745- ITracker& startRun();
22746-
22747- void startCycle() {
22748- m_currentTracker = m_rootTracker.get();
22749- m_runState = Executing;
22750- }
22751- void completeCycle();
22752-
22753- bool completedCycle() const;
22754- ITracker& currentTracker() { return *m_currentTracker; }
22755- void setCurrentTracker( ITracker* tracker );
22756- };
22757-
22758- class TrackerBase : public ITracker {
22759- protected:
22760-
22761- TrackerContext& m_ctx;
22762-
22763- public:
22764- TrackerBase( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent );
22765-
22766- bool isComplete() const override;
22767-
22768- void open();
22769-
22770- void close() override;
22771- void fail() override;
22772-
22773- private:
22774- void moveToParent();
22775- void moveToThis();
22776- };
22777-
22778- class SectionTracker : public TrackerBase {
22779- std::vector<StringRef> m_filters;
22780- // Note that lifetime-wise we piggy back off the name stored in the `ITracker` parent`.
22781- // Currently it allocates owns the name, so this is safe. If it is later refactored
22782- // to not own the name, the name still has to outlive the `ITracker` parent, so
22783- // this should still be safe.
22784- StringRef m_trimmed_name;
22785- public:
22786- SectionTracker( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent );
22787-
22788- bool isSectionTracker() const override;
22789-
22790- bool isComplete() const override;
22791-
22792- static SectionTracker& acquire( TrackerContext& ctx, NameAndLocationRef const& nameAndLocation );
22793-
22794- void tryOpen();
22795-
22796- void addInitialFilters( std::vector<std::string> const& filters );
22797- void addNextFilters( std::vector<StringRef> const& filters );
22798- //! Returns filters active in this tracker
22799- std::vector<StringRef> const& getFilters() const { return m_filters; }
22800- //! Returns whitespace-trimmed name of the tracked section
22801- StringRef trimmedName() const;
22802- };
22803-
22804-} // namespace TestCaseTracking
22805-
22806-using TestCaseTracking::ITracker;
22807-using TestCaseTracking::TrackerContext;
22808-using TestCaseTracking::SectionTracker;
22809-
22810-} // namespace Catch
22811-
22812-#endif // CATCH_TEST_CASE_TRACKER_HPP_INCLUDED
22813-
22814-
22815-#ifndef CATCH_THREAD_SUPPORT_HPP_INCLUDED
22816-#define CATCH_THREAD_SUPPORT_HPP_INCLUDED
22817-
22818-
22819-#if defined( CATCH_CONFIG_EXPERIMENTAL_THREAD_SAFE_ASSERTIONS )
22820-# include <atomic>
22821-# include <mutex>
22822-#endif
22823-
22824-
22825-namespace Catch {
22826- namespace Detail {
22827-#if defined( CATCH_CONFIG_EXPERIMENTAL_THREAD_SAFE_ASSERTIONS )
22828- using Mutex = std::mutex;
22829- using LockGuard = std::lock_guard<std::mutex>;
22830- struct AtomicCounts {
22831- std::atomic<std::uint64_t> passed = 0;
22832- std::atomic<std::uint64_t> failed = 0;
22833- std::atomic<std::uint64_t> failedButOk = 0;
22834- std::atomic<std::uint64_t> skipped = 0;
22835- };
22836-#else // ^^ Use actual mutex, lock and atomics
22837- // vv Dummy implementations for single-thread performance
22838-
22839- struct Mutex {
22840- void lock() {}
22841- void unlock() {}
22842- };
22843-
22844- struct LockGuard {
22845- LockGuard( Mutex ) {}
22846- };
22847-
22848- using AtomicCounts = Counts;
22849-#endif
22850-
22851- } // namespace Detail
22852-} // namespace Catch
22853-
22854-#endif // CATCH_THREAD_SUPPORT_HPP_INCLUDED
22855-
22856-#include <string>
22857-
22858-namespace Catch {
22859-
22860- class IGeneratorTracker;
22861- class IConfig;
22862- class IEventListener;
22863- using IEventListenerPtr = Detail::unique_ptr<IEventListener>;
22864- class OutputRedirect;
22865-
22866- ///////////////////////////////////////////////////////////////////////////
22867-
22868- class RunContext final : public IResultCapture {
22869-
22870- public:
22871- RunContext( RunContext const& ) = delete;
22872- RunContext& operator =( RunContext const& ) = delete;
22873-
22874- explicit RunContext( IConfig const* _config, IEventListenerPtr&& reporter );
22875-
22876- ~RunContext() override;
22877-
22878- Totals runTest(TestCaseHandle const& testCase);
22879-
22880- public: // IResultCapture
22881-
22882- // Assertion handlers
22883- void handleExpr
22884- ( AssertionInfo const& info,
22885- ITransientExpression const& expr,
22886- AssertionReaction& reaction ) override;
22887- void handleMessage
22888- ( AssertionInfo const& info,
22889- ResultWas::OfType resultType,
22890- std::string&& message,
22891- AssertionReaction& reaction ) override;
22892- void handleUnexpectedExceptionNotThrown
22893- ( AssertionInfo const& info,
22894- AssertionReaction& reaction ) override;
22895- void handleUnexpectedInflightException
22896- ( AssertionInfo const& info,
22897- std::string&& message,
22898- AssertionReaction& reaction ) override;
22899- void handleIncomplete
22900- ( AssertionInfo const& info ) override;
22901- void handleNonExpr
22902- ( AssertionInfo const &info,
22903- ResultWas::OfType resultType,
22904- AssertionReaction &reaction ) override;
22905-
22906- void notifyAssertionStarted( AssertionInfo const& info ) override;
22907- bool sectionStarted( StringRef sectionName,
22908- SourceLineInfo const& sectionLineInfo,
22909- Counts& assertions ) override;
22910-
22911- void sectionEnded( SectionEndInfo&& endInfo ) override;
22912- void sectionEndedEarly( SectionEndInfo&& endInfo ) override;
22913-
22914- IGeneratorTracker*
22915- acquireGeneratorTracker( StringRef generatorName,
22916- SourceLineInfo const& lineInfo ) override;
22917- IGeneratorTracker* createGeneratorTracker(
22918- StringRef generatorName,
22919- SourceLineInfo lineInfo,
22920- Generators::GeneratorBasePtr&& generator ) override;
22921-
22922-
22923- void benchmarkPreparing( StringRef name ) override;
22924- void benchmarkStarting( BenchmarkInfo const& info ) override;
22925- void benchmarkEnded( BenchmarkStats<> const& stats ) override;
22926- void benchmarkFailed( StringRef error ) override;
22927-
22928- std::string getCurrentTestName() const override;
22929-
22930- const AssertionResult* getLastResult() const override;
22931-
22932- void exceptionEarlyReported() override;
22933-
22934- void handleFatalErrorCondition( StringRef message ) override;
22935-
22936- bool lastAssertionPassed() override;
22937-
22938- public:
22939- // !TBD We need to do this another way!
22940- bool aborting() const;
22941-
22942- private:
22943- void assertionPassedFastPath( SourceLineInfo lineInfo );
22944- // Update the non-thread-safe m_totals from the atomic assertion counts.
22945- void updateTotalsFromAtomics();
22946-
22947- void runCurrentTest();
22948- void invokeActiveTestCase();
22949-
22950- bool testForMissingAssertions( Counts& assertions );
22951-
22952- void assertionEnded( AssertionResult&& result );
22953- void reportExpr
22954- ( AssertionInfo const &info,
22955- ResultWas::OfType resultType,
22956- ITransientExpression const *expr,
22957- bool negated );
22958-
22959- void populateReaction( AssertionReaction& reaction, bool has_normal_disposition );
22960-
22961- // Creates dummy info for unexpected exceptions/fatal errors,
22962- // where we do not have the access to one, but we still need
22963- // to send one to the reporters.
22964- AssertionInfo makeDummyAssertionInfo();
22965-
22966- private:
22967-
22968- void handleUnfinishedSections();
22969- mutable Detail::Mutex m_assertionMutex;
22970- TestRunInfo m_runInfo;
22971- TestCaseHandle const* m_activeTestCase = nullptr;
22972- ITracker* m_testCaseTracker = nullptr;
22973- Optional<AssertionResult> m_lastResult;
22974- IConfig const* m_config;
22975- Totals m_totals;
22976- Detail::AtomicCounts m_atomicAssertionCount;
22977- IEventListenerPtr m_reporter;
22978- std::vector<SectionEndInfo> m_unfinishedSections;
22979- std::vector<ITracker*> m_activeSections;
22980- TrackerContext m_trackerContext;
22981- Detail::unique_ptr<OutputRedirect> m_outputRedirect;
22982- FatalConditionHandler m_fatalConditionhandler;
22983- // Caches m_config->abortAfter() to avoid vptr calls/allow inlining
22984- size_t m_abortAfterXFailedAssertions;
22985- bool m_shouldReportUnexpected = true;
22986- // Caches whether `assertionStarting` events should be sent to the reporter.
22987- bool m_reportAssertionStarting;
22988- // Caches whether `assertionEnded` events for successful assertions should be sent to the reporter
22989- bool m_includeSuccessfulResults;
22990- // Caches m_config->shouldDebugBreak() to avoid vptr calls/allow inlining
22991- bool m_shouldDebugBreak;
22992- };
22993-
22994- void seedRng(IConfig const& config);
22995- unsigned int rngSeed();
22996-} // end namespace Catch
22997-
22998-#endif // CATCH_RUN_CONTEXT_HPP_INCLUDED
22999-
23000-
23001-#ifndef CATCH_SHARDING_HPP_INCLUDED
23002-#define CATCH_SHARDING_HPP_INCLUDED
23003-
23004-#include <cassert>
23005-#include <algorithm>
23006-
23007-namespace Catch {
23008-
23009- template<typename Container>
23010- Container createShard(Container const& container, std::size_t const shardCount, std::size_t const shardIndex) {
23011- assert(shardCount > shardIndex);
23012-
23013- if (shardCount == 1) {
23014- return container;
23015- }
23016-
23017- const std::size_t totalTestCount = container.size();
23018-
23019- const std::size_t shardSize = totalTestCount / shardCount;
23020- const std::size_t leftoverTests = totalTestCount % shardCount;
23021-
23022- const std::size_t startIndex = shardIndex * shardSize + (std::min)(shardIndex, leftoverTests);
23023- const std::size_t endIndex = (shardIndex + 1) * shardSize + (std::min)(shardIndex + 1, leftoverTests);
23024-
23025- auto startIterator = std::next(container.begin(), static_cast<std::ptrdiff_t>(startIndex));
23026- auto endIterator = std::next(container.begin(), static_cast<std::ptrdiff_t>(endIndex));
23027-
23028- return Container(startIterator, endIterator);
23029- }
23030-
23031-}
23032-
23033-#endif // CATCH_SHARDING_HPP_INCLUDED
23034-
23035-
23036-#ifndef CATCH_SINGLETONS_HPP_INCLUDED
23037-#define CATCH_SINGLETONS_HPP_INCLUDED
23038-
23039-namespace Catch {
23040-
23041- struct ISingleton {
23042- virtual ~ISingleton(); // = default
23043- };
23044-
23045-
23046- void addSingleton( ISingleton* singleton );
23047- void cleanupSingletons();
23048-
23049-
23050- template<typename SingletonImplT, typename InterfaceT = SingletonImplT, typename MutableInterfaceT = InterfaceT>
23051- class Singleton : SingletonImplT, public ISingleton {
23052-
23053- static auto getInternal() -> Singleton* {
23054- static Singleton* s_instance = nullptr;
23055- if( !s_instance ) {
23056- s_instance = new Singleton;
23057- addSingleton( s_instance );
23058- }
23059- return s_instance;
23060- }
23061-
23062- public:
23063- static auto get() -> InterfaceT const& {
23064- return *getInternal();
23065- }
23066- static auto getMutable() -> MutableInterfaceT& {
23067- return *getInternal();
23068- }
23069- };
23070-
23071-} // namespace Catch
23072-
23073-#endif // CATCH_SINGLETONS_HPP_INCLUDED
23074-
23075-
23076-#ifndef CATCH_STARTUP_EXCEPTION_REGISTRY_HPP_INCLUDED
23077-#define CATCH_STARTUP_EXCEPTION_REGISTRY_HPP_INCLUDED
23078-
23079-
23080-#include <vector>
23081-#include <exception>
23082-
23083-namespace Catch {
23084-
23085- class StartupExceptionRegistry {
23086-#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
23087- public:
23088- void add(std::exception_ptr const& exception) noexcept;
23089- std::vector<std::exception_ptr> const& getExceptions() const noexcept;
23090- private:
23091- std::vector<std::exception_ptr> m_exceptions;
23092-#endif
23093- };
23094-
23095-} // end namespace Catch
23096-
23097-#endif // CATCH_STARTUP_EXCEPTION_REGISTRY_HPP_INCLUDED
23098-
23099-
23100-
23101-#ifndef CATCH_STDSTREAMS_HPP_INCLUDED
23102-#define CATCH_STDSTREAMS_HPP_INCLUDED
23103-
23104-#include <iosfwd>
23105-
23106-namespace Catch {
23107-
23108- std::ostream& cout();
23109- std::ostream& cerr();
23110- std::ostream& clog();
23111-
23112-} // namespace Catch
23113-
23114-#endif
23115-
23116-
23117-#ifndef CATCH_STRING_MANIP_HPP_INCLUDED
23118-#define CATCH_STRING_MANIP_HPP_INCLUDED
23119-
23120-
23121-#include <cstdint>
23122-#include <string>
23123-#include <iosfwd>
23124-#include <vector>
23125-
23126-namespace Catch {
23127-
23128- bool startsWith( std::string const& s, std::string const& prefix );
23129- bool startsWith( StringRef s, char prefix );
23130- bool endsWith( std::string const& s, std::string const& suffix );
23131- bool endsWith( std::string const& s, char suffix );
23132- bool contains( std::string const& s, std::string const& infix );
23133- void toLowerInPlace( std::string& s );
23134- std::string toLower( std::string const& s );
23135- char toLower( char c );
23136- //! Returns a new string without whitespace at the start/end
23137- std::string trim( std::string const& str );
23138- //! Returns a substring of the original ref without whitespace. Beware lifetimes!
23139- StringRef trim(StringRef ref);
23140-
23141- // !!! Be aware, returns refs into original string - make sure original string outlives them
23142- std::vector<StringRef> splitStringRef( StringRef str, char delimiter );
23143- bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis );
23144-
23145- /**
23146- * Helper for streaming a "count [maybe-plural-of-label]" human-friendly string
23147- *
23148- * Usage example:
23149- * ```cpp
23150- * std::cout << "Found " << pluralise(count, "error") << '\n';
23151- * ```
23152- *
23153- * **Important:** The provided string must outlive the instance
23154- */
23155- class pluralise {
23156- std::uint64_t m_count;
23157- StringRef m_label;
23158-
23159- public:
23160- constexpr pluralise(std::uint64_t count, StringRef label):
23161- m_count(count),
23162- m_label(label)
23163- {}
23164-
23165- friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser );
23166- };
23167-}
23168-
23169-#endif // CATCH_STRING_MANIP_HPP_INCLUDED
23170-
23171-
23172-#ifndef CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED
23173-#define CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED
23174-
23175-
23176-#include <map>
23177-#include <string>
23178-
23179-namespace Catch {
23180- struct SourceLineInfo;
23181-
23182- class TagAliasRegistry : public ITagAliasRegistry {
23183- public:
23184- ~TagAliasRegistry() override;
23185- TagAlias const* find( std::string const& alias ) const override;
23186- std::string expandAliases( std::string const& unexpandedTestSpec ) const override;
23187- void add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo );
23188-
23189- private:
23190- std::map<std::string, TagAlias> m_registry;
23191- };
23192-
23193-} // end namespace Catch
23194-
23195-#endif // CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED
23196-
23197-
23198-#ifndef CATCH_TEST_CASE_INFO_HASHER_HPP_INCLUDED
23199-#define CATCH_TEST_CASE_INFO_HASHER_HPP_INCLUDED
23200-
23201-#include <cstdint>
23202-
23203-namespace Catch {
23204-
23205- struct TestCaseInfo;
23206-
23207- class TestCaseInfoHasher {
23208- public:
23209- using hash_t = std::uint64_t;
23210- TestCaseInfoHasher( hash_t seed );
23211- uint32_t operator()( TestCaseInfo const& t ) const;
23212-
23213- private:
23214- hash_t m_seed;
23215- };
23216-
23217-} // namespace Catch
23218-
23219-#endif /* CATCH_TEST_CASE_INFO_HASHER_HPP_INCLUDED */
23220-
23221-
23222-#ifndef CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED
23223-#define CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED
23224-
23225-
23226-#include <vector>
23227-
23228-namespace Catch {
23229-
23230- class IConfig;
23231- class ITestInvoker;
23232- class TestCaseHandle;
23233- class TestSpec;
23234-
23235- std::vector<TestCaseHandle> sortTests( IConfig const& config, std::vector<TestCaseHandle> const& unsortedTestCases );
23236-
23237- bool isThrowSafe( TestCaseHandle const& testCase, IConfig const& config );
23238-
23239- std::vector<TestCaseHandle> filterTests( std::vector<TestCaseHandle> const& testCases, TestSpec const& testSpec, IConfig const& config );
23240- std::vector<TestCaseHandle> const& getAllTestCasesSorted( IConfig const& config );
23241-
23242- class TestRegistry : public ITestCaseRegistry {
23243- public:
23244- void registerTest( Detail::unique_ptr<TestCaseInfo> testInfo, Detail::unique_ptr<ITestInvoker> testInvoker );
23245-
23246- std::vector<TestCaseInfo*> const& getAllInfos() const override;
23247- std::vector<TestCaseHandle> const& getAllTests() const override;
23248- std::vector<TestCaseHandle> const& getAllTestsSorted( IConfig const& config ) const override;
23249-
23250- ~TestRegistry() override; // = default
23251-
23252- private:
23253- std::vector<Detail::unique_ptr<TestCaseInfo>> m_owned_test_infos;
23254- // Keeps a materialized vector for `getAllInfos`.
23255- // We should get rid of that eventually (see interface note)
23256- std::vector<TestCaseInfo*> m_viewed_test_infos;
23257-
23258- std::vector<Detail::unique_ptr<ITestInvoker>> m_invokers;
23259- std::vector<TestCaseHandle> m_handles;
23260- mutable TestRunOrder m_currentSortOrder = TestRunOrder::Declared;
23261- mutable std::vector<TestCaseHandle> m_sortedFunctions;
23262- };
23263-
23264- ///////////////////////////////////////////////////////////////////////////
23265-
23266-
23267-} // end namespace Catch
23268-
23269-
23270-#endif // CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED
23271-
23272-
23273-#ifndef CATCH_TEST_SPEC_PARSER_HPP_INCLUDED
23274-#define CATCH_TEST_SPEC_PARSER_HPP_INCLUDED
23275-
23276-#ifdef __clang__
23277-#pragma clang diagnostic push
23278-#pragma clang diagnostic ignored "-Wpadded"
23279-#endif
23280-
23281-
23282-#include <vector>
23283-#include <string>
23284-
23285-namespace Catch {
23286-
23287- class ITagAliasRegistry;
23288-
23289- class TestSpecParser {
23290- enum Mode{ None, Name, QuotedName, Tag, EscapedName };
23291- Mode m_mode = None;
23292- Mode lastMode = None;
23293- bool m_exclusion = false;
23294- std::size_t m_pos = 0;
23295- std::size_t m_realPatternPos = 0;
23296- std::string m_arg;
23297- std::string m_substring;
23298- std::string m_patternName;
23299- std::vector<std::size_t> m_escapeChars;
23300- TestSpec::Filter m_currentFilter;
23301- TestSpec m_testSpec;
23302- ITagAliasRegistry const* m_tagAliases = nullptr;
23303-
23304- public:
23305- TestSpecParser( ITagAliasRegistry const& tagAliases );
23306-
23307- TestSpecParser& parse( std::string const& arg );
23308- TestSpec testSpec();
23309-
23310- private:
23311- bool visitChar( char c );
23312- void startNewMode( Mode mode );
23313- bool processNoneChar( char c );
23314- void processNameChar( char c );
23315- bool processOtherChar( char c );
23316- void endMode();
23317- void escape();
23318- bool isControlChar( char c ) const;
23319- void saveLastMode();
23320- void revertBackToLastMode();
23321- void addFilter();
23322- bool separate();
23323-
23324- // Handles common preprocessing of the pattern for name/tag patterns
23325- std::string preprocessPattern();
23326- // Adds the current pattern as a test name
23327- void addNamePattern();
23328- // Adds the current pattern as a tag
23329- void addTagPattern();
23330-
23331- inline void addCharToPattern(char c) {
23332- m_substring += c;
23333- m_patternName += c;
23334- m_realPatternPos++;
23335- }
23336-
23337- };
23338-
23339-} // namespace Catch
23340-
23341-#ifdef __clang__
23342-#pragma clang diagnostic pop
23343-#endif
23344-
23345-#endif // CATCH_TEST_SPEC_PARSER_HPP_INCLUDED
23346-
23347-
23348-#ifndef CATCH_TEXTFLOW_HPP_INCLUDED
23349-#define CATCH_TEXTFLOW_HPP_INCLUDED
23350-
23351-
23352-#include <cassert>
23353-#include <string>
23354-#include <vector>
23355-
23356-namespace Catch {
23357- namespace TextFlow {
23358-
23359- class Columns;
23360-
23361- /**
23362- * Abstraction for a string with ansi escape sequences that
23363- * automatically skips over escapes when iterating. Only graphical
23364- * escape sequences are considered.
23365- *
23366- * Internal representation:
23367- * An escape sequence looks like \033[39;49m
23368- * We need bidirectional iteration and the unbound length of escape
23369- * sequences poses a problem for operator-- To make this work we'll
23370- * replace the last `m` with a 0xff (this is a codepoint that won't have
23371- * any utf-8 meaning).
23372- */
23373- class AnsiSkippingString {
23374- std::string m_string;
23375- std::size_t m_size = 0;
23376-
23377- // perform 0xff replacement and calculate m_size
23378- void preprocessString();
23379-
23380- public:
23381- class const_iterator;
23382- using iterator = const_iterator;
23383- // note: must be u-suffixed or this will cause a "truncation of
23384- // constant value" warning on MSVC
23385- static constexpr char sentinel = static_cast<char>( 0xffu );
23386-
23387- explicit AnsiSkippingString( std::string const& text );
23388- explicit AnsiSkippingString( std::string&& text );
23389-
23390- const_iterator begin() const;
23391- const_iterator end() const;
23392-
23393- size_t size() const { return m_size; }
23394-
23395- std::string substring( const_iterator begin,
23396- const_iterator end ) const;
23397- };
23398-
23399- class AnsiSkippingString::const_iterator {
23400- friend AnsiSkippingString;
23401- struct EndTag {};
23402-
23403- const std::string* m_string;
23404- std::string::const_iterator m_it;
23405-
23406- explicit const_iterator( const std::string& string, EndTag ):
23407- m_string( &string ), m_it( string.end() ) {}
23408-
23409- void tryParseAnsiEscapes();
23410- void advance();
23411- void unadvance();
23412-
23413- public:
23414- using difference_type = std::ptrdiff_t;
23415- using value_type = char;
23416- using pointer = value_type*;
23417- using reference = value_type&;
23418- using iterator_category = std::bidirectional_iterator_tag;
23419-
23420- explicit const_iterator( const std::string& string ):
23421- m_string( &string ), m_it( string.begin() ) {
23422- tryParseAnsiEscapes();
23423- }
23424-
23425- char operator*() const { return *m_it; }
23426-
23427- const_iterator& operator++() {
23428- advance();
23429- return *this;
23430- }
23431- const_iterator operator++( int ) {
23432- iterator prev( *this );
23433- operator++();
23434- return prev;
23435- }
23436- const_iterator& operator--() {
23437- unadvance();
23438- return *this;
23439- }
23440- const_iterator operator--( int ) {
23441- iterator prev( *this );
23442- operator--();
23443- return prev;
23444- }
23445-
23446- bool operator==( const_iterator const& other ) const {
23447- return m_it == other.m_it;
23448- }
23449- bool operator!=( const_iterator const& other ) const {
23450- return !operator==( other );
23451- }
23452- bool operator<=( const_iterator const& other ) const {
23453- return m_it <= other.m_it;
23454- }
23455-
23456- const_iterator oneBefore() const {
23457- auto it = *this;
23458- return --it;
23459- }
23460- };
23461-
23462- /**
23463- * Represents a column of text with specific width and indentation
23464- *
23465- * When written out to a stream, it will perform linebreaking
23466- * of the provided text so that the written lines fit within
23467- * target width.
23468- */
23469- class Column {
23470- // String to be written out
23471- AnsiSkippingString m_string;
23472- // Width of the column for linebreaking
23473- size_t m_width = CATCH_CONFIG_CONSOLE_WIDTH - 1;
23474- // Indentation of other lines (including first if initial indent is
23475- // unset)
23476- size_t m_indent = 0;
23477- // Indentation of the first line
23478- size_t m_initialIndent = std::string::npos;
23479-
23480- public:
23481- /**
23482- * Iterates "lines" in `Column` and returns them
23483- */
23484- class const_iterator {
23485- friend Column;
23486- struct EndTag {};
23487-
23488- Column const& m_column;
23489- // Where does the current line start?
23490- AnsiSkippingString::const_iterator m_lineStart;
23491- // How long should the current line be?
23492- AnsiSkippingString::const_iterator m_lineEnd;
23493- // How far have we checked the string to iterate?
23494- AnsiSkippingString::const_iterator m_parsedTo;
23495- // Should a '-' be appended to the line?
23496- bool m_addHyphen = false;
23497-
23498- const_iterator( Column const& column, EndTag ):
23499- m_column( column ),
23500- m_lineStart( m_column.m_string.end() ),
23501- m_lineEnd( column.m_string.end() ),
23502- m_parsedTo( column.m_string.end() ) {}
23503-
23504- // Calculates the length of the current line
23505- void calcLength();
23506-
23507- // Returns current indentation width
23508- size_t indentSize() const;
23509-
23510- // Creates an indented and (optionally) suffixed string from
23511- // current iterator position, indentation and length.
23512- std::string addIndentAndSuffix(
23513- AnsiSkippingString::const_iterator start,
23514- AnsiSkippingString::const_iterator end ) const;
23515-
23516- public:
23517- using difference_type = std::ptrdiff_t;
23518- using value_type = std::string;
23519- using pointer = value_type*;
23520- using reference = value_type&;
23521- using iterator_category = std::forward_iterator_tag;
23522-
23523- explicit const_iterator( Column const& column );
23524-
23525- std::string operator*() const;
23526-
23527- const_iterator& operator++();
23528- const_iterator operator++( int );
23529-
23530- bool operator==( const_iterator const& other ) const {
23531- return m_lineStart == other.m_lineStart &&
23532- &m_column == &other.m_column;
23533- }
23534- bool operator!=( const_iterator const& other ) const {
23535- return !operator==( other );
23536- }
23537- };
23538- using iterator = const_iterator;
23539-
23540- explicit Column( std::string const& text ): m_string( text ) {}
23541- explicit Column( std::string&& text ):
23542- m_string( CATCH_MOVE( text ) ) {}
23543-
23544- Column& width( size_t newWidth ) & {
23545- assert( newWidth > 0 );
23546- m_width = newWidth;
23547- return *this;
23548- }
23549- Column&& width( size_t newWidth ) && {
23550- assert( newWidth > 0 );
23551- m_width = newWidth;
23552- return CATCH_MOVE( *this );
23553- }
23554- Column& indent( size_t newIndent ) & {
23555- m_indent = newIndent;
23556- return *this;
23557- }
23558- Column&& indent( size_t newIndent ) && {
23559- m_indent = newIndent;
23560- return CATCH_MOVE( *this );
23561- }
23562- Column& initialIndent( size_t newIndent ) & {
23563- m_initialIndent = newIndent;
23564- return *this;
23565- }
23566- Column&& initialIndent( size_t newIndent ) && {
23567- m_initialIndent = newIndent;
23568- return CATCH_MOVE( *this );
23569- }
23570-
23571- size_t width() const { return m_width; }
23572- const_iterator begin() const { return const_iterator( *this ); }
23573- const_iterator end() const {
23574- return { *this, const_iterator::EndTag{} };
23575- }
23576-
23577- friend std::ostream& operator<<( std::ostream& os,
23578- Column const& col );
23579-
23580- friend Columns operator+( Column const& lhs, Column const& rhs );
23581- friend Columns operator+( Column&& lhs, Column&& rhs );
23582- };
23583-
23584- //! Creates a column that serves as an empty space of specific width
23585- Column Spacer( size_t spaceWidth );
23586-
23587- class Columns {
23588- std::vector<Column> m_columns;
23589-
23590- public:
23591- class iterator {
23592- friend Columns;
23593- struct EndTag {};
23594-
23595- std::vector<Column> const& m_columns;
23596- std::vector<Column::const_iterator> m_iterators;
23597- size_t m_activeIterators;
23598-
23599- iterator( Columns const& columns, EndTag );
23600-
23601- public:
23602- using difference_type = std::ptrdiff_t;
23603- using value_type = std::string;
23604- using pointer = value_type*;
23605- using reference = value_type&;
23606- using iterator_category = std::forward_iterator_tag;
23607-
23608- explicit iterator( Columns const& columns );
23609-
23610- auto operator==( iterator const& other ) const -> bool {
23611- return m_iterators == other.m_iterators;
23612- }
23613- auto operator!=( iterator const& other ) const -> bool {
23614- return m_iterators != other.m_iterators;
23615- }
23616- std::string operator*() const;
23617- iterator& operator++();
23618- iterator operator++( int );
23619- };
23620- using const_iterator = iterator;
23621-
23622- iterator begin() const { return iterator( *this ); }
23623- iterator end() const { return { *this, iterator::EndTag() }; }
23624-
23625- friend Columns& operator+=( Columns& lhs, Column const& rhs );
23626- friend Columns& operator+=( Columns& lhs, Column&& rhs );
23627- friend Columns operator+( Columns const& lhs, Column const& rhs );
23628- friend Columns operator+( Columns&& lhs, Column&& rhs );
23629-
23630- friend std::ostream& operator<<( std::ostream& os,
23631- Columns const& cols );
23632- };
23633-
23634- } // namespace TextFlow
23635-} // namespace Catch
23636-#endif // CATCH_TEXTFLOW_HPP_INCLUDED
23637-
23638-
23639-#ifndef CATCH_TO_STRING_HPP_INCLUDED
23640-#define CATCH_TO_STRING_HPP_INCLUDED
23641-
23642-#include <string>
23643-
23644-
23645-namespace Catch {
23646- template <typename T>
23647- std::string to_string(T const& t) {
23648-#if defined(CATCH_CONFIG_CPP11_TO_STRING)
23649- return std::to_string(t);
23650-#else
23651- ReusableStringStream rss;
23652- rss << t;
23653- return rss.str();
23654-#endif
23655- }
23656-} // end namespace Catch
23657-
23658-#endif // CATCH_TO_STRING_HPP_INCLUDED
23659-
23660-
23661-#ifndef CATCH_UNCAUGHT_EXCEPTIONS_HPP_INCLUDED
23662-#define CATCH_UNCAUGHT_EXCEPTIONS_HPP_INCLUDED
23663-
23664-namespace Catch {
23665- bool uncaught_exceptions();
23666-} // end namespace Catch
23667-
23668-#endif // CATCH_UNCAUGHT_EXCEPTIONS_HPP_INCLUDED
23669-
23670-
23671-#ifndef CATCH_XMLWRITER_HPP_INCLUDED
23672-#define CATCH_XMLWRITER_HPP_INCLUDED
23673-
23674-
23675-#include <iosfwd>
23676-#include <vector>
23677-#include <cstdint>
23678-
23679-namespace Catch {
23680- enum class XmlFormatting : std::uint8_t {
23681- None = 0x00,
23682- Indent = 0x01,
23683- Newline = 0x02,
23684- };
23685-
23686- constexpr XmlFormatting operator|( XmlFormatting lhs, XmlFormatting rhs ) {
23687- return static_cast<XmlFormatting>( static_cast<std::uint8_t>( lhs ) |
23688- static_cast<std::uint8_t>( rhs ) );
23689- }
23690-
23691- constexpr XmlFormatting operator&( XmlFormatting lhs, XmlFormatting rhs ) {
23692- return static_cast<XmlFormatting>( static_cast<std::uint8_t>( lhs ) &
23693- static_cast<std::uint8_t>( rhs ) );
23694- }
23695-
23696-
23697- /**
23698- * Helper for XML-encoding text (escaping angle brackets, quotes, etc)
23699- *
23700- * Note: doesn't take ownership of passed strings, and thus the
23701- * encoded string must outlive the encoding instance.
23702- */
23703- class XmlEncode {
23704- public:
23705- enum ForWhat { ForTextNodes, ForAttributes };
23706-
23707- constexpr XmlEncode( StringRef str, ForWhat forWhat = ForTextNodes ):
23708- m_str( str ), m_forWhat( forWhat ) {}
23709-
23710-
23711- void encodeTo( std::ostream& os ) const;
23712-
23713- friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode );
23714-
23715- private:
23716- StringRef m_str;
23717- ForWhat m_forWhat;
23718- };
23719-
23720- class XmlWriter {
23721- public:
23722-
23723- class ScopedElement {
23724- public:
23725- ScopedElement( XmlWriter* writer, XmlFormatting fmt );
23726-
23727- ScopedElement( ScopedElement&& other ) noexcept;
23728- ScopedElement& operator=( ScopedElement&& other ) noexcept;
23729-
23730- ~ScopedElement();
23731-
23732- ScopedElement&
23733- writeText( StringRef text,
23734- XmlFormatting fmt = XmlFormatting::Newline |
23735- XmlFormatting::Indent );
23736-
23737- ScopedElement& writeAttribute( StringRef name,
23738- StringRef attribute );
23739- template <typename T,
23740- // Without this SFINAE, this overload is a better match
23741- // for `std::string`, `char const*`, `char const[N]` args.
23742- // While it would still work, it would cause code bloat
23743- // and multiple iteration over the strings
23744- typename = typename std::enable_if_t<
23745- !std::is_convertible<T, StringRef>::value>>
23746- ScopedElement& writeAttribute( StringRef name,
23747- T const& attribute ) {
23748- m_writer->writeAttribute( name, attribute );
23749- return *this;
23750- }
23751-
23752- private:
23753- XmlWriter* m_writer = nullptr;
23754- XmlFormatting m_fmt;
23755- };
23756-
23757- XmlWriter( std::ostream& os );
23758- ~XmlWriter();
23759-
23760- XmlWriter( XmlWriter const& ) = delete;
23761- XmlWriter& operator=( XmlWriter const& ) = delete;
23762-
23763- XmlWriter& startElement( std::string const& name, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
23764-
23765- ScopedElement scopedElement( std::string const& name, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
23766-
23767- XmlWriter& endElement(XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
23768-
23769- //! The attribute content is XML-encoded
23770- XmlWriter& writeAttribute( StringRef name, StringRef attribute );
23771-
23772- //! Writes the attribute as "true/false"
23773- XmlWriter& writeAttribute( StringRef name, bool attribute );
23774-
23775- //! The attribute content is XML-encoded
23776- XmlWriter& writeAttribute( StringRef name, char const* attribute );
23777-
23778- //! The attribute value must provide op<<(ostream&, T). The resulting
23779- //! serialization is XML-encoded
23780- template <typename T,
23781- // Without this SFINAE, this overload is a better match
23782- // for `std::string`, `char const*`, `char const[N]` args.
23783- // While it would still work, it would cause code bloat
23784- // and multiple iteration over the strings
23785- typename = typename std::enable_if_t<
23786- !std::is_convertible<T, StringRef>::value>>
23787- XmlWriter& writeAttribute( StringRef name, T const& attribute ) {
23788- ReusableStringStream rss;
23789- rss << attribute;
23790- return writeAttribute( name, rss.str() );
23791- }
23792-
23793- //! Writes escaped `text` in a element
23794- XmlWriter& writeText( StringRef text,
23795- XmlFormatting fmt = XmlFormatting::Newline |
23796- XmlFormatting::Indent );
23797-
23798- //! Writes XML comment as "<!-- text -->"
23799- XmlWriter& writeComment( StringRef text,
23800- XmlFormatting fmt = XmlFormatting::Newline |
23801- XmlFormatting::Indent );
23802-
23803- void writeStylesheetRef( StringRef url );
23804-
23805- void ensureTagClosed();
23806-
23807- private:
23808-
23809- void applyFormatting(XmlFormatting fmt);
23810-
23811- void writeDeclaration();
23812-
23813- void newlineIfNecessary();
23814-
23815- bool m_tagIsOpen = false;
23816- bool m_needsNewline = false;
23817- std::vector<std::string> m_tags;
23818- std::string m_indent;
23819- std::ostream& m_os;
23820- };
23821-
23822-}
23823-
23824-#endif // CATCH_XMLWRITER_HPP_INCLUDED
23825-
23826-
23827-/** \file
23828- * This is a convenience header for Catch2's Matcher support. It includes
23829- * **all** of Catch2 headers related to matchers.
23830- *
23831- * Generally the Catch2 users should use specific includes they need,
23832- * but this header can be used instead for ease-of-experimentation, or
23833- * just plain convenience, at the cost of increased compilation times.
23834- *
23835- * When a new header is added to either the `matchers` folder, or to
23836- * the corresponding internal subfolder, it should be added here.
23837- */
23838-
23839-#ifndef CATCH_MATCHERS_ALL_HPP_INCLUDED
23840-#define CATCH_MATCHERS_ALL_HPP_INCLUDED
23841-
23842-
23843-
23844-#ifndef CATCH_MATCHERS_HPP_INCLUDED
23845-#define CATCH_MATCHERS_HPP_INCLUDED
23846-
23847-
23848-
23849-#ifndef CATCH_MATCHERS_IMPL_HPP_INCLUDED
23850-#define CATCH_MATCHERS_IMPL_HPP_INCLUDED
23851-
23852-
23853-#include <string>
23854-
23855-namespace Catch {
23856-
23857-#ifdef __clang__
23858-# pragma clang diagnostic push
23859-# pragma clang diagnostic ignored "-Wsign-compare"
23860-# pragma clang diagnostic ignored "-Wnon-virtual-dtor"
23861-#elif defined __GNUC__
23862-# pragma GCC diagnostic push
23863-# pragma GCC diagnostic ignored "-Wsign-compare"
23864-# pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
23865-#endif
23866-
23867- template<typename ArgT, typename MatcherT>
23868- class MatchExpr : public ITransientExpression {
23869- ArgT && m_arg;
23870- MatcherT const& m_matcher;
23871- public:
23872- constexpr MatchExpr( ArgT && arg, MatcherT const& matcher )
23873- : ITransientExpression{ true, matcher.match( arg ) }, // not forwarding arg here on purpose
23874- m_arg( CATCH_FORWARD(arg) ),
23875- m_matcher( matcher )
23876- {}
23877-
23878- void streamReconstructedExpression( std::ostream& os ) const override {
23879- os << Catch::Detail::stringify( m_arg )
23880- << ' '
23881- << m_matcher.toString();
23882- }
23883- };
23884-
23885-#ifdef __clang__
23886-# pragma clang diagnostic pop
23887-#elif defined __GNUC__
23888-# pragma GCC diagnostic pop
23889-#endif
23890-
23891-
23892- namespace Matchers {
23893- template <typename ArgT>
23894- class MatcherBase;
23895- }
23896-
23897- using StringMatcher = Matchers::MatcherBase<std::string>;
23898-
23899- void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher );
23900-
23901- template<typename ArgT, typename MatcherT>
23902- constexpr MatchExpr<ArgT, MatcherT>
23903- makeMatchExpr( ArgT&& arg, MatcherT const& matcher ) {
23904- return MatchExpr<ArgT, MatcherT>( CATCH_FORWARD(arg), matcher );
23905- }
23906-
23907-} // namespace Catch
23908-
23909-
23910-///////////////////////////////////////////////////////////////////////////////
23911-#define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \
23912- do { \
23913- Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
23914- INTERNAL_CATCH_TRY { \
23915- catchAssertionHandler.handleExpr( Catch::makeMatchExpr( arg, matcher ) ); \
23916- } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
23917- catchAssertionHandler.complete(); \
23918- } while( false )
23919-
23920-
23921-///////////////////////////////////////////////////////////////////////////////
23922-#define INTERNAL_CATCH_THROWS_MATCHES( macroName, exceptionType, resultDisposition, matcher, ... ) \
23923- do { \
23924- Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(exceptionType) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
23925- if( catchAssertionHandler.allowThrows() ) \
23926- try { \
23927- CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
23928- CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \
23929- static_cast<void>(__VA_ARGS__ ); \
23930- CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
23931- catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
23932- } \
23933- catch( exceptionType const& ex ) { \
23934- catchAssertionHandler.handleExpr( Catch::makeMatchExpr( ex, matcher ) ); \
23935- } \
23936- catch( ... ) { \
23937- catchAssertionHandler.handleUnexpectedInflightException(); \
23938- } \
23939- else \
23940- catchAssertionHandler.handleThrowingCallSkipped(); \
23941- catchAssertionHandler.complete(); \
23942- } while( false )
23943-
23944-
23945-#endif // CATCH_MATCHERS_IMPL_HPP_INCLUDED
23946-
23947-#include <string>
23948-#include <vector>
23949-
23950-namespace Catch {
23951-namespace Matchers {
23952-
23953- class MatcherUntypedBase {
23954- public:
23955- MatcherUntypedBase() = default;
23956-
23957- MatcherUntypedBase(MatcherUntypedBase const&) = default;
23958- MatcherUntypedBase(MatcherUntypedBase&&) = default;
23959-
23960- MatcherUntypedBase& operator = (MatcherUntypedBase const&) = delete;
23961- MatcherUntypedBase& operator = (MatcherUntypedBase&&) = delete;
23962-
23963- std::string toString() const;
23964-
23965- protected:
23966- virtual ~MatcherUntypedBase(); // = default;
23967- virtual std::string describe() const = 0;
23968- mutable std::string m_cachedToString;
23969- };
23970-
23971-
23972- template<typename T>
23973- class MatcherBase : public MatcherUntypedBase {
23974- public:
23975- virtual bool match( T const& arg ) const = 0;
23976- };
23977-
23978- namespace Detail {
23979-
23980- template<typename ArgT>
23981- class MatchAllOf final : public MatcherBase<ArgT> {
23982- std::vector<MatcherBase<ArgT> const*> m_matchers;
23983-
23984- public:
23985- MatchAllOf() = default;
23986- MatchAllOf(MatchAllOf const&) = delete;
23987- MatchAllOf& operator=(MatchAllOf const&) = delete;
23988- MatchAllOf(MatchAllOf&&) = default;
23989- MatchAllOf& operator=(MatchAllOf&&) = default;
23990-
23991-
23992- bool match( ArgT const& arg ) const override {
23993- for( auto matcher : m_matchers ) {
23994- if (!matcher->match(arg))
23995- return false;
23996- }
23997- return true;
23998- }
23999- std::string describe() const override {
24000- std::string description;
24001- description.reserve( 4 + m_matchers.size()*32 );
24002- description += "( ";
24003- bool first = true;
24004- for( auto matcher : m_matchers ) {
24005- if( first )
24006- first = false;
24007- else
24008- description += " and ";
24009- description += matcher->toString();
24010- }
24011- description += " )";
24012- return description;
24013- }
24014-
24015- friend MatchAllOf operator&& (MatchAllOf&& lhs, MatcherBase<ArgT> const& rhs) {
24016- lhs.m_matchers.push_back(&rhs);
24017- return CATCH_MOVE(lhs);
24018- }
24019- friend MatchAllOf operator&& (MatcherBase<ArgT> const& lhs, MatchAllOf&& rhs) {
24020- rhs.m_matchers.insert(rhs.m_matchers.begin(), &lhs);
24021- return CATCH_MOVE(rhs);
24022- }
24023- };
24024-
24025- //! lvalue overload is intentionally deleted, users should
24026- //! not be trying to compose stored composition matchers
24027- template<typename ArgT>
24028- MatchAllOf<ArgT> operator&& (MatchAllOf<ArgT> const& lhs, MatcherBase<ArgT> const& rhs) = delete;
24029- //! lvalue overload is intentionally deleted, users should
24030- //! not be trying to compose stored composition matchers
24031- template<typename ArgT>
24032- MatchAllOf<ArgT> operator&& (MatcherBase<ArgT> const& lhs, MatchAllOf<ArgT> const& rhs) = delete;
24033-
24034- template<typename ArgT>
24035- class MatchAnyOf final : public MatcherBase<ArgT> {
24036- std::vector<MatcherBase<ArgT> const*> m_matchers;
24037- public:
24038- MatchAnyOf() = default;
24039- MatchAnyOf(MatchAnyOf const&) = delete;
24040- MatchAnyOf& operator=(MatchAnyOf const&) = delete;
24041- MatchAnyOf(MatchAnyOf&&) = default;
24042- MatchAnyOf& operator=(MatchAnyOf&&) = default;
24043-
24044- bool match( ArgT const& arg ) const override {
24045- for( auto matcher : m_matchers ) {
24046- if (matcher->match(arg))
24047- return true;
24048- }
24049- return false;
24050- }
24051- std::string describe() const override {
24052- std::string description;
24053- description.reserve( 4 + m_matchers.size()*32 );
24054- description += "( ";
24055- bool first = true;
24056- for( auto matcher : m_matchers ) {
24057- if( first )
24058- first = false;
24059- else
24060- description += " or ";
24061- description += matcher->toString();
24062- }
24063- description += " )";
24064- return description;
24065- }
24066-
24067- friend MatchAnyOf operator|| (MatchAnyOf&& lhs, MatcherBase<ArgT> const& rhs) {
24068- lhs.m_matchers.push_back(&rhs);
24069- return CATCH_MOVE(lhs);
24070- }
24071- friend MatchAnyOf operator|| (MatcherBase<ArgT> const& lhs, MatchAnyOf&& rhs) {
24072- rhs.m_matchers.insert(rhs.m_matchers.begin(), &lhs);
24073- return CATCH_MOVE(rhs);
24074- }
24075- };
24076-
24077- //! lvalue overload is intentionally deleted, users should
24078- //! not be trying to compose stored composition matchers
24079- template<typename ArgT>
24080- MatchAnyOf<ArgT> operator|| (MatchAnyOf<ArgT> const& lhs, MatcherBase<ArgT> const& rhs) = delete;
24081- //! lvalue overload is intentionally deleted, users should
24082- //! not be trying to compose stored composition matchers
24083- template<typename ArgT>
24084- MatchAnyOf<ArgT> operator|| (MatcherBase<ArgT> const& lhs, MatchAnyOf<ArgT> const& rhs) = delete;
24085-
24086- template<typename ArgT>
24087- class MatchNotOf final : public MatcherBase<ArgT> {
24088- MatcherBase<ArgT> const& m_underlyingMatcher;
24089-
24090- public:
24091- explicit MatchNotOf( MatcherBase<ArgT> const& underlyingMatcher ):
24092- m_underlyingMatcher( underlyingMatcher )
24093- {}
24094-
24095- bool match( ArgT const& arg ) const override {
24096- return !m_underlyingMatcher.match( arg );
24097- }
24098-
24099- std::string describe() const override {
24100- return "not " + m_underlyingMatcher.toString();
24101- }
24102- };
24103-
24104- } // namespace Detail
24105-
24106- template <typename T>
24107- Detail::MatchAllOf<T> operator&& (MatcherBase<T> const& lhs, MatcherBase<T> const& rhs) {
24108- return Detail::MatchAllOf<T>{} && lhs && rhs;
24109- }
24110- template <typename T>
24111- Detail::MatchAnyOf<T> operator|| (MatcherBase<T> const& lhs, MatcherBase<T> const& rhs) {
24112- return Detail::MatchAnyOf<T>{} || lhs || rhs;
24113- }
24114-
24115- template <typename T>
24116- Detail::MatchNotOf<T> operator! (MatcherBase<T> const& matcher) {
24117- return Detail::MatchNotOf<T>{ matcher };
24118- }
24119-
24120-
24121-} // namespace Matchers
24122-} // namespace Catch
24123-
24124-
24125-#if defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE)
24126- #define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr )
24127- #define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr )
24128-
24129- #define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
24130- #define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
24131-
24132- #define CATCH_CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg )
24133- #define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )
24134-
24135-#elif defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE)
24136-
24137- #define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) (void)(0)
24138- #define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0)
24139-
24140- #define CATCH_CHECK_THROWS_WITH( expr, matcher ) (void)(0)
24141- #define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0)
24142-
24143- #define CATCH_CHECK_THAT( arg, matcher ) (void)(0)
24144- #define CATCH_REQUIRE_THAT( arg, matcher ) (void)(0)
24145-
24146-#elif !defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE)
24147-
24148- #define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr )
24149- #define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr )
24150-
24151- #define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
24152- #define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
24153-
24154- #define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg )
24155- #define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )
24156-
24157-#elif !defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE)
24158-
24159- #define REQUIRE_THROWS_WITH( expr, matcher ) (void)(0)
24160- #define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0)
24161-
24162- #define CHECK_THROWS_WITH( expr, matcher ) (void)(0)
24163- #define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0)
24164-
24165- #define CHECK_THAT( arg, matcher ) (void)(0)
24166- #define REQUIRE_THAT( arg, matcher ) (void)(0)
24167-
24168-#endif // end of user facing macro declarations
24169-
24170-#endif // CATCH_MATCHERS_HPP_INCLUDED
24171-
24172-
24173-#ifndef CATCH_MATCHERS_CONTAINER_PROPERTIES_HPP_INCLUDED
24174-#define CATCH_MATCHERS_CONTAINER_PROPERTIES_HPP_INCLUDED
24175-
24176-
24177-
24178-#ifndef CATCH_MATCHERS_TEMPLATED_HPP_INCLUDED
24179-#define CATCH_MATCHERS_TEMPLATED_HPP_INCLUDED
24180-
24181-
24182-#include <array>
24183-#include <algorithm>
24184-#include <string>
24185-#include <type_traits>
24186-
24187-namespace Catch {
24188-namespace Matchers {
24189- class MatcherGenericBase : public MatcherUntypedBase {
24190- public:
24191- MatcherGenericBase() = default;
24192- ~MatcherGenericBase() override; // = default;
24193-
24194- MatcherGenericBase(MatcherGenericBase const&) = default;
24195- MatcherGenericBase(MatcherGenericBase&&) = default;
24196-
24197- MatcherGenericBase& operator=(MatcherGenericBase const&) = delete;
24198- MatcherGenericBase& operator=(MatcherGenericBase&&) = delete;
24199- };
24200-
24201-
24202- namespace Detail {
24203- template<std::size_t N, std::size_t M>
24204- std::array<void const*, N + M> array_cat(std::array<void const*, N> && lhs, std::array<void const*, M> && rhs) {
24205- std::array<void const*, N + M> arr{};
24206- std::copy_n(lhs.begin(), N, arr.begin());
24207- std::copy_n(rhs.begin(), M, arr.begin() + N);
24208- return arr;
24209- }
24210-
24211- template<std::size_t N>
24212- std::array<void const*, N+1> array_cat(std::array<void const*, N> && lhs, void const* rhs) {
24213- std::array<void const*, N+1> arr{};
24214- std::copy_n(lhs.begin(), N, arr.begin());
24215- arr[N] = rhs;
24216- return arr;
24217- }
24218-
24219- template<std::size_t N>
24220- std::array<void const*, N+1> array_cat(void const* lhs, std::array<void const*, N> && rhs) {
24221- std::array<void const*, N + 1> arr{ {lhs} };
24222- std::copy_n(rhs.begin(), N, arr.begin() + 1);
24223- return arr;
24224- }
24225-
24226- template<typename T>
24227- static constexpr bool is_generic_matcher_v = std::is_base_of<
24228- Catch::Matchers::MatcherGenericBase,
24229- std::remove_cv_t<std::remove_reference_t<T>>
24230- >::value;
24231-
24232- template<typename... Ts>
24233- static constexpr bool are_generic_matchers_v = Catch::Detail::conjunction<std::integral_constant<bool,is_generic_matcher_v<Ts>>...>::value;
24234-
24235- template<typename T>
24236- static constexpr bool is_matcher_v = std::is_base_of<
24237- Catch::Matchers::MatcherUntypedBase,
24238- std::remove_cv_t<std::remove_reference_t<T>>
24239- >::value;
24240-
24241-
24242- template<std::size_t N, typename Arg>
24243- bool match_all_of(Arg&&, std::array<void const*, N> const&, std::index_sequence<>) {
24244- return true;
24245- }
24246-
24247- template<typename T, typename... MatcherTs, std::size_t N, typename Arg, std::size_t Idx, std::size_t... Indices>
24248- bool match_all_of(Arg&& arg, std::array<void const*, N> const& matchers, std::index_sequence<Idx, Indices...>) {
24249- return static_cast<T const*>(matchers[Idx])->match(arg) && match_all_of<MatcherTs...>(arg, matchers, std::index_sequence<Indices...>{});
24250- }
24251-
24252-
24253- template<std::size_t N, typename Arg>
24254- bool match_any_of(Arg&&, std::array<void const*, N> const&, std::index_sequence<>) {
24255- return false;
24256- }
24257-
24258- template<typename T, typename... MatcherTs, std::size_t N, typename Arg, std::size_t Idx, std::size_t... Indices>
24259- bool match_any_of(Arg&& arg, std::array<void const*, N> const& matchers, std::index_sequence<Idx, Indices...>) {
24260- return static_cast<T const*>(matchers[Idx])->match(arg) || match_any_of<MatcherTs...>(arg, matchers, std::index_sequence<Indices...>{});
24261- }
24262-
24263- std::string describe_multi_matcher(StringRef combine, std::string const* descriptions_begin, std::string const* descriptions_end);
24264-
24265- template<typename... MatcherTs, std::size_t... Idx>
24266- std::string describe_multi_matcher(StringRef combine, std::array<void const*, sizeof...(MatcherTs)> const& matchers, std::index_sequence<Idx...>) {
24267- std::array<std::string, sizeof...(MatcherTs)> descriptions {{
24268- static_cast<MatcherTs const*>(matchers[Idx])->toString()...
24269- }};
24270-
24271- return describe_multi_matcher(combine, descriptions.data(), descriptions.data() + descriptions.size());
24272- }
24273-
24274-
24275- template<typename... MatcherTs>
24276- class MatchAllOfGeneric final : public MatcherGenericBase {
24277- public:
24278- MatchAllOfGeneric(MatchAllOfGeneric const&) = delete;
24279- MatchAllOfGeneric& operator=(MatchAllOfGeneric const&) = delete;
24280- MatchAllOfGeneric(MatchAllOfGeneric&&) = default;
24281- MatchAllOfGeneric& operator=(MatchAllOfGeneric&&) = default;
24282-
24283- MatchAllOfGeneric(MatcherTs const&... matchers) : m_matchers{ {std::addressof(matchers)...} } {}
24284- explicit MatchAllOfGeneric(std::array<void const*, sizeof...(MatcherTs)> matchers) : m_matchers{matchers} {}
24285-
24286- template<typename Arg>
24287- bool match(Arg&& arg) const {
24288- return match_all_of<MatcherTs...>(arg, m_matchers, std::index_sequence_for<MatcherTs...>{});
24289- }
24290-
24291- std::string describe() const override {
24292- return describe_multi_matcher<MatcherTs...>(" and "_sr, m_matchers, std::index_sequence_for<MatcherTs...>{});
24293- }
24294-
24295- // Has to be public to enable the concatenating operators
24296- // below, because they are not friend of the RHS, only LHS,
24297- // and thus cannot access private fields of RHS
24298- std::array<void const*, sizeof...( MatcherTs )> m_matchers;
24299-
24300-
24301- //! Avoids type nesting for `GenericAllOf && GenericAllOf` case
24302- template<typename... MatchersRHS>
24303- friend
24304- MatchAllOfGeneric<MatcherTs..., MatchersRHS...> operator && (
24305- MatchAllOfGeneric<MatcherTs...>&& lhs,
24306- MatchAllOfGeneric<MatchersRHS...>&& rhs) {
24307- return MatchAllOfGeneric<MatcherTs..., MatchersRHS...>{array_cat(CATCH_MOVE(lhs.m_matchers), CATCH_MOVE(rhs.m_matchers))};
24308- }
24309-
24310- //! Avoids type nesting for `GenericAllOf && some matcher` case
24311- template<typename MatcherRHS>
24312- friend std::enable_if_t<is_matcher_v<MatcherRHS>,
24313- MatchAllOfGeneric<MatcherTs..., MatcherRHS>> operator && (
24314- MatchAllOfGeneric<MatcherTs...>&& lhs,
24315- MatcherRHS const& rhs) {
24316- return MatchAllOfGeneric<MatcherTs..., MatcherRHS>{array_cat(CATCH_MOVE(lhs.m_matchers), static_cast<void const*>(&rhs))};
24317- }
24318-
24319- //! Avoids type nesting for `some matcher && GenericAllOf` case
24320- template<typename MatcherLHS>
24321- friend std::enable_if_t<is_matcher_v<MatcherLHS>,
24322- MatchAllOfGeneric<MatcherLHS, MatcherTs...>> operator && (
24323- MatcherLHS const& lhs,
24324- MatchAllOfGeneric<MatcherTs...>&& rhs) {
24325- return MatchAllOfGeneric<MatcherLHS, MatcherTs...>{array_cat(static_cast<void const*>(std::addressof(lhs)), CATCH_MOVE(rhs.m_matchers))};
24326- }
24327- };
24328-
24329-
24330- template<typename... MatcherTs>
24331- class MatchAnyOfGeneric final : public MatcherGenericBase {
24332- public:
24333- MatchAnyOfGeneric(MatchAnyOfGeneric const&) = delete;
24334- MatchAnyOfGeneric& operator=(MatchAnyOfGeneric const&) = delete;
24335- MatchAnyOfGeneric(MatchAnyOfGeneric&&) = default;
24336- MatchAnyOfGeneric& operator=(MatchAnyOfGeneric&&) = default;
24337-
24338- MatchAnyOfGeneric(MatcherTs const&... matchers) : m_matchers{ {std::addressof(matchers)...} } {}
24339- explicit MatchAnyOfGeneric(std::array<void const*, sizeof...(MatcherTs)> matchers) : m_matchers{matchers} {}
24340-
24341- template<typename Arg>
24342- bool match(Arg&& arg) const {
24343- return match_any_of<MatcherTs...>(arg, m_matchers, std::index_sequence_for<MatcherTs...>{});
24344- }
24345-
24346- std::string describe() const override {
24347- return describe_multi_matcher<MatcherTs...>(" or "_sr, m_matchers, std::index_sequence_for<MatcherTs...>{});
24348- }
24349-
24350-
24351- // Has to be public to enable the concatenating operators
24352- // below, because they are not friend of the RHS, only LHS,
24353- // and thus cannot access private fields of RHS
24354- std::array<void const*, sizeof...( MatcherTs )> m_matchers;
24355-
24356- //! Avoids type nesting for `GenericAnyOf || GenericAnyOf` case
24357- template<typename... MatchersRHS>
24358- friend MatchAnyOfGeneric<MatcherTs..., MatchersRHS...> operator || (
24359- MatchAnyOfGeneric<MatcherTs...>&& lhs,
24360- MatchAnyOfGeneric<MatchersRHS...>&& rhs) {
24361- return MatchAnyOfGeneric<MatcherTs..., MatchersRHS...>{array_cat(CATCH_MOVE(lhs.m_matchers), CATCH_MOVE(rhs.m_matchers))};
24362- }
24363-
24364- //! Avoids type nesting for `GenericAnyOf || some matcher` case
24365- template<typename MatcherRHS>
24366- friend std::enable_if_t<is_matcher_v<MatcherRHS>,
24367- MatchAnyOfGeneric<MatcherTs..., MatcherRHS>> operator || (
24368- MatchAnyOfGeneric<MatcherTs...>&& lhs,
24369- MatcherRHS const& rhs) {
24370- return MatchAnyOfGeneric<MatcherTs..., MatcherRHS>{array_cat(CATCH_MOVE(lhs.m_matchers), static_cast<void const*>(std::addressof(rhs)))};
24371- }
24372-
24373- //! Avoids type nesting for `some matcher || GenericAnyOf` case
24374- template<typename MatcherLHS>
24375- friend std::enable_if_t<is_matcher_v<MatcherLHS>,
24376- MatchAnyOfGeneric<MatcherLHS, MatcherTs...>> operator || (
24377- MatcherLHS const& lhs,
24378- MatchAnyOfGeneric<MatcherTs...>&& rhs) {
24379- return MatchAnyOfGeneric<MatcherLHS, MatcherTs...>{array_cat(static_cast<void const*>(std::addressof(lhs)), CATCH_MOVE(rhs.m_matchers))};
24380- }
24381- };
24382-
24383-
24384- template<typename MatcherT>
24385- class MatchNotOfGeneric final : public MatcherGenericBase {
24386- MatcherT const& m_matcher;
24387-
24388- public:
24389- MatchNotOfGeneric(MatchNotOfGeneric const&) = delete;
24390- MatchNotOfGeneric& operator=(MatchNotOfGeneric const&) = delete;
24391- MatchNotOfGeneric(MatchNotOfGeneric&&) = default;
24392- MatchNotOfGeneric& operator=(MatchNotOfGeneric&&) = default;
24393-
24394- explicit MatchNotOfGeneric(MatcherT const& matcher) : m_matcher{matcher} {}
24395-
24396- template<typename Arg>
24397- bool match(Arg&& arg) const {
24398- return !m_matcher.match(arg);
24399- }
24400-
24401- std::string describe() const override {
24402- return "not " + m_matcher.toString();
24403- }
24404-
24405- //! Negating negation can just unwrap and return underlying matcher
24406- friend MatcherT const& operator ! (MatchNotOfGeneric<MatcherT> const& matcher) {
24407- return matcher.m_matcher;
24408- }
24409- };
24410- } // namespace Detail
24411-
24412-
24413- // compose only generic matchers
24414- template<typename MatcherLHS, typename MatcherRHS>
24415- std::enable_if_t<Detail::are_generic_matchers_v<MatcherLHS, MatcherRHS>, Detail::MatchAllOfGeneric<MatcherLHS, MatcherRHS>>
24416- operator && (MatcherLHS const& lhs, MatcherRHS const& rhs) {
24417- return { lhs, rhs };
24418- }
24419-
24420- template<typename MatcherLHS, typename MatcherRHS>
24421- std::enable_if_t<Detail::are_generic_matchers_v<MatcherLHS, MatcherRHS>, Detail::MatchAnyOfGeneric<MatcherLHS, MatcherRHS>>
24422- operator || (MatcherLHS const& lhs, MatcherRHS const& rhs) {
24423- return { lhs, rhs };
24424- }
24425-
24426- //! Wrap provided generic matcher in generic negator
24427- template<typename MatcherT>
24428- std::enable_if_t<Detail::is_generic_matcher_v<MatcherT>, Detail::MatchNotOfGeneric<MatcherT>>
24429- operator ! (MatcherT const& matcher) {
24430- return Detail::MatchNotOfGeneric<MatcherT>{matcher};
24431- }
24432-
24433-
24434- // compose mixed generic and non-generic matchers
24435- template<typename MatcherLHS, typename ArgRHS>
24436- std::enable_if_t<Detail::is_generic_matcher_v<MatcherLHS>, Detail::MatchAllOfGeneric<MatcherLHS, MatcherBase<ArgRHS>>>
24437- operator && (MatcherLHS const& lhs, MatcherBase<ArgRHS> const& rhs) {
24438- return { lhs, rhs };
24439- }
24440-
24441- template<typename ArgLHS, typename MatcherRHS>
24442- std::enable_if_t<Detail::is_generic_matcher_v<MatcherRHS>, Detail::MatchAllOfGeneric<MatcherBase<ArgLHS>, MatcherRHS>>
24443- operator && (MatcherBase<ArgLHS> const& lhs, MatcherRHS const& rhs) {
24444- return { lhs, rhs };
24445- }
24446-
24447- template<typename MatcherLHS, typename ArgRHS>
24448- std::enable_if_t<Detail::is_generic_matcher_v<MatcherLHS>, Detail::MatchAnyOfGeneric<MatcherLHS, MatcherBase<ArgRHS>>>
24449- operator || (MatcherLHS const& lhs, MatcherBase<ArgRHS> const& rhs) {
24450- return { lhs, rhs };
24451- }
24452-
24453- template<typename ArgLHS, typename MatcherRHS>
24454- std::enable_if_t<Detail::is_generic_matcher_v<MatcherRHS>, Detail::MatchAnyOfGeneric<MatcherBase<ArgLHS>, MatcherRHS>>
24455- operator || (MatcherBase<ArgLHS> const& lhs, MatcherRHS const& rhs) {
24456- return { lhs, rhs };
24457- }
24458-
24459-} // namespace Matchers
24460-} // namespace Catch
24461-
24462-#endif // CATCH_MATCHERS_TEMPLATED_HPP_INCLUDED
24463-
24464-namespace Catch {
24465- namespace Matchers {
24466-
24467- class IsEmptyMatcher final : public MatcherGenericBase {
24468- public:
24469- template <typename RangeLike>
24470- bool match(RangeLike&& rng) const {
24471-#if defined(CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS)
24472- using Catch::Detail::empty;
24473-#else
24474- using std::empty;
24475-#endif
24476- return empty(rng);
24477- }
24478-
24479- std::string describe() const override;
24480- };
24481-
24482- class HasSizeMatcher final : public MatcherGenericBase {
24483- std::size_t m_target_size;
24484- public:
24485- explicit HasSizeMatcher(std::size_t target_size):
24486- m_target_size(target_size)
24487- {}
24488-
24489- template <typename RangeLike>
24490- bool match(RangeLike&& rng) const {
24491-#if defined(CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS)
24492- using Catch::Detail::size;
24493-#else
24494- using std::size;
24495-#endif
24496- return size(rng) == m_target_size;
24497- }
24498-
24499- std::string describe() const override;
24500- };
24501-
24502- template <typename Matcher>
24503- class SizeMatchesMatcher final : public MatcherGenericBase {
24504- Matcher m_matcher;
24505- public:
24506- explicit SizeMatchesMatcher(Matcher m):
24507- m_matcher(CATCH_MOVE(m))
24508- {}
24509-
24510- template <typename RangeLike>
24511- bool match(RangeLike&& rng) const {
24512-#if defined(CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS)
24513- using Catch::Detail::size;
24514-#else
24515- using std::size;
24516-#endif
24517- return m_matcher.match(size(rng));
24518- }
24519-
24520- std::string describe() const override {
24521- return "size matches " + m_matcher.describe();
24522- }
24523- };
24524-
24525-
24526- //! Creates a matcher that accepts empty ranges/containers
24527- IsEmptyMatcher IsEmpty();
24528- //! Creates a matcher that accepts ranges/containers with specific size
24529- HasSizeMatcher SizeIs(std::size_t sz);
24530- template <typename Matcher>
24531- std::enable_if_t<Detail::is_matcher_v<Matcher>,
24532- SizeMatchesMatcher<Matcher>> SizeIs(Matcher&& m) {
24533- return SizeMatchesMatcher<Matcher>{CATCH_FORWARD(m)};
24534- }
24535-
24536- } // end namespace Matchers
24537-} // end namespace Catch
24538-
24539-#endif // CATCH_MATCHERS_CONTAINER_PROPERTIES_HPP_INCLUDED
24540-
24541-
24542-#ifndef CATCH_MATCHERS_CONTAINS_HPP_INCLUDED
24543-#define CATCH_MATCHERS_CONTAINS_HPP_INCLUDED
24544-
24545-
24546-#include <functional>
24547-#include <type_traits>
24548-
24549-namespace Catch {
24550- namespace Matchers {
24551- //! Matcher for checking that an element in range is equal to specific element
24552- template <typename T, typename Equality>
24553- class ContainsElementMatcher final : public MatcherGenericBase {
24554- T m_desired;
24555- Equality m_eq;
24556- public:
24557- template <typename T2, typename Equality2>
24558- ContainsElementMatcher(T2&& target, Equality2&& predicate):
24559- m_desired(CATCH_FORWARD(target)),
24560- m_eq(CATCH_FORWARD(predicate))
24561- {}
24562-
24563- std::string describe() const override {
24564- return "contains element " + Catch::Detail::stringify(m_desired);
24565- }
24566-
24567- template <typename RangeLike>
24568- bool match( RangeLike&& rng ) const {
24569- for ( auto&& elem : rng ) {
24570- if ( m_eq( elem, m_desired ) ) { return true; }
24571- }
24572- return false;
24573- }
24574- };
24575-
24576- //! Meta-matcher for checking that an element in a range matches a specific matcher
24577- template <typename Matcher>
24578- class ContainsMatcherMatcher final : public MatcherGenericBase {
24579- Matcher m_matcher;
24580- public:
24581- // Note that we do a copy+move to avoid having to SFINAE this
24582- // constructor (and also avoid some perfect forwarding failure
24583- // cases)
24584- ContainsMatcherMatcher(Matcher matcher):
24585- m_matcher(CATCH_MOVE(matcher))
24586- {}
24587-
24588- template <typename RangeLike>
24589- bool match(RangeLike&& rng) const {
24590- for (auto&& elem : rng) {
24591- if (m_matcher.match(elem)) {
24592- return true;
24593- }
24594- }
24595- return false;
24596- }
24597-
24598- std::string describe() const override {
24599- return "contains element matching " + m_matcher.describe();
24600- }
24601- };
24602-
24603- /**
24604- * Creates a matcher that checks whether a range contains a specific element.
24605- *
24606- * Uses `std::equal_to` to do the comparison
24607- */
24608- template <typename T>
24609- std::enable_if_t<!Detail::is_matcher_v<T>,
24610- ContainsElementMatcher<T, std::equal_to<>>> Contains(T&& elem) {
24611- return { CATCH_FORWARD(elem), std::equal_to<>{} };
24612- }
24613-
24614- //! Creates a matcher that checks whether a range contains element matching a matcher
24615- template <typename Matcher>
24616- std::enable_if_t<Detail::is_matcher_v<Matcher>,
24617- ContainsMatcherMatcher<Matcher>> Contains(Matcher&& matcher) {
24618- return { CATCH_FORWARD(matcher) };
24619- }
24620-
24621- /**
24622- * Creates a matcher that checks whether a range contains a specific element.
24623- *
24624- * Uses `eq` to do the comparisons, the element is provided on the rhs
24625- */
24626- template <typename T, typename Equality>
24627- ContainsElementMatcher<T, Equality> Contains(T&& elem, Equality&& eq) {
24628- return { CATCH_FORWARD(elem), CATCH_FORWARD(eq) };
24629- }
24630-
24631- }
24632-}
24633-
24634-#endif // CATCH_MATCHERS_CONTAINS_HPP_INCLUDED
24635-
24636-
24637-#ifndef CATCH_MATCHERS_EXCEPTION_HPP_INCLUDED
24638-#define CATCH_MATCHERS_EXCEPTION_HPP_INCLUDED
24639-
24640-
24641-namespace Catch {
24642-namespace Matchers {
24643-
24644-class ExceptionMessageMatcher final : public MatcherBase<std::exception> {
24645- std::string m_message;
24646-public:
24647-
24648- ExceptionMessageMatcher(std::string const& message):
24649- m_message(message)
24650- {}
24651-
24652- bool match(std::exception const& ex) const override;
24653-
24654- std::string describe() const override;
24655-};
24656-
24657-//! Creates a matcher that checks whether a std derived exception has the provided message
24658-ExceptionMessageMatcher Message(std::string const& message);
24659-
24660-template <typename StringMatcherType>
24661-class ExceptionMessageMatchesMatcher final
24662- : public MatcherBase<std::exception> {
24663- StringMatcherType m_matcher;
24664-
24665-public:
24666- ExceptionMessageMatchesMatcher( StringMatcherType matcher ):
24667- m_matcher( CATCH_MOVE( matcher ) ) {}
24668-
24669- bool match( std::exception const& ex ) const override {
24670- return m_matcher.match( ex.what() );
24671- }
24672-
24673- std::string describe() const override {
24674- return " matches \"" + m_matcher.describe() + '"';
24675- }
24676-};
24677-
24678-//! Creates a matcher that checks whether a message from an std derived
24679-//! exception matches a provided matcher
24680-template <typename StringMatcherType>
24681-ExceptionMessageMatchesMatcher<StringMatcherType>
24682-MessageMatches( StringMatcherType&& matcher ) {
24683- return { CATCH_FORWARD( matcher ) };
24684-}
24685-
24686-} // namespace Matchers
24687-} // namespace Catch
24688-
24689-#endif // CATCH_MATCHERS_EXCEPTION_HPP_INCLUDED
24690-
24691-
24692-#ifndef CATCH_MATCHERS_FLOATING_POINT_HPP_INCLUDED
24693-#define CATCH_MATCHERS_FLOATING_POINT_HPP_INCLUDED
24694-
24695-
24696-namespace Catch {
24697-namespace Matchers {
24698-
24699- namespace Detail {
24700- enum class FloatingPointKind : uint8_t;
24701- }
24702-
24703- class WithinAbsMatcher final : public MatcherBase<double> {
24704- public:
24705- WithinAbsMatcher(double target, double margin);
24706- bool match(double const& matchee) const override;
24707- std::string describe() const override;
24708- private:
24709- double m_target;
24710- double m_margin;
24711- };
24712-
24713- //! Creates a matcher that accepts numbers within certain range of target
24714- WithinAbsMatcher WithinAbs( double target, double margin );
24715-
24716-
24717-
24718- class WithinUlpsMatcher final : public MatcherBase<double> {
24719- public:
24720- WithinUlpsMatcher( double target,
24721- uint64_t ulps,
24722- Detail::FloatingPointKind baseType );
24723- bool match(double const& matchee) const override;
24724- std::string describe() const override;
24725- private:
24726- double m_target;
24727- uint64_t m_ulps;
24728- Detail::FloatingPointKind m_type;
24729- };
24730-
24731- //! Creates a matcher that accepts doubles within certain ULP range of target
24732- WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff);
24733- //! Creates a matcher that accepts floats within certain ULP range of target
24734- WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff);
24735-
24736-
24737-
24738- // Given IEEE-754 format for floats and doubles, we can assume
24739- // that float -> double promotion is lossless. Given this, we can
24740- // assume that if we do the standard relative comparison of
24741- // |lhs - rhs| <= epsilon * max(fabs(lhs), fabs(rhs)), then we get
24742- // the same result if we do this for floats, as if we do this for
24743- // doubles that were promoted from floats.
24744- class WithinRelMatcher final : public MatcherBase<double> {
24745- public:
24746- WithinRelMatcher( double target, double epsilon );
24747- bool match(double const& matchee) const override;
24748- std::string describe() const override;
24749- private:
24750- double m_target;
24751- double m_epsilon;
24752- };
24753-
24754- //! Creates a matcher that accepts doubles within certain relative range of target
24755- WithinRelMatcher WithinRel(double target, double eps);
24756- //! Creates a matcher that accepts doubles within 100*DBL_EPS relative range of target
24757- WithinRelMatcher WithinRel(double target);
24758- //! Creates a matcher that accepts doubles within certain relative range of target
24759- WithinRelMatcher WithinRel(float target, float eps);
24760- //! Creates a matcher that accepts floats within 100*FLT_EPS relative range of target
24761- WithinRelMatcher WithinRel(float target);
24762-
24763-
24764-
24765- class IsNaNMatcher final : public MatcherBase<double> {
24766- public:
24767- IsNaNMatcher() = default;
24768- bool match( double const& matchee ) const override;
24769- std::string describe() const override;
24770- };
24771-
24772- IsNaNMatcher IsNaN();
24773-
24774-} // namespace Matchers
24775-} // namespace Catch
24776-
24777-#endif // CATCH_MATCHERS_FLOATING_POINT_HPP_INCLUDED
24778-
24779-
24780-#ifndef CATCH_MATCHERS_PREDICATE_HPP_INCLUDED
24781-#define CATCH_MATCHERS_PREDICATE_HPP_INCLUDED
24782-
24783-
24784-#include <string>
24785-
24786-namespace Catch {
24787-namespace Matchers {
24788-
24789-namespace Detail {
24790- std::string finalizeDescription(const std::string& desc);
24791-} // namespace Detail
24792-
24793-template <typename T, typename Predicate>
24794-class PredicateMatcher final : public MatcherBase<T> {
24795- Predicate m_predicate;
24796- std::string m_description;
24797-public:
24798-
24799- PredicateMatcher(Predicate&& elem, std::string const& descr)
24800- :m_predicate(CATCH_FORWARD(elem)),
24801- m_description(Detail::finalizeDescription(descr))
24802- {}
24803-
24804- bool match( T const& item ) const override {
24805- return m_predicate(item);
24806- }
24807-
24808- std::string describe() const override {
24809- return m_description;
24810- }
24811-};
24812-
24813- /**
24814- * Creates a matcher that calls delegates `match` to the provided predicate.
24815- *
24816- * The user has to explicitly specify the argument type to the matcher
24817- */
24818- template<typename T, typename Pred>
24819- PredicateMatcher<T, Pred> Predicate(Pred&& predicate, std::string const& description = "") {
24820- static_assert(is_callable<Pred(T)>::value, "Predicate not callable with argument T");
24821- static_assert(std::is_same<bool, FunctionReturnType<Pred, T>>::value, "Predicate does not return bool");
24822- return PredicateMatcher<T, Pred>(CATCH_FORWARD(predicate), description);
24823- }
24824-
24825-} // namespace Matchers
24826-} // namespace Catch
24827-
24828-#endif // CATCH_MATCHERS_PREDICATE_HPP_INCLUDED
24829-
24830-
24831-#ifndef CATCH_MATCHERS_QUANTIFIERS_HPP_INCLUDED
24832-#define CATCH_MATCHERS_QUANTIFIERS_HPP_INCLUDED
24833-
24834-
24835-namespace Catch {
24836- namespace Matchers {
24837- // Matcher for checking that all elements in range matches a given matcher.
24838- template <typename Matcher>
24839- class AllMatchMatcher final : public MatcherGenericBase {
24840- Matcher m_matcher;
24841- public:
24842- AllMatchMatcher(Matcher matcher):
24843- m_matcher(CATCH_MOVE(matcher))
24844- {}
24845-
24846- std::string describe() const override {
24847- return "all match " + m_matcher.describe();
24848- }
24849-
24850- template <typename RangeLike>
24851- bool match(RangeLike&& rng) const {
24852- for (auto&& elem : rng) {
24853- if (!m_matcher.match(elem)) {
24854- return false;
24855- }
24856- }
24857- return true;
24858- }
24859- };
24860-
24861- // Matcher for checking that no element in range matches a given matcher.
24862- template <typename Matcher>
24863- class NoneMatchMatcher final : public MatcherGenericBase {
24864- Matcher m_matcher;
24865- public:
24866- NoneMatchMatcher(Matcher matcher):
24867- m_matcher(CATCH_MOVE(matcher))
24868- {}
24869-
24870- std::string describe() const override {
24871- return "none match " + m_matcher.describe();
24872- }
24873-
24874- template <typename RangeLike>
24875- bool match(RangeLike&& rng) const {
24876- for (auto&& elem : rng) {
24877- if (m_matcher.match(elem)) {
24878- return false;
24879- }
24880- }
24881- return true;
24882- }
24883- };
24884-
24885- // Matcher for checking that at least one element in range matches a given matcher.
24886- template <typename Matcher>
24887- class AnyMatchMatcher final : public MatcherGenericBase {
24888- Matcher m_matcher;
24889- public:
24890- AnyMatchMatcher(Matcher matcher):
24891- m_matcher(CATCH_MOVE(matcher))
24892- {}
24893-
24894- std::string describe() const override {
24895- return "any match " + m_matcher.describe();
24896- }
24897-
24898- template <typename RangeLike>
24899- bool match(RangeLike&& rng) const {
24900- for (auto&& elem : rng) {
24901- if (m_matcher.match(elem)) {
24902- return true;
24903- }
24904- }
24905- return false;
24906- }
24907- };
24908-
24909- // Matcher for checking that all elements in range are true.
24910- class AllTrueMatcher final : public MatcherGenericBase {
24911- public:
24912- std::string describe() const override;
24913-
24914- template <typename RangeLike>
24915- bool match(RangeLike&& rng) const {
24916- for (auto&& elem : rng) {
24917- if (!elem) {
24918- return false;
24919- }
24920- }
24921- return true;
24922- }
24923- };
24924-
24925- // Matcher for checking that no element in range is true.
24926- class NoneTrueMatcher final : public MatcherGenericBase {
24927- public:
24928- std::string describe() const override;
24929-
24930- template <typename RangeLike>
24931- bool match(RangeLike&& rng) const {
24932- for (auto&& elem : rng) {
24933- if (elem) {
24934- return false;
24935- }
24936- }
24937- return true;
24938- }
24939- };
24940-
24941- // Matcher for checking that any element in range is true.
24942- class AnyTrueMatcher final : public MatcherGenericBase {
24943- public:
24944- std::string describe() const override;
24945-
24946- template <typename RangeLike>
24947- bool match(RangeLike&& rng) const {
24948- for (auto&& elem : rng) {
24949- if (elem) {
24950- return true;
24951- }
24952- }
24953- return false;
24954- }
24955- };
24956-
24957- // Creates a matcher that checks whether all elements in a range match a matcher
24958- template <typename Matcher>
24959- AllMatchMatcher<Matcher> AllMatch(Matcher&& matcher) {
24960- return { CATCH_FORWARD(matcher) };
24961- }
24962-
24963- // Creates a matcher that checks whether no element in a range matches a matcher.
24964- template <typename Matcher>
24965- NoneMatchMatcher<Matcher> NoneMatch(Matcher&& matcher) {
24966- return { CATCH_FORWARD(matcher) };
24967- }
24968-
24969- // Creates a matcher that checks whether any element in a range matches a matcher.
24970- template <typename Matcher>
24971- AnyMatchMatcher<Matcher> AnyMatch(Matcher&& matcher) {
24972- return { CATCH_FORWARD(matcher) };
24973- }
24974-
24975- // Creates a matcher that checks whether all elements in a range are true
24976- AllTrueMatcher AllTrue();
24977-
24978- // Creates a matcher that checks whether no element in a range is true
24979- NoneTrueMatcher NoneTrue();
24980-
24981- // Creates a matcher that checks whether any element in a range is true
24982- AnyTrueMatcher AnyTrue();
24983- }
24984-}
24985-
24986-#endif // CATCH_MATCHERS_QUANTIFIERS_HPP_INCLUDED
24987-
24988-
24989-#ifndef CATCH_MATCHERS_RANGE_EQUALS_HPP_INCLUDED
24990-#define CATCH_MATCHERS_RANGE_EQUALS_HPP_INCLUDED
24991-
24992-
24993-#include <functional>
24994-
24995-namespace Catch {
24996- namespace Matchers {
24997-
24998- /**
24999- * Matcher for checking that an element contains the same
25000- * elements in the same order
25001- */
25002- template <typename TargetRangeLike, typename Equality>
25003- class RangeEqualsMatcher final : public MatcherGenericBase {
25004- TargetRangeLike m_desired;
25005- Equality m_predicate;
25006-
25007- public:
25008- template <typename TargetRangeLike2, typename Equality2>
25009- constexpr
25010- RangeEqualsMatcher( TargetRangeLike2&& range,
25011- Equality2&& predicate ):
25012- m_desired( CATCH_FORWARD( range ) ),
25013- m_predicate( CATCH_FORWARD( predicate ) ) {}
25014-
25015- template <typename RangeLike>
25016- constexpr
25017- bool match( RangeLike&& rng ) const {
25018- auto rng_start = begin( rng );
25019- const auto rng_end = end( rng );
25020- auto target_start = begin( m_desired );
25021- const auto target_end = end( m_desired );
25022-
25023- while (rng_start != rng_end && target_start != target_end) {
25024- if (!m_predicate(*rng_start, *target_start)) {
25025- return false;
25026- }
25027- ++rng_start;
25028- ++target_start;
25029- }
25030- return rng_start == rng_end && target_start == target_end;
25031- }
25032-
25033- std::string describe() const override {
25034- return "elements are " + Catch::Detail::stringify( m_desired );
25035- }
25036- };
25037-
25038- /**
25039- * Matcher for checking that an element contains the same
25040- * elements (but not necessarily in the same order)
25041- */
25042- template <typename TargetRangeLike, typename Equality>
25043- class UnorderedRangeEqualsMatcher final : public MatcherGenericBase {
25044- TargetRangeLike m_desired;
25045- Equality m_predicate;
25046-
25047- public:
25048- template <typename TargetRangeLike2, typename Equality2>
25049- constexpr
25050- UnorderedRangeEqualsMatcher( TargetRangeLike2&& range,
25051- Equality2&& predicate ):
25052- m_desired( CATCH_FORWARD( range ) ),
25053- m_predicate( CATCH_FORWARD( predicate ) ) {}
25054-
25055- template <typename RangeLike>
25056- constexpr
25057- bool match( RangeLike&& rng ) const {
25058- using std::begin;
25059- using std::end;
25060- return Catch::Detail::is_permutation( begin( m_desired ),
25061- end( m_desired ),
25062- begin( rng ),
25063- end( rng ),
25064- m_predicate );
25065- }
25066-
25067- std::string describe() const override {
25068- return "unordered elements are " +
25069- ::Catch::Detail::stringify( m_desired );
25070- }
25071- };
25072-
25073- /**
25074- * Creates a matcher that checks if all elements in a range are equal
25075- * to all elements in another range.
25076- *
25077- * Uses the provided predicate `predicate` to do the comparisons
25078- * (defaulting to `std::equal_to`)
25079- */
25080- template <typename RangeLike,
25081- typename Equality = decltype( std::equal_to<>{} )>
25082- constexpr
25083- RangeEqualsMatcher<RangeLike, Equality>
25084- RangeEquals( RangeLike&& range,
25085- Equality&& predicate = std::equal_to<>{} ) {
25086- return { CATCH_FORWARD( range ), CATCH_FORWARD( predicate ) };
25087- }
25088-
25089- /**
25090- * Creates a matcher that checks if all elements in a range are equal
25091- * to all elements in an initializer list.
25092- *
25093- * Uses the provided predicate `predicate` to do the comparisons
25094- * (defaulting to `std::equal_to`)
25095- */
25096- template <typename T,
25097- typename Equality = decltype( std::equal_to<>{} )>
25098- constexpr
25099- RangeEqualsMatcher<std::initializer_list<T>, Equality>
25100- RangeEquals( std::initializer_list<T> range,
25101- Equality&& predicate = std::equal_to<>{} ) {
25102- return { range, CATCH_FORWARD( predicate ) };
25103- }
25104-
25105- /**
25106- * Creates a matcher that checks if all elements in a range are equal
25107- * to all elements in another range, in some permutation.
25108- *
25109- * Uses the provided predicate `predicate` to do the comparisons
25110- * (defaulting to `std::equal_to`)
25111- */
25112- template <typename RangeLike,
25113- typename Equality = decltype( std::equal_to<>{} )>
25114- constexpr
25115- UnorderedRangeEqualsMatcher<RangeLike, Equality>
25116- UnorderedRangeEquals( RangeLike&& range,
25117- Equality&& predicate = std::equal_to<>{} ) {
25118- return { CATCH_FORWARD( range ), CATCH_FORWARD( predicate ) };
25119- }
25120-
25121- /**
25122- * Creates a matcher that checks if all elements in a range are equal
25123- * to all elements in an initializer list, in some permutation.
25124- *
25125- * Uses the provided predicate `predicate` to do the comparisons
25126- * (defaulting to `std::equal_to`)
25127- */
25128- template <typename T,
25129- typename Equality = decltype( std::equal_to<>{} )>
25130- constexpr
25131- UnorderedRangeEqualsMatcher<std::initializer_list<T>, Equality>
25132- UnorderedRangeEquals( std::initializer_list<T> range,
25133- Equality&& predicate = std::equal_to<>{} ) {
25134- return { range, CATCH_FORWARD( predicate ) };
25135- }
25136- } // namespace Matchers
25137-} // namespace Catch
25138-
25139-#endif // CATCH_MATCHERS_RANGE_EQUALS_HPP_INCLUDED
25140-
25141-
25142-#ifndef CATCH_MATCHERS_STRING_HPP_INCLUDED
25143-#define CATCH_MATCHERS_STRING_HPP_INCLUDED
25144-
25145-
25146-#include <string>
25147-
25148-namespace Catch {
25149-namespace Matchers {
25150-
25151- struct CasedString {
25152- CasedString( std::string const& str, CaseSensitive caseSensitivity );
25153- std::string adjustString( std::string const& str ) const;
25154- StringRef caseSensitivitySuffix() const;
25155-
25156- CaseSensitive m_caseSensitivity;
25157- std::string m_str;
25158- };
25159-
25160- class StringMatcherBase : public MatcherBase<std::string> {
25161- protected:
25162- CasedString m_comparator;
25163- StringRef m_operation;
25164-
25165- public:
25166- StringMatcherBase( StringRef operation,
25167- CasedString const& comparator );
25168- std::string describe() const override;
25169- };
25170-
25171- class StringEqualsMatcher final : public StringMatcherBase {
25172- public:
25173- StringEqualsMatcher( CasedString const& comparator );
25174- bool match( std::string const& source ) const override;
25175- };
25176- class StringContainsMatcher final : public StringMatcherBase {
25177- public:
25178- StringContainsMatcher( CasedString const& comparator );
25179- bool match( std::string const& source ) const override;
25180- };
25181- class StartsWithMatcher final : public StringMatcherBase {
25182- public:
25183- StartsWithMatcher( CasedString const& comparator );
25184- bool match( std::string const& source ) const override;
25185- };
25186- class EndsWithMatcher final : public StringMatcherBase {
25187- public:
25188- EndsWithMatcher( CasedString const& comparator );
25189- bool match( std::string const& source ) const override;
25190- };
25191-
25192- class RegexMatcher final : public MatcherBase<std::string> {
25193- std::string m_regex;
25194- CaseSensitive m_caseSensitivity;
25195-
25196- public:
25197- RegexMatcher( std::string regex, CaseSensitive caseSensitivity );
25198- bool match( std::string const& matchee ) const override;
25199- std::string describe() const override;
25200- };
25201-
25202- //! Creates matcher that accepts strings that are exactly equal to `str`
25203- StringEqualsMatcher Equals( std::string const& str, CaseSensitive caseSensitivity = CaseSensitive::Yes );
25204- //! Creates matcher that accepts strings that contain `str`
25205- StringContainsMatcher ContainsSubstring( std::string const& str, CaseSensitive caseSensitivity = CaseSensitive::Yes );
25206- //! Creates matcher that accepts strings that _end_ with `str`
25207- EndsWithMatcher EndsWith( std::string const& str, CaseSensitive caseSensitivity = CaseSensitive::Yes );
25208- //! Creates matcher that accepts strings that _start_ with `str`
25209- StartsWithMatcher StartsWith( std::string const& str, CaseSensitive caseSensitivity = CaseSensitive::Yes );
25210- //! Creates matcher that accepts strings matching `regex`
25211- RegexMatcher Matches( std::string const& regex, CaseSensitive caseSensitivity = CaseSensitive::Yes );
25212-
25213-} // namespace Matchers
25214-} // namespace Catch
25215-
25216-#endif // CATCH_MATCHERS_STRING_HPP_INCLUDED
25217-
25218-
25219-#ifndef CATCH_MATCHERS_VECTOR_HPP_INCLUDED
25220-#define CATCH_MATCHERS_VECTOR_HPP_INCLUDED
25221-
25222-
25223-#include <algorithm>
25224-
25225-namespace Catch {
25226-namespace Matchers {
25227-
25228- template<typename T, typename Alloc>
25229- class VectorContainsElementMatcher final : public MatcherBase<std::vector<T, Alloc>> {
25230- T const& m_comparator;
25231-
25232- public:
25233- VectorContainsElementMatcher(T const& comparator):
25234- m_comparator(comparator)
25235- {}
25236-
25237- bool match(std::vector<T, Alloc> const& v) const override {
25238- for (auto const& el : v) {
25239- if (el == m_comparator) {
25240- return true;
25241- }
25242- }
25243- return false;
25244- }
25245-
25246- std::string describe() const override {
25247- return "Contains: " + ::Catch::Detail::stringify( m_comparator );
25248- }
25249- };
25250-
25251- template<typename T, typename AllocComp, typename AllocMatch>
25252- class ContainsMatcher final : public MatcherBase<std::vector<T, AllocMatch>> {
25253- std::vector<T, AllocComp> const& m_comparator;
25254-
25255- public:
25256- ContainsMatcher(std::vector<T, AllocComp> const& comparator):
25257- m_comparator( comparator )
25258- {}
25259-
25260- bool match(std::vector<T, AllocMatch> const& v) const override {
25261- // !TBD: see note in EqualsMatcher
25262- if (m_comparator.size() > v.size())
25263- return false;
25264- for (auto const& comparator : m_comparator) {
25265- auto present = false;
25266- for (const auto& el : v) {
25267- if (el == comparator) {
25268- present = true;
25269- break;
25270- }
25271- }
25272- if (!present) {
25273- return false;
25274- }
25275- }
25276- return true;
25277- }
25278- std::string describe() const override {
25279- return "Contains: " + ::Catch::Detail::stringify( m_comparator );
25280- }
25281- };
25282-
25283- template<typename T, typename AllocComp, typename AllocMatch>
25284- class EqualsMatcher final : public MatcherBase<std::vector<T, AllocMatch>> {
25285- std::vector<T, AllocComp> const& m_comparator;
25286-
25287- public:
25288- EqualsMatcher(std::vector<T, AllocComp> const& comparator):
25289- m_comparator( comparator )
25290- {}
25291-
25292- bool match(std::vector<T, AllocMatch> const& v) const override {
25293- // !TBD: This currently works if all elements can be compared using !=
25294- // - a more general approach would be via a compare template that defaults
25295- // to using !=. but could be specialised for, e.g. std::vector<T> etc
25296- // - then just call that directly
25297- if ( m_comparator.size() != v.size() ) { return false; }
25298- for ( std::size_t i = 0; i < v.size(); ++i ) {
25299- if ( !( m_comparator[i] == v[i] ) ) { return false; }
25300- }
25301- return true;
25302- }
25303- std::string describe() const override {
25304- return "Equals: " + ::Catch::Detail::stringify( m_comparator );
25305- }
25306- };
25307-
25308- template<typename T, typename AllocComp, typename AllocMatch>
25309- class ApproxMatcher final : public MatcherBase<std::vector<T, AllocMatch>> {
25310- std::vector<T, AllocComp> const& m_comparator;
25311- mutable Catch::Approx approx = Catch::Approx::custom();
25312-
25313- public:
25314- ApproxMatcher(std::vector<T, AllocComp> const& comparator):
25315- m_comparator( comparator )
25316- {}
25317-
25318- bool match(std::vector<T, AllocMatch> const& v) const override {
25319- if (m_comparator.size() != v.size())
25320- return false;
25321- for (std::size_t i = 0; i < v.size(); ++i)
25322- if (m_comparator[i] != approx(v[i]))
25323- return false;
25324- return true;
25325- }
25326- std::string describe() const override {
25327- return "is approx: " + ::Catch::Detail::stringify( m_comparator );
25328- }
25329- template <typename = std::enable_if_t<std::is_constructible<double, T>::value>>
25330- ApproxMatcher& epsilon( T const& newEpsilon ) {
25331- approx.epsilon(static_cast<double>(newEpsilon));
25332- return *this;
25333- }
25334- template <typename = std::enable_if_t<std::is_constructible<double, T>::value>>
25335- ApproxMatcher& margin( T const& newMargin ) {
25336- approx.margin(static_cast<double>(newMargin));
25337- return *this;
25338- }
25339- template <typename = std::enable_if_t<std::is_constructible<double, T>::value>>
25340- ApproxMatcher& scale( T const& newScale ) {
25341- approx.scale(static_cast<double>(newScale));
25342- return *this;
25343- }
25344- };
25345-
25346- template<typename T, typename AllocComp, typename AllocMatch>
25347- class UnorderedEqualsMatcher final : public MatcherBase<std::vector<T, AllocMatch>> {
25348- std::vector<T, AllocComp> const& m_target;
25349-
25350- public:
25351- UnorderedEqualsMatcher(std::vector<T, AllocComp> const& target):
25352- m_target(target)
25353- {}
25354- bool match(std::vector<T, AllocMatch> const& vec) const override {
25355- if (m_target.size() != vec.size()) {
25356- return false;
25357- }
25358- return std::is_permutation(m_target.begin(), m_target.end(), vec.begin());
25359- }
25360-
25361- std::string describe() const override {
25362- return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target);
25363- }
25364- };
25365-
25366-
25367- // The following functions create the actual matcher objects.
25368- // This allows the types to be inferred
25369-
25370- //! Creates a matcher that matches vectors that contain all elements in `comparator`
25371- template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>
25372- ContainsMatcher<T, AllocComp, AllocMatch> Contains( std::vector<T, AllocComp> const& comparator ) {
25373- return ContainsMatcher<T, AllocComp, AllocMatch>(comparator);
25374- }
25375-
25376- //! Creates a matcher that matches vectors that contain `comparator` as an element
25377- template<typename T, typename Alloc = std::allocator<T>>
25378- VectorContainsElementMatcher<T, Alloc> VectorContains( T const& comparator ) {
25379- return VectorContainsElementMatcher<T, Alloc>(comparator);
25380- }
25381-
25382- //! Creates a matcher that matches vectors that are exactly equal to `comparator`
25383- template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>
25384- EqualsMatcher<T, AllocComp, AllocMatch> Equals( std::vector<T, AllocComp> const& comparator ) {
25385- return EqualsMatcher<T, AllocComp, AllocMatch>(comparator);
25386- }
25387-
25388- //! Creates a matcher that matches vectors that `comparator` as an element
25389- template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>
25390- ApproxMatcher<T, AllocComp, AllocMatch> Approx( std::vector<T, AllocComp> const& comparator ) {
25391- return ApproxMatcher<T, AllocComp, AllocMatch>(comparator);
25392- }
25393-
25394- //! Creates a matcher that matches vectors that is equal to `target` modulo permutation
25395- template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>
25396- UnorderedEqualsMatcher<T, AllocComp, AllocMatch> UnorderedEquals(std::vector<T, AllocComp> const& target) {
25397- return UnorderedEqualsMatcher<T, AllocComp, AllocMatch>(target);
25398- }
25399-
25400-} // namespace Matchers
25401-} // namespace Catch
25402-
25403-#endif // CATCH_MATCHERS_VECTOR_HPP_INCLUDED
25404-
25405-#endif // CATCH_MATCHERS_ALL_HPP_INCLUDED
25406-
25407-
25408-/** \file
25409- * This is a convenience header for Catch2's Reporter support. It includes
25410- * **all** of Catch2 headers related to reporters, including all reporters.
25411- *
25412- * Generally the Catch2 users should use specific includes they need,
25413- * but this header can be used instead for ease-of-experimentation, or
25414- * just plain convenience, at the cost of (significantly) increased
25415- * compilation times.
25416- *
25417- * When a new header (reporter) is added to either the `reporter` folder,
25418- * or to the corresponding internal subfolder, it should be added here.
25419- */
25420-
25421-#ifndef CATCH_REPORTERS_ALL_HPP_INCLUDED
25422-#define CATCH_REPORTERS_ALL_HPP_INCLUDED
25423-
25424-
25425-
25426-#ifndef CATCH_REPORTER_AUTOMAKE_HPP_INCLUDED
25427-#define CATCH_REPORTER_AUTOMAKE_HPP_INCLUDED
25428-
25429-
25430-
25431-#ifndef CATCH_REPORTER_STREAMING_BASE_HPP_INCLUDED
25432-#define CATCH_REPORTER_STREAMING_BASE_HPP_INCLUDED
25433-
25434-
25435-
25436-#ifndef CATCH_REPORTER_COMMON_BASE_HPP_INCLUDED
25437-#define CATCH_REPORTER_COMMON_BASE_HPP_INCLUDED
25438-
25439-
25440-#include <map>
25441-#include <string>
25442-
25443-namespace Catch {
25444- class ColourImpl;
25445-
25446- /**
25447- * This is the base class for all reporters.
25448- *
25449- * If are writing a reporter, you must derive from this type, or one
25450- * of the helper reporter bases that are derived from this type.
25451- *
25452- * ReporterBase centralizes handling of various common tasks in reporters,
25453- * like storing the right stream for the reporters to write to, and
25454- * providing the default implementation of the different listing events.
25455- */
25456- class ReporterBase : public IEventListener {
25457- protected:
25458- //! The stream wrapper as passed to us by outside code
25459- Detail::unique_ptr<IStream> m_wrapped_stream;
25460- //! Cached output stream from `m_wrapped_stream` to reduce
25461- //! number of indirect calls needed to write output.
25462- std::ostream& m_stream;
25463- //! Colour implementation this reporter was configured for
25464- Detail::unique_ptr<ColourImpl> m_colour;
25465- //! The custom reporter options user passed down to the reporter
25466- std::map<std::string, std::string> m_customOptions;
25467-
25468- public:
25469- ReporterBase( ReporterConfig&& config );
25470- ~ReporterBase() override; // = default;
25471-
25472- /**
25473- * Provides a simple default listing of reporters.
25474- *
25475- * Should look roughly like the reporter listing in v2 and earlier
25476- * versions of Catch2.
25477- */
25478- void listReporters(
25479- std::vector<ReporterDescription> const& descriptions ) override;
25480- /**
25481- * Provides a simple default listing of listeners
25482- *
25483- * Looks similarly to listing of reporters, but with listener type
25484- * instead of reporter name.
25485- */
25486- void listListeners(
25487- std::vector<ListenerDescription> const& descriptions ) override;
25488- /**
25489- * Provides a simple default listing of tests.
25490- *
25491- * Should look roughly like the test listing in v2 and earlier versions
25492- * of Catch2. Especially supports low-verbosity listing that mimics the
25493- * old `--list-test-names-only` output.
25494- */
25495- void listTests( std::vector<TestCaseHandle> const& tests ) override;
25496- /**
25497- * Provides a simple default listing of tags.
25498- *
25499- * Should look roughly like the tag listing in v2 and earlier versions
25500- * of Catch2.
25501- */
25502- void listTags( std::vector<TagInfo> const& tags ) override;
25503- };
25504-} // namespace Catch
25505-
25506-#endif // CATCH_REPORTER_COMMON_BASE_HPP_INCLUDED
25507-
25508-#include <vector>
25509-
25510-namespace Catch {
25511-
25512- class StreamingReporterBase : public ReporterBase {
25513- public:
25514- // GCC5 compat: we cannot use inherited constructor, because it
25515- // doesn't implement backport of P0136
25516- StreamingReporterBase(ReporterConfig&& _config):
25517- ReporterBase(CATCH_MOVE(_config))
25518- {}
25519- ~StreamingReporterBase() override;
25520-
25521- void benchmarkPreparing( StringRef ) override {}
25522- void benchmarkStarting( BenchmarkInfo const& ) override {}
25523- void benchmarkEnded( BenchmarkStats<> const& ) override {}
25524- void benchmarkFailed( StringRef ) override {}
25525-
25526- void fatalErrorEncountered( StringRef /*error*/ ) override {}
25527- void noMatchingTestCases( StringRef /*unmatchedSpec*/ ) override {}
25528- void reportInvalidTestSpec( StringRef /*invalidArgument*/ ) override {}
25529-
25530- void testRunStarting( TestRunInfo const& _testRunInfo ) override;
25531-
25532- void testCaseStarting(TestCaseInfo const& _testInfo) override {
25533- currentTestCaseInfo = &_testInfo;
25534- }
25535- void testCasePartialStarting( TestCaseInfo const&, uint64_t ) override {}
25536- void sectionStarting(SectionInfo const& _sectionInfo) override {
25537- m_sectionStack.push_back(_sectionInfo);
25538- }
25539-
25540- void assertionStarting( AssertionInfo const& ) override {}
25541- void assertionEnded( AssertionStats const& ) override {}
25542-
25543- void sectionEnded(SectionStats const& /* _sectionStats */) override {
25544- m_sectionStack.pop_back();
25545- }
25546- void testCasePartialEnded( TestCaseStats const&, uint64_t ) override {}
25547- void testCaseEnded(TestCaseStats const& /* _testCaseStats */) override {
25548- currentTestCaseInfo = nullptr;
25549- }
25550- void testRunEnded( TestRunStats const& /* _testRunStats */ ) override;
25551-
25552- void skipTest(TestCaseInfo const&) override {
25553- // Don't do anything with this by default.
25554- // It can optionally be overridden in the derived class.
25555- }
25556-
25557- protected:
25558- TestRunInfo currentTestRunInfo{ "test run has not started yet"_sr };
25559- TestCaseInfo const* currentTestCaseInfo = nullptr;
25560-
25561- //! Stack of all _active_ sections in the _current_ test case
25562- std::vector<SectionInfo> m_sectionStack;
25563- };
25564-
25565-} // end namespace Catch
25566-
25567-#endif // CATCH_REPORTER_STREAMING_BASE_HPP_INCLUDED
25568-
25569-#include <string>
25570-
25571-namespace Catch {
25572-
25573- class AutomakeReporter final : public StreamingReporterBase {
25574- public:
25575- // GCC5 compat: we cannot use inherited constructor, because it
25576- // doesn't implement backport of P0136
25577- AutomakeReporter( ReporterConfig&& _config ):
25578- StreamingReporterBase( CATCH_MOVE( _config ) ) {
25579- m_preferences.shouldReportAllAssertionStarts = false;
25580- }
25581-
25582- ~AutomakeReporter() override;
25583-
25584- static std::string getDescription() {
25585- using namespace std::string_literals;
25586- return "Reports test results in the format of Automake .trs files"s;
25587- }
25588-
25589- void testCaseEnded(TestCaseStats const& _testCaseStats) override;
25590- void skipTest(TestCaseInfo const& testInfo) override;
25591- };
25592-
25593-} // end namespace Catch
25594-
25595-#endif // CATCH_REPORTER_AUTOMAKE_HPP_INCLUDED
25596-
25597-
25598-#ifndef CATCH_REPORTER_COMPACT_HPP_INCLUDED
25599-#define CATCH_REPORTER_COMPACT_HPP_INCLUDED
25600-
25601-
25602-
25603-
25604-namespace Catch {
25605-
25606- class CompactReporter final : public StreamingReporterBase {
25607- public:
25608- CompactReporter( ReporterConfig&& _config ):
25609- StreamingReporterBase( CATCH_MOVE( _config ) ) {
25610- m_preferences.shouldReportAllAssertionStarts = false;
25611- }
25612-
25613- ~CompactReporter() override;
25614-
25615- static std::string getDescription();
25616-
25617- void noMatchingTestCases( StringRef unmatchedSpec ) override;
25618-
25619- void testRunStarting( TestRunInfo const& _testInfo ) override;
25620-
25621- void assertionEnded(AssertionStats const& _assertionStats) override;
25622-
25623- void sectionEnded(SectionStats const& _sectionStats) override;
25624-
25625- void testRunEnded(TestRunStats const& _testRunStats) override;
25626-
25627- };
25628-
25629-} // end namespace Catch
25630-
25631-#endif // CATCH_REPORTER_COMPACT_HPP_INCLUDED
25632-
25633-
25634-#ifndef CATCH_REPORTER_CONSOLE_HPP_INCLUDED
25635-#define CATCH_REPORTER_CONSOLE_HPP_INCLUDED
25636-
25637-
25638-namespace Catch {
25639- // Fwd decls
25640- class TablePrinter;
25641-
25642- class ConsoleReporter final : public StreamingReporterBase {
25643- Detail::unique_ptr<TablePrinter> m_tablePrinter;
25644-
25645- public:
25646- ConsoleReporter(ReporterConfig&& config);
25647- ~ConsoleReporter() override;
25648- static std::string getDescription();
25649-
25650- void noMatchingTestCases( StringRef unmatchedSpec ) override;
25651- void reportInvalidTestSpec( StringRef arg ) override;
25652-
25653- void assertionEnded(AssertionStats const& _assertionStats) override;
25654-
25655- void sectionStarting(SectionInfo const& _sectionInfo) override;
25656- void sectionEnded(SectionStats const& _sectionStats) override;
25657-
25658- void benchmarkPreparing( StringRef name ) override;
25659- void benchmarkStarting(BenchmarkInfo const& info) override;
25660- void benchmarkEnded(BenchmarkStats<> const& stats) override;
25661- void benchmarkFailed( StringRef error ) override;
25662-
25663- void testCaseEnded(TestCaseStats const& _testCaseStats) override;
25664- void testRunEnded(TestRunStats const& _testRunStats) override;
25665- void testRunStarting(TestRunInfo const& _testRunInfo) override;
25666-
25667- private:
25668- void lazyPrint();
25669-
25670- void lazyPrintWithoutClosingBenchmarkTable();
25671- void lazyPrintRunInfo();
25672- void printTestCaseAndSectionHeader();
25673-
25674- void printClosedHeader(std::string const& _name);
25675- void printOpenHeader(std::string const& _name);
25676-
25677- // if string has a : in first line will set indent to follow it on
25678- // subsequent lines
25679- void printHeaderString(std::string const& _string, std::size_t indent = 0);
25680-
25681- void printTotalsDivider(Totals const& totals);
25682-
25683- bool m_headerPrinted = false;
25684- bool m_testRunInfoPrinted = false;
25685- };
25686-
25687-} // end namespace Catch
25688-
25689-#endif // CATCH_REPORTER_CONSOLE_HPP_INCLUDED
25690-
25691-
25692-#ifndef CATCH_REPORTER_CUMULATIVE_BASE_HPP_INCLUDED
25693-#define CATCH_REPORTER_CUMULATIVE_BASE_HPP_INCLUDED
25694-
25695-
25696-#include <string>
25697-#include <vector>
25698-
25699-namespace Catch {
25700-
25701- namespace Detail {
25702-
25703- //! Represents either an assertion or a benchmark result to be handled by cumulative reporter later
25704- class AssertionOrBenchmarkResult {
25705- // This should really be a variant, but this is much faster
25706- // to write and the data layout here is already terrible
25707- // enough that we do not have to care about the object size.
25708- Optional<AssertionStats> m_assertion;
25709- Optional<BenchmarkStats<>> m_benchmark;
25710- public:
25711- AssertionOrBenchmarkResult(AssertionStats const& assertion);
25712- AssertionOrBenchmarkResult(BenchmarkStats<> const& benchmark);
25713-
25714- bool isAssertion() const;
25715- bool isBenchmark() const;
25716-
25717- AssertionStats const& asAssertion() const;
25718- BenchmarkStats<> const& asBenchmark() const;
25719- };
25720- }
25721-
25722- /**
25723- * Utility base for reporters that need to handle all results at once
25724- *
25725- * It stores tree of all test cases, sections and assertions, and after the
25726- * test run is finished, calls into `testRunEndedCumulative` to pass the
25727- * control to the deriving class.
25728- *
25729- * If you are deriving from this class and override any testing related
25730- * member functions, you should first call into the base's implementation to
25731- * avoid breaking the tree construction.
25732- *
25733- * Due to the way this base functions, it has to expand assertions up-front,
25734- * even if they are later unused (e.g. because the deriving reporter does
25735- * not report successful assertions, or because the deriving reporter does
25736- * not use assertion expansion at all). Derived classes can use two
25737- * customization points, `m_shouldStoreSuccesfulAssertions` and
25738- * `m_shouldStoreFailedAssertions`, to disable the expansion and gain extra
25739- * performance. **Accessing the assertion expansions if it wasn't stored is
25740- * UB.**
25741- */
25742- class CumulativeReporterBase : public ReporterBase {
25743- public:
25744- template<typename T, typename ChildNodeT>
25745- struct Node {
25746- explicit Node( T const& _value ) : value( _value ) {}
25747-
25748- using ChildNodes = std::vector<Detail::unique_ptr<ChildNodeT>>;
25749- T value;
25750- ChildNodes children;
25751- };
25752- struct SectionNode {
25753- explicit SectionNode(SectionStats const& _stats) : stats(_stats) {}
25754-
25755- bool operator == (SectionNode const& other) const {
25756- return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo;
25757- }
25758-
25759- bool hasAnyAssertions() const;
25760-
25761- SectionStats stats;
25762- std::vector<Detail::unique_ptr<SectionNode>> childSections;
25763- std::vector<Detail::AssertionOrBenchmarkResult> assertionsAndBenchmarks;
25764- std::string stdOut;
25765- std::string stdErr;
25766- };
25767-
25768-
25769- using TestCaseNode = Node<TestCaseStats, SectionNode>;
25770- using TestRunNode = Node<TestRunStats, TestCaseNode>;
25771-
25772- // GCC5 compat: we cannot use inherited constructor, because it
25773- // doesn't implement backport of P0136
25774- CumulativeReporterBase(ReporterConfig&& _config):
25775- ReporterBase(CATCH_MOVE(_config))
25776- {}
25777- ~CumulativeReporterBase() override;
25778-
25779- void benchmarkPreparing( StringRef ) override {}
25780- void benchmarkStarting( BenchmarkInfo const& ) override {}
25781- void benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) override;
25782- void benchmarkFailed( StringRef ) override {}
25783-
25784- void noMatchingTestCases( StringRef ) override {}
25785- void reportInvalidTestSpec( StringRef ) override {}
25786- void fatalErrorEncountered( StringRef /*error*/ ) override {}
25787-
25788- void testRunStarting( TestRunInfo const& ) override {}
25789-
25790- void testCaseStarting( TestCaseInfo const& ) override {}
25791- void testCasePartialStarting( TestCaseInfo const&, uint64_t ) override {}
25792- void sectionStarting( SectionInfo const& sectionInfo ) override;
25793-
25794- void assertionStarting( AssertionInfo const& ) override {}
25795-
25796- void assertionEnded( AssertionStats const& assertionStats ) override;
25797- void sectionEnded( SectionStats const& sectionStats ) override;
25798- void testCasePartialEnded( TestCaseStats const&, uint64_t ) override {}
25799- void testCaseEnded( TestCaseStats const& testCaseStats ) override;
25800- void testRunEnded( TestRunStats const& testRunStats ) override;
25801- //! Customization point: called after last test finishes (testRunEnded has been handled)
25802- virtual void testRunEndedCumulative() = 0;
25803-
25804- void skipTest(TestCaseInfo const&) override {}
25805-
25806- protected:
25807- //! Should the cumulative base store the assertion expansion for successful assertions?
25808- bool m_shouldStoreSuccesfulAssertions = true;
25809- //! Should the cumulative base store the assertion expansion for failed assertions?
25810- bool m_shouldStoreFailedAssertions = true;
25811-
25812- // We need lazy construction here. We should probably refactor it
25813- // later, after the events are redone.
25814- //! The root node of the test run tree.
25815- Detail::unique_ptr<TestRunNode> m_testRun;
25816-
25817- private:
25818- // Note: We rely on pointer identity being stable, which is why
25819- // we store pointers to the nodes rather than the values.
25820- std::vector<Detail::unique_ptr<TestCaseNode>> m_testCases;
25821- // Root section of the _current_ test case
25822- Detail::unique_ptr<SectionNode> m_rootSection;
25823- // Deepest section of the _current_ test case
25824- SectionNode* m_deepestSection = nullptr;
25825- // Stack of _active_ sections in the _current_ test case
25826- std::vector<SectionNode*> m_sectionStack;
25827- };
25828-
25829-} // end namespace Catch
25830-
25831-#endif // CATCH_REPORTER_CUMULATIVE_BASE_HPP_INCLUDED
25832-
25833-
25834-#ifndef CATCH_REPORTER_EVENT_LISTENER_HPP_INCLUDED
25835-#define CATCH_REPORTER_EVENT_LISTENER_HPP_INCLUDED
25836-
25837-
25838-namespace Catch {
25839-
25840- /**
25841- * Base class to simplify implementing listeners.
25842- *
25843- * Provides empty default implementation for all IEventListener member
25844- * functions, so that a listener implementation can pick which
25845- * member functions it actually cares about.
25846- */
25847- class EventListenerBase : public IEventListener {
25848- public:
25849- using IEventListener::IEventListener;
25850-
25851- void reportInvalidTestSpec( StringRef unmatchedSpec ) override;
25852- void fatalErrorEncountered( StringRef error ) override;
25853-
25854- void benchmarkPreparing( StringRef name ) override;
25855- void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) override;
25856- void benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) override;
25857- void benchmarkFailed( StringRef error ) override;
25858-
25859- void assertionStarting( AssertionInfo const& assertionInfo ) override;
25860- void assertionEnded( AssertionStats const& assertionStats ) override;
25861-
25862- void listReporters(
25863- std::vector<ReporterDescription> const& descriptions ) override;
25864- void listListeners(
25865- std::vector<ListenerDescription> const& descriptions ) override;
25866- void listTests( std::vector<TestCaseHandle> const& tests ) override;
25867- void listTags( std::vector<TagInfo> const& tagInfos ) override;
25868-
25869- void noMatchingTestCases( StringRef unmatchedSpec ) override;
25870- void testRunStarting( TestRunInfo const& testRunInfo ) override;
25871- void testCaseStarting( TestCaseInfo const& testInfo ) override;
25872- void testCasePartialStarting( TestCaseInfo const& testInfo,
25873- uint64_t partNumber ) override;
25874- void sectionStarting( SectionInfo const& sectionInfo ) override;
25875- void sectionEnded( SectionStats const& sectionStats ) override;
25876- void testCasePartialEnded( TestCaseStats const& testCaseStats,
25877- uint64_t partNumber ) override;
25878- void testCaseEnded( TestCaseStats const& testCaseStats ) override;
25879- void testRunEnded( TestRunStats const& testRunStats ) override;
25880- void skipTest( TestCaseInfo const& testInfo ) override;
25881- };
25882-
25883-} // end namespace Catch
25884-
25885-#endif // CATCH_REPORTER_EVENT_LISTENER_HPP_INCLUDED
25886-
25887-
25888-#ifndef CATCH_REPORTER_HELPERS_HPP_INCLUDED
25889-#define CATCH_REPORTER_HELPERS_HPP_INCLUDED
25890-
25891-#include <iosfwd>
25892-#include <string>
25893-#include <vector>
25894-
25895-
25896-namespace Catch {
25897-
25898- class IConfig;
25899- class TestCaseHandle;
25900- class ColourImpl;
25901-
25902- // Returns double formatted as %.3f (format expected on output)
25903- std::string getFormattedDuration( double duration );
25904-
25905- //! Should the reporter show duration of test given current configuration?
25906- bool shouldShowDuration( IConfig const& config, double duration );
25907-
25908- std::string serializeFilters( std::vector<std::string> const& filters );
25909-
25910- struct lineOfChars {
25911- char c;
25912- constexpr lineOfChars( char c_ ): c( c_ ) {}
25913-
25914- friend std::ostream& operator<<( std::ostream& out, lineOfChars value );
25915- };
25916-
25917- /**
25918- * Lists reporter descriptions to the provided stream in user-friendly
25919- * format
25920- *
25921- * Used as the default listing implementation by the first party reporter
25922- * bases. The output should be backwards compatible with the output of
25923- * Catch2 v2 binaries.
25924- */
25925- void
25926- defaultListReporters( std::ostream& out,
25927- std::vector<ReporterDescription> const& descriptions,
25928- Verbosity verbosity );
25929-
25930- /**
25931- * Lists listeners descriptions to the provided stream in user-friendly
25932- * format
25933- */
25934- void defaultListListeners( std::ostream& out,
25935- std::vector<ListenerDescription> const& descriptions );
25936-
25937- /**
25938- * Lists tag information to the provided stream in user-friendly format
25939- *
25940- * Used as the default listing implementation by the first party reporter
25941- * bases. The output should be backwards compatible with the output of
25942- * Catch2 v2 binaries.
25943- */
25944- void defaultListTags( std::ostream& out, std::vector<TagInfo> const& tags, bool isFiltered );
25945-
25946- /**
25947- * Lists test case information to the provided stream in user-friendly
25948- * format
25949- *
25950- * Used as the default listing implementation by the first party reporter
25951- * bases. The output is backwards compatible with the output of Catch2
25952- * v2 binaries, and also supports the format specific to the old
25953- * `--list-test-names-only` option, for people who used it in integrations.
25954- */
25955- void defaultListTests( std::ostream& out,
25956- ColourImpl* streamColour,
25957- std::vector<TestCaseHandle> const& tests,
25958- bool isFiltered,
25959- Verbosity verbosity );
25960-
25961- /**
25962- * Prints test run totals to the provided stream in user-friendly format
25963- *
25964- * Used by the console and compact reporters.
25965- */
25966- void printTestRunTotals( std::ostream& stream,
25967- ColourImpl& streamColour,
25968- Totals const& totals );
25969-
25970-} // end namespace Catch
25971-
25972-#endif // CATCH_REPORTER_HELPERS_HPP_INCLUDED
25973-
25974-
25975-
25976-#ifndef CATCH_REPORTER_JSON_HPP_INCLUDED
25977-#define CATCH_REPORTER_JSON_HPP_INCLUDED
25978-
25979-
25980-#include <stack>
25981-
25982-namespace Catch {
25983- class JsonReporter : public StreamingReporterBase {
25984- public:
25985- JsonReporter( ReporterConfig&& config );
25986-
25987- ~JsonReporter() override;
25988-
25989- static std::string getDescription();
25990-
25991- public: // StreamingReporterBase
25992- void testRunStarting( TestRunInfo const& runInfo ) override;
25993- void testRunEnded( TestRunStats const& runStats ) override;
25994-
25995- void testCaseStarting( TestCaseInfo const& tcInfo ) override;
25996- void testCaseEnded( TestCaseStats const& tcStats ) override;
25997-
25998- void testCasePartialStarting( TestCaseInfo const& tcInfo,
25999- uint64_t index ) override;
26000- void testCasePartialEnded( TestCaseStats const& tcStats,
26001- uint64_t index ) override;
26002-
26003- void sectionStarting( SectionInfo const& sectionInfo ) override;
26004- void sectionEnded( SectionStats const& sectionStats ) override;
26005-
26006- void assertionEnded( AssertionStats const& assertionStats ) override;
26007-
26008- //void testRunEndedCumulative() override;
26009-
26010- void benchmarkPreparing( StringRef name ) override;
26011- void benchmarkStarting( BenchmarkInfo const& ) override;
26012- void benchmarkEnded( BenchmarkStats<> const& ) override;
26013- void benchmarkFailed( StringRef error ) override;
26014-
26015- void listReporters(
26016- std::vector<ReporterDescription> const& descriptions ) override;
26017- void listListeners(
26018- std::vector<ListenerDescription> const& descriptions ) override;
26019- void listTests( std::vector<TestCaseHandle> const& tests ) override;
26020- void listTags( std::vector<TagInfo> const& tags ) override;
26021-
26022- private:
26023- Timer m_testCaseTimer;
26024- enum class Writer {
26025- Object,
26026- Array
26027- };
26028-
26029- JsonArrayWriter& startArray();
26030- JsonArrayWriter& startArray( StringRef key );
26031-
26032- JsonObjectWriter& startObject();
26033- JsonObjectWriter& startObject( StringRef key );
26034-
26035- void endObject();
26036- void endArray();
26037-
26038- bool isInside( Writer writer );
26039-
26040- void startListing();
26041- void endListing();
26042-
26043- // Invariant:
26044- // When m_writers is not empty and its top element is
26045- // - Writer::Object, then m_objectWriters is not be empty
26046- // - Writer::Array, then m_arrayWriters shall not be empty
26047- std::stack<JsonObjectWriter> m_objectWriters{};
26048- std::stack<JsonArrayWriter> m_arrayWriters{};
26049- std::stack<Writer> m_writers{};
26050-
26051- bool m_startedListing = false;
26052-
26053- // std::size_t m_sectionDepth = 0;
26054- // std::size_t m_sectionStarted = 0;
26055- };
26056-} // namespace Catch
26057-
26058-#endif // CATCH_REPORTER_JSON_HPP_INCLUDED
26059-
26060-
26061-#ifndef CATCH_REPORTER_JUNIT_HPP_INCLUDED
26062-#define CATCH_REPORTER_JUNIT_HPP_INCLUDED
26063-
26064-
26065-
26066-namespace Catch {
26067-
26068- class JunitReporter final : public CumulativeReporterBase {
26069- public:
26070- JunitReporter(ReporterConfig&& _config);
26071-
26072- static std::string getDescription();
26073-
26074- void testRunStarting(TestRunInfo const& runInfo) override;
26075-
26076- void testCaseStarting(TestCaseInfo const& testCaseInfo) override;
26077- void assertionEnded(AssertionStats const& assertionStats) override;
26078-
26079- void testCaseEnded(TestCaseStats const& testCaseStats) override;
26080-
26081- void testRunEndedCumulative() override;
26082-
26083- private:
26084- void writeRun(TestRunNode const& testRunNode, double suiteTime);
26085-
26086- void writeTestCase(TestCaseNode const& testCaseNode);
26087-
26088- void writeSection( std::string const& className,
26089- std::string const& rootName,
26090- SectionNode const& sectionNode,
26091- bool testOkToFail );
26092-
26093- void writeAssertions(SectionNode const& sectionNode);
26094- void writeAssertion(AssertionStats const& stats);
26095-
26096- XmlWriter xml;
26097- Timer suiteTimer;
26098- std::string stdOutForSuite;
26099- std::string stdErrForSuite;
26100- unsigned int unexpectedExceptions = 0;
26101- bool m_okToFail = false;
26102- };
26103-
26104-} // end namespace Catch
26105-
26106-#endif // CATCH_REPORTER_JUNIT_HPP_INCLUDED
26107-
26108-
26109-#ifndef CATCH_REPORTER_MULTI_HPP_INCLUDED
26110-#define CATCH_REPORTER_MULTI_HPP_INCLUDED
26111-
26112-
26113-namespace Catch {
26114-
26115- class MultiReporter final : public IEventListener {
26116- /*
26117- * Stores all added reporters and listeners
26118- *
26119- * All Listeners are stored before all reporters, and individual
26120- * listeners/reporters are stored in order of insertion.
26121- */
26122- std::vector<IEventListenerPtr> m_reporterLikes;
26123- bool m_haveNoncapturingReporters = false;
26124-
26125- // Keep track of how many listeners we have already inserted,
26126- // so that we can insert them into the main vector at the right place
26127- size_t m_insertedListeners = 0;
26128-
26129- void updatePreferences(IEventListener const& reporterish);
26130-
26131- public:
26132- MultiReporter( IConfig const* config ):
26133- IEventListener( config ) {
26134- m_preferences.shouldReportAllAssertionStarts = false;
26135- }
26136-
26137- using IEventListener::IEventListener;
26138-
26139- void addListener( IEventListenerPtr&& listener );
26140- void addReporter( IEventListenerPtr&& reporter );
26141-
26142- public: // IEventListener
26143-
26144- void noMatchingTestCases( StringRef unmatchedSpec ) override;
26145- void fatalErrorEncountered( StringRef error ) override;
26146- void reportInvalidTestSpec( StringRef arg ) override;
26147-
26148- void benchmarkPreparing( StringRef name ) override;
26149- void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) override;
26150- void benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) override;
26151- void benchmarkFailed( StringRef error ) override;
26152-
26153- void testRunStarting( TestRunInfo const& testRunInfo ) override;
26154- void testCaseStarting( TestCaseInfo const& testInfo ) override;
26155- void testCasePartialStarting(TestCaseInfo const& testInfo, uint64_t partNumber) override;
26156- void sectionStarting( SectionInfo const& sectionInfo ) override;
26157- void assertionStarting( AssertionInfo const& assertionInfo ) override;
26158-
26159- void assertionEnded( AssertionStats const& assertionStats ) override;
26160- void sectionEnded( SectionStats const& sectionStats ) override;
26161- void testCasePartialEnded(TestCaseStats const& testStats, uint64_t partNumber) override;
26162- void testCaseEnded( TestCaseStats const& testCaseStats ) override;
26163- void testRunEnded( TestRunStats const& testRunStats ) override;
26164-
26165- void skipTest( TestCaseInfo const& testInfo ) override;
26166-
26167- void listReporters(std::vector<ReporterDescription> const& descriptions) override;
26168- void listListeners(std::vector<ListenerDescription> const& descriptions) override;
26169- void listTests(std::vector<TestCaseHandle> const& tests) override;
26170- void listTags(std::vector<TagInfo> const& tags) override;
26171-
26172-
26173- };
26174-
26175-} // end namespace Catch
26176-
26177-#endif // CATCH_REPORTER_MULTI_HPP_INCLUDED
26178-
26179-
26180-#ifndef CATCH_REPORTER_REGISTRARS_HPP_INCLUDED
26181-#define CATCH_REPORTER_REGISTRARS_HPP_INCLUDED
26182-
26183-
26184-#include <type_traits>
26185-
26186-namespace Catch {
26187-
26188- namespace Detail {
26189-
26190- template <typename T, typename = void>
26191- struct has_description : std::false_type {};
26192-
26193- template <typename T>
26194- struct has_description<
26195- T,
26196- void_t<decltype( T::getDescription() )>>
26197- : std::true_type {};
26198-
26199- //! Indirection for reporter registration, so that the error handling is
26200- //! independent on the reporter's concrete type
26201- void registerReporterImpl( std::string const& name,
26202- IReporterFactoryPtr reporterPtr );
26203- //! Actually registers the factory, independent on listener's concrete type
26204- void registerListenerImpl( Detail::unique_ptr<EventListenerFactory> listenerFactory );
26205- } // namespace Detail
26206-
26207- class IEventListener;
26208- using IEventListenerPtr = Detail::unique_ptr<IEventListener>;
26209-
26210- template <typename T>
26211- class ReporterFactory : public IReporterFactory {
26212-
26213- IEventListenerPtr create( ReporterConfig&& config ) const override {
26214- return Detail::make_unique<T>( CATCH_MOVE(config) );
26215- }
26216-
26217- std::string getDescription() const override {
26218- return T::getDescription();
26219- }
26220- };
26221-
26222-
26223- template<typename T>
26224- class ReporterRegistrar {
26225- public:
26226- explicit ReporterRegistrar( std::string const& name ) {
26227- registerReporterImpl( name,
26228- Detail::make_unique<ReporterFactory<T>>() );
26229- }
26230- };
26231-
26232- template<typename T>
26233- class ListenerRegistrar {
26234-
26235- class TypedListenerFactory : public EventListenerFactory {
26236- StringRef m_listenerName;
26237-
26238- std::string getDescriptionImpl( std::true_type ) const {
26239- return T::getDescription();
26240- }
26241-
26242- std::string getDescriptionImpl( std::false_type ) const {
26243- return "(No description provided)";
26244- }
26245-
26246- public:
26247- TypedListenerFactory( StringRef listenerName ):
26248- m_listenerName( listenerName ) {}
26249-
26250- IEventListenerPtr create( IConfig const* config ) const override {
26251- return Detail::make_unique<T>( config );
26252- }
26253-
26254- StringRef getName() const override {
26255- return m_listenerName;
26256- }
26257-
26258- std::string getDescription() const override {
26259- return getDescriptionImpl( Detail::has_description<T>{} );
26260- }
26261- };
26262-
26263- public:
26264- ListenerRegistrar(StringRef listenerName) {
26265- registerListenerImpl( Detail::make_unique<TypedListenerFactory>(listenerName) );
26266- }
26267- };
26268-}
26269-
26270-#if !defined(CATCH_CONFIG_DISABLE)
26271-
26272-# define CATCH_REGISTER_REPORTER( name, reporterType ) \
26273- CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
26274- CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
26275- namespace { \
26276- const Catch::ReporterRegistrar<reporterType> \
26277- INTERNAL_CATCH_UNIQUE_NAME( catch_internal_RegistrarFor )( \
26278- name ); \
26279- } \
26280- CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
26281-
26282-# define CATCH_REGISTER_LISTENER( listenerType ) \
26283- CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
26284- CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
26285- namespace { \
26286- const Catch::ListenerRegistrar<listenerType> \
26287- INTERNAL_CATCH_UNIQUE_NAME( catch_internal_RegistrarFor )( \
26288- #listenerType##_catch_sr ); \
26289- } \
26290- CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
26291-
26292-#else // CATCH_CONFIG_DISABLE
26293-
26294-#define CATCH_REGISTER_REPORTER(name, reporterType)
26295-#define CATCH_REGISTER_LISTENER(listenerType)
26296-
26297-#endif // CATCH_CONFIG_DISABLE
26298-
26299-#endif // CATCH_REPORTER_REGISTRARS_HPP_INCLUDED
26300-
26301-
26302-#ifndef CATCH_REPORTER_SONARQUBE_HPP_INCLUDED
26303-#define CATCH_REPORTER_SONARQUBE_HPP_INCLUDED
26304-
26305-
26306-
26307-namespace Catch {
26308-
26309- class SonarQubeReporter final : public CumulativeReporterBase {
26310- public:
26311- SonarQubeReporter(ReporterConfig&& config)
26312- : CumulativeReporterBase(CATCH_MOVE(config))
26313- , xml(m_stream) {
26314- m_preferences.shouldRedirectStdOut = true;
26315- m_preferences.shouldReportAllAssertions = false;
26316- m_preferences.shouldReportAllAssertionStarts = false;
26317- m_shouldStoreSuccesfulAssertions = false;
26318- }
26319-
26320- static std::string getDescription() {
26321- using namespace std::string_literals;
26322- return "Reports test results in the Generic Test Data SonarQube XML format"s;
26323- }
26324-
26325- void testRunStarting( TestRunInfo const& testRunInfo ) override;
26326-
26327- void testRunEndedCumulative() override {
26328- writeRun( *m_testRun );
26329- xml.endElement();
26330- }
26331-
26332- void writeRun( TestRunNode const& runNode );
26333-
26334- void writeTestFile(StringRef filename, std::vector<TestCaseNode const*> const& testCaseNodes);
26335-
26336- void writeTestCase(TestCaseNode const& testCaseNode);
26337-
26338- void writeSection(std::string const& rootName, SectionNode const& sectionNode, bool okToFail);
26339-
26340- void writeAssertions(SectionNode const& sectionNode, bool okToFail);
26341-
26342- void writeAssertion(AssertionStats const& stats, bool okToFail);
26343-
26344- private:
26345- XmlWriter xml;
26346- };
26347-
26348-
26349-} // end namespace Catch
26350-
26351-#endif // CATCH_REPORTER_SONARQUBE_HPP_INCLUDED
26352-
26353-
26354-#ifndef CATCH_REPORTER_TAP_HPP_INCLUDED
26355-#define CATCH_REPORTER_TAP_HPP_INCLUDED
26356-
26357-
26358-namespace Catch {
26359-
26360- class TAPReporter final : public StreamingReporterBase {
26361- public:
26362- TAPReporter( ReporterConfig&& config ):
26363- StreamingReporterBase( CATCH_MOVE(config) ) {
26364- m_preferences.shouldReportAllAssertions = true;
26365- m_preferences.shouldReportAllAssertionStarts = false;
26366- }
26367-
26368- static std::string getDescription() {
26369- using namespace std::string_literals;
26370- return "Reports test results in TAP format, suitable for test harnesses"s;
26371- }
26372-
26373- void testRunStarting( TestRunInfo const& testInfo ) override;
26374-
26375- void noMatchingTestCases( StringRef unmatchedSpec ) override;
26376-
26377- void assertionEnded(AssertionStats const& _assertionStats) override;
26378-
26379- void testRunEnded(TestRunStats const& _testRunStats) override;
26380-
26381- private:
26382- std::size_t counter = 0;
26383- };
26384-
26385-} // end namespace Catch
26386-
26387-#endif // CATCH_REPORTER_TAP_HPP_INCLUDED
26388-
26389-
26390-#ifndef CATCH_REPORTER_TEAMCITY_HPP_INCLUDED
26391-#define CATCH_REPORTER_TEAMCITY_HPP_INCLUDED
26392-
26393-
26394-#include <cstring>
26395-
26396-#ifdef __clang__
26397-# pragma clang diagnostic push
26398-# pragma clang diagnostic ignored "-Wpadded"
26399-#endif
26400-
26401-namespace Catch {
26402-
26403- class TeamCityReporter final : public StreamingReporterBase {
26404- public:
26405- TeamCityReporter( ReporterConfig&& _config )
26406- : StreamingReporterBase( CATCH_MOVE(_config) )
26407- {
26408- m_preferences.shouldRedirectStdOut = true;
26409- m_preferences.shouldReportAllAssertionStarts = false;
26410- }
26411-
26412- ~TeamCityReporter() override;
26413-
26414- static std::string getDescription() {
26415- using namespace std::string_literals;
26416- return "Reports test results as TeamCity service messages"s;
26417- }
26418-
26419- void testRunStarting( TestRunInfo const& runInfo ) override;
26420- void testRunEnded( TestRunStats const& runStats ) override;
26421-
26422-
26423- void assertionEnded(AssertionStats const& assertionStats) override;
26424-
26425- void sectionStarting(SectionInfo const& sectionInfo) override {
26426- m_headerPrintedForThisSection = false;
26427- StreamingReporterBase::sectionStarting( sectionInfo );
26428- }
26429-
26430- void testCaseStarting(TestCaseInfo const& testInfo) override;
26431-
26432- void testCaseEnded(TestCaseStats const& testCaseStats) override;
26433-
26434- private:
26435- void printSectionHeader(std::ostream& os);
26436-
26437- bool m_headerPrintedForThisSection = false;
26438- Timer m_testTimer;
26439- };
26440-
26441-} // end namespace Catch
26442-
26443-#ifdef __clang__
26444-# pragma clang diagnostic pop
26445-#endif
26446-
26447-#endif // CATCH_REPORTER_TEAMCITY_HPP_INCLUDED
26448-
26449-
26450-#ifndef CATCH_REPORTER_XML_HPP_INCLUDED
26451-#define CATCH_REPORTER_XML_HPP_INCLUDED
26452-
26453-
26454-
26455-
26456-namespace Catch {
26457- class XmlReporter : public StreamingReporterBase {
26458- public:
26459- XmlReporter(ReporterConfig&& _config);
26460-
26461- ~XmlReporter() override;
26462-
26463- static std::string getDescription();
26464-
26465- virtual std::string getStylesheetRef() const;
26466-
26467- void writeSourceInfo(SourceLineInfo const& sourceInfo);
26468-
26469- public: // StreamingReporterBase
26470-
26471- void testRunStarting(TestRunInfo const& testInfo) override;
26472-
26473- void testCaseStarting(TestCaseInfo const& testInfo) override;
26474-
26475- void sectionStarting(SectionInfo const& sectionInfo) override;
26476-
26477- void assertionEnded(AssertionStats const& assertionStats) override;
26478-
26479- void sectionEnded(SectionStats const& sectionStats) override;
26480-
26481- void testCaseEnded(TestCaseStats const& testCaseStats) override;
26482-
26483- void testRunEnded(TestRunStats const& testRunStats) override;
26484-
26485- void benchmarkPreparing( StringRef name ) override;
26486- void benchmarkStarting(BenchmarkInfo const&) override;
26487- void benchmarkEnded(BenchmarkStats<> const&) override;
26488- void benchmarkFailed( StringRef error ) override;
26489-
26490- void listReporters(std::vector<ReporterDescription> const& descriptions) override;
26491- void listListeners(std::vector<ListenerDescription> const& descriptions) override;
26492- void listTests(std::vector<TestCaseHandle> const& tests) override;
26493- void listTags(std::vector<TagInfo> const& tags) override;
26494-
26495- private:
26496- Timer m_testCaseTimer;
26497- XmlWriter m_xml;
26498- int m_sectionDepth = 0;
26499- };
26500-
26501-} // end namespace Catch
26502-
26503-#endif // CATCH_REPORTER_XML_HPP_INCLUDED
26504-
26505-#endif // CATCH_REPORTERS_ALL_HPP_INCLUDED
26506-
26507-#endif // CATCH_ALL_HPP_INCLUDED
26508-#endif // CATCH_AMALGAMATED_HPP_INCLUDED
26509diff --git a/include/grim.h b/include/grim.h
26510index c27f237..53ee278 100755
26511--- a/include/grim.h
26512+++ b/include/grim.h
26513@@ -2,24 +2,19 @@
26514 #ifndef GRIM_H
26515 #define GRIM_H
26516
26517-#include <iostream>
26518-#include <string>
26519-#include <string_view>
26520-#include <vector>
26521-#include <unordered_map>
26522-#include <unordered_set>
26523-#include <memory>
26524-#include <charconv>
26525-#include <optional>
26526-#include <stdexcept>
26527-#include <deque>
26528+#include <stdio.h>
26529+#include <stddef.h>
26530
26531-// TODO:
26532-// * templates
26533
26534+#define MAX_TOKENS 32
26535+#define MAX_GROUPS 16
26536+#define MAX_STR_LEN 128
26537
26538
26539-enum class UnitType : short {
26540+
26541+
26542+/*
26543+typedef enum {
26544 // Color
26545 TEST, HEX,
26546 // Logic
26547@@ -114,182 +109,9 @@ enum class UnitType : short {
26548 // Image & Grouping
26549 URL, IMAGE_SET, CROSS_FADE, ELEMENT, GROUP, GRADIENT,
26550 NON_FUNC_PADDING
26551-};
26552-
26553+} UnitType;
26554
26555-// 8 bytes
26556-struct Unit {
26557- UnitType type; // short
26558- float value;
26559-};
26560-
26561-struct Range {
26562- size_t start;
26563- size_t end;
26564-};
26565-
26566-struct Context {
26567- int id;
26568- size_t index;
26569- size_t length;
26570- Context* previous;
26571-};
26572-
26573-struct Snapshot {
26574- Context* ctx;
26575- size_t pointer;
26576-};
26577-
26578-class Memory {
26579- private:
26580- std::deque<Context> arena;
26581- Context* current = nullptr;
26582- size_t pointer = 0;
26583- public:
26584- std::vector<Unit> heap;
26585-
26586- Memory() { heap.resize(1024); }
26587-
26588- void push(int id, std::vector<Unit>& units, size_t start, size_t end) {
26589- size_t len = end-start;
26590- arena.push_back({id, pointer, len, current});
26591- current = &arena.back();
26592- std::copy(units.begin() + start, units.begin() + end, heap.begin() + pointer);
26593- pointer += len;
26594- }
26595-
26596- void alloc(int id, size_t size) {
26597- arena.push_back({id, pointer, size, current});
26598- current = &arena.back();
26599- pointer += size;
26600-
26601- }
26602-
26603- // Used to prefill the heap
26604- void push_back(int id, Unit unit) {
26605- arena.push_back({id, pointer, 1, current});
26606- current = &arena.back();
26607- heap[pointer] = unit;
26608- pointer += 1;
26609- }
26610-
26611- Range get(int id) {
26612- Context* walker = current;
26613- while (walker != nullptr) {
26614- if (walker->id == id) return {walker->index, walker->index+walker->length};
26615- walker = walker->previous;
26616- }
26617- return {0,0}; // Not found
26618- }
26619-
26620- Snapshot save() {
26621- return {current, pointer};
26622- }
26623-
26624- void restore(Snapshot s) {
26625- current = s.ctx;
26626- pointer = s.pointer;
26627- }
26628-};
26629-
26630-class Window;
26631-
26632-struct ClassList {
26633- private:
26634- std::string* classString;
26635- std::vector<std::pair<int, int>> indexes;
26636- size_t len;
26637- // No return, modifies indexes directly
26638- void createIndex();
26639- bool checkIndex();
26640-
26641- public:
26642- ClassList(std::string* cs) : classString(cs) {}
26643- void add(std::string value);
26644- void remove(std::string value);
26645- void toggle(std::string value);
26646- void replace(std::string key, std::string value);
26647- bool contains(std::string value);
26648- std::string item(size_t key);
26649- size_t length();
26650-};
26651-
26652-struct StyleList {
26653- private:
26654- std::string* styleString;
26655- std::vector<std::tuple<int, int, int>> indexes;
26656- size_t len;
26657- void createIndex();
26658- bool checkIndex();
26659- public:
26660- StyleList(std::string* sS) : styleString(sS) {}
26661- std::string get(std::string key);
26662- void set(std::string key, std::string value);
26663- void remove(std::string key);
26664- std::pair<std::string, std::string> item(size_t index);
26665- size_t length();
26666-};
26667-
26668-struct dom_list {
26669- std::vector<Node> elements;
26670-}
26671-
26672-struct Node {
26673- std::vector<Pair> attributes;
26674- std::vector<Pair> computed_style;
26675-}
26676-
26677-struct Pair {
26678- std::string key;
26679- std::string value;
26680-}
26681-
26682-class Node {
26683- private:
26684- std::string TagName = "";
26685- std::unordered_map<std::string, std::string> attributes;
26686- float em = 0;
26687- float width = 0;
26688- float height = 0;
26689- public:
26690- Window* window;
26691-
26692- Node* parent;
26693-
26694- std::vector<Node> children;
26695- ClassList classList() { return ClassList(&this->attributes["class"]); }
26696- StyleList style() { return StyleList(&this->attributes["style"]); }
26697-
26698- Node() : parent(nullptr) {}
26699-
26700- std::string getTagName() const;
26701- void setTagName(const std::string& name);
26702-
26703- float getEM() const; // Returns value from the cache
26704- float getWidth() const;
26705- float getHeight() const;
26706- void cacheEM(const float value); // Sets the cache value (should not be manually used)
26707- void cacheWidth(const float value);
26708- void cacheHeight(const float value);
26709-
26710- Node* createElement(std::string name);
26711-
26712- void setAttribute(const std::string& name, const std::string& value);
26713- void deleteAttribute(const std::string& name);
26714- std::string getAttribute(const std::string& name) const;
26715- bool hasAttribute(const std::string& name) const;
26716-
26717- const std::unordered_map<std::string, std::string>& getAttributes() const;
26718- std::vector<std::string> getAttributeKeys();
26719-
26720- std::string print(int indent = 0);
26721-};
26722-
26723-std::vector<std::vector<std::string>> parseSelectorParts(std::string_view);
26724-
26725-bool testSelector(Node*, std::vector<std::vector<std::string>>);
26726-
26727-enum class KeyType : short {
26728+typedef enum {
26729 ACCENT_COLOR, ALIGN_CONTENT, ALIGN_ITEMS, ALIGN_SELF, ALIGNMENT_BASELINE, ALL, ANCHOR_NAME, ANIMATION_COMPOSITION, ANIMATION_DELAY,
26730 ANIMATION_DIRECTION, ANIMATION_DURATION, ANIMATION_FILL_MODE, ANIMATION_ITERATION_COUNT, ANIMATION_NAME, ANIMATION_PLAY_STATE, ANIMATION_RANGE_END,
26731 ANIMATION_RANGE_START, ANIMATION_RANGE, ANIMATION_TIMELINE, ANIMATION_TIMING_FUNCTION, ANIMATION, APPEARANCE, ASPECT_RATIO,
26732@@ -361,84 +183,9 @@ enum class KeyType : short {
26733 X,
26734 Y,
26735 Z_INDEX, ZOOM
26736-};
26737+} KeyType;
26738
26739-class IndexedMap {
26740- public:
26741- std::vector<std::pair<std::string, std::vector<Unit>>> map{};
26742- std::vector<Unit> find(std::string key) {
26743- for (size_t i = 0; i < map.size(); i++) {
26744- if (map[i].first == key) {
26745- return map[i].second;
26746- }
26747- }
26748- }
26749-
26750- bool contains(std::string key) {
26751- for (size_t i = 0; i < map.size(); i++) {
26752- if (map[i].first == key) {
26753- return true;
26754- }
26755- }
26756- return false;
26757- }
26758-
26759- size_t index(std::string key) {
26760- for (size_t i = 0; i < map.size(); i++) {
26761- if (map[i].first == key) {
26762- return i;
26763- }
26764- }
26765- }
26766- std::vector<Unit> at(size_t i) {
26767- return map[i].second;
26768- }
26769-
26770- std::string key(size_t i) {
26771- return map[i].first;
26772- }
26773-
26774- size_t set(std::string key, std::vector<Unit> value) {
26775- for (size_t i = 0; i < map.size(); i++) {
26776- if (map[i].first == key) {
26777- map[i].second = value;
26778- return i;
26779- }
26780- }
26781- map.push_back({key, value});
26782- return map.size()-1;
26783- }
26784-
26785-
26786- // add
26787-
26788- // function to build Context and heap
26789-
26790- //
26791-};
26792-
26793-class Style {
26794- public:
26795- std::unordered_map<std::string, std::vector<size_t>> basemap{};
26796-
26797- std::string name; // remove
26798- std::vector<std::vector<std::string>> selector{};
26799-
26800- std::unordered_map<KeyType, std::vector<Unit>> properties{}; // When computing have a is rel function that if not full compute the value
26801- // like if the value is calc(1px + 10px) then just store 11px but if its 10vw
26802- // then you can't
26803-
26804- IndexedMap variables{};
26805-
26806- // Nesting
26807- std::vector<Style> children{};
26808-
26809- // Functions
26810- void addChild(Style s);
26811- std::unordered_map<KeyType, UnitType> getStyles(Node* n);
26812-};
26813-
26814-enum class Media : char {
26815+typedef enum {
26816 All,
26817 Print,
26818 Screen,
26819@@ -456,158 +203,59 @@ enum class Media : char {
26820 Reduce,
26821 Fast,
26822 Slow
26823-};
26824+} Media;
26825
26826-class Window {
26827- private:
26828- float width = 0;
26829- float height = 0;
26830- float resolution = 0;
26831- float em = 16;
26832- public:
26833-
26834- std::unordered_map<std::string, Media> MediaFeatures {
26835- {"any-hover", Media::Hover},
26836- {"any-pointer", Media::Fine},
26837- {"orientation", Media::Landscape},
26838- {"pefers-color-scheme", Media::Light},
26839- {"contrast", Media::NoPreference},
26840- {"prefers-reduced-motion", Media::NoPreference},
26841- {"prefers-reduced-transparency", Media::NoPreference},
26842- {"update", Media::Fast},
26843- {"media", Media::All},
26844- };
26845-
26846-
26847- void parseHTML(std::istream& inputStream);
26848-
26849- Node document;
26850- Style CSS;
26851-
26852- // +---------------------------------------------------+
26853- // | (hldfk) Window Properties |
26854- // +---------------------------------------------------+
26855-
26856- void setWidth(float value) {
26857- width = value;
26858- }
26859- void setHeight(float value) {
26860- height = value;
26861- }
26862- void setResolution(float value) {
26863- resolution = value;
26864- }
26865-
26866- void setEM(float value) {
26867- em = value;
26868- }
26869-
26870- void setMouse(Media value) {
26871- // Accepts: Media::Hover && Media::None
26872- MediaFeatures.at("any-hover") = value;
26873- MediaFeatures.at("any-pointer") = value;
26874- }
26875-
26876- void setOrientation(Media value) {
26877- MediaFeatures.at("orientation") = value;
26878- }
26879-
26880- void setColorScheme(Media value) {
26881- MediaFeatures.at("prefers-color-scheme") = value;
26882- }
26883-
26884- void setContrast(Media value) {
26885- MediaFeatures.at("contrast") = value;
26886- }
26887-
26888- void setReducedMotion(Media value) {
26889- MediaFeatures.at("prefers-reduced-motion") = value;
26890- }
26891-
26892- void setReducedTransparency(Media value) {
26893- MediaFeatures.at("prefers-reduced-transparency") = value;
26894- }
26895-
26896- void setUpdate(Media value) {
26897- MediaFeatures.at("update") = value;
26898- }
26899-
26900- void setMedia(Media value) {
26901- MediaFeatures.at("media") = value;
26902- }
26903-
26904- // Getters
26905- float getWidth() const {
26906- return width;
26907- }
26908- float getHeight() const {
26909- return height;
26910- }
26911- float getResolution() const {
26912- return resolution;
26913- }
26914- float getEM() const {
26915- return em;
26916- }
26917- float getAspectRatio() const {
26918- if (height == 0) return 0.0;
26919- return static_cast<double>(width) / height;
26920- }
26921- Media getMedia() const {
26922- auto it = MediaFeatures.find("media");
26923- return it->second;
26924- }
26925-
26926- Media getAnyHover() const {
26927- auto it = MediaFeatures.find("any-hover");
26928- return it->second;
26929- }
26930-
26931- Media getAnyPointer() const {
26932- auto it = MediaFeatures.find("any-pointer");
26933- return it->second;
26934- }
26935+// 8 bytes
26936+struct Unit {
26937+ UnitType type; // short
26938+ float value;
26939+};
26940
26941- Media getOrientation() const {
26942- auto it = MediaFeatures.find("orientation");
26943- return it->second;
26944- }
26945+struct Range {
26946+ size_t start;
26947+ size_t end;
26948+};
26949
26950- Media getColorScheme() const {
26951- auto it = MediaFeatures.find("prefers-color-scheme");
26952- return it->second;
26953- }
26954+struct Context {
26955+ int id;
26956+ size_t index;
26957+ size_t length;
26958+ Context* previous;
26959+};
26960
26961- Media getContrast() const {
26962- auto it = MediaFeatures.find("contrast");
26963- return it->second;
26964- }
26965+struct Snapshot {
26966+ Context* ctx;
26967+ size_t pointer;
26968+};
26969
26970- Media getReducedMotion() const {
26971- auto it = MediaFeatures.find("prefers-reduced-motion");
26972- return it->second;
26973- }
26974+struct dom_list {
26975+ std::vector<Node> elements;
26976+}
26977
26978- Media getReducedTransparency() const {
26979- auto it = MediaFeatures.find("prefers-reduced-motion");
26980- return it->second;
26981- }
26982+struct Node {
26983+ std::vector<Pair> attributes;
26984+ std::vector<Pair> computed_style;
26985+}
26986
26987- Media getUpdate() const {
26988- auto it = MediaFeatures.find("update");
26989- return it->second;
26990- }
26991-};
26992+struct Pair {
26993+ std::string key;
26994+ std::string value;
26995+}
26996+*/
26997+typedef struct {
26998+ char items[MAX_TOKENS][MAX_STR_LEN];
26999+ int size;
27000+} SelectorParts;
27001
27002-// Will need to require an adapter later
27003-// for now I just want to work on at rules
27004+typedef struct {
27005+ SelectorParts items[MAX_GROUPS];
27006+ int size;
27007+} ParsedSelector;
27008
27009+ParsedSelector parseSelectorParts(const char*);
27010 /*
27011-For the adapter, it will take a window as a argument to set the adapters capabilties
27012-*/
27013-Window createWindow();
27014-
27015+bool testSelector(Node*, std::vector<std::vector<std::string>>);
27016
27017 Unit UnitValue(Memory&, std::vector<Unit>&, size_t, size_t);
27018-
27019+*/
27020 #endif // NODE_H
27021diff --git a/include/parser.h b/include/parser.h
27022index abcbdca..7f5b328 100755
27023--- a/include/parser.h
27024+++ b/include/parser.h
27025@@ -2,20 +2,6 @@
27026 #ifndef PARSER_H
27027 #define PARSER_H
27028
27029-#include <memory>
27030-#include <istream>
27031-#include <unordered_map>
27032-#include <string>
27033-#include <string_view>
27034-
27035-class Node;
27036-class Style;
27037-
27038-struct ParsedDocument {
27039- Node document;
27040- Style CSS;
27041-};
27042-
27043 struct SymbolTable {
27044 std::unordered_map<std::string, int> table;
27045 int next;
27046diff --git a/playground/parseselectorparts.c b/playground/parseselectorparts.c
27047new file mode 100644
27048index 0000000..0a826bb
27049--- /dev/null
27050+++ b/playground/parseselectorparts.c
27051@@ -0,0 +1,188 @@
27052+#define _POSIX_C_SOURCE 199309L
27053+#include <stdio.h>
27054+#include <time.h>
27055+#include <string.h>
27056+
27057+#include "../include/grim.h"
27058+
27059+#include <stdbool.h>
27060+
27061+// Helper to check if a single part (buffer) matches expected strings
27062+bool verify_part(SelectorParts actual, const char* expected[], int expected_count, int part_idx) {
27063+ if (actual.size != expected_count) {
27064+ printf(" ❌ Fail Part %d: Got %d items, expected %d\n", part_idx, actual.size, expected_count);
27065+ return false;
27066+ }
27067+ for (int i = 0; i < expected_count; i++) {
27068+ if (strcmp(actual.items[i], expected[i]) != 0) {
27069+ printf(" ❌ Fail Part %d index %d: Got \"%s\", expected \"%s\"\n",
27070+ part_idx, i, actual.items[i], expected[i]);
27071+ return false;
27072+ }
27073+ }
27074+ return true;
27075+}
27076+
27077+// The main test runner
27078+void test_selector(const char* query, const char* expected_parts[][MAX_TOKENS], int item_counts[], int part_count) {
27079+ ParsedSelector actual = parseSelectorParts(query);
27080+ bool pass = true;
27081+
27082+ printf("Test: %s\n", query);
27083+
27084+ if (actual.size != part_count) {
27085+ printf(" ❌ Fail: Got %d comma-separated parts, expected %d\n", actual.size, part_count);
27086+ pass = false;
27087+ } else {
27088+ for (int i = 0; i < part_count; i++) {
27089+ if (!verify_part(actual.items[i], expected_parts[i], item_counts[i], i)) {
27090+ pass = false;
27091+ }
27092+ }
27093+ }
27094+
27095+ if (pass) printf(" ✅ Passed\n");
27096+}
27097+
27098+void print_parsed_selector(ParsedSelector p) {
27099+ puts("[\n");
27100+ for (int i = 0; i < p.size; i++) {
27101+ puts("[");
27102+ for (int j = 0; j < p.items[i].size; j++) {
27103+ printf("\"%s\", ", p.items[i].items[j]);
27104+ }
27105+ puts("],\n");
27106+ }
27107+ puts("]\n");
27108+}
27109+
27110+void benchmark_parse_selector_parts(const char* query) {
27111+ struct timespec start, end;
27112+
27113+ int iterations = 10000;
27114+ ParsedSelector r;
27115+
27116+ // Get start time
27117+ clock_gettime(CLOCK_MONOTONIC, &start);
27118+
27119+ for (int i = 0; i < iterations; i++) {
27120+ r = parseSelectorParts(query);
27121+ }
27122+
27123+ // Get end time
27124+ clock_gettime(CLOCK_MONOTONIC, &end);
27125+
27126+ print_parsed_selector(r);
27127+
27128+ // Calculate time difference in seconds
27129+ double total_time = (end.tv_sec - start.tv_sec) + (end.tv_nsec - start.tv_nsec) / 1e9;
27130+ printf("Average execution time: %.9f seconds (%f us)\n",
27131+ total_time / iterations,
27132+ (total_time / iterations) * 1000000);
27133+}
27134+
27135+void run_css_test_suite() {
27136+ // 1. Simple CSS selector
27137+ {
27138+ const char* exp[1][MAX_TOKENS] = {{"div", ">", "h1"}};
27139+ int counts[] = {3};
27140+ test_selector("div > h1", exp, counts, 1);
27141+ }
27142+
27143+ // 2. Simple with pseudo class
27144+ {
27145+ const char* exp[1][MAX_TOKENS] = {{"div", ">", "h1", ":checked"}};
27146+ int counts[] = {4};
27147+ test_selector("div > h1:checked", exp, counts, 1);
27148+ }
27149+
27150+ // 3. Attribute selector
27151+ {
27152+ const char* exp[1][MAX_TOKENS] = {{"a", "[href=\"https://www.example.com/\"]"}};
27153+ int counts[] = {2};
27154+ test_selector("a[href=\"https://www.example.com/\"]", exp, counts, 1);
27155+ }
27156+
27157+ // 4. has() logic
27158+ {
27159+ const char* exp[1][MAX_TOKENS] = {{"h1", ":has", "(+ h2)"}};
27160+ int counts[] = {3};
27161+ test_selector("h1:has(+ h2)", exp, counts, 1);
27162+ }
27163+
27164+ // 5. where() with internal commas (should be one token)
27165+ {
27166+ const char* exp[1][MAX_TOKENS] = {{":where", "(ol, ul, menu:unsupported)"}};
27167+ int counts[] = {2};
27168+ test_selector(":where(ol, ul, menu:unsupported)", exp, counts, 1);
27169+ }
27170+
27171+ // 6. Multiple simple selectors (Commas!)
27172+ {
27173+ const char* exp[3][MAX_TOKENS] = {
27174+ {"input", ":required"},
27175+ {"div", "#id", "+", "h1", ".c1", ".c2"},
27176+ {"input", "[type=\"password\"]", ".class"}
27177+ };
27178+ int counts[] = {2, 6, 3};
27179+ test_selector("input:required, div#id + h1.c1.c2, input[type='password'].class", exp, counts, 3);
27180+ }
27181+
27182+ // 7. Descendant combinator (The space)
27183+ {
27184+ const char* exp[1][MAX_TOKENS] = {{"div", " ", "h1"}};
27185+ int counts[] = {3};
27186+ test_selector("div h1", exp, counts, 1);
27187+ }
27188+
27189+ // 8. has() + pseudo
27190+ {
27191+ const char* exp[1][MAX_TOKENS] = {{"div", ":has", "(h1)", ":checked"}};
27192+ int counts[] = {4};
27193+ test_selector("div:has(h1):checked", exp, counts, 1);
27194+ }
27195+
27196+ // 9. ID only
27197+ {
27198+ const char* exp[1][MAX_TOKENS] = {{"#id"}};
27199+ int counts[] = {1};
27200+ test_selector("#id", exp, counts, 1);
27201+ }
27202+
27203+ // 10. Multiple selectors (Mixed)
27204+ {
27205+ const char* exp[3][MAX_TOKENS] = {
27206+ {"h1"},
27207+ {"h1", "~", "p"},
27208+ {":last-child"}
27209+ };
27210+ int counts[] = {1, 3, 1};
27211+ test_selector("h1, h1 ~p, :last-child", exp, counts, 3);
27212+ }
27213+
27214+ // 11. Relative selector
27215+ {
27216+ const char* exp[1][MAX_TOKENS] = {{"+", "p"}};
27217+ int counts[] = {2};
27218+ test_selector("+ p", exp, counts, 1);
27219+ }
27220+
27221+ // 12. Tag + Attr + Pseudo
27222+ {
27223+ const char* exp[1][MAX_TOKENS] = {{"input", "[type=\"text\"]", ":disabled"}};
27224+ int counts[] = {3};
27225+ test_selector("input[type=\"text\"]:disabled", exp, counts, 1);
27226+ }
27227+
27228+ // 13. Pseudo element
27229+ {
27230+ const char* exp[1][MAX_TOKENS] = {{"h1", ":before"}}; // Note: Your code currently strips the second colon
27231+ int counts[] = {2};
27232+ test_selector("h1::before", exp, counts, 1);
27233+ }
27234+}
27235+
27236+int main() {
27237+ benchmark_parse_selector_parts("input:required, div#id + h1.c1.c2, input[type='password'].class");
27238+ run_css_test_suite();
27239+}
27240diff --git a/playground/parseselectorparts.cc b/playground/parseselectorparts.cc
27241deleted file mode 100644
27242index ca566fe..0000000
27243--- a/playground/parseselectorparts.cc
27244+++ /dev/null
27245@@ -1,21 +0,0 @@
27246-#include "../include/grim.h"
27247-#include "../include/parser.h"
27248-#include <string>
27249-#include <vector>
27250-#include <iostream>
27251-
27252-int main() {
27253- std::vector<std::vector<std::string>> parts = parseSelectorParts("@media (min-width: 60px)");
27254-
27255-
27256- std::cout << "[" << std::endl;
27257- for (size_t i = 0; i < parts.size(); i++) {
27258- std::cout << "[";
27259- for (size_t j = 0; j < parts[i].size(); j++) {
27260- std::cout << "\"" << parts[i][j] << "\", ";
27261- }
27262- std::cout << "]," << std::endl;
27263- }
27264- std::cout << "]" << std::endl;
27265-}
27266-
27267diff --git a/src/grim.cc b/src/grim.c
27268similarity index 73%
27269rename from src/grim.cc
27270rename to src/grim.c
27271index 18f1ccd..0c6051e 100755
27272--- a/src/grim.cc
27273+++ b/src/grim.c
27274@@ -1,19 +1,9 @@
27275 #include "grim.h"
27276-#include "parser.h"
27277-#include <iostream>
27278-#include <sstream>
27279-#include <algorithm>
27280-#include <stdexcept>
27281-#include <cctype>
27282-#include <string_view>
27283-#include <queue>
27284-#include <set>
27285-#include <tuple>
27286-#include <optional>
27287-#include <stdexcept>
27288-#include <limits>
27289-#include <cmath>
27290-#include <string>
27291+//#include "parser.h"
27292+#include <stdio.h>
27293+#include <stddef.h>
27294+#include <string.h>
27295+#include <ctype.h>
27296
27297 // +------------------------------------------------------+
27298 // |(TOC) Table of contents |
27299@@ -35,54 +25,6 @@
27300 // | (p98ym) Utils |
27301 // +---------------------------------------------------+
27302
27303-void trimSpace(std::string& str) {
27304- if (str.empty()) {
27305- return;
27306- }
27307-
27308- // Find first non-space
27309- size_t first_non_space = 0;
27310- while (first_non_space < str.length() && std::isspace(str[first_non_space])) {
27311- first_non_space++;
27312- }
27313-
27314- // If all spaces or empty
27315- if (first_non_space == str.length()) {
27316- str.clear(); // Set to empty string
27317- return;
27318- }
27319-
27320- // Find last non-space
27321- size_t last_non_space = str.length() - 1;
27322- while (last_non_space >= first_non_space && std::isspace(str[last_non_space])) {
27323- last_non_space--;
27324- }
27325-
27326- // Erase trailing spaces
27327- if (last_non_space < str.length() - 1) {
27328- str.erase(last_non_space + 1);
27329- }
27330-
27331- // Erase leading spaces
27332- if (first_non_space > 0) {
27333- str.erase(0, first_non_space);
27334- }
27335-}
27336-// +---------------------------------------------------+
27337-// | (hldfk) Window |
27338-// +---------------------------------------------------+
27339-// All of windows props will come from the adapter setting
27340-// them
27341-Window createWindow() {
27342- Window window;
27343- return window;
27344-}
27345-
27346-void Window::parseHTML(std::istream& inputStream) {
27347- ParsedDocument doc = parseDocument(inputStream);
27348- document = doc.document;
27349- CSS = doc.CSS;
27350-}
27351
27352 // +---------------------------------------------------+
27353 // | (tigfn) Attribute Handling |
27354@@ -96,461 +38,15 @@ void Window::parseHTML(std::istream& inputStream) {
27355 // handlers like ClassList (.classList) and StyleList
27356 // (.style) for more information on each view
27357 // f98y0 and lhujn respectively.
27358+/*
27359+void SET_ATTRIBUTE(Node* n, char* key, char* value) {
27360
27361-// The Attribute class is defined in the header file
27362-
27363-static const std::unordered_map<std::string, std::string> DEFAULT_ATTRIBUTE_VALUES = {
27364- {"tabindex", "-1"},
27365- {"hidden", "false"}
27366-};
27367-
27368-// Tag Name is not a attribute so it needs to be handled differently
27369-std::string Node::getTagName() const {
27370- return TagName;
27371-}
27372-void Node::setTagName(const std::string& name) { TagName = name; }
27373-
27374-void Node::setAttribute(const std::string& name, const std::string& value) {
27375- attributes[name] = value;
27376-}
27377-
27378-void Node::deleteAttribute(const std::string& name) {
27379- attributes.erase(name);
27380-}
27381-
27382-std::string Node::getAttribute(const std::string& name) const {
27383- // First check in the user set attributes
27384- auto it = attributes.find(name);
27385- if (it != attributes.end()) {
27386- // return the value wrapped in the Attribute class
27387- return it->second;
27388- } else {
27389- // If its not set by the user then find it in the
27390- // default values map
27391- it = DEFAULT_ATTRIBUTE_VALUES.find(name);
27392- if (it != DEFAULT_ATTRIBUTE_VALUES.end()) {
27393- return it->second;
27394- } else {
27395- return "";
27396- }
27397- }
27398-}
27399-
27400-bool Node::hasAttribute(const std::string& name) const {
27401- return attributes.contains(name) || DEFAULT_ATTRIBUTE_VALUES.contains(name);
27402-}
27403-
27404-std::vector<std::string> Node::getAttributeKeys() {
27405- std::vector<std::string> keys;
27406-
27407- for(auto p : attributes) {
27408- keys.push_back(p.first);
27409- }
27410- return keys;
27411-}
27412-
27413-const std::unordered_map<std::string, std::string>& Node::getAttributes() const {
27414- return attributes;
27415-}
27416-
27417-// +---------------------------------------------------+
27418-// | (o78ty) Cache |
27419-// +---------------------------------------------------+
27420-// For frequently accessed values like em, width, height
27421-// it makes sense to not fully calculate the value access
27422-// during rendering as it is very intensive. The functions
27423-// below are used to store/retrive the last calculated
27424-// value. cache*() will not set the real value for the
27425-// Nodei, it only effects the interval variables.
27426-
27427-float Node::getEM() const {
27428- return em;
27429-}
27430-float Node::getWidth() const {
27431- return width;
27432-}
27433-float Node::getHeight() const {
27434- return height;
27435-}
27436-void Node::cacheEM(const float value) {
27437- em = value;
27438-}
27439-void Node::cacheWidth(const float value) {
27440- width = value;
27441-}
27442-void Node::cacheHeight(const float value) {
27443- height = value;
27444-}
27445-
27446-
27447-// +---------------------------------------------------+
27448-// | (f98y0) ClassList |
27449-// +---------------------------------------------------+
27450-
27451-void ClassList::createIndex() {
27452- int index = 0;
27453- // Add a space to the back to help trigger the adding of the
27454- // last item
27455- std::string classes = *classString+" ";
27456- // Update the stored length
27457- len = classes.length();
27458- indexes.clear();
27459-
27460- bool waitForFirstChar = true;
27461-
27462- for (size_t i = 0; i < len; i++) {
27463- if (waitForFirstChar && classes[i] != ' ') {
27464- index = i;
27465- waitForFirstChar = false;
27466- } else if (!waitForFirstChar) {
27467- if (classes[i] == ' ') {
27468- indexes.push_back({index, i-index});
27469- waitForFirstChar = true;
27470- }
27471- }
27472- }
27473-}
27474-
27475-
27476-bool ClassList::checkIndex() {
27477- if (classString->length() != len) {
27478- return false;
27479- } else {
27480- // Skip the first one because there is a space
27481- // also we don't care if the values are the same
27482- // just that the array indexing is the same. If the
27483- // value is the same size and position it doesn't matter
27484- for (size_t i = 1; i < indexes.size(); i++) {
27485- // See if the index position is a space
27486- // if not return false
27487- if (!std::isspace(classString->at(indexes[i-1].first))) {
27488- return false;
27489- }
27490- }
27491- return true;
27492- }
27493-}
27494-
27495-size_t ClassList::length() {
27496- if (!checkIndex()) {
27497- createIndex();
27498- }
27499- return indexes.size();
27500-}
27501-
27502-
27503-std::string ClassList::item(size_t key) {
27504- if (!checkIndex()) {
27505- createIndex();
27506- }
27507- if (key < indexes.size()) {
27508- std::pair<int, int> pair = indexes[key];
27509- return classString->substr(pair.first, pair.second);
27510- } else {
27511- return "";
27512- }
27513-}
27514-
27515-void ClassList::add(std::string value) {
27516- if (!checkIndex()) {
27517- createIndex();
27518- }
27519-
27520- if (classString->length() == 0) {
27521- classString->append(value);
27522- } else {
27523- classString->append(" "+value);
27524- }
27525- // len because the index of the added space will be the length of
27526- // the prevous string
27527- int vl = value.length();
27528- indexes.push_back({len, vl});
27529- len += vl+1;
27530-}
27531-
27532-void ClassList::remove(std::string value) {
27533- if (!checkIndex()) {
27534- createIndex();
27535- }
27536-
27537- int newLen = value.length();
27538- size_t cLen = indexes.size();
27539-
27540- for (size_t i = 0; i < cLen; i++) {
27541- std::pair<int, int> pair = indexes[i];
27542- if (newLen == pair.second) {
27543- if (classString->substr(pair.first, pair.second) == value) {
27544- // Splice out the value to be removed
27545- // ISSUE: This will keep the surounding spaces and cause the size to grow when
27546- // classes are added and removed
27547- classString->erase(pair.first, pair.second);
27548- }
27549- }
27550- }
27551-}
27552-
27553-bool ClassList::contains(std::string value) {
27554- if (!checkIndex()) {
27555- createIndex();
27556- }
27557-
27558- int newLen = value.length();
27559- size_t cLen = indexes.size();
27560- bool found = false;
27561-
27562- for (size_t i = 0; i < cLen; i++) {
27563- std::pair<int, int> pair = indexes[i];
27564- if (newLen == pair.second) {
27565- if (classString->substr(pair.first, pair.second) == value) {
27566- // Same logic as remove but turns found true then breaks
27567- found = true;
27568- break;
27569- }
27570- }
27571- }
27572- return found;
27573-}
27574-
27575-void ClassList::toggle(std::string value) {
27576- if (contains(value)) {
27577- remove(value);
27578- } else {
27579- add(value);
27580- }
27581-}
27582-
27583-// +---------------------------------------------------+
27584-// | (lhujn) StyleList |
27585-// +---------------------------------------------------+
27586-// StyleList provides the JS .style API with a few changes
27587-// to get/set values use .get or .set. To get the entire
27588-// value call .getAttribute("style"). The StyleList stores
27589-// a index of the positions of the first charactor, the ':',
27590-// and the position of the ';'. On every read/write the index
27591-// is verified then the change or read is made. If the value
27592-// changes the positions of the index it will be updated on the
27593-// next read/write. This allows the attribute "style" to always
27594-// contain the true value of the inline style and still have an
27595-// easy to use API for .style. To get all styles, call .length()
27596-// and itterate through all items using .item(<size_t>).
27597-
27598-void StyleList::createIndex() {
27599- // Update the stored length
27600- len = styleString->length();
27601- indexes.clear();
27602-
27603- // " background-color: white;"
27604- // ^
27605-
27606- int firstLetter = 0;
27607- bool firstNonWhiteSpace = false;
27608- // " background-color: white;"
27609- // ^
27610- int splitPoint = 0;
27611- bool keyFound = false;
27612- // " background-color: white;"
27613- // ^
27614- int end = 0;
27615- bool secondNonWhiteSpace = false;
27616- // " background-color: white;"
27617- // ^
27618- // Reset all to false and add the indexs
27619-
27620-
27621- for (size_t i = 0; i < len; i++) {
27622- char s = styleString->at(i);
27623- if (firstNonWhiteSpace) {
27624- if (keyFound) {
27625- if (secondNonWhiteSpace) {
27626- if (s == ';' || i >= len-1) {
27627- if (i >= len-1 && s != ';') {
27628- end = i+1;
27629- } else {
27630- end = i;
27631- }
27632- indexes.push_back({firstLetter, splitPoint, end});
27633- firstNonWhiteSpace = false;
27634- secondNonWhiteSpace = false;
27635- keyFound = false;
27636- }
27637- } else if (!std::isspace(s)) {
27638- secondNonWhiteSpace = true;
27639- }
27640- } else if (s == ':') {
27641- splitPoint = i;
27642- keyFound = true;
27643- }
27644- } else if (!std::isspace(s)) {
27645- firstLetter = i;
27646- firstNonWhiteSpace = true;
27647- }
27648- }
27649-}
27650-
27651-
27652-bool StyleList::checkIndex() {
27653- if (styleString->length() != len) {
27654- return false;
27655- } else {
27656- for (size_t i = 0; i < indexes.size(); i++) {
27657- if (std::isspace(styleString->at(std::get<0>(indexes[i]))) ||
27658- styleString->at(std::get<1>(indexes[i])) != ':' ||
27659- styleString->at(std::get<2>(indexes[i])) != ';'
27660- ) {
27661- return false;
27662- }
27663- }
27664- return true;
27665- }
27666-}
27667-
27668-std::pair<std::string, std::string> StyleList::item(size_t index) {
27669- if (!checkIndex()) {
27670- createIndex();
27671- }
27672-
27673- std::pair<std::string, std::string> property;
27674-
27675- int f = std::get<0>(indexes[index]);
27676- int s = std::get<1>(indexes[index]);
27677- property.first = styleString->substr(f, s-f);
27678- trimSpace(property.first);
27679-
27680- int t = std::get<2>(indexes[index]);
27681- property.second = styleString->substr(s+1, t-(s+1));
27682- trimSpace(property.second);
27683- return property;
27684-
27685-}
27686-
27687-size_t StyleList::length() {
27688- if (!checkIndex()) {
27689- createIndex();
27690- }
27691- return indexes.size();
27692-}
27693-
27694-std::string StyleList::get(std::string key) {
27695- if (!checkIndex()) {
27696- createIndex();
27697- }
27698- for (size_t i = 0; i < indexes.size(); i++) {
27699- int f = std::get<0>(indexes[i]);
27700- int s = std::get<1>(indexes[i]);
27701- std::string slicedKey = styleString->substr(f, s-f);
27702- trimSpace(slicedKey);
27703- if (slicedKey == key) {
27704- int t = std::get<2>(indexes[i]);
27705- std::string value = styleString->substr(s+1, t-(s+1));
27706- trimSpace(value);
27707- return value;
27708- }
27709- }
27710- return "";
27711-}
27712-
27713-void StyleList::set(std::string key, std::string value) {
27714- if (!checkIndex()) {
27715- createIndex();
27716- }
27717-
27718- for (size_t i = 0; i < indexes.size(); i++) {
27719- int f = std::get<0>(indexes[i]);
27720- int s = std::get<1>(indexes[i]);
27721-
27722- std::string slicedKey = styleString->substr(f, s-f);
27723- trimSpace(slicedKey);
27724- if (slicedKey == key) {
27725- int t = std::get<2>(indexes[i]);
27726- styleString->replace(f,t-f," "+key+":"+value+";");
27727- // Return early to skip the appending value;
27728- return;
27729- }
27730- }
27731-
27732- // If the property wasn't replaced then add it
27733-
27734- if (!indexes.empty()) {
27735- char lastChar = styleString->at(std::get<2>(indexes[indexes.size()-1]));
27736-
27737- if (lastChar == ';') {
27738- styleString->append(" "+key+":"+value+";");
27739- } else {
27740- // If the user didn't terminate the last style
27741- // terminate it for them
27742- styleString->append("; "+key+":"+value+";");
27743- }
27744- }
27745-}
27746-
27747-void StyleList::remove(std::string key) {
27748- if (!checkIndex()) {
27749- createIndex();
27750- }
27751-
27752- for (size_t i = 0; i < indexes.size(); i++) {
27753- int f = std::get<0>(indexes[i]);
27754- int s = std::get<1>(indexes[i]);
27755- std::string slicedKey = styleString->substr(f, s-f);
27756- trimSpace(slicedKey);
27757- if (slicedKey == key) {
27758- int t = std::get<2>(indexes[i]);
27759- styleString->erase(f, t);
27760- return;
27761- }
27762- }
27763 }
27764
27765-// +---------------------------------------------------+
27766-// | (kuib7) Other Node functions |
27767-// +---------------------------------------------------+
27768+void GET_ATTRIBUTE(Node* n, char* key) {
27769
27770-Node* Node::createElement(std::string name) {
27771- Node newNode;
27772- newNode.setTagName(name);
27773- newNode.parent = this;
27774- children.push_back(newNode);
27775- return &children.back();
27776 }
27777-
27778-std::string Node::print(int indent) {
27779- std::string out = "";
27780- for (int i = 0; i < indent; ++i) {
27781- out += " ";
27782- }
27783-
27784- out += "<" + getTagName();
27785- for (const auto& attr_pair : getAttributes()) {
27786- if (attr_pair.first == "innerText" || attr_pair.first == "tagName") {
27787- continue;
27788- }
27789- out += " " + attr_pair.first;
27790- if (!attr_pair.second.empty()) {
27791- out += "=\"" + attr_pair.second + "\"";
27792- }
27793- }
27794- out += ">";
27795-
27796- std::string innerText = getAttribute("innerText");
27797-
27798- if (innerText != "") {
27799- out += "\n" + innerText;
27800- }
27801-
27802- out += "\n";
27803-
27804- for (auto& child : children) {
27805- out += child.print(indent + 1)+"\n";
27806- }
27807-
27808- for (int i = 0; i < indent; ++i) {
27809- out += " ";
27810- }
27811- out += "</" + getTagName() + ">\n";
27812-
27813- return out;
27814-}
27815-
27816+*/
27817 // +---------------------------------------------------+
27818 // | (mnjki) CSS Style Handling |
27819 // +---------------------------------------------------+
27820@@ -567,35 +63,38 @@ std::string Node::print(int indent) {
27821 // that should be ran once parselector and the results saved somewhere due to
27822 // the high cost to run the function
27823
27824-std::vector<std::vector<std::string>> parseSelectorParts(std::string_view selector) {
27825+ParsedSelector parseSelectorParts(const char* selector) {
27826 // need to account for selectors with parenthesis like: h1:(+ input:required)
27827 // need to convert all single quotes to double quotes
27828 // need to account for commas, will return
27829 // need to colapse all spaces to a single space
27830 // need to trim spaces
27831
27832- std::vector<std::vector<std::string>> parts;
27833- std::vector<std::string> buffer;
27834- std::string current;
27835+ ParsedSelector parts;
27836+ int parts_index = 0;
27837+
27838+ SelectorParts buffer;
27839+ int buffer_index = 0;
27840+
27841+ char current[MAX_STR_LEN] = {0};
27842+ int current_index = 0;
27843
27844 size_t start = 0;
27845- size_t end = selector.length();
27846+ size_t end = strlen(selector);
27847
27848 for (size_t i = start; i < end; i++) {
27849- if (!std::isspace(selector[i])) {
27850+ if (!isspace(selector[i])) {
27851 start = i;
27852 break;
27853 }
27854 }
27855 for (size_t i = end; i > start; i--) {
27856- if (!std::isspace(selector[i])) {
27857+ if (!isspace(selector[i])) {
27858 end = i;
27859 break;
27860 }
27861 }
27862
27863- current.reserve(end);
27864-
27865 size_t nesting = 0;
27866
27867 for (size_t i = start; i < end; i++) {
27868@@ -603,90 +102,111 @@ std::vector<std::vector<std::string>> parseSelectorParts(std::string_view select
27869 if (s == '\'') s = '"';
27870
27871 if ((s == '(' || s == '[' || s == '{')) {
27872- if (!current.empty() && nesting == 0) {
27873- buffer.push_back(current);
27874- current.clear();
27875+ if (current_index > 0 && nesting == 0) {
27876+ current[current_index++] = '\0';
27877+ strcpy(buffer.items[buffer_index++], current);
27878+ current_index = 0;
27879 }
27880
27881- current.push_back(s);
27882+ current[current_index++] = s;
27883 nesting++;
27884 continue;
27885 }
27886
27887 if ((s == ')' || s == ']' || s == '}')) {
27888 nesting--;
27889- current.push_back(s);
27890- if (!current.empty() && nesting == 0) {
27891-
27892- buffer.push_back(current);
27893- current.clear();
27894+ current[current_index++] = s;
27895+ if (current_index > 0 && nesting == 0) {
27896+ current[current_index++] = '\0';
27897+ strcpy(buffer.items[buffer_index++], current);
27898+ current_index = 0;
27899 }
27900 continue;
27901 } else {
27902-
27903 if (nesting > 0) {
27904- current.push_back(s);
27905+ current[current_index++] = s;
27906 continue;
27907 }
27908 }
27909
27910- if (std::isspace(s)) {
27911- if (i < end-1 && std::isspace(selector[i+1])) {
27912+ if (isspace(s)) {
27913+ if (i < end-1 && isspace(selector[i+1])) {
27914 continue;
27915 } else {
27916- if (!current.empty()) {
27917- buffer.push_back(current);
27918- buffer.push_back(" ");
27919- current.clear();
27920+ if (current_index > 0) {
27921+ current[current_index++] = '\0';
27922+ strcpy(buffer.items[buffer_index++], current);
27923+ buffer.items[buffer_index][0] = ' ';
27924+ buffer.items[buffer_index][1] = '\0';
27925+ buffer_index++;
27926+ current_index = 0;
27927 }
27928 }
27929 } else {
27930 if (s == ',') {
27931- if (!current.empty()) {
27932- buffer.push_back(current);
27933- current.clear();
27934+ if (current_index > 0) {
27935+ current[current_index++] = '\0';
27936+ strcpy(buffer.items[buffer_index++], current);
27937+ current_index = 0;
27938 }
27939- parts.push_back(buffer);
27940- buffer.clear();
27941+ buffer.size = buffer_index;
27942+ parts.items[parts_index++] = buffer;
27943+ buffer_index = 0;
27944 } else if (s == '~' || s == '+' || s == '|' || s == '>') {
27945- if (!current.empty()) {
27946- buffer.push_back(current);
27947- current.clear();
27948+ if (current_index > 0) {
27949+ current[current_index++] = '\0';
27950+ strcpy(buffer.items[buffer_index++], current);
27951+ current_index = 0;
27952 }
27953 // A few lines above we add a empty space when the next char is not a space
27954 // and the current is not empty. This is to create the decendant combinator
27955- // but if one of the symbols in the statement are folling then we need to replace
27956+ // but if one of the symbols in the statement are following then we need to replace
27957 // the empty space with the correct combinator
27958- if (buffer.size() == 0) {
27959- buffer.push_back("");
27960- }
27961- buffer.back() = s;
27962+
27963+ // Look back at the previous item in the buffer
27964+ if (buffer_index > 0 && isspace(buffer.items[buffer_index - 1][0])) {
27965+ // Overwrite the existing space with the combinator
27966+ buffer.items[buffer_index - 1][0] = s;
27967+ buffer.items[buffer_index - 1][1] = '\0';
27968+ } else {
27969+ // No space preceded this, just add the combinator as a new part
27970+ buffer.items[buffer_index][0] = s;
27971+ buffer.items[buffer_index][1] = '\0';
27972+ buffer_index++;
27973+ }
27974 } else if (s == ':' || s == '#' || s == '.') {
27975 if (i < end-1 && selector[i+1] == ':') continue;
27976- if (!current.empty()) {
27977- buffer.push_back(current);
27978+ if (current_index > 0) {
27979+ current[current_index++] = '\0';
27980+ strcpy(buffer.items[buffer_index++], current);
27981 }
27982- current = s;
27983+ current[0] = s;
27984+ current_index = 1;
27985
27986 } else {
27987- current.push_back(s);
27988+ current[current_index++] = s;
27989 }
27990 }
27991
27992
27993 }
27994
27995- if (!current.empty()) {
27996- buffer.push_back(current);
27997+ if (current_index > 0) {
27998+ current[current_index++] = '\0';
27999+ strcpy(buffer.items[buffer_index++], current);
28000 }
28001
28002- if (!buffer.empty()) {
28003- parts.push_back(buffer);
28004+ if (buffer_index > 0) {
28005+ buffer.size = buffer_index;
28006+ parts.items[parts_index++] = buffer;
28007 }
28008
28009+ parts.size = parts_index;
28010+
28011 return parts;
28012 }
28013
28014+/*
28015
28016 // +---------------------------------------------------+
28017 // | (luoiy) Node Selector Parsing |
28018@@ -735,77 +255,6 @@ std::vector<std::string> parseNodeParts(Node* node) {
28019 return parts;
28020 }
28021
28022-
28023-void Style::addChild(Style s) {
28024- size_t index = children.size();
28025-
28026- children.push_back(s);
28027-
28028- // Get the last selector group from the parsed selector parts
28029- // because that is the selector that applies to an element
28030- // and map them into basemap
28031- if (s.selector.size() > 0) {
28032- std::vector<std::string> targetParts = s.selector[s.selector.size()-1];
28033- for (auto p : targetParts) {
28034- if (basemap.find(p) != basemap.end()) {
28035- basemap[p].push_back(index);
28036- } else {
28037- std::vector<size_t> bm = {index};
28038- basemap[p] = bm;
28039- }
28040- }
28041- }
28042-}
28043-
28044-
28045-std::unordered_map<KeyType, UnitType> Style::getStyles(Node* node) {
28046- std::vector<std::string> node_parts = parseNodeParts(node);
28047- /*
28048- std::vector<size_t> canidates;
28049-
28050- // Now we have to start from the window.CSS.root, use the basemap to find styles
28051- // | test each selector, if a selector matches, go into its children and repeat
28052-
28053- for (std::string p : node_parts) {
28054- if (auto sty = sheet->basemap.find(p); sty != sheet->basemap.end()) {
28055- for (auto s : sty->second) {
28056- bool found = false;
28057- // This makes sure we aren't adding the same styles to the candidates list
28058- for (auto c : canidates) {
28059- if (c == s) {
28060- found = true;
28061- break;
28062- }
28063- }
28064- if (!found) {
28065- canidates.push_back(s);
28066- }
28067- }
28068- }
28069- }
28070-
28071- // Now we have the list of candidates next we will refined our selection
28072- // we need to pull the selectors from each candidate then run testSelector on it
28073-
28074- for (size_t c : canidates) {
28075- // need to check the type of sheet it is
28076- std::vector<std::vector<std::string>> selector = sheet->children[c].selector;
28077-
28078- // Run testSelector with the preparsed parts
28079- if (testSelector(node, selector)) {
28080- std::unordered_map<std::string, std::string> props = sheet->children[c].properties;
28081- for (auto p : props) {
28082- styles->insert(p);
28083- }
28084-
28085- // If the Sheet matches then we will repeat the same process with that sheet
28086- if (sheet->children[c].children.size() > 0) {
28087- getstyles(node, node_parts, &sheet->children[c], styles);
28088- }
28089- }
28090- }*/
28091-}
28092-
28093 // +------------------------------------------------------+
28094 // |(7tygl) Query matching |
28095 // +------------------------------------------------------+
28096@@ -816,7 +265,7 @@ bool testQuery(Node* node, std::vector<std::vector<std::string>> parts) {
28097 // Takes a fully parsed selector. If it is a at-rule even multiple,
28098 // the at-rule tag must but the first.
28099
28100-/*
28101+
28102 Just a ref
28103 bool result = false;
28104 for (auto& condition : conditions) {
28105@@ -825,7 +274,7 @@ for (auto& condition : conditions) {
28106
28107
28108 also not can only be at the start
28109-*/
28110+
28111
28112 Window* w = node->window;
28113
28114@@ -847,11 +296,11 @@ also not can only be at the start
28115 return true;
28116 }
28117
28118-/*
28119+
28120 at-rules consist of "query's" the are tre or false given the stat of the window.
28121 executeQuery runs the non-logic (and, or etc..) and returns the value of the
28122 executed query.
28123-*/
28124+
28125
28126 std::unordered_map<std::string, Media> MediaLookup {
28127 {"all", Media::All},
28128@@ -872,7 +321,7 @@ std::unordered_map<std::string, Media> MediaLookup {
28129 {"fast", Media::Fast},
28130 {"slow", Media::Slow},
28131 };
28132-/*
28133+
28134 // Media queries like @media (hover: hover) are written like @media (hover)
28135 bool executeQuery(Window* w, std::string p) {
28136 Context c;
28137@@ -900,7 +349,7 @@ bool executeQuery(Window* w, std::string p) {
28138 }
28139 return matches;
28140 }
28141-*/
28142+
28143
28144 Range getNextUnit(const std::vector<Unit>& units, size_t& offset, size_t end) {
28145 if (offset >= end) return {0, 0}; // Done
28146@@ -2319,4 +1768,4 @@ bool testSelector(Node* node, std::vector<std::vector<std::string>> selector) {
28147
28148 return matched;
28149 }
28150-
28151+*/