250 lines
11 KiB
C++
250 lines
11 KiB
C++
/*
|
|
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 02139, USA.
|
|
|
|
* *****************************************************/
|
|
|
|
/** @file mock-support-test.cpp
|
|
** unit test \ref MockSupport_test
|
|
*/
|
|
|
|
|
|
#include "lib/test/run.hpp"
|
|
#include "lib/error.hpp"
|
|
#include "steam/engine/mock-dispatcher.hpp"
|
|
#include "vault/engine/dummy-job.hpp"
|
|
#include "lib/util-tuple.hpp"
|
|
#include "lib/util.hpp"
|
|
#include "vault/engine/nop-job-functor.hpp"
|
|
|
|
#include "lib/format-cout.hpp"///////////////////////TODO
|
|
|
|
//#include "steam/engine/job-planning.hpp"
|
|
|
|
//#include <ctime>
|
|
|
|
using test::Test;
|
|
|
|
using util::isSameObject;
|
|
using util::seqTuple;
|
|
//using std::rand;
|
|
|
|
|
|
namespace steam {
|
|
namespace engine{
|
|
namespace test {
|
|
|
|
using vault::engine::DummyJob;
|
|
|
|
namespace { // test fixture...
|
|
|
|
} // (End) test fixture
|
|
|
|
|
|
|
|
|
|
/**********************************************************************//**
|
|
* @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
|
|
*
|
|
* @todo WIP-WIP-WIP 4/2023
|
|
*
|
|
* @see JobPlanningSetup_test
|
|
* @see Dispatcher
|
|
* @see vault::engine::Job
|
|
* @see steam::fixture::Segmentation
|
|
*/
|
|
class MockSupport_test : public Test
|
|
{
|
|
|
|
virtual void
|
|
run (Arg)
|
|
{
|
|
simpleUsage();
|
|
verify_MockJob();
|
|
verify_MockJobTicket();
|
|
verify_MockSegmentation();
|
|
}
|
|
|
|
|
|
/** @test simple usage example of the test helpers */
|
|
void
|
|
simpleUsage()
|
|
{
|
|
TODO ("simple usage example");
|
|
}
|
|
|
|
|
|
/** @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();
|
|
CHECK (DummyJob::was_invoked (mockJob));
|
|
CHECK (RealClock::wasRecently (DummyJob::invocationTime (mockJob)));
|
|
CHECK (nominalTime == DummyJob::invocationNominalTime (mockJob) );
|
|
CHECK (additionalKey == DummyJob::invocationAdditionalKey(mockJob));
|
|
|
|
Time prevInvocation = DummyJob::invocationTime (mockJob);
|
|
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()
|
|
{
|
|
FrameCoord coord;
|
|
coord.absoluteNominalTime = lib::test::randTime();
|
|
|
|
// build a render job to do nothing....
|
|
Job nopJob = JobTicket::NOP.createJobFor(coord);
|
|
CHECK (INSTANCEOF (vault::engine::NopJobFunctor, static_cast<JobClosure*> (nopJob.jobClosure))); //////////TICKET #1287 : fix actual interface down to JobFunctor (after removing C structs)
|
|
CHECK (nopJob.parameter.nominalTime == coord.absoluteNominalTime);
|
|
InvocationInstanceID empty; ///////////////////////////////////////////////////////////////////////TICKET #1287 : temporary workaround until we get rid of the C base structs
|
|
CHECK (lumiera_invokey_eq (&nopJob.parameter.invoKey, &empty));
|
|
|
|
MockJobTicket mockTicket;
|
|
CHECK (mockTicket.discoverPrerequisites().empty());
|
|
Job mockJob = mockTicket.createJobFor (coord);
|
|
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
|
|
TODO ("cover details of MockJobTicket");
|
|
}
|
|
|
|
|
|
/** @test document and verify usage of a complete mocked Segmentation to back frame dispatch */
|
|
void
|
|
verify_MockSegmentation()
|
|
{
|
|
FrameCoord coord;
|
|
Time someTime = lib::test::randTime();
|
|
coord.absoluteNominalTime = someTime;
|
|
//-----------------------------------------------------------------/// Empty default Segmentation
|
|
{
|
|
MockSegmentation mockSeg;
|
|
CHECK (1 == mockSeg.size());
|
|
JobTicket const& ticket = mockSeg[someTime].jobTicket();
|
|
CHECK (util::isSameObject (ticket, JobTicket::NOP));
|
|
}
|
|
//-----------------------------------------------------------------/// Segmentation with one default segment spanning complete timeline
|
|
{
|
|
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();
|
|
CHECK (not util::isSameObject (ticket, JobTicket::NOP));
|
|
|
|
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
|
|
CHECK (not DummyJob::was_invoked (someJob));
|
|
|
|
someJob.triggerJob();
|
|
CHECK (DummyJob::was_invoked (someJob));
|
|
CHECK (RealClock::wasRecently (DummyJob::invocationTime (someJob)));
|
|
CHECK (someTime == DummyJob::invocationNominalTime (someJob));
|
|
}
|
|
//-----------------------------------------------------------------/// Segmentation with a segment spanning part of the timeline > 10s
|
|
{
|
|
// 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
|
|
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));
|
|
}
|
|
|
|
|
|
TODO ("cover more details of MockSegmentation");
|
|
}
|
|
};
|
|
|
|
|
|
/** Register this test class... */
|
|
LAUNCHER (MockSupport_test, "unit engine");
|
|
|
|
|
|
|
|
}}} // namespace steam::engine::test
|