From 4df4ff27922c2596ee1b78c84d8dc9d18ebf526f Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sun, 13 Oct 2024 03:49:01 +0200 Subject: [PATCH] Invocation: consider minimal test setup and verification __Analysis__: what kind of verifications are sensible to employ to cover building, wiring and invocation of render nodes? Notably, a test should cover requirements and observable functionality, while ''avoiding direct hard coupling to implementation internals...'' __Draft__: the most simple node builder invocation conceivable... --- src/steam/engine/node-builder.hpp | 8 +- src/steam/engine/weaving-pattern-builder.hpp | 2 +- tests/core/steam/engine/node-linkage-test.cpp | 3 + .../core/steam/engine/test-rand-ontology.hpp | 14 +- tests/library/random-test.cpp | 2 +- wiki/thinkPad.ichthyo.mm | 582 ++++++++++++++++-- 6 files changed, 568 insertions(+), 43 deletions(-) diff --git a/src/steam/engine/node-builder.hpp b/src/steam/engine/node-builder.hpp index e41bc56a5..973b4fb9a 100644 --- a/src/steam/engine/node-builder.hpp +++ b/src/steam/engine/node-builder.hpp @@ -203,8 +203,8 @@ namespace engine { template class PortBuilderRoot : protected NodeBuilder - , util::MoveOnly { + public: NodeBuilder completePort() { @@ -318,8 +318,10 @@ namespace engine { } // slice away the subclass private: - PortBuilder(_Par&& base) + template + PortBuilder(_Par&& base, FUN&& fun) : _Par{move(base)} + , weavingBuilder_{forward (fun)} { } friend class PortBuilderRoot; @@ -332,7 +334,7 @@ namespace engine { PortBuilderRoot::invoke (FUN&& fun) { using WeavingBuilder_FUN = WeavingBuilder(), FUN>; - return PortBuilder{move(*this)}; + return PortBuilder{move(*this), forward (fun)}; } /* template diff --git a/src/steam/engine/weaving-pattern-builder.hpp b/src/steam/engine/weaving-pattern-builder.hpp index 83b50af64..ee9af93f1 100644 --- a/src/steam/engine/weaving-pattern-builder.hpp +++ b/src/steam/engine/weaving-pattern-builder.hpp @@ -121,7 +121,7 @@ namespace engine { manifoldSiz() { using _F = _ProcFun; - auto bound = std::max (_F::FAN_I, _F::FAN_O); + auto constexpr bound = std::max (_F::FAN_I, _F::FAN_O); static_assert (bound <= 10, "Limitation of template instances exceeded"); return bound < 3? bound diff --git a/tests/core/steam/engine/node-linkage-test.cpp b/tests/core/steam/engine/node-linkage-test.cpp index 68008ef3a..c555844e8 100644 --- a/tests/core/steam/engine/node-linkage-test.cpp +++ b/tests/core/steam/engine/node-linkage-test.cpp @@ -70,6 +70,9 @@ namespace test { build_connected_nodes() { auto con = prepareNode() + .preparePort() + .invoke(dummyOp) + .completePort() .build(); UNIMPLEMENTED ("build render nodes linked into a connectivity network"); } diff --git a/tests/core/steam/engine/test-rand-ontology.hpp b/tests/core/steam/engine/test-rand-ontology.hpp index fcbfe3f17..10a57dbeb 100644 --- a/tests/core/steam/engine/test-rand-ontology.hpp +++ b/tests/core/steam/engine/test-rand-ontology.hpp @@ -31,12 +31,24 @@ #include "steam/engine/testframe.hpp" +#include + namespace steam { namespace engine{ namespace test { - + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1367 : Dummy / Placeholder + using SoloArg = std::array; + /** @todo a placeholder operation to wire a prototypical render node + */ + inline void + dummyOp (SoloArg in, SoloArg out) + { + UNIMPLEMENTED ("a sincerely nonsensical operation"); + } +/////////////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1367 : Dummy / Placeholder /** * A fake _Domain Ontology_ to describe mocked »render operations« on * dummy data frames filled with random numbers. diff --git a/tests/library/random-test.cpp b/tests/library/random-test.cpp index 6b8b4932c..4aef33168 100644 --- a/tests/library/random-test.cpp +++ b/tests/library/random-test.cpp @@ -35,7 +35,7 @@ namespace test { /******************************************************************//** * @test demonstrate simple access to random number generation, - * as well as the setup of controlled random number sequences. + * as well as the setup of controlled random number sequences. * @see random.hpp */ class Random_test : public Test diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 5e86cdb5f..63fc5d75d 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -8017,9 +8017,7 @@ - - - +

Tiefe, bis zu der dieser Pfad gedeckt ist. @@ -8032,9 +8030,7 @@ - - - +

heap-allozierter expliziter Pfad. @@ -8120,9 +8116,7 @@ - - - +

Ha! das ist eine Monade!!!!!1!11! @@ -8194,9 +8188,7 @@ - - - +

Das heißt, wir müssen ihn bereits im Aufrufkontext bereit liegen haben @@ -8335,9 +8327,7 @@ - - - +

mathematische Monaden sind viel mehr... @@ -8615,9 +8605,7 @@ - - - +

...selbst wenn man ihn für eine triviale Implementierung @@ -9000,9 +8988,7 @@ - - - +

TreeExplorer per slicing move entfernen @@ -9992,9 +9978,7 @@ - - - +

Stichwort: virtual base offset @@ -11956,9 +11940,7 @@ - - - +

  • @@ -15701,9 +15683,7 @@ - - - +

    Policy: Unit-Tests dürfen keine GTK-Abhängigkeit haben @@ -48991,9 +48971,7 @@ - - - +

    das ist der wesentliche Kniff, @@ -85785,6 +85763,9 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    + + + @@ -85823,6 +85804,11 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    + + + + + @@ -89209,8 +89195,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    Die Indirektion ist nur notwendig, wenn es einen für den Benutzer sichtbaren Lebenszyklus-Zustand gibt; andernfalls gilt es lediglich als Service-Konfiguration und der Client kann sich direkte Referenzen für die verwendeten Services ziehen

    - -
    +
    @@ -89255,8 +89240,7 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    da es offensichtlicher ist, und zwischen Konstruktor und den von diesem erzeugten Services keine architektonische Trennung besteht

    - -
    +
    @@ -89662,6 +89646,517 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    + + + + + + + +

    + Hier droht die typische Falle des white-box-Testing: daß man auf Implementierungsdetails abstellt — was ganz besonders gefährlich wird, wenn die Implementierung erwartbar eine hohe Kohäsivität aufweist. Daher sollte der Hauptfokus darauf gereichtet sein, eine Test-Ontologie  aufzubauen, vermöge deren der erfolgte Berechnungsvorgang präzise ausgeleuchtet werden kann. +

    + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + +

    + siehe TestFrame_test +

    + + +
    + + + + + + +

    + es gibt nur einen festen Seed-Mechanismus, der auf der Kanal- und Sequenz-Nummer beruht +

    + + +
    +
    + + + + +

    + kann Lifecycle markieren als CREATED, EMITTED, DISCARDED +

    + + +
    +
    + + + + + + + + + + + + + +

    + bringt nicht wirklich was, aber zumindest sollte std::random mit kompatiblem Generator verwendet werden +

    + + +
    + +
    + + + + + + +

    + ...also zumindest eine globale Variable, die auslesbar und zuweisbar ist. +

    +

    + Es fehlt ja generell noch ein Framework für Zufallswerte in Tests, so daß jeder Test seinen definiten Seed bekommt, welcher zwar normalerweise zufällig, ansonsten aber feststellbar und reproduzierbar sein sollte +

    + + +
    + +
    + + + + +

    + Das sind sie bereits in der bestehenden Implementierung, und das Prinzip ist auch bereits gut genug; allerdings sollten wir das Schema von std::random verwenden, d.h. jeweils einen Generator und darauf aufbauend eine Distribution +

    + + +
    + +
    +
    +
    + + + + +

    + Das Daten-Array liegt nicht am Anfang, und ist deshalb plattform/implementierungsabhängig aligned; das erschwert auch die direkte Interpretation eines Datenblocks als TestFrame.... +

    + + +
    + + + + + + +

    + ....und damit sollte man jede beliebige Speicherlocation als Testframe interpretieren können, ohne diese zu korrumpieren; das impliziert auch, daß der behandelnde Code erkennen kann, ob ein Metadatenblock überhaupt angelegt wurde — und wenn das nicht der Fall ist, sollte auch niemals implizit in den Speicher geschrieben werden +

    + + +
    +
    + + + + +

    + Dabei ist die Prüfsumme ein verknüpfter Hash, und man sollte diese jederzeit berechnen können; jedoch ein regulär erstellter TestFrame sollte die Prüfsumme explizit speichern, und auch für beliebigen Dateninhalt sollte sich die Prüfsumme explizit markiern (speichern) lassen, denn damit werden auch weitergehende Berechnungen auf den Daten möglich, die vom initialen Seed abweichen +

    + + +
    +
    +
    + + + + + + + + + + +

    + neue Bedeutung: es ist ein TestFrame mit erkennbarem Metadatenblock (auch wenn ansonsten keine der Prüfsummen mit den Daten zusammenpaßt); es sollte recht unwahrscheinlich sein, daß ein zufälliger Datenblock diesen Test besteht. +

    + + +
    +
    + + + + +

    + Es ist ein TestFrame mit gültigem Metadaten-Block, und die dort gespeicherte Prüfsumme wird durch die Daten bestätigt +

    + + +
    +
    + + + + +

    + entspricht dem bisherigen isSane() — d.h. isValid() aber zusätzlich passen die Daten auf die gespeicherte distinction, und das heißt, die Daten wurden vom Standard-Schema erzeugt und nicht weiter bearbeitet +

    + + +
    +
    +
    +
    +
    +
    + + + + +

    + testframe.hpp (/zLumi/tests/core/steam/engine) +

    +
      +
    • + buffer-metadata-test.cpp (/zLumi/tests/core/steam/engine) +
    • +
    • + buffer-provider-protocol-test.cpp (/zLumi/tests/core/steam/engine) +
    • +
    • + diagnostic-output-slot.hpp (/zLumi/tests/core/steam/play) +
    • +
    • + output-slot-protocol-test.cpp (/zLumi/tests/core/steam/play) +
    • +
    • + testframe.cpp (/zLumi/tests/core/steam/engine) +
    • +
    • + testframe-test.cpp (/zLumi/tests/core/steam/engine) +
    • +
    • + test-rand-ontology.hpp (/zLumi/tests/core/steam/engine) +
    • +
    • + tracking-heap-block-provider-test.cpp (/zLumi/tests/core/steam/engine) +
    • +
    + + +
    +
    +
    +
    + + + + +
      +
    • + hängt nur von den Eingabedaten ab +
    • +
    • + für jeden Pixel auch durch Direktaufruf der Berechnung reproduzierbar +
    • +
    • + (optional) in jedem Schritt mit einer Instanz-ID verknüpfbar +
    • +
    + +
    + + + + + + + +

    + ...das bedeutet, sie läuft auf size_t (oder was dann letztlich die Wortbreite sein wird für Lumiera Hash-Vorgänge) und sie ist nicht kommutativ in den Argumenten +

    + + +
    +
    + + + + +

    + Jeder Funktionsaufruf ist „gefärbt“, aber ansonsten äquivalent. Das heißt, ein fester Parameterwert fließt mit in die Berechnung jedes einzelnen Datenpunktes, und dieser Wert ist an den jeweiligen Aufruf gebunden wird, wodurch auch eine Kette gleichartiger Aufrufe in der Reihenfolge unterscheidbar gemacht werden kann. +

    + + +
    +
    + + + + +

    + ...zwar handelt es sich stets nur um eine Hash-Verknüpfung, aber die Arität (und ggfs. später auch noch ein Array-Wertiger Input) kommen als Steuerparameter hinzu. Diese Parameter können als lesbarer Spec-String ausgegeben werden, und in einen Hash eingerechnet werden, der dann die Funktion markiert und unterscheidbar macht. Wenn ein Seed explizit angegeben wird, dann fließt er zusätzlich mit ein, und markiert außerdem auch die Berechnung an jedem Datenpunkt +

    + + +
    +
    + + + + +

    + ...später, wenn ich abschließend geklärt habe, wie Automation funktionieren soll. Derzeit denke ich, daß solche Funktions-Parameter in einem Tree-walk vor dem eigentlichen pull() der Invocation gesetzt werden, also über das Turnout-System. Speziell für die Test-Ontology könnte man hier auch eine Node-ID oder einen Node-Struktur-Hash einfließen lassen (wobei mit jetzt aber nicht klar ist, ob diese Idee für das Testen überhaupt von Nutzen ist) +

    + + +
    +
    +
    + + + + +

    + Ich will also eine laterale Vermischung der Daten vermeiden; erst über die Prüfsumme des Ergebnis-Datenblocks werden die einzelnen Datenpunkte zusammengeführt; theoretisch wäre es dadurch sogar möglich, die Korruption einzelner Datenpunkte zu erkennen, indem man die intendierte Berechnungskette explizit gecodet nochmal ausführt und dann die Ergebnisdaten vergleicht. +

    + + +
    +
    + + + + +

    + Also einen String, der die Operation mit Parametrisierung und Seed darstellt. Aufbauend darauf läßt sich dann auch eine Node-Spec generieren +

    + +
    +
    +
    + + + + + + +

    + d.h. das EventLog liegt in einem Singleton, und wenn es da ist, dann hinterläßt jeder Funktionsaufruf einen Log-Eintrag, so daß sich der gesamte Berechnungsweg mit allen Aufruf-Reihenfolgen nachvollziehen und verifizieren läßt +

    + + +
    +
    +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    + TestFrame wurde zwar schon 2011 angelegt, soll nun (2024) aber auch die Basis für eine Test-Ontology werden; die Analyse ergab, daß die vorhandene Funktionalität hierfür lediglich maßvoll erweitert werden muß: +

    +
      +
    • + das Datenlayout im Speicher sollte konsistenter sein +
    • +
    • + wir brauchen einen dedizierten Metadaten-Block, der aber optional ist +
    • +
    • + die Zufallsberechnung bleibt inhaltlich komplett gleich, aber wird umgestellt auf std::random +
    • +
    • + zusätzlich wird noch eine Hashberechnung über die konkreten Datenwerte hinzugefügt +
    • +
    + +
    + +
    + + + + + + + + + + + + + + + + + + + + + + +

    + neue Bedeutung: es ist ein TestFrame mit erkennbarem Metadatenblock (auch wenn ansonsten keine der Prüfsummen mit den Daten zusammenpaßt); es sollte recht unwahrscheinlich sein, daß ein zufälliger Datenblock diesen Test besteht. +

    + +
    +
    + + + + +

    + Es ist ein TestFrame mit gültigem Metadaten-Block, und die dort gespeicherte Prüfsumme wird durch die Daten bestätigt +

    + +
    +
    + + + + +

    + entspricht dem bisherigen isSane() — d.h. isValid() aber zusätzlich passen die Daten auf die gespeicherte distinction, und das heißt, die Daten wurden vom Standard-Schema erzeugt und nicht weiter bearbeitet +

    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    @@ -89820,6 +90315,19 @@ Date:   Thu Apr 20 18:53:17 2023 +0200
    + + + + + + + + + + + + +