Invocation: build a DSL to verify connectivity (see #1377)
This was a lot of intricate technical work, and is now verified in-depth, covering all possible cases. __We can now__ * build Nodes * verify in detail correct connectivity * read Node-IDs and processing specifications * maintain a symbolic spec for the arguments of a Port (and beyond that, we can also **invoke nodes**, which remains to be formally verified)
This commit is contained in:
parent
d5a47bf3e4
commit
72d7986b5e
8 changed files with 564 additions and 135 deletions
|
|
@ -227,6 +227,10 @@ namespace lib {
|
|||
friend auto begin (Several const& svl) { return svl.begin();}
|
||||
friend auto end (Several const& svl) { return svl.end(); }
|
||||
|
||||
using value_type = typename meta::RefTraits<I>::Value;
|
||||
using reference = typename meta::RefTraits<I>::Reference;
|
||||
using const_reference = value_type const&;
|
||||
|
||||
|
||||
protected:
|
||||
size_t
|
||||
|
|
|
|||
|
|
@ -13,9 +13,11 @@
|
|||
|
||||
|
||||
/** @file proc-node.cpp
|
||||
** Translation unit to hold the actual implementation of node processing operations.
|
||||
**
|
||||
** @todo WIP-WIP-WIP 6/2024 not clear yet what goes here and what goes into turnout-system.cpp
|
||||
** Translation unit for implementation details regarding node-IDs and verification.
|
||||
** @remark \ref ProcNode itself is a shell to provide a node-ID and a high-level API
|
||||
** for Render Node invocation. The actual implementation of processing functionality
|
||||
** is located within the [Turnout](\ref turnout.hpp) and the individual »weaving patterns«
|
||||
** embedded therein.
|
||||
*/
|
||||
|
||||
|
||||
|
|
@ -247,7 +249,7 @@ namespace engine {
|
|||
ProcID::genProcSpec() const
|
||||
{
|
||||
std::ostringstream buffer;
|
||||
buffer << nodeName_
|
||||
buffer << genNodeSymbol()
|
||||
<< genQualifier()
|
||||
<< argLists_;
|
||||
return buffer.str();
|
||||
|
|
@ -501,17 +503,135 @@ namespace engine {
|
|||
{
|
||||
auto& leadPorts = srcPorts();
|
||||
return input < leadPorts.size()
|
||||
and isSameObject (leadPorts[input].get(), tarPort);
|
||||
and leadPorts[input] == tarPort;
|
||||
}
|
||||
|
||||
bool
|
||||
PortDiagnostic::verify_connected (Port& tarPort)
|
||||
{
|
||||
for (Port& port : srcPorts())
|
||||
if (isSameObject (port, tarPort))
|
||||
if (port == tarPort)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @remark _ConCheck provides a fluent DSL notation to verify node connectivity.
|
||||
* This is achieved by first collecting some counterparts and index specifications
|
||||
* for the kind of connection to validate. Each qualifier just sets a parameter and
|
||||
* returns the _ConCheck object by move. The final result is retrieved by this bool
|
||||
* conversion — which in fact has to implement a collection of different evaluations.
|
||||
* The proper kind of evaluation will be picked based on the actual arguments given;
|
||||
* the more are present, the more constricted the evaluation becomes. The selection
|
||||
* of the evaluation to take is thus ordered in reverse order, starting with the
|
||||
* most constricted cases. Three different kinds of link validations are provided
|
||||
* - compare two fully qualified Port objects for identity (same object)
|
||||
* - check if a given Port object is present in a collection of Ports
|
||||
* - exhaustive search for a match in the cross product of two Port collections.
|
||||
* The last case is what allows to perform a high-level connectivity test between
|
||||
* two nodes, which are considered as connected if any link is found.
|
||||
* @see NodeMeta_test::verify_ID_connectivity()
|
||||
*/
|
||||
_ConCheck::operator bool()
|
||||
{
|
||||
auto validPort = [this](uint idx) { return idx < anchor.ports().size(); };
|
||||
auto validLead = [this](uint idx) { return idx < anchor.leads().size(); };
|
||||
auto validSrc = [this](uint pNo
|
||||
,uint sNo) { return sNo < anchor.watchPort(pNo).srcPorts().size(); };
|
||||
auto validSrcP = [this](ProcNode& lead
|
||||
,uint idx) { return idx < watch(lead).ports().size(); };
|
||||
|
||||
auto find_link = [](auto& seq1, auto& seq2)
|
||||
{
|
||||
return explore(seq1)
|
||||
.transform([&](auto& elm){ return contains (seq2, *elm); })
|
||||
.has_any();
|
||||
};
|
||||
|
||||
// Determine case to handle,
|
||||
// starting with the most constricted...
|
||||
if (portNo and srcNo and srcNode and srcPNo)
|
||||
return validPort(*portNo) // is_linked(node).port(portNo).asSrc(srcNo).to(srcNode).atPort(srcPNo)
|
||||
and validSrc (*portNo, *srcNo)
|
||||
and validSrcP(*srcNode,*srcPNo)
|
||||
and anchor.watchPort(*portNo).srcPorts()[*srcNo]
|
||||
== watch(*srcNode).ports()[*srcPNo];
|
||||
else
|
||||
if (portNo and srcNo and leadNo and srcPNo)
|
||||
return validPort(*portNo) // is_linked(node).port(portNo).asSrc(srcNo).toLead(leadNo).atPort(srcPNo)
|
||||
and validSrc (*portNo,*srcNo)
|
||||
and validLead(*leadNo)
|
||||
and validSrcP(anchor.leads()[*leadNo], *srcPNo)
|
||||
and anchor.watchPort(*portNo).srcPorts()[*srcNo]
|
||||
== anchor.watchLead(*leadNo).ports()[*srcPNo];
|
||||
else
|
||||
if (portNo and srcNo and srcPort)
|
||||
return validPort(*portNo) // is_linked(node).port(portNo).asSrc(srcNo).to(srcPort)
|
||||
and validSrc (*portNo,*srcNo)
|
||||
and anchor.watchPort(*portNo).srcPorts()[*srcNo]
|
||||
== *srcPort;
|
||||
else
|
||||
if (portNo and srcNo and srcNode)
|
||||
return validPort(*portNo) // is_linked(node).port(portNo).asSrc(srcNo).to(srcNode)
|
||||
and validSrc (*portNo,*srcNo)
|
||||
and contains (watch(*srcNode).ports()
|
||||
,anchor.watchPort(*portNo).srcPorts()[*srcNo]);
|
||||
else
|
||||
if (portNo and srcNo and leadNo)
|
||||
return validPort(*portNo) // is_linked(node).port(portNo).asSrc(srcNo).toLead(leadNo)
|
||||
and validSrc (*portNo,*srcNo)
|
||||
and validLead(*leadNo)
|
||||
and contains (anchor.watchLead(*leadNo).ports()
|
||||
,anchor.watchPort(*portNo).srcPorts()[*srcNo]);
|
||||
else
|
||||
if (portNo and srcNo)
|
||||
return validPort(*portNo) // is_linked(node).port(portNo).asSrc(srcNo)
|
||||
and validSrc (*portNo,*srcNo);
|
||||
else
|
||||
if (portNo and srcNode and srcPNo)
|
||||
return validPort(*portNo) // is_linked(node).port(portNo).to(srcNode).atPort(srcPNo)
|
||||
and validSrcP(*srcNode,*srcPNo)
|
||||
and contains (anchor.watchPort(*portNo).srcPorts()
|
||||
,watch(*srcNode).ports()[*srcPNo]);
|
||||
else
|
||||
if (portNo and leadNo and srcPNo)
|
||||
return validPort(*portNo) // is_linked(node).port(portNo).toLead(leadNo).atPort(srcPNo)
|
||||
and validLead(*leadNo)
|
||||
and validSrcP(anchor.leads()[*leadNo], *srcPNo)
|
||||
and contains (anchor.watchPort(*portNo).srcPorts()
|
||||
,anchor.watchLead(*leadNo).ports()[*srcPNo]);
|
||||
else
|
||||
if (portNo and srcPort)
|
||||
return validPort(*portNo) // is_linked(node).port(portNo).to(srcPort)
|
||||
and contains (anchor.watchPort(*portNo).srcPorts()
|
||||
,*srcPort);
|
||||
else
|
||||
if (portNo and srcNode)
|
||||
return validPort(*portNo) // is_linked(node).port(portNo).to(srcNode)
|
||||
and find_link(watch(*srcNode).ports()
|
||||
,anchor.watchPort(*portNo).srcPorts());
|
||||
else
|
||||
if (portNo and leadNo)
|
||||
return validPort(*portNo) // is_linked(node).port(portNo).toLead(leadNo)
|
||||
and validLead(*leadNo)
|
||||
and find_link(anchor.watchLead(*leadNo).ports()
|
||||
,anchor.watchPort(*portNo).srcPorts());
|
||||
else
|
||||
if (portNo)
|
||||
return validPort(*portNo) // is_linked(node).port(portNo)
|
||||
and not anchor.watchPort(*portNo).isSrc();
|
||||
else
|
||||
if (srcNode and leadNo)
|
||||
return validLead(*leadNo) // is_linked(node).to(srcNode).asLead(leadNo)
|
||||
and anchor.leads()[*leadNo]
|
||||
== *srcNode;
|
||||
else
|
||||
if (srcNode)
|
||||
return contains (anchor.leads() // is_linked(node).to(srcNode)
|
||||
,*srcNode);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}} // namespace steam::engine
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@
|
|||
** @remark A future extension to this scheme is conceivable, where common processing pipelines
|
||||
** are pre-compiled in entirety, possibly combined with hardware acceleration.
|
||||
**
|
||||
** @todo WIP-WIP 12/2024 Node-Invocation is reworked from ground up for the »Playback Vertical Slice«
|
||||
** @todo WIP 2/2025 Node-Invocation is reworked from ground up for the »Playback Vertical Slice«
|
||||
**
|
||||
** @see turnout.hpp
|
||||
** @see turnout-system.hpp
|
||||
|
|
@ -99,11 +99,8 @@
|
|||
#include "lib/error.hpp"
|
||||
#include "lib/nocopy.hpp"
|
||||
#include "lib/hash-value.h"
|
||||
//#include "steam/asset/proc.hpp"
|
||||
//#include "steam/mobject/parameter.hpp"
|
||||
#include "steam/engine/buffhandle.hpp"
|
||||
#include "steam/engine/turnout-system.hpp"
|
||||
#include "lib/ref-array.hpp" /////////////////////OOO phase out
|
||||
#include "lib/format-string.hpp"
|
||||
#include "lib/several.hpp"
|
||||
|
||||
|
|
@ -118,6 +115,8 @@ namespace engine {
|
|||
|
||||
using std::move;
|
||||
using std::string;
|
||||
using std::nullopt;
|
||||
using std::optional;
|
||||
using lib::HashVal;
|
||||
using util::_Fmt;
|
||||
|
||||
|
|
@ -145,6 +144,10 @@ namespace engine {
|
|||
virtual BuffHandle weave (TurnoutSystem&, OptionalBuff =std::nullopt) =0;
|
||||
|
||||
ProcID& procID;
|
||||
|
||||
/// Port has reference semantics: all instances are distinct
|
||||
friend bool operator== (Port const& pl, Port const& pr){ return & pl == & pr;}
|
||||
friend bool operator!= (Port const& pl, Port const& pr){ return not (pl == pr); }
|
||||
};
|
||||
|
||||
using PortRef = std::reference_wrapper<Port>;
|
||||
|
|
@ -232,6 +235,10 @@ namespace engine {
|
|||
return wiring_.ports[portIdx];
|
||||
}
|
||||
|
||||
/// ProcNode has reference semantics: all instances are distinct
|
||||
friend bool operator== (ProcNode const& nl, ProcNode const& nr){ return & nl == & nr;}
|
||||
friend bool operator!= (ProcNode const& nl, ProcNode const& nr){ return not (nl == nr); }
|
||||
|
||||
|
||||
/*************************************************************//**
|
||||
* Engine Core operation: render and pull output from this node.
|
||||
|
|
@ -333,5 +340,47 @@ namespace engine {
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** Helper for connectivity-checks in tests */
|
||||
class _ConCheck
|
||||
: util::MoveOnly
|
||||
{
|
||||
ProcNodeDiagnostic anchor;
|
||||
ProcNode* srcNode{nullptr};
|
||||
Port* srcPort{nullptr};
|
||||
optional<uint> leadNo{nullopt};
|
||||
optional<uint> portNo{nullopt};
|
||||
optional<uint> srcNo {nullopt};
|
||||
optional<uint> srcPNo{nullopt};
|
||||
|
||||
public:
|
||||
_ConCheck (ProcNode& n)
|
||||
: anchor{watch(n)}
|
||||
{ }
|
||||
|
||||
/** implement decision logic based on context given. */
|
||||
operator bool();
|
||||
|
||||
_ConCheck to (ProcNode& n) { srcNode = &n; return move(*this); }
|
||||
_ConCheck to (Port& p) { srcPort = &p; return move(*this); }
|
||||
_ConCheck asLead (uint idx){ leadNo = idx; return move(*this); }
|
||||
_ConCheck toLead (uint idx){ leadNo = idx; return move(*this); }
|
||||
_ConCheck asSrc (uint idx){ srcNo = idx; return move(*this); }
|
||||
_ConCheck port (uint idx){ portNo = idx; return move(*this); }
|
||||
_ConCheck atPort (uint idx){ srcPNo = idx; return move(*this); }
|
||||
};
|
||||
|
||||
/**
|
||||
* start a DSL expression to verify node connectivity.
|
||||
* @see NodeMeta_test::verify_ID_connectivity()
|
||||
*/
|
||||
inline _ConCheck
|
||||
is_linked (ProcNode& n)
|
||||
{
|
||||
return _ConCheck{n};
|
||||
}
|
||||
|
||||
|
||||
}} // namespace steam::engine
|
||||
#endif /*STEAM_ENGINE_PROC_NODE_H*/
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ PLANNED "Proc Node connectivity" NodeLink_test <<END
|
|||
END
|
||||
|
||||
|
||||
PLANNED "Proc Node metadata key" NodeMeta_test <<END
|
||||
Test "Proc Node metadata key" NodeMeta_test <<END
|
||||
END
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -208,6 +208,9 @@ namespace test {
|
|||
.completePort()
|
||||
.build()};
|
||||
|
||||
CHECK (is_linked(n3).to(n1));
|
||||
CHECK (is_linked(n3).to(n2));
|
||||
|
||||
uint res = invokeRenderNode(n3);
|
||||
CHECK (res == peek+1 + LIFE_AND_UNIVERSE_4EVER+1 );
|
||||
CHECK (peek != -1);
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ namespace test {
|
|||
CHECK (watch(n1).ports().size() == 1);
|
||||
|
||||
// can generate a symbolic spec to describe the Port's processing functionality...
|
||||
CHECK (watch(n1).getPortSpec(0) == "Test:dummy.op(int)"_expect);
|
||||
CHECK (watch(n1).getPortSpec(0) == "dummy.op(int)"_expect);
|
||||
CHECK (watch(n1).getPortSpec(1) == "↯"_expect);
|
||||
|
||||
// such a symbolic spec is actually generated by a deduplicated metadata descriptor
|
||||
|
|
@ -111,15 +111,15 @@ namespace test {
|
|||
|
||||
// re-generate the descriptor for the source node (n1)
|
||||
auto& metaN1 = ProcID::describe("Test:dummy","op(int)");
|
||||
CHECK (metaN1.genProcSpec() == "Test:dummy.op(int)"_expect);
|
||||
CHECK (metaN1.genProcName() == "Test:dummy.op"_expect);
|
||||
CHECK (metaN1.genProcSpec() == "dummy.op(int)"_expect);
|
||||
CHECK (metaN1.genProcName() == "dummy.op"_expect);
|
||||
CHECK (metaN1.genNodeName() == "Test:dummy"_expect);
|
||||
CHECK (metaN1.genNodeSpec(con.leads) == "Test:dummy-◎"_expect);
|
||||
}
|
||||
|
||||
|
||||
/** @test TODO Build more elaborate Render Nodes linked into a connectivity network
|
||||
* @todo WIP 1/25 🔁 define ⟶ implement
|
||||
/** @test Build more elaborate Render Nodes linked into a connectivity network
|
||||
* @todo WIP 1/25 🔁 define ⟶ ✔ implement
|
||||
*/
|
||||
void
|
||||
build_connected_nodes()
|
||||
|
|
@ -197,6 +197,13 @@ SHOW_EXPR(watch(n1).getPortSpec(0))
|
|||
SHOW_EXPR(watch(n1).getPortSpec(1))
|
||||
SHOW_EXPR(watch(n1.getPort(0)).getProcSpec())
|
||||
SHOW_EXPR(watch(n1.getPort(0)).isSrc())
|
||||
|
||||
CHECK ( is_linked(n2).to(n1));
|
||||
CHECK (not is_linked(n1b).to(n1));
|
||||
|
||||
CHECK (not is_linked(n3).to(n1));
|
||||
CHECK ( is_linked(n3).to(n1b));
|
||||
CHECK ( is_linked(n3).to(n2));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -21,26 +21,22 @@
|
|||
#include "steam/engine/node-builder.hpp"
|
||||
#include "lib/format-util.hpp"
|
||||
#include "lib/test/test-helper.hpp"
|
||||
//#include "steam/engine/test-rand-ontology.hpp" ///////////TODO
|
||||
#include "lib/test/diagnostic-output.hpp"/////////////////TODO
|
||||
//#include "lib/util.hpp"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
//using std::string;
|
||||
|
||||
|
||||
namespace steam {
|
||||
namespace engine{
|
||||
namespace test {
|
||||
|
||||
using std::abs;
|
||||
// using util::join;
|
||||
|
||||
|
||||
|
||||
/***************************************************************//**
|
||||
* @test Render node metadata and hash identity keys.
|
||||
* @todo 2/2025 hash computation is not yet specified...
|
||||
*/
|
||||
class NodeMeta_test : public Test
|
||||
{
|
||||
|
|
@ -77,8 +73,8 @@ namespace test {
|
|||
CHECK (p2.genProcName() == "N2.+"_expect ); // domain omitted, qualifier joined with '.'
|
||||
CHECK (p2.genQualifier() == ".+"_expect ); // qualifier includes leading '.'
|
||||
CHECK (p3.genProcName() == "N3"_expect );
|
||||
CHECK (p2.genProcSpec() == "U:N2.+(a1,a2)"_expect );
|
||||
CHECK (p3.genProcSpec() == "O:N3(in/3)(o1,o2/2)"_expect );
|
||||
CHECK (p2.genProcSpec() == "N2.+(a1,a2)"_expect );
|
||||
CHECK (p3.genProcSpec() == "N3(in/3)(o1,o2/2)"_expect );
|
||||
|
||||
ProcID::ArgModel arg1 = p1.genArgModel();
|
||||
ProcID::ArgModel arg2 = p2.genArgModel();
|
||||
|
|
@ -109,13 +105,31 @@ namespace test {
|
|||
}
|
||||
|
||||
|
||||
/** @test TODO aspects of node definition relevant for the ProcID
|
||||
* @todo WIP 2/25 🔁 define ⟶ 🔁 implement
|
||||
|
||||
/** @test validate the interplay of node connectivity
|
||||
* with reported properties at the ProcID and
|
||||
* demonstrate tools to check connectivity.
|
||||
* - Build a 3-node network with dummy operations,
|
||||
* which however are built to mimic the very common
|
||||
* situation where two sources are mixed
|
||||
* - at exit side, three different »flavours« can be
|
||||
* produced, which implies that there are three Ports.
|
||||
* - the source at the »A-side« provided only two flavours,
|
||||
* and thus an explicit wiring has to be made for the
|
||||
* A-side connection of the third chain
|
||||
* - In real usage, the node specification strings will be
|
||||
* provided from the Media-Lib adapter plug-in. Here it is
|
||||
* hard wired, and defined in a way to reflect structure.
|
||||
* - various ways to drill-down into the structure are explored
|
||||
* by verifying the ProcID specification visible at each point.
|
||||
* - then the tools for verifying connectivity are demonstrated
|
||||
* and covered with relevant positive and negative combinations.
|
||||
* @todo 2/25 🔁 define ⟶ ✔ implement
|
||||
*/
|
||||
void
|
||||
verify_ID_connectivity()
|
||||
{
|
||||
// This operation emulates a data source
|
||||
// These operations emulate data sources
|
||||
auto src_opA = [](int param, int* res) { *res = param; };
|
||||
auto src_opB = [](ulong param, ulong* res){ *res = param; };
|
||||
|
||||
|
|
@ -214,7 +228,8 @@ namespace test {
|
|||
CHECK (watch(nM).watchPort(2).watchLead(1).getProcName() == "srcB.c"_expect );
|
||||
CHECK (watch(nM).watchPort(2).watchLead(1).getProcSpec() == "srcB.c(ulong)"_expect);
|
||||
CHECK (watch(nM).watchPort(2).watchLead(1).isSrc() == true ); // the lead port itself is a source
|
||||
CHECK (watch(nM).watchPort(2).watchLead(1).srcPorts().size() == 0 );
|
||||
CHECK (watch(nM).watchPort(2).watchLead(1).srcPorts().size() == 0 ); // ...and thus has an empty source-port-collection
|
||||
|
||||
|
||||
// Helper predicate to verify connectedness to a specific Port given by reference
|
||||
CHECK (watch(nM).watchPort(2).verify_connected( watch(nA).ports()[0]) == false );
|
||||
|
|
@ -227,8 +242,169 @@ namespace test {
|
|||
CHECK (watch(nM).watchPort(2).verify_connected(0, watch(nB).ports()[2]) == false );
|
||||
CHECK (watch(nM).watchPort(2).verify_connected(1, watch(nA).ports()[1]) == false ); // Node-nM.port#2 doesn't connect via source#1 to Node-nA.port#1
|
||||
|
||||
///////////////////////////////////////////////////////TODO WIP
|
||||
UNIMPLEMENTED ("verify connectivity");
|
||||
|
||||
//__________________________________
|
||||
// Inspect Node and Port connectivity
|
||||
|
||||
// High-level case: connections between nodes
|
||||
CHECK (is_linked(nM).to(nA) == true );
|
||||
CHECK (is_linked(nM).to(nB) == true );
|
||||
CHECK (is_linked(nA).to(nB) == false);
|
||||
|
||||
// additionally qualify the index position
|
||||
// of the source node in the sequence of »Lead nodes«
|
||||
CHECK (is_linked(nM).to(nA).asLead(0) == true ); // Node-nA is Lead-#0
|
||||
CHECK (is_linked(nM).to(nA).asLead(1) == false);
|
||||
CHECK (is_linked(nM).to(nB).asLead(0) == false);
|
||||
CHECK (is_linked(nM).to(nB).asLead(1) == true ); // Node-nB is Lead-#1
|
||||
|
||||
// Check if a specific Port is connected to a source node
|
||||
CHECK (is_linked(nM).port(0).to(nA) == true );
|
||||
CHECK (is_linked(nM).port(0).to(nB) == true );
|
||||
CHECK (is_linked(nM).port(0).to(nM) == false); // never connected to itself
|
||||
|
||||
// Similar, but now pick the source node from the »Leads«
|
||||
CHECK (is_linked(nM).port(0).toLead(0) == true );
|
||||
CHECK (is_linked(nM).port(0).toLead(1) == true );
|
||||
CHECK (is_linked(nA).port(0).toLead(0) == false); // nA is a source node and thus has no further source-connections
|
||||
|
||||
// Verify detailed port-to-port connectivity
|
||||
CHECK (is_linked(nM).port(0).to(watch(nA).ports()[0]) == true ); // Node-nM connected within Port-0 to Port-0 of Node-nA
|
||||
CHECK (is_linked(nM).port(0).to(watch(nA).ports()[1]) == false); // ......but not connected to Port-1 of Node-nA
|
||||
CHECK (is_linked(nM).port(0).to(watch(nB).ports()[0]) == true );
|
||||
CHECK (is_linked(nM).port(0).to(watch(nB).ports()[1]) == false);
|
||||
CHECK (is_linked(nM).port(0).to(watch(nB).ports()[2]) == false);
|
||||
CHECK (is_linked(nM).port(2).to(watch(nA).ports()[0]) == false);
|
||||
CHECK (is_linked(nM).port(2).to(watch(nA).ports()[1]) == true ); // this is the connection routed from port-2 to Node-nA, Port-1
|
||||
CHECK (is_linked(nM).port(2).to(watch(nB).ports()[0]) == false);
|
||||
CHECK (is_linked(nM).port(2).to(watch(nB).ports()[1]) == false);
|
||||
CHECK (is_linked(nM).port(2).to(watch(nB).ports()[2]) == true );
|
||||
CHECK (is_linked(nM).port(2).to(watch(nM).ports()[2]) == false); // a nonsensical check, nodes are never connected to themselves
|
||||
|
||||
CHECK (is_linked(nM).port(0).to(nA).atPort(0) == true );
|
||||
CHECK (is_linked(nM).port(0).to(nA).atPort(1) == false);
|
||||
CHECK (is_linked(nM).port(0).to(nB).atPort(0) == true );
|
||||
CHECK (is_linked(nM).port(0).to(nB).atPort(1) == false);
|
||||
CHECK (is_linked(nM).port(0).to(nB).atPort(2) == false);
|
||||
CHECK (is_linked(nM).port(2).to(nA).atPort(0) == false);
|
||||
CHECK (is_linked(nM).port(2).to(nA).atPort(1) == true );
|
||||
CHECK (is_linked(nM).port(2).to(nB).atPort(0) == false);
|
||||
CHECK (is_linked(nM).port(2).to(nB).atPort(1) == false);
|
||||
CHECK (is_linked(nM).port(2).to(nB).atPort(2) == true );
|
||||
CHECK (is_linked(nM).port(2).to(nM).atPort(2) == false);
|
||||
|
||||
CHECK (is_linked(nM).port(0).toLead(0).atPort(0) == true );
|
||||
CHECK (is_linked(nM).port(0).toLead(0).atPort(1) == false);
|
||||
CHECK (is_linked(nM).port(0).toLead(1).atPort(0) == true );
|
||||
CHECK (is_linked(nM).port(0).toLead(1).atPort(1) == false);
|
||||
CHECK (is_linked(nM).port(0).toLead(1).atPort(2) == false);
|
||||
CHECK (is_linked(nM).port(2).toLead(0).atPort(0) == false);
|
||||
CHECK (is_linked(nM).port(2).toLead(0).atPort(1) == true );
|
||||
CHECK (is_linked(nM).port(2).toLead(1).atPort(0) == false);
|
||||
CHECK (is_linked(nM).port(2).toLead(1).atPort(1) == false);
|
||||
CHECK (is_linked(nM).port(2).toLead(1).atPort(2) == true );
|
||||
|
||||
// additionally also qualify the «source slot«
|
||||
// at which the connection is used as input for the processing-function
|
||||
CHECK (is_linked(nM).port(0).asSrc(0).to(nA) == true ); // Node-nM, Port-0 uses as source-slot-0 a connection to Node-nA
|
||||
CHECK (is_linked(nM).port(0).asSrc(1).to(nA) == false );
|
||||
CHECK (is_linked(nM).port(0).asSrc(0).to(nB) == false );
|
||||
CHECK (is_linked(nM).port(0).asSrc(1).to(nB) == true );
|
||||
CHECK (is_linked(nM).port(2).asSrc(0).to(nA) == true );
|
||||
CHECK (is_linked(nM).port(2).asSrc(1).to(nA) == false );
|
||||
CHECK (is_linked(nM).port(2).asSrc(0).to(nB) == false );
|
||||
CHECK (is_linked(nM).port(2).asSrc(1).to(nB) == true );
|
||||
CHECK (is_linked(nM).port(2).asSrc(1).to(nM) == false ); // never connected to itself
|
||||
|
||||
CHECK (is_linked(nM).port(0).asSrc(0).toLead(0) == true ); // Lead-#0 is Node-nA
|
||||
CHECK (is_linked(nM).port(0).asSrc(1).toLead(0) == false );
|
||||
CHECK (is_linked(nM).port(0).asSrc(0).toLead(1) == false );
|
||||
CHECK (is_linked(nM).port(0).asSrc(1).toLead(1) == true );
|
||||
CHECK (is_linked(nM).port(2).asSrc(0).toLead(0) == true );
|
||||
CHECK (is_linked(nM).port(2).asSrc(1).toLead(0) == false );
|
||||
CHECK (is_linked(nM).port(2).asSrc(0).toLead(1) == false );
|
||||
CHECK (is_linked(nM).port(2).asSrc(1).toLead(1) == true );
|
||||
|
||||
// Again detailed port-to-port connections, this time limited by «source slot»
|
||||
CHECK (is_linked(nM).port(0).asSrc(0).to(watch(nA).ports()[0]) == true ); // Node-nA, Port-0 connects as src-#0 to node-nA at Port-0
|
||||
CHECK (is_linked(nM).port(0).asSrc(0).to(watch(nA).ports()[1]) == false); // ...and can thus not be connected to any other Port there
|
||||
CHECK (is_linked(nM).port(0).asSrc(1).to(watch(nA).ports()[0]) == false);
|
||||
CHECK (is_linked(nM).port(0).asSrc(1).to(watch(nA).ports()[1]) == false);
|
||||
CHECK (is_linked(nM).port(0).asSrc(0).to(watch(nB).ports()[0]) == false);
|
||||
CHECK (is_linked(nM).port(0).asSrc(0).to(watch(nB).ports()[1]) == false);
|
||||
CHECK (is_linked(nM).port(0).asSrc(0).to(watch(nB).ports()[2]) == false);
|
||||
CHECK (is_linked(nM).port(0).asSrc(1).to(watch(nB).ports()[0]) == true );
|
||||
CHECK (is_linked(nM).port(0).asSrc(1).to(watch(nB).ports()[1]) == false);
|
||||
CHECK (is_linked(nM).port(0).asSrc(1).to(watch(nB).ports()[2]) == false);
|
||||
CHECK (is_linked(nM).port(2).asSrc(0).to(watch(nA).ports()[0]) == false);
|
||||
CHECK (is_linked(nM).port(2).asSrc(0).to(watch(nA).ports()[1]) == true );
|
||||
CHECK (is_linked(nM).port(2).asSrc(1).to(watch(nA).ports()[0]) == false);
|
||||
CHECK (is_linked(nM).port(2).asSrc(1).to(watch(nA).ports()[1]) == false);
|
||||
CHECK (is_linked(nM).port(2).asSrc(0).to(watch(nB).ports()[0]) == false);
|
||||
CHECK (is_linked(nM).port(2).asSrc(0).to(watch(nB).ports()[1]) == false);
|
||||
CHECK (is_linked(nM).port(2).asSrc(0).to(watch(nB).ports()[2]) == false);
|
||||
CHECK (is_linked(nM).port(2).asSrc(1).to(watch(nB).ports()[0]) == false);
|
||||
CHECK (is_linked(nM).port(2).asSrc(1).to(watch(nB).ports()[1]) == false);
|
||||
CHECK (is_linked(nM).port(2).asSrc(1).to(watch(nB).ports()[2]) == true );
|
||||
CHECK (is_linked(nM).port(2).asSrc(1).to(watch(nM).ports()[2]) == false); // never connected to itself
|
||||
|
||||
CHECK (is_linked(nM).port(0).asSrc(0).to(nA).atPort(0) == true );
|
||||
CHECK (is_linked(nM).port(0).asSrc(0).to(nA).atPort(1) == false);
|
||||
CHECK (is_linked(nM).port(0).asSrc(1).to(nA).atPort(0) == false);
|
||||
CHECK (is_linked(nM).port(0).asSrc(1).to(nA).atPort(1) == false);
|
||||
CHECK (is_linked(nM).port(0).asSrc(0).to(nB).atPort(0) == false);
|
||||
CHECK (is_linked(nM).port(0).asSrc(0).to(nB).atPort(1) == false);
|
||||
CHECK (is_linked(nM).port(0).asSrc(0).to(nB).atPort(2) == false);
|
||||
CHECK (is_linked(nM).port(0).asSrc(1).to(nB).atPort(0) == true );
|
||||
CHECK (is_linked(nM).port(0).asSrc(1).to(nB).atPort(1) == false);
|
||||
CHECK (is_linked(nM).po
|
||||
|
|
|
|||
Loading…
Reference in a new issue