diff --git a/Testing/TableTest.cc b/Testing/TableTest.cc new file mode 100644 index 0000000..2ed377c --- /dev/null +++ b/Testing/TableTest.cc @@ -0,0 +1,36 @@ +static_assert( __cplusplus > 2020'99 ); + +#include "TableTest.h" + +namespace Alepha::Hydrogen::Testing::detail::TableTest_m +{ + int + UniversalCasesBase::operator() () const + { + int failureCount= 0; + for( const auto &[ comment, checker ]: tests ) + { + const auto [result, supplement]= checker( comment ); + if( result == TestResult::Failed ) + { + ++failureCount; + std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl; + if( supplement.has_value() ) + { + std::cout << " " << C::testWarn << "DETAILS" << resetStyle << ": " << supplement.value() << std::endl; + } + } + else + { + std::cout << " " << C::testPass << "PASSED CASE" << resetStyle << ": " << comment << std::endl; + if( supplement.has_value() ) + { + std::cout << " " << C::testWarn << "INFO: " << resetStyle << ": " << supplement.value() << std::endl; + } + } + breakpoint(); + } + + return failureCount; + } +} diff --git a/Testing/TableTest.h b/Testing/TableTest.h index 018dd16..48e9a00 100644 --- a/Testing/TableTest.h +++ b/Testing/TableTest.h @@ -15,9 +15,6 @@ static_assert( __cplusplus > 2020'99 ); #include #include -#include -#include - #include #include @@ -25,6 +22,7 @@ static_assert( __cplusplus > 2020'99 ); #include #include +#include #include @@ -84,7 +82,7 @@ namespace Alepha::Hydrogen::Testing ::detail:: TableTest_m } catch( const std::exception &ex ) { - return ErrorMessage{ typeid( ex ).name() }; + return ErrorMessage{ Utility::fancyTypeName( typeid( ex ) ) }; } catch( ... ) { @@ -127,7 +125,7 @@ namespace Alepha::Hydrogen::Testing ::detail:: TableTest_m } catch( const std::exception &ex ) { - return ErrorMessage{ typeid( ex ).name() }; + return ErrorMessage{ Utility::fancyTypeName( typeid( ex ) ) }; } catch( ... ) { @@ -160,13 +158,26 @@ namespace Alepha::Hydrogen::Testing ::detail:: TableTest_m { try { - std::ignore= invoker(); - breakpoint(); - return { TestResult::Failed, std::nullopt }; + try + { + std::ignore= invoker(); + breakpoint(); + return { TestResult::Failed, IOStreams::String() << "No exception was thrown, but " << Utility::fancyTypeName< T >() << " expected." }; + } + catch( const T & ) + { + return { TestResult::Passed, std::nullopt }; + } } - catch( const T & ) + catch( const std::exception &ex ) { - return { TestResult::Passed, std::nullopt }; + return { TestResult::Failed, IOStreams::String() << "Incorrect exception type " << Utility::fancyTypeName( typeid( ex ) ) << " was thrown, but " + << Utility::fancyTypeName< T >() << " was expected." }; + } + catch( ... ) + { + return { TestResult::Failed, IOStreams::String() << "Incorrect exception type () was thrown, but " + << Utility::fancyTypeName< T >() << " was expected." }; } } } @@ -183,9 +194,15 @@ namespace Alepha::Hydrogen::Testing ::detail:: TableTest_m std::ignore= invoker(); return { TestResult::Passed, std::nullopt }; } + catch( const std::exception &ex ) + { + return { TestResult::Failed, IOStreams::String() << "Exception type " << Utility::fancyTypeName( typeid( ex ) ) << " was thrown, but " + "no exception was expected." }; + } catch( ... ) { - return { TestResult::Failed, std::nullopt }; + return { TestResult::Failed, IOStreams::String() << "Exception type () was thrown, but " + "no exception was expected." }; } } } @@ -198,21 +215,34 @@ namespace Alepha::Hydrogen::Testing ::detail:: TableTest_m { try { - invoker(); - return { TestResult::Failed, - IOStreams::String{} << "expected exception `" << typeid( T ).name() << "` wasn't thrown." }; - } - catch( const T &ex ) - { - const std::string witness= ex.what(); - const TestResult rv= witness == expected ? TestResult::Passed : TestResult::Failed; - std::ostringstream oss; - if( rv == TestResult::Failed ) + try { - oss << "expected message did not match." << std::endl; - streamDebugging< outputMode >( oss, witness, expected ); + invoker(); + return { TestResult::Failed, + IOStreams::String{} << "expected exception `" << Utility::fancyTypeName< T >() << "` wasn't thrown." }; } - return { rv, oss.str().empty() ? std::optional< std::string >{} : std::move( oss ).str() }; + catch( const T &ex ) + { + const std::string witness= ex.what(); + const TestResult rv= witness == expected ? TestResult::Passed : TestResult::Failed; + std::ostringstream oss; + if( rv == TestResult::Failed ) + { + oss << "expected message did not match." << std::endl; + streamDebugging< outputMode >( oss, witness, expected ); + } + return { rv, oss.str().empty() ? std::optional< std::string >{} : std::move( oss ).str() }; + } + } + catch( const std::exception &ex ) + { + return { TestResult::Failed, IOStreams::String() << "Incorrect exception type " << Utility::fancyTypeName( typeid( ex ) ) << " was thrown, but " + << Utility::fancyTypeName< T >() << " was expected." }; + } + catch( ... ) + { + return { TestResult::Failed, IOStreams::String() << "Incorrect exception type () was thrown, but " + << Utility::fancyTypeName< T >() << " was expected." }; } } } @@ -303,7 +333,7 @@ namespace Alepha::Hydrogen::Testing ::detail:: TableTest_m { for( const auto [ comment, params, handler ]: initList ) { - if( C::debugCaseTypes ) std::cerr << boost::core::demangle( typeid( params ).name() ) << std::endl; + if( C::debugCaseTypes ) std::cerr << Utility::fancyTypeName( typeid( params ) ) << std::endl; auto invoker= [=] { breakpoint(); diff --git a/Testing/TableTest.test/test2.cc b/Testing/TableTest.test/test2.cc index 40de87e..0e8588a 100644 --- a/Testing/TableTest.test/test2.cc +++ b/Testing/TableTest.test/test2.cc @@ -50,12 +50,17 @@ namespace { "Negative case", { -10, -20 }, -30 }, }; + struct DerivedError : std::runtime_error + { + using std::runtime_error::runtime_error; + }; + "Can we use Aggregates with universal cases, correctly?"_test <= TableTest < []( const int x ) { - if( x < 0 ) throw std::runtime_error{ "Cannot be negative." }; + if( x < 0 ) throw DerivedError{ "Cannot be negative." }; return Aggregate{ x, x, x }; } > @@ -66,16 +71,19 @@ namespace { "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 }, std::runtime_error{ "Cannot be negative." } }, + { "Expect exception value specific", { -42 }, DerivedError{ "Cannot be negative." } }, + { "Expect exception value specific (loose)", { -42 }, std::runtime_error{ "Cannot be negative." } }, /* These cases should fail, but we don't want to fail them in normal builds. */ #if 0 - { "Failing: Basic value case", { -42 }, { 42, 42, 42 } }, - { "Failing: Ignore exceptions case (`std::nothrow`)", { -42 }, std::nothrow }, - { "Failing: Ignore exceptions case (`std::type_identity< void >`)", { -42 }, std::type_identity< void >{} }, - { "Failing: Expect exception type runtime_error", { 42 }, std::type_identity< std::runtime_error >{} }, - { "Failing: Expect exception type exception", { 42 }, std::type_identity< std::exception >{} }, - { "Failing: Expect exception value specific", { 42 }, std::runtime_error{ "Cannot be negative." } }, + { "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 (wrong)", { -42 }, std::logic_error{ "Cannot be negative." } }, #endif }; }; diff --git a/Utility/fancyTypeName.cc b/Utility/fancyTypeName.cc index a45279d..2a10c6b 100644 --- a/Utility/fancyTypeName.cc +++ b/Utility/fancyTypeName.cc @@ -7,7 +7,7 @@ static_assert( __cplusplus > 2020'99 ); namespace Alepha::Hydrogen::Utility::detail::fancyTypeName_m { std::string - fancyTypeName( const std::type_index idx ) + exports::fancyTypeName( const std::type_index idx ) { return boost::core::demangle( idx.name() ); }