diff --git a/tests/15library.tests b/tests/15library.tests
index 118e9932f..6a8e4c654 100644
--- a/tests/15library.tests
+++ b/tests/15library.tests
@@ -598,7 +598,7 @@ return: 0
END
-PLANNED "Several elements" SeveralBuilder_test < frame.data().size()); // additional metadata placed behind
+ }
+
+
+ void
+ verifyDataContent()
+ {
TestFrame frameA;
TestFrame frameB;
TestFrame frameC(5);
@@ -90,6 +111,11 @@ namespace test {
CHECK (frameA != frameC);
CHECK (frameB != frameC);
+ CHECK (frameA.data() == frameB.data());
+ CHECK (frameA.data() != frameC.data());
+ for (uint i=0; iisDead());
- CHECK (frame->isAlive());
- CHECK (frame->isSane());
+ CHECK (not frame->isDead());
+ CHECK ( frame->isAlive());
+ CHECK ( frame->isValid());
frame->~TestFrame();
- CHECK ( TestFrame::isDead (frame));
- CHECK (!TestFrame::isAlive (frame));
+ CHECK ( TestFrame::isDead (frame));
+ CHECK (not TestFrame::isAlive (frame));
+ CHECK ( frame->isValid());
+ CHECK ( frame->isSane());
}
@@ -151,8 +202,8 @@ namespace test {
{
thisFrames[i].swap (prevFrames[i]);
thisFrames[i].reset (new TestFrame(nr, i));
- CHECK (thisFrames[i]->isSane());
- CHECK (prevFrames[i]->isSane());
+ CHECK (thisFrames[i]->isPristine());
+ CHECK (prevFrames[i]->isPristine());
CHECK (prevFrames[i]->isAlive());
CHECK (*thisFrames[i] != *prevFrames[i]); // differs from predecessor within the same channel
@@ -165,18 +216,18 @@ namespace test {
} } }
- /** @test the table of test frames
- * computed on demand */
+
+ /** @test the table of test frames computed on demand */
void
useFrameTable()
{
- TestFrame& frX = testData(3,50);
- TestFrame& frY = testData(3,25);
- TestFrame& frZ = testData(3,50);
+ TestFrame& frX = testData(50,3);
+ TestFrame& frY = testData(50,2);
+ TestFrame& frZ = testData(50,3);
- CHECK (frX.isSane());
- CHECK (frY.isSane());
- CHECK (frZ.isSane());
+ CHECK (frX.isPristine());
+ CHECK (frY.isPristine());
+ CHECK (frZ.isPristine());
CHECK (frX != frY);
CHECK (frX == frZ);
@@ -185,14 +236,22 @@ namespace test {
CHECK (isSameObject (frX, frZ));
corruptMemory(&frZ,40,20);
- CHECK (!frX.isSane());
- CHECK (!testData(3,50).isSane());
- CHECK ( testData(3,51).isSane());
- CHECK ( testData(3,49).isSane());
+ CHECK (not frX.isPristine());
+ CHECK (not testData(50,3).isPristine());
+ CHECK ( testData(51,3).isPristine());
+ CHECK ( testData(49,3).isPristine());
+
+ char c = testData(49,3).data()[5]; // some arbitrary content
TestFrame::reseed();
- CHECK ( testData(3,50).isSane());
+ CHECK ( testData(50,3).isPristine());
+ CHECK (c != testData(49,3).data()[5]); // content regenerated with different seed
+
+ TestFrame o{49,3}; // all data content is reproducible with the new seed
+ CHECK (not isSameObject(o, testData(49,3)));
+ CHECK (o == testData(49,3));
+ CHECK (o.data()[5] == testData(49,3).data()[5]);
}
};
diff --git a/tests/core/steam/engine/testframe.cpp b/tests/core/steam/engine/testframe.cpp
index ba379b200..8a6a3fe35 100644
--- a/tests/core/steam/engine/testframe.cpp
+++ b/tests/core/steam/engine/testframe.cpp
@@ -12,7 +12,22 @@
* *****************************************************************/
/** @file testframe.cpp
- ** Implementation of fake data frames to support unit testing
+ ** 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.
*/
@@ -31,8 +46,9 @@
namespace steam {
-namespace engine {
-namespace test {
+namespace engine{
+namespace test {
+ namespace err = lumiera::error;
using util::unConst;
using std::vector;
@@ -105,7 +121,7 @@ namespace test {
stampHeader()
{
static const HashVal MARK = lib::entropyGen.hash()
- | 0b1000'1000'1000'1000'1000'1000'1000'1000;
+ | 0b1000'1000'1000'1000'1000'1000'1000'1000; //////////////////////////////TICKET #722 : not portable because HashVal ≡ size_t — should it be?
return MARK;
}
@@ -201,13 +217,7 @@ namespace test {
TestFrame&
- testData (uint seqNr)
- {
- return accessTestFrame (seqNr, 0);
- }
-
- TestFrame&
- testData (uint chanNr, uint seqNr)
+ testData (uint seqNr, uint chanNr)
{
return accessTestFrame (seqNr,chanNr);
}
@@ -227,7 +237,7 @@ namespace test {
TestFrame::reseed()
{
testFrames.reset();
- drawSeed (lib::defaultGen);
+ dataSeed = drawSeed (lib::defaultGen);
}
@@ -251,8 +261,8 @@ namespace test {
TestFrame::TestFrame (uint seq, uint family)
: header_{seq,family}
{
+ buildData();
ASSERT (0 < header_.distinction);
- header_.checksum = buildData();
ENSURE (CREATED == header_.stage);
ENSURE (isPristine());
}
@@ -269,7 +279,7 @@ namespace test {
TestFrame::operator= (TestFrame const& o)
{
if (not isAlive())
- throw new error::Logic ("target TestFrame already dead or unaccessible");
+ throw err::Logic ("target TestFrame already dead or unaccessible");
if (not util::isSameAdr (this, o))
{
data() = o.data();
@@ -280,43 +290,41 @@ namespace test {
}
+ /**
+ * 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.
+ * Based on the assumption that it is unlikely that some random memory location
+ * just happens to hold our [marker word](\ref stampHeader()).
+ * @note this is only the base level of verification, because in addition
+ * \ref isValid verifies the checksum and \ref isPristine additionally
+ * recomputes the data generation to see if it matches the Meta::distinction
+ */
+ bool
+ TestFrame::Meta::isPlausible() const
+ {
+ return _MARK_ == stampHeader()
+ and stage <= DISCARDED;
+ }
+
TestFrame::Meta&
TestFrame::accessHeader()
{
+ if (not header_.isPlausible())
+ throw err::Invalid{"TestFrame: missing or corrupted metadata"};
return header_;
}
TestFrame::Meta const&
TestFrame::accessHeader() const
{
- ///////////////////////OOO detect if valid header present and else throw
return unConst(this)->accessHeader();
}
TestFrame::StageOfLife
TestFrame::currStage() const
{
- ///////////////////////OOO detect if valid header present and then access
- }
-
- /** @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.isSane()
- && candidate.isAlive();
- }
-
- bool
- TestFrame::isDead (void* memLocation)
- {
- TestFrame& candidate (accessAsTestFrame (memLocation));
- return candidate.isSane()
- && candidate.isDead();
+ return header_.isPlausible()? header_.stage
+ : DISCARDED;
}
bool
@@ -327,67 +335,83 @@ namespace test {
&& candidate == *this;
}
+ bool
+ TestFrame::Meta::operator== (Meta const&o) const
+ {
+ return isPlausible() and o.isPlausible()
+ and stage == o.stage
+ and checksum == o.checksum
+ and distinction == o.distinction;
+ }
+
bool
TestFrame::contentEquals (TestFrame const& o) const
{
- for (uint i=0; i 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();
+ }
+
+
bool
TestFrame::hasValidChecksum() const
{
- ////////////////////////////////////////////OOO actually compute checksum and verify
- }
-
- bool
- TestFrame::isAlive() const
- {
- return (CREATED == currStage())
- || (EMITTED == currStage());
- }
-
- bool
- TestFrame::isDead() const
- {
- return (DISCARDED == currStage());
+ return accessHeader().checksum == computeChecksum();
}
bool
TestFrame::isSane() const
{
- return ( (CREATED == currStage())
- ||(EMITTED == currStage())
- ||(DISCARDED == currStage()))
- && verifyData();
+ return header_.isPlausible();
}
bool
@@ -399,9 +423,42 @@ namespace test {
bool
TestFrame::isPristine() const
+ {
+ return isValid()
+ and matchDistinction();
+ }
+
+ bool
+ TestFrame::isAlive() const
{
return isSane()
- and hasValidChecksum();
+ and not isDead();
+ }
+
+ bool
+ TestFrame::isDead() const
+ {
+ return isSane()
+ 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();
}
diff --git a/tests/core/steam/engine/testframe.hpp b/tests/core/steam/engine/testframe.hpp
index 0d9d932f0..31d2756c2 100644
--- a/tests/core/steam/engine/testframe.hpp
+++ b/tests/core/steam/engine/testframe.hpp
@@ -12,7 +12,21 @@
*/
/** @file testframe.hpp
- ** Unit test helper to generate fake test data frames
+ ** Unit test helper to generate fake test data frames.
+ ** Each TestFrame holds a 1k buffer of byte data, which can be
+ ** verified, accessed and manipulated to emulate media computations.
+ ** A [metadata header](\ref steam::engine::test::TestFrame::Meta) is placed
+ ** in memory behind the working buffer, which allows to detect data corruption
+ ** and stores a lifecycle phase and a data checksum.
+ **
+ ** The contents of each TestFrame are filled on creation with pseudo-random data,
+ ** which is created from a _discriminator seed,_ based on a »family« and a »frame-nr«
+ ** within the family. Due to the deterministic nature of these computations, the
+ ** _pristine state_ of any frame can be determined. But the payload data is accessible
+ ** and can be manipulated, and a new [checksum can be recorded](\ref TestFrame::markChecksum).
+ **
+ ** For ease of testing, a static store of TestFrame instances is maintained internally,
+ ** and an arbitrary memory location can be treated as TestFrame.
*/
@@ -68,6 +82,8 @@ namespace test {
StageOfLife stage;
Meta (uint seq, uint family);
+ bool isPlausible() const;
+ bool operator== (Meta const&) const;
};
/** inline storage buffer for the payload media data */
@@ -86,6 +102,9 @@ namespace test {
TestFrame (TestFrame const&);
TestFrame& operator= (TestFrame const&);
+ /** recompute and store checksum based on current contents */
+ HashVal markChecksum();
+
/** Helper to verify that a given memory location holds
* an active TestFrame instance (created, not yet destroyed)
* @return true if the TestFrame datastructure is intact and
@@ -114,8 +133,8 @@ namespace test {
private:
bool contentEquals (TestFrame const& o) const;
- bool verifyData() const;
- HashVal buildData();
+ bool matchDistinction() const;
+ void buildData();
Meta& accessHeader();
Meta const& accessHeader() const;
StageOfLife currStage() const;
@@ -131,9 +150,7 @@ namespace test {
* test frames filled with different yet reproducible pseudo random data.
* Client code is free to access and corrupt this data.
*/
- TestFrame& testData (uint seqNr);
-
- TestFrame& testData (uint chanNr, uint seqNr);
+ TestFrame& testData (uint seqNr =0, uint chanNr =0);
diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm
index 32829ca5a..607ee0ec8 100644
--- a/wiki/thinkPad.ichthyo.mm
+++ b/wiki/thinkPad.ichthyo.mm
@@ -17871,9 +17871,7 @@
-
-
-
+
ScrollWindowPos == wo befindet sich das Scroll-Window (sichtbarer Ausschnitt) innerhalb eines größeren Intervalles, welches vom Widget dargestellt wird
@@ -18742,9 +18740,7 @@
-
-
-
+
Fazit: ja die Lösung funktioniert und erscheint stabil
@@ -18996,9 +18992,7 @@
-
-
-
+
auch hier mehrstufige Prüfung...
@@ -19552,9 +19546,7 @@
-
-
-
+
-
@@ -20223,9 +20215,7 @@
-
-
-
+
...den eingebauten Debug-Meldungen zufolge zu urteilen
@@ -21451,9 +21441,7 @@
-
-
-
+
wie ich's auch drehe und wende, daran führt kein Weg vorbei. Weil die Referenz eben nicht wirklich global ist, sondern einen root-Kontext darstellt (nämlich die umschließende Timeline).
@@ -24436,9 +24424,7 @@
-
-
-
+
wird komplett erledigt durch TrackBody::establishTrackSpace
@@ -42071,9 +42057,7 @@
-
-
-
+
hinreichend große Fenster (ab ein paar hunder Pixeln) können die ganze Zeitdomäne abdecken
@@ -43371,9 +43355,7 @@
-
-
-
+
-
-
-
+
man muß Floating-point runden wenn man glatte Werte will
@@ -45937,9 +45917,7 @@
-
-
-
+
(GlobalCtx)->InteractionDirector->Navigator
@@ -46086,9 +46064,7 @@
-
-
-
+
block[__element][--modifier]
@@ -46231,9 +46207,7 @@
-
-
-
+
vom tangible initiiert
@@ -56402,8 +56376,9 @@
-
+
+
@@ -56463,11 +56438,16 @@
+
+
+
+
+
@@ -56758,8 +56738,8 @@
-
-
+
+
@@ -56777,8 +56757,7 @@
Diskriminator-ID ≔ (seq+1) * (dataSeed+family)
-
-
+
@@ -56788,8 +56767,7 @@
Erläuterung: jede »family« hat ein eigenes Stepping
-
-
+
@@ -56800,8 +56778,7 @@
...weil es dann passieren könnte, daß für bestimmte Familien die Frames sich nicht mehr unterscheiden
-
-
+
@@ -56820,17 +56797,17 @@
-
-
+
+
-
-
+
+
-
-
+
+
@@ -56851,12 +56828,14 @@
-
-
+
+
-
-
-
+
+
+
+
+
@@ -56874,26 +56853,26 @@
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
+
@@ -56902,8 +56881,9 @@
+
-
+
@@ -56912,8 +56892,9 @@
+
-
+
@@ -56922,10 +56903,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ frameNr und seqNr - Parameter waren vertauscht bei testData()
+
+
+ Das habe ich erst bemerkt, als ich tatsächlich dazu noch einen frei stehenden TestFrame mit gleichen Koordinaten erzeugt und verglichen habe...
+
+
+ GnaGnaGna
+
+
+
+
+
+
+
+
@@ -56951,13 +56973,13 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
@@ -57001,10 +57023,15 @@
-
+
+
+
+
-
+
+
+
@@ -92272,11 +92299,11 @@ Date: Thu Apr 20 18:53:17 2023 +0200
-
+
-
-
+
+
@@ -92342,7 +92369,7 @@ Date: Thu Apr 20 18:53:17 2023 +0200
-
+
@@ -92352,9 +92379,13 @@ Date: Thu Apr 20 18:53:17 2023 +0200
-
-
-
+
+
+
+
+
+
+
@@ -92363,8 +92394,9 @@ Date: Thu Apr 20 18:53:17 2023 +0200
+
-
+
@@ -92373,14 +92405,15 @@ Date: Thu Apr 20 18:53:17 2023 +0200
+
-
-
+
+
-
-
-
+
+
+