|
|
|
@ -33,6 +33,8 @@ static_assert( __cplusplus > 2020'00 );
|
|
|
|
|
|
|
|
|
|
#include <Alepha/Utility/evaluation_helpers.h>
|
|
|
|
|
|
|
|
|
|
#include <Alepha/Reflection/tuplizeAggregate.h>
|
|
|
|
|
|
|
|
|
|
#include <Alepha/TotalOrder.h>
|
|
|
|
|
#include <Alepha/Console.h>
|
|
|
|
|
|
|
|
|
@ -45,6 +47,8 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
|
|
|
|
enum class OutputMode { All, Relaxed };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline void breakpoint() {}
|
|
|
|
|
|
|
|
|
|
namespace C
|
|
|
|
|
{
|
|
|
|
|
inline namespace Colors
|
|
|
|
@ -53,6 +57,506 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template< OutputMode outputMode, typename T >
|
|
|
|
|
void printDebugging( const T &witness, const T &expected );
|
|
|
|
|
|
|
|
|
|
template< Aggregate Agg, TypeListType >
|
|
|
|
|
struct TupleSneak;
|
|
|
|
|
|
|
|
|
|
template< Aggregate Agg >
|
|
|
|
|
struct TupleSneak< Agg, Nil >
|
|
|
|
|
: Agg
|
|
|
|
|
{
|
|
|
|
|
TupleSneak() { std::cerr << "The inherited default ctor was called." << std::endl; }
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
void set( Agg agg ) { static_cast< Agg & >( *this )= agg; }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template< Aggregate Agg, typename ... Args >
|
|
|
|
|
struct TupleSneak< Agg, TypeList< Args... > >
|
|
|
|
|
: TupleSneak< Agg, cdr_t< TypeList< Args... > > >
|
|
|
|
|
{
|
|
|
|
|
using Parent= TupleSneak< Agg, cdr_t< TypeList< Args... > > >;
|
|
|
|
|
using Parent::Parent;
|
|
|
|
|
|
|
|
|
|
TupleSneak( Args ... args )
|
|
|
|
|
{
|
|
|
|
|
std::cerr << "I was the ctor called, with " << sizeof...( Args ) << " arguments." << std::endl;
|
|
|
|
|
tuple_for_each( std::tuple{ args... } ) <=
|
|
|
|
|
[]( const auto element )
|
|
|
|
|
{
|
|
|
|
|
std::cerr << "Element: " << element << std::endl;
|
|
|
|
|
};
|
|
|
|
|
this->set( { args... } );
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum class TestResult { Passed, Failed };
|
|
|
|
|
|
|
|
|
|
struct BlankBase {};
|
|
|
|
|
|
|
|
|
|
template< typename T >
|
|
|
|
|
static consteval auto
|
|
|
|
|
compute_base_f() noexcept
|
|
|
|
|
{
|
|
|
|
|
if constexpr ( Aggregate< T > ) return std::type_identity< TupleSneak< T, list_from_tuple_t< Reflection::aggregate_tuple_t< T > > > >{};
|
|
|
|
|
else if constexpr( std::is_class_v< T > ) return std::type_identity< T >{};
|
|
|
|
|
else return std::type_identity< BlankBase >{};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template< typename T >
|
|
|
|
|
using compute_base_t= typename decltype( compute_base_f< std::decay_t< T > >() )::type;
|
|
|
|
|
|
|
|
|
|
template< typename return_type, OutputMode outputMode >
|
|
|
|
|
struct BasicUniversalHandler;
|
|
|
|
|
|
|
|
|
|
template< Primitive return_type, OutputMode outputMode >
|
|
|
|
|
struct BasicUniversalHandler< return_type, outputMode >
|
|
|
|
|
{
|
|
|
|
|
using Invoker= std::function< return_type () >;
|
|
|
|
|
std::function< TestResult ( Invoker, const std::string & ) > impl;
|
|
|
|
|
|
|
|
|
|
TestResult
|
|
|
|
|
operator() ( Invoker invoker, const std::string &comment ) const
|
|
|
|
|
{
|
|
|
|
|
return impl( invoker, comment );
|
|
|
|
|
//if constexpr( std::is_base_of_v< std::decay_t< return_type >, ComputedBase > )
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if 1
|
|
|
|
|
BasicUniversalHandler( const return_type expected )
|
|
|
|
|
: impl
|
|
|
|
|
{
|
|
|
|
|
[expected]( Invoker invoker, const std::string &comment )
|
|
|
|
|
{
|
|
|
|
|
const auto witness= Utility::evaluate <=[&]() -> std::optional< return_type >
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
return invoker();
|
|
|
|
|
}
|
|
|
|
|
catch( ... )
|
|
|
|
|
{
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
const auto result= witness == expected ? TestResult::Passed : TestResult::Failed;
|
|
|
|
|
|
|
|
|
|
if( result == TestResult::Failed )
|
|
|
|
|
{
|
|
|
|
|
if( witness.has_value() )
|
|
|
|
|
{
|
|
|
|
|
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
|
|
|
|
printDebugging< outputMode >( witness.value(), expected );
|
|
|
|
|
}
|
|
|
|
|
else std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": Unexpected exception in \"" << comment << '"' << std::endl;
|
|
|
|
|
}
|
|
|
|
|
else std::cout << " " << C::testPass << "PASSED CASE" << resetStyle << ": " << comment << std::endl;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
{}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
template< typename ... Args >
|
|
|
|
|
requires ConstructibleFrom< return_type, std::decay_t< Args >... >
|
|
|
|
|
BasicUniversalHandler( Args &&... expected_init )
|
|
|
|
|
: BasicUniversalHandler( return_type{ std::forward< Args >( expected_init )... } )
|
|
|
|
|
{}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if 1
|
|
|
|
|
template< typename T >
|
|
|
|
|
requires( not SameAs< T, void > )
|
|
|
|
|
BasicUniversalHandler( std::type_identity< T > ) : impl
|
|
|
|
|
{
|
|
|
|
|
[]( Invoker invoker, const std::string &comment )
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
std::ignore= invoker();
|
|
|
|
|
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
|
|
|
|
return TestResult::Failed;
|
|
|
|
|
}
|
|
|
|
|
catch( const T & )
|
|
|
|
|
{
|
|
|
|
|
std::cout << " " << C::testPass << "PASSED CASE" << resetStyle << ": " << comment << std::endl;
|
|
|
|
|
return TestResult::Passed;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
template< typename T >
|
|
|
|
|
requires( SameAs< T, std::type_identity< void > > or SameAs< T, std::nothrow_t > )
|
|
|
|
|
BasicUniversalHandler( T ) : impl
|
|
|
|
|
{
|
|
|
|
|
[]( Invoker invoker, const std::string &comment )
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
std::ignore= invoker();
|
|
|
|
|
std::cout << " " << C::testPass << "PASSED CASE" << resetStyle << ": " << comment << std::endl;
|
|
|
|
|
return TestResult::Passed;
|
|
|
|
|
}
|
|
|
|
|
catch( ... )
|
|
|
|
|
{
|
|
|
|
|
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
|
|
|
|
return TestResult::Failed;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
template< DerivedFrom< std::exception > T >
|
|
|
|
|
BasicUniversalHandler( const T exemplar ) : impl
|
|
|
|
|
{
|
|
|
|
|
[expected= std::string{ exemplar.what() }]( Invoker invoker, const std::string &comment )
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
invoker();
|
|
|
|
|
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
|
|
|
|
std::cout << " " << C::testInfo << "NOTE" << resetStyle << ": expected exception `"
|
|
|
|
|
<< typeid( T ).name()
|
|
|
|
|
<< "` wasn't thrown." << std::endl;
|
|
|
|
|
return TestResult::Failed;
|
|
|
|
|
}
|
|
|
|
|
catch( const T &ex )
|
|
|
|
|
{
|
|
|
|
|
const std::string witness= ex.what();
|
|
|
|
|
const TestResult rv= witness == expected ? TestResult::Passed : TestResult::Failed;
|
|
|
|
|
if( rv == TestResult::Failed )
|
|
|
|
|
{
|
|
|
|
|
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
|
|
|
|
std::cout << " " << C::testInfo << "NOTE" << resetStyle << ": expected message did not match." << std::endl;
|
|
|
|
|
printDebugging< outputMode >( witness, expected );
|
|
|
|
|
}
|
|
|
|
|
return rv;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
{}
|
|
|
|
|
#endif
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template< Aggregate return_type, OutputMode outputMode >
|
|
|
|
|
struct BasicUniversalHandler< return_type, outputMode >
|
|
|
|
|
: compute_base_t< return_type >
|
|
|
|
|
{
|
|
|
|
|
using ComputedBase= compute_base_t< return_type >;
|
|
|
|
|
using ComputedBase::ComputedBase;
|
|
|
|
|
|
|
|
|
|
using Invoker= std::function< return_type () >;
|
|
|
|
|
|
|
|
|
|
std::function< TestResult ( Invoker, const std::string & ) > impl;
|
|
|
|
|
|
|
|
|
|
TestResult
|
|
|
|
|
operator() ( Invoker invoker, const std::string &comment ) const
|
|
|
|
|
{
|
|
|
|
|
if( impl != nullptr ) return impl( invoker, comment );
|
|
|
|
|
//if constexpr( std::is_base_of_v< std::decay_t< return_type >, ComputedBase > )
|
|
|
|
|
if constexpr( true )
|
|
|
|
|
{
|
|
|
|
|
const return_type *const expected_p= this;
|
|
|
|
|
const auto expected= *expected_p;
|
|
|
|
|
breakpoint();
|
|
|
|
|
const auto witness= Utility::evaluate <=[&]() -> std::optional< return_type >
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
return invoker();
|
|
|
|
|
}
|
|
|
|
|
catch( ... )
|
|
|
|
|
{
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
const auto result= witness == expected ? TestResult::Passed : TestResult::Failed;
|
|
|
|
|
|
|
|
|
|
if( result == TestResult::Failed )
|
|
|
|
|
{
|
|
|
|
|
if( witness.has_value() )
|
|
|
|
|
{
|
|
|
|
|
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
|
|
|
|
printDebugging< outputMode >( witness.value(), expected );
|
|
|
|
|
}
|
|
|
|
|
else std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": Unexpected exception in \"" << comment << '"' << std::endl;
|
|
|
|
|
}
|
|
|
|
|
else std::cout << " " << C::testPass << "PASSED CASE" << resetStyle << ": " << comment << std::endl;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
else throw std::logic_error( "Somehow we didn't setup impl, and it's not an adapted case!" );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
template< typename T_= return_type, typename= std::enable_if_t< not std::is_class_v< std::decay_t< T_ > > > >
|
|
|
|
|
BasicUniversalHandler( const T_ expected )
|
|
|
|
|
: impl
|
|
|
|
|
{
|
|
|
|
|
[expected]( Invoker invoker, const std::string &comment )
|
|
|
|
|
{
|
|
|
|
|
static_assert( not Aggregate< T_ > );
|
|
|
|
|
static_assert( not std::is_class_v< T_ > );
|
|
|
|
|
const return_type witness= invoker();
|
|
|
|
|
const auto result= witness == expected ? TestResult::Passed : TestResult::Failed;
|
|
|
|
|
|
|
|
|
|
if( result == TestResult::Failed )
|
|
|
|
|
{
|
|
|
|
|
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
|
|
|
|
printDebugging< outputMode >( witness, expected );
|
|
|
|
|
}
|
|
|
|
|
else std::cout << " " << C::testPass << "PASSED CASE" << resetStyle << ": " << comment << std::endl;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
{}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
template< typename ... Args >
|
|
|
|
|
requires ConstructibleFrom< return_type, std::decay_t< Args >... >
|
|
|
|
|
BasicUniversalHandler( Args &&... expected_init )
|
|
|
|
|
: BasicUniversalHandler( return_type{ std::forward< Args >( expected_init )... } )
|
|
|
|
|
{}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if 1
|
|
|
|
|
template< typename T >
|
|
|
|
|
requires( not SameAs< T, void > )
|
|
|
|
|
BasicUniversalHandler( std::type_identity< T > ) : impl
|
|
|
|
|
{
|
|
|
|
|
[]( Invoker invoker, const std::string &comment )
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
std::ignore= invoker();
|
|
|
|
|
breakpoint();
|
|
|
|
|
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
|
|
|
|
return TestResult::Failed;
|
|
|
|
|
}
|
|
|
|
|
catch( const T & )
|
|
|
|
|
{
|
|
|
|
|
std::cout << " " << C::testPass << "PASSED CASE" << resetStyle << ": " << comment << std::endl;
|
|
|
|
|
return TestResult::Passed;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
template< typename T >
|
|
|
|
|
requires( SameAs< T, std::type_identity< void > > or SameAs< T, std::nothrow_t > )
|
|
|
|
|
BasicUniversalHandler( T ) : impl
|
|
|
|
|
{
|
|
|
|
|
[]( Invoker invoker, const std::string &comment )
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
std::ignore= invoker();
|
|
|
|
|
std::cout << " " << C::testPass << "PASSED CASE" << resetStyle << ": " << comment << std::endl;
|
|
|
|
|
return TestResult::Passed;
|
|
|
|
|
}
|
|
|
|
|
catch( ... )
|
|
|
|
|
{
|
|
|
|
|
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
|
|
|
|
return TestResult::Failed;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
template< DerivedFrom< std::exception > T >
|
|
|
|
|
BasicUniversalHandler( const T exemplar ) : impl
|
|
|
|
|
{
|
|
|
|
|
[expected= std::string{ exemplar.what() }]( Invoker invoker, const std::string &comment )
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
invoker();
|
|
|
|
|
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
|
|
|
|
std::cout << " " << C::testInfo << "NOTE" << resetStyle << ": expected exception `"
|
|
|
|
|
<< typeid( T ).name()
|
|
|
|
|
<< "` wasn't thrown." << std::endl;
|
|
|
|
|
return TestResult::Failed;
|
|
|
|
|
}
|
|
|
|
|
catch( const T &ex )
|
|
|
|
|
{
|
|
|
|
|
const std::string witness= ex.what();
|
|
|
|
|
const TestResult rv= witness == expected ? TestResult::Passed : TestResult::Failed;
|
|
|
|
|
if( rv == TestResult::Failed )
|
|
|
|
|
{
|
|
|
|
|
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
|
|
|
|
std::cout << " " << C::testInfo << "NOTE" << resetStyle << ": expected message did not match." << std::endl;
|
|
|
|
|
printDebugging< outputMode >( witness, expected );
|
|
|
|
|
}
|
|
|
|
|
return rv;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
{}
|
|
|
|
|
#endif
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template< typename return_type, OutputMode outputMode >
|
|
|
|
|
struct BasicUniversalHandler
|
|
|
|
|
: return_type
|
|
|
|
|
{
|
|
|
|
|
using return_type::return_type;
|
|
|
|
|
|
|
|
|
|
BasicUniversalHandler( return_type rt ) : return_type( rt ) {}
|
|
|
|
|
|
|
|
|
|
using Invoker= std::function< return_type () >;
|
|
|
|
|
|
|
|
|
|
std::function< TestResult ( Invoker, const std::string & ) > impl;
|
|
|
|
|
|
|
|
|
|
TestResult
|
|
|
|
|
operator() ( Invoker invoker, const std::string &comment ) const
|
|
|
|
|
{
|
|
|
|
|
if( impl != nullptr ) return impl( invoker, comment );
|
|
|
|
|
//if constexpr( std::is_base_of_v< std::decay_t< return_type >, ComputedBase > )
|
|
|
|
|
if constexpr( true )
|
|
|
|
|
{
|
|
|
|
|
const return_type *const expected_p= this;
|
|
|
|
|
const auto expected= *expected_p;
|
|
|
|
|
const auto witness= Utility::evaluate <=[&]() -> std::optional< return_type >
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
return invoker();
|
|
|
|
|
}
|
|
|
|
|
catch( ... )
|
|
|
|
|
{
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
const auto result= witness == expected ? TestResult::Passed : TestResult::Failed;
|
|
|
|
|
|
|
|
|
|
if( result == TestResult::Failed )
|
|
|
|
|
{
|
|
|
|
|
if( witness.has_value() )
|
|
|
|
|
{
|
|
|
|
|
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
|
|
|
|
printDebugging< outputMode >( witness.value(), expected );
|
|
|
|
|
}
|
|
|
|
|
else std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": Unexpected exception in \"" << comment << '"' << std::endl;
|
|
|
|
|
}
|
|
|
|
|
else std::cout << " " << C::testPass << "PASSED CASE" << resetStyle << ": " << comment << std::endl;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
else throw std::logic_error( "Somehow we didn't setup impl, and it's not an adapted case!" );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
template< typename T_= return_type, typename= std::enable_if_t< not std::is_class_v< std::decay_t< T_ > > > >
|
|
|
|
|
BasicUniversalHandler( const T_ expected )
|
|
|
|
|
: impl
|
|
|
|
|
{
|
|
|
|
|
[expected]( Invoker invoker, const std::string &comment )
|
|
|
|
|
{
|
|
|
|
|
static_assert( not Aggregate< T_ > );
|
|
|
|
|
static_assert( not std::is_class_v< T_ > );
|
|
|
|
|
const return_type witness= invoker();
|
|
|
|
|
const auto result= witness == expected ? TestResult::Passed : TestResult::Failed;
|
|
|
|
|
|
|
|
|
|
if( result == TestResult::Failed )
|
|
|
|
|
{
|
|
|
|
|
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
|
|
|
|
printDebugging< outputMode >( witness, expected );
|
|
|
|
|
}
|
|
|
|
|
else std::cout << " " << C::testPass << "PASSED CASE" << resetStyle << ": " << comment << std::endl;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
{}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
template< typename ... Args >
|
|
|
|
|
requires ConstructibleFrom< return_type, std::decay_t< Args >... >
|
|
|
|
|
BasicUniversalHandler( Args &&... expected_init )
|
|
|
|
|
: BasicUniversalHandler( return_type{ std::forward< Args >( expected_init )... } )
|
|
|
|
|
{}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if 1
|
|
|
|
|
template< typename T >
|
|
|
|
|
requires( not SameAs< T, void > )
|
|
|
|
|
BasicUniversalHandler( std::type_identity< T > ) : impl
|
|
|
|
|
{
|
|
|
|
|
[]( Invoker invoker, const std::string &comment )
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
std::ignore= invoker();
|
|
|
|
|
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
|
|
|
|
return TestResult::Failed;
|
|
|
|
|
}
|
|
|
|
|
catch( const T & )
|
|
|
|
|
{
|
|
|
|
|
std::cout << " " << C::testPass << "PASSED CASE" << resetStyle << ": " << comment << std::endl;
|
|
|
|
|
return TestResult::Passed;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
template< typename T >
|
|
|
|
|
requires( SameAs< T, std::type_identity< void > > or SameAs< T, std::nothrow_t > )
|
|
|
|
|
BasicUniversalHandler( T ) : impl
|
|
|
|
|
{
|
|
|
|
|
[]( Invoker invoker, const std::string &comment )
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
std::ignore= invoker();
|
|
|
|
|
std::cout << " " << C::testPass << "PASSED CASE" << resetStyle << ": " << comment << std::endl;
|
|
|
|
|
return TestResult::Passed;
|
|
|
|
|
}
|
|
|
|
|
catch( ... )
|
|
|
|
|
{
|
|
|
|
|
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
|
|
|
|
return TestResult::Failed;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
template< DerivedFrom< std::exception > T >
|
|
|
|
|
BasicUniversalHandler( const T exemplar ) : impl
|
|
|
|
|
{
|
|
|
|
|
[expected= std::string{ exemplar.what() }]( Invoker invoker, const std::string &comment )
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
invoker();
|
|
|
|
|
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
|
|
|
|
std::cout << " " << C::testInfo << "NOTE" << resetStyle << ": expected exception `"
|
|
|
|
|
<< typeid( T ).name()
|
|
|
|
|
<< "` wasn't thrown." << std::endl;
|
|
|
|
|
return TestResult::Failed;
|
|
|
|
|
}
|
|
|
|
|
catch( const T &ex )
|
|
|
|
|
{
|
|
|
|
|
const std::string witness= ex.what();
|
|
|
|
|
const TestResult rv= witness == expected ? TestResult::Passed : TestResult::Failed;
|
|
|
|
|
if( rv == TestResult::Failed )
|
|
|
|
|
{
|
|
|
|
|
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
|
|
|
|
std::cout << " " << C::testInfo << "NOTE" << resetStyle << ": expected message did not match." << std::endl;
|
|
|
|
|
printDebugging< outputMode >( witness, expected );
|
|
|
|
|
}
|
|
|
|
|
return rv;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
{}
|
|
|
|
|
#endif
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template< typename F >
|
|
|
|
|
concept FunctionVariable=
|
|
|
|
|
requires( const F &f )
|
|
|
|
@ -66,8 +570,6 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
|
|
|
|
template< FunctionVariable auto, OutputMode outputMode= OutputMode::All > struct TableTest;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline void breakpoint() {}
|
|
|
|
|
|
|
|
|
|
namespace C
|
|
|
|
|
{
|
|
|
|
|
const bool debug= false;
|
|
|
|
@ -288,7 +790,7 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct ExceptionCases
|
|
|
|
|
struct ExceptionCases_real
|
|
|
|
|
{
|
|
|
|
|
using Invoker= std::function< void () >;
|
|
|
|
|
struct ExceptionHandler
|
|
|
|
@ -312,6 +814,23 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
template< typename T >
|
|
|
|
|
requires( SameAs< T, std::type_identity< void > > or SameAs< T, std::nothrow_t > )
|
|
|
|
|
ExceptionHandler( T ) : impl
|
|
|
|
|
{
|
|
|
|
|
[]( Invoker invoker )
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
invoker();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
catch( ... ) { return false; }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
template< typename T >
|
|
|
|
|
requires( not SameAs< T, void > )
|
|
|
|
|
ExceptionHandler( std::type_identity< T > ) : impl
|
|
|
|
|
{
|
|
|
|
|
[]( Invoker invoker )
|
|
|
|
@ -376,7 +895,7 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
explicit
|
|
|
|
|
ExceptionCases( std::initializer_list< TestDescription > initList )
|
|
|
|
|
ExceptionCases_real( std::initializer_list< TestDescription > initList )
|
|
|
|
|
: tests( initList ) {}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
@ -401,65 +920,65 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class UniversalCases
|
|
|
|
|
using ComputedBase= compute_base_t< return_type >;
|
|
|
|
|
|
|
|
|
|
struct UniversalCases
|
|
|
|
|
{
|
|
|
|
|
using RunDescription= std::tuple< std::string, args_type, return_type >;
|
|
|
|
|
using Invoker= std::function< return_type () >;
|
|
|
|
|
|
|
|
|
|
enum class TestResult { Passed, Failed };
|
|
|
|
|
using UniversalHandler= BasicUniversalHandler< return_type, outputMode >;
|
|
|
|
|
|
|
|
|
|
struct UniversalHandler
|
|
|
|
|
using TestDescription= std::tuple< std::string, args_type, UniversalHandler >;
|
|
|
|
|
std::vector< TestDescription > tests;
|
|
|
|
|
|
|
|
|
|
UniversalCases( std::initializer_list< TestDescription > initList )
|
|
|
|
|
{
|
|
|
|
|
std::function< TestResult ( Invoker, const std::string & ) > impl;
|
|
|
|
|
|
|
|
|
|
bool operator() ( Invoker invoker ) const { return impl( invoker ); }
|
|
|
|
|
|
|
|
|
|
UniversalHandler( const return_type expected ) : impl
|
|
|
|
|
for( const auto &desc: initList )
|
|
|
|
|
{
|
|
|
|
|
[expected]( Invoker invoker, const std::string &comment )
|
|
|
|
|
if constexpr( Aggregate< return_type > )
|
|
|
|
|
{
|
|
|
|
|
const auto witness= invoker();
|
|
|
|
|
const auto result= witness == expected ? TestResult::Passed : TestResult::Failed;
|
|
|
|
|
std::cerr << "Case: " << std::get< 0 >( desc );
|
|
|
|
|
const return_type &v= std::get< 2 >( desc );
|
|
|
|
|
std::cerr << " (" << v << ")" << std::endl;
|
|
|
|
|
tests.push_back( desc );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
auto invoker= [&]
|
|
|
|
|
{
|
|
|
|
|
breakpoint();
|
|
|
|
|
return std::apply( function, params );
|
|
|
|
|
};
|
|
|
|
|
const TestResult result= checker( invoker, comment );
|
|
|
|
|
if( result == TestResult::Failed )
|
|
|
|
|
{
|
|
|
|
|
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
|
|
|
|
printDebugging< outputMode >( witness, expected );
|
|
|
|
|
++failureCount;
|
|
|
|
|
}
|
|
|
|
|
else std::cout << " " << C::testPass << "PASSED CASE" << resetStyle << ": " << comment << std::endl;
|
|
|
|
|
return result;
|
|
|
|
|
breakpoint();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
template< typename T >
|
|
|
|
|
UniversalHandler( std::type_identity< T > ) : impl
|
|
|
|
|
{
|
|
|
|
|
[]( Invoker invoker )
|
|
|
|
|
{
|
|
|
|
|
try { std::ignore= invoker(); }
|
|
|
|
|
catch( const T & ) { return TestResult::Passed; }
|
|
|
|
|
return TestResult::Failed;
|
|
|
|
|
return failureCount;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
UniversalHandler( const DerivedFrom< std::exception > auto exemplar ) : impl
|
|
|
|
|
{
|
|
|
|
|
[expected= std::string{ exemplar.what() }]( Invoker invoker )
|
|
|
|
|
{
|
|
|
|
|
throw "Unimpl";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
{}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
using TestDescription= std::tuple< std::string, args_type, UniversalHandler >;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// When the `UniversalCases` impl is ready to go, then this alias shim can be redirected to that form. Then I can
|
|
|
|
|
// retire the `ExceptionCases` and `ExecutionCases` forms and replace them with an alias to `UniversalCases`.
|
|
|
|
|
using Cases= ExecutionCases;
|
|
|
|
|
//using Cases= ExecutionCases;
|
|
|
|
|
using Cases= UniversalCases;
|
|
|
|
|
|
|
|
|
|
//using ExceptionCases= ExceptionCases_real;
|
|
|
|
|
using ExceptionCases= UniversalCases;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#ifdef DISABLED
|
|
|
|
|