OpenWalnut
1.2.5
|
00001 //--------------------------------------------------------------------------- 00002 // 00003 // Project: OpenWalnut ( http://www.openwalnut.org ) 00004 // 00005 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS 00006 // For more information see http://www.openwalnut.org/copying 00007 // 00008 // This file is part of OpenWalnut. 00009 // 00010 // OpenWalnut is free software: you can redistribute it and/or modify 00011 // it under the terms of the GNU Lesser General Public License as published by 00012 // the Free Software Foundation, either version 3 of the License, or 00013 // (at your option) any later version. 00014 // 00015 // OpenWalnut is distributed in the hope that it will be useful, 00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00018 // GNU Lesser General Public License for more details. 00019 // 00020 // You should have received a copy of the GNU Lesser General Public License 00021 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>. 00022 // 00023 //--------------------------------------------------------------------------- 00024 00025 #ifndef WMODULECONNECTOR_TEST_H 00026 #define WMODULECONNECTOR_TEST_H 00027 00028 #include <iostream> 00029 #include <string> 00030 00031 #include <boost/shared_ptr.hpp> 00032 00033 #include <cxxtest/TestSuite.h> 00034 00035 #include "../WModuleConnector.h" 00036 #include "../WModuleInputData.h" 00037 #include "../WModuleOutputData.h" 00038 #include "../WModuleInputConnector.h" 00039 #include "../WModuleOutputConnector.h" 00040 #include "../WModule.h" 00041 #include "../../common/WSegmentationFault.h" 00042 #include "../../common/WTransferable.h" 00043 #include "../../common/WPrototyped.h" 00044 #include "../../common/WLogger.h" 00045 #include "../exceptions/WModuleConnectorInitFailed.h" 00046 #include "../exceptions/WModuleConnectionFailed.h" 00047 #include "../exceptions/WModuleConnectorsIncompatible.h" 00048 #include "../exceptions/WModuleException.h" 00049 #include "../exceptions/WModuleConnectorUnconnected.h" 00050 00051 /** 00052 * Test class used to test data transfer and compatibility checks. 00053 */ 00054 class WTestTransferableBase: public WTransferable 00055 { 00056 friend class WModuleConnectorTest; 00057 00058 public: 00059 00060 /** 00061 * Constructor. 00062 */ 00063 WTestTransferableBase(): WTransferable() 00064 { 00065 // do nothing here 00066 m_data = 0; 00067 }; 00068 00069 /** 00070 * Gets the name of this prototype. 00071 * 00072 * \return the name. 00073 */ 00074 virtual const std::string getName() const 00075 { 00076 return "WTestTransferableBase"; 00077 } 00078 00079 /** 00080 * Gets the description for this prototype. 00081 * 00082 * \return the description 00083 */ 00084 virtual const std::string getDescription() const 00085 { 00086 return "Test class for testing transfer of data."; 00087 } 00088 00089 /** 00090 * Returns a prototype instantiated with the true type of the deriving class. 00091 * 00092 * \return the prototype. 00093 */ 00094 static boost::shared_ptr< WPrototyped > getPrototype() 00095 { 00096 return boost::shared_ptr< WPrototyped >( new WTestTransferableBase() ); 00097 } 00098 00099 /** 00100 * Gives the magic int. 00101 * 00102 * \return the currently set data 00103 */ 00104 int get() const 00105 { 00106 return m_data; 00107 } 00108 00109 /** 00110 * Sets the new int. 00111 * 00112 * \param i the int used for testing. 00113 */ 00114 void set( int i ) 00115 { 00116 m_data = i; 00117 } 00118 00119 protected: 00120 00121 /** 00122 * The data. 00123 */ 00124 int m_data; 00125 00126 private: 00127 }; 00128 00129 /** 00130 * Derived test class used to test data transfer and compatibility checks, especially the inheritance checks. 00131 */ 00132 class WTestTransferableDerived: public WTestTransferableBase 00133 { 00134 friend class WModuleConnectorTest; 00135 00136 public: 00137 00138 /** 00139 * Constructor. 00140 */ 00141 WTestTransferableDerived(): WTestTransferableBase() 00142 { 00143 }; 00144 00145 /** 00146 * Gets the name of this prototype. 00147 * 00148 * \return the name. 00149 */ 00150 virtual const std::string getName() const 00151 { 00152 return "WTestTransferableDerived"; 00153 } 00154 00155 /** 00156 * Gets the description for this prototype. 00157 * 00158 * \return the description 00159 */ 00160 virtual const std::string getDescription() const 00161 { 00162 return "Test class for testing transfer of data."; 00163 } 00164 00165 /** 00166 * Returns a prototype instantiated with the true type of the deriving class. 00167 * 00168 * \return the prototype. 00169 */ 00170 static boost::shared_ptr< WPrototyped > getPrototype() 00171 { 00172 return boost::shared_ptr< WPrototyped >( new WTestTransferableDerived() ); 00173 } 00174 00175 protected: 00176 00177 private: 00178 }; 00179 00180 /** 00181 * Class implementing a simple module since WModuleConnector itself is not usable for proper 00182 * testing itself because it is has pure virtual methods, i.e. is abstract. 00183 */ 00184 class WModuleImpl: public WModule 00185 { 00186 friend class WModuleConnectorTest; 00187 00188 public: 00189 00190 /** 00191 * Constructor. 00192 * 00193 * \param n a string to test with (sets initial value). 00194 */ 00195 explicit WModuleImpl( std::string n="?" ): WModule() 00196 { 00197 this->n = n; 00198 } 00199 00200 /** 00201 * Destructor. 00202 */ 00203 virtual ~WModuleImpl() 00204 { 00205 } 00206 00207 /** 00208 * Create instance of this module class. 00209 * 00210 * \return new instance of this module. 00211 */ 00212 virtual boost::shared_ptr< WModule > factory() const 00213 { 00214 return boost::shared_ptr< WModule >( new WModuleImpl() ); 00215 } 00216 00217 /** 00218 * Returns name of this module. 00219 * 00220 * \return the name of this module. 00221 */ 00222 virtual const std::string getName() const 00223 { 00224 return "testmodule"; 00225 } 00226 00227 /** 00228 * Returns description of module. 00229 * 00230 * \return the description. 00231 */ 00232 const std::string getDescription() const 00233 { 00234 return "testdesc"; 00235 } 00236 00237 /** 00238 * Set up connectors. 00239 */ 00240 virtual void connectors() 00241 { 00242 m_input = boost::shared_ptr< WModuleInputData< WTestTransferableBase > >( 00243 new WModuleInputData< WTestTransferableBase > ( shared_from_this(), "in1", "desc1" ) 00244 ); 00245 // add it to the list of connectors. Please note, that a connector NOT added via addConnector will not work as expected. 00246 addConnector( m_input ); 00247 00248 m_output = boost::shared_ptr< WModuleOutputData< WTestTransferableBase > >( 00249 new WModuleOutputData< WTestTransferableBase > ( shared_from_this(), "out1", "desc2" ) 00250 ); 00251 // add it to the list of connectors. Please note, that a connector NOT added via addConnector will not work as expected. 00252 addConnector( m_output ); 00253 00254 // now, the same with the derived class as type 00255 m_inputDerived = boost::shared_ptr< WModuleInputData< WTestTransferableDerived > >( 00256 new WModuleInputData< WTestTransferableDerived > ( shared_from_this(), "in2", "desc1" ) 00257 ); 00258 // add it to the list of connectors. Please note, that a connector NOT added via addConnector will not work as expected. 00259 addConnector( m_inputDerived ); 00260 00261 m_outputDerived = boost::shared_ptr< WModuleOutputData< WTestTransferableDerived > >( 00262 new WModuleOutputData< WTestTransferableDerived > ( shared_from_this(), "out2", "desc2" ) 00263 ); 00264 // add it to the list of connectors. Please note, that a connector NOT added via addConnector will not work as expected. 00265 addConnector( m_outputDerived ); 00266 } 00267 00268 protected: 00269 00270 /** 00271 * temporary name string 00272 */ 00273 std::string n; 00274 00275 // required since pure virtual 00276 virtual void moduleMain() 00277 { 00278 // Since the modules run in a separate thread: such loops are possible 00279 while( !m_shutdownFlag() ) 00280 { 00281 // do fancy stuff 00282 sleep( 1 ); 00283 } 00284 } 00285 00286 /** 00287 * Notifier called whenever a connection got established. 00288 */ 00289 virtual void notifyConnectionEstablished( boost::shared_ptr< WModuleConnector > /*here*/, 00290 boost::shared_ptr< WModuleConnector > /*there*/ ) 00291 { 00292 // std::cout << "connection established between " << n << ":" << here->getCanonicalName() << " and " 00293 // << there->getCanonicalName() << std::endl; 00294 } 00295 00296 /** 00297 * Notifier called whenever a connection got closed. 00298 */ 00299 virtual void notifyConnectionClosed( boost::shared_ptr< WModuleConnector > /*here*/, 00300 boost::shared_ptr< WModuleConnector > /*there*/ ) 00301 { 00302 // std::cout << "connection closed between " << n << ":" << here->getCanonicalName() << " and " 00303 // << there->getCanonicalName() << std::endl; 00304 } 00305 00306 /** 00307 * Notifier called whenever a changed data was propagated to one of this modules connectors. 00308 * 00309 * param input the local connector receiving the event. 00310 * \param output the remote connector propagating the event. 00311 */ 00312 virtual void notifyDataChange( boost::shared_ptr< WModuleConnector > /*input */, 00313 boost::shared_ptr< WModuleConnector > output ) 00314 { 00315 // just copy the data and add one 00316 boost::shared_ptr< WModuleOutputData< WTestTransferableBase > > o = 00317 boost::shared_dynamic_cast< WModuleOutputData< WTestTransferableBase > >( output ); 00318 if( !o.get() ) 00319 { 00320 return; 00321 } 00322 00323 boost::shared_ptr< WTestTransferableBase > ds = o->getData(); 00324 if( ds.get() ) 00325 { 00326 data = ds->get() + 1; 00327 } 00328 00329 // std::cout << "change to " << data << " in " << input->getCanonicalName() << " from " << output->getCanonicalName() 00330 // << std::endl; 00331 } 00332 00333 private: 00334 00335 /** 00336 * The data lastly submitted. 00337 */ 00338 int data; 00339 00340 /** 00341 * Input connection. 00342 */ 00343 boost::shared_ptr< WModuleInputData< WTestTransferableBase > > m_input; 00344 00345 /** 00346 * Input connection with a derived class as transferable. 00347 */ 00348 boost::shared_ptr< WModuleInputData< WTestTransferableDerived > > m_inputDerived; 00349 00350 /** 00351 * Output connection. 00352 */ 00353 boost::shared_ptr< WModuleOutputData< WTestTransferableBase > > m_output; 00354 00355 /** 00356 * Output connection with a derived class as transferable 00357 */ 00358 boost::shared_ptr< WModuleOutputData< WTestTransferableDerived > > m_outputDerived; 00359 }; 00360 00361 /** 00362 * Tests the WModuleConnector class. We use WModuleConnector's direct derived classes WModuleInputConnector and 00363 * WModuleOutputConnector to test their common functionality implemented in WModuleConnector (which has pure virtual members -> so 00364 * can't be instantiated directly). 00365 */ 00366 class WModuleConnectorTest : public CxxTest::TestSuite 00367 { 00368 public: 00369 00370 /** 00371 * Setup logger and other stuff for each test. 00372 */ 00373 void setUp() 00374 { 00375 WLogger::startup(); 00376 } 00377 00378 /** 00379 * Simple module to test with. 00380 */ 00381 boost::shared_ptr< WModuleImpl > m1; 00382 00383 /** 00384 * Simple module to test with. 00385 */ 00386 boost::shared_ptr< WModuleImpl > m2; 00387 00388 /** 00389 * Simple module to test with. 00390 */ 00391 boost::shared_ptr< WModuleImpl > m3; 00392 00393 /** 00394 * Initialized the test modules. 00395 */ 00396 void createModules( void ) 00397 { 00398 // init 3 separate test modules 00399 m1 = boost::shared_ptr< WModuleImpl >( new WModuleImpl( "m1" ) ); 00400 m2 = boost::shared_ptr< WModuleImpl >( new WModuleImpl( "m2" ) ); 00401 m3 = boost::shared_ptr< WModuleImpl >( new WModuleImpl( "m3" ) ); 00402 } 00403 00404 /** 00405 * Initializes modules. This is normally done by the module container. 00406 */ 00407 void initModules( void ) 00408 { 00409 m1->initialize(); 00410 m2->initialize(); 00411 m3->initialize(); 00412 } 00413 00414 /** 00415 * Initialize some connections. 00416 */ 00417 void initConnections( void ) 00418 { 00419 // connect output with input (cyclic) 00420 m1->m_output->connect( m2->m_input ); 00421 m1->m_input->connect( m2->m_output ); 00422 } 00423 00424 /** 00425 * Test whether modules can be created without exception and proper initialization of connection lists. 00426 */ 00427 void testModuleCreation( void ) 00428 { 00429 TS_ASSERT_THROWS_NOTHING( createModules() ); 00430 00431 // check whether there are NO connectors. 00432 // The constructor should now create connectors since shared_ptr are needed -> init in constructor leads to exception 00433 // (it is enough to test one of them) 00434 TS_ASSERT( m1->m_inputConnectors.size() == 0 ); 00435 TS_ASSERT( m1->m_outputConnectors.size() == 0 ); 00436 } 00437 00438 /** 00439 * Test whether modules can be initialized without problems. 00440 */ 00441 void testModuleInitialization( void ) 00442 { 00443 createModules(); 00444 00445 TS_ASSERT_THROWS_NOTHING( initModules() ); 00446 00447 // now there should be 1 everywhere 00448 TS_ASSERT( m1->m_inputConnectors.size() == 2 ); 00449 TS_ASSERT( m1->m_outputConnectors.size() == 2 ); 00450 TS_ASSERT( m2->m_inputConnectors.size() == 2 ); 00451 TS_ASSERT( m2->m_outputConnectors.size() == 2 ); 00452 TS_ASSERT( m3->m_inputConnectors.size() == 2 ); 00453 TS_ASSERT( m3->m_outputConnectors.size() == 2 ); 00454 00455 // now we have 3 properly initialized modules? 00456 TS_ASSERT( m1->isInitialized()() ); 00457 TS_ASSERT( m2->isInitialized()() ); 00458 TS_ASSERT( m3->isInitialized()() ); 00459 } 00460 00461 /** 00462 * Test whether module initialization is robust against double init. 00463 */ 00464 void testModuleTwiceInitialization( void ) 00465 { 00466 WException::disableBacktrace(); 00467 00468 createModules(); 00469 initModules(); 00470 00471 // try initializing twice 00472 TS_ASSERT_THROWS( m1->initialize(), WModuleConnectorInitFailed ); 00473 TS_ASSERT( m1->isInitialized()() ); 00474 } 00475 00476 /** 00477 * Test whether automatic compatibility check works. 00478 */ 00479 void testModuleConnectorCompatibility( void ) 00480 { 00481 WException::disableBacktrace(); 00482 00483 createModules(); 00484 initModules(); 00485 00486 // connect input with input and output with output should fail 00487 TS_ASSERT_THROWS( m1->m_input->connect( m2->m_input ), WModuleConnectorsIncompatible ); 00488 TS_ASSERT_THROWS( m1->m_output->connect( m2->m_output ), WModuleConnectorsIncompatible ); 00489 00490 // there should be nothing connected. 00491 TS_ASSERT( m1->m_output->m_connected.size() == 0 ); 00492 TS_ASSERT( m1->m_input->m_connected.size() == 0 ); 00493 TS_ASSERT( m2->m_output->m_connected.size() == 0 ); 00494 TS_ASSERT( m2->m_input->m_connected.size() == 0 ); 00495 } 00496 00497 /** 00498 * Test whether automatic type compatibility check works. 00499 */ 00500 void testModuleConnectorTypeCompatibility( void ) 00501 { 00502 WException::disableBacktrace(); 00503 00504 createModules(); 00505 initModules(); 00506 00507 TS_ASSERT( m1->m_input->m_connected.size() == 0 ); 00508 TS_ASSERT( m1->m_output->m_connected.size() == 0 ); 00509 TS_ASSERT( m1->m_inputDerived->m_connected.size() == 0 ); 00510 TS_ASSERT( m1->m_outputDerived->m_connected.size() == 0 ); 00511 00512 // connect an input with base type to output of derived type 00513 TS_ASSERT_THROWS_NOTHING( m1->m_input->connect( m2->m_outputDerived ) ); 00514 TS_ASSERT( m1->m_input->m_connected.size() == 1 ); 00515 TS_ASSERT( m2->m_outputDerived->m_connected.size() == 1 ); 00516 00517 // connect an input of derived type with output of base type 00518 TS_ASSERT_THROWS( m1->m_output->connect( m2->m_inputDerived ), WModuleConnectorsIncompatible ); 00519 TS_ASSERT( m1->m_output->m_connected.size() == 0 ); 00520 TS_ASSERT( m1->m_inputDerived->m_connected.size() == 0 ); 00521 } 00522 00523 /** 00524 * Test whether connection works properly 00525 */ 00526 void testModuleConnection( void ) 00527 { 00528 createModules(); 00529 initModules(); 00530 00531 TS_ASSERT_THROWS_NOTHING( initConnections() ); 00532 00533 // check that every connector has a connection count of 1 00534 TS_ASSERT( m1->m_output->m_connected.size() == 1 ); 00535 TS_ASSERT( m1->m_input->m_connected.size() == 1 ); 00536 TS_ASSERT( m2->m_output->m_connected.size() == 1 ); 00537 TS_ASSERT( m2->m_input->m_connected.size() == 1 ); 00538 } 00539 00540 /** 00541 * Test whether connecting twice is not possible. 00542 */ 00543 void testModuleTwiceConnection( void ) 00544 { 00545 createModules(); 00546 initModules(); 00547 initConnections(); 00548 00549 // try to connect twice 00550 TS_ASSERT_THROWS_NOTHING( m1->m_output->connect( m2->m_input ) ); 00551 TS_ASSERT_THROWS_NOTHING( m1->m_input->connect( m2->m_output ) ); 00552 TS_ASSERT( m1->m_output->m_connected.size() == 1 ); 00553 TS_ASSERT( m1->m_input->m_connected.size() == 1 ); 00554 TS_ASSERT( m2->m_output->m_connected.size() == 1 ); 00555 TS_ASSERT( m2->m_input->m_connected.size() == 1 ); 00556 } 00557 00558 /** 00559 * Test whether the connection can properly be disconnected. 00560 */ 00561 void testModuleDisconnect( void ) 00562 { 00563 createModules(); 00564 initModules(); 00565 initConnections(); 00566 00567 // Disconnect something not connected 00568 TS_ASSERT_THROWS_NOTHING( m1->m_output->disconnect( m1->m_input ) ); 00569 TS_ASSERT( m1->m_output->m_connected.size() == 1 ); 00570 TS_ASSERT( m1->m_input->m_connected.size() == 1 ); 00571 00572 // Disconnect a connected 00573 TS_ASSERT_THROWS_NOTHING( m1->m_output->disconnect( m2->m_input ) ); 00574 TS_ASSERT( m1->m_output->m_connected.size() == 0 ); 00575 TS_ASSERT( m1->m_input->m_connected.size() == 1 ); 00576 TS_ASSERT( m2->m_output->m_connected.size() == 1 ); 00577 TS_ASSERT( m2->m_input->m_connected.size() == 0 ); 00578 } 00579 00580 /** 00581 * Test whether all connections can be removed in one step. 00582 */ 00583 void testModuleDisconnectAll( void ) 00584 { 00585 createModules(); 00586 initModules(); 00587 initConnections(); 00588 00589 // connect m3 00590 TS_ASSERT_THROWS_NOTHING( m3->m_input->connect( m2->m_output ) ); 00591 00592 // now m2->out should have 2 connections 00593 TS_ASSERT( m2->m_output->m_connected.size() == 2 ); 00594 TS_ASSERT( m3->m_input->m_connected.size() == 1 ); 00595 00596 // remove both connections 00597 m2->m_output->disconnectAll(); 00598 TS_ASSERT( m2->m_output->m_connected.size() == 0 ); 00599 TS_ASSERT( m1->m_input->m_connected.size() == 0 ); 00600 TS_ASSERT( m3->m_input->m_connected.size() == 0 ); 00601 } 00602 00603 /** 00604 * Test whether module clean up is working properly. 00605 */ 00606 void testModuleCleanup( void ) 00607 { 00608 createModules(); 00609 initModules(); 00610 initConnections(); 00611 00612 TS_ASSERT_THROWS_NOTHING( m1->cleanup() ); 00613 TS_ASSERT( m1->m_inputConnectors.size() == 0 ); 00614 TS_ASSERT( m1->m_outputConnectors.size() == 0 ); 00615 } 00616 00617 /** 00618 * Tests the propagation of data. 00619 */ 00620 void testModulePropagateDataChange( void ) 00621 { 00622 createModules(); 00623 initModules(); 00624 initConnections(); 00625 00626 // set some data, propagate change 00627 boost::shared_ptr< WTestTransferableBase > data = boost::shared_ptr< WTestTransferableBase >( new WTestTransferableBase() ); 00628 int d = 5; 00629 data->set( d ); 00630 TS_ASSERT_THROWS_NOTHING( m1->m_output->updateData( data ) ); 00631 00632 // got the data transferred? 00633 TS_ASSERT( m1->m_output->getData()->get() == d ); 00634 TS_ASSERT( m2->m_input->getData()->get() == d ); 00635 TS_ASSERT( m2->data == d + 1 ); 00636 } 00637 00638 /** 00639 * Tests several cases of unset data. 00640 */ 00641 void testModuleInvalidData( void ) 00642 { 00643 WException::disableBacktrace(); 00644 00645 createModules(); 00646 initModules(); 00647 initConnections(); 00648 00649 // try to get data from an unconnected connector 00650 TS_ASSERT( !m3->m_input->getData().get() ); 00651 00652 // try to get uninitialized data -> should return an "NULL" Pointer 00653 TS_ASSERT( m2->m_input->getData() == boost::shared_ptr< WTestTransferableBase >() ); 00654 } 00655 }; 00656 00657 #endif // WMODULECONNECTOR_TEST_H 00658