lest.h 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484
  1. // Copyright 2013-2018 by Martin Moene
  2. //
  3. // lest is based on ideas by Kevlin Henney, see video at
  4. // http://skillsmatter.com/podcast/agile-testing/kevlin-henney-rethinking-unit-testing-in-c-plus-plus
  5. //
  6. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  7. // file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  8. #ifndef LEST_LEST_HPP_INCLUDED
  9. #define LEST_LEST_HPP_INCLUDED
  10. #include <algorithm>
  11. #include <chrono>
  12. #include <functional>
  13. #include <iomanip>
  14. #include <iostream>
  15. #include <iterator>
  16. #include <limits>
  17. #include <random>
  18. #include <sstream>
  19. #include <stdexcept>
  20. #include <string>
  21. #include <set>
  22. #include <tuple>
  23. #include <typeinfo>
  24. #include <type_traits>
  25. #include <utility>
  26. #include <vector>
  27. #include <cctype>
  28. #include <cmath>
  29. #include <cstddef>
  30. #define lest_MAJOR 1
  31. #define lest_MINOR 35
  32. #define lest_PATCH 1
  33. #define lest_VERSION lest_STRINGIFY(lest_MAJOR) "." lest_STRINGIFY(lest_MINOR) "." lest_STRINGIFY(lest_PATCH)
  34. #ifndef lest_FEATURE_AUTO_REGISTER
  35. # define lest_FEATURE_AUTO_REGISTER 0
  36. #endif
  37. #ifndef lest_FEATURE_COLOURISE
  38. # define lest_FEATURE_COLOURISE 0
  39. #endif
  40. #ifndef lest_FEATURE_LITERAL_SUFFIX
  41. # define lest_FEATURE_LITERAL_SUFFIX 0
  42. #endif
  43. #ifndef lest_FEATURE_REGEX_SEARCH
  44. # define lest_FEATURE_REGEX_SEARCH 0
  45. #endif
  46. #ifndef lest_FEATURE_TIME_PRECISION
  47. # define lest_FEATURE_TIME_PRECISION 0
  48. #endif
  49. #ifndef lest_FEATURE_WSTRING
  50. # define lest_FEATURE_WSTRING 1
  51. #endif
  52. #ifdef lest_FEATURE_RTTI
  53. # define lest__cpp_rtti lest_FEATURE_RTTI
  54. #elif defined(__cpp_rtti)
  55. # define lest__cpp_rtti __cpp_rtti
  56. #elif defined(__GXX_RTTI) || defined (_CPPRTTI)
  57. # define lest__cpp_rtti 1
  58. #else
  59. # define lest__cpp_rtti 0
  60. #endif
  61. #if lest_FEATURE_REGEX_SEARCH
  62. # include <regex>
  63. #endif
  64. // Stringify:
  65. #define lest_STRINGIFY( x ) lest_STRINGIFY_( x )
  66. #define lest_STRINGIFY_( x ) #x
  67. // Compiler warning suppression:
  68. #if defined (__clang__)
  69. # pragma clang diagnostic ignored "-Waggregate-return"
  70. # pragma clang diagnostic ignored "-Woverloaded-shift-op-parentheses"
  71. # pragma clang diagnostic push
  72. # pragma clang diagnostic ignored "-Wunused-comparison"
  73. #elif defined (__GNUC__)
  74. # pragma GCC diagnostic ignored "-Waggregate-return"
  75. # pragma GCC diagnostic push
  76. #endif
  77. // Suppress shadow and unused-value warning for sections:
  78. #if defined (__clang__)
  79. # define lest_SUPPRESS_WSHADOW _Pragma( "clang diagnostic push" ) \
  80. _Pragma( "clang diagnostic ignored \"-Wshadow\"" )
  81. # define lest_SUPPRESS_WUNUSED _Pragma( "clang diagnostic push" ) \
  82. _Pragma( "clang diagnostic ignored \"-Wunused-value\"" )
  83. # define lest_RESTORE_WARNINGS _Pragma( "clang diagnostic pop" )
  84. #elif defined (__GNUC__)
  85. # define lest_SUPPRESS_WSHADOW _Pragma( "GCC diagnostic push" ) \
  86. _Pragma( "GCC diagnostic ignored \"-Wshadow\"" )
  87. # define lest_SUPPRESS_WUNUSED _Pragma( "GCC diagnostic push" ) \
  88. _Pragma( "GCC diagnostic ignored \"-Wunused-value\"" )
  89. # define lest_RESTORE_WARNINGS _Pragma( "GCC diagnostic pop" )
  90. #else
  91. # define lest_SUPPRESS_WSHADOW /*empty*/
  92. # define lest_SUPPRESS_WUNUSED /*empty*/
  93. # define lest_RESTORE_WARNINGS /*empty*/
  94. #endif
  95. // C++ language version detection (C++20 is speculative):
  96. // Note: VC14.0/1900 (VS2015) lacks too much from C++14.
  97. #ifndef lest_CPLUSPLUS
  98. # if defined(_MSVC_LANG ) && !defined(__clang__)
  99. # define lest_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG )
  100. # else
  101. # define lest_CPLUSPLUS __cplusplus
  102. # endif
  103. #endif
  104. #define lest_CPP98_OR_GREATER ( lest_CPLUSPLUS >= 199711L )
  105. #define lest_CPP11_OR_GREATER ( lest_CPLUSPLUS >= 201103L )
  106. #define lest_CPP14_OR_GREATER ( lest_CPLUSPLUS >= 201402L )
  107. #define lest_CPP17_OR_GREATER ( lest_CPLUSPLUS >= 201703L )
  108. #define lest_CPP20_OR_GREATER ( lest_CPLUSPLUS >= 202000L )
  109. #if ! defined( lest_NO_SHORT_MACRO_NAMES ) && ! defined( lest_NO_SHORT_ASSERTION_NAMES )
  110. # define MODULE lest_MODULE
  111. # if ! lest_FEATURE_AUTO_REGISTER
  112. # define CASE lest_CASE
  113. # define CASE_ON lest_CASE_ON
  114. # define SCENARIO lest_SCENARIO
  115. # endif
  116. # define SETUP lest_SETUP
  117. # define SECTION lest_SECTION
  118. # define EXPECT lest_EXPECT
  119. # define EXPECT_NOT lest_EXPECT_NOT
  120. # define EXPECT_NO_THROW lest_EXPECT_NO_THROW
  121. # define EXPECT_THROWS lest_EXPECT_THROWS
  122. # define EXPECT_THROWS_AS lest_EXPECT_THROWS_AS
  123. # define GIVEN lest_GIVEN
  124. # define WHEN lest_WHEN
  125. # define THEN lest_THEN
  126. # define AND_WHEN lest_AND_WHEN
  127. # define AND_THEN lest_AND_THEN
  128. #endif
  129. #if lest_FEATURE_AUTO_REGISTER
  130. #define lest_SCENARIO( specification, sketch ) lest_CASE( specification, lest::text("Scenario: ") + sketch )
  131. #else
  132. #define lest_SCENARIO( sketch ) lest_CASE( lest::text("Scenario: ") + sketch )
  133. #endif
  134. #define lest_GIVEN( context ) lest_SETUP( lest::text(" Given: ") + context )
  135. #define lest_WHEN( story ) lest_SECTION( lest::text(" When: ") + story )
  136. #define lest_THEN( story ) lest_SECTION( lest::text(" Then: ") + story )
  137. #define lest_AND_WHEN( story ) lest_SECTION( lest::text("And then: ") + story )
  138. #define lest_AND_THEN( story ) lest_SECTION( lest::text("And then: ") + story )
  139. #if lest_FEATURE_AUTO_REGISTER
  140. # define lest_CASE( specification, proposition ) \
  141. static void lest_FUNCTION( lest::env & ); \
  142. namespace { lest::add_test lest_REGISTRAR( specification, lest::test( proposition, lest_FUNCTION ) ); } \
  143. static void lest_FUNCTION( lest::env & lest_env )
  144. #else // lest_FEATURE_AUTO_REGISTER
  145. # define lest_CASE( proposition ) \
  146. proposition, []( lest::env & lest_env )
  147. # define lest_CASE_ON( proposition, ... ) \
  148. proposition, [__VA_ARGS__]( lest::env & lest_env )
  149. # define lest_MODULE( specification, module ) \
  150. namespace { lest::add_module _( specification, module ); }
  151. #endif //lest_FEATURE_AUTO_REGISTER
  152. #define lest_SETUP( context ) \
  153. for ( int lest__section = 0, lest__count = 1; lest__section < lest__count; lest__count -= 0==lest__section++ ) \
  154. for ( lest::ctx lest__ctx_setup( lest_env, context ); lest__ctx_setup; )
  155. #define lest_SECTION( proposition ) \
  156. lest_SUPPRESS_WSHADOW \
  157. static int lest_UNIQUE( id ) = 0; \
  158. if ( lest::guard( lest_UNIQUE( id ), lest__section, lest__count ) ) \
  159. for ( int lest__section = 0, lest__count = 1; lest__section < lest__count; lest__count -= 0==lest__section++ ) \
  160. for ( lest::ctx lest__ctx_section( lest_env, proposition ); lest__ctx_section; ) \
  161. lest_RESTORE_WARNINGS
  162. #define lest_EXPECT( expr ) \
  163. do { \
  164. try \
  165. { \
  166. if ( lest::result score = lest_DECOMPOSE( expr ) ) \
  167. throw lest::failure{ lest_LOCATION, #expr, score.decomposition }; \
  168. else if ( lest_env.pass() ) \
  169. lest::report( lest_env.os, lest::passing{ lest_LOCATION, #expr, score.decomposition, lest_env.zen() }, lest_env.context() ); \
  170. } \
  171. catch(...) \
  172. { \
  173. lest::inform( lest_LOCATION, #expr ); \
  174. } \
  175. } while ( lest::is_false() )
  176. #define lest_EXPECT_NOT( expr ) \
  177. do { \
  178. try \
  179. { \
  180. if ( lest::result score = lest_DECOMPOSE( expr ) ) \
  181. { \
  182. if ( lest_env.pass() ) \
  183. lest::report( lest_env.os, lest::passing{ lest_LOCATION, lest::not_expr( #expr ), lest::not_expr( score.decomposition ), lest_env.zen() }, lest_env.context() ); \
  184. } \
  185. else \
  186. throw lest::failure{ lest_LOCATION, lest::not_expr( #expr ), lest::not_expr( score.decomposition ) }; \
  187. } \
  188. catch(...) \
  189. { \
  190. lest::inform( lest_LOCATION, lest::not_expr( #expr ) ); \
  191. } \
  192. } while ( lest::is_false() )
  193. #define lest_EXPECT_NO_THROW( expr ) \
  194. do \
  195. { \
  196. try \
  197. { \
  198. lest_SUPPRESS_WUNUSED \
  199. expr; \
  200. lest_RESTORE_WARNINGS \
  201. } \
  202. catch (...) \
  203. { \
  204. lest::inform( lest_LOCATION, #expr ); \
  205. } \
  206. if ( lest_env.pass() ) \
  207. lest::report( lest_env.os, lest::got_none( lest_LOCATION, #expr ), lest_env.context() ); \
  208. } while ( lest::is_false() )
  209. #define lest_EXPECT_THROWS( expr ) \
  210. do \
  211. { \
  212. try \
  213. { \
  214. lest_SUPPRESS_WUNUSED \
  215. expr; \
  216. lest_RESTORE_WARNINGS \
  217. } \
  218. catch (...) \
  219. { \
  220. if ( lest_env.pass() ) \
  221. lest::report( lest_env.os, lest::got{ lest_LOCATION, #expr }, lest_env.context() ); \
  222. break; \
  223. } \
  224. throw lest::expected{ lest_LOCATION, #expr }; \
  225. } \
  226. while ( lest::is_false() )
  227. #define lest_EXPECT_THROWS_AS( expr, excpt ) \
  228. do \
  229. { \
  230. try \
  231. { \
  232. lest_SUPPRESS_WUNUSED \
  233. expr; \
  234. lest_RESTORE_WARNINGS \
  235. } \
  236. catch ( excpt & ) \
  237. { \
  238. if ( lest_env.pass() ) \
  239. lest::report( lest_env.os, lest::got{ lest_LOCATION, #expr, lest::of_type( #excpt ) }, lest_env.context() ); \
  240. break; \
  241. } \
  242. catch (...) {} \
  243. throw lest::expected{ lest_LOCATION, #expr, lest::of_type( #excpt ) }; \
  244. } \
  245. while ( lest::is_false() )
  246. #define lest_UNIQUE( name ) lest_UNIQUE2( name, __LINE__ )
  247. #define lest_UNIQUE2( name, line ) lest_UNIQUE3( name, line )
  248. #define lest_UNIQUE3( name, line ) name ## line
  249. #define lest_DECOMPOSE( expr ) ( lest::expression_decomposer() << expr )
  250. #define lest_FUNCTION lest_UNIQUE(__lest_function__ )
  251. #define lest_REGISTRAR lest_UNIQUE(__lest_registrar__ )
  252. #define lest_LOCATION lest::location{__FILE__, __LINE__}
  253. namespace lest {
  254. const int exit_max_value = 255;
  255. using text = std::string;
  256. using texts = std::vector<text>;
  257. struct env;
  258. struct test
  259. {
  260. text name;
  261. std::function<void( env & )> behaviour;
  262. #if lest_FEATURE_AUTO_REGISTER
  263. test( text name_, std::function<void( env & )> behaviour_ )
  264. : name( name_), behaviour( behaviour_) {}
  265. #endif
  266. };
  267. using tests = std::vector<test>;
  268. #if lest_FEATURE_AUTO_REGISTER
  269. struct add_test
  270. {
  271. add_test( tests & specification, test const & test_case )
  272. {
  273. specification.push_back( test_case );
  274. }
  275. };
  276. #else
  277. struct add_module
  278. {
  279. template< std::size_t N >
  280. add_module( tests & specification, test const (&module)[N] )
  281. {
  282. specification.insert( specification.end(), std::begin( module ), std::end( module ) );
  283. }
  284. };
  285. #endif
  286. struct result
  287. {
  288. const bool passed;
  289. const text decomposition;
  290. template< typename T >
  291. result( T const & passed_, text decomposition_)
  292. : passed( !!passed_), decomposition( decomposition_) {}
  293. explicit operator bool() { return ! passed; }
  294. };
  295. struct location
  296. {
  297. const text file;
  298. const int line;
  299. location( text file_, int line_)
  300. : file( file_), line( line_) {}
  301. };
  302. struct comment
  303. {
  304. const text info;
  305. comment( text info_) : info( info_) {}
  306. explicit operator bool() { return ! info.empty(); }
  307. };
  308. struct message : std::runtime_error
  309. {
  310. const text kind;
  311. const location where;
  312. const comment note;
  313. ~message() throw() {} // GCC 4.6
  314. message( text kind_, location where_, text expr_, text note_ = "" )
  315. : std::runtime_error( expr_), kind( kind_), where( where_), note( note_) {}
  316. };
  317. struct failure : message
  318. {
  319. failure( location where_, text expr_, text decomposition_)
  320. : message{ "failed", where_, expr_ + " for " + decomposition_ } {}
  321. };
  322. struct success : message
  323. {
  324. // using message::message; // VC is lagging here
  325. success( text kind_, location where_, text expr_, text note_ = "" )
  326. : message( kind_, where_, expr_, note_ ) {}
  327. };
  328. struct passing : success
  329. {
  330. passing( location where_, text expr_, text decomposition_, bool zen )
  331. : success( "passed", where_, expr_ + (zen ? "":" for " + decomposition_) ) {}
  332. };
  333. struct got_none : success
  334. {
  335. got_none( location where_, text expr_ )
  336. : success( "passed: got no exception", where_, expr_ ) {}
  337. };
  338. struct got : success
  339. {
  340. got( location where_, text expr_)
  341. : success( "passed: got exception", where_, expr_) {}
  342. got( location where_, text expr_, text excpt_)
  343. : success( "passed: got exception " + excpt_, where_, expr_) {}
  344. };
  345. struct expected : message
  346. {
  347. expected( location where_, text expr_, text excpt_ = "" )
  348. : message{ "failed: didn't get exception", where_, expr_, excpt_ } {}
  349. };
  350. struct unexpected : message
  351. {
  352. unexpected( location where_, text expr_, text note_ = "" )
  353. : message{ "failed: got unexpected exception", where_, expr_, note_ } {}
  354. };
  355. struct guard
  356. {
  357. int & id;
  358. int const & section;
  359. guard( int & id_, int const & section_, int & count )
  360. : id( id_), section( section_)
  361. {
  362. if ( section == 0 )
  363. id = count++ - 1;
  364. }
  365. operator bool() { return id == section; }
  366. };
  367. class approx
  368. {
  369. public:
  370. explicit approx ( double magnitude )
  371. : epsilon_ { std::numeric_limits<float>::epsilon() * 100 }
  372. , scale_ { 1.0 }
  373. , magnitude_{ magnitude } {}
  374. approx( approx const & other ) = default;
  375. static approx custom() { return approx( 0 ); }
  376. approx operator()( double new_magnitude )
  377. {
  378. approx appr( new_magnitude );
  379. appr.epsilon( epsilon_ );
  380. appr.scale ( scale_ );
  381. return appr;
  382. }
  383. double magnitude() const { return magnitude_; }
  384. approx & epsilon( double epsilon ) { epsilon_ = epsilon; return *this; }
  385. approx & scale ( double scale ) { scale_ = scale; return *this; }
  386. friend bool operator == ( double lhs, approx const & rhs )
  387. {
  388. // Thanks to Richard Harris for his help refining this formula.
  389. return std::abs( lhs - rhs.magnitude_ ) < rhs.epsilon_ * ( rhs.scale_ + (std::min)( std::abs( lhs ), std::abs( rhs.magnitude_ ) ) );
  390. }
  391. friend bool operator == ( approx const & lhs, double rhs ) { return operator==( rhs, lhs ); }
  392. friend bool operator != ( double lhs, approx const & rhs ) { return !operator==( lhs, rhs ); }
  393. friend bool operator != ( approx const & lhs, double rhs ) { return !operator==( rhs, lhs ); }
  394. friend bool operator <= ( double lhs, approx const & rhs ) { return lhs < rhs.magnitude_ || lhs == rhs; }
  395. friend bool operator <= ( approx const & lhs, double rhs ) { return lhs.magnitude_ < rhs || lhs == rhs; }
  396. friend bool operator >= ( double lhs, approx const & rhs ) { return lhs > rhs.magnitude_ || lhs == rhs; }
  397. friend bool operator >= ( approx const & lhs, double rhs ) { return lhs.magnitude_ > rhs || lhs == rhs; }
  398. private:
  399. double epsilon_;
  400. double scale_;
  401. double magnitude_;
  402. };
  403. inline bool is_false( ) { return false; }
  404. inline bool is_true ( bool flag ) { return flag; }
  405. inline text not_expr( text message )
  406. {
  407. return "! ( " + message + " )";
  408. }
  409. inline text with_message( text message )
  410. {
  411. return "with message \"" + message + "\"";
  412. }
  413. inline text of_type( text type )
  414. {
  415. return "of type " + type;
  416. }
  417. inline void inform( location where, text expr )
  418. {
  419. try
  420. {
  421. throw;
  422. }
  423. catch( message const & )
  424. {
  425. throw;
  426. }
  427. catch( std::exception const & e )
  428. {
  429. throw unexpected{ where, expr, with_message( e.what() ) }; \
  430. }
  431. catch(...)
  432. {
  433. throw unexpected{ where, expr, "of unknown type" }; \
  434. }
  435. }
  436. // Expression decomposition:
  437. template< typename T >
  438. auto make_value_string( T const & value ) -> std::string;
  439. template< typename T >
  440. auto make_memory_string( T const & item ) -> std::string;
  441. #if lest_FEATURE_LITERAL_SUFFIX
  442. inline char const * sfx( char const * txt ) { return txt; }
  443. #else
  444. inline char const * sfx( char const * ) { return ""; }
  445. #endif
  446. inline std::string transformed( char chr )
  447. {
  448. struct Tr { char chr; char const * str; } table[] =
  449. {
  450. {'\\', "\\\\" },
  451. {'\r', "\\r" }, {'\f', "\\f" },
  452. {'\n', "\\n" }, {'\t', "\\t" },
  453. };
  454. for ( auto tr : table )
  455. {
  456. if ( chr == tr.chr )
  457. return tr.str;
  458. }
  459. auto unprintable = [](char c){ return 0 <= c && c < ' '; };
  460. auto to_hex_string = [](char c)
  461. {
  462. std::ostringstream os;
  463. os << "\\x" << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>( static_cast<unsigned char>(c) );
  464. return os.str();
  465. };
  466. return unprintable( chr ) ? to_hex_string( chr ) : std::string( 1, chr );
  467. }
  468. inline std::string make_tran_string( std::string const & txt ) { std::ostringstream os; for(auto c:txt) os << transformed(c); return os.str(); }
  469. inline std::string make_strg_string( std::string const & txt ) { return "\"" + make_tran_string( txt ) + "\"" ; }
  470. inline std::string make_char_string( char chr ) { return "\'" + make_tran_string( std::string( 1, chr ) ) + "\'" ; }
  471. inline std::string to_string( std::nullptr_t ) { return "nullptr"; }
  472. inline std::string to_string( std::string const & txt ) { return make_strg_string( txt ); }
  473. #if lest_FEATURE_WSTRING
  474. inline std::string to_string( std::wstring const & txt ) ;
  475. #endif
  476. inline std::string to_string( char const * const txt ) { return txt ? make_strg_string( txt ) : "{null string}"; }
  477. inline std::string to_string( char * const txt ) { return txt ? make_strg_string( txt ) : "{null string}"; }
  478. #if lest_FEATURE_WSTRING
  479. inline std::string to_string( wchar_t const * const txt ) { return txt ? to_string( std::wstring( txt ) ) : "{null string}"; }
  480. inline std::string to_string( wchar_t * const txt ) { return txt ? to_string( std::wstring( txt ) ) : "{null string}"; }
  481. #endif
  482. inline std::string to_string( bool flag ) { return flag ? "true" : "false"; }
  483. inline std::string to_string( signed short value ) { return make_value_string( value ) ; }
  484. inline std::string to_string( unsigned short value ) { return make_value_string( value ) + sfx("u" ); }
  485. inline std::string to_string( signed int value ) { return make_value_string( value ) ; }
  486. inline std::string to_string( unsigned int value ) { return make_value_string( value ) + sfx("u" ); }
  487. inline std::string to_string( signed long value ) { return make_value_string( value ) + sfx("l" ); }
  488. inline std::string to_string( unsigned long value ) { return make_value_string( value ) + sfx("ul" ); }
  489. inline std::string to_string( signed long long value ) { return make_value_string( value ) + sfx("ll" ); }
  490. inline std::string to_string( unsigned long long value ) { return make_value_string( value ) + sfx("ull"); }
  491. inline std::string to_string( double value ) { return make_value_string( value ) ; }
  492. inline std::string to_string( float value ) { return make_value_string( value ) + sfx("f" ); }
  493. inline std::string to_string( signed char chr ) { return make_char_string( static_cast<char>( chr ) ); }
  494. inline std::string to_string( unsigned char chr ) { return make_char_string( static_cast<char>( chr ) ); }
  495. inline std::string to_string( char chr ) { return make_char_string( chr ); }
  496. template< typename T >
  497. struct is_streamable
  498. {
  499. template< typename U >
  500. static auto test( int ) -> decltype( std::declval<std::ostream &>() << std::declval<U>(), std::true_type() );
  501. template< typename >
  502. static auto test( ... ) -> std::false_type;
  503. #ifdef _MSC_VER
  504. enum { value = std::is_same< decltype( test<T>(0) ), std::true_type >::value };
  505. #else
  506. static constexpr bool value = std::is_same< decltype( test<T>(0) ), std::true_type >::value;
  507. #endif
  508. };
  509. template< typename T >
  510. struct is_container
  511. {
  512. template< typename U >
  513. static auto test( int ) -> decltype( std::declval<U>().begin() == std::declval<U>().end(), std::true_type() );
  514. template< typename >
  515. static auto test( ... ) -> std::false_type;
  516. #ifdef _MSC_VER
  517. enum { value = std::is_same< decltype( test<T>(0) ), std::true_type >::value };
  518. #else
  519. static constexpr bool value = std::is_same< decltype( test<T>(0) ), std::true_type >::value;
  520. #endif
  521. };
  522. template< typename T, typename R >
  523. using ForEnum = typename std::enable_if< std::is_enum<T>::value, R>::type;
  524. template< typename T, typename R >
  525. using ForNonEnum = typename std::enable_if< ! std::is_enum<T>::value, R>::type;
  526. template< typename T, typename R >
  527. using ForStreamable = typename std::enable_if< is_streamable<T>::value, R>::type;
  528. template< typename T, typename R >
  529. using ForNonStreamable = typename std::enable_if< ! is_streamable<T>::value, R>::type;
  530. template< typename T, typename R >
  531. using ForContainer = typename std::enable_if< is_container<T>::value, R>::type;
  532. template< typename T, typename R >
  533. using ForNonContainerNonPointer = typename std::enable_if< ! (is_container<T>::value || std::is_pointer<T>::value), R>::type;
  534. template< typename T >
  535. auto make_enum_string( T const & item ) -> ForNonEnum<T, std::string>
  536. {
  537. #if lest__cpp_rtti
  538. return text("[type: ") + typeid(T).name() + "]: " + make_memory_string( item );
  539. #else
  540. return text("[type: (no RTTI)]: ") + make_memory_string( item );
  541. #endif
  542. }
  543. template< typename T >
  544. auto make_enum_string( T const & item ) -> ForEnum<T, std::string>
  545. {
  546. return to_string( static_cast<typename std::underlying_type<T>::type>( item ) );
  547. }
  548. template< typename T >
  549. auto make_string( T const & item ) -> ForNonStreamable<T, std::string>
  550. {
  551. return make_enum_string( item );
  552. }
  553. template< typename T >
  554. auto make_string( T const & item ) -> ForStreamable<T, std::string>
  555. {
  556. std::ostringstream os; os << item; return os.str();
  557. }
  558. template<typename T1, typename T2>
  559. auto make_string( std::pair<T1,T2> const & pair ) -> std::string
  560. {
  561. std::ostringstream oss;
  562. oss << "{ " << to_string( pair.first ) << ", " << to_string( pair.second ) << " }";
  563. return oss.str();
  564. }
  565. template< typename TU, std::size_t N >
  566. struct make_tuple_string
  567. {
  568. static std::string make( TU const & tuple )
  569. {
  570. std::ostringstream os;
  571. os << to_string( std::get<N - 1>( tuple ) ) << ( N < std::tuple_size<TU>::value ? ", ": " ");
  572. return make_tuple_string<TU, N - 1>::make( tuple ) + os.str();
  573. }
  574. };
  575. template< typename TU >
  576. struct make_tuple_string<TU, 0>
  577. {
  578. static std::string make( TU const & ) { return ""; }
  579. };
  580. template< typename ...TS >
  581. auto make_string( std::tuple<TS...> const & tuple ) -> std::string
  582. {
  583. return "{ " + make_tuple_string<std::tuple<TS...>, sizeof...(TS)>::make( tuple ) + "}";
  584. }
  585. template< typename T >
  586. inline std::string make_string( T const * ptr )
  587. {
  588. // Note showbase affects the behavior of /integer/ output;
  589. std::ostringstream os;
  590. os << std::internal << std::hex << std::showbase << std::setw( 2 + 2 * sizeof(T*) ) << std::setfill('0') << reinterpret_cast<std::ptrdiff_t>( ptr );
  591. return os.str();
  592. }
  593. template< typename C, typename R >
  594. inline std::string make_string( R C::* ptr )
  595. {
  596. std::ostringstream os;
  597. os << std::internal << std::hex << std::showbase << std::setw( 2 + 2 * sizeof(R C::* ) ) << std::setfill('0') << ptr;
  598. return os.str();
  599. }
  600. template< typename T >
  601. auto to_string( T const * ptr ) -> std::string
  602. {
  603. return ! ptr ? "nullptr" : make_string( ptr );
  604. }
  605. template<typename C, typename R>
  606. auto to_string( R C::* ptr ) -> std::string
  607. {
  608. return ! ptr ? "nullptr" : make_string( ptr );
  609. }
  610. template< typename T >
  611. auto to_string( T const & item ) -> ForNonContainerNonPointer<T, std::string>
  612. {
  613. return make_string( item );
  614. }
  615. template< typename C >
  616. auto to_string( C const & cont ) -> ForContainer<C, std::string>
  617. {
  618. std::ostringstream os;
  619. os << "{ ";
  620. for ( auto & x : cont )
  621. {
  622. os << to_string( x ) << ", ";
  623. }
  624. os << "}";
  625. return os.str();
  626. }
  627. #if lest_FEATURE_WSTRING
  628. inline
  629. auto to_string( std::wstring const & txt ) -> std::string
  630. {
  631. std::string result; result.reserve( txt.size() );
  632. for( auto & chr : txt )
  633. {
  634. result += chr <= 0xff ? static_cast<char>( chr ) : '?';
  635. }
  636. return to_string( result );
  637. }
  638. #endif
  639. template< typename T >
  640. auto make_value_string( T const & value ) -> std::string
  641. {
  642. std::ostringstream os; os << value; return os.str();
  643. }
  644. inline
  645. auto make_memory_string( void const * item, std::size_t size ) -> std::string
  646. {
  647. // reverse order for little endian architectures:
  648. auto is_little_endian = []
  649. {
  650. union U { int i = 1; char c[ sizeof(int) ]; };
  651. return 1 != U{}.c[ sizeof(int) - 1 ];
  652. };
  653. int i = 0, end = static_cast<int>( size ), inc = 1;
  654. if ( is_little_endian() ) { i = end - 1; end = inc = -1; }
  655. unsigned char const * bytes = static_cast<unsigned char const *>( item );
  656. std::ostringstream os;
  657. os << "0x" << std::setfill( '0' ) << std::hex;
  658. for ( ; i != end; i += inc )
  659. {
  660. os << std::setw(2) << static_cast<unsigned>( bytes[i] ) << " ";
  661. }
  662. return os.str();
  663. }
  664. template< typename T >
  665. auto make_memory_string( T const & item ) -> std::string
  666. {
  667. return make_memory_string( &item, sizeof item );
  668. }
  669. inline
  670. auto to_string( approx const & appr ) -> std::string
  671. {
  672. return to_string( appr.magnitude() );
  673. }
  674. template< typename L, typename R >
  675. auto to_string( L const & lhs, std::string op, R const & rhs ) -> std::string
  676. {
  677. std::ostringstream os; os << to_string( lhs ) << " " << op << " " << to_string( rhs ); return os.str();
  678. }
  679. template< typename L >
  680. struct expression_lhs
  681. {
  682. const L lhs;
  683. expression_lhs( L lhs_) : lhs( lhs_) {}
  684. operator result() { return result{ !!lhs, to_string( lhs ) }; }
  685. template< typename R > result operator==( R const & rhs ) { return result{ lhs == rhs, to_string( lhs, "==", rhs ) }; }
  686. template< typename R > result operator!=( R const & rhs ) { return result{ lhs != rhs, to_string( lhs, "!=", rhs ) }; }
  687. template< typename R > result operator< ( R const & rhs ) { return result{ lhs < rhs, to_string( lhs, "<" , rhs ) }; }
  688. template< typename R > result operator<=( R const & rhs ) { return result{ lhs <= rhs, to_string( lhs, "<=", rhs ) }; }
  689. template< typename R > result operator> ( R const & rhs ) { return result{ lhs > rhs, to_string( lhs, ">" , rhs ) }; }
  690. template< typename R > result operator>=( R const & rhs ) { return result{ lhs >= rhs, to_string( lhs, ">=", rhs ) }; }
  691. };
  692. struct expression_decomposer
  693. {
  694. template <typename L>
  695. expression_lhs<L const &> operator<< ( L const & operand )
  696. {
  697. return expression_lhs<L const &>( operand );
  698. }
  699. };
  700. // Reporter:
  701. #if lest_FEATURE_COLOURISE
  702. inline text red ( text words ) { return "\033[1;31m" + words + "\033[0m"; }
  703. inline text green( text words ) { return "\033[1;32m" + words + "\033[0m"; }
  704. inline text gray ( text words ) { return "\033[1;30m" + words + "\033[0m"; }
  705. inline bool starts_with( text words, text with )
  706. {
  707. return 0 == words.find( with );
  708. }
  709. inline text replace( text words, text from, text to )
  710. {
  711. size_t pos = words.find( from );
  712. return pos == std::string::npos ? words : words.replace( pos, from.length(), to );
  713. }
  714. inline text colour( text words )
  715. {
  716. if ( starts_with( words, "failed" ) ) return replace( words, "failed", red ( "failed" ) );
  717. else if ( starts_with( words, "passed" ) ) return replace( words, "passed", green( "passed" ) );
  718. return replace( words, "for", gray( "for" ) );
  719. }
  720. inline bool is_cout( std::ostream & os ) { return &os == &std::cout; }
  721. struct colourise
  722. {
  723. const text words;
  724. colourise( text words )
  725. : words( words ) {}
  726. // only colourise for std::cout, not for a stringstream as used in tests:
  727. std::ostream & operator()( std::ostream & os ) const
  728. {
  729. return is_cout( os ) ? os << colour( words ) : os << words;
  730. }
  731. };
  732. inline std::ostream & operator<<( std::ostream & os, colourise words ) { return words( os ); }
  733. #else
  734. inline text colourise( text words ) { return words; }
  735. #endif
  736. inline text pluralise( text word, int n )
  737. {
  738. return n == 1 ? word : word + "s";
  739. }
  740. inline std::ostream & operator<<( std::ostream & os, comment note )
  741. {
  742. return os << (note ? " " + note.info : "" );
  743. }
  744. inline std::ostream & operator<<( std::ostream & os, location where )
  745. {
  746. #ifdef __GNUG__
  747. return os << where.file << ":" << where.line;
  748. #else
  749. return os << where.file << "(" << where.line << ")";
  750. #endif
  751. }
  752. inline void report( std::ostream & os, message const & e, text test )
  753. {
  754. os << e.where << ": " << colourise( e.kind ) << e.note << ": " << test << ": " << colourise( e.what() ) << std::endl;
  755. }
  756. // Test runner:
  757. #if lest_FEATURE_REGEX_SEARCH
  758. inline bool search( text re, text line )
  759. {
  760. return std::regex_search( line, std::regex( re ) );
  761. }
  762. #else
  763. inline bool search( text part, text line )
  764. {
  765. auto case_insensitive_equal = []( char a, char b )
  766. {
  767. return tolower( a ) == tolower( b );
  768. };
  769. return std::search(
  770. line.begin(), line.end(),
  771. part.begin(), part.end(), case_insensitive_equal ) != line.end();
  772. }
  773. #endif
  774. inline bool match( texts whats, text line )
  775. {
  776. for ( auto & what : whats )
  777. {
  778. if ( search( what, line ) )
  779. return true;
  780. }
  781. return false;
  782. }
  783. inline bool select( text name, texts include )
  784. {
  785. auto none = []( texts args ) { return args.size() == 0; };
  786. #if lest_FEATURE_REGEX_SEARCH
  787. auto hidden = []( text arg ){ return match( { "\\[\\..*", "\\[hide\\]" }, arg ); };
  788. #else
  789. auto hidden = []( text arg ){ return match( { "[.", "[hide]" }, arg ); };
  790. #endif
  791. if ( none( include ) )
  792. {
  793. return ! hidden( name );
  794. }
  795. bool any = false;
  796. for ( auto pos = include.rbegin(); pos != include.rend(); ++pos )
  797. {
  798. auto & part = *pos;
  799. if ( part == "@" || part == "*" )
  800. return true;
  801. if ( search( part, name ) )
  802. return true;
  803. if ( '!' == part[0] )
  804. {
  805. any = true;
  806. if ( search( part.substr(1), name ) )
  807. return false;
  808. }
  809. else
  810. {
  811. any = false;
  812. }
  813. }
  814. return any && ! hidden( name );
  815. }
  816. inline int indefinite( int repeat ) { return repeat == -1; }
  817. using seed_t = std::mt19937::result_type;
  818. struct options
  819. {
  820. bool help = false;
  821. bool abort = false;
  822. bool count = false;
  823. bool list = false;
  824. bool tags = false;
  825. bool time = false;
  826. bool pass = false;
  827. bool zen = false;
  828. bool lexical = false;
  829. bool random = false;
  830. bool verbose = false;
  831. bool version = false;
  832. int repeat = 1;
  833. seed_t seed = 0;
  834. };
  835. struct env
  836. {
  837. std::ostream & os;
  838. options opt;
  839. text testing;
  840. std::vector< text > ctx;
  841. env( std::ostream & out, options option )
  842. : os( out ), opt( option ), testing(), ctx() {}
  843. env & operator()( text test )
  844. {
  845. clear(); testing = test; return *this;
  846. }
  847. bool abort() { return opt.abort; }
  848. bool pass() { return opt.pass; }
  849. bool zen() { return opt.zen; }
  850. void clear() { ctx.clear(); }
  851. void pop() { ctx.pop_back(); }
  852. void push( text proposition ) { ctx.emplace_back( proposition ); }
  853. text context() { return testing + sections(); }
  854. text sections()
  855. {
  856. if ( ! opt.verbose )
  857. return "";
  858. text msg;
  859. for( auto section : ctx )
  860. {
  861. msg += "\n " + section;
  862. }
  863. return msg;
  864. }
  865. };
  866. struct ctx
  867. {
  868. env & environment;
  869. bool once;
  870. ctx( env & environment_, text proposition_ )
  871. : environment( environment_), once( true )
  872. {
  873. environment.push( proposition_);
  874. }
  875. ~ctx()
  876. {
  877. #if lest_CPP17_OR_GREATER
  878. if ( std::uncaught_exceptions() == 0 )
  879. #else
  880. if ( ! std::uncaught_exception() )
  881. #endif
  882. {
  883. environment.pop();
  884. }
  885. }
  886. explicit operator bool() { bool result = once; once = false; return result; }
  887. };
  888. struct action
  889. {
  890. std::ostream & os;
  891. action( std::ostream & out ) : os( out ) {}
  892. action( action const & ) = delete;
  893. void operator=( action const & ) = delete;
  894. operator int() { return 0; }
  895. bool abort() { return false; }
  896. action & operator()( test ) { return *this; }
  897. };
  898. struct print : action
  899. {
  900. print( std::ostream & out ) : action( out ) {}
  901. print & operator()( test testing )
  902. {
  903. os << testing.name << "\n"; return *this;
  904. }
  905. };
  906. inline texts tags( text name, texts result = {} )
  907. {
  908. auto none = std::string::npos;
  909. auto lb = name.find_first_of( "[" );
  910. auto rb = name.find_first_of( "]" );
  911. if ( lb == none || rb == none )
  912. return result;
  913. result.emplace_back( name.substr( lb, rb - lb + 1 ) );
  914. return tags( name.substr( rb + 1 ), result );
  915. }
  916. struct ptags : action
  917. {
  918. std::set<text> result;
  919. ptags( std::ostream & out ) : action( out ), result() {}
  920. ptags & operator()( test testing )
  921. {
  922. for ( auto & tag : tags( testing.name ) )
  923. result.insert( tag );
  924. return *this;
  925. }
  926. ~ptags()
  927. {
  928. std::copy( result.begin(), result.end(), std::ostream_iterator<text>( os, "\n" ) );
  929. }
  930. };
  931. struct count : action
  932. {
  933. int n = 0;
  934. count( std::ostream & out ) : action( out ) {}
  935. count & operator()( test ) { ++n; return *this; }
  936. ~count()
  937. {
  938. os << n << " selected " << pluralise("test", n) << "\n";
  939. }
  940. };
  941. struct timer
  942. {
  943. using time = std::chrono::high_resolution_clock;
  944. time::time_point start = time::now();
  945. double elapsed_seconds() const
  946. {
  947. return 1e-6 * static_cast<double>( std::chrono::duration_cast< std::chrono::microseconds >( time::now() - start ).count() );
  948. }
  949. };
  950. struct times : action
  951. {
  952. env output;
  953. int selected = 0;
  954. int failures = 0;
  955. timer total;
  956. times( std::ostream & out, options option )
  957. : action( out ), output( out, option ), total()
  958. {
  959. os << std::setfill(' ') << std::fixed << std::setprecision( lest_FEATURE_TIME_PRECISION );
  960. }
  961. operator int() { return failures; }
  962. bool abort() { return output.abort() && failures > 0; }
  963. times & operator()( test testing )
  964. {
  965. timer t;
  966. try
  967. {
  968. testing.behaviour( output( testing.name ) );
  969. }
  970. catch( message const & )
  971. {
  972. ++failures;
  973. }
  974. os << std::setw(3) << ( 1000 * t.elapsed_seconds() ) << " ms: " << testing.name << "\n";
  975. return *this;
  976. }
  977. ~times()
  978. {
  979. os << "Elapsed time: " << std::setprecision(1) << total.elapsed_seconds() << " s\n";
  980. }
  981. };
  982. struct confirm : action
  983. {
  984. env output;
  985. int selected = 0;
  986. int failures = 0;
  987. confirm( std::ostream & out, options option )
  988. : action( out ), output( out, option ) {}
  989. operator int() { return failures; }
  990. bool abort() { return output.abort() && failures > 0; }
  991. confirm & operator()( test testing )
  992. {
  993. try
  994. {
  995. ++selected; testing.behaviour( output( testing.name ) );
  996. }
  997. catch( message const & e )
  998. {
  999. ++failures; report( os, e, output.context() );
  1000. }
  1001. return *this;
  1002. }
  1003. ~confirm()
  1004. {
  1005. if ( failures > 0 )
  1006. {
  1007. os << failures << " out of " << selected << " selected " << pluralise("test", selected) << " " << colourise( "failed.\n" );
  1008. }
  1009. else if ( output.pass() )
  1010. {
  1011. os << "All " << selected << " selected " << pluralise("test", selected) << " " << colourise( "passed.\n" );
  1012. }
  1013. }
  1014. };
  1015. template< typename Action >
  1016. bool abort( Action & perform )
  1017. {
  1018. return perform.abort();
  1019. }
  1020. template< typename Action >
  1021. Action && for_test( tests specification, texts in, Action && perform, int n = 1 )
  1022. {
  1023. for ( int i = 0; indefinite( n ) || i < n; ++i )
  1024. {
  1025. for ( auto & testing : specification )
  1026. {
  1027. if ( select( testing.name, in ) )
  1028. if ( abort( perform( testing ) ) )
  1029. return std::move( perform );
  1030. }
  1031. }
  1032. return std::move( perform );
  1033. }
  1034. inline void sort( tests & specification )
  1035. {
  1036. auto test_less = []( test const & a, test const & b ) { return a.name < b.name; };
  1037. std::sort( specification.begin(), specification.end(), test_less );
  1038. }
  1039. inline void shuffle( tests & specification, options option )
  1040. {
  1041. std::shuffle( specification.begin(), specification.end(), std::mt19937( option.seed ) );
  1042. }
  1043. // workaround MinGW bug, http://stackoverflow.com/a/16132279:
  1044. inline int stoi( text num )
  1045. {
  1046. return static_cast<int>( std::strtol( num.c_str(), nullptr, 10 ) );
  1047. }
  1048. inline bool is_number( text arg )
  1049. {
  1050. return std::all_of( arg.begin(), arg.end(), ::isdigit );
  1051. }
  1052. inline seed_t seed( text opt, text arg )
  1053. {
  1054. if ( is_number( arg ) )
  1055. return static_cast<seed_t>( lest::stoi( arg ) );
  1056. if ( arg == "time" )
  1057. return static_cast<seed_t>( std::chrono::high_resolution_clock::now().time_since_epoch().count() );
  1058. throw std::runtime_error( "expecting 'time' or positive number with option '" + opt + "', got '" + arg + "' (try option --help)" );
  1059. }
  1060. inline int repeat( text opt, text arg )
  1061. {
  1062. const int num = lest::stoi( arg );
  1063. if ( indefinite( num ) || num >= 0 )
  1064. return num;
  1065. throw std::runtime_error( "expecting '-1' or positive number with option '" + opt + "', got '" + arg + "' (try option --help)" );
  1066. }
  1067. inline auto split_option( text arg ) -> std::tuple<text, text>
  1068. {
  1069. auto pos = arg.rfind( '=' );
  1070. return pos == text::npos
  1071. ? std::make_tuple( arg, "" )
  1072. : std::make_tuple( arg.substr( 0, pos ), arg.substr( pos + 1 ) );
  1073. }
  1074. inline auto split_arguments( texts args ) -> std::tuple<options, texts>
  1075. {
  1076. options option; texts in;
  1077. bool in_options = true;
  1078. for ( auto & arg : args )
  1079. {
  1080. if ( in_options )
  1081. {
  1082. text opt, val;
  1083. std::tie( opt, val ) = split_option( arg );
  1084. if ( opt[0] != '-' ) { in_options = false; }
  1085. else if ( opt == "--" ) { in_options = false; continue; }
  1086. else if ( opt == "-h" || "--help" == opt ) { option.help = true; continue; }
  1087. else if ( opt == "-a" || "--abort" == opt ) { option.abort = true; continue; }
  1088. else if ( opt == "-c" || "--count" == opt ) { option.count = true; continue; }
  1089. else if ( opt == "-g" || "--list-tags" == opt ) { option.tags = true; continue; }
  1090. else if ( opt == "-l" || "--list-tests" == opt ) { option.list = true; continue; }
  1091. else if ( opt == "-t" || "--time" == opt ) { option.time = true; continue; }
  1092. else if ( opt == "-p" || "--pass" == opt ) { option.pass = true; continue; }
  1093. else if ( opt == "-z" || "--pass-zen" == opt ) { option.zen = true; continue; }
  1094. else if ( opt == "-v" || "--verbose" == opt ) { option.verbose = true; continue; }
  1095. else if ( "--version" == opt ) { option.version = true; continue; }
  1096. else if ( opt == "--order" && "declared" == val ) { /* by definition */ ; continue; }
  1097. else if ( opt == "--order" && "lexical" == val ) { option.lexical = true; continue; }
  1098. else if ( opt == "--order" && "random" == val ) { option.random = true; continue; }
  1099. else if ( opt == "--random-seed" ) { option.seed = seed ( "--random-seed", val ); continue; }
  1100. else if ( opt == "--repeat" ) { option.repeat = repeat( "--repeat" , val ); continue; }
  1101. else throw std::runtime_error( "unrecognised option '" + arg + "' (try option --help)" );
  1102. }
  1103. in.push_back( arg );
  1104. }
  1105. option.pass = option.pass || option.zen;
  1106. return std::make_tuple( option, in );
  1107. }
  1108. inline int usage( std::ostream & os )
  1109. {
  1110. os <<
  1111. "\nUsage: test [options] [test-spec ...]\n"
  1112. "\n"
  1113. "Options:\n"
  1114. " -h, --help this help message\n"
  1115. " -a, --abort abort at first failure\n"
  1116. " -c, --count count selected tests\n"
  1117. " -g, --list-tags list tags of selected tests\n"
  1118. " -l, --list-tests list selected tests\n"
  1119. " -p, --pass also report passing tests\n"
  1120. " -z, --pass-zen ... without expansion\n"
  1121. " -t, --time list duration of selected tests\n"
  1122. " -v, --verbose also report passing or failing sections\n"
  1123. " --order=declared use source code test order (default)\n"
  1124. " --order=lexical use lexical sort test order\n"
  1125. " --order=random use random test order\n"
  1126. " --random-seed=n use n for random generator seed\n"
  1127. " --random-seed=time use time for random generator seed\n"
  1128. " --repeat=n repeat selected tests n times (-1: indefinite)\n"
  1129. " --version report lest version and compiler used\n"
  1130. " -- end options\n"
  1131. "\n"
  1132. "Test specification:\n"
  1133. " \"@\", \"*\" all tests, unless excluded\n"
  1134. " empty all tests, unless tagged [hide] or [.optional-name]\n"
  1135. #if lest_FEATURE_REGEX_SEARCH
  1136. " \"re\" select tests that match regular expression\n"
  1137. " \"!re\" omit tests that match regular expression\n"
  1138. #else
  1139. " \"text\" select tests that contain text (case insensitive)\n"
  1140. " \"!text\" omit tests that contain text (case insensitive)\n"
  1141. #endif
  1142. ;
  1143. return 0;
  1144. }
  1145. inline text compiler()
  1146. {
  1147. std::ostringstream os;
  1148. #if defined (__clang__ )
  1149. os << "clang " << __clang_version__;
  1150. #elif defined (__GNUC__ )
  1151. os << "gcc " << __GNUC__ << "." << __GNUC_MINOR__ << "." << __GNUC_PATCHLEVEL__;
  1152. #elif defined ( _MSC_VER )
  1153. os << "MSVC " << (_MSC_VER / 100 - 5 - (_MSC_VER < 1900)) << " (" << _MSC_VER << ")";
  1154. #else
  1155. os << "[compiler]";
  1156. #endif
  1157. return os.str();
  1158. }
  1159. inline int version( std::ostream & os )
  1160. {
  1161. os << "lest version " << lest_VERSION << "\n"
  1162. << "Compiled with " << compiler() << " on " << __DATE__ << " at " << __TIME__ << ".\n"
  1163. << "For more information, see https://github.com/martinmoene/lest.\n";
  1164. return 0;
  1165. }
  1166. inline int run( tests specification, texts arguments, std::ostream & os = std::cout )
  1167. {
  1168. try
  1169. {
  1170. options option; texts in;
  1171. std::tie( option, in ) = split_arguments( arguments );
  1172. if ( option.lexical ) { sort( specification ); }
  1173. if ( option.random ) { shuffle( specification, option ); }
  1174. if ( option.help ) { return usage ( os ); }
  1175. if ( option.version ) { return version ( os ); }
  1176. if ( option.count ) { return for_test( specification, in, count( os ) ); }
  1177. if ( option.list ) { return for_test( specification, in, print( os ) ); }
  1178. if ( option.tags ) { return for_test( specification, in, ptags( os ) ); }
  1179. if ( option.time ) { return for_test( specification, in, times( os, option ) ); }
  1180. return for_test( specification, in, confirm( os, option ), option.repeat );
  1181. }
  1182. catch ( std::exception const & e )
  1183. {
  1184. os << "Error: " << e.what() << "\n";
  1185. return 1;
  1186. }
  1187. }
  1188. inline int run( tests specification, int argc, char * argv[], std::ostream & os = std::cout )
  1189. {
  1190. return run( specification, texts( argv + 1, argv + argc ), os );
  1191. }
  1192. template< std::size_t N >
  1193. int run( test const (&specification)[N], texts arguments, std::ostream & os = std::cout )
  1194. {
  1195. std::cout.sync_with_stdio( false );
  1196. return (std::min)( run( tests( specification, specification + N ), arguments, os ), exit_max_value );
  1197. }
  1198. template< std::size_t N >
  1199. int run( test const (&specification)[N], std::ostream & os = std::cout )
  1200. {
  1201. return run( tests( specification, specification + N ), {}, os );
  1202. }
  1203. template< std::size_t N >
  1204. int run( test const (&specification)[N], int argc, char * argv[], std::ostream & os = std::cout )
  1205. {
  1206. return run( tests( specification, specification + N ), texts( argv + 1, argv + argc ), os );
  1207. }
  1208. } // namespace lest
  1209. #if defined (__clang__)
  1210. # pragma clang diagnostic pop
  1211. #elif defined (__GNUC__)
  1212. # pragma GCC diagnostic pop
  1213. #endif
  1214. #endif // LEST_LEST_HPP_INCLUDED