From 6aa302f791b298cb920443d9c6b96a5d6218e50f Mon Sep 17 00:00:00 2001 From: ADAM David Alan Martin Date: Mon, 23 Oct 2023 04:10:51 -0400 Subject: [PATCH] Table testing for exception cases. I still have to implement a bit more here, but this is a good start. --- Testing/TableTest.h | 115 +++++++++++++++++++++++++++++++++++- Testing/colors.h | 1 + string_algorithms.test/0.cc | 16 ++--- 3 files changed, 123 insertions(+), 9 deletions(-) diff --git a/Testing/TableTest.h b/Testing/TableTest.h index acab94f..8e483a4 100644 --- a/Testing/TableTest.h +++ b/Testing/TableTest.h @@ -280,7 +280,118 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test } }; - //struct VectorCases; + struct ExceptionCases + { + using Invoker= std::function< void () >; + struct ExceptionHandler + { + std::function< bool ( Invoker ) > impl; + + bool operator() ( Invoker invoker ) const { return impl( invoker ); } + + ExceptionHandler() : impl + { + []( Invoker invoker ) + { + try + { + invoker(); + return true; + } + catch( ... ) { return false; } + } + } + {} + + template< typename T > + ExceptionHandler( std::type_identity< T > ) : impl + { + []( Invoker invoker ) + { + try + { + invoker(); + return false; + } + catch( const T & ) { return true; } + } + } + {} + + template< typename T > + ExceptionHandler( const T exemplar ) : impl + { + [expected= std::string{ exemplar.what() }]( Invoker invoker ) + { + try + { + invoker(); + std::cerr << " " << C::testInfo << "NOTE" << resetStyle << ": expected exception `"<< typeid( T ).name() + << "` wasn't thrown." << std::endl; + return false; + } + catch( const T &ex ) + { + const std::string witness= ex.what(); + const bool rv= witness == expected; + if( not rv ) + { + std::cerr << " " << C::testInfo << "NOTE" << resetStyle << ": expected exception `"<< typeid( T ).name() + << "` wasn't thrown." << std::endl; + printDebugging< outputMode >( witness, expected ); + } + return rv; + } + } + } + {} + + // This checker is invoked during `catch( ... )` + ExceptionHandler( const std::function< bool () > checker ) : impl + { + [=]( Invoker invoker ) + { + try + { + invoker(); + return false; + } + catch( ... ) { checker(); } // The `checker` can use `throw` to run any complex checks it needs. + } + } + {} + }; + + using TestDescription= std::tuple< std::string, args_type, ExceptionHandler >; + + std::vector< TestDescription > tests; + + + explicit + ExceptionCases( std::initializer_list< TestDescription > initList ) + : tests( initList ) {} + + int + operator() () const + { + int failureCount= 0; + for( const auto &[ comment, params, checker ]: tests ) + { + if( C::debugCaseTypes ) std::cerr << boost::core::demangle( typeid( params ).name() ) << std::endl; + breakpoint(); + auto invoker= [&]{ std::apply( function, params ); }; + const auto result= checker( invoker ); + if( not result ) + { + std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl; + ++failureCount; + } + else std::cout << " " << C::testPass << "PASSED CASE" << resetStyle << ": " << comment << std::endl; + } + + return failureCount; + } + }; }; #ifdef DISABLED @@ -295,7 +406,7 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test std::vector< std::pair< typename std::tuple_element_t< 0, std::tuple< Args... > >::value_type, typename RetVal::value_type > > >; std::vector< TestDescription > tests; - + explicit VectorCases( std::initializer_list< TestDescription > initList ) : tests( initList ) {} diff --git a/Testing/colors.h b/Testing/colors.h index d448e01..b84deb8 100644 --- a/Testing/colors.h +++ b/Testing/colors.h @@ -12,6 +12,7 @@ namespace Alepha::Hydrogen::Testing ::detail:: testing_colors { inline const auto testFail= createStyle( "test-failure", setFgColor( BasicTextColor::red ) ); inline const auto testPass= createStyle( "test-success", setFgColor( BasicTextColor::green ) ); + inline const auto testInfo= createStyle( "test-info", "italic ansi:5"_sgr ); } } } diff --git a/string_algorithms.test/0.cc b/string_algorithms.test/0.cc index 55c1329..b982d52 100644 --- a/string_algorithms.test/0.cc +++ b/string_algorithms.test/0.cc @@ -38,14 +38,16 @@ static auto init= enroll <=[] }, }; - "An exception should be thrown when there is a trailing unenclosed variable."_test <=[] + "An exception should be thrown when there is a trailing unenclosed variable."_test <=TableTest< Alepha::expandVariables >::ExceptionCases { - try - { - Alepha::expandVariables( "$H$ $W", { { "H", lambaste<="Hello" }, { "W", lambaste<="World" } }, '$' ); - abort(); - } - catch( ... ) {} + { "Complete var", + { "$H$ $W$", { { "H", lambaste<="Hello" }, { "W", lambaste<="World" } }, '$' }, + {} + }, + { "Incomplete var", + { "$H$ $W", { { "H", lambaste<="Hello" }, { "W", lambaste<="World" } }, '$' }, + std::type_identity< std::exception >{} + }, }; "Does the `split` function handle simple cases correctly?"_test <=TableTest< Alepha::split >::Cases