state_test.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002   tag: Peter Soetens  Mon Jan 10 15:59:51 CET 2005  state_test.cpp
00003 
00004                         state_test.cpp -  description
00005                            -------------------
00006     begin                : Mon January 10 2005
00007     copyright            : (C) 2005 Peter Soetens
00008     email                : peter.soetens@mech.kuleuven.ac.be
00009 
00010  ***************************************************************************
00011  *                                                                         *
00012  *   This program is free software; you can redistribute it and/or modify  *
00013  *   it under the terms of the GNU General Public License as published by  *
00014  *   the Free Software Foundation; either version 2 of the License, or     *
00015  *   (at your option) any later version.                                   *
00016  *                                                                         *
00017  ***************************************************************************/
00018 
00019 #include "unit.hpp"
00020 
00021 #include <rtt-config.h>
00022 #include <extras/SimulationThread.hpp>
00023 #include <extras/SimulationActivity.hpp>
00024 #include <scripting/StateMachine.hpp>
00025 #include <scripting/ParsedStateMachine.hpp>
00026 #include <scripting/DumpObject.hpp>
00027 #include <scripting/Parser.hpp>
00028 
00029 #include <Service.hpp>
00030 #include <TaskContext.hpp>
00031 #include <OperationCaller.hpp>
00032 #include <Port.hpp>
00033 #include <scripting/ScriptingService.hpp>
00034 #include "operations_fixture.hpp"
00035 
00036 #include <string>
00037 #include <iostream>
00038 #include <sstream>
00039 
00040 using namespace RTT;
00041 using namespace RTT::detail;
00042 using namespace std;
00043 
00044 class StateTest
00045     : public OperationsFixture
00046 {
00047 public:
00048     Parser parser;
00049     InputPort<double> d_event;
00050     InputPort<bool>   b_event;
00051     InputPort<int>    t_event;
00052     Operation<void(double)> o_event;
00053     OutputPort<double> d_event_source;
00054     OutputPort<bool>   b_event_source;
00055     OutputPort<int>    t_event_source;
00056     ScriptingService::shared_ptr sa;
00057 
00058     void log(const std::string& msg) {
00059         Logger::log(Logger::Info) << msg << endlog();
00060     }
00061     void doState(const std::string& name, const std::string& prog, TaskContext*, bool test=true );
00062     void parseState( const std::string& prog, TaskContext*, bool test=true );
00063     void runState(const std::string& name, TaskContext*, bool test=true );
00064     void checkState( const std::string& name, TaskContext*, bool test=true );
00065     void finishState( std::string const& name, TaskContext*, bool test=true );
00066 
00067     std::string sline;
00068 public:
00069     StateTest()
00070         :
00071          d_event("d_event"), b_event("b_event"), t_event("t_event"), o_event("o_event"),
00072          d_event_source("d_event_source"), b_event_source("b_event_source"), t_event_source("t_event_source")
00073          ,sa( ScriptingService::Create(tc) )
00074     {
00075         tc->stop();
00076         tc->setActivity( new SimulationActivity(0.001) );
00077 
00078         tc->ports()->addPort( d_event );
00079         tc->ports()->addPort( b_event );
00080         tc->ports()->addPort( t_event );
00081         tc->provides()->addOperation( o_event );
00082         tc->ports()->addPort( d_event_source );
00083         tc->ports()->addPort( b_event_source );
00084         tc->ports()->addPort( t_event_source );
00085 
00086         d_event_source.connectTo( &d_event );
00087         b_event_source.connectTo( &b_event );
00088         t_event_source.connectTo( &t_event );
00089         tc->start();
00090         i = 0;
00091         SimulationThread::Instance()->stop();
00092 
00093         tc->addOperation("log", &StateTest::log, this);
00094     }
00095     ~StateTest(){
00096     }
00097 };
00098 
00099 BOOST_FIXTURE_TEST_SUITE( StateTestSuite, StateTest )
00100 
00101 BOOST_AUTO_TEST_CASE( testParseState)
00102 {
00103     // a state which should never fail
00104     string prog = string("StateMachine X {\n")
00105         + " param int isten\n"
00106         + " param bool isflse\n"
00107         + " param bool isok\n"
00108         + " param double isnegative\n"
00109         + " var bool istrrue = true\n"
00110         + " var double d_dummy = -1.0\n"
00111         + " var int    i_dummy = -1\n"
00112         + " var bool   varinit = false\n"
00113         + " var bool   b_dummy = true\n" // 10
00114         + " initial state INIT {\n"
00115         // XXX bug : preconditions are not checked in the initial state.
00116 //         + " preconditions {\n"
00117 //         + "     if (istrrue == false) || (isflse == true) || (isten != 10) ||( isnegative >= 0. )  then select PRE_PARAMFAIL\n"
00118 //         + "     if false then select PRE_ERROR\n"
00119 //         + "     if (isnegative != -1.) then select PRE_PARAMFAIL\n"
00120 //         + "     if (istrrue != true) then select PRE_PARAMFAIL\n"
00121 //         + "     if (isflse != false) then select PRE_PARAMFAIL\n"
00122 //         + "     if (isten != 10 ) then select PRE_PARAMFAIL\n"
00123 //         + "     if (d_dummy != -1.) || (i_dummy != -1) then select PRE_VARFAIL\n"
00124 //         + " }\n"
00125         + " entry {\n"
00126         + "     set varinit = (d_dummy != -1.) || (i_dummy != -1) \n"
00127         + "     do test.good()\n"
00128         + "     set d_dummy = 1.234\n"
00129         + "     set i_dummy = -2\n"
00130         + "     do test.good()\n"
00131         + " }\n"
00132         + " handle {\n"
00133         + "     do test.good()\n" // 20
00134         + " }\n"
00135         + " exit {\n"
00136         + "     do test.good()\n"
00137         + "     set d_dummy = 0.0\n"
00138         + "     set i_dummy = 0\n"
00139         + " }\n"
00140         + " transitions {\n"
00141         + "     if false then select ERROR\n"
00142         + "     if varinit == true then select PRE_VARFAIL\n"
00143         + "     if (d_dummy != 1.234) || (i_dummy != -2)  then select ENTRYFAIL\n" // 30
00144         + " }\n"
00145         + " transition if (istrrue == false) || (isflse == true) || (isten != 10) ||( isnegative >= 0. )  then select PARAMFAIL\n"
00146         + " transition if isok == false then select PARAMFAIL\n"
00147         + " transition select FINI\n"
00148         + " transition select ERROR\n" // do not reach
00149         + " }\n"
00150         + " state PRE_ERROR { entry { do test.assert(false) }\n"
00151         + " }\n"
00152         + " state PRE_PARAMFAIL { entry { do test.assert(false) }\n"
00153         + " }\n"
00154         + " state PRE_VARFAIL { entry { do test.assert(false) }\n"
00155         + " }\n"
00156         + " state ERROR { entry { do test.assert(false) }\n"
00157         + " }\n"
00158         + " state PARAMFAIL {\n"
00159         + "      entry { \n"
00160         + "      do test.assertMsg( isten == 10, \"isten parameter not correctly initialised\")\n"
00161         + "      do test.assertMsg( istrrue == true, \"istrrue parameter not correctly initialised\")\n"
00162         + "      do test.assertMsg( isok == true, \"isok parameter not correctly initialised\")\n"
00163         + "      do test.assertMsg( isflse == false, \"isflse parameter not correctly initialised\")\n"
00164         + "      do test.assertMsg( true == true, \"true ident not correctly done\")\n"
00165         + "      do test.assertMsg( false == false, \"false ident not correctly done\")\n"
00166         + "      do test.assertMsg( isnegative == -1.0, \"isnegative parameter not correctly initialised\")\n"
00167         + "      }\n"
00168         + " }\n"
00169         + " state VARFAIL { entry { do test.assert(false) }\n"
00170         + " }\n"
00171         + " state EXITFAIL { entry { do test.assert(false) }\n"
00172         + " }\n"
00173         + " state ENTRYFAIL { entry { do test.assert(false) }\n"
00174         + " }\n"
00175         + " final state FINI {\n"
00176         + " preconditions {\n"
00177         + "     if (d_dummy != 0.) || (i_dummy != 0)  then select EXITFAIL\n"
00178         + "     if false then select ERROR\n"
00179         + " }\n"
00180         + " entry {\n"
00181         + "     do test.good()\n"
00182         + "     set d_dummy = -1.\n"
00183         + "     set i_dummy = -1\n"
00184         + " }\n"
00185         + " handle {\n"
00186         + "     do test.good()\n"
00187         + " }\n"
00188         + " exit {\n"
00189         + "     do test.good()\n"
00190         + " }\n"
00191         + " transitions {\n"
00192         + "     if false then select ERROR\n"
00193         + "     select INIT\n"
00194         + "     select ERROR\n" // do not reach
00195         + " }\n"
00196         + " }\n"
00197         + " }\n"
00198         //        + " RootMachine X x( isten = 10, isflse = false, isnegative = -1.0) \n" // instantiate a non hierarchical SC
00199         + " RootMachine X x( isten = 10, isok = true, isflse=false, isnegative = -1.0) \n" // instantiate a non hierarchical SC
00200         ;
00201 
00202     this->doState("x", prog, tc );
00203     this->finishState( "x", tc );
00204 }
00205 
00206 BOOST_AUTO_TEST_CASE( testStateFailure)
00207 {
00208     // test _command_ (through methods though) failure detection on several places.
00209     // it is an incomplete test, even more that parsing should fail on the second
00210     // run since the type 'X' is defined twice.
00211     string prog = string("StateMachine X {\n")
00212         + " initial state INIT {\n"
00213         + " entry {\n"
00214         + "     do test.increase()\n"                // set i to i+1
00215         + "     do test.assert( test.i != 1)\n" // fail if i == 1
00216         + " }\n"
00217         + " run {\n"
00218         + "     do test.assert( test.i != 2)\n"
00219         + " }\n"
00220         + " exit {\n"
00221         + "     do test.assert( test.i != 3)\n"
00222         + " }\n"
00223         + " transitions {\n"
00224         + "     if (true) then { do test.assert( test.i != 7); } select FINI\n"
00225         + " }\n"
00226         + " }\n"
00227         + " state ERROR {\n"
00228         + " }\n"
00229         + " final state FINI {\n"
00230         + " entry {\n"
00231         + "     do test.assert( test.i != 4)\n"
00232         + " }\n"
00233         + " run {\n"
00234         + "     do test.assert( test.i != 5)\n"
00235         + " }\n"
00236         + " exit {\n"
00237         + "     do test.assert( test.i != 6)\n"
00238         + " }\n"
00239         + " transitions {\n"
00240         + "     select ERROR\n"
00241         + " }\n"
00242         + " }\n"
00243         + " }\n"
00244         + " RootMachine X x\n" // instantiate a non hierarchical SC
00245         ;
00246 
00247     // should fail each time
00248     const int max = 7;
00249     int x = 0;
00250     while ( i < max && x < max) {
00251         this->doState("x", prog, tc, false );
00252         //cout << "i is: "<< i <<endl;
00253         // assert that an error happened :
00254         BOOST_CHECK_MESSAGE( sa->getStateMachineStatus("x") == StateMachine::Status::error, "Status is: " + sa->getStateMachineStatusStr("x") );
00255 
00256         this->finishState( "x", tc, false);
00257         ++x;
00258     }
00259 }
00260 BOOST_AUTO_TEST_CASE( testStateChildren)
00261 {
00262     // instantiate two children and check init of vars and params
00263     string prog = string("StateMachine Y {\n")
00264         + " param double isnegative\n"
00265         + " var   double t = 1.0\n"
00266         + " initial state INIT {\n"
00267         + " entry {\n"
00268         + "     do test.good()\n"
00269         + " }\n"
00270         + " transitions {\n"
00271         + "     if isnegative >= 0. then select PARAMFAIL\n"
00272         + "     select FINI\n"
00273         + " }\n"
00274         + " }\n"
00275         + " state ERROR { entry { do test.assert(false) }\n"
00276         + " }\n"
00277         + " state PARAMFAIL { entry { do test.assert(false) }\n"
00278         + " }\n"
00279         + " state VARFAIL { entry { do test.assert(false) }\n"
00280         + " }\n"
00281         + " state EXITFAIL { entry { do test.assert(false) }\n"
00282         + " }\n"
00283         + " state ENTRYFAIL { entry { do test.assert(false) }\n"
00284         + " }\n"
00285         + " final state FINI {\n"
00286         + " entry {\n"
00287         + "     do test.good()\n"
00288         + " }\n"
00289         + " transitions {\n"
00290         + "     select INIT\n"
00291         + " }\n"
00292         + " }\n"
00293         + " }\n"
00294         + string("StateMachine Z {\n")
00295         + " param double neg\n"
00296         + " initial state INIT {\n"
00297         + " transitions {\n"
00298         + "     if neg >= 0. then select PARAMFAIL\n"
00299         + "     select FINI\n"
00300         + " }\n"
00301         + " }\n"
00302         + " state PARAMFAIL { entry { do test.assert(false) }\n"
00303         + " }\n"
00304         + " final state FINI {\n"
00305         + " transitions {\n"
00306         + "     select INIT\n"
00307         + " }\n"
00308         + " }\n"
00309         + " }\n"
00310         + string("StateMachine X {\n")
00311         + " param double isnegative\n"
00312         + " var double d_dummy = -2.0\n"
00313         + " var int    i_dummy = -1\n"
00314         + " SubMachine Y y1(isnegative = d_dummy)\n"
00315         + " SubMachine Y y2(isnegative = -3.0)\n"
00316         + " SubMachine Y y3(isnegative = isnegative)\n"
00317         + " SubMachine Z z1( neg = d_dummy)\n"
00318         + " initial state INIT {\n"
00319         + " entry {\n"
00320         + "     do test.good()\n"
00321         + "     do y1.activate()\n"
00322         + "     do y2.activate()\n"
00323         + "     do y3.activate()\n"
00324         + "     do z1.activate()\n"
00325         + " }\n"
00326         + " exit {\n"
00327         + "     do y1.start()\n"
00328         + "     do y2.start()\n"
00329         + "     do y3.start()\n"
00330         + "     do z1.start()\n"
00331         + " }\n"
00332         + " transitions {\n"
00333         + "     select FINI\n"
00334         + " }\n"
00335         + " }\n"
00336         + " state ERROR { entry { do test.assert(false) }\n"
00337         + " }\n"
00338         + " state PARAMFAIL {\n"
00339         + "      entry { \n"
00340         + "      do test.assertMsg( y3.isnegative == isnegative, \"y3 parameter not correctly initialised\")\n"
00341         + "      do test.assertMsg( y2.isnegative == -3.0, \"y2 parameter not correctly initialised\")\n"
00342         + "      do test.assertMsg( y1.isnegative == d_dummy, \"y1 parameter not correctly initialised\")\n"
00343         + "      do test.assertMsg( z1.neg == d_dummy, \"z1 parameter not correctly initialised\")\n"
00344         + "      }\n"
00345         + " }\n"
00346         + " state VARFAIL { entry { do test.assert(false) }\n"
00347         + " }\n"
00348         + " state EXITFAIL { entry { do test.assert(false) }\n"
00349         + " }\n"
00350         + " state ENTRYFAIL { entry { do test.assert(false) }\n"
00351         + " }\n"
00352         + " final state FINI {\n"
00353         + " entry {\n"
00354         + "     do test.good()\n"
00355         + "     do y1.stop()\n"
00356         + "     do y2.stop()\n"
00357         + "     do y3.stop()\n"
00358         + "     do z1.stop()\n"
00359         + " }\n"
00360         + " exit {\n"
00361         + "     do test.good()\n"
00362         + "     do y1.deactivate()\n"
00363         + "     do y2.deactivate()\n"
00364         + "     do y3.deactivate()\n"
00365         + "     do z1.deactivate()\n"
00366         + " }\n"
00367         + " transitions {\n"
00368         + "     if z1.neg != d_dummy then select PARAMFAIL\n"
00369         + "     if y1.isnegative != d_dummy then select PARAMFAIL\n"
00370         + "     if y2.isnegative != -3.0 then select PARAMFAIL\n"
00371         + "     if y3.isnegative != isnegative then select PARAMFAIL\n"
00372         + "     select INIT\n"
00373         + " }\n"
00374         + " }\n"
00375         + " }\n"
00376         + " RootMachine X x( isnegative = -1.0) \n" // instantiate a hierarchical SC
00377         ;
00378 
00379     this->doState("x", prog, tc );
00380     this->finishState( "x", tc);
00381 }
00382 
00383 BOOST_AUTO_TEST_CASE( testStateEmpty)
00384 {
00385     // test processing of completely empty states
00386     string prog = string("StateMachine X {\n")
00387         + " initial state INIT {\n"
00388         + " transitions {\n"
00389         + "     select TEST;\n" // only a transition
00390         + " }\n"
00391         + " }\n"
00392         + " state TEST {\n"  // not even used
00393         + " }\n"
00394         + " final state FINI {\n" // completely empty
00395         + " }\n"
00396         + " }\n"
00397         + " RootMachine X x\n" // instantiate a non hierarchical SC
00398         ;
00399      this->doState("x", prog, tc );
00400      this->finishState( "x", tc);
00401 }
00402 
00403 BOOST_AUTO_TEST_CASE( testStateEmptyChild)
00404 {
00405     // test processing of completely empty states
00406     string prog = string("StateMachine Y {\n")
00407         + " initial state INIT {\n"
00408         + " }\n"
00409         + " final state FINI {\n"
00410         + " }\n"
00411         + "}\n"
00412         + "StateMachine X {\n"
00413         + "  SubMachine Y y;\n"
00414         + " initial state INIT {\n"
00415         + " }\n"
00416         + " final state FINI {\n"
00417         + " }\n"
00418         + "}\n"
00419         + "RootMachine X x\n"
00420         ;
00421 
00422     this->doState("x", prog, tc );
00423     this->finishState( "x", tc);
00424 }
00425 
00426 BOOST_AUTO_TEST_CASE( testStateTransitions)
00427 {
00428     // test processing of transition statements.
00429     string prog = string("StateMachine X {\n")
00430         + " initial state INIT {\n"
00431         + " var int i = 0;\n" // transition counter
00432         + " var int j = 0;\n" // entry counter
00433         + " var int k = 0;\n" // run counter
00434         + " entry {\n"
00435         + "   set j = j + 1\n"
00436         + " }\n"
00437         + " run {\n"
00438         + "   set k = k + 1\n"
00439         + " }\n"
00440         + " transitions {\n"
00441         + "  if i < 5 then {\n"
00442         + "    set i = i + 1;\n" // execute this program
00443         + "  } select INIT\n" // test EXPLICIT transition to self: no entry/exit.
00444         + "  if i < 10 then {\n"
00445         + "    set i = i + 1;\n" // execute this program
00446         + "  }\n" // test IMPLICIT transition to self: no entry/exit.
00447         + "  if i < 10 then {\n"
00448         + "  } select TRANS_SHOULD_NOT_CHECK\n" // should never be reached.
00449         + "  if i == 10 then {\n"
00450         + "    set i = i + 1;\n" // execute this program
00451         + "  } select TEST_ENTRY\n"
00452         + " }\n"
00453         + " }\n"
00454         + " state TEST_ENTRY {\n" // test if entry was executed one time
00455         + " transitions {\n"
00456         + "  if k != i then {\n"
00457         + "  } select RUN_FAILED\n"
00458         + "  if j != 1 then {\n"
00459         + "  } select ENTRY_FAILED\n"
00460         + "  else select FINI\n"
00461         + " }\n"
00462         + " }\n"
00463         + " state TRANS_SHOULD_NOT_CHECK {\n" // failure state
00464         + " entry { do test.assert(false); }\n"
00465         + " }\n"
00466         + " state ENTRY_FAILED {\n"           // failure state
00467         + " entry { do test.assert(false); }\n"
00468         + " }\n"
00469         + " state RUN_FAILED {\n"           // failure state
00470         + " entry { do test.assert(false); }\n"
00471         + " }\n"
00472         + " final state FINI {\n" // Success state.
00473         + " }\n"
00474         + " }\n"
00475         + " RootMachine X x\n" // instantiate a non hierarchical SC
00476         ;
00477      this->doState("x", prog, tc );
00478      BOOST_CHECK( sa->getStateMachine( "x" )->inState("FINI") );
00479      this->finishState( "x", tc);
00480 }
00481 
00482 BOOST_AUTO_TEST_CASE( testStateTransitionStop )
00483 {
00484     // test processing of transition statements.
00485     string prog = string("StateMachine X {\n")
00486         + " initial state INIT {\n"
00487         + " transitions {\n"
00488         + "  if stop() == true then select NEXT\n" // calls stop on the component !
00489         + " }\n"
00490         + " }\n"
00491         + " state NEXT {\n" // Success state.
00492         + " entry { do test.assert(true); }\n"
00493         + " }\n"
00494         + " final state FINI {\n" // Failure state.
00495         + " entry { do test.assert(true); }\n"
00496         + " }\n"
00497         + " }\n"
00498         + " RootMachine X x\n" // instantiate a non hierarchical SC
00499         ;
00500      this->doState("x", prog, tc );
00501      BOOST_CHECK( sa->getStateMachine( "x" )->inState("NEXT") );
00502      this->finishState( "x", tc);
00503 }
00504 
00505 BOOST_AUTO_TEST_CASE( testStateGlobalTransitions)
00506 {
00507     // test processing of transition statements.
00508     string prog = string("StateMachine X {\n")
00509         + " var int gi = 0;\n" // transition counter
00510         + " transitions {\n"
00511 
00512         + "  if gi < 5 then {\n"
00513         + "    set gi = gi + 1;\n" // execute this program
00514         + "  } select INIT\n" // test EXPLICIT transition to self: no entry/exit.
00515 
00516         + "  if gi < 10 then {\n"
00517         + "    if gi < 5 then do test.assert(false);\n"
00518         + "    set gi = gi + 1;\n" // execute this program
00519         + "  }\n" // test IMPLICIT transition to self: no entry/exit.
00520         + "  if gi < 10 then {\n"
00521         + "   do test.assert(false);\n"
00522         + "  } select TRANS_SHOULD_NOT_CHECK\n" // should never be reached.
00523         + "  if gi >= 10 then {\n"
00524         + "  } select FINI\n" // we must be checked before
00525         + " }\n"
00526         + " initial state INIT {\n"
00527         + " var int i = 0;\n" // transition counter
00528         + " var int j = 0;\n" // entry counter
00529         + " var int k = 0;\n" // run counter
00530         + " entry {\n"
00531         + "   set j = j + 1\n"
00532         + " }\n"
00533         + " run {\n"
00534         + "   set k = k + 1\n"
00535         + " }\n"
00536         + " transitions {\n"
00537         + "  if i < 5 then {\n"
00538         + "    set i = i + 1;\n" // execute this program
00539         + "  } select INIT\n" // test EXPLICIT transition to self: no entry/exit.
00540         + "  if i < 10 then {\n"
00541         + "    set i = i + 1;\n" // execute this program
00542         + "  }\n" // test IMPLICIT transition to self: no entry/exit.
00543         + "  if i < 10 then {\n"
00544         + "  } select TRANS_SHOULD_NOT_CHECK\n" // should never be reached.
00545         + " }\n"
00546         + " }\n"
00547         + " state TRANS_SHOULD_NOT_CHECK {\n" // failure state
00548         + " entry { do test.assert(false); }\n"
00549         + " }\n"
00550         + " state ENTRY_FAILED {\n"           // failure state
00551         + " entry { do test.assert(false); }\n"
00552         + " }\n"
00553         + " state RUN_FAILED {\n"           // failure state
00554         + " entry { do test.assert(false); }\n"
00555         + " }\n"
00556         + " final state FINI {\n" // Success state.
00557         + " }\n"
00558         + " }\n"
00559         + " RootMachine X x\n" // instantiate a non hierarchical SC
00560         ;
00561      this->doState("x", prog, tc );
00562      BOOST_CHECK( sa->getStateMachine( "x" )->inState("FINI") );
00563      this->finishState( "x", tc);
00564 }
00565 
00566 
00567 BOOST_AUTO_TEST_CASE( testStateSubStateVars)
00568 {
00569     // test get/set access of substate variables and parameters
00570     string prog = string("StateMachine Y {\n")
00571         + " param double isnegative\n"
00572         + " var   double t = 1.0\n"
00573         + " initial state INIT {\n"
00574         + " transitions {\n"
00575         + "     if isnegative >= 0. then select PARAMFAIL\n"
00576         + "     if t >= 0. then select VARFAIL\n"
00577         + "     select FINI\n"
00578         + " }\n"
00579         + " exit { set isnegative = +1.0 }\n"
00580         + " }\n" // 11
00581         + " state ERROR { entry { do test.assert(false) }\n"
00582         + " }\n"
00583         + " state PARAMFAIL { entry { do test.assert(false) }\n"
00584         + " }\n"
00585         + " state VARFAIL { entry { do test.assert(false) }\n"
00586         + " }\n"
00587         + " state EXITFAIL { entry { do test.assert(false) }\n"
00588         + " }\n"
00589         + " state ENTRYFAIL { entry { do test.assert(false) }\n"
00590         + " }\n" // 21
00591         + " final state FINI {\n"
00592         + " transitions {\n"
00593         + "     if isnegative <= 0. then select PARAMFAIL\n"
00594         + " }\n"
00595         + " }\n"
00596         + " }\n"
00597         + string("StateMachine X {\n")
00598         + " param double isnegative\n"
00599         + " var double d_dummy = -2.0\n"
00600         + " var int    i_dummy = -1\n" //31
00601         + " SubMachine Y y1(isnegative = d_dummy)\n"
00602         + " initial state INIT {\n"
00603         + " entry {\n"
00604         + "     do y1.activate()\n"
00605         + "     set y1.t = -1.0 \n"
00606         + " }\n"
00607         + " exit {\n"
00608         + "     do y1.start()\n"
00609         + " }\n"
00610         + " transitions {\n"
00611         + "     select TEST\n"
00612         + " }\n"
00613         + " }\n"
00614         + " state TEST {\n"
00615         + " entry {\n"
00616         + "     do yield\n"
00617         + "     do test.assert( y1.inState(\"FINI\") )\n" // if y1 not in FINI, stop here.
00618         + " }\n"
00619         + " transitions {\n"
00620         + "     select FINI\n"
00621         + " }\n"
00622         + " }\n"
00623         + " final state FINI {\n"
00624         + " entry {\n"
00625         + "     do y1.stop()\n" // prepare y1 to start-over
00626         + " }\n"
00627         + " exit {\n"
00628         + "     set y1.isnegative = -1.0 \n"
00629         + "     do y1.deactivate()\n"
00630         + " }\n"
00631         + " transitions {\n"
00632         + "     select INIT\n" // start-over y1.
00633         + " }\n"
00634         + " }\n"
00635         + " }\n"
00636         + " RootMachine X x( isnegative = -1.0) \n" // instantiate a hierarchical SC
00637         ;
00638 
00639      this->doState("x", prog, tc );
00640      this->finishState( "x", tc);
00641 }
00642 
00643 BOOST_AUTO_TEST_CASE( testStateSubStateCommands)
00644 {
00645     // test get/set access of substate variables and parameters
00646     string prog = string("StateMachine Y {\n")
00647         + " param double isnegative\n"
00648         + " var   double t = 1.0\n"
00649         + " initial state INIT {\n"
00650         + " transitions {\n"
00651         + "     if isnegative < 0. then select ISNEGATIVE\n"
00652         + "     if t >= 0. then select ISPOSITIVE\n"
00653         + "     select DEFAULT\n"
00654         + " }\n"
00655         + " }\n"
00656         + " state ISNEGATIVE {\n"
00657         + " transitions {\n"
00658         + "      select INIT\n"
00659         + " }\n"
00660         + " }\n"
00661         + " state ISPOSITIVE {\n"
00662         + " transitions {\n"
00663         + "      select INIT\n"
00664         + " }\n"
00665         // 20 :
00666         + " }\n"
00667         + " state DEFAULT {\n"
00668         + " transitions {\n"
00669         + "      select FINI\n"
00670         + " }\n"
00671         + " }\n"
00672         + " final state FINI {\n"
00673         + " }\n"
00674         + " }\n"
00675         + string("StateMachine X {\n") // 1
00676         + " SubMachine Y y1(isnegative = -1.0)\n"
00677         + " initial state INIT {\n"
00678         + " entry {\n"
00679         + "     set y1.t = -1.0 \n"
00680         + "     do y1.activate()\n"
00681         + "     do y1.requestState(\"ISNEGATIVE\")\n"
00682         + "     do test.assert( y1.inState(\"ISNEGATIVE\") )\n"
00683         + "     do y1.requestState(\"INIT\")\n"
00684         + "     do test.assert( y1.inState(\"INIT\") )\n"
00685         + "     set y1.isnegative = +1.0 \n"
00686         + "     try y1.requestState(\"ISNEGATIVE\") \n "
00687         + "     catch \n{\n"
00688         + "         do test.assert( y1.inState(\"INIT\") )\n" // do not leave INIT
00689         + "     }\n"
00690         + "     do test.assert( y1.inState(\"INIT\") )\n" // do not leave INIT
00691         + "     do y1.requestState(\"FINI\")\n"      // request final state
00692         + "     do test.assert( y1.inState(\"FINI\") )\n"
00693         + " }\n"
00694         + " exit {\n"
00695         + "     do y1.requestState(\"INIT\")\n"      // request initial state
00696         + "     do test.assert( y1.inState(\"INIT\") )\n"
00697         + "     set y1.isnegative = +1.0 \n"
00698         + "     set y1.t = -1.0 \n"
00699         + "     do y1.start()\n"  // must reach FINI after a while.
00700         + "     while ! y1.inState(\"FINI\") \n"
00701         + "        do nothing\n"
00702         + " }\n"
00703         + " transitions {\n"
00704         + "     select FINI\n"
00705         + " }\n"
00706         + " }\n"
00707         + " final state FINI {\n"
00708         + " entry {\n"
00709         + "     do y1.stop()\n"
00710         + " }\n"
00711         + " exit {\n"
00712         + "     do y1.deactivate()\n"
00713         + " }\n"
00714         + " transitions {\n"
00715         + "     select INIT\n"
00716         + " }\n"
00717         + " }\n"
00718         + " }\n"
00719         + " RootMachine X x() \n" // instantiate a hierarchical SC
00720         ;
00721 
00722      this->doState("x", prog, tc );
00723      this->finishState( "x", tc);
00724 }
00725 
00726 #ifdef ORO_SIGNALLING_OPERATIONS
00727 BOOST_AUTO_TEST_CASE( testStateOperationSignalTransition )
00728 {
00729     // test event reception in sub states.
00730     string prog = string("StateMachine X {\n")
00731         + " var   double et = 0.0\n"
00732         + " initial state INIT {\n"
00733         + "    transition o_event(et) select FINI\n" // test signal transition
00734         + " }\n"
00735         + " final state FINI {} \n"
00736         + "}\n"
00737         + "RootMachine X x()\n";
00738     this->parseState( prog, tc );
00739     StateMachinePtr sm = sa->getStateMachine("x");
00740     BOOST_REQUIRE( sm );
00741     this->runState("x", tc);
00742     checkState( "x", tc);
00743     OperationCaller<void(double)> mo( tc->provides()->getOperation("o_event"), tc->engine());
00744     mo(3.33);
00745     checkState( "x", tc);
00746     BOOST_CHECK( SimulationThread::Instance()->run(100) );
00747     checkState( "x", tc);
00748     BOOST_CHECK( sm->inState("FINI") );
00749     this->checkState("x",tc);
00750     this->finishState("x", tc);
00751 }
00752 
00753 BOOST_AUTO_TEST_CASE( testStateOperationSignalTransitionProgram )
00754 {
00755     string prog = string("StateMachine X {\n")
00756         + " var   double et = 0.0\n"
00757         + " initial state INIT {\n"
00758         + "    transition o_event(et) { test.i = 5; } select FINI\n" // test program
00759         + " }\n"
00760         + " final state FINI {} \n"
00761         + "}\n"
00762         + "RootMachine X x()\n";
00763     this->parseState( prog, tc );
00764     StateMachinePtr sm = sa->getStateMachine("x");
00765     BOOST_REQUIRE( sm );
00766     //checkState( prog, tc);
00767     this->runState("x", tc);
00768     checkState( "x", tc);
00769     // causes error state when received in INIT:
00770     OperationCaller<void(double)> mo( tc->provides()->getOperation("o_event"), tc->engine());
00771     mo(3.33);
00772     checkState( "x", tc);
00773     BOOST_CHECK( SimulationThread::Instance()->run(1000) );
00774     BOOST_CHECK_EQUAL( i, 5 );
00775     checkState( "x", tc);
00776     BOOST_CHECK( sm->inState("FINI") );
00777     this->checkState("x",tc);
00778     this->finishState("x", tc);
00779 }
00780 
00781 BOOST_AUTO_TEST_CASE( testStateOperationSignalGuard )
00782 {
00783     string prog = string("StateMachine X {\n")
00784         + " var   double et = 0.0\n"
00785         + " initial state INIT {\n"
00786         + "    transition o_event(et) if (et == 3.33) then select FINI\n" // test guard
00787         + " }\n"
00788         + " final state FINI {} \n"
00789         + "}\n"
00790         + "RootMachine X x()\n";
00791     this->parseState( prog, tc );
00792     StateMachinePtr sm = sa->getStateMachine("x");
00793     BOOST_REQUIRE( sm );
00794     //checkState( prog, tc);
00795     this->runState("x", tc);
00796     checkState( "x", tc);
00797     // causes error state when received in INIT:
00798     OperationCaller<void(double)> mo( tc->provides()->getOperation("o_event"), tc->engine());
00799     mo(3.33);
00800     checkState( "x", tc);
00801     BOOST_CHECK( SimulationThread::Instance()->run(1000) );
00802     checkState( "x", tc);
00803     BOOST_CHECK( sm->inState("FINI") );
00804     this->checkState("x",tc);
00805     this->finishState("x", tc);
00806 }
00807 #endif
00808 
00809 BOOST_AUTO_TEST_CASE( testStateEvents)
00810 {
00811     // test event reception in sub states.
00812     string prog = string("StateMachine Y {\n")
00813         + " var   int t = 0\n"
00814         + " var   double et = 0.0\n"
00815         + " var   bool eb = false\n"
00816         + " var   bool eflag = false\n"
00817         + " transition t_event(t) { do log(\"Global Transition to TESTSELF\");} select TESTSELF\n" // test self transition
00818         + " transition d_event(et)\n"
00819         + "     if et < 0. then { do log(\"Global ISNEGATIVE Transition\");} select ISNEGATIVE\n"
00820         + "     else { do log(\"Global ISPOSITIVE Transition\");} select ISPOSITIVE\n" // NewData == false !!!
00821         + " initial state INIT {\n"
00822         + "   entry { do log(\"INIT\"); set eb = false; }\n"
00823         + " }\n"
00824         + " state ISNEGATIVE {\n"
00825         + "   entry { do log(\"ISNEGATIVE\");}\n"
00826         + "   transition b_event(eb)\n"
00827         + "      if (eb) then { do log(\"Local ISNEGATIVE->INIT Transition\");} select INIT\n"
00828         + " }\n"
00829         + " state ISPOSITIVE {\n"
00830         + "   entry { do log(\"ISPOSITIVE\");}\n"
00831         + "   transition b_event(eb)\n"
00832         + "      if (eb == true) then { do log(\"Local ISPOSITIVE->INIT Transition for b_event\");} select INIT\n" // 20
00833 #ifdef ORO_SIGNALLING_OPERATIONS
00834         + "   transition o_event(et)\n"
00835         + "      if ( et == 3.0 ) then { do log(\"Local ISPOSITIVE->INIT Transition for o_event\");} select INIT\n"
00836 #endif
00837         + " }\n"
00838         + " state TESTSELF {\n"
00839         + "   entry {\n"
00840         + "      do log(\"TESTSELF\");\n"
00841         + "      set eflag = !eflag\n"
00842         + "   }\n"
00843         + "   transition t_event(t) { do log(\"Self Transition in TESTSELF\");} select TESTSELF\n"     // does not execute entry {}, overrides global t_event()
00844         + "   transition b_event(eb)\n"
00845         + "      if (eb == true) then { do log(\"Local TESTSELF->INIT Transition\");} select INIT\n"
00846         + "      else { log(\"Failed to select INIT upon event.\");}\n"
00847         + " }\n"
00848         + " final state FINI {\n"
00849         + "   entry { do log(\"FINI\");}\n"
00850         + " }\n"
00851         + " }\n" // 40
00852         + string("StateMachine X {\n") // 1
00853         + " SubMachine Y y1()\n"
00854         + " initial state INIT {\n"
00855         + " entry {\n"
00856         + "     do y1.trace(true)\n"
00857         + "     do y1.activate()\n"
00858         + "     do y1.start()\n"
00859         + "     do yield\n"
00860         + " }"
00861         + " run {\n"
00862 
00863         + "     do d_event_source.write(-1.0)\n"
00864         + "     do nothing\n"
00865         + "     do test.assert( !y1.inState(\"INIT\") )\n"
00866         + "     do test.assert( !y1.inState(\"ISPOSITIVE\") )\n"
00867         + "     do test.assert( y1.inState(\"ISNEGATIVE\") )\n"
00868         + "     do b_event_source.write( true )\n" // go to INIT.
00869         + "     do yield\n"
00870         + "     do test.assert( y1.inState(\"INIT\") )\n"
00871 
00872         + "     do d_event_source.write(+1.0)\n"
00873         + "     do nothing\n"
00874         + "     do test.assert( !y1.inState(\"INIT\") )\n"
00875         + "     do test.assert( y1.inState(\"ISPOSITIVE\") )\n"
00876         + "     do test.assert( !y1.inState(\"ISNEGATIVE\") )\n"
00877         + "     if ( !y1.inState(\"ISPOSITIVE\") ) then\n"
00878         + "          do test.assertMsg( false, \"Not ISNEGATIVE but \" + y1.getState() )\n"
00879         + "     do test.assert( y1.inState(\"ISPOSITIVE\") )\n"
00880         + "     do b_event_source.write( true )\n" // go to INIT.
00881         + "     do yield\n"
00882         + "     do test.assert( y1.inState(\"INIT\") )\n"
00883 #ifdef ORO_SIGNALLING_OPERATIONS
00884         // test operation
00885         + "     do d_event_source.write(+1.0)\n"
00886         + "     do nothing\n"
00887         + "     do test.assert( !y1.inState(\"INIT\") )\n"
00888         + "     do test.assert( y1.inState(\"ISPOSITIVE\") )\n"
00889         + "     do test.assert( !y1.inState(\"ISNEGATIVE\") )\n"
00890         + "     if ( !y1.inState(\"ISPOSITIVE\") ) then\n"
00891         + "          do test.assertMsg( false, \"Not ISNEGATIVE but \" + y1.getState() )\n"
00892         + "     do test.assert( y1.inState(\"ISPOSITIVE\") )\n"
00893         + "     do o_event( 3.0 )\n" // go to INIT.
00894         + "     do yield\n"
00895         + "     do test.assert( y1.inState(\"INIT\") )\n"
00896 #endif
00897         // test self transitions
00898         + "     set y1.eflag = true;\n"
00899         + "     do t_event_source.write(1)\n"
00900         + "     do nothing\n"
00901         + "     do test.assert( !y1.inState(\"INIT\") )\n"
00902         + "     do test.assert( !y1.inState(\"ISPOSITIVE\") )\n"
00903         + "     do test.assert( !y1.inState(\"ISNEGATIVE\") )\n"
00904         + "     do test.assert( y1.inState(\"TESTSELF\") )\n"
00905         + "     do test.assert( y1.eflag == false ) /* first */\n"
00906         + "     do t_event_source.write(1)\n"
00907         + "     do nothing\n"
00908         + "     do test.assert( y1.inState(\"TESTSELF\") )\n"
00909         + "     do test.assert( y1.eflag == false ) /* second */\n" // no entry
00910         + "     do log(\"Trigger b_event.\");\n"
00911         + "     do b_event_source.write(true);\n"
00912         + "     yield;\n"
00913         + "     do test.assert( y1.inState(\"INIT\") ) /* last */\n"
00914         + " }\n"
00915         + " transitions {\n"
00916         + "     select FINI\n"
00917         + " }\n"
00918         + " }\n"
00919         + " final state FINI {\n"
00920         + " entry {\n"
00921         + "     do y1.deactivate()\n"
00922         //+ "     do test.assert(false)\n"
00923         + " }\n"
00924         + " transitions {\n"
00925         + "     select INIT\n"
00926         + " }\n"
00927         + " }\n"
00928         + " }\n"
00929         + " RootMachine X x() \n" // instantiate a hierarchical SC
00930         ;
00931 
00932      this->doState("x", prog, tc );
00933      //BOOST_CHECK( tc->engine()->states()->getStateMachine( "x" )->inState("FINI") );
00934      this->finishState( "x", tc);
00935 }
00936 
00937 BOOST_AUTO_TEST_SUITE_END()
00938 
00939 void StateTest::doState(  const std::string& name, const std::string& prog, TaskContext* tc, bool test )
00940 {
00941     BOOST_CHECK( tc->engine() );
00942 
00943     parseState( prog, tc, test);
00944     runState(name, tc, test);
00945     checkState(name, tc, test);
00946 }
00947 
00948 void StateTest::parseState(const std::string& prog, TaskContext* tc, bool test )
00949 {
00950     // Alternative way: test ScriptingService as well.
00951     try {
00952         sa->loadStateMachines( prog, std::string("state_test.cpp"), true );
00953     }
00954     catch( const file_parse_exception& exc )
00955         {
00956             BOOST_REQUIRE_MESSAGE( !test, exc.what() );
00957         }
00958     catch( const parse_exception& exc )
00959         {
00960             BOOST_REQUIRE_MESSAGE( !test, exc.what() );
00961         }
00962     catch( const program_load_exception& e)
00963         {
00964             BOOST_REQUIRE_MESSAGE( !test, e.what() );
00965         }
00966     catch( const std::exception& e ) {
00967             BOOST_CHECK_MESSAGE( !test , e.what());
00968             BOOST_REQUIRE_MESSAGE( !test, "Uncaught Processor load exception" );
00969     }
00970 }
00971 
00972 void StateTest::runState(const std::string& name, TaskContext* tc, bool test )
00973 {
00974     StateMachinePtr sm = sa->getStateMachine(name);
00975     BOOST_REQUIRE( sm );
00976     sm->trace(true);
00977     OperationCaller<bool(StateMachine*)> act = tc->provides(name)->getOperation("activate");
00978     OperationCaller<bool(StateMachine*)> autom = tc->provides(name)->getOperation("automatic");
00979     BOOST_CHECK( act(sm.get()) );
00980     BOOST_CHECK( SimulationThread::Instance()->run(1) );
00981     BOOST_CHECK_MESSAGE( sm->isActive(), "Error : Activate Command for '"+sm->getName()+"' did not have effect." );
00982     BOOST_CHECK( autom(sm.get()) || !test  );
00983 
00984     BOOST_CHECK( SimulationThread::Instance()->run(1000) );
00985 }
00986 
00987 void StateTest::checkState(const std::string& name, TaskContext* tc, bool test )
00988 {
00989     StateMachinePtr sm = sa->getStateMachine(name);
00990     BOOST_REQUIRE( sm );
00991     if ( test ) {
00992         // check error status of parent :
00993         BOOST_CHECK_MESSAGE( sm->isActive(), "Error : State Context '"+sm->getName()+"' did not get activated." );
00994         stringstream errormsg;
00995         int line = sm->getLineNumber();
00996         errormsg <<" in StateMachine "+sm->getName()
00997                  <<" in state "<< (sm->currentState() ? sm->currentState()->getName() : "(null)")
00998                  <<" on line " << line <<" of that StateMachine:"<<endl;
00999         {
01000             stringstream sctext( sm->getText() );
01001             int cnt = 1;
01002             while ( cnt++ <line && sctext ) {
01003                 string garbage;
01004                 getline( sctext, garbage, '\n' );
01005             }
01006             getline( sctext, sline, '\n' );
01007         }
01008         errormsg <<"here  > " << sline << endl;
01009         if ( sm->inError() ) {
01010             RTT::scripting::DumpObject( tc->provides() );
01011             RTT::scripting::DumpObject( tc->provides(name) );
01012         }
01013         BOOST_CHECK_MESSAGE( sm->inError() == false, "Runtime error (inError() == true) encountered" + errormsg.str() );
01014         // check error status of all children:
01015         StateMachine::ChildList cl = sm->getChildren();
01016         StateMachine::ChildList::iterator clit = cl.begin();
01017         while( clit != cl.end() ) {
01018             line = (*clit)->getLineNumber();
01019             {
01020                 stringstream sctext( (*clit)->getText() );
01021                 int cnt = 1;
01022                 while ( cnt++ <line && sctext ) {
01023                     string garbage;
01024                     getline( sctext, garbage, '\n' );
01025                 }
01026                 getline( sctext, sline, '\n' );
01027             }
01028             stringstream cerrormsg;
01029             if ( (*clit)->currentState() )
01030                 cerrormsg <<" in child "<< (*clit)->getName() <<" in state "<<(*clit)->currentState()->getName()<< " on line " <<  (*clit)->getLineNumber() <<" of that StateMachine."<<endl <<"here  > " << sline << endl;
01031             else
01032                 cerrormsg <<" child "<< (*clit)->getName() << " (deactivated) on line " <<  (*clit)->getLineNumber() <<" of that StateMachine."<<endl<<"here  > " << sline << endl;
01033 
01034             BOOST_CHECK_MESSAGE( (*clit)->inError() == false, "Runtime error (inError() == true) encountered" + cerrormsg.str() );
01035             if ( (*clit)->inError() == false && sm->inError() == true) {
01036                 cout << "Child Status:" << cerrormsg.str() << endl;
01037             }
01038             ++clit;
01039         }
01040     }
01041 }
01042 
01043 void StateTest::finishState(std::string const& name, TaskContext* tc, bool test)
01044 {
01045     StateMachinePtr sm = sa->getStateMachine(name);
01046     BOOST_REQUIRE( sm );
01047     BOOST_CHECK( sa->getStateMachine( name )->stop() );
01048     BOOST_CHECK( SimulationThread::Instance()->run(500) );
01049     if (test) {
01050         stringstream errormsg;
01051         errormsg << " on line " << sm->getLineNumber() <<", status is "<< sa->getStateMachineStatusStr(name) <<endl <<"here  > " << sline << endl;;
01052         BOOST_CHECK_MESSAGE( sm->isStopped(), "StateMachine stalled " + errormsg.str() );
01053     }
01054     // you can call deactivate even when the proc is not running.
01055     // but deactivation may be 'in progress if exit state has commands in it.
01056     BOOST_CHECK( sa->getStateMachine( name )->deactivate() );
01057     BOOST_CHECK( SimulationThread::Instance()->run(200) );
01058     if ( sm->isActive() )
01059         BOOST_CHECK( sa->getStateMachine( name )->deactivate() );
01060     BOOST_CHECK( SimulationThread::Instance()->run(200) );
01061     BOOST_CHECK( sa->getStateMachine( name )->isActive() == false );
01062 
01063     // only stop now, since deactivate won't work if simtask not running.
01064     tc->stop();
01065 
01066     try {
01067         BOOST_CHECK( sa->unloadStateMachine( name ) );
01068     }
01069     catch( const program_unload_exception& e)
01070         {
01071             BOOST_REQUIRE_MESSAGE( false, e.what() );
01072         }
01073     catch( ... ) {
01074             BOOST_REQUIRE_MESSAGE( false, "Uncaught Processor unload exception" );
01075     }
01076 
01077 }
01078 


rtt
Author(s): RTT Developers
autogenerated on Mon Oct 6 2014 03:13:54