2013-09-07 02:37:17 +02:00
/*
DummyJob - diagnostic job for unit tests
Copyright ( C ) Lumiera . org
2013 , 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 .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2017-02-22 01:54:20 +01:00
/** @file dummy-job.cpp
2023-05-24 03:38:12 +02:00
* * Implementation of a dummy render job for unit tests .
* * Based on using a specifically rigged DummyClosure as JobFunctor ,
* * where the actual Job invocation does nothing other than storing
* * the invocation mark and parameters into a invocationLog_ table .
* * Together with the likewise specifically rigged steam : : engine : : test : : MockJobTicket ,
* * the invocation hash can be marked , which allows to prove after the invocation
* * that a given Segment or JobTicket actually generated a specific Job , which was
* * then invoked with specific parameters .
* *
* * # Usage front - end
* *
* * The static functions in vault : : engine : : DummyJob allow to
* * - build such a mock job , possibly with random ( or well defined ) parameters
* * - when passing back this job instance , verify invocation and extract data
2016-11-03 18:20:10 +01:00
*/
2013-09-07 02:37:17 +02:00
2018-11-15 23:42:43 +01:00
# include "vault/engine/dummy-job.hpp"
2013-09-07 02:37:17 +02:00
2023-06-13 03:47:42 +02:00
# include "vault/engine/nop-job-functor.hpp"
2013-09-07 02:37:17 +02:00
# include "lib/test/test-helper.hpp"
# include "lib/time/timevalue.hpp"
2018-11-15 23:42:43 +01:00
# include "vault/real-clock.hpp"
2013-09-07 02:37:17 +02:00
# include "lib/null-value.hpp"
# include "lib/hash-value.h"
2023-06-13 03:47:42 +02:00
# include "lib/depend.hpp"
2013-09-07 02:37:17 +02:00
# include "lib/util.hpp"
# include <cstdlib>
2014-04-03 22:42:48 +02:00
# include <unordered_map>
2023-04-21 05:29:10 +02:00
# include <functional>
2013-09-07 02:37:17 +02:00
2018-11-15 23:55:13 +01:00
namespace vault {
2013-09-07 02:37:17 +02:00
namespace engine {
namespace { // DummyJob implementation details...
using lib : : HashVal ;
using lib : : NullValue ;
using lib : : time : : TimeVar ;
2014-04-03 22:42:48 +02:00
using std : : unordered_map ;
2013-09-07 02:37:17 +02:00
using util : : access_or_default ;
const int MAX_PARAM_A ( 1000 ) ; ///< random test values 0...1000
const int MAX_PARAM_B ( 10 ) ; ///< random test values -10...+10
/**
* test dummy jobs are backed by this closure .
* DummyJob invocations are recorded in a hashtable
2023-05-24 03:38:12 +02:00
* @ note as of 5 / 2023 , we use a simplistic map - based implementation ,
2013-09-07 02:37:17 +02:00
* causing a consecutive invocation of the same job instance
2023-05-24 03:38:12 +02:00
* with identical JobParameter to overwrite the previous log entry .
2013-09-07 02:37:17 +02:00
*/
class DummyClosure
: public JobClosure
{
void
2023-04-30 02:18:56 +02:00
invokeJobOperation ( JobParameter parameter ) override
2013-09-07 02:37:17 +02:00
{
invocationLog_ [ hash_value ( parameter ) ] = Invocation ( parameter ) ;
}
void
2023-04-30 02:18:56 +02:00
signalFailure ( JobParameter , JobFailureReason ) override
2013-09-07 02:37:17 +02:00
{
NOTREACHED ( " Job failure is not subject of this test " ) ;
}
JobKind
2023-04-30 02:18:56 +02:00
getJobKind ( ) const override
2013-09-07 02:37:17 +02:00
{
return META_JOB ;
}
bool
2023-04-30 02:18:56 +02:00
verify ( Time nominalJobTime , InvocationInstanceID invoKey ) const override
2013-09-07 02:37:17 +02:00
{
2018-11-17 17:25:10 +01:00
return Time : : ANYTIME < nominalJobTime
2023-04-30 22:33:42 +02:00
& & 0 < = invoKey . part . a
& & invoKey . part . a < MAX_PARAM_A
& & - MAX_PARAM_B < = invoKey . part . b
& & invoKey . part . b < MAX_PARAM_B ;
2013-09-07 02:37:17 +02:00
}
2023-04-30 22:33:42 +02:00
/**
* Generate a specifically marked invocationKey for use in unit - tests .
* @ remark in the actual implementation , this function generates a distinct
2023-05-24 03:38:12 +02:00
* base hash to tag specific processing provided by this JobFunctor ;
2023-04-30 22:33:42 +02:00
* the seed usually factors in the media stream format ; on invocation
* the nominal frame time will additionally be hashed in . Yet for
* unit testing , we typically use this dummy JobFunctor and it is
* expedient if this hash - chaining calculation is easy predictable ;
* @ return a zero - initialised invocationKey , assigning seed to the lower part
*/
2023-04-30 02:18:56 +02:00
InvocationInstanceID
buildInstanceID ( HashVal seed ) const override
{
2023-05-05 03:46:42 +02:00
InvocationInstanceID instance ;
instance . part . a = seed ;
return instance ;
2023-04-30 02:18:56 +02:00
}
2013-09-07 02:37:17 +02:00
size_t
2023-04-30 22:33:42 +02:00
hashOfInstance ( InvocationInstanceID invoKey ) const override
2013-09-07 02:37:17 +02:00
{
2023-04-30 22:33:42 +02:00
std : : hash < size_t > hashr ;
HashVal res = hashr ( invoKey . frameNumber ) ;
lib : : hash : : combine ( res , hashr ( invoKey . part . t ) ) ;
return res ;
}
2013-09-07 02:37:17 +02:00
/* === Logging/Reporting of job invocation === */
struct Invocation
{
TimeVar nominal ;
TimeVar real ;
int a , b ;
2023-04-30 22:33:42 +02:00
Invocation ( JobParameter param )
: nominal { TimeValue ( param . nominalTime ) }
, real { RealClock : : now ( ) }
, a { param . invoKey . part . a }
, b { param . invoKey . part . b }
2013-09-07 02:37:17 +02:00
{ }
Invocation ( )
2023-04-30 22:33:42 +02:00
: nominal { Time : : ANYTIME }
, real { Time : : NEVER }
, a { MAX_PARAM_A } , b { 0 }
2013-09-07 02:37:17 +02:00
{ }
} ;
/** recording DummyJob invocations */
unordered_map < HashVal , Invocation > invocationLog_ ;
public :
Invocation const &
queryInvocation ( JobParameter param ) const
{
return access_or_default ( invocationLog_ , hash_value ( param )
, NullValue < Invocation > : : get ( ) ) ;
}
2023-04-30 02:18:56 +02:00
void
clearLog ( )
{
invocationLog_ . clear ( ) ;
}
2013-09-07 02:37:17 +02:00
} ;
2023-05-24 03:38:12 +02:00
/** actual instance of the test dummy job functor */
2013-09-07 02:37:17 +02:00
DummyClosure dummyClosure ;
2023-06-13 03:47:42 +02:00
/** access to the fallback-implementation for empty segments */
lib : : Depend < vault : : engine : : NopJobFunctor > nopFunctor ;
2013-09-07 02:37:17 +02:00
} // (End)Implementation details
Job
DummyJob : : build ( )
{
InvocationInstanceID invoKey ;
2023-04-30 22:33:42 +02:00
invoKey . part . a = rand ( ) % MAX_PARAM_A ;
invoKey . part . b = rand ( ) % ( 2 * MAX_PARAM_B ) - MAX_PARAM_B ;
2013-09-07 02:37:17 +02:00
Time nominalTime = lib : : test : : randTime ( ) ;
return Job ( dummyClosure , invoKey , nominalTime ) ;
}
Job
DummyJob : : build ( Time nominalTime , int additionalKey )
{
InvocationInstanceID invoKey ;
2023-04-30 22:33:42 +02:00
invoKey . part . a = additionalKey ;
invoKey . part . b = rand ( ) % ( 2 * MAX_PARAM_B ) - MAX_PARAM_B ;
2013-09-07 02:37:17 +02:00
return Job ( dummyClosure , invoKey , nominalTime ) ;
}
bool
DummyJob : : was_invoked ( Job const & job )
{
REQUIRE ( job . usesClosure ( dummyClosure ) ) ;
2018-11-17 17:25:10 +01:00
return Time : : NEVER ! = dummyClosure . queryInvocation ( job . parameter ) . real ;
2013-09-07 02:37:17 +02:00
}
Time
DummyJob : : invocationTime ( Job const & job )
{
REQUIRE ( job . usesClosure ( dummyClosure ) ) ;
return dummyClosure . queryInvocation ( job . parameter ) . real ;
}
2023-04-21 05:29:10 +02:00
Time
DummyJob : : invocationNominalTime ( Job const & job )
{
REQUIRE ( job . usesClosure ( dummyClosure ) ) ;
return dummyClosure . queryInvocation ( job . parameter ) . nominal ;
}
int
DummyJob : : invocationAdditionalKey ( Job const & job )
{
REQUIRE ( job . usesClosure ( dummyClosure ) ) ;
return dummyClosure . queryInvocation ( job . parameter ) . a ;
}
/** @internal for collaboration with other Mock/Dummy facilities */
JobClosure &
DummyJob : : getFunctor ( )
{
return dummyClosure ;
}
2023-06-13 03:47:42 +02:00
/** @internal likewise to support the MockDispatcher diagnostics;
* locate here since this is a dedicated translation unit
* @ return ` true ` iff the job was defined in the typical way used by
* JobTicket to generate fill jobs for empty segments .
* @ see JobTicket : : JobTicket : : createJobFor ( FrameCoord )
*/
bool
DummyJob : : isNopJob ( Job const & job )
{
InvocationInstanceID empty ; ///////////////////////////////////////////////////////////////////////TICKET #1287 : temporary workaround until we get rid of the C base structs
JobClosure & jobFunctor = static_cast < JobClosure & > ( * job . jobClosure ) ; //////////////////////////TICKET #1287 : fix actual interface down to JobFunctor (after removing C structs)
return lumiera_invokey_eq ( & util : : unConst ( job ) . parameter . invoKey , & empty )
and util : : isSameObject ( jobFunctor , nopFunctor ( ) ) ;
}
2023-04-21 05:29:10 +02:00
2018-11-15 23:55:13 +01:00
} } // namespace vault::engine