OpenWalnut  1.4.0
WFlag_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 WFLAG_TEST_H
00026 #define WFLAG_TEST_H
00027 
00028 #include <iostream>
00029 
00030 #include <boost/thread.hpp>
00031 #include <cxxtest/TestSuite.h>
00032 
00033 #include "../WFlag.h"
00034 #include "../WConditionOneShot.h"
00035 
00036 /**
00037  * Helper class.
00038  */
00039 class Callable
00040 {
00041 public:
00042     /**
00043      * The flag to be tested
00044      */
00045     WFlag<bool>* flag;
00046 
00047     /**
00048      * True if the thread finishes.
00049      */
00050     bool finished;
00051 
00052     /**
00053      * Constructor. To init the Flag.
00054      */
00055     Callable()
00056     {
00057         finished = false;
00058         flag = new WFlag< bool >( new WConditionOneShot(), false );
00059     }
00060 
00061     /**
00062      * Thread function.
00063      */
00064     void threadMain()
00065     {
00066         // just wait
00067         flag->wait();
00068         finished = true;
00069     };
00070 };
00071 
00072 /**
00073  * Test WFlag
00074  */
00075 class WFlagTest : public CxxTest::TestSuite
00076 {
00077 public:
00078     /**
00079      * A temporary holder for some value.
00080      */
00081     bool m_testTemporary;
00082 
00083     /**
00084      * Helper function which simply sets the value above to true. It is used to test some conditions here.
00085      */
00086     void setTemporary()
00087     {
00088         m_testTemporary = true;
00089     }
00090 
00091     /**
00092      * An instantiation should never throw an exception, as well as tear down.
00093      */
00094     void testInstantiation( void )
00095     {
00096         WFlag< bool >* flag = 0;
00097 
00098         TS_ASSERT_THROWS_NOTHING( flag = new WFlag< bool >( new WConditionOneShot(), false ) );
00099         TS_ASSERT_THROWS_NOTHING( delete flag );
00100     }
00101 
00102     /**
00103      * Test whether notification is working.
00104      */
00105     void testWaitNotify()
00106     {
00107         Callable t;
00108         // the flag should be false now
00109         // NOTE: the syntax to get the value of the flag looks ugly here, but you normally do not use pointers
00110         TS_ASSERT( !( *t.flag )() );
00111 
00112         // start a thread
00113         boost::thread thread = boost::thread( boost::bind( &Callable::threadMain, &t ) );
00114 
00115         // set value equal to the one already set
00116         ( *t.flag )( false );
00117         // this should NOT notify the thread since the set value is not different to the initial one
00118         TS_ASSERT( !t.finished );
00119 
00120         // notify
00121         ( *t.flag )( true );
00122         thread.join();
00123 
00124         TS_ASSERT( ( *t.flag )() );
00125     }
00126 
00127     /**
00128      * Test whether change condition is fired.
00129      */
00130     void testChangeCondition()
00131     {
00132         m_testTemporary = false;
00133 
00134         // create a condition
00135         WConditionOneShot* c = new WConditionOneShot();
00136         c->subscribeSignal( boost::bind( &WFlagTest::setTemporary, this ) );
00137 
00138         // use own condition here
00139         WFlag< bool >* flag = new WFlag< bool >( c, false );
00140 
00141         // change value
00142         flag->set( !flag->get( true ) );
00143 
00144         // condition fired?
00145         // Remember: the condition calls the above member function when fired
00146         TS_ASSERT( m_testTemporary );
00147 
00148         // setting with the suppression flag enabled should not fire the condition:
00149         m_testTemporary = false;
00150         // change value
00151         flag->set( !flag->get( true ), true );
00152         TS_ASSERT( !m_testTemporary );
00153 
00154         // setting without a change of value should also not call the condition
00155         flag->set( flag->get( true ) );
00156         TS_ASSERT( !m_testTemporary );
00157     }
00158 
00159     /**
00160      * Test whether change flag is set and reset.
00161      */
00162     void testChangeFlagAndReset()
00163     {
00164         // create a flag
00165         WFlag< bool >* flag = new WFlag< bool >( new WConditionOneShot(), false );
00166 
00167         // after creation, the change flag always is true
00168         TS_ASSERT( flag->changed() );
00169 
00170         // getting the value does not change the flag
00171         bool v = flag->get();
00172         TS_ASSERT( !v );
00173         TS_ASSERT( flag->changed() );
00174 
00175         // getting the value with the argument "true" should reset the change flag
00176         v = flag->get( true );
00177         TS_ASSERT( !flag->changed() );
00178 
00179         delete flag;
00180     }
00181 
00182     /**
00183      * Test whether copy construction/cloning is working.
00184      */
00185     void testCopyConstruction()
00186     {
00187         // create a flag
00188         WFlag< bool >* flag = new WFlag< bool >( new WConditionOneShot(), false );
00189 
00190         // clone
00191         WFlag< bool >* flagClone = new WFlag< bool >( *flag );
00192 
00193         // check that value, flag and so on are the same
00194         TS_ASSERT( flag->get() == flagClone->get() );
00195         TS_ASSERT( flag->changed() == flagClone->changed() );
00196 
00197         // the first should not influence the clone
00198         flag->get( true );
00199         TS_ASSERT( flag->changed() != flagClone->changed() );
00200         flagClone->set( !flagClone->get( true ) );
00201         TS_ASSERT( flag->get() != flagClone->get() );
00202 
00203         // the conditions need to be different
00204         // This is because the flag is another one and you won't expect to wake up if someone changes a Flag you do not know
00205         TS_ASSERT( flag->getCondition() != flagClone->getCondition() );
00206         TS_ASSERT( flag->getValueChangeCondition() != flagClone->getValueChangeCondition() );
00207     }
00208 };
00209 
00210 #endif  // WFLAG_TEST_H
00211 
00212