1
0
forked from Alepha/Alepha

Basic support for exception verification in tests

This probably needs to be expanded upon.  The basic functionality
added is to permit a test expectation clause to be a function which
takes some kind of exception type.  That function can then
perform any arbitrary checks and analyses it needs to confirm that
the exception which was caught passes muster for that test case.
This commit is contained in:
2024-06-12 00:08:14 -04:00
parent e16be47994
commit 26eb1b080e
2 changed files with 68 additions and 2 deletions

View File

@ -69,6 +69,18 @@ namespace Alepha::Hydrogen::Testing ::detail:: TableTest_m
else return ex.message();
}
template< typename T >
concept ExceptionLike= DerivedFrom< T, std::exception >
or DerivedFrom< T, Alepha::Exception >;
template< typename T, typename Param >
concept FunctionOver= Concepts::UnaryFunction< T >
and Concepts::SameAs< get_args_t< T >, std::tuple< Param > >;
template< typename T >
concept FunctionTakingThrowable= UnaryFunction< T >
and ExceptionLike< get_arg_t< T, 0 > >;
template< typename return_type, OutputMode outputMode >
struct BasicUniversalHandler
: compute_base_t< return_type >
@ -80,6 +92,41 @@ namespace Alepha::Hydrogen::Testing ::detail:: TableTest_m
std::function< std::tuple< TestResult, std::optional< std::string > > ( Invoker, const std::string & ) > impl;
template< FunctionTakingThrowable Verifier >
BasicUniversalHandler( Verifier verifier ) : impl
{
[verifier] ( Invoker invoker, const std::string &comment ) -> std::tuple< TestResult, std::optional< std::string > >
{
try
{
invoker();
return { TestResult::Failed, "Expected an exception but none was thrown." };
}
catch( const get_arg_t< Verifier, 0 > &ex )
{
if( verifier( ex ) ) return { TestResult::Passed, std::nullopt };
return { TestResult::Failed, "Verification of exception contents failed." };
}
catch( ... )
{
try { throw; }
catch( const std::exception &ex )
{
return { TestResult::Failed, "Unexpected Exception Type: " + Utility::fancyTypeName( typeid( ex ) ) };
}
catch( const Alepha::Exception &ex )
{
return { TestResult::Failed, "Unexpected Exception Type: " + Utility::fancyTypeName( typeid( ex ) ) };
}
catch( ... )
{
return { TestResult::Failed, "Unknown Exception Type." };
}
}
}
}
{}
BasicUniversalHandler( const return_type expected ) : impl
{
[expected]( Invoker invoker, const std::string &comment ) -> std::tuple< TestResult, std::optional< std::string > >
@ -220,7 +267,15 @@ namespace Alepha::Hydrogen::Testing ::detail:: TableTest_m
{}
template< typename T >
requires( DerivedFrom< T, std::exception > or DerivedFrom< T, Alepha::Exception > )
requires
(
(
false
or DerivedFrom< T, std::exception >
or DerivedFrom< T, Alepha::Exception >
)
and not std::is_same_v< return_type, T >
)
BasicUniversalHandler( const T exemplar ) : impl
{
[expected= getMessageFromException( exemplar )]( Invoker invoker, const std::string &comment ) -> std::tuple< TestResult, std::optional< std::string > >

View File

@ -53,6 +53,12 @@ namespace
struct DerivedError : std::runtime_error
{
using std::runtime_error::runtime_error;
std::optional< int > value_;
explicit DerivedError( const std::string &s, int value_ ) : std::runtime_error{ s }, value_( value_ ) {}
int value() const { return value_.value(); }
};
"Can we use Aggregates with universal cases, correctly?"_test <=
@ -60,7 +66,7 @@ namespace
<
[]( const int x )
{
if( x < 0 ) throw DerivedError{ "Cannot be negative." };
if( x < 0 ) throw DerivedError{ "Cannot be negative.", x };
return Aggregate{ x, x, x };
}
>
@ -73,6 +79,11 @@ namespace
{ "Expect exception type exception", { -42 }, std::type_identity< std::exception >{} },
{ "Expect exception value specific", { -42 }, DerivedError{ "Cannot be negative." } },
{ "Expect exception value specific (loose)", { -42 }, std::runtime_error{ "Cannot be negative." } },
{ "Expect exception value specific (loose)", { -42 },
[]( const DerivedError &e )
{
return e.value() == -42;
} },
/* These cases should fail, but we don't want to fail them in normal builds. */
/* A few different ways of disabling these tests are shown below. */