From b804015cd7cfc6c58d37d9db9992cb22c5c1984c Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 1 Jun 2026 19:54:51 +0200 Subject: [PATCH] Attempt to fix DummyBuilderContext / DummyPlayConnection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These provide a faked context setup for unit testing. I created them ''out of sheer desperation'' several years ago, since it is impossible to verify the building blocks if you don't know what the building itself will look like. The recent design clean-up of OutputSlot has unfortunately removed a bunch of »hexagonal hooks« — and now I seem to be unable to hook into anything with my tests. Oh my! --- tests/steam/play/dummy-builder-context.hpp | 134 ++++++++++++++++----- tests/steam/play/dummy-play-connection.cpp | 2 +- 2 files changed, 102 insertions(+), 34 deletions(-) diff --git a/tests/steam/play/dummy-builder-context.hpp b/tests/steam/play/dummy-builder-context.hpp index e5c1e1364..1a728f5fd 100644 --- a/tests/steam/play/dummy-builder-context.hpp +++ b/tests/steam/play/dummy-builder-context.hpp @@ -37,6 +37,10 @@ ** _component integration test_ -- yet for this to work, we'd need ** - a fake calculation ** - a fake OutputSlot + ** @todo 5/2026 now I have beefed up the OutputSlot so that it can receive + ** two feeds with an arbitrary number of frames. Still not sure if it's needed; + ** however it should be noted that the MockDispatcher relies on the DummyPlayConnection, + ** which in turn uses SimulatedBuilderContext, mostly to get _just some model ports_. ** ** @see mock-dispatcher.hpp ** @see JobPlanningPipeline_test @@ -47,6 +51,8 @@ #define STEAM_PLAY_DUMMY_BUILDER_CONTEXT_H +#include "lib/error.hpp" +#include "lib/format-string.hpp" #include "steam/mobject/model-port.hpp" #include "steam/fixture/model-port-registry.hpp" #include "vault/out/output-slot-connection.hpp" @@ -61,11 +67,14 @@ #include "lib/util.hpp" #include +#include +#include namespace steam{ namespace play { namespace test { + namespace err = lumiera::error; using fixture::ModelPortRegistry; using vault::mem::Buff; @@ -73,44 +82,83 @@ namespace test { using vault::out::DataSink; using vault::out::FrameID; using lib::time::TimeValue; + using util::_Fmt; + + /** - * @todo 5/2023 quick-n-dirty placeholder to be able to fabricate fake DataSink handles (`Handle`) - */ /////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : after the refactoring of OutputSlot 3/2026 it is not that easy any more. We need a Fake OutputSlot - class UnimplementedConnection - : public vault::out::OutputSlot::Connection - { - size_t getBufferSize() const override { UNIMPLEMENTED ("getBufferSize()"); } - Buff* claimBufferFor (FrameID) override; - void publish (Buff*) override { UNIMPLEMENTED ("publish buffer content"); } - void release (Buff*) override { UNIMPLEMENTED ("complete buffer cycle"); } - void shutDown () override { UNIMPLEMENTED ("shutDown() Connection"); } - - public: - ~UnimplementedConnection(); - UnimplementedConnection() = default; - }; - - - /** - * A placeholder/dummy OutputSlot - * @todo 5/2026 it can barely be created right now; + * A placeholder/dummy OutputSlot that captures all + * delivered output data into heap-allocated memory. + * @todo 5/2026 it can now be created and allocates a fixed layout + * of buffer storage, which implies it should not be copied + * and is thus used differently than a real OutputSlot; * should reconsider what is actually needed here! + * @warning this used to be placeholder code, and now it was adapted + * to store frames, yet this new functionality is untested as of 5/2026 */ - struct FakeSlot + struct FakeOutput : OutputSlot + , util::NonCopyable { - static constexpr uint NUM_CONNECTIONS = 2; + static constexpr uint NUM_FEEDS = 2; static constexpr bool SINGLE_THREADED_TEST = true; - using Connections = lib::ScopedCollection; - using MockConnectState = OutputSlot::AllocState; - FakeSlot() - : OutputSlot{std::make_unique (NUM_CONNECTIONS, Connections::fill())} + using DummyDat = uint64_t; + static constexpr size_t DUMMY_BUFF_SIZ = 1_KiB * sizeof(DummyDat); + + using DummyBuff = std::array; + using DummyBuffSeq = std::deque; + + /** + * @todo 5/2026 quick-n-dirty placeholder code + * to expose some output buffers and provide + * the corresponding DataSink handles + */ + class DummyOutputConnection + : public vault::out::OutputSlot::Connection + { + DummyBuffSeq& buffers_; + + size_t getBufferSize() const override { return DUMMY_BUFF_SIZ; } + Buff* claimBufferFor (FrameID) override; + void publish (Buff*) override { /* fake "publish buffer content" */ } + void release (Buff*) override { /* fake "complete buffer cycle" */ } + void shutDown () override { /* fake "shutDown() Connection" */ } + + public: + ~DummyOutputConnection(); + DummyOutputConnection (DummyBuffSeq& buffers) + : buffers_{buffers} + { } + // OutputSlot::Connection is non-copyable + }; + + using Connections = lib::ScopedCollection; + using MockConnectState = OutputSlot::AllocState; + + using OutBuffs = std::array; + OutBuffs buffers_{}; + + FakeOutput() + : OutputSlot{std::make_unique (NUM_FEEDS + ,[&,i=0](auto& storage) mutable + { + storage.template create (buffers_[i++]); + })} { } }; + inline Buff* + FakeOutput::DummyOutputConnection::claimBufferFor (FrameID fra) + { + REQUIRE (fra >= 0); + if (uint64_t(fra) >= buffers_.size()) + buffers_.resize(fra+10); + return reinterpret_cast (& buffers_[fra]); + } + + using asset::Pipe; using asset::PPipe; using asset::Struct; @@ -159,6 +207,8 @@ namespace test { std::vector modelPorts_; std::vector dataSinks_; + FakeOutput fakeOutput_; + /** setup */ SimulatedBuilderContext() : registry_() @@ -194,11 +244,9 @@ namespace test { modelPorts_.push_back (ModelPort(pipeB)); // prepare corresponding placeholder DataSink (a fake active output connection) - FakeSlot fakeSlot; dataSinks_.clear(); - lib::explore(fakeSlot.getOpenedSinks()) + lib::explore(fakeOutput_.getOpenedSinks()) .effuse (dataSinks_); - // Note: keeps FakeSlot alive (due to embedded ref-count)... } @@ -216,12 +264,32 @@ namespace test { ,dataSinks_[index] }; } - }; - inline vault::mem::Buff* UnimplementedConnection::claimBufferFor (FrameID) + /** + * Access a generated output frame. + * @remark FakeOutput maintains Deque-Storage for each feed. + * @tparam X data type to assume as content of the frame (only checked for size) + * @param feed number of the output feed to access + * @param frame frame numer within the output feed + */ + template + X& + accessOutputBufferAs (uint feed, FrameID frame) { - UNIMPLEMENTED ("claimBufferFor(FrameID)"); + static_assert (sizeof(X) <= FakeOutput::DUMMY_BUFF_SIZ + ,"desired data type would not fit into FakeOutput buffer"); + if (feed >= FakeOutput::NUM_FEEDS) + throw err::Invalid{_Fmt{"Feed #%i > %i allowed"} + % feed % (FakeOutput::NUM_FEEDS-1)}; + + auto availFrames = fakeOutput_.buffers_[feed].size(); + if (frame >= availFrames) + throw err::Invalid{_Fmt{"Frame #%02i > %02i available frames"} + % frame % availFrames}; + + return reinterpret_cast (fakeOutput_.buffers_[feed][frame]); } + }; - }}} // namespace steam::play::test +}}} // namespace steam::play::test #endif /*STEAM_PLAY_DUMMY_BUILDER_CONTEXT_H*/ diff --git a/tests/steam/play/dummy-play-connection.cpp b/tests/steam/play/dummy-play-connection.cpp index be9e25955..e47395c17 100644 --- a/tests/steam/play/dummy-play-connection.cpp +++ b/tests/steam/play/dummy-play-connection.cpp @@ -38,7 +38,7 @@ namespace test { } // (End) hidden service impl details - UnimplementedConnection::~UnimplementedConnection() { } ///< emit VTable here... + FakeOutput::DummyOutputConnection::~DummyOutputConnection() { } ///< emit VTable here...