2011-10-31 00:13:35 +01:00
|
|
|
|
/*
|
|
|
|
|
|
TestFrame - test data frame (stub) for checking Render engine functionality
|
|
|
|
|
|
|
Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
* there is no entity "Lumiera.org" which holds any copyrights
* Lumiera source code is provided under the GPL Version 2+
== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''
The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!
The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
|
|
|
|
Copyright (C)
|
2024-11-20 15:32:49 +01:00
|
|
|
|
2011, 2024 Hermann Vosseler <Ichthyostega@web.de>
|
2011-10-31 00:13:35 +01:00
|
|
|
|
|
Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
* there is no entity "Lumiera.org" which holds any copyrights
* Lumiera source code is provided under the GPL Version 2+
== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''
The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!
The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
|
|
|
|
**Lumiera** 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. See the file COPYING for further details.
|
2011-10-31 00:13:35 +01:00
|
|
|
|
|
Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
* there is no entity "Lumiera.org" which holds any copyrights
* Lumiera source code is provided under the GPL Version 2+
== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''
The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!
The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
|
|
|
|
* *****************************************************************/
|
2011-10-31 00:13:35 +01:00
|
|
|
|
|
2017-02-22 01:58:49 +01:00
|
|
|
|
/** @file testframe.cpp
|
2024-11-20 05:50:44 +01:00
|
|
|
|
** Implementation of fake data frames to support unit testing.
|
|
|
|
|
|
** The data generation is based on a _discriminator seed value,_
|
|
|
|
|
|
** which is computed as a linear combination of a statically fixed anchor-seed
|
|
|
|
|
|
** combined with the family-number and sequence number. Based on this seed,
|
|
|
|
|
|
** the contents are then filled by a pseudo-random sequence.
|
|
|
|
|
|
** @note while initially drawn from real entropy, the anchor-seed can be
|
|
|
|
|
|
** reset from the default PRNG, which allows to establish a totally
|
|
|
|
|
|
** deterministically setup from test code, because the test itself
|
|
|
|
|
|
** can seed the default PRNG and thus establish a reproducible state.
|
|
|
|
|
|
**
|
|
|
|
|
|
** Additionally, beyond this basic test-data feature, the contents can be
|
|
|
|
|
|
** manipulated freely, and a new checksum can be stored in the metadata,
|
|
|
|
|
|
** which allows to build pseudo media computation functions with a
|
|
|
|
|
|
** reproducible effect — so that the proper invocation of several
|
|
|
|
|
|
** computation steps invoked deep down in the render engine can
|
|
|
|
|
|
** be verified after completing a test invocation.
|
2016-11-03 18:20:10 +01:00
|
|
|
|
*/
|
|
|
|
|
|
|
2011-10-31 00:13:35 +01:00
|
|
|
|
|
|
|
|
|
|
#include "lib/error.hpp"
|
2024-11-13 02:23:23 +01:00
|
|
|
|
#include "lib/random.hpp"
|
2024-11-18 23:55:30 +01:00
|
|
|
|
#include "lib/hash-standard.hpp"
|
|
|
|
|
|
#include "lib/hash-combine.hpp"
|
2024-11-05 21:23:13 +01:00
|
|
|
|
#include "steam/engine/testframe.hpp"
|
2024-11-18 02:45:37 +01:00
|
|
|
|
#include "lib/nocopy.hpp"
|
|
|
|
|
|
#include "lib/util.hpp"
|
2011-10-31 00:13:35 +01:00
|
|
|
|
|
2024-11-18 02:45:37 +01:00
|
|
|
|
#include <climits>
|
2017-01-05 00:56:46 +01:00
|
|
|
|
#include <memory>
|
2024-11-20 15:32:49 +01:00
|
|
|
|
#include <deque>
|
2011-10-31 00:13:35 +01:00
|
|
|
|
|
2011-11-01 03:11:43 +01:00
|
|
|
|
|
2011-10-31 00:13:35 +01:00
|
|
|
|
|
2018-11-15 23:55:13 +01:00
|
|
|
|
namespace steam {
|
2024-11-20 05:50:44 +01:00
|
|
|
|
namespace engine{
|
|
|
|
|
|
namespace test {
|
|
|
|
|
|
namespace err = lumiera::error;
|
2011-10-31 00:13:35 +01:00
|
|
|
|
|
2024-11-20 15:32:49 +01:00
|
|
|
|
using std::deque;
|
2024-11-18 23:55:30 +01:00
|
|
|
|
using util::unConst;
|
2011-11-01 03:11:43 +01:00
|
|
|
|
|
2024-11-18 02:45:37 +01:00
|
|
|
|
/** @note using a random-congruential engine to generate the payload data */
|
|
|
|
|
|
using PseudoRandom = lib::RandomSequencer<std::minstd_rand>;
|
2011-11-01 03:11:43 +01:00
|
|
|
|
|
2011-10-31 00:13:35 +01:00
|
|
|
|
|
|
|
|
|
|
namespace { // hidden local support facilities....
|
|
|
|
|
|
|
2024-11-18 02:45:37 +01:00
|
|
|
|
/**
|
|
|
|
|
|
* Offset to set the seed values of »families« apart.
|
|
|
|
|
|
* The data in the test frames is generated from a distinctive ID-seed,
|
|
|
|
|
|
* which is controlled by the _family_ and the _seq-No_ within each family.
|
|
|
|
|
|
* The seeds for consecutive frames are spread apart by the #dataSeed,
|
|
|
|
|
|
* and the SEQUENCE_SPREAD constant acts as minimum spread. While seed
|
|
|
|
|
|
* values can wrap within the 64bit number range, this generation scheme
|
|
|
|
|
|
* makes it very unlikely that neighbouring frames end up with the same seed.
|
|
|
|
|
|
*/
|
|
|
|
|
|
const size_t SEQUENCE_SPREAD = 100;
|
|
|
|
|
|
|
|
|
|
|
|
HashVal
|
|
|
|
|
|
drawSeed (lib::Random& srcGen)
|
|
|
|
|
|
{
|
|
|
|
|
|
return srcGen.distribute(
|
|
|
|
|
|
std::uniform_int_distribution<HashVal>{SEQUENCE_SPREAD
|
|
|
|
|
|
,std::numeric_limits<HashVal>::max()-SEQUENCE_SPREAD});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** @internal a static seed hash used to anchor the data distinction ID-seeds */
|
|
|
|
|
|
HashVal dataSeed{drawSeed(lib::entropyGen)};
|
|
|
|
|
|
|
2011-10-31 02:20:32 +01:00
|
|
|
|
/** @internal helper for generating unique test frames.
|
2024-11-18 23:55:30 +01:00
|
|
|
|
* This »discriminator« is used as a random seed when filling the test frame data buffers.
|
2024-11-18 02:45:37 +01:00
|
|
|
|
* It is generated to be very likely different on adjacent frames of the same series,
|
|
|
|
|
|
* as well as to differ to all nearby neighbouring channels.
|
2024-11-18 23:55:30 +01:00
|
|
|
|
* @note the #dataSeed hash is limited by #SEQUENCE_SPREAD to prevent „risky“ families;
|
|
|
|
|
|
* the extreme case would be dataSeed+family ≡ 0 (all frames would be equal then)
|
2011-10-31 02:20:32 +01:00
|
|
|
|
* @param seq the sequence number of the frame within the channel
|
|
|
|
|
|
* @param family the channel this frame belongs to
|
|
|
|
|
|
*/
|
|
|
|
|
|
uint64_t
|
2024-11-18 23:55:30 +01:00
|
|
|
|
generateDiscriminator(uint seq, uint family)
|
2011-10-31 02:20:32 +01:00
|
|
|
|
{
|
|
|
|
|
|
// use the family as stepping
|
2024-11-18 02:45:37 +01:00
|
|
|
|
return (seq+1) * (dataSeed+family);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class DistinctNucleus
|
|
|
|
|
|
: public lib::SeedNucleus
|
|
|
|
|
|
, util::MoveOnly
|
|
|
|
|
|
{
|
2024-11-20 15:32:49 +01:00
|
|
|
|
uint64_t const& distinction_;
|
|
|
|
|
|
|
2024-11-18 02:45:37 +01:00
|
|
|
|
public:
|
|
|
|
|
|
DistinctNucleus(uint64_t const& anchor)
|
2024-11-20 15:32:49 +01:00
|
|
|
|
: distinction_{anchor}
|
2024-11-18 02:45:37 +01:00
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
|
|
uint64_t
|
|
|
|
|
|
getSeed() override
|
|
|
|
|
|
{
|
2024-11-20 15:32:49 +01:00
|
|
|
|
return distinction_;
|
2024-11-18 02:45:37 +01:00
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2024-11-18 23:55:30 +01:00
|
|
|
|
/** @return a stable characteristic memory marker for the metadata record */
|
|
|
|
|
|
HashVal
|
|
|
|
|
|
stampHeader()
|
|
|
|
|
|
{
|
|
|
|
|
|
static const HashVal MARK = lib::entropyGen.hash()
|
2024-11-20 05:50:44 +01:00
|
|
|
|
| 0b1000'1000'1000'1000'1000'1000'1000'1000; //////////////////////////////TICKET #722 : not portable because HashVal ≡ size_t — should it be?
|
2024-11-18 23:55:30 +01:00
|
|
|
|
return MARK;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-11-18 02:45:37 +01:00
|
|
|
|
/** @internal build a PRNG starting from the referred fixed seed */
|
|
|
|
|
|
auto
|
|
|
|
|
|
buildDataGenFrom (uint64_t const& anchor)
|
|
|
|
|
|
{
|
|
|
|
|
|
DistinctNucleus seed{anchor};
|
|
|
|
|
|
return PseudoRandom{seed};
|
2011-10-31 02:20:32 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
TestFrame&
|
|
|
|
|
|
accessAsTestFrame (void* memoryLocation)
|
|
|
|
|
|
{
|
|
|
|
|
|
REQUIRE (memoryLocation);
|
|
|
|
|
|
return *reinterpret_cast<TestFrame*> (memoryLocation);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-11-20 15:32:49 +01:00
|
|
|
|
/* ======= static TestFrame repository ======= */
|
|
|
|
|
|
|
|
|
|
|
|
/** @internal table to hold test data frames in heap memory.
|
2011-10-31 02:20:32 +01:00
|
|
|
|
* These frames are built on demand, but retained thereafter.
|
|
|
|
|
|
* Some tests might rely on the actual memory locations, using the
|
|
|
|
|
|
* test frames to simulate a real input frame data stream.
|
2024-11-20 15:32:49 +01:00
|
|
|
|
* @note \ref TestFrame::reseed() also discards this storage, which
|
|
|
|
|
|
* otherwise is retained at stable location until process end.
|
2011-10-31 02:20:32 +01:00
|
|
|
|
*/
|
|
|
|
|
|
struct TestFrameTable
|
2024-11-20 15:32:49 +01:00
|
|
|
|
: deque<deque<TestFrame>>
|
2011-10-31 02:20:32 +01:00
|
|
|
|
{
|
2024-11-20 15:32:49 +01:00
|
|
|
|
TestFrameTable() = default;
|
2011-10-31 02:20:32 +01:00
|
|
|
|
|
|
|
|
|
|
TestFrame&
|
2024-11-20 15:32:49 +01:00
|
|
|
|
getFrame (uint seqNr, uint chanNr)
|
2011-10-31 02:20:32 +01:00
|
|
|
|
{
|
|
|
|
|
|
if (chanNr >= this->size())
|
|
|
|
|
|
resize(chanNr+1);
|
|
|
|
|
|
ENSURE (chanNr < this->size());
|
2024-11-20 15:32:49 +01:00
|
|
|
|
deque<TestFrame>& channel = at(chanNr);
|
2011-10-31 02:20:32 +01:00
|
|
|
|
|
|
|
|
|
|
if (seqNr >= channel.size())
|
|
|
|
|
|
{
|
2024-11-20 15:32:49 +01:00
|
|
|
|
INFO (test, "Growing channel #%d of test frames %d -> %d elements."
|
|
|
|
|
|
, chanNr, channel.size(), seqNr+1);
|
|
|
|
|
|
for (uint nr=channel.size(); nr<=seqNr; ++nr)
|
|
|
|
|
|
channel.emplace_back (nr, chanNr);
|
2011-10-31 02:20:32 +01:00
|
|
|
|
}
|
|
|
|
|
|
ENSURE (seqNr < channel.size());
|
|
|
|
|
|
return channel[seqNr];
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
2024-11-20 15:32:49 +01:00
|
|
|
|
//
|
|
|
|
|
|
std::unique_ptr<TestFrameTable> testFrames;
|
|
|
|
|
|
//
|
|
|
|
|
|
}// (End) hidden impl details
|
2011-10-31 00:13:35 +01:00
|
|
|
|
|
|
|
|
|
|
|
2011-10-31 02:20:32 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
TestFrame&
|
2024-11-20 05:50:44 +01:00
|
|
|
|
testData (uint seqNr, uint chanNr)
|
2011-10-31 02:20:32 +01:00
|
|
|
|
{
|
2024-11-20 15:32:49 +01:00
|
|
|
|
if (not testFrames)
|
|
|
|
|
|
testFrames = std::make_unique<TestFrameTable>();
|
|
|
|
|
|
return testFrames->getFrame (seqNr, chanNr);
|
2011-10-31 02:20:32 +01:00
|
|
|
|
}
|
2024-11-18 02:45:37 +01:00
|
|
|
|
|
2011-10-31 02:20:32 +01:00
|
|
|
|
|
2024-11-18 02:45:37 +01:00
|
|
|
|
/**
|
|
|
|
|
|
* @remark this function should be invoked at the start of any test
|
|
|
|
|
|
* which requires reproducible data values in the TestFrame.
|
|
|
|
|
|
* It generates a new base seed to distinguish individual data frames.
|
|
|
|
|
|
* The seed is drawn from the \ref lib::defaultGen, and thus will be
|
|
|
|
|
|
* reproducible if the latter has been reseeded beforehand.
|
|
|
|
|
|
* @warning after invoking reseed(), the validity of previously generated
|
|
|
|
|
|
* frames can no longer be verified.
|
|
|
|
|
|
*/
|
2011-10-31 02:20:32 +01:00
|
|
|
|
void
|
2024-11-18 02:45:37 +01:00
|
|
|
|
TestFrame::reseed()
|
2011-10-31 02:20:32 +01:00
|
|
|
|
{
|
2024-11-20 15:32:49 +01:00
|
|
|
|
testFrames.reset(); // discard existing test data repository
|
2024-11-20 05:50:44 +01:00
|
|
|
|
dataSeed = drawSeed (lib::defaultGen);
|
2011-10-31 02:20:32 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-11-20 15:32:49 +01:00
|
|
|
|
|
|
|
|
|
|
/* ======= TestFrame class ======= */
|
2011-10-31 02:20:32 +01:00
|
|
|
|
|
2024-11-18 23:55:30 +01:00
|
|
|
|
TestFrame::Meta::Meta (uint seq, uint family)
|
|
|
|
|
|
: _MARK_{stampHeader()}
|
|
|
|
|
|
, checksum{0}
|
|
|
|
|
|
, distinction{generateDiscriminator (seq,family)}
|
|
|
|
|
|
, stage{CREATED}
|
|
|
|
|
|
{ }
|
|
|
|
|
|
|
2011-10-31 02:20:32 +01:00
|
|
|
|
TestFrame::~TestFrame()
|
|
|
|
|
|
{
|
2024-11-18 23:55:30 +01:00
|
|
|
|
header_.stage = DISCARDED;
|
2011-10-31 02:20:32 +01:00
|
|
|
|
}
|
2011-10-31 00:13:35 +01:00
|
|
|
|
|
|
|
|
|
|
|
2024-11-18 23:55:30 +01:00
|
|
|
|
TestFrame::TestFrame (uint seq, uint family)
|
|
|
|
|
|
: header_{seq,family}
|
2011-10-31 02:20:32 +01:00
|
|
|
|
{
|
2024-11-20 05:50:44 +01:00
|
|
|
|
buildData();
|
2024-11-18 23:55:30 +01:00
|
|
|
|
ASSERT (0 < header_.distinction);
|
|
|
|
|
|
ENSURE (CREATED == header_.stage);
|
|
|
|
|
|
ENSURE (isPristine());
|
2011-10-31 02:20:32 +01:00
|
|
|
|
}
|
2011-10-31 00:13:35 +01:00
|
|
|
|
|
|
|
|
|
|
TestFrame::TestFrame (TestFrame const& o)
|
2024-11-18 23:55:30 +01:00
|
|
|
|
: header_{o.header_}
|
2011-10-31 00:13:35 +01:00
|
|
|
|
{
|
2024-11-18 23:55:30 +01:00
|
|
|
|
data() = o.data();
|
|
|
|
|
|
header_.stage = CREATED;
|
2011-10-31 00:13:35 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TestFrame&
|
|
|
|
|
|
TestFrame::operator= (TestFrame const& o)
|
|
|
|
|
|
{
|
2024-11-18 23:55:30 +01:00
|
|
|
|
if (not isAlive())
|
2024-11-20 05:50:44 +01:00
|
|
|
|
throw err::Logic ("target TestFrame already dead or unaccessible");
|
2024-11-18 02:45:37 +01:00
|
|
|
|
if (not util::isSameAdr (this, o))
|
2011-10-31 00:13:35 +01:00
|
|
|
|
{
|
2024-11-18 23:55:30 +01:00
|
|
|
|
data() = o.data();
|
|
|
|
|
|
header_ = o.header_;
|
|
|
|
|
|
header_.stage = CREATED;
|
2011-10-31 00:13:35 +01:00
|
|
|
|
}
|
|
|
|
|
|
return *this;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-11-20 05:50:44 +01:00
|
|
|
|
/**
|
|
|
|
|
|
* Sanity check on the metadata header.
|
|
|
|
|
|
* @remark Relevant to detect memory corruption or when accessing some
|
|
|
|
|
|
* arbitrary memory location, which may or may not actually hold a TestFrame.
|
2024-11-20 15:32:49 +01:00
|
|
|
|
* Based on the assumption that it is unlikely that any given memory location
|
|
|
|
|
|
* just happens to hold our [marker word](\ref stampHeader()) by accident.
|
2024-11-20 05:50:44 +01:00
|
|
|
|
* @note this is only the base level of verification, because in addition
|
|
|
|
|
|
* \ref isValid verifies the checksum and \ref isPristine additionally
|
2024-11-20 15:32:49 +01:00
|
|
|
|
* recomputes the data generation to see if it matches the Meta::distinction.
|
2024-11-20 05:50:44 +01:00
|
|
|
|
*/
|
|
|
|
|
|
bool
|
|
|
|
|
|
TestFrame::Meta::isPlausible() const
|
|
|
|
|
|
{
|
|
|
|
|
|
return _MARK_ == stampHeader()
|
|
|
|
|
|
and stage <= DISCARDED;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-11-18 23:55:30 +01:00
|
|
|
|
TestFrame::Meta&
|
|
|
|
|
|
TestFrame::accessHeader()
|
|
|
|
|
|
{
|
2024-11-20 05:50:44 +01:00
|
|
|
|
if (not header_.isPlausible())
|
|
|
|
|
|
throw err::Invalid{"TestFrame: missing or corrupted metadata"};
|
2024-11-18 23:55:30 +01:00
|
|
|
|
return header_;
|
|
|
|
|
|
}
|
|
|
|
|
|
TestFrame::Meta const&
|
|
|
|
|
|
TestFrame::accessHeader() const
|
|
|
|
|
|
{
|
|
|
|
|
|
return unConst(this)->accessHeader();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TestFrame::StageOfLife
|
|
|
|
|
|
TestFrame::currStage() const
|
|
|
|
|
|
{
|
2024-11-20 05:50:44 +01:00
|
|
|
|
return header_.isPlausible()? header_.stage
|
|
|
|
|
|
: DISCARDED;
|
2024-11-18 23:55:30 +01:00
|
|
|
|
}
|
2011-10-31 00:13:35 +01:00
|
|
|
|
|
|
|
|
|
|
bool
|
2024-11-20 05:50:44 +01:00
|
|
|
|
TestFrame::Meta::operator== (Meta const&o) const
|
2011-10-31 00:13:35 +01:00
|
|
|
|
{
|
2024-11-20 05:50:44 +01:00
|
|
|
|
return isPlausible() and o.isPlausible()
|
|
|
|
|
|
and stage == o.stage
|
|
|
|
|
|
and checksum == o.checksum
|
|
|
|
|
|
and distinction == o.distinction;
|
2011-10-31 00:13:35 +01:00
|
|
|
|
}
|
2024-11-20 15:32:49 +01:00
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
|
TestFrame::operator== (void* memLocation) const
|
|
|
|
|
|
{
|
|
|
|
|
|
TestFrame& candidate (accessAsTestFrame (memLocation));
|
|
|
|
|
|
return candidate.isSane()
|
|
|
|
|
|
&& candidate == *this;
|
|
|
|
|
|
}
|
2024-11-20 05:50:44 +01:00
|
|
|
|
|
2011-10-31 00:13:35 +01:00
|
|
|
|
bool
|
|
|
|
|
|
TestFrame::contentEquals (TestFrame const& o) const
|
|
|
|
|
|
{
|
2024-11-27 15:31:50 +01:00
|
|
|
|
return data() == o.data();
|
2011-10-31 00:13:35 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-11-18 23:55:30 +01:00
|
|
|
|
|
2024-11-20 05:50:44 +01:00
|
|
|
|
/**
|
|
|
|
|
|
* Generate baseline data content based on the Meta::distinction seed.
|
|
|
|
|
|
* @remark the seed is a [discriminator](\ref buildDiscriminator) based
|
|
|
|
|
|
* on both the »family« and the frameNo within this family;
|
|
|
|
|
|
* thus closely related frames are very unlikely to hold the same
|
|
|
|
|
|
* baseline data. Of course, follow-up manipulations could change
|
|
|
|
|
|
* the data, which should be documented by \ref markChecksum().
|
|
|
|
|
|
*/
|
|
|
|
|
|
void
|
2024-11-18 23:55:30 +01:00
|
|
|
|
TestFrame::buildData()
|
|
|
|
|
|
{
|
|
|
|
|
|
auto gen = buildDataGenFrom (accessHeader().distinction);
|
2024-11-27 15:31:50 +01:00
|
|
|
|
for (uint64_t& dat : data64())
|
|
|
|
|
|
dat = gen.u64();
|
2024-11-20 05:50:44 +01:00
|
|
|
|
markChecksum();
|
2024-11-18 23:55:30 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-11-20 05:50:44 +01:00
|
|
|
|
/** verify the current data was not touched since initialisation
|
|
|
|
|
|
* @remark implemented by regenerating the data sequence deterministically,
|
2024-11-20 15:32:49 +01:00
|
|
|
|
* based on the Meta::distinction mark recorded in the metadata. */
|
2011-10-31 00:13:35 +01:00
|
|
|
|
bool
|
2024-11-20 05:50:44 +01:00
|
|
|
|
TestFrame::matchDistinction() const
|
2011-10-31 00:13:35 +01:00
|
|
|
|
{
|
2024-11-18 23:55:30 +01:00
|
|
|
|
auto gen = buildDataGenFrom (accessHeader().distinction);
|
2024-11-27 15:31:50 +01:00
|
|
|
|
for (uint64_t const& dat : data64())
|
|
|
|
|
|
if (dat != gen.u64())
|
2011-10-31 02:20:32 +01:00
|
|
|
|
return false;
|
|
|
|
|
|
return true;
|
2011-10-31 00:13:35 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-11-20 05:50:44 +01:00
|
|
|
|
/** @return a hash checksum computed over current data content */
|
2024-11-18 23:55:30 +01:00
|
|
|
|
HashVal
|
|
|
|
|
|
TestFrame::computeChecksum() const
|
2011-10-31 00:13:35 +01:00
|
|
|
|
{
|
2024-11-20 05:50:44 +01:00
|
|
|
|
HashVal checksum{0};
|
|
|
|
|
|
std::hash<char> getHash;
|
|
|
|
|
|
for (char const& dat : data())
|
|
|
|
|
|
lib::hash::combine (checksum, getHash (dat));
|
|
|
|
|
|
return checksum;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** @remark can be used to mark a manipulated new content as _valid_ */
|
|
|
|
|
|
HashVal
|
|
|
|
|
|
TestFrame::markChecksum()
|
|
|
|
|
|
{
|
|
|
|
|
|
return accessHeader().checksum = computeChecksum();
|
2011-10-31 00:13:35 +01:00
|
|
|
|
}
|
2024-11-20 05:50:44 +01:00
|
|
|
|
|
2011-10-31 00:13:35 +01:00
|
|
|
|
|
2024-11-18 23:55:30 +01:00
|
|
|
|
bool
|
|
|
|
|
|
TestFrame::hasValidChecksum() const
|
|
|
|
|
|
{
|
2024-11-20 05:50:44 +01:00
|
|
|
|
return accessHeader().checksum == computeChecksum();
|
2024-11-18 23:55:30 +01:00
|
|
|
|
}
|
2011-10-31 00:13:35 +01:00
|
|
|
|
|
2011-10-31 02:20:32 +01:00
|
|
|
|
bool
|
2024-11-20 05:50:44 +01:00
|
|
|
|
TestFrame::isSane() const
|
2011-10-31 02:20:32 +01:00
|
|
|
|
{
|
2024-11-20 05:50:44 +01:00
|
|
|
|
return header_.isPlausible();
|
2011-10-31 02:20:32 +01:00
|
|
|
|
}
|
2011-10-31 00:13:35 +01:00
|
|
|
|
|
2011-10-31 02:20:32 +01:00
|
|
|
|
bool
|
2024-11-20 05:50:44 +01:00
|
|
|
|
TestFrame::isValid() const
|
2011-10-31 00:13:35 +01:00
|
|
|
|
{
|
2024-11-20 05:50:44 +01:00
|
|
|
|
return isSane()
|
|
|
|
|
|
and hasValidChecksum();
|
2011-10-31 00:13:35 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-10-31 02:20:32 +01:00
|
|
|
|
bool
|
2024-11-20 05:50:44 +01:00
|
|
|
|
TestFrame::isPristine() const
|
2011-10-31 00:13:35 +01:00
|
|
|
|
{
|
2024-11-20 05:50:44 +01:00
|
|
|
|
return isValid()
|
|
|
|
|
|
and matchDistinction();
|
2011-10-31 00:13:35 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-11-18 23:55:30 +01:00
|
|
|
|
bool
|
2024-11-20 05:50:44 +01:00
|
|
|
|
TestFrame::isAlive() const
|
2024-11-18 23:55:30 +01:00
|
|
|
|
{
|
|
|
|
|
|
return isSane()
|
2024-11-20 05:50:44 +01:00
|
|
|
|
and not isDead();
|
2024-11-18 23:55:30 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool
|
2024-11-20 05:50:44 +01:00
|
|
|
|
TestFrame::isDead() const
|
2024-11-18 23:55:30 +01:00
|
|
|
|
{
|
|
|
|
|
|
return isSane()
|
2024-11-20 05:50:44 +01:00
|
|
|
|
and (DISCARDED == currStage());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** @note performing an unchecked conversion of the given
|
|
|
|
|
|
* memory location to be accessed as TestFrame.
|
|
|
|
|
|
* The sanity of the data found at that location
|
|
|
|
|
|
* is checked as well, not only the lifecycle flag.
|
|
|
|
|
|
*/
|
|
|
|
|
|
bool
|
|
|
|
|
|
TestFrame::isAlive (void* memLocation)
|
|
|
|
|
|
{
|
|
|
|
|
|
TestFrame& candidate (accessAsTestFrame (memLocation));
|
|
|
|
|
|
return candidate.isAlive();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
|
TestFrame::isDead (void* memLocation)
|
|
|
|
|
|
{
|
|
|
|
|
|
TestFrame& candidate (accessAsTestFrame (memLocation));
|
|
|
|
|
|
return candidate.isDead();
|
2024-11-18 23:55:30 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2011-10-31 00:13:35 +01:00
|
|
|
|
|
2018-11-15 23:55:13 +01:00
|
|
|
|
}}} // namespace steam::engine::test
|