Library: ensure automatic re-seeding for TestFrame
This closes a ''conceptual gap.'' There was a `lib::TestFrame::reseed()` function, which should be invoked whenever a clean / deterministinc seed is required for computations involving `TestFrame` data. On occasion I noticed that most actual usages of `TestFrame`, which became quite common lately, were missing this `reseed()` call, while the enclosing test had indeed a proper Test::seedRand() call. So my conclusion is: if even ''I myself'' miss that fine point frequently, it is justified to automated this setup, even while `TestFrame` is right now the only client of such a setup-facility. There is a twist though. `TestFrame` is part of the ''Engine'' test coverage, i.e. it is linked into `libtest-core.so`. While the support for random numbers and reseeding is obviously a very basic library feature, and linked into `liblumiera.so` **Oh well**. So now we have ''yet another'' static registration service. I kept everything as simple as possible, which means, we continue to use the ''common, global random generator'' from the library, and there is no protection against some other code using those library functions in a non-deterministic way. `lib/random-reseed.cpp` is just a glorified hard-wired setup, beware!
This commit is contained in:
parent
cfdb659ccb
commit
5a203513c9
8 changed files with 547 additions and 7 deletions
95
src/lib/random-reseed.cpp
Normal file
95
src/lib/random-reseed.cpp
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
RandomReseed - establish controlled seed for deterministic randomness
|
||||
|
||||
Copyright (C)
|
||||
2026, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
**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.
|
||||
|
||||
* *****************************************************************/
|
||||
|
||||
|
||||
/** @file random-reseed.cpp
|
||||
** Implementation of coordinated reseeding of random number generators.
|
||||
** @todo 3/2024 work out how some executions or performances are configured reproducibly.
|
||||
*/
|
||||
|
||||
|
||||
#include "lib/error.hpp"
|
||||
#include "lib/random.hpp"
|
||||
#include "lib/random-reseed.hpp"
|
||||
#include "lib/format-string.hpp"
|
||||
#include "lib/iter-adapter-stl.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace lib {
|
||||
namespace err = lumiera::error;
|
||||
|
||||
using util::_Fmt;
|
||||
using util::contains;
|
||||
using iter_stl::eachVal;
|
||||
|
||||
typedef void (*Hook)();
|
||||
|
||||
|
||||
namespace {// Implementation: a central registry for callbacks...
|
||||
|
||||
class RandomReseed
|
||||
: util::NonCopyable
|
||||
{
|
||||
std::map<uint, Hook> registry_;
|
||||
|
||||
public:
|
||||
void
|
||||
enrol (uint idx, Hook callback)
|
||||
{
|
||||
if (contains (registry_, idx))
|
||||
throw err::Fatal{_Fmt{"Duplicate registration for random-reseeding-slot %d"} % idx};
|
||||
|
||||
registry_[idx] = callback;
|
||||
}
|
||||
|
||||
void
|
||||
triggerAll()
|
||||
{
|
||||
for (Hook hook : eachVal (registry_))
|
||||
(*hook)();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Static internal access to a global (hidden) registry.
|
||||
* @note use Meyer's Singleton to allow registration from
|
||||
* a static-init context, without prerequisites.
|
||||
*/
|
||||
inline RandomReseed&
|
||||
randomReseedService()
|
||||
{
|
||||
static RandomReseed registry;
|
||||
return registry;
|
||||
}
|
||||
}//(End)hidden impl.
|
||||
|
||||
|
||||
|
||||
uint
|
||||
register_at_seq (uint idx, Hook callback)
|
||||
{
|
||||
randomReseedService().enrol (idx, callback);
|
||||
return idx;
|
||||
}
|
||||
|
||||
void
|
||||
reseed_for_test (SeedNucleus& reseedingNucleus)
|
||||
{
|
||||
lib::defaultGen.reseed (reseedingNucleus);
|
||||
randomReseedService().triggerAll();
|
||||
}
|
||||
|
||||
|
||||
} // namespace lib
|
||||
76
src/lib/random-reseed.hpp
Normal file
76
src/lib/random-reseed.hpp
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
RANDOM-RESEED.hpp - establish controlled seed for deterministic randomness
|
||||
|
||||
Copyright (C)
|
||||
2026, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
**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.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/** @file random-reseed.hpp
|
||||
** A setup to allow for coordinated reseeding of otherwise independent components.
|
||||
** The primary purpose of this setup is to allow for probabilistic unit-testing,
|
||||
** yet including some facilities which are more intricate to setup. These will have
|
||||
** to configure themselves to be registered with this random-reseeding service.
|
||||
** Each registration-»slot« allocates an unique index number, and for each such
|
||||
** index, some random values will be drawn from the global lib::defaultGen.
|
||||
** @remark reseeding for »deterministic randomness« is an intricate topic.
|
||||
** This setup is intended to be used as "one-stop solution" for all basic stuff,
|
||||
** commonly used in unit tests whenever "some random XYZ" seems appropriate.
|
||||
** Obviously, such a solution can only be provisional, and must be augmented,
|
||||
** once new requirements arise. In 2026, using pseudo-random values and chained
|
||||
** hash computations has become quite commonplace in the Lumiera test suite;
|
||||
** since 2024, there is a framework in place to allow for controlled re-seeding
|
||||
** and deterministic computation. However, in practice, the necessary setup
|
||||
** and initialisation was overlooked frequently, and thus we now have to raise
|
||||
** to the next level, by providing this one and central implementation function.
|
||||
** @warning _deliberately_ there is no coordination in place to ensure consistency
|
||||
** of registration or initialisation. This is only a convenient front-end, while
|
||||
** the actual registration and setup remains essentially hard-wired.
|
||||
** @see Test::seedRand()
|
||||
** @see Random_test
|
||||
*/
|
||||
|
||||
|
||||
#ifndef LIB_RANDOM_RESEED_H
|
||||
#define LIB_RANDOM_RESEED_H
|
||||
|
||||
|
||||
#include "lib/integral.hpp"
|
||||
|
||||
|
||||
namespace lib {
|
||||
|
||||
class SeedNucleus; // see lib/random.hpp
|
||||
|
||||
|
||||
/**
|
||||
* Install a callback \a Hook to be invoked whenever
|
||||
* _reseeding_ of random number generators becomes necessary.
|
||||
* @param idx number of a distinct »slot« to allocate;
|
||||
* invocation will happen in ascending order
|
||||
* @remark this function can be used to plant a static variable
|
||||
* to ensure registration happens early and once within
|
||||
* some implementation translation unit. The callback
|
||||
* is called way later, typically when the first test
|
||||
* case invokes test::Test::seedRand()
|
||||
*/
|
||||
uint register_at_seq (uint idx, void(*)(void) );
|
||||
|
||||
/**
|
||||
* Reseed generic randomness used for probabilistic unit-testing.
|
||||
* After calling this function, the default random generator in the Lumiera library
|
||||
* is reconfigured and reseeded based on the given seeding nucleus; furthermore, a
|
||||
* small, hard-wired collection of test facilities will be re-set and re-seeded
|
||||
* from this newly configured random source.
|
||||
*/
|
||||
void reseed_for_test (SeedNucleus&);
|
||||
|
||||
|
||||
} // namespace lib
|
||||
#endif /*LIB_RANDOM_RESEED_H*/
|
||||
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#include "lib/error.hpp"
|
||||
#include "lib/symbol.hpp"
|
||||
#include "lib/random-reseed.hpp"
|
||||
#include "lib/format-cout.hpp"
|
||||
#include "lib/test/suite.hpp"
|
||||
#include "lib/test/run.hpp"
|
||||
|
|
@ -210,7 +211,7 @@ namespace test {
|
|||
void
|
||||
Test::seedRand()
|
||||
{
|
||||
lib::defaultGen.reseed (suiteSeed);
|
||||
lib::reseed_for_test (suiteSeed);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -78,7 +78,6 @@ namespace test {
|
|||
run (Arg)
|
||||
{
|
||||
seedRand();
|
||||
TestFrame::reseed();
|
||||
|
||||
processing_generateFrame();
|
||||
processing_generateMultichan();
|
||||
|
|
|
|||
|
|
@ -54,7 +54,6 @@ namespace test {
|
|||
|
||||
// Assuming some data block is »given«
|
||||
seedRand();
|
||||
TestFrame::reseed();
|
||||
size_t frameNr = defaultGen.u64();
|
||||
TestFrame dataBlock (frameNr);
|
||||
CHECK ( dataBlock.isPristine());
|
||||
|
|
|
|||
|
|
@ -70,8 +70,7 @@ namespace test {
|
|||
virtual void
|
||||
run (Arg)
|
||||
{
|
||||
seedRand();
|
||||
TestFrame::reseed();
|
||||
seedRand(); // ◁—————————————————————————— Note: TestFrame::reseed() automatically invoked here
|
||||
|
||||
simpleUsage();
|
||||
verifyDataContent();
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
#include "lib/error.hpp"
|
||||
#include "lib/random.hpp"
|
||||
#include "lib/random-reseed.hpp"
|
||||
#include "lib/hash-standard.hpp"
|
||||
#include "lib/hash-combine.hpp"
|
||||
#include "steam/engine/testframe.hpp"
|
||||
|
|
@ -192,11 +193,13 @@ namespace test {
|
|||
|
||||
|
||||
/**
|
||||
* @remark this function should be invoked at the start of any test
|
||||
* which requires reproducible data values in the TestFrame.
|
||||
* @remark this function can be invoked whenever either completely new
|
||||
* or reproducible data values are required in TestFrame instances.
|
||||
* 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.
|
||||
* @note A default registration setup ensures this function is invoked
|
||||
* from each call of test::Test::seedRand()
|
||||
* @warning after invoking reseed(), the validity of previously generated
|
||||
* frames can no longer be verified.
|
||||
*/
|
||||
|
|
@ -207,6 +210,11 @@ namespace test {
|
|||
dataSeed = drawSeed (lib::defaultGen);
|
||||
}
|
||||
|
||||
namespace { // ---------------automatic-registration-for-uint-tests-----------------
|
||||
const uint RESEED_SLOT{1};
|
||||
static uint _registration_ = lib::register_at_seq (RESEED_SLOT, &TestFrame::reseed );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -60350,6 +60350,32 @@
|
|||
</html></richcontent>
|
||||
<arrowlink COLOR="#7e8fc5" DESTINATION="ID_39230986" ENDARROW="Default" ENDINCLINATION="-219;12;" ID="Arrow_ID_1543995286" STARTARROW="None" STARTINCLINATION="616;34;"/>
|
||||
</node>
|
||||
<node COLOR="#435e98" CREATED="1771788116588" ID="ID_1995924412" MODIFIED="1771803485608" TEXT="2/2026 re-Seeding muß automatisiert werden">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Das ist nicht eigentlich ein Bug, aber etwas, was man natürlicherweise erwarten würde; bisher habe ich mich auf den Standpunkt gestellt, daß man sich da schon selber darum kümmern sollte. Wenn ich jetzt aber durch alle Tests suche, die TestFrame verwenden, finde ich fast keinen, der ein korrektes re-Seeding macht, aber die meisten haben immerhin ein Test::seedRand()
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<linktarget COLOR="#a00e3d" DESTINATION="ID_1995924412" ENDARROW="Default" ENDINCLINATION="-2471;146;" ID="Arrow_ID_1407537427" SOURCE="ID_262212223" STARTARROW="None" STARTINCLINATION="-636;133;"/>
|
||||
<node CREATED="1771788718816" ID="ID_1308819378" MODIFIED="1771788732388" TEXT="TestFrame::reseed() zieht einen neuen Diskriminator"/>
|
||||
<node CREATED="1771788734069" ID="ID_1418590090" MODIFIED="1771788755081">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
das muß <i>nach</i> dem Herstellen eines deterministischen Master-Seed passieren
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node COLOR="#35648a" CREATED="1771788763842" ID="ID_1471348244" MODIFIED="1771803475338" TEXT="dieser Zusammenhang ist alles andere als offensichtlich ⟹ automatisieren">
|
||||
<arrowlink COLOR="#422ac0" DESTINATION="ID_400533719" ENDARROW="Default" ENDINCLINATION="560;-60;" ID="Arrow_ID_1144401880" STARTARROW="None" STARTINCLINATION="59;634;"/>
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1729979079809" ID="ID_1106549131" MODIFIED="1729979157169" TEXT="Eigenschaften">
|
||||
<icon BUILTIN="info"/>
|
||||
|
|
@ -61649,6 +61675,343 @@
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#435e98" CREATED="1771788793398" FOLDED="true" ID="ID_1642148991" MODIFIED="1771803623517" TEXT="2026/02 re-seeding-Hook schaffen">
|
||||
<node CREATED="1771788805420" ID="ID_1256962982" MODIFIED="1771789656478" TEXT="Begründung">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Es wird in Zukunft immer wieder Einrichtungen geben, die neu re-seeded werden müssen, um deterministisch zu sein. Dieses re-Seeding muß zuverlässig und reproduzierbar erfolgen, nachdem der globale PRNG neu initialisiert wurde.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
<node CREATED="1771789666980" ID="ID_981389862" MODIFIED="1771789803408" TEXT="relevant für...">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
...jede Art von Einrichtung, die in komplexer Weise vom Random-Seed abhängt, und bei korrektem Setup deterministisch gemacht werden kann; also immer dann, wenn dieses Setup »schwierig« wird! Als Kontrast: für einen banalen Test zieht man sich einfach eine Zufallszahl und gut is; inwiefern das Test-Ergabnis von dieser Zufallszahl abhängt, ist in einem solchen Fall komplett offensichtlich.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
<node CREATED="1771789805546" ID="ID_400533719" MODIFIED="1771790039049" TEXT="TestFrame">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
TestFrame definiert nicht nur einen Mechanismus, einen Datenblock von Zufallszahlen zu erzeugen, sondern er definiert auch deterministische Sequenzen und Familien solcher Sequenzen. Diese werden aus einem »Diskriminator« gebildet. Per TestFrame::reseed() verwirft man <b>alle bestehenden Testframes<i> </i></b>und zieht einen neuen Diskriminator. Sofern ein Test mit Test-Frames <i>einzeln</i> reproduzierbar sein soll, muß dieres reseed() aufgerufen werden. Das übersieht man natürlich leicht, denn normalerweise will man solche Tests nicht deterministisch wiederholen (was solange gilt, bis es mal ein ernstes Problem gibt)
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
<linktarget COLOR="#422ac0" DESTINATION="ID_400533719" ENDARROW="Default" ENDINCLINATION="560;-60;" ID="Arrow_ID_1144401880" SOURCE="ID_1471348244" STARTARROW="None" STARTINCLINATION="59;634;"/>
|
||||
<node COLOR="#338800" CREATED="1771803415569" HGAP="27" ID="ID_1924672804" MODIFIED="1771803444630" TEXT="registriert sich jetzt automatisch für random-reseed" VSHIFT="13">
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1771790054409" ID="ID_357338456" MODIFIED="1771803328757" TEXT="Design-Fragen">
|
||||
<icon BUILTIN="help"/>
|
||||
<node CREATED="1771790065853" ID="ID_1743155131" MODIFIED="1771790072136" TEXT="wie tief soll das sitzen?">
|
||||
<node CREATED="1771790075663" ID="ID_199419157" MODIFIED="1771790086593" TEXT="soll nicht »global« sein"/>
|
||||
<node CREATED="1771790095335" ID="ID_1384451064" MODIFIED="1771790139494" TEXT="ist keine Vorgabe für die Applikation selber">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Wenn die Lumiera-Applikation mal etwas Vergleichbares braucht, muß es anderweitig an den Application-Lifecycle gebunden werden
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
<node CREATED="1771790141343" ID="ID_82436164" MODIFIED="1771790159436">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
soll aber <i>ohne Weiteres</i> stets für jeden Test verfügbar sein
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
<node CREATED="1771790162692" ID="ID_1146500637" MODIFIED="1771790172217" TEXT="⟹ gehört ins Test-Framework"/>
|
||||
</node>
|
||||
<node CREATED="1771790176570" ID="ID_1357084707" MODIFIED="1771790190212" TEXT="wie »deterministisch« soll es sein?">
|
||||
<node CREATED="1771790191983" ID="ID_1480062449" MODIFIED="1771790209296" TEXT="eigentlich möchte man bloß einen gescheiterten Test wiederholen können"/>
|
||||
<node CREATED="1771790290929" ID="ID_1202418399" MODIFIED="1771790309172" TEXT="kleine Lösung: ich werfe den Test nochmal per Debugger an...."/>
|
||||
<node CREATED="1771790309974" ID="ID_420047653" MODIFIED="1771790327300" TEXT="große Lösung: ich reproduziere auf einer anderen Plattform, oder mit Release/Debug-Build"/>
|
||||
</node>
|
||||
<node CREATED="1771790516661" ID="ID_240891815" MODIFIED="1771790530643" TEXT="wie »flexibel« und »aufwendig« können wir uns leisten?">
|
||||
<node CREATED="1771790541501" ID="ID_6099611" MODIFIED="1771790592906" TEXT="klarer Fall von YAGNI !">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Explizit ausformuliert:
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
in der Tat sich Probleme absehbar
|
||||
</li>
|
||||
<li>
|
||||
aber wir warten mit der Lösung bis sich diese erwartbaren Probleme tatsächlich manifestieren
|
||||
</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
<node CREATED="1771790594730" ID="ID_57250862" MODIFIED="1771790600805" TEXT="denkbare Spannbreite">
|
||||
<node CREATED="1771790773155" ID="ID_1631916355" MODIFIED="1771790890048" TEXT="eine zentrale Implementierungs-Funktion mit hart gecodeten Aufrufen">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Jede Einrichtung, die am re-Seeding teilnehmen muß, hat sich da selbst in den Code zu integrieren. Sobald sich diese Integrierung ändert, ändert sich der Seed für alle Beteiligten. Aufgrund der Layer-Ordnung können nur Library-Einrichtungen an einem solchen Setup teilnehmen; alles oberhalb muß dann auf weitere, verteilte Random-Generatoren aufbauen
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
<node CREATED="1771790606212" ID="ID_1443915290" MODIFIED="1771791021498" TEXT="ein Reseeding-System, mit dem eine feste Reihenfolge garantiert wird">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
irgend ein Koordiniertungs-System, entweder compile-time oder run-time. Es muß sicherstellen, daß Partizipatoren leicht hinzukonfiguriert werden können, idealerweise automatisch, indem man einen Header includiert. Weiterhin muß aber sichergestellt werden, daß die Ordnung der Zuteilung stabil bleibt. Konsequenz: das wird aufwendiger als es auf den ersten Blick aussieht; dafür ist die Aufgabe für die Konsumenten des Random-Seed sehr einfach
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
<node CREATED="1771790638283" ID="ID_847997173" MODIFIED="1771791176690" TEXT="lediglich einen Master-Seed bereitstellen — jeder muß seinen eigenen Generator verwalten">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Auch bei dieser Variante gibt es einen Registrierungs-Hook, der sehr bequem automatisiert wird. Allerdings liefert er nur <i>einen einzigen Seed-Wert identisch an alle Konsumenten.</i> Jeder Konsument muß daher zwingend seinen eigenen, lokalen Random-Generator verwalten und darf nirgends lib::defaultGen verwenden. Wenn mehr als ein einziger Client diese Regel mißachtet, bricht das System zusammen
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
<node CREATED="1771790731312" ID="ID_1007624727" MODIFIED="1771791752741" TEXT="eine Registrierung auf ein Application-Event">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Dieser Ansatz ist mit den beiden zuvor genannten Varianten kombinierbar. Es erlaubt dann beliebigen Komponenten in verschiedensten Setups, automatisch am re-Seeding teilzunehmen. Effektiv läuft das aber darauf hinaus, auch getrennte Generatoren für jeden Konsumenten zu verlangen, also keine bequeme Library-Funktion mehr!
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1771791759624" ID="ID_459999408" MODIFIED="1771791773321" TEXT="ich sehe folgende Stufen">
|
||||
<node CREATED="1771791777380" ID="ID_928787324" MODIFIED="1771794166900" TEXT="nichts tun! jeder Test ist selbst verantwortlich" VSHIFT="4">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
<u>Vorteil</u>: in den meisten Tests ist die Situation so einfach, daß sich all die schwierigeren Fragen überhaupt nicht stellen
|
||||
</p>
|
||||
<p>
|
||||
<u>Nachteil</u>: das Thema ist nicht offensichtlich und wird deshalb leicht übersehen, so daß man dann im Ernstfall vor einem nicht-reproduzierbaren Problem steht
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
<node COLOR="#435e98" CREATED="1771792328036" HGAP="25" ID="ID_1177735425" MODIFIED="1771792411958" TEXT="so habe ich das bisher gehalten" VSHIFT="-10">
|
||||
<font NAME="SansSerif" SIZE="10"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1771791855035" ID="ID_1248754284" MODIFIED="1771794227272" TEXT="zentrale Reseed-Funktion für alle problematischen Komponenten">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
<u>Vorteil</u>: man kümmert sich nur um das, was wirklich ein Problem darstellt, und läßt alles andere laufen
|
||||
</p>
|
||||
<p>
|
||||
<u>Nachteil</u>: das Problembewußtsein muß da sein, sonst funktioniert der Ansatz nicht
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
<linktarget COLOR="#a71043" DESTINATION="ID_1248754284" ENDARROW="Default" ENDINCLINATION="-130;5;" ID="Arrow_ID_1619567275" SOURCE="ID_1809491977" STARTARROW="None" STARTINCLINATION="10;-13;"/>
|
||||
</node>
|
||||
<node CREATED="1771792007414" ID="ID_937121719" MODIFIED="1771792019688" TEXT="was »feineres«">
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#f7000e" CREATED="1771792428766" HGAP="23" ID="ID_846403897" MODIFIED="1771792451865" TEXT="YAGNI" VSHIFT="5">
|
||||
<font NAME="SansSerif" SIZE="13"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#ccb59b" COLOR="#6e2a38" CREATED="1771792036558" ID="ID_1809491977" MODIFIED="1771794227272" TEXT="Beschluß: zentrale Reseed-Funktion verwenden">
|
||||
<arrowlink COLOR="#a71043" DESTINATION="ID_1248754284" ENDARROW="Default" ENDINCLINATION="-130;5;" ID="Arrow_ID_1619567275" STARTARROW="None" STARTINCLINATION="10;-13;"/>
|
||||
<font ITALIC="true" NAME="SansSerif" SIZE="14"/>
|
||||
<icon BUILTIN="yes"/>
|
||||
<node CREATED="1771792165521" ID="ID_1770432641" MODIFIED="1771792197425" TEXT="eigentlich gibt es diese Funktion bereits: in suite.cpp"/>
|
||||
<node CREATED="1771792223499" ID="ID_208804929" MODIFIED="1771792240827" TEXT="zur besseren Dokumentation: random-reseed.hpp|cpp"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1771794038416" ID="ID_1190475268" MODIFIED="1771803309859" TEXT="Implementierung">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#bb1490" CREATED="1771794484488" ID="ID_1866843924" MODIFIED="1771794530803">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
tja ... alles schön gesültzt bis jetzt — <b>geht aber am Problem vorbei</b>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
<icon BUILTIN="smiley-angry"/>
|
||||
<node BACKGROUND_COLOR="#fafe99" COLOR="#980d32" CREATED="1771794537160" ID="ID_1578449818" MODIFIED="1771794672517" TEXT="�� Problem ist...">
|
||||
<node CREATED="1771794554047" ID="ID_1793181159" MODIFIED="1771794571808" TEXT="ich habe (bisher) exakt einen Use-Case"/>
|
||||
<node CREATED="1771794572796" ID="ID_1762569226" MODIFIED="1771794596493">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
und der paßt nicht ins Schema: der sitzt nämlich <b>NICHT</b> in der lib-Lumiera
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
<node CREATED="1771794643571" ID="ID_870959085" MODIFIED="1771794649046" TEXT="sondern in libtest-core.so"/>
|
||||
</node>
|
||||
<node CREATED="1771794721112" ID="ID_339259825" MODIFIED="1771795424036">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
wir haben auch schon ein App-Event-System — das ist aber <i><font color="#a70202">leider zu knapp definiert</font></i>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
...es kann nur einfachste void(void)-Funktionen aufrufen, und auch nicht in definierter Reihenfolge. Zudem gibt es keine Scopes, d.h. wir müßten ein globales Lifecycle-Event definieren ON_RESEED. Das ist <b>genau das was ich definitiv nicht will</b> — weil wir damit in ein viel anspruchsvolleres Feature einsteigen
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1771795425474" ID="ID_114413932" MODIFIED="1771803342428" TEXT="also hilft nur: basteln">
|
||||
<icon BUILTIN="yes"/>
|
||||
<node CREATED="1771795443654" ID="ID_509998029" MODIFIED="1771795450218" TEXT="einen neuen Service erfinden"/>
|
||||
<node COLOR="#338800" CREATED="1771795452478" ID="ID_18529675" MODIFIED="1771803398097" TEXT="muß aus statischem Kontext verwendbar sein">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#435e98" CREATED="1771803366239" ID="ID_305992027" MODIFIED="1771803380166" TEXT="möglichst alle Dependencies vermeiden">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
</node>
|
||||
<node COLOR="#435e98" CREATED="1771803380956" ID="ID_1114520881" MODIFIED="1771803392770" TEXT="Meyer's Singleton">
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#435e98" CREATED="1771795466134" ID="ID_1551562740" MODIFIED="1771803316573" TEXT="RandReseed-Service">
|
||||
<icon BUILTIN="forward"/>
|
||||
<node CREATED="1771795516102" ID="ID_142736564" MODIFIED="1771799570153" TEXT="Zugang....">
|
||||
<node CREATED="1771795548826" ID="ID_1707648492" MODIFIED="1771799578695" TEXT="register_at_seq(i, Hook)"/>
|
||||
<node CREATED="1771795584944" ID="ID_613198098" MODIFIED="1771800275490" TEXT="reseed_for_test (SeedNucleus)"/>
|
||||
</node>
|
||||
<node CREATED="1771795595092" ID="ID_1616947725" MODIFIED="1771795598001" TEXT="Verhalten">
|
||||
<node CREATED="1771795599287" ID="ID_1800784713" MODIFIED="1771795622633" TEXT="duplikate Registrierungen werfen error::Fatal"/>
|
||||
<node CREATED="1771795626134" ID="ID_256372633" MODIFIED="1771795664062" TEXT="die Hooks werden sortiert"/>
|
||||
<node CREATED="1771797091710" ID="ID_852981887" MODIFIED="1771797094793" TEXT="Aufruf">
|
||||
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1771797095881" ID="ID_1268487725" MODIFIED="1771803320183" TEXT="einfachste Lösung: vorhandene Callbacks, sortiert">
|
||||
<icon BUILTIN="forward"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1771797115401" ID="ID_964151813" MODIFIED="1771797141314" TEXT="späterer Ausbau: Zuteilung eines Seed für jeden Slot">
|
||||
<icon BUILTIN="hourglass"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1771795740790" ID="ID_1333995474" MODIFIED="1771795743516" TEXT="Begründung">
|
||||
<node CREATED="1771795744520" ID="ID_1130706569" MODIFIED="1771795757504" TEXT="will nicht jetzt in etwas Elaborierteres einsteigen"/>
|
||||
<node CREATED="1771795759519" ID="ID_291198746" MODIFIED="1771795781299" TEXT="möchte weiterhin einfach lib::rani(x) verwenden"/>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1771803502493" ID="ID_1580946206" MODIFIED="1771803620895" TEXT="manuell getestet">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
<i>Explizit nicht sinnvoll</i> hierfür einen Unit-Test zu schreiben!
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
bin mit dem Debugger durch eine komplette Verwendungs-Sequenz gesteppt
|
||||
</li>
|
||||
<li>
|
||||
hab das gleiche mit einem komplett anderen Test wiederholt
|
||||
</li>
|
||||
<li>
|
||||
habe zusätzliche Test-Hooks installiert
|
||||
</li>
|
||||
<li>
|
||||
verifiziert daß duplikate Slot-Nummern eine Exception werfen
|
||||
</li>
|
||||
<li>
|
||||
verifiziert daß Slots in aufsteigender Sortier-Reihenfolge aufgerufen werden
|
||||
</li>
|
||||
<li>
|
||||
verifiziert daß die absolute Nummer keine Rolle spielt
|
||||
</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
|
|||
Loading…
Reference in a new issue