forked from Alepha/Alepha
239 lines
6.9 KiB
C++
239 lines
6.9 KiB
C++
static_assert( __cplusplus > 2020'99 );
|
|
|
|
#pragma once
|
|
|
|
#include <Alepha/Alepha.h>
|
|
|
|
#include <utility>
|
|
#include <iostream>
|
|
|
|
#include <Alepha/Meta/functor_traits.h>
|
|
#include <Alepha/Meta/require_relationship.h>
|
|
|
|
#include <Alepha/Truss/function.h>
|
|
|
|
namespace Alepha
|
|
{
|
|
inline namespace Aluminum
|
|
{
|
|
namespace Mockination
|
|
{
|
|
template< std::size_t order, std::size_t count >
|
|
struct overload_count
|
|
{
|
|
using type= overload_count;
|
|
static constexpr std::size_t value= count;
|
|
};
|
|
|
|
// We'd like a `boost::mpl::map`, probably. A metafunction for now.
|
|
|
|
template< typename ... Args > struct count_map;
|
|
|
|
template< std::size_t order, std::size_t count >
|
|
struct count_map< overload_count< order, count > >
|
|
{
|
|
using entry_type= overload_count< order, count >;
|
|
};
|
|
|
|
template< std::size_t order, std::size_t count, typename ... Args >
|
|
struct count_map< overload_count< order, count >, Args... >
|
|
{
|
|
using entry_type= overload_count< order, count >;
|
|
};
|
|
|
|
//template< template CountMap, std::size_t order_key > struct find_entry;
|
|
|
|
#if 0
|
|
template< std::size_t order_key, std::size_t count, typename ... Args >
|
|
find_entry< count_map< overload_count< order_key, count >, Args... >,
|
|
{
|
|
using type=
|
|
}
|
|
#endif
|
|
|
|
template< int id, typename Function > class MockFunctionImpl;
|
|
|
|
template< int id, typename Function, typename ... Selection > struct select_overload;
|
|
|
|
template< int id, typename Function >
|
|
struct select_overload< id, Function, Function >
|
|
{
|
|
using type= MockFunctionImpl< id, Function >;
|
|
};
|
|
|
|
template< int id, typename Function, typename Selection0, typename ... Selections >
|
|
struct select_overload< id, Function, Selection0, Selections... >
|
|
: select_overload< id, Function, Selections... > {};
|
|
|
|
template< int id, typename Function, typename ... Selections >
|
|
struct select_overload< id, Function, Function, Selections... >
|
|
{
|
|
using type= MockFunctionImpl< id, Function >;
|
|
};
|
|
|
|
|
|
class skip_execution {};
|
|
|
|
|
|
template< int id, typename ... Args >
|
|
class MockFunctionImpl< id, void ( Args ... ) >
|
|
{
|
|
public:
|
|
static Alepha::Truss::function< void ( Args ... ) > impl;
|
|
|
|
using return_type= void;
|
|
|
|
template< typename Needed >
|
|
using overload= typename select_overload< id, Needed, void ( Args... ) >::type;
|
|
|
|
MockFunctionImpl()= default;
|
|
|
|
static void clear() { impl= nullptr; }
|
|
|
|
void
|
|
operator() ( Args ... args ) const
|
|
{
|
|
if( impl == nullptr ) abort();
|
|
return impl( std::forward< Args >( args )... );
|
|
}
|
|
|
|
static void set_operation( Alepha::Truss::function< void ( Args ... ) > i )
|
|
{
|
|
std::cerr << "Set operation impl..." << std::endl;
|
|
impl= std::move( i );
|
|
}
|
|
|
|
static void set_operation_impl( Alepha::Truss::function< void ( Args ... ) > i ) { impl= std::move( i ); }
|
|
|
|
static void
|
|
add_operation( Alepha::Truss::function< void ( Args ... ) > i )
|
|
{
|
|
Alepha::Truss::function< void ( Args ... ) > first= impl ? impl : []( Args ... ){};
|
|
impl= [first, i]( Args... args )
|
|
{
|
|
try { i( args... ); } catch( const skip_execution & ) {}
|
|
first( args... );
|
|
};
|
|
}
|
|
};
|
|
template< int id, typename ... Args >
|
|
Alepha::Truss::function< void ( Args ... ) > MockFunctionImpl< id, void ( Args ... ) >::impl= nullptr;
|
|
|
|
template< int id, typename Rv, typename ... Args >
|
|
class MockFunctionImpl< id, Rv ( Args ... ) >
|
|
{
|
|
public:
|
|
static Alepha::Truss::function< Rv ( Args ... ) > impl;
|
|
|
|
using return_type= Rv;
|
|
|
|
template< typename Needed >
|
|
using overload= typename select_overload< id, Needed, Rv ( Args... ) >::type;
|
|
|
|
MockFunctionImpl()= default;
|
|
|
|
static void clear() { impl= nullptr; }
|
|
|
|
Rv operator() ( Args ... args ) const { return impl( std::forward< Args >( args )... ); }
|
|
|
|
static void
|
|
set_result( Rv r )
|
|
{
|
|
impl= [r]( Args ... args ){ return r; };
|
|
}
|
|
|
|
static void set_operation( Alepha::Truss::function< Rv ( Args ... ) > i ) { impl= std::move( i ); }
|
|
static void set_operation_impl( Alepha::Truss::function< Rv ( Args ... ) > i ) { impl= std::move( i ); }
|
|
|
|
static Rv
|
|
add_operation( Alepha::Truss::function< Rv ( Args ... ) > i )
|
|
{
|
|
impl= [first= impl, i]( Args ... args )
|
|
{
|
|
try { return i( args... ); } catch( const skip_execution & ) {}
|
|
return first( args... );
|
|
};
|
|
}
|
|
};
|
|
|
|
template< int id, typename Rv, typename ... Args >
|
|
Alepha::Truss::function< Rv ( Args... ) > MockFunctionImpl< id, Rv ( Args... ) >::impl= nullptr;
|
|
|
|
template< int id, typename ... Funcs > class MockFunction;
|
|
|
|
template< int id, typename Rv, typename ... Args >
|
|
class MockFunction< id, Rv( Args ... ) >
|
|
: public MockFunctionImpl< id, Rv( Args... ) >
|
|
{
|
|
public:
|
|
static void clear_all() { MockFunctionImpl< id, Rv( Args... ) >::clear(); }
|
|
};
|
|
|
|
template< typename M > struct match;
|
|
template< typename Class >
|
|
struct match< void (Class::*) ( std::size_t ) > : std::true_type
|
|
{
|
|
};
|
|
template< typename Class >
|
|
struct match< void (Class::*) ( std::size_t ) const > : std::true_type
|
|
{
|
|
};
|
|
|
|
template< typename T >
|
|
auto
|
|
soak_traits( T )//typename std::enable_if< std::is_class< T >::value, T >::type )
|
|
{
|
|
return typename Meta::functor_traits< decltype( &T::operator() ) >::type{};
|
|
}
|
|
|
|
template< typename Rv, typename ... Args >
|
|
Meta::functor_traits< Rv ( Args... ) >
|
|
soak_traits( Rv ( Args... ) )
|
|
{
|
|
return Meta::functor_traits< Rv ( Args... ) >{};
|
|
}
|
|
|
|
template< int id, typename Func0, typename ... Funcs >
|
|
class MockFunction< id, Func0, Funcs... >
|
|
: public MockFunctionImpl< id, Func0 >, public MockFunction< id, Funcs... >
|
|
{
|
|
public:
|
|
template< typename Needed >
|
|
using overload= typename select_overload< id, Needed, Func0, Funcs... >::type;
|
|
|
|
template< typename Callable >
|
|
static void
|
|
set_operation( Callable c )
|
|
{
|
|
std::cerr << "Set operation deduced..." << std::endl;
|
|
auto magic_traits= soak_traits( c );
|
|
using magic_traits_type= decltype( magic_traits );
|
|
using traits= typename magic_traits_type::type;
|
|
using ftype= typename traits::std_function_type;
|
|
|
|
static_assert( Meta::require_relationship< std::is_base_of,
|
|
MockFunctionImpl< id, typename traits::functor_type >,
|
|
MockFunction >::type::value,
|
|
"No overload exists in this mock for the specified function type." );
|
|
MockFunctionImpl< id, typename traits::functor_type >::set_operation_impl( c );
|
|
}
|
|
|
|
template< typename Callable, typename FuncType >
|
|
static void
|
|
set_operation( Callable c )
|
|
{
|
|
std::cerr << "Set operation forced..." << std::endl;
|
|
MockFunctionImpl< id, FuncType >::set_operation_impl( Alepha::Truss::function< FuncType >{ c } );
|
|
}
|
|
|
|
static void
|
|
clear_all()
|
|
{
|
|
MockFunctionImpl< id, Func0 >::clear();
|
|
MockFunction< id, Funcs... >::clear_all();
|
|
}
|
|
};
|
|
}
|
|
}
|
|
}
|