2023-04-27 19:38:37 +02:00
/*
MockSupport ( Test ) - verify test support for fixture and job dispatch
Copyright ( C ) Lumiera . org
2023 , Hermann Vosseler < Ichthyostega @ web . de >
This program is free software ; you can redistribute it and / or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation ; either version 2 of
the License , or ( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/** @file mock-support-test.cpp
* * unit test \ ref MockSupport_test
*/
# include "lib/test/run.hpp"
# include "steam/engine/mock-dispatcher.hpp"
2023-05-10 14:57:41 +02:00
# include "vault/engine/nop-job-functor.hpp"
2023-04-27 19:38:37 +02:00
# include "vault/engine/dummy-job.hpp"
2023-05-15 23:25:29 +02:00
# include "lib/iter-tree-explorer.hpp"
2023-05-10 13:50:19 +02:00
# include "lib/util-tuple.hpp"
2023-04-27 22:30:49 +02:00
# include "lib/util.hpp"
2023-05-15 23:25:29 +02:00
# include "lib/format-cout.hpp"
# include "lib/test/test-helper.hpp"
2023-05-23 01:06:22 +02:00
# include "lib/meta/duck-detector.hpp" ///////////////TODO WIP
2023-04-27 19:38:37 +02:00
using test : : Test ;
2023-05-10 13:50:19 +02:00
2023-04-27 19:38:37 +02:00
2023-05-15 23:25:29 +02:00
///////////////////////////////////////////////////////TODO WIP for investigation
namespace lib {
namespace iter_explorer {
template < class RES >
using DecoTraits = _DecoratorTraits < RES > ;
2023-05-23 01:06:22 +02:00
template < class SRC , class RES >
using ExpoTraits = _ExpanderTraits < SRC , RES > ;
2023-05-15 23:25:29 +02:00
} }
///////////////////////////////////////////////////////TODO WIP for investigation
2023-04-27 19:38:37 +02:00
namespace steam {
namespace engine {
namespace test {
2023-05-10 14:57:41 +02:00
using steam : : fixture : : Segment ;
2023-04-27 19:38:37 +02:00
using vault : : engine : : DummyJob ;
2023-05-15 23:25:29 +02:00
using lib : : singleValIterator ;
2023-05-10 14:57:41 +02:00
using util : : isSameObject ;
using util : : seqTuple ;
2023-05-10 03:59:46 +02:00
2023-05-23 01:06:22 +02:00
///////////////////////////////////////////////////////TODO WIP for investigation
template < class U >
struct ReBind
{
using type = typename U : : type ;
} ;
// template<typename X, typename SEL = void>
// struct has_TypeResult : std::false_type { };
//
// template<typename X>
// struct has_TypeResult<X, typename ReBind<X>::type> : std::true_type { };
//
// template<typename X>
// struct has_TypeResult<X, typename X::Type> : std::true_type { };
// using lib::meta::Yes_t;
// using lib::meta::No_t;
//
// template<typename TY>
// class HasNested_type
// {
// template<class X>
// static Yes_t check(typename X::type *);
// template<class X>
// static Yes_t check(typename X::Type *);
// template<class>
// static No_t check(...);
//
// public:
// static const bool value = (sizeof(Yes_t)==sizeof(check<TY>(0)));
// };
//
// template<typename X>
// struct has_TypeResult : std::bool_constant<HasNested_type<X>::value> { };
///////////////////////////////////////////////////////TODO WIP for investigation
2023-04-27 19:38:37 +02:00
/**********************************************************************/ /**
* @ test validate test support for render job planning and dispatch .
* - creating and invoking mock render jobs
* - a mocked JobTicket , generating mock render jobs
* - configurable test setup for a mocked Segmentation datastructure
* @ see JobPlanningSetup_test
* @ see Dispatcher
* @ see vault : : engine : : Job
* @ see steam : : fixture : : Segmentation
*/
class MockSupport_test : public Test
{
virtual void
2023-05-10 14:57:41 +02:00
run ( Arg )
2023-04-27 19:38:37 +02:00
{
simpleUsage ( ) ;
verify_MockJob ( ) ;
verify_MockJobTicket ( ) ;
verify_MockSegmentation ( ) ;
2023-05-11 22:47:56 +02:00
verify_MockPrerequisites ( ) ;
2023-04-27 19:38:37 +02:00
}
/** @test simple usage example of the test helpers */
void
simpleUsage ( )
{
2023-05-10 14:57:41 +02:00
// Build a simple Segment at [10s ... 20s[
MockSegmentation mockSegs { MakeRec ( )
. attrib ( " start " , Time { 0 , 10 }
, " after " , Time { 0 , 20 } )
. genNode ( ) } ;
CHECK ( 3 = = mockSegs . size ( ) ) ;
fixture : : Segment const & seg = mockSegs [ Time { 0 , 15 } ] ; // access anywhere 10s <= t < 20s
2023-05-11 22:47:56 +02:00
JobTicket const & ticket = seg . jobTicket ( ) ; ///////////////////////////////////////////////////TICKET #1297 : will need to pass a ModelPort number here (use the first one, i.e. 0)
2023-05-10 14:57:41 +02:00
FrameCoord coord ;
coord . absoluteNominalTime = Time ( 0 , 15 ) ;
Job job = ticket . createJobFor ( coord ) ;
CHECK ( MockJobTicket : : isAssociated ( job , ticket ) ) ;
job . triggerJob ( ) ;
CHECK ( DummyJob : : was_invoked ( job ) ) ;
2023-04-27 19:38:37 +02:00
}
2023-05-10 14:57:41 +02:00
2023-04-27 19:38:37 +02:00
/** @test document and verify usage of a mock render job */
void
verify_MockJob ( )
{
Time nominalTime = lib : : test : : randTime ( ) ;
int additionalKey = rand ( ) % 5000 ;
Job mockJob = DummyJob : : build ( nominalTime , additionalKey ) ;
CHECK ( mockJob . getNominalTime ( ) = = nominalTime ) ;
CHECK ( not DummyJob : : was_invoked ( mockJob ) ) ;
mockJob . triggerJob ( ) ;
2023-04-30 02:18:56 +02:00
CHECK ( DummyJob : : was_invoked ( mockJob ) ) ;
2023-04-27 19:38:37 +02:00
CHECK ( RealClock : : wasRecently ( DummyJob : : invocationTime ( mockJob ) ) ) ;
CHECK ( nominalTime = = DummyJob : : invocationNominalTime ( mockJob ) ) ;
CHECK ( additionalKey = = DummyJob : : invocationAdditionalKey ( mockJob ) ) ;
2023-04-30 02:18:56 +02:00
Time prevInvocation = DummyJob : : invocationTime ( mockJob ) ;
2023-04-27 19:38:37 +02:00
mockJob . triggerJob ( ) ;
CHECK ( prevInvocation < DummyJob : : invocationTime ( mockJob ) ) ; // invoked again, recorded new invocation time
CHECK ( nominalTime = = DummyJob : : invocationNominalTime ( mockJob ) ) ; // all other Job parameter recorded again unaltered
CHECK ( additionalKey = = DummyJob : : invocationAdditionalKey ( mockJob ) ) ;
}
/** @test document and verify usage of a mock JobTicket for frame dispatch */
void
verify_MockJobTicket ( )
{
2023-05-01 01:48:36 +02:00
FrameCoord coord ;
coord . absoluteNominalTime = lib : : test : : randTime ( ) ;
// build a render job to do nothing....
Job nopJob = JobTicket : : NOP . createJobFor ( coord ) ;
2023-05-01 14:07:21 +02:00
CHECK ( INSTANCEOF ( vault : : engine : : NopJobFunctor , static_cast < JobClosure * > ( nopJob . jobClosure ) ) ) ; //////////TICKET #1287 : fix actual interface down to JobFunctor (after removing C structs)
2023-05-01 01:48:36 +02:00
CHECK ( nopJob . parameter . nominalTime = = coord . absoluteNominalTime ) ;
2023-05-01 14:07:21 +02:00
InvocationInstanceID empty ; ///////////////////////////////////////////////////////////////////////TICKET #1287 : temporary workaround until we get rid of the C base structs
CHECK ( lumiera_invokey_eq ( & nopJob . parameter . invoKey , & empty ) ) ;
2023-05-01 01:48:36 +02:00
2023-04-30 02:18:56 +02:00
MockJobTicket mockTicket ;
CHECK ( mockTicket . discoverPrerequisites ( ) . empty ( ) ) ;
2023-05-01 01:48:36 +02:00
Job mockJob = mockTicket . createJobFor ( coord ) ;
2023-05-01 14:07:21 +02:00
CHECK ( mockTicket . verify_associated ( mockJob ) ) ; // proof by invocation hash : is indeed backed by this JobTicket
CHECK ( not mockTicket . verify_associated ( nopJob ) ) ; // ...while some random other job is not related
2023-04-27 19:38:37 +02:00
}
2023-05-10 14:57:41 +02:00
/** @test document and verify usage of a complete mocked Segmentation
* to back frame dispatch
*/
2023-04-27 19:38:37 +02:00
void
verify_MockSegmentation ( )
{
2023-05-01 17:02:11 +02:00
FrameCoord coord ;
Time someTime = lib : : test : : randTime ( ) ;
coord . absoluteNominalTime = someTime ;
2023-05-10 03:59:46 +02:00
//-----------------------------------------------------------------/// Empty default Segmentation
2023-05-01 17:02:11 +02:00
{
MockSegmentation mockSeg ;
CHECK ( 1 = = mockSeg . size ( ) ) ;
JobTicket const & ticket = mockSeg [ someTime ] . jobTicket ( ) ;
CHECK ( util : : isSameObject ( ticket , JobTicket : : NOP ) ) ;
}
2023-05-10 03:59:46 +02:00
//-----------------------------------------------------------------/// Segmentation with one default segment spanning complete timeline
2023-05-01 17:02:11 +02:00
{
2023-05-05 03:46:42 +02:00
MockSegmentation mockSegs { MakeRec ( ) . genNode ( ) } ;
CHECK ( 1 = = mockSegs . size ( ) ) ;
CHECK ( Time : : MIN = = mockSegs [ someTime ] . start ( ) ) ;
CHECK ( Time : : MAX = = mockSegs [ someTime ] . after ( ) ) ;
JobTicket const & ticket = mockSegs [ someTime ] . jobTicket ( ) ;
2023-05-01 17:02:11 +02:00
CHECK ( not util : : isSameObject ( ticket , JobTicket : : NOP ) ) ;
2023-05-10 03:59:46 +02:00
Job someJob = ticket . createJobFor ( coord ) ; // JobTicket uses, but does not check the time given in FrameCoord
CHECK ( someJob . parameter . nominalTime = = _raw ( coord . absoluteNominalTime ) ) ;
CHECK ( MockJobTicket : : isAssociated ( someJob , ticket ) ) ; // but the generated Job is linked to the Closure backed by the JobTicket
2023-05-01 17:02:11 +02:00
CHECK ( not DummyJob : : was_invoked ( someJob ) ) ;
someJob . triggerJob ( ) ;
CHECK ( DummyJob : : was_invoked ( someJob ) ) ;
CHECK ( RealClock : : wasRecently ( DummyJob : : invocationTime ( someJob ) ) ) ;
CHECK ( someTime = = DummyJob : : invocationNominalTime ( someJob ) ) ;
}
2023-05-10 03:59:46 +02:00
//-----------------------------------------------------------------/// Segmentation with a segment spanning part of the timeline > 10s
2023-05-05 03:46:42 +02:00
{
// Marker to verify the job calls back into the right segment
int marker = rand ( ) % 1000 ;
// Build a Segmentation partitioned at 10s
MockSegmentation mockSegs { MakeRec ( )
. attrib ( " start " , Time { 0 , 10 }
, " mark " , marker )
. genNode ( ) } ;
CHECK ( 2 = = mockSegs . size ( ) ) ;
// since only start-time was given, the SplitSplice-Algo will attach
// the new Segment starting at 10s and expand towards +∞,
// while the left part of the axis is marked as NOP / empty
fixture : : Segment const & seg1 = mockSegs [ Time : : ZERO ] ; // access anywhere < 10s
fixture : : Segment const & seg2 = mockSegs [ Time { 0 , 20 } ] ; // access anywhere >= 10s
CHECK ( util : : isSameObject ( seg1 . jobTicket ( ) , JobTicket : : NOP ) ) ;
CHECK ( not util : : isSameObject ( seg2 . jobTicket ( ) , JobTicket : : NOP ) ) ; // this one is the active segment
Job job = seg2 . jobTicket ( ) . createJobFor ( coord ) ;
CHECK ( not MockJobTicket : : isAssociated ( job , seg1 . jobTicket ( ) ) ) ;
CHECK ( MockJobTicket : : isAssociated ( job , seg2 . jobTicket ( ) ) ) ;
CHECK ( marker = = job . parameter . invoKey . part . a ) ;
job . triggerJob ( ) ;
CHECK ( DummyJob : : was_invoked ( job ) ) ;
CHECK ( RealClock : : wasRecently ( DummyJob : : invocationTime ( job ) ) ) ;
CHECK ( marker = = DummyJob : : invocationAdditionalKey ( job ) ) ; // DummyClosure is rigged such as to feed back the seed in `part.a`
// and thus we can prove this job really belongs to the marked segment
// create another job from the (empty) seg1
job = seg1 . jobTicket ( ) . createJobFor ( coord ) ;
InvocationInstanceID empty ; /////////////////////////////////////////////////////////////////////TICKET #1287 : temporary workaround until we get rid of the C base structs
2023-05-10 03:59:46 +02:00
CHECK ( lumiera_invokey_eq ( & job . parameter . invoKey , & empty ) ) ; // indicates that it's just a placeholder to mark a "NOP"-Job
CHECK ( seg1 . jobTicket ( ) . empty ( ) ) ;
CHECK ( seg1 . empty ( ) ) ;
CHECK ( not seg2 . empty ( ) ) ;
}
//-----------------------------------------------------------------/// Segmentation with one delineated segment, and otherwise empty
{
int marker = rand ( ) % 1000 ;
// Build Segmentation with one fully defined segment
MockSegmentation mockSegs { MakeRec ( )
. attrib ( " start " , Time { 0 , 10 }
, " after " , Time { 0 , 20 }
, " mark " , marker )
. genNode ( ) } ;
CHECK ( 3 = = mockSegs . size ( ) ) ;
auto const & [ s1 , s2 , s3 ] = seqTuple < 3 > ( mockSegs . eachSeg ( ) ) ;
CHECK ( s1 . empty ( ) ) ;
CHECK ( not s2 . empty ( ) ) ;
CHECK ( s3 . empty ( ) ) ;
CHECK ( isSameObject ( s2 , mockSegs [ Time { 0 , 10 } ] ) ) ;
CHECK ( Time : : MIN = = s1 . start ( ) ) ;
CHECK ( Time ( 0 , 10 ) = = s1 . after ( ) ) ;
CHECK ( Time ( 0 , 10 ) = = s2 . start ( ) ) ;
CHECK ( Time ( 0 , 20 ) = = s2 . after ( ) ) ;
CHECK ( Time ( 0 , 20 ) = = s3 . start ( ) ) ;
CHECK ( Time : : MAX = = s3 . after ( ) ) ;
Job job = s2 . jobTicket ( ) . createJobFor ( coord ) ;
job . triggerJob ( ) ;
CHECK ( marker = = DummyJob : : invocationAdditionalKey ( job ) ) ;
2023-05-05 03:46:42 +02:00
}
2023-05-10 14:57:41 +02:00
//-----------------------------------------------------------------/// Segmentation with several segments built in specific order
{
// Build Segmentation by partitioning in several steps
MockSegmentation mockSegs { MakeRec ( )
. attrib ( " start " , Time { 0 , 20 } // note: inverted segment definition is rectified automatically
, " after " , Time { 0 , 10 }
, " mark " , 1 )
. genNode ( )
, MakeRec ( )
. attrib ( " after " , Time : : ZERO
, " mark " , 2 )
. genNode ( )
, MakeRec ( )
. attrib ( " start " , Time { FSecs { - 5 } }
, " mark " , 3 )
. genNode ( ) } ;
CHECK ( 5 = = mockSegs . size ( ) ) ;
auto const & [ s1 , s2 , s3 , s4 , s5 ] = seqTuple < 5 > ( mockSegs . eachSeg ( ) ) ;
CHECK ( not s1 . empty ( ) ) ;
CHECK ( not s2 . empty ( ) ) ;
CHECK ( s3 . empty ( ) ) ;
CHECK ( not s4 . empty ( ) ) ;
CHECK ( s5 . empty ( ) ) ;
CHECK ( Time : : MIN = = s1 . start ( ) ) ; // the second added segment has covered the whole negative axis
CHECK ( - Time ( 0 , 5 ) = = s1 . after ( ) ) ; // ..up to the partitioning point -5
CHECK ( - Time ( 0 , 5 ) = = s2 . start ( ) ) ; // ...while the rest was taken up by the third added segment
CHECK ( Time ( 0 , 0 ) = = s2 . after ( ) ) ;
CHECK ( Time ( 0 , 0 ) = = s3 . start ( ) ) ; // an empty gap remains between [0 ... 10[
CHECK ( Time ( 0 , 10 ) = = s3 . after ( ) ) ;
CHECK ( Time ( 0 , 10 ) = = s4 . start ( ) ) ; // here is the first added segment
CHECK ( Time ( 0 , 20 ) = = s4 . after ( ) ) ;
CHECK ( Time ( 0 , 20 ) = = s5 . start ( ) ) ; // and the remaining part of the positive axis is empty
CHECK ( Time : : MAX = = s5 . after ( ) ) ;
auto probeKey = [ & ] ( Segment const & segment )
{
if ( segment . empty ( ) ) return 0 ;
Job job = segment . jobTicket ( ) . createJobFor ( coord ) ;
job . triggerJob ( ) ;
CHECK ( DummyJob : : was_invoked ( job ) ) ;
CHECK ( RealClock : : wasRecently ( DummyJob : : invocationTime ( job ) ) ) ;
return DummyJob : : invocationAdditionalKey ( job ) ;
} ;
CHECK ( 2 = = probeKey ( s1 ) ) ; // verify all generated jobs are wired back to the correct segment
CHECK ( 3 = = probeKey ( s2 ) ) ;
CHECK ( 0 = = probeKey ( s3 ) ) ;
CHECK ( 1 = = probeKey ( s4 ) ) ;
CHECK ( 0 = = probeKey ( s5 ) ) ;
}
2023-04-27 19:38:37 +02:00
}
2023-05-11 22:47:56 +02:00
/**
* @ test build a Segment with additional prerequisites ,
* resulting in additional JobTickets to explore and
* additional prerequisite Jobs to build for each frame .
*/
void
verify_MockPrerequisites ( )
{
FrameCoord coord ;
//-----------------------------------------------------------------/// one Segment with one additional prerequisite
{
MockSegmentation mockSegs { MakeRec ( )
. attrib ( " mark " , 11 )
. scope ( MakeRec ( )
. attrib ( " mark " , 23 )
. genNode ( ) )
. genNode ( ) } ;
CHECK ( 1 = = mockSegs . size ( ) ) ;
JobTicket const & ticket = mockSegs [ Time : : ZERO ] . jobTicket ( ) ;
auto prereq = ticket . getPrerequisites ( ) ;
CHECK ( not isnil ( prereq ) ) ;
JobTicket const & preTicket = * prereq ;
+ + prereq ;
CHECK ( isnil ( prereq ) ) ;
Job job1 = preTicket . createJobFor ( coord ) ;
Job job2 = ticket . createJobFor ( coord ) ;
job1 . triggerJob ( ) ;
job2 . triggerJob ( ) ;
CHECK ( 23 = = DummyJob : : invocationAdditionalKey ( job1 ) ) ;
CHECK ( 11 = = DummyJob : : invocationAdditionalKey ( job2 ) ) ;
}
2023-05-15 23:25:29 +02:00
//-----------------------------------------------------------------/// deep nested prerequisite
{
MockSegmentation mockSegs { MakeRec ( )
. attrib ( " mark " , 11 )
. scope ( MakeRec ( )
. attrib ( " mark " , 23 )
. genNode ( ) )
. genNode ( ) } ;
using RTick = std : : reference_wrapper < JobTicket > ;
2023-05-23 01:06:22 +02:00
auto start = singleValIterator ( mockSegs [ Time : : ZERO ] . jobTicket ( ) ) ;
2023-05-15 23:25:29 +02:00
2023-05-23 01:06:22 +02:00
using SrC = lib : : iter_explorer : : BaseAdapter < lib : : SingleValIter < engine : : JobTicket const & > > ;
2023-05-15 23:25:29 +02:00
2023-05-23 01:06:22 +02:00
auto bunny = [ ] ( JobTicket const & ticket )
2023-05-15 23:25:29 +02:00
{
2023-05-23 01:06:22 +02:00
return ticket . getPrerequisites ( ) ;
// return lib::transformIterator(ticket.getPrerequisites()
// ,[](JobTicket const& preq) -> JobTicket*
// { return unConst(&preq); }
// );
2023-05-15 23:25:29 +02:00
} ;
2023-05-23 01:06:22 +02:00
using ExIt = decltype ( bunny ( std : : declval < JobTicket const & > ( ) ) ) ;
2023-05-15 23:25:29 +02:00
2023-05-23 01:06:22 +02:00
using Funny = std : : function < ExIt ( JobTicket const & ) > ;
2023-05-15 23:25:29 +02:00
Funny funny = bunny ;
using ExpandedChildren = typename lib : : iter_explorer : : _FunTraits < Funny , SrC > : : Res ;
using ResIter = typename lib : : iter_explorer : : DecoTraits < ExpandedChildren > : : SrcIter ;
2023-05-23 01:06:22 +02:00
// lib::test::TypeDebugger<ResIter> buggy;
2023-05-15 23:25:29 +02:00
using ResIterVal = typename ResIter : : value_type ;
using SrcIterVal = typename SrC : : value_type ;
2023-05-23 01:06:22 +02:00
// lib::test::TypeDebugger<ResIterVal> buggy;
2023-05-15 23:25:29 +02:00
// lib::test::TypeDebugger<ExIt> bugggy;
2023-05-22 01:49:55 +02:00
using FunResTrait = lib : : iter_explorer : : _FunTraits < Funny , ResIter > ;
using FunArg = typename FunResTrait : : Arg ;
using ArgAdaptRes = typename FunResTrait : : ArgAdapter < ResIter > ;
static_assert ( std : : is_convertible < typename ResIter : : reference , FunArg > ( ) ) ;
// lib::test::TypeDebugger<decltype(ArgAdaptRes::wrap(bunny))> buggy;
2023-05-23 01:06:22 +02:00
// using ResCore = iter_explorer::Expander<SRC, ExpandedChildren>;
2023-05-22 01:49:55 +02:00
using ResCore = lib : : iter_explorer : : Expander < SrC , ExpandedChildren > ;
2023-05-23 01:06:22 +02:00
// using ExResIter = typename lib::iter_explorer::DecoTraits<ResCore>::SrcIter;
// static_assert(lib::meta::can_IterForEach<ResCore>::value);
// static_assert(lib::meta::can_STL_ForEach<ResCore>::value);
struct Murks
{
using type = void ;
} ;
struct Gurks : Murks { } ;
static_assert ( lib : : meta : : has_TypeResult < Gurks > ( ) ) ;
using Wootz = std : : common_type < JobTicket & , JobTicket const & > ;
using Wauzz = typename Wootz : : type ;
// lib::test::TypeDebugger<Wauzz> bully;
static_assert ( lib : : meta : : has_TypeResult < std : : common_type < JobTicket * , void * > > ( ) ) ;
// static_assert(HasNested_type<Gurks>::value);
// static_assert(HasNested_type<Wootz>::value);
// static_assert(has_TypeResult<Wootz>());
using ExiTrait = lib : : iter_explorer : : ExpoTraits < SrC , ExpandedChildren > ;
using WrapIter = typename lib : : iter_explorer : : DecoTraits < ResCore > : : SrcIter ;
// lib::test::TypeDebugger<typename lib::meta::ValueTypeBinding<WrapIter>::reference> bully;
// static_assert(std::is_const_v<JobTicket const&>);
// static_assert(std::is_const_v<JobTicket const>);
// static_assert(std::is_const_v<JobTicket&&>);
// lib::test::TypeDebugger<std::common_type_t<JobTicket const, JobTicket const>> bully;
// lib::test::TypeDebugger<typename ExiTrait::CommonType> bully;
// lib::test::TypeDebugger<typename ExiTrait::reference> bully;
// lib::test::TypeDebugger<ResCore::reference> bully;
2023-05-15 23:25:29 +02:00
auto it = lib : : explore ( start )
// .transform ([](RTick t) -> JobTicket const&
// {
// return t.get();
// })
. expand ( funny )
. expandAll ( )
2023-05-23 01:06:22 +02:00
. transform ( [ & ] ( JobTicket const & ticket )
2023-05-15 23:25:29 +02:00
{
2023-05-23 01:06:22 +02:00
return ticket . createJobFor ( coord ) . parameter . invoKey . part . a ;
2023-05-15 23:25:29 +02:00
} ) ;
cout < < util : : join ( it , " - " ) < < endl ;
2023-05-22 01:49:55 +02:00
# if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #1294
2023-05-15 23:25:29 +02:00
# endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #1294
}
2023-05-11 22:47:56 +02:00
}
2023-04-27 19:38:37 +02:00
} ;
/** Register this test class... */
LAUNCHER ( MockSupport_test , " unit engine " ) ;
} } } // namespace steam::engine::test