static_assert( __cplusplus > 2020'99 ); #include #include #include #include #include #include namespace { using namespace Alepha::Testing::exports; using namespace Alepha::Utility::exports::evaluation_helpers_m; int add( int a, int b ) { return a + b; } auto basic_test= "basic_test"_test <=[] { return 0; }; auto test= "addition.two.test"_test <=TableTest< add >::Cases { { "Basic Smoke Test", { 2, 2 }, 4 }, { "Lefthand identity", { 0, 25 }, 25 }, { "Righthand identity", { 25, 0 }, 25 }, }; template< typename= Alepha::Capabilities< Alepha::IOStreams::OStreamable, Alepha::comparable > > struct Aggregate_core { int x, y, z; friend bool operator == ( Aggregate_core, Aggregate_core ) noexcept= default; }; using Aggregate= Aggregate_core<>; auto alltests= enroll <=[] { "addition.two.local"_test <=TableTest< add >::Cases { { "Negative case", { -10, -20 }, -30 }, }; 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 <= TableTest < []( const int x ) { if( x < 0 ) throw DerivedError{ "Cannot be negative.", x }; return Aggregate{ x, x, x }; } > ::UniversalCases { { "Basic value case", { 42 }, { 42, 42, 42 } }, { "Ignore exceptions case (`std::nothrow`)", { 42 }, std::nothrow }, { "Ignore exceptions case (`std::type_identity< void >`)", { 42 }, std::type_identity< void >{} }, { "Expect exception type runtime_error", { -42 }, std::type_identity< std::runtime_error >{} }, { "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. */ { Skip <="Basic value case", { -42 }, { 42, 42, 42 } }, { !!Disable <="Ignore exceptions case (`std::nothrow`)", { -42 }, std::nothrow }, { -Enable <="Ignore exceptions case (`std::type_identity< void >`)", { -42 }, std::type_identity< void >{} }, { -"Expect exception type runtime_error"_case, { 42 }, std::type_identity< std::runtime_error >{} }, { Disable <="Expect exception type exception", { 42 }, std::type_identity< std::exception >{} }, { !"Expect exception value specific"_case, { 42 }, DerivedError{ "Cannot be negative." } }, { Skip <="Expect exception value specific (loose)", { 42 }, std::runtime_error{ "Cannot be negative." } }, { Skip <="Expect exception value specific (wrong)", { -42 }, std::logic_error{ "Cannot be negative." } }, }; }; }