Attempt to fix DummyBuilderContext / DummyPlayConnection

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!
This commit is contained in:
Fischlurch 2026-06-01 19:54:51 +02:00
parent eeabbb4f60
commit b804015cd7
2 changed files with 102 additions and 34 deletions

View file

@ -37,6 +37,10 @@
** _component integration test_ -- yet for this to work, we'd need ** _component integration test_ -- yet for this to work, we'd need
** - a fake calculation ** - a fake calculation
** - a fake OutputSlot ** - 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 mock-dispatcher.hpp
** @see JobPlanningPipeline_test ** @see JobPlanningPipeline_test
@ -47,6 +51,8 @@
#define STEAM_PLAY_DUMMY_BUILDER_CONTEXT_H #define STEAM_PLAY_DUMMY_BUILDER_CONTEXT_H
#include "lib/error.hpp"
#include "lib/format-string.hpp"
#include "steam/mobject/model-port.hpp" #include "steam/mobject/model-port.hpp"
#include "steam/fixture/model-port-registry.hpp" #include "steam/fixture/model-port-registry.hpp"
#include "vault/out/output-slot-connection.hpp" #include "vault/out/output-slot-connection.hpp"
@ -61,11 +67,14 @@
#include "lib/util.hpp" #include "lib/util.hpp"
#include <vector> #include <vector>
#include <deque>
#include <array>
namespace steam{ namespace steam{
namespace play { namespace play {
namespace test { namespace test {
namespace err = lumiera::error;
using fixture::ModelPortRegistry; using fixture::ModelPortRegistry;
using vault::mem::Buff; using vault::mem::Buff;
@ -73,44 +82,83 @@ namespace test {
using vault::out::DataSink; using vault::out::DataSink;
using vault::out::FrameID; using vault::out::FrameID;
using lib::time::TimeValue; using lib::time::TimeValue;
using util::_Fmt;
/** /**
* @todo 5/2023 quick-n-dirty placeholder to be able to fabricate fake DataSink handles (`Handle<Connection>`) * A placeholder/dummy OutputSlot that captures all
*/ /////////////////////////////////////////////////////////////////////////////////////////////////////TICKET #1410 : after the refactoring of OutputSlot 3/2026 it is not that easy any more. We need a Fake OutputSlot * delivered output data into heap-allocated memory.
class UnimplementedConnection * @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 FakeOutput
: OutputSlot
, util::NonCopyable
{
static constexpr uint NUM_FEEDS = 2;
static constexpr bool SINGLE_THREADED_TEST = true;
using DummyDat = uint64_t;
static constexpr size_t DUMMY_BUFF_SIZ = 1_KiB * sizeof(DummyDat);
using DummyBuff = std::array<DummyDat, DUMMY_BUFF_SIZ>;
using DummyBuffSeq = std::deque<DummyBuff>;
/**
* @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 : public vault::out::OutputSlot::Connection
{ {
size_t getBufferSize() const override { UNIMPLEMENTED ("getBufferSize()"); } DummyBuffSeq& buffers_;
size_t getBufferSize() const override { return DUMMY_BUFF_SIZ; }
Buff* claimBufferFor (FrameID) override; Buff* claimBufferFor (FrameID) override;
void publish (Buff*) override { UNIMPLEMENTED ("publish buffer content"); } void publish (Buff*) override { /* fake "publish buffer content" */ }
void release (Buff*) override { UNIMPLEMENTED ("complete buffer cycle"); } void release (Buff*) override { /* fake "complete buffer cycle" */ }
void shutDown () override { UNIMPLEMENTED ("shutDown() Connection"); } void shutDown () override { /* fake "shutDown() Connection" */ }
public: public:
~UnimplementedConnection(); ~DummyOutputConnection();
UnimplementedConnection() = default; DummyOutputConnection (DummyBuffSeq& buffers)
: buffers_{buffers}
{ }
// OutputSlot::Connection is non-copyable
}; };
using Connections = lib::ScopedCollection<DummyOutputConnection>;
using MockConnectState = OutputSlot::AllocState<DummyOutputConnection, SINGLE_THREADED_TEST>;
/** using OutBuffs = std::array<DummyBuffSeq, NUM_FEEDS>;
* A placeholder/dummy OutputSlot OutBuffs buffers_{};
* @todo 5/2026 it can barely be created right now;
* should reconsider what is actually needed here! FakeOutput()
*/ : OutputSlot{std::make_unique<MockConnectState> (NUM_FEEDS
struct FakeSlot ,[&,i=0](auto& storage) mutable
: OutputSlot
{ {
static constexpr uint NUM_CONNECTIONS = 2; storage.template create<DummyOutputConnection> (buffers_[i++]);
static constexpr bool SINGLE_THREADED_TEST = true; })}
using Connections = lib::ScopedCollection<UnimplementedConnection>;
using MockConnectState = OutputSlot::AllocState<UnimplementedConnection, SINGLE_THREADED_TEST>;
FakeSlot()
: OutputSlot{std::make_unique<MockConnectState> (NUM_CONNECTIONS, Connections::fill())}
{ } { }
}; };
inline Buff*
FakeOutput::DummyOutputConnection::claimBufferFor (FrameID fra)
{
REQUIRE (fra >= 0);
if (uint64_t(fra) >= buffers_.size())
buffers_.resize(fra+10);
return reinterpret_cast<Buff*> (& buffers_[fra]);
}
using asset::Pipe; using asset::Pipe;
using asset::PPipe; using asset::PPipe;
using asset::Struct; using asset::Struct;
@ -159,6 +207,8 @@ namespace test {
std::vector<ModelPort> modelPorts_; std::vector<ModelPort> modelPorts_;
std::vector<DataSink> dataSinks_; std::vector<DataSink> dataSinks_;
FakeOutput fakeOutput_;
/** setup */ /** setup */
SimulatedBuilderContext() SimulatedBuilderContext()
: registry_() : registry_()
@ -194,11 +244,9 @@ namespace test {
modelPorts_.push_back (ModelPort(pipeB)); modelPorts_.push_back (ModelPort(pipeB));
// prepare corresponding placeholder DataSink (a fake active output connection) // prepare corresponding placeholder DataSink (a fake active output connection)
FakeSlot fakeSlot;
dataSinks_.clear(); dataSinks_.clear();
lib::explore(fakeSlot.getOpenedSinks()) lib::explore(fakeOutput_.getOpenedSinks())
.effuse (dataSinks_); .effuse (dataSinks_);
// Note: keeps FakeSlot alive (due to embedded ref-count)...
} }
@ -216,12 +264,32 @@ namespace test {
,dataSinks_[index] ,dataSinks_[index]
}; };
} }
/**
* 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<typename X>
X&
accessOutputBufferAs (uint feed, FrameID frame)
{
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<X&> (fakeOutput_.buffers_[feed][frame]);
}
}; };
inline vault::mem::Buff* UnimplementedConnection::claimBufferFor (FrameID) }}} // namespace steam::play::test
{
UNIMPLEMENTED ("claimBufferFor(FrameID)");
}
}}} // namespace steam::play::test
#endif /*STEAM_PLAY_DUMMY_BUILDER_CONTEXT_H*/ #endif /*STEAM_PLAY_DUMMY_BUILDER_CONTEXT_H*/

View file

@ -38,7 +38,7 @@ namespace test {
} // (End) hidden service impl details } // (End) hidden service impl details
UnimplementedConnection::~UnimplementedConnection() { } ///< emit VTable here... FakeOutput::DummyOutputConnection::~DummyOutputConnection() { } ///< emit VTable here...