|
@@ -31,7 +31,11 @@
|
31
|
31
|
#include <cmath>
|
32
|
32
|
#include <cstddef>
|
33
|
33
|
|
34
|
|
-#define lest_VERSION "1.33.1"
|
|
34
|
+#define lest_MAJOR 1
|
|
35
|
+#define lest_MINOR 35
|
|
36
|
+#define lest_PATCH 1
|
|
37
|
+
|
|
38
|
+#define lest_VERSION lest_STRINGIFY(lest_MAJOR) "." lest_STRINGIFY(lest_MINOR) "." lest_STRINGIFY(lest_PATCH)
|
35
|
39
|
|
36
|
40
|
#ifndef lest_FEATURE_AUTO_REGISTER
|
37
|
41
|
# define lest_FEATURE_AUTO_REGISTER 0
|
|
@@ -49,50 +53,55 @@
|
49
|
53
|
# define lest_FEATURE_REGEX_SEARCH 0
|
50
|
54
|
#endif
|
51
|
55
|
|
52
|
|
-#ifndef lest_FEATURE_TIME_PRECISION
|
53
|
|
-#define lest_FEATURE_TIME_PRECISION 0
|
|
56
|
+#ifndef lest_FEATURE_TIME_PRECISION
|
|
57
|
+# define lest_FEATURE_TIME_PRECISION 0
|
54
|
58
|
#endif
|
55
|
59
|
|
56
|
|
-#ifndef lest_FEATURE_WSTRING
|
57
|
|
-#define lest_FEATURE_WSTRING 1
|
|
60
|
+#ifndef lest_FEATURE_WSTRING
|
|
61
|
+# define lest_FEATURE_WSTRING 1
|
58
|
62
|
#endif
|
59
|
63
|
|
60
|
|
-#ifdef lest_FEATURE_RTTI
|
61
|
|
-# define lest__cpp_rtti lest_FEATURE_RTTI
|
|
64
|
+#ifdef lest_FEATURE_RTTI
|
|
65
|
+# define lest__cpp_rtti lest_FEATURE_RTTI
|
62
|
66
|
#elif defined(__cpp_rtti)
|
63
|
|
-# define lest__cpp_rtti __cpp_rtti
|
|
67
|
+# define lest__cpp_rtti __cpp_rtti
|
64
|
68
|
#elif defined(__GXX_RTTI) || defined (_CPPRTTI)
|
65
|
|
-# define lest__cpp_rtti 1
|
|
69
|
+# define lest__cpp_rtti 1
|
66
|
70
|
#else
|
67
|
|
-# define lest__cpp_rtti 0
|
|
71
|
+# define lest__cpp_rtti 0
|
68
|
72
|
#endif
|
69
|
73
|
|
70
|
74
|
#if lest_FEATURE_REGEX_SEARCH
|
71
|
75
|
# include <regex>
|
72
|
76
|
#endif
|
73
|
77
|
|
|
78
|
+// Stringify:
|
|
79
|
+
|
|
80
|
+#define lest_STRINGIFY( x ) lest_STRINGIFY_( x )
|
|
81
|
+#define lest_STRINGIFY_( x ) #x
|
|
82
|
+
|
74
|
83
|
// Compiler warning suppression:
|
75
|
84
|
|
76
|
|
-#ifdef __clang__
|
|
85
|
+#if defined (__clang__)
|
77
|
86
|
# pragma clang diagnostic ignored "-Waggregate-return"
|
78
|
87
|
# pragma clang diagnostic ignored "-Woverloaded-shift-op-parentheses"
|
79
|
88
|
# pragma clang diagnostic push
|
80
|
89
|
# pragma clang diagnostic ignored "-Wunused-comparison"
|
81
|
|
-#elif defined __GNUC__
|
|
90
|
+#elif defined (__GNUC__)
|
82
|
91
|
# pragma GCC diagnostic ignored "-Waggregate-return"
|
83
|
92
|
# pragma GCC diagnostic push
|
84
|
93
|
#endif
|
85
|
94
|
|
86
|
95
|
// Suppress shadow and unused-value warning for sections:
|
87
|
96
|
|
88
|
|
-#if defined __clang__
|
|
97
|
+#if defined (__clang__)
|
89
|
98
|
# define lest_SUPPRESS_WSHADOW _Pragma( "clang diagnostic push" ) \
|
90
|
99
|
_Pragma( "clang diagnostic ignored \"-Wshadow\"" )
|
91
|
100
|
# define lest_SUPPRESS_WUNUSED _Pragma( "clang diagnostic push" ) \
|
92
|
101
|
_Pragma( "clang diagnostic ignored \"-Wunused-value\"" )
|
93
|
102
|
# define lest_RESTORE_WARNINGS _Pragma( "clang diagnostic pop" )
|
94
|
103
|
|
95
|
|
-#elif defined __GNUC__
|
|
104
|
+#elif defined (__GNUC__)
|
96
|
105
|
# define lest_SUPPRESS_WSHADOW _Pragma( "GCC diagnostic push" ) \
|
97
|
106
|
_Pragma( "GCC diagnostic ignored \"-Wshadow\"" )
|
98
|
107
|
# define lest_SUPPRESS_WUNUSED _Pragma( "GCC diagnostic push" ) \
|
|
@@ -104,12 +113,22 @@
|
104
|
113
|
# define lest_RESTORE_WARNINGS /*empty*/
|
105
|
114
|
#endif
|
106
|
115
|
|
107
|
|
-#ifdef _MSVC_LANG
|
108
|
|
-# define lest_CPP17_OR_GREATER_MS ( _MSVC_LANG >= 201703L )
|
109
|
|
-#else
|
110
|
|
-# define lest_CPP17_OR_GREATER_MS 0
|
|
116
|
+// C++ language version detection (C++20 is speculative):
|
|
117
|
+// Note: VC14.0/1900 (VS2015) lacks too much from C++14.
|
|
118
|
+
|
|
119
|
+#ifndef lest_CPLUSPLUS
|
|
120
|
+# if defined(_MSVC_LANG ) && !defined(__clang__)
|
|
121
|
+# define lest_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG )
|
|
122
|
+# else
|
|
123
|
+# define lest_CPLUSPLUS __cplusplus
|
|
124
|
+# endif
|
111
|
125
|
#endif
|
112
|
|
-# define lest_CPP17_OR_GREATER ( __cplusplus >= 201703L || lest_CPP17_OR_GREATER_MS )
|
|
126
|
+
|
|
127
|
+#define lest_CPP98_OR_GREATER ( lest_CPLUSPLUS >= 199711L )
|
|
128
|
+#define lest_CPP11_OR_GREATER ( lest_CPLUSPLUS >= 201103L )
|
|
129
|
+#define lest_CPP14_OR_GREATER ( lest_CPLUSPLUS >= 201402L )
|
|
130
|
+#define lest_CPP17_OR_GREATER ( lest_CPLUSPLUS >= 201703L )
|
|
131
|
+#define lest_CPP20_OR_GREATER ( lest_CPLUSPLUS >= 202000L )
|
113
|
132
|
|
114
|
133
|
#if ! defined( lest_NO_SHORT_MACRO_NAMES ) && ! defined( lest_NO_SHORT_ASSERTION_NAMES )
|
115
|
134
|
# define MODULE lest_MODULE
|
|
@@ -186,7 +205,7 @@
|
186
|
205
|
if ( lest::result score = lest_DECOMPOSE( expr ) ) \
|
187
|
206
|
throw lest::failure{ lest_LOCATION, #expr, score.decomposition }; \
|
188
|
207
|
else if ( lest_env.pass() ) \
|
189
|
|
- lest::report( lest_env.os, lest::passing{ lest_LOCATION, #expr, score.decomposition }, lest_env.context() ); \
|
|
208
|
+ lest::report( lest_env.os, lest::passing{ lest_LOCATION, #expr, score.decomposition, lest_env.zen() }, lest_env.context() ); \
|
190
|
209
|
} \
|
191
|
210
|
catch(...) \
|
192
|
211
|
{ \
|
|
@@ -201,7 +220,7 @@
|
201
|
220
|
if ( lest::result score = lest_DECOMPOSE( expr ) ) \
|
202
|
221
|
{ \
|
203
|
222
|
if ( lest_env.pass() ) \
|
204
|
|
- lest::report( lest_env.os, lest::passing{ lest_LOCATION, lest::not_expr( #expr ), lest::not_expr( score.decomposition ) }, lest_env.context() ); \
|
|
223
|
+ lest::report( lest_env.os, lest::passing{ lest_LOCATION, lest::not_expr( #expr ), lest::not_expr( score.decomposition ), lest_env.zen() }, lest_env.context() ); \
|
205
|
224
|
} \
|
206
|
225
|
else \
|
207
|
226
|
throw lest::failure{ lest_LOCATION, lest::not_expr( #expr ), lest::not_expr( score.decomposition ) }; \
|
|
@@ -381,8 +400,8 @@ struct success : message
|
381
|
400
|
|
382
|
401
|
struct passing : success
|
383
|
402
|
{
|
384
|
|
- passing( location where_, text expr_, text decomposition_ )
|
385
|
|
- : success( "passed", where_, expr_ + " for " + decomposition_) {}
|
|
403
|
+ passing( location where_, text expr_, text decomposition_, bool zen )
|
|
404
|
+ : success( "passed", where_, expr_ + (zen ? "":" for " + decomposition_) ) {}
|
386
|
405
|
};
|
387
|
406
|
|
388
|
407
|
struct got_none : success
|
|
@@ -524,14 +543,45 @@ inline char const * sfx( char const * txt ) { return txt; }
|
524
|
543
|
inline char const * sfx( char const * ) { return ""; }
|
525
|
544
|
#endif
|
526
|
545
|
|
527
|
|
-inline std::string to_string( std::nullptr_t ) { return "nullptr"; }
|
528
|
|
-inline std::string to_string( std::string const & txt ) { return "\"" + txt + "\"" ; }
|
|
546
|
+inline std::string transformed( char chr )
|
|
547
|
+{
|
|
548
|
+ struct Tr { char chr; char const * str; } table[] =
|
|
549
|
+ {
|
|
550
|
+ {'\\', "\\\\" },
|
|
551
|
+ {'\r', "\\r" }, {'\f', "\\f" },
|
|
552
|
+ {'\n', "\\n" }, {'\t', "\\t" },
|
|
553
|
+ };
|
|
554
|
+
|
|
555
|
+ for ( auto tr : table )
|
|
556
|
+ {
|
|
557
|
+ if ( chr == tr.chr )
|
|
558
|
+ return tr.str;
|
|
559
|
+ }
|
|
560
|
+
|
|
561
|
+ auto unprintable = [](char c){ return 0 <= c && c < ' '; };
|
|
562
|
+
|
|
563
|
+ auto to_hex_string = [](char c)
|
|
564
|
+ {
|
|
565
|
+ std::ostringstream os;
|
|
566
|
+ os << "\\x" << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>( static_cast<unsigned char>(c) );
|
|
567
|
+ return os.str();
|
|
568
|
+ };
|
|
569
|
+
|
|
570
|
+ return unprintable( chr ) ? to_hex_string( chr ) : std::string( 1, chr );
|
|
571
|
+}
|
|
572
|
+
|
|
573
|
+inline std::string make_tran_string( std::string const & txt ) { std::ostringstream os; for(auto c:txt) os << transformed(c); return os.str(); }
|
|
574
|
+inline std::string make_strg_string( std::string const & txt ) { return "\"" + make_tran_string( txt ) + "\"" ; }
|
|
575
|
+inline std::string make_char_string( char chr ) { return "\'" + make_tran_string( std::string( 1, chr ) ) + "\'" ; }
|
|
576
|
+
|
|
577
|
+inline std::string to_string( std::nullptr_t ) { return "nullptr"; }
|
|
578
|
+inline std::string to_string( std::string const & txt ) { return make_strg_string( txt ); }
|
529
|
579
|
#if lest_FEATURE_WSTRING
|
530
|
580
|
inline std::string to_string( std::wstring const & txt ) ;
|
531
|
581
|
#endif
|
532
|
582
|
|
533
|
|
-inline std::string to_string( char const * const txt ) { return txt ? to_string( std::string ( txt ) ) : "{null string}"; }
|
534
|
|
-inline std::string to_string( char * const txt ) { return txt ? to_string( std::string ( txt ) ) : "{null string}"; }
|
|
583
|
+inline std::string to_string( char const * const txt ) { return txt ? make_strg_string( txt ) : "{null string}"; }
|
|
584
|
+inline std::string to_string( char * const txt ) { return txt ? make_strg_string( txt ) : "{null string}"; }
|
535
|
585
|
#if lest_FEATURE_WSTRING
|
536
|
586
|
inline std::string to_string( wchar_t const * const txt ) { return txt ? to_string( std::wstring( txt ) ) : "{null string}"; }
|
537
|
587
|
inline std::string to_string( wchar_t * const txt ) { return txt ? to_string( std::wstring( txt ) ) : "{null string}"; }
|
|
@@ -550,29 +600,9 @@ inline std::string to_string( unsigned long long value ) { return make_value_
|
550
|
600
|
inline std::string to_string( double value ) { return make_value_string( value ) ; }
|
551
|
601
|
inline std::string to_string( float value ) { return make_value_string( value ) + sfx("f" ); }
|
552
|
602
|
|
553
|
|
-inline std::string to_string( signed char chr ) { return to_string( static_cast<char>( chr ) ); }
|
554
|
|
-inline std::string to_string( unsigned char chr ) { return to_string( static_cast<char>( chr ) ); }
|
555
|
|
-
|
556
|
|
-inline std::string to_string( char chr )
|
557
|
|
-{
|
558
|
|
- struct Tr { char chr; char const * str; } table[] =
|
559
|
|
- {
|
560
|
|
- {'\r', "'\\r'" }, {'\f', "'\\f'" },
|
561
|
|
- {'\n', "'\\n'" }, {'\t', "'\\t'" },
|
562
|
|
- };
|
563
|
|
-
|
564
|
|
- for ( auto tr : table )
|
565
|
|
- {
|
566
|
|
- if ( chr == tr.chr )
|
567
|
|
- return tr.str;
|
568
|
|
- }
|
569
|
|
-
|
570
|
|
- auto unprintable = [](char c){ return 0 <= c && c < ' '; };
|
571
|
|
-
|
572
|
|
- return unprintable( chr )
|
573
|
|
- ? to_string( static_cast<unsigned int>( chr ) )
|
574
|
|
- : "\'" + std::string( 1, chr ) + "\'" ;
|
575
|
|
-}
|
|
603
|
+inline std::string to_string( signed char chr ) { return make_char_string( static_cast<char>( chr ) ); }
|
|
604
|
+inline std::string to_string( unsigned char chr ) { return make_char_string( static_cast<char>( chr ) ); }
|
|
605
|
+inline std::string to_string( char chr ) { return make_char_string( chr ); }
|
576
|
606
|
|
577
|
607
|
template< typename T >
|
578
|
608
|
struct is_streamable
|
|
@@ -968,7 +998,7 @@ inline bool select( text name, texts include )
|
968
|
998
|
|
969
|
999
|
inline int indefinite( int repeat ) { return repeat == -1; }
|
970
|
1000
|
|
971
|
|
-using seed_t = unsigned long;
|
|
1001
|
+using seed_t = std::mt19937::result_type;
|
972
|
1002
|
|
973
|
1003
|
struct options
|
974
|
1004
|
{
|
|
@@ -979,6 +1009,7 @@ struct options
|
979
|
1009
|
bool tags = false;
|
980
|
1010
|
bool time = false;
|
981
|
1011
|
bool pass = false;
|
|
1012
|
+ bool zen = false;
|
982
|
1013
|
bool lexical = false;
|
983
|
1014
|
bool random = false;
|
984
|
1015
|
bool verbose = false;
|
|
@@ -999,12 +1030,14 @@ struct env
|
999
|
1030
|
|
1000
|
1031
|
env & operator()( text test )
|
1001
|
1032
|
{
|
1002
|
|
- testing = test; return *this;
|
|
1033
|
+ clear(); testing = test; return *this;
|
1003
|
1034
|
}
|
1004
|
1035
|
|
1005
|
1036
|
bool abort() { return opt.abort; }
|
1006
|
1037
|
bool pass() { return opt.pass; }
|
|
1038
|
+ bool zen() { return opt.zen; }
|
1007
|
1039
|
|
|
1040
|
+ void clear() { ctx.clear(); }
|
1008
|
1041
|
void pop() { ctx.pop_back(); }
|
1009
|
1042
|
void push( text proposition ) { ctx.emplace_back( proposition ); }
|
1010
|
1043
|
|
|
@@ -1311,6 +1344,7 @@ inline auto split_arguments( texts args ) -> std::tuple<options, texts>
|
1311
|
1344
|
else if ( opt == "-l" || "--list-tests" == opt ) { option.list = true; continue; }
|
1312
|
1345
|
else if ( opt == "-t" || "--time" == opt ) { option.time = true; continue; }
|
1313
|
1346
|
else if ( opt == "-p" || "--pass" == opt ) { option.pass = true; continue; }
|
|
1347
|
+ else if ( opt == "-z" || "--pass-zen" == opt ) { option.zen = true; continue; }
|
1314
|
1348
|
else if ( opt == "-v" || "--verbose" == opt ) { option.verbose = true; continue; }
|
1315
|
1349
|
else if ( "--version" == opt ) { option.version = true; continue; }
|
1316
|
1350
|
else if ( opt == "--order" && "declared" == val ) { /* by definition */ ; continue; }
|
|
@@ -1322,6 +1356,8 @@ inline auto split_arguments( texts args ) -> std::tuple<options, texts>
|
1322
|
1356
|
}
|
1323
|
1357
|
in.push_back( arg );
|
1324
|
1358
|
}
|
|
1359
|
+ option.pass = option.pass || option.zen;
|
|
1360
|
+
|
1325
|
1361
|
return std::make_tuple( option, in );
|
1326
|
1362
|
}
|
1327
|
1363
|
|
|
@@ -1337,6 +1373,7 @@ inline int usage( std::ostream & os )
|
1337
|
1373
|
" -g, --list-tags list tags of selected tests\n"
|
1338
|
1374
|
" -l, --list-tests list selected tests\n"
|
1339
|
1375
|
" -p, --pass also report passing tests\n"
|
|
1376
|
+ " -z, --pass-zen ... without expansion\n"
|
1340
|
1377
|
" -t, --time list duration of selected tests\n"
|
1341
|
1378
|
" -v, --verbose also report passing or failing sections\n"
|
1342
|
1379
|
" --order=declared use source code test order (default)\n"
|
|
@@ -1437,9 +1474,9 @@ int run( test const (&specification)[N], int argc, char * argv[], std::ostream &
|
1437
|
1474
|
|
1438
|
1475
|
} // namespace lest
|
1439
|
1476
|
|
1440
|
|
-#ifdef __clang__
|
|
1477
|
+#if defined (__clang__)
|
1441
|
1478
|
# pragma clang diagnostic pop
|
1442
|
|
-#elif defined __GNUC__
|
|
1479
|
+#elif defined (__GNUC__)
|
1443
|
1480
|
# pragma GCC diagnostic pop
|
1444
|
1481
|
#endif
|
1445
|
1482
|
|