forked from Alepha/Alepha
I think I have everything working with universal testing cases.
This commit is contained in:
@ -60,13 +60,36 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
|||||||
template< OutputMode outputMode, typename T >
|
template< OutputMode outputMode, typename T >
|
||||||
void printDebugging( const T &witness, const T &expected );
|
void printDebugging( const T &witness, const T &expected );
|
||||||
|
|
||||||
template< Aggregate Agg, typename ... Args >
|
template< Aggregate Agg, TypeListType >
|
||||||
struct TupleSneak
|
struct TupleSneak;
|
||||||
|
|
||||||
|
template< Aggregate Agg >
|
||||||
|
struct TupleSneak< Agg, Nil >
|
||||||
: Agg
|
: 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 )
|
TupleSneak( Args ... args )
|
||||||
: Agg( 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 };
|
enum class TestResult { Passed, Failed };
|
||||||
@ -77,7 +100,7 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
|||||||
static consteval auto
|
static consteval auto
|
||||||
compute_base_f() noexcept
|
compute_base_f() noexcept
|
||||||
{
|
{
|
||||||
if constexpr ( Aggregate< T > ) return std::type_identity< TupleSneak< T, Reflection::aggregate_tuple_t< T > > >{};
|
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 if constexpr( std::is_class_v< T > ) return std::type_identity< T >{};
|
||||||
else return std::type_identity< BlankBase >{};
|
else return std::type_identity< BlankBase >{};
|
||||||
}
|
}
|
||||||
@ -107,13 +130,27 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
|||||||
{
|
{
|
||||||
[expected]( Invoker invoker, const std::string &comment )
|
[expected]( Invoker invoker, const std::string &comment )
|
||||||
{
|
{
|
||||||
const return_type witness= invoker();
|
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;
|
const auto result= witness == expected ? TestResult::Passed : TestResult::Failed;
|
||||||
|
|
||||||
if( result == TestResult::Failed )
|
if( result == TestResult::Failed )
|
||||||
|
{
|
||||||
|
if( witness.has_value() )
|
||||||
{
|
{
|
||||||
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
||||||
printDebugging< outputMode >( witness, expected );
|
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;
|
else std::cout << " " << C::testPass << "PASSED CASE" << resetStyle << ": " << comment << std::endl;
|
||||||
return result;
|
return result;
|
||||||
@ -164,7 +201,7 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
|||||||
std::cout << " " << C::testPass << "PASSED CASE" << resetStyle << ": " << comment << std::endl;
|
std::cout << " " << C::testPass << "PASSED CASE" << resetStyle << ": " << comment << std::endl;
|
||||||
return TestResult::Passed;
|
return TestResult::Passed;
|
||||||
}
|
}
|
||||||
catch( const T & )
|
catch( ... )
|
||||||
{
|
{
|
||||||
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
||||||
return TestResult::Failed;
|
return TestResult::Failed;
|
||||||
@ -207,10 +244,10 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
|||||||
|
|
||||||
template< Aggregate return_type, OutputMode outputMode >
|
template< Aggregate return_type, OutputMode outputMode >
|
||||||
struct BasicUniversalHandler< return_type, outputMode >
|
struct BasicUniversalHandler< return_type, outputMode >
|
||||||
: return_type
|
: compute_base_t< return_type >
|
||||||
{
|
{
|
||||||
using ComputedBase= compute_base_t< return_type >;
|
using ComputedBase= compute_base_t< return_type >;
|
||||||
//using ComputedBase::ComputedBase;
|
using ComputedBase::ComputedBase;
|
||||||
|
|
||||||
using Invoker= std::function< return_type () >;
|
using Invoker= std::function< return_type () >;
|
||||||
|
|
||||||
@ -225,14 +262,28 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
|||||||
{
|
{
|
||||||
const return_type *const expected_p= this;
|
const return_type *const expected_p= this;
|
||||||
const auto expected= *expected_p;
|
const auto expected= *expected_p;
|
||||||
const return_type witness= invoker();
|
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;
|
const auto result= witness == expected ? TestResult::Passed : TestResult::Failed;
|
||||||
|
|
||||||
if( result == TestResult::Failed )
|
if( result == TestResult::Failed )
|
||||||
|
{
|
||||||
|
if( witness.has_value() )
|
||||||
{
|
{
|
||||||
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
||||||
printDebugging< outputMode >( witness, expected );
|
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;
|
else std::cout << " " << C::testPass << "PASSED CASE" << resetStyle << ": " << comment << std::endl;
|
||||||
return result;
|
return result;
|
||||||
@ -272,7 +323,7 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
|||||||
{}
|
{}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if 0
|
#if 1
|
||||||
template< typename T >
|
template< typename T >
|
||||||
requires( not SameAs< T, void > )
|
requires( not SameAs< T, void > )
|
||||||
BasicUniversalHandler( std::type_identity< T > ) : impl
|
BasicUniversalHandler( std::type_identity< T > ) : impl
|
||||||
@ -282,6 +333,7 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
std::ignore= invoker();
|
std::ignore= invoker();
|
||||||
|
breakpoint();
|
||||||
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
||||||
return TestResult::Failed;
|
return TestResult::Failed;
|
||||||
}
|
}
|
||||||
@ -306,7 +358,7 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
|||||||
std::cout << " " << C::testPass << "PASSED CASE" << resetStyle << ": " << comment << std::endl;
|
std::cout << " " << C::testPass << "PASSED CASE" << resetStyle << ": " << comment << std::endl;
|
||||||
return TestResult::Passed;
|
return TestResult::Passed;
|
||||||
}
|
}
|
||||||
catch( const T & )
|
catch( ... )
|
||||||
{
|
{
|
||||||
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
||||||
return TestResult::Failed;
|
return TestResult::Failed;
|
||||||
@ -368,14 +420,27 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
|||||||
{
|
{
|
||||||
const return_type *const expected_p= this;
|
const return_type *const expected_p= this;
|
||||||
const auto expected= *expected_p;
|
const auto expected= *expected_p;
|
||||||
const return_type witness= invoker();
|
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;
|
const auto result= witness == expected ? TestResult::Passed : TestResult::Failed;
|
||||||
|
|
||||||
if( result == TestResult::Failed )
|
if( result == TestResult::Failed )
|
||||||
|
{
|
||||||
|
if( witness.has_value() )
|
||||||
{
|
{
|
||||||
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
||||||
printDebugging< outputMode >( witness, expected );
|
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;
|
else std::cout << " " << C::testPass << "PASSED CASE" << resetStyle << ": " << comment << std::endl;
|
||||||
return result;
|
return result;
|
||||||
@ -449,7 +514,7 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
|||||||
std::cout << " " << C::testPass << "PASSED CASE" << resetStyle << ": " << comment << std::endl;
|
std::cout << " " << C::testPass << "PASSED CASE" << resetStyle << ": " << comment << std::endl;
|
||||||
return TestResult::Passed;
|
return TestResult::Passed;
|
||||||
}
|
}
|
||||||
catch( const T & )
|
catch( ... )
|
||||||
{
|
{
|
||||||
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
std::cout << " " << C::testFail << "FAILED CASE" << resetStyle << ": " << comment << std::endl;
|
||||||
return TestResult::Failed;
|
return TestResult::Failed;
|
||||||
@ -759,7 +824,7 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
|||||||
invoker();
|
invoker();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch( const T & ) { return false; }
|
catch( ... ) { return false; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{}
|
{}
|
||||||
@ -868,7 +933,18 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
|||||||
std::vector< TestDescription > tests;
|
std::vector< TestDescription > tests;
|
||||||
|
|
||||||
UniversalCases( std::initializer_list< TestDescription > initList )
|
UniversalCases( std::initializer_list< TestDescription > initList )
|
||||||
: tests( initList ) {}
|
{
|
||||||
|
for( const auto &desc: initList )
|
||||||
|
{
|
||||||
|
if constexpr( Aggregate< return_type > )
|
||||||
|
{
|
||||||
|
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
|
int
|
||||||
operator() () const
|
operator() () const
|
||||||
@ -877,8 +953,11 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
|||||||
for( const auto &[ comment, params, checker ]: tests )
|
for( const auto &[ comment, params, checker ]: tests )
|
||||||
{
|
{
|
||||||
if( C::debugCaseTypes ) std::cerr << boost::core::demangle( typeid( params ).name() ) << std::endl;
|
if( C::debugCaseTypes ) std::cerr << boost::core::demangle( typeid( params ).name() ) << std::endl;
|
||||||
|
auto invoker= [&]
|
||||||
|
{
|
||||||
breakpoint();
|
breakpoint();
|
||||||
auto invoker= [&]{ return std::apply( function, params ); };
|
return std::apply( function, params );
|
||||||
|
};
|
||||||
const TestResult result= checker( invoker, comment );
|
const TestResult result= checker( invoker, comment );
|
||||||
if( result == TestResult::Failed )
|
if( result == TestResult::Failed )
|
||||||
{
|
{
|
||||||
@ -886,6 +965,7 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
|||||||
++failureCount;
|
++failureCount;
|
||||||
}
|
}
|
||||||
else std::cout << " " << C::testPass << "PASSED CASE" << resetStyle << ": " << comment << std::endl;
|
else std::cout << " " << C::testPass << "PASSED CASE" << resetStyle << ": " << comment << std::endl;
|
||||||
|
breakpoint();
|
||||||
}
|
}
|
||||||
|
|
||||||
return failureCount;
|
return failureCount;
|
||||||
@ -894,11 +974,11 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test
|
|||||||
|
|
||||||
// When the `UniversalCases` impl is ready to go, then this alias shim can be redirected to that form. Then I can
|
// 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`.
|
// retire the `ExceptionCases` and `ExecutionCases` forms and replace them with an alias to `UniversalCases`.
|
||||||
using Cases= ExecutionCases;
|
//using Cases= ExecutionCases;
|
||||||
//using Cases= UniversalCases;
|
using Cases= UniversalCases;
|
||||||
|
|
||||||
using ExceptionCases= ExceptionCases_real;
|
//using ExceptionCases= ExceptionCases_real;
|
||||||
//using ExceptionCases= UniversalCases;
|
using ExceptionCases= UniversalCases;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef DISABLED
|
#ifdef DISABLED
|
||||||
|
|||||||
@ -1,9 +1,15 @@
|
|||||||
static_assert( __cplusplus > 2020'00 );
|
static_assert( __cplusplus > 2020'00 );
|
||||||
|
|
||||||
#include <Alepha/Testing/TableTest.h>
|
#include <Alepha/Testing/TableTest.h>
|
||||||
|
|
||||||
#include <Alepha/Testing/test.h>
|
#include <Alepha/Testing/test.h>
|
||||||
#include <Alepha/Utility/evaluation_helpers.h>
|
#include <Alepha/Utility/evaluation_helpers.h>
|
||||||
|
|
||||||
|
#include <Alepha/IOStreams/delimiters.h>
|
||||||
|
#include <Alepha/IOStreams/OStreamable.h>
|
||||||
|
|
||||||
|
#include <Alepha/comparisons.h>
|
||||||
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
@ -28,11 +34,49 @@ namespace
|
|||||||
{ "Righthand identity", { 25, 0 }, 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 <=[]
|
auto alltests= enroll <=[]
|
||||||
{
|
{
|
||||||
"addition.two.local"_test <=TableTest< add >::Cases
|
"addition.two.local"_test <=TableTest< add >::Cases
|
||||||
{
|
{
|
||||||
{ "Negative case", { -10, -20 }, -30 },
|
{ "Negative case", { -10, -20 }, -30 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
"Can we use Aggregates with universal cases, correctly?"_test <=
|
||||||
|
TableTest
|
||||||
|
<
|
||||||
|
[]( const int x )
|
||||||
|
{
|
||||||
|
if( x < 0 ) throw std::runtime_error{ "Cannot be negative." };
|
||||||
|
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 }, 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." } },
|
||||||
|
#endif
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user