OpenWalnut  1.4.0
WConditionSet_test.h
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 WCONDITIONSET_TEST_H
00026 #define WCONDITIONSET_TEST_H
00027 
00028 #include <iostream>
00029 
00030 #include <boost/thread.hpp>
00031 #include <cxxtest/TestSuite.h>
00032 
00033 #include "../WConditionSet.h"
00034 #include "../WCondition.h"
00035 
00036 /**
00037  * Helper class.
00038  */
00039 class Callable
00040 {
00041 public:
00042     /**
00043      * Flag set to true when thread starts
00044      */
00045     bool flag;
00046 
00047     /**
00048      * The condition to be used for signalling.
00049      */
00050     WCondition* c;
00051 
00052     /**
00053      * Thread main method.
00054      */
00055     void threadMain()
00056     {
00057         flag = true;
00058 
00059         // let the test's thread reach its "wait" call first
00060         boost::this_thread::sleep( boost::posix_time::seconds( 1 ) );
00061         c->notify();
00062     };
00063 };
00064 
00065 /**
00066  * Test WConditionSet
00067  */
00068 class WConditionSetTest : public CxxTest::TestSuite
00069 {
00070 public:
00071     /**
00072      * An instantiation should never throw an exception, as well as tear down.
00073      */
00074     void testInstantiation( void )
00075     {
00076         WConditionSet* c = NULL;
00077 
00078         TS_ASSERT_THROWS_NOTHING( c = new WConditionSet() );
00079         TS_ASSERT_THROWS_NOTHING( delete c );
00080     }
00081 
00082     /**
00083      * Tests add and remove methods. Also check double remove/add.
00084      */
00085     void testAddRemove( void )
00086     {
00087         WConditionSet* cs = new WConditionSet();
00088 
00089         // create some conditions
00090         boost::shared_ptr< WCondition > c1( new WCondition() );
00091         boost::shared_ptr< WCondition > c2( new WCondition() );
00092         boost::shared_ptr< WCondition > c3( new WCondition() );
00093 
00094         // add them
00095         TS_ASSERT_THROWS_NOTHING( cs->add( c1 ) );
00096         // adding it a second time should not cause any exception
00097         TS_ASSERT_THROWS_NOTHING( cs->add( c1 ) );
00098         TS_ASSERT_THROWS_NOTHING( cs->add( c2 ) );
00099 
00100         // the size should now be 2
00101         TS_ASSERT( cs->m_conditionSet.size() == 2 );
00102 
00103         // try to remove a condition which is NOT inside the condition set
00104         TS_ASSERT_THROWS_NOTHING( cs->remove( c3 ) );
00105         TS_ASSERT( cs->m_conditionSet.size() == 2 );
00106 
00107         // remove a condition inside the set
00108         TS_ASSERT_THROWS_NOTHING( cs->remove( c1 ) );
00109         TS_ASSERT( cs->m_conditionSet.size() == 1 );
00110 
00111         // remove a condition inside the set
00112         TS_ASSERT_THROWS_NOTHING( cs->remove( c2 ) );
00113         TS_ASSERT( cs->m_conditionSet.size() == 0 );
00114 
00115         delete cs;
00116     }
00117 
00118     /**
00119      * Tests whether the condition set really reacts on fired conditions.
00120      */
00121     void testWait( void )
00122     {
00123         WConditionSet* cs = new WConditionSet();
00124 
00125         // create some conditions
00126         boost::shared_ptr< WCondition > c1( new WCondition() );
00127         boost::shared_ptr< WCondition > c2( new WCondition() );
00128 
00129         // disable resetable feature
00130         cs->setResetable( false, false );
00131         cs->add( c1 );
00132         cs->add( c2 );
00133 
00134         // create a thread which fires a condition in the set for us
00135         Callable t;
00136         t.flag = false;
00137         t.c = c1.get();
00138 
00139         // start a thread
00140         boost::thread thread = boost::thread( boost::bind( &Callable::threadMain, &t ) );
00141 
00142         // wait for condition
00143         cs->wait();
00144 
00145         // ugly but this is the only way to test it.
00146         TS_ASSERT( true );
00147 
00148         // reset it
00149         cs->reset();
00150         TS_ASSERT( !cs->m_fired );
00151 
00152         // ensure that a condition which has been removed does NOT fire the condition set
00153         cs->remove( c2 );
00154         c2->notify();
00155         TS_ASSERT( !cs->m_fired );
00156 
00157         // the other one should fire the set
00158         c1->notify();
00159         TS_ASSERT( cs->m_fired );
00160 
00161         delete cs;
00162     }
00163 
00164     /**
00165      * Tests the resetable feature.
00166      */
00167     void testWaitResetable( void )
00168     {
00169         WConditionSet* cs = new WConditionSet();
00170 
00171         // create some conditions
00172         boost::shared_ptr< WCondition > c1( new WCondition() );
00173         boost::shared_ptr< WCondition > c2( new WCondition() );
00174 
00175         // disable resetable feature
00176         cs->setResetable( true, true );
00177         cs->add( c1 );
00178         cs->add( c2 );
00179 
00180         // notify a condition
00181         c2->notify();
00182 
00183         // after the notification, m_fired should be true
00184         TS_ASSERT( cs->m_fired );
00185 
00186         // wait should return instantly
00187         cs->wait();     // how to test it? it just freezes the test if it does not work ;-) also some kind of error notification :-)
00188 
00189         // as the condition set has auto-reset enabled: m_fired should be false again
00190         TS_ASSERT( !cs->m_fired );
00191 
00192         // if resetable without auto-reset:
00193         cs->setResetable( true, false );
00194 
00195         // notify again
00196         c2->notify();
00197 
00198         // m_fired should be true
00199         TS_ASSERT( cs->m_fired );
00200 
00201         // wait should return instantly
00202         cs->wait();     // how to test it? it just freezes the test if it does not work ;-) also some kind of error notification :-)
00203 
00204         // m_fired should stay true
00205         TS_ASSERT( cs->m_fired );
00206 
00207         delete cs;
00208     }
00209 
00210     /**
00211      * Ensures reset() never throws something.
00212      */
00213     void testResetOnNotResetable( void )
00214     {
00215         WConditionSet* cs = new WConditionSet();
00216 
00217         cs->setResetable( false, false );
00218 
00219         // just ensure it does not throw something
00220         TS_ASSERT_THROWS_NOTHING( cs->reset() );
00221 
00222         delete cs;
00223     }
00224 };
00225 
00226 #endif  // WCONDITIONSET_TEST_H
00227