1
//---------------------------------------------------------------------------
3
// Project: OpenWalnut ( http://www.openwalnut.org )
5
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
6
// For more information see http://www.openwalnut.org/copying
8
// This file is part of OpenWalnut.
10
// OpenWalnut is free software: you can redistribute it and/or modify
11
// it under the terms of the GNU Lesser General Public License as published by
12
// the Free Software Foundation, either version 3 of the License, or
13
// (at your option) any later version.
15
// OpenWalnut is distributed in the hope that it will be useful,
16
// but WITHOUT ANY WARRANTY; without even the implied warranty of
17
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
// GNU Lesser General Public License for more details.
20
// You should have received a copy of the GNU Lesser General Public License
21
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
23
//---------------------------------------------------------------------------
25
#ifndef WMODULECONNECTOR_TEST_H
26
#define WMODULECONNECTOR_TEST_H
31
#include <boost/shared_ptr.hpp>
33
#include <cxxtest/TestSuite.h>
35
#include "../WModuleConnector.h"
36
#include "../WModuleInputData.h"
37
#include "../WModuleOutputData.h"
38
#include "../WModuleInputConnector.h"
39
#include "../WModuleOutputConnector.h"
40
#include "../WModule.h"
41
#include "../../common/WSegmentationFault.h"
42
#include "../../common/WTransferable.h"
43
#include "../../common/WPrototyped.h"
44
#include "../../common/WLogger.h"
45
#include "../exceptions/WModuleConnectorInitFailed.h"
46
#include "../exceptions/WModuleConnectionFailed.h"
47
#include "../exceptions/WModuleConnectorsIncompatible.h"
48
#include "../exceptions/WModuleException.h"
49
#include "../exceptions/WModuleConnectorUnconnected.h"
52
* Test class used to test data transfer and compatibility checks.
54
class WTestTransferableBase: public WTransferable
56
friend class WModuleConnectorTest;
62
WTestTransferableBase(): WTransferable()
69
* Gets the name of this prototype.
73
virtual const std::string getName() const
75
return "WTestTransferableBase";
79
* Gets the description for this prototype.
81
* \return the description
83
virtual const std::string getDescription() const
85
return "Test class for testing transfer of data.";
89
* Returns a prototype instantiated with the true type of the deriving class.
91
* \return the prototype.
93
static boost::shared_ptr< WPrototyped > getPrototype()
95
return boost::shared_ptr< WPrototyped >( new WTestTransferableBase() );
99
* Gives the magic int.
101
* \return the currently set data
111
* \param i the int used for testing.
128
* Derived test class used to test data transfer and compatibility checks, especially the inheritance checks.
130
class WTestTransferableDerived: public WTestTransferableBase
132
friend class WModuleConnectorTest;
138
WTestTransferableDerived(): WTestTransferableBase()
143
* Gets the name of this prototype.
147
virtual const std::string getName() const
149
return "WTestTransferableDerived";
153
* Gets the description for this prototype.
155
* \return the description
157
virtual const std::string getDescription() const
159
return "Test class for testing transfer of data.";
163
* Returns a prototype instantiated with the true type of the deriving class.
165
* \return the prototype.
167
static boost::shared_ptr< WPrototyped > getPrototype()
169
return boost::shared_ptr< WPrototyped >( new WTestTransferableDerived() );
177
* Class implementing a simple module since WModuleConnector itself is not usable for proper
178
* testing itself because it is has pure virtual methods, i.e. is abstract.
180
class WModuleImpl: public WModule
182
friend class WModuleConnectorTest;
188
* \param n a string to test with (sets initial value).
190
explicit WModuleImpl( std::string n="?" ): WModule()
198
virtual ~WModuleImpl()
203
* Create instance of this module class.
205
* \return new instance of this module.
207
virtual boost::shared_ptr< WModule > factory() const
209
return boost::shared_ptr< WModule >( new WModuleImpl() );
213
* Returns name of this module.
215
* \return the name of this module.
217
virtual const std::string getName() const
223
* Returns description of module.
225
* \return the description.
227
const std::string getDescription() const
235
virtual void connectors()
237
m_input = boost::shared_ptr< WModuleInputData< WTestTransferableBase > >(
238
new WModuleInputData< WTestTransferableBase > ( shared_from_this(), "in1", "desc1" )
240
// add it to the list of connectors. Please note, that a connector NOT added via addConnector will not work as expected.
241
addConnector( m_input );
243
m_output = boost::shared_ptr< WModuleOutputData< WTestTransferableBase > >(
244
new WModuleOutputData< WTestTransferableBase > ( shared_from_this(), "out1", "desc2" )
246
// add it to the list of connectors. Please note, that a connector NOT added via addConnector will not work as expected.
247
addConnector( m_output );
249
// now, the same with the derived class as type
250
m_inputDerived = boost::shared_ptr< WModuleInputData< WTestTransferableDerived > >(
251
new WModuleInputData< WTestTransferableDerived > ( shared_from_this(), "in2", "desc1" )
253
// add it to the list of connectors. Please note, that a connector NOT added via addConnector will not work as expected.
254
addConnector( m_inputDerived );
256
m_outputDerived = boost::shared_ptr< WModuleOutputData< WTestTransferableDerived > >(
257
new WModuleOutputData< WTestTransferableDerived > ( shared_from_this(), "out2", "desc2" )
259
// add it to the list of connectors. Please note, that a connector NOT added via addConnector will not work as expected.
260
addConnector( m_outputDerived );
265
* temporary name string
269
// required since pure virtual
270
virtual void moduleMain()
272
// Since the modules run in a separate thread: such loops are possible
273
while( !m_shutdownFlag() )
281
* Notifier called whenever a connection got established.
283
virtual void notifyConnectionEstablished( boost::shared_ptr< WModuleConnector > /*here*/,
284
boost::shared_ptr< WModuleConnector > /*there*/ )
286
// std::cout << "connection established between " << n << ":" << here->getCanonicalName() << " and "
287
// << there->getCanonicalName() << std::endl;
291
* Notifier called whenever a connection got closed.
293
virtual void notifyConnectionClosed( boost::shared_ptr< WModuleConnector > /*here*/,
294
boost::shared_ptr< WModuleConnector > /*there*/ )
296
// std::cout << "connection closed between " << n << ":" << here->getCanonicalName() << " and "
297
// << there->getCanonicalName() << std::endl;
301
* Notifier called whenever a changed data was propagated to one of this modules connectors.
303
* param input the local connector receiving the event.
304
* \param output the remote connector propagating the event.
306
virtual void notifyDataChange( boost::shared_ptr< WModuleConnector > /*input */,
307
boost::shared_ptr< WModuleConnector > output )
309
// just copy the data and add one
310
boost::shared_ptr< WModuleOutputData< WTestTransferableBase > > o =
311
boost::shared_dynamic_cast< WModuleOutputData< WTestTransferableBase > >( output );
317
boost::shared_ptr< WTestTransferableBase > ds = o->getData();
320
data = ds->get() + 1;
323
// std::cout << "change to " << data << " in " << input->getCanonicalName() << " from " << output->getCanonicalName()
329
* The data lastly submitted.
336
boost::shared_ptr< WModuleInputData< WTestTransferableBase > > m_input;
339
* Input connection with a derived class as transferable.
341
boost::shared_ptr< WModuleInputData< WTestTransferableDerived > > m_inputDerived;
346
boost::shared_ptr< WModuleOutputData< WTestTransferableBase > > m_output;
349
* Output connection with a derived class as transferable
351
boost::shared_ptr< WModuleOutputData< WTestTransferableDerived > > m_outputDerived;
355
* Tests the WModuleConnector class. We use WModuleConnector's direct derived classes WModuleInputConnector and
356
* WModuleOutputConnector to test their common functionality implemented in WModuleConnector (which has pure virtual members -> so
357
* can't be instantiated directly).
359
class WModuleConnectorTest : public CxxTest::TestSuite
363
* Setup logger and other stuff for each test.
371
* Simple module to test with.
373
boost::shared_ptr< WModuleImpl > m1;
376
* Simple module to test with.
378
boost::shared_ptr< WModuleImpl > m2;
381
* Simple module to test with.
383
boost::shared_ptr< WModuleImpl > m3;
386
* Initialized the test modules.
388
void createModules( void )
390
// init 3 separate test modules
391
m1 = boost::shared_ptr< WModuleImpl >( new WModuleImpl( "m1" ) );
392
m2 = boost::shared_ptr< WModuleImpl >( new WModuleImpl( "m2" ) );
393
m3 = boost::shared_ptr< WModuleImpl >( new WModuleImpl( "m3" ) );
397
* Initializes modules. This is normally done by the module container.
399
void initModules( void )
407
* Initialize some connections.
409
void initConnections( void )
411
// connect output with input (cyclic)
412
m1->m_output->connect( m2->m_input );
413
m1->m_input->connect( m2->m_output );
417
* Test whether modules can be created without exception and proper initialization of connection lists.
419
void testModuleCreation( void )
421
TS_ASSERT_THROWS_NOTHING( createModules() );
423
// check whether there are NO connectors.
424
// The constructor should now create connectors since shared_ptr are needed -> init in constructor leads to exception
425
// (it is enough to test one of them)
426
TS_ASSERT( m1->m_inputConnectors.size() == 0 );
427
TS_ASSERT( m1->m_outputConnectors.size() == 0 );
431
* Test whether modules can be initialized without problems.
433
void testModuleInitialization( void )
437
TS_ASSERT_THROWS_NOTHING( initModules() );
439
// now there should be 1 everywhere
440
TS_ASSERT( m1->m_inputConnectors.size() == 2 );
441
TS_ASSERT( m1->m_outputConnectors.size() == 2 );
442
TS_ASSERT( m2->m_inputConnectors.size() == 2 );
443
TS_ASSERT( m2->m_outputConnectors.size() == 2 );
444
TS_ASSERT( m3->m_inputConnectors.size() == 2 );
445
TS_ASSERT( m3->m_outputConnectors.size() == 2 );
447
// now we have 3 properly initialized modules?
448
TS_ASSERT( m1->isInitialized()() );
449
TS_ASSERT( m2->isInitialized()() );
450
TS_ASSERT( m3->isInitialized()() );
454
* Test whether module initialization is robust against double init.
456
void testModuleTwiceInitialization( void )
458
WException::disableBacktrace();
463
// try initializing twice
464
TS_ASSERT_THROWS( m1->initialize(), WModuleConnectorInitFailed );
465
TS_ASSERT( m1->isInitialized()() );
469
* Test whether automatic compatibility check works.
471
void testModuleConnectorCompatibility( void )
473
WException::disableBacktrace();
478
// connect input with input and output with output should fail
479
TS_ASSERT_THROWS( m1->m_input->connect( m2->m_input ), WModuleConnectorsIncompatible );
480
TS_ASSERT_THROWS( m1->m_output->connect( m2->m_output ), WModuleConnectorsIncompatible );
482
// there should be nothing connected.
483
TS_ASSERT( m1->m_output->m_connected.size() == 0 );
484
TS_ASSERT( m1->m_input->m_connected.size() == 0 );
485
TS_ASSERT( m2->m_output->m_connected.size() == 0 );
486
TS_ASSERT( m2->m_input->m_connected.size() == 0 );
490
* Test whether automatic type compatibility check works.
492
void testModuleConnectorTypeCompatibility( void )
494
WException::disableBacktrace();
499
TS_ASSERT( m1->m_input->m_connected.size() == 0 );
500
TS_ASSERT( m1->m_output->m_connected.size() == 0 );
501
TS_ASSERT( m1->m_inputDerived->m_connected.size() == 0 );
502
TS_ASSERT( m1->m_outputDerived->m_connected.size() == 0 );
504
// connect an input with base type to output of derived type
505
TS_ASSERT_THROWS_NOTHING( m1->m_input->connect( m2->m_outputDerived ) );
506
TS_ASSERT( m1->m_input->m_connected.size() == 1 );
507
TS_ASSERT( m2->m_outputDerived->m_connected.size() == 1 );
509
// connect an input of derived type with output of base type
510
TS_ASSERT_THROWS( m1->m_output->connect( m2->m_inputDerived ), WModuleConnectorsIncompatible );
511
TS_ASSERT( m1->m_output->m_connected.size() == 0 );
512
TS_ASSERT( m1->m_inputDerived->m_connected.size() == 0 );
516
* Test whether connection works properly
518
void testModuleConnection( void )
523
TS_ASSERT_THROWS_NOTHING( initConnections() );
525
// check that every connector has a connection count of 1
526
TS_ASSERT( m1->m_output->m_connected.size() == 1 );
527
TS_ASSERT( m1->m_input->m_connected.size() == 1 );
528
TS_ASSERT( m2->m_output->m_connected.size() == 1 );
529
TS_ASSERT( m2->m_input->m_connected.size() == 1 );
533
* Test whether connecting twice is not possible.
535
void testModuleTwiceConnection( void )
541
// try to connect twice
542
TS_ASSERT_THROWS_NOTHING( m1->m_output->connect( m2->m_input ) );
543
TS_ASSERT_THROWS_NOTHING( m1->m_input->connect( m2->m_output ) );
544
TS_ASSERT( m1->m_output->m_connected.size() == 1 );
545
TS_ASSERT( m1->m_input->m_connected.size() == 1 );
546
TS_ASSERT( m2->m_output->m_connected.size() == 1 );
547
TS_ASSERT( m2->m_input->m_connected.size() == 1 );
551
* Test whether the connection can properly be disconnected.
553
void testModuleDisconnect( void )
559
// Disconnect something not connected
560
TS_ASSERT_THROWS_NOTHING( m1->m_output->disconnect( m1->m_input ) );
561
TS_ASSERT( m1->m_output->m_connected.size() == 1 );
562
TS_ASSERT( m1->m_input->m_connected.size() == 1 );
564
// Disconnect a connected
565
TS_ASSERT_THROWS_NOTHING( m1->m_output->disconnect( m2->m_input ) );
566
TS_ASSERT( m1->m_output->m_connected.size() == 0 );
567
TS_ASSERT( m1->m_input->m_connected.size() == 1 );
568
TS_ASSERT( m2->m_output->m_connected.size() == 1 );
569
TS_ASSERT( m2->m_input->m_connected.size() == 0 );
573
* Test whether all connections can be removed in one step.
575
void testModuleDisconnectAll( void )
582
TS_ASSERT_THROWS_NOTHING( m3->m_input->connect( m2->m_output ) );
584
// now m2->out should have 2 connections
585
TS_ASSERT( m2->m_output->m_connected.size() == 2 );
586
TS_ASSERT( m3->m_input->m_connected.size() == 1 );
588
// remove both connections
589
m2->m_output->disconnectAll();
590
TS_ASSERT( m2->m_output->m_connected.size() == 0 );
591
TS_ASSERT( m1->m_input->m_connected.size() == 0 );
592
TS_ASSERT( m3->m_input->m_connected.size() == 0 );
596
* Test whether module clean up is working properly.
598
void testModuleCleanup( void )
604
TS_ASSERT_THROWS_NOTHING( m1->cleanup() );
605
TS_ASSERT( m1->m_inputConnectors.size() == 0 );
606
TS_ASSERT( m1->m_outputConnectors.size() == 0 );
610
* Tests the propagation of data.
612
void testModulePropagateDataChange( void )
618
// set some data, propagate change
619
boost::shared_ptr< WTestTransferableBase > data = boost::shared_ptr< WTestTransferableBase >( new WTestTransferableBase() );
622
TS_ASSERT_THROWS_NOTHING( m1->m_output->updateData( data ) );
624
// got the data transferred?
625
TS_ASSERT( m1->m_output->getData()->get() == d );
626
TS_ASSERT( m2->m_input->getData()->get() == d );
627
TS_ASSERT( m2->data == d + 1 );
631
* Tests several cases of unset data.
633
void testModuleInvalidData( void )
635
WException::disableBacktrace();
641
// try to get data from an unconnected connector
642
TS_ASSERT( !m3->m_input->getData().get() );
644
// try to get uninitialized data -> should return an "NULL" Pointer
645
TS_ASSERT( m2->m_input->getData() == boost::shared_ptr< WTestTransferableBase >() );
649
#endif // WMODULECONNECTOR_TEST_H