2007-09-03 02:33:47 +02:00
/*
2024-12-06 23:43:18 +01:00
NodeBase ( Test ) - unit test to cover the render node base elements
2010-12-17 23:28:49 +01:00
Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
* there is no entity "Lumiera.org" which holds any copyrights
* Lumiera source code is provided under the GPL Version 2+
== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''
The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!
The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
Copyright ( C )
2009 , Hermann Vosseler < Ichthyostega @ web . de >
2010-12-17 23:28:49 +01:00
Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
* there is no entity "Lumiera.org" which holds any copyrights
* Lumiera source code is provided under the GPL Version 2+
== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''
The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!
The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
* * 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 .
2010-12-17 23:28:49 +01:00
Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
* there is no entity "Lumiera.org" which holds any copyrights
* Lumiera source code is provided under the GPL Version 2+
== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''
The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!
The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-09-03 02:33:47 +02:00
2024-12-06 23:43:18 +01:00
/** @file node-base-test.cpp
* * Unit test \ ref NodeBase_test covers elementary components of render nodes .
2016-11-03 18:20:10 +01:00
*/
2007-09-03 02:33:47 +02:00
2008-12-18 04:47:41 +01:00
# include "lib/test/run.hpp"
2024-12-18 22:22:28 +01:00
# include "lib/iter-zip.hpp"
2024-12-14 03:50:10 +01:00
# include "lib/meta/function.hpp"
2024-12-06 23:43:18 +01:00
# include "steam/engine/proc-node.hpp"
# include "steam/engine/turnout.hpp"
2024-05-12 17:27:07 +02:00
# include "steam/engine/turnout-system.hpp"
2024-12-15 23:25:01 +01:00
# include "steam/engine/feed-manifold.hpp"
2024-12-16 02:26:26 +01:00
# include "steam/engine/diagnostic-buffer-provider.hpp"
# include "steam/engine/buffhandle-attach.hpp"
2024-12-18 22:22:28 +01:00
# include "lib/test/test-helper.hpp"
2016-01-07 03:58:29 +01:00
//#include "lib/format-cout.hpp"
2024-12-17 23:32:11 +01:00
# include "lib/test/diagnostic-output.hpp" /////////////////////TODO
2024-12-18 22:22:28 +01:00
# include "lib/format-util.hpp" ///////////////////////////////TODO
2024-12-18 03:54:31 +01:00
# include "lib/util.hpp"
2007-09-03 02:33:47 +02:00
2009-08-31 01:32:53 +02:00
//using std::string;
2024-12-18 22:22:28 +01:00
using std : : tuple ;
using std : : array ;
2024-12-18 03:54:31 +01:00
using util : : isSameAdr ;
2024-12-18 22:22:28 +01:00
using lib : : test : : showType ;
2024-12-19 19:44:21 +01:00
using lib : : izip ;
2007-09-03 02:33:47 +02:00
2018-11-15 23:55:13 +01:00
namespace steam {
2009-08-31 00:49:08 +02:00
namespace engine {
namespace test {
2009-08-31 01:32:53 +02:00
namespace { // Test fixture
/**
*/
}
2009-08-31 00:49:08 +02:00
2013-10-24 23:06:36 +02:00
/***************************************************************/ /**
2009-08-31 00:49:08 +02:00
* @ test basic render node properties and behaviour .
*/
2024-12-06 23:43:18 +01:00
class NodeBase_test : public Test
2007-09-03 02:33:47 +02:00
{
2024-12-07 18:15:44 +01:00
virtual void
run ( Arg )
2009-08-31 00:49:08 +02:00
{
2024-12-07 18:15:44 +01:00
seedRand ( ) ;
verify_TurnoutSystem ( ) ;
2024-12-15 23:25:01 +01:00
verify_FeedManifold ( ) ;
2024-12-20 01:47:40 +01:00
verify_FeedPrototype ( ) ;
2009-08-31 00:49:08 +02:00
UNIMPLEMENTED ( " build a simple render node and then activate it " ) ;
2024-12-07 18:15:44 +01:00
}
/** @test the TurnoutSystem as transient coordinator for node invocation
*/
void
verify_TurnoutSystem ( )
{
Time nomTime { rani ( 10'000 ) , 0 } ; // drive test with a random »nominal Time« <10s with ms granularity
TurnoutSystem invoker { nomTime } ; // a time spec is mandatory, all further parameters are optional
}
2024-12-15 23:25:01 +01:00
/** @test the FeedManifold as adapter between Engine and processing library
2024-12-19 19:44:21 +01:00
* - bind local λ with various admissible signatures
* - construct specifically tailored FeedManifold types
* - use the DiagnosticBufferProvider for test buffers
* - create FeedManifold instance , passing the λ and additional parameters
* - connect BuffHandle for these buffers into the FeedManifold instance
* - trigger invocation of the function
* - look into the buffers and verify effect
* @ remark within each Render Node , a FeedManifold is used as junction
* to tap into processing functionality provided by external libraries .
* Those will be adapted by a Plug - in , to be loaded by the Lumiera core
* application . The _signature of a functor_ linked to the FeedManifold
* is used as kind of a _low - level - specification_ how to invoke external
* processing functions . Obviously this must be complemented by a more
* high - level descriptor , which is interpreted by the Builder to connect
* a suitable structure of Render Nodes .
* @ see feed - manifold . h
* @ see NodeLinkage_test
2024-12-15 23:25:01 +01:00
*/
void
verify_FeedManifold ( )
{
2024-12-19 04:06:26 +01:00
// Prepare setup to build a suitable FeedManifold...
2024-12-15 23:25:01 +01:00
long r1 = rani ( 100 ) ;
using Buffer = long ;
2024-12-19 04:06:26 +01:00
2024-12-18 03:54:31 +01:00
2024-12-19 19:44:21 +01:00
//______________________________________________________________
2024-12-18 03:54:31 +01:00
// Example-1: a FeedManifold to adapt a simple generator function
2024-12-19 04:06:26 +01:00
auto fun_singleOut = [ & ] ( Buffer * buff ) { * buff = r1 ; } ;
2024-12-15 23:25:01 +01:00
using M1 = FeedManifold < decltype ( fun_singleOut ) > ;
CHECK ( not M1 : : hasInput ( ) ) ;
CHECK ( not M1 : : hasParam ( ) ) ;
2024-12-19 19:44:21 +01:00
CHECK ( 0 = = M1 : : FAN_P ) ;
CHECK ( 0 = = M1 : : FAN_I ) ;
CHECK ( 1 = = M1 : : FAN_O ) ;
2024-12-18 03:54:31 +01:00
// instantiate...
2024-12-17 23:32:11 +01:00
M1 m1 { fun_singleOut } ;
2024-12-16 02:26:26 +01:00
CHECK ( 1 = = m1 . outBuff . array ( ) . size ( ) ) ;
CHECK ( nullptr = = m1 . outArgs ) ;
// CHECK (m1.inArgs ); // does not compile because storage field is not provided
// CHECK (m1.param );
BufferProvider & provider = DiagnosticBufferProvider : : build ( ) ;
2024-12-18 17:04:30 +01:00
BuffHandle buff = provider . lockBufferFor < Buffer > ( - 55 ) ;
2024-12-16 02:26:26 +01:00
CHECK ( buff . isValid ( ) ) ;
CHECK ( buff . accessAs < long > ( ) = = - 55 ) ;
2024-12-18 03:54:31 +01:00
m1 . outBuff . createAt ( 0 , buff ) ; // plant a copy of the BuffHandle into the output slot
2024-12-16 02:26:26 +01:00
CHECK ( m1 . outBuff [ 0 ] . isValid ( ) ) ;
CHECK ( m1 . outBuff [ 0 ] . accessAs < long > ( ) = = - 55 ) ;
2024-12-17 23:32:11 +01:00
2024-12-18 03:54:31 +01:00
m1 . connect ( ) ; // instruct the manifold to connect buffers to arguments
CHECK ( isSameAdr ( m1 . outArgs , * buff ) ) ;
CHECK ( * m1 . outArgs = = - 55 ) ;
m1 . invoke ( ) ; // invoke the adapted processing function (fun_singleOut)
CHECK ( buff . accessAs < long > ( ) = = r1 ) ; // result: the random number r1 was written into the buffer.
2024-12-18 22:22:28 +01:00
2024-12-19 19:44:21 +01:00
//_____________________________________________________________
2024-12-18 03:54:31 +01:00
// Example-2: adapt a function to process input -> output buffer
2024-12-18 17:04:30 +01:00
auto fun_singleInOut = [ ] ( Buffer * in , Buffer * out ) { * out = * in + 1 ; } ;
2024-12-18 03:54:31 +01:00
using M2 = FeedManifold < decltype ( fun_singleInOut ) > ;
2024-12-18 17:04:30 +01:00
CHECK ( M2 : : hasInput ( ) ) ;
2024-12-18 03:54:31 +01:00
CHECK ( not M2 : : hasParam ( ) ) ;
CHECK ( 1 = = M2 : : FAN_I ) ;
CHECK ( 1 = = M2 : : FAN_O ) ;
// instantiate...
M2 m2 { fun_singleInOut } ;
2024-12-18 17:04:30 +01:00
CHECK ( 1 = = m2 . inBuff . array ( ) . size ( ) ) ;
2024-12-18 03:54:31 +01:00
CHECK ( 1 = = m2 . outBuff . array ( ) . size ( ) ) ;
2024-12-18 17:04:30 +01:00
CHECK ( nullptr = = m2 . inArgs ) ;
2024-12-18 03:54:31 +01:00
CHECK ( nullptr = = m2 . outArgs ) ;
2024-12-18 17:04:30 +01:00
// use the result of the preceding Example-1 as input
// and get a new buffer to capture the output
BuffHandle buffOut = provider . lockBufferFor < Buffer > ( - 99 ) ;
CHECK ( buff . accessAs < long > ( ) = = r1 ) ;
CHECK ( buffOut . accessAs < long > ( ) = = - 55 ) ; ///////////////////////////////////////OOO should be -99 --> aliasing of buffer meta records due to bug with hash generation
// configure the Manifold-2 with this input and output buffer
m2 . inBuff . createAt ( 0 , buff ) ;
m2 . outBuff . createAt ( 0 , buffOut ) ;
CHECK ( m2 . inBuff [ 0 ] . isValid ( ) ) ;
CHECK ( m2 . inBuff [ 0 ] . accessAs < long > ( ) = = r1 ) ;
CHECK ( m2 . outBuff [ 0 ] . isValid ( ) ) ;
CHECK ( m2 . outBuff [ 0 ] . accessAs < long > ( ) = = - 55 ) ; ////////////////////////////////OOO should be -99
// connect arguments to buffers
m2 . connect ( ) ;
CHECK ( isSameAdr ( m2 . inArgs , * buff ) ) ;
CHECK ( isSameAdr ( m2 . outArgs , * buffOut ) ) ;
CHECK ( * m2 . outArgs = = - 55 ) ; ////////////////////////////////OOO should be -99
m2 . invoke ( ) ;
CHECK ( buffOut . accessAs < long > ( ) = = r1 + 1 ) ;
2024-12-18 22:22:28 +01:00
2024-12-19 19:44:21 +01:00
//______________________________________
2024-12-18 22:22:28 +01:00
// Example-3: accept complex buffer setup
using Sequence = array < Buffer , 3 > ;
using Channels = array < Buffer * , 3 > ;
using Compound = tuple < Sequence * , Buffer * > ;
auto fun_complexInOut = [ ] ( Channels in , Compound out )
{
auto [ seq , extra ] = out ;
2024-12-19 19:44:21 +01:00
for ( auto [ i , b ] : izip ( in ) )
2024-12-18 22:22:28 +01:00
{
( * seq ) [ i ] = * b + 1 ;
* extra + = * b ;
}
} ;
using M3 = FeedManifold < decltype ( fun_complexInOut ) > ;
CHECK ( M3 : : hasInput ( ) ) ;
CHECK ( not M3 : : hasParam ( ) ) ;
CHECK ( 3 = = M3 : : FAN_I ) ;
CHECK ( 2 = = M3 : : FAN_O ) ;
CHECK ( showType < M3 : : ArgI > ( ) = = " array<long*, 3ul> " _expect ) ;
CHECK ( showType < M3 : : ArgO > ( ) = = " tuple<array<long, 3ul>*, long*> " _expect ) ;
// instantiate...
M3 m3 { fun_complexInOut } ;
CHECK ( 3 = = m3 . inBuff . array ( ) . size ( ) ) ;
CHECK ( 2 = = m3 . outBuff . array ( ) . size ( ) ) ;
// use existing buffers and one additional buffer for input
BuffHandle buffI0 = buff ;
BuffHandle buffI1 = buffOut ;
BuffHandle buffI2 = provider . lockBufferFor < Buffer > ( - 22 ) ;
CHECK ( buffI0 . accessAs < long > ( ) = = r1 ) ; // (result from Example-1)
CHECK ( buffI1 . accessAs < long > ( ) = = r1 + 1 ) ; // (result from Example-2)
CHECK ( buffI2 . accessAs < long > ( ) = = - 55 ) ; ///////////////////////////////////////OOO should be -22
// prepare a compound buffer and an extra buffer for output...
BuffHandle buffO0 = provider . lockBufferFor < Sequence > ( Sequence { - 111 , - 222 , - 333 } ) ;
BuffHandle buffO1 = provider . lockBufferFor < Buffer > ( - 33 ) ;
CHECK ( ( buffO0 . accessAs < Sequence > ( ) = = Sequence { - 111 , - 222 , - 333 } ) ) ;
CHECK ( buffO1 . accessAs < long > ( ) = = - 55 ) ; ///////////////////////////////////////OOO should be -33
// configure the Manifold-3 with these input and output buffers
m3 . inBuff . createAt ( 0 , buffI0 ) ;
m3 . inBuff . createAt ( 1 , buffI1 ) ;
m3 . inBuff . createAt ( 2 , buffI2 ) ;
m3 . outBuff . createAt ( 0 , buffO0 ) ;
m3 . outBuff . createAt ( 1 , buffO1 ) ;
m3 . connect ( ) ;
// Verify data exposed prior to invocation....
auto & [ ia0 , ia1 , ia2 ] = m3 . inArgs ;
auto & [ oa0 , oa1 ] = m3 . outArgs ;
auto & [ o00 , o01 , o02 ] = * oa0 ;
CHECK ( * ia0 = = r1 ) ;
CHECK ( * ia1 = = r1 + 1 ) ;
CHECK ( * ia2 = = - 55 ) ; /////////////////////////////////////////////////////OOO should be -22
CHECK ( o00 = = - 111 ) ;
CHECK ( o01 = = - 222 ) ;
CHECK ( o02 = = - 333 ) ;
CHECK ( * oa1 = = - 55 ) ; /////////////////////////////////////////////////////OOO should be -33
m3 . invoke ( ) ;
CHECK ( * ia0 = = r1 ) ; // Input buffers unchanged
CHECK ( * ia1 = = r1 + 1 ) ;
CHECK ( * ia2 = = - 55 ) ; /////////////////////////////////////////////////////OOO should be -22
CHECK ( o00 = = * ia0 + 1 ) ; // Output buffers as processed by the function
CHECK ( o01 = = * ia1 + 1 ) ;
CHECK ( o02 = = * ia2 + 1 ) ;
CHECK ( * oa1 = = - 55 + * ia0 + * ia1 + * ia2 ) ; ///////////////////////////////////////////OOO should be -33
2024-12-19 19:44:21 +01:00
//_________________________________
// Example-4: pass a parameter tuple
using Params = tuple < short , long > ;
// Note: demonstrates mix of complex params, an array for input, but just a simple output buffer
auto fun_ParamInOut = [ ] ( Params param , Channels in , Buffer * out )
{
auto [ s , l ] = param ;
* out = 0 ;
for ( Buffer * b : in )
* out + = ( s + l ) * ( * b ) ;
} ;
using M4 = FeedManifold < decltype ( fun_ParamInOut ) > ;
CHECK ( M4 : : hasInput ( ) ) ;
CHECK ( M4 : : hasParam ( ) ) ;
CHECK ( 2 = = M4 : : FAN_P ) ;
CHECK ( 3 = = M4 : : FAN_I ) ;
CHECK ( 1 = = M4 : : FAN_O ) ;
CHECK ( showType < M4 : : ArgI > ( ) = = " array<long*, 3ul> " _expect ) ;
CHECK ( showType < M4 : : ArgO > ( ) = = " long * " _expect ) ;
CHECK ( showType < M4 : : Param > ( ) = = " tuple<short, long> " _expect ) ;
// Note: instantiate passing param values as extra arguments
short r2 = 1 + rani ( 10 ) ;
long r3 = rani ( 1000 ) ;
M4 m4 { Params { r2 , r3 } , fun_ParamInOut } ; // parameters directly given by-value
auto & [ p0 , p1 ] = m4 . param ;
CHECK ( p0 = = r2 ) ; // parameter values exposed through manifold
CHECK ( p1 = = r3 ) ;
// wire-in existing buffers for this example
m4 . inBuff . createAt ( 0 , buffI0 ) ;
m4 . inBuff . createAt ( 1 , buffI1 ) ;
m4 . inBuff . createAt ( 2 , buffI2 ) ;
m4 . outBuff . createAt ( 0 , buffO1 ) ;
CHECK ( * ia0 = = r1 ) ; // existing values in the buffers....
CHECK ( * ia1 = = r1 + 1 ) ;
CHECK ( * ia2 = = - 55 ) ; /////////////////////////////////////////////////////OOO should be -22
CHECK ( * oa1 = = - 55 + * ia0 + * ia1 + * ia2 ) ; ///////////////////////////////////////////OOO should be -33
m4 . connect ( ) ;
m4 . invoke ( ) ; // processing combines input buffers with parameters
CHECK ( * oa1 = = ( r2 + r3 ) * ( r1 + r1 + 1 - 55 ) ) ; /////////////////////////////////////OOO should be -22
//______________________________________
// Example-5: simple parameter and output
2024-12-20 01:47:40 +01:00
auto fun_singleParamOut = [ ] ( short param , Buffer * buff ) { * buff = param - 1 ; } ;
2024-12-19 19:44:21 +01:00
using M5 = FeedManifold < decltype ( fun_singleParamOut ) > ;
CHECK ( not M5 : : hasInput ( ) ) ;
CHECK ( M5 : : hasParam ( ) ) ;
CHECK ( 1 = = M5 : : FAN_P ) ;
CHECK ( 0 = = M5 : : FAN_I ) ;
CHECK ( 1 = = M5 : : FAN_O ) ;
CHECK ( showType < M5 : : ArgI > ( ) = = " tuple<> " _expect ) ;
CHECK ( showType < M5 : : ArgO > ( ) = = " long * " _expect ) ;
CHECK ( showType < M5 : : Param > ( ) = = " short " _expect ) ;
// instantiate, directly passing param value
M5 m5 { r2 , fun_singleParamOut } ;
// wire with one output buffer
m5 . outBuff . createAt ( 0 , buffO1 ) ;
m5 . connect ( ) ;
CHECK ( m5 . param = = r2 ) ; // the parameter value passed to the ctor
// CHECK (m5.inArgs ); // does not compile because storage field is not provided
CHECK ( * m5 . outArgs = = * oa1 ) ; // still previous value sitting in the buffer...
m5 . invoke ( ) ;
CHECK ( * oa1 = = r2 - 1 ) ; // processing has placed result based on param into output buffer
2024-12-20 01:47:40 +01:00
// done with these buffers
buffI0 . release ( ) ;
buffI1 . release ( ) ;
buffI2 . release ( ) ;
buffO0 . release ( ) ;
buffO1 . release ( ) ;
}
/** @test Setup of a FeeManifold to attach parameter-functors
*/
void
verify_FeedPrototype ( )
{
// Prepare setup to build a suitable FeedManifold...
long r1 = rani ( 100 ) ;
using Buffer = long ;
BufferProvider & provider = DiagnosticBufferProvider : : build ( ) ;
BuffHandle buff = provider . lockBufferFor < Buffer > ( - 55 ) ;
auto fun_singleParamOut = [ ] ( short param , Buffer * buff ) { * buff = param - 1 ; } ;
using M1 = FeedManifold < decltype ( fun_singleParamOut ) > ;
using P1 = M1 : : Prototype ;
CHECK ( P1 : : hasParam ( ) ) ;
CHECK ( not P1 : : hasParamFun ( ) ) ;
CHECK ( not P1 : : canActivate ( ) ) ;
P1 p1 { move ( fun_singleParamOut ) } ;
CHECK ( sizeof ( p1 ) < = sizeof ( void * ) ) ;
TurnoutSystem turSys { Time : : NEVER } ;
M1 m1 = p1 . createFeed ( turSys ) ;
CHECK ( m1 . param = = short { } ) ;
m1 . outBuff . createAt ( 0 , buff ) ;
CHECK ( buff . accessAs < long > ( ) = = - 55 ) ;
m1 . connect ( ) ;
CHECK ( * m1 . outArgs = = - 55 ) ;
m1 . invoke ( ) ;
CHECK ( * m1 . outArgs = = 0 - 1 ) ;
CHECK ( buff . accessAs < long > ( ) = = 0 - 1 ) ;
2024-12-15 23:25:01 +01:00
}
2009-08-31 00:49:08 +02:00
} ;
/** Register this test class... */
2024-12-06 23:43:18 +01:00
LAUNCHER ( NodeBase_test , " unit node " ) ;
2009-08-31 00:49:08 +02:00
2018-11-15 23:55:13 +01:00
} } } // namespace steam::engine::test