00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
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 <rt_string.hpp>
00035 #include "operations_fixture.hpp"
00036
00037 #include <string>
00038 #include <iostream>
00039 #include <sstream>
00040
00041 using namespace RTT;
00042 using namespace RTT::detail;
00043 using namespace std;
00044
00045 class StateTest
00046 : public OperationsFixture
00047 {
00048 public:
00049 Parser parser;
00050 InputPort<double> d_event;
00051 InputPort<bool> b_event;
00052 InputPort<int> t_event;
00053 Operation<void(void)> v_event;
00054 Operation<void(double)> o_event;
00055 Operation<void(void)> v1_event;
00056 Operation<void(void)> v2_event;
00057 Operation<void(void)> v3_event;
00058 OutputPort<double> d_event_source;
00059 OutputPort<bool> b_event_source;
00060 OutputPort<int> t_event_source;
00061 Operation<void(double)> c_event;
00062 ScriptingService::shared_ptr sa;
00063
00064 RTT::Operation<void(RTT::rt_string)> setState_op;
00065 void setState(RTT::rt_string state) {
00066 mrt_state = state;
00067
00068 }
00069
00070 RTT::rt_string mrt_state;
00071
00072 void log(const std::string& msg) {
00073 Logger::log(Logger::Info) << msg << endlog();
00074 }
00075 void doState(const std::string& name, const std::string& prog, TaskContext*, bool test=true );
00076 void parseState( const std::string& prog, TaskContext*, bool test=true );
00077 void runState(const std::string& name, TaskContext*, bool test=true );
00078 void checkState( const std::string& name, TaskContext*, bool test=true );
00079 void finishState( std::string const& name, TaskContext*, bool test=true );
00080
00081 std::string sline;
00082 public:
00083 StateTest()
00084 :
00085 d_event("d_event"), b_event("b_event"), t_event("t_event"), v_event("v_event"),o_event("o_event"),
00086 v1_event("v1_event"),v2_event("v2_event"),v3_event("v3_event"),c_event("c_event"),
00087 d_event_source("d_event_source"), b_event_source("b_event_source"), t_event_source("t_event_source")
00088 ,sa( ScriptingService::Create(tc) ),
00089 setState_op("setState", &StateTest::setState, this, RTT::OwnThread)
00090 {
00091 tc->stop();
00092 tc->setActivity( new SimulationActivity(0.001) );
00093
00094 tc->addPeer(caller);
00095
00096 tc->ports()->addPort( d_event );
00097 tc->ports()->addPort( b_event );
00098 tc->ports()->addPort( t_event );
00099 #ifdef ORO_SIGNALLING_OPERATIONS
00100 tc->provides()->addEventOperation( o_event );
00101 tc->provides()->addEventOperation( v_event );
00102 tc->provides()->addEventOperation( v1_event );
00103 tc->provides()->addEventOperation( v2_event );
00104 tc->provides()->addEventOperation( v3_event );
00105 caller->provides()->addEventOperation( c_event );
00106 #else
00107 tc->provides()->addOperation( o_event );
00108 tc->provides()->addOperation( v_event );
00109 tc->provides()->addOperation( v1_event );
00110 tc->provides()->addOperation( v2_event );
00111 tc->provides()->addOperation( v3_event );
00112 caller->provides()->addOperation( c_event );
00113 #endif
00114
00115 tc->provides()->addOperation(setState_op).doc("Communicates state from SM").arg("state", "Name of state");
00116
00117 tc->ports()->addPort( d_event_source );
00118 tc->ports()->addPort( b_event_source );
00119 tc->ports()->addPort( t_event_source );
00120
00121 d_event_source.connectTo( &d_event );
00122 b_event_source.connectTo( &b_event );
00123 t_event_source.connectTo( &t_event );
00124 tc->start();
00125 i = 0;
00126 SimulationThread::Instance()->stop();
00127
00128 tc->addOperation("log", &StateTest::log, this);
00129 }
00130 ~StateTest(){
00131 }
00132 };
00133
00134 BOOST_FIXTURE_TEST_SUITE( StateTestSuite, StateTest )
00135
00136 BOOST_AUTO_TEST_CASE( testParseState)
00137 {
00138
00139 string prog = string("StateMachine X {\n")
00140 + " param int isten\n"
00141 + " param bool isflse\n"
00142 + " param bool isok\n"
00143 + " param double isnegative\n"
00144 + " var bool istrrue = true\n"
00145 + " var double d_dummy = -1.0\n"
00146 + " var int i_dummy = -1\n"
00147 + " var bool varinit = false\n"
00148 + " var bool b_dummy = true\n"
00149 + " initial state INIT {\n"
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160 + " entry {\n"
00161 + " set varinit = (d_dummy != -1.) || (i_dummy != -1) \n"
00162 + " do test.good()\n"
00163 + " set d_dummy = 1.234\n"
00164 + " set i_dummy = -2\n"
00165 + " do test.good()\n"
00166 + " }\n"
00167 + " handle {\n"
00168 + " do test.good()\n"
00169 + " }\n"
00170 + " exit {\n"
00171 + " do test.good()\n"
00172 + " set d_dummy = 0.0\n"
00173 + " set i_dummy = 0\n"
00174 + " }\n"
00175 + " transitions {\n"
00176 + " if false then select ERROR\n"
00177 + " if varinit == true then select PRE_VARFAIL\n"
00178 + " if (d_dummy != 1.234) || (i_dummy != -2) then select ENTRYFAIL\n"
00179 + " }\n"
00180 + " transition if (istrrue == false) || (isflse == true) || (isten != 10) ||( isnegative >= 0. ) then select PARAMFAIL\n"
00181 + " transition if isok == false then select PARAMFAIL\n"
00182 + " transition select FINI\n"
00183 + " transition select ERROR\n"
00184 + " }\n"
00185 + " state PRE_ERROR { entry { do test.assert(false) }\n"
00186 + " }\n"
00187 + " state PRE_PARAMFAIL { entry { do test.assert(false) }\n"
00188 + " }\n"
00189 + " state PRE_VARFAIL { entry { do test.assert(false) }\n"
00190 + " }\n"
00191 + " state ERROR { entry { do test.assert(false) }\n"
00192 + " }\n"
00193 + " state PARAMFAIL {\n"
00194 + " entry { \n"
00195 + " do test.assertMsg( isten == 10, \"isten parameter not correctly initialised\")\n"
00196 + " do test.assertMsg( istrrue == true, \"istrrue parameter not correctly initialised\")\n"
00197 + " do test.assertMsg( isok == true, \"isok parameter not correctly initialised\")\n"
00198 + " do test.assertMsg( isflse == false, \"isflse parameter not correctly initialised\")\n"
00199 + " do test.assertMsg( true == true, \"true ident not correctly done\")\n"
00200 + " do test.assertMsg( false == false, \"false ident not correctly done\")\n"
00201 + " do test.assertMsg( isnegative == -1.0, \"isnegative parameter not correctly initialised\")\n"
00202 + " }\n"
00203 + " }\n"
00204 + " state VARFAIL { entry { do test.assert(false) }\n"
00205 + " }\n"
00206 + " state EXITFAIL { entry { do test.assert(false) }\n"
00207 + " }\n"
00208 + " state ENTRYFAIL { entry { do test.assert(false) }\n"
00209 + " }\n"
00210 + " final state FINI {\n"
00211 + " preconditions {\n"
00212 + " if (d_dummy != 0.) || (i_dummy != 0) then select EXITFAIL\n"
00213 + " if false then select ERROR\n"
00214 + " }\n"
00215 + " entry {\n"
00216 + " do test.good()\n"
00217 + " set d_dummy = -1.\n"
00218 + " set i_dummy = -1\n"
00219 + " }\n"
00220 + " handle {\n"
00221 + " do test.good()\n"
00222 + " }\n"
00223 + " exit {\n"
00224 + " do test.good()\n"
00225 + " }\n"
00226 + " transitions {\n"
00227 + " if false then select ERROR\n"
00228 + " select INIT\n"
00229 + " select ERROR\n"
00230 + " }\n"
00231 + " }\n"
00232 + " }\n"
00233
00234 + " RootMachine X x( isten = 10, isok = true, isflse=false, isnegative = -1.0) \n"
00235 ;
00236
00237 this->doState("x", prog, tc );
00238 this->finishState( "x", tc );
00239 }
00240
00241 BOOST_AUTO_TEST_CASE( testStateFailure)
00242 {
00243
00244
00245
00246 string prog = string("StateMachine X {\n")
00247 + " initial state INIT {\n"
00248 + " entry {\n"
00249 + " do test.increase()\n"
00250 + " do test.assert( test.i != 1)\n"
00251 + " }\n"
00252 + " run {\n"
00253 + " do test.assert( test.i != 2)\n"
00254 + " }\n"
00255 + " exit {\n"
00256 + " do test.assert( test.i != 3)\n"
00257 + " }\n"
00258 + " transitions {\n"
00259 + " if (true) then { do test.assert( test.i != 7); } select FINI\n"
00260 + " }\n"
00261 + " }\n"
00262 + " state ERROR {\n"
00263 + " }\n"
00264 + " final state FINI {\n"
00265 + " entry {\n"
00266 + " do test.assert( test.i != 4)\n"
00267 + " }\n"
00268 + " run {\n"
00269 + " do test.assert( test.i != 5)\n"
00270 + " }\n"
00271 + " exit {\n"
00272 + " do test.assert( test.i != 6)\n"
00273 + " }\n"
00274 + " transitions {\n"
00275 + " select ERROR\n"
00276 + " }\n"
00277 + " }\n"
00278 + " }\n"
00279 + " RootMachine X x\n"
00280 ;
00281
00282
00283 const int max = 7;
00284 int x = 0;
00285 while ( i < max && x < max) {
00286 this->doState("x", prog, tc, false );
00287
00288
00289 BOOST_CHECK_MESSAGE( sa->getStateMachineStatus("x") == StateMachine::Status::error, "Status is: " + sa->getStateMachineStatusStr("x") );
00290
00291 this->finishState( "x", tc, false);
00292 ++x;
00293 }
00294 }
00295 BOOST_AUTO_TEST_CASE( testStateChildren)
00296 {
00297
00298 string prog = string("StateMachine Y {\n")
00299 + " param double isnegative\n"
00300 + " var double t = 1.0\n"
00301 + " initial state INIT {\n"
00302 + " entry {\n"
00303 + " do test.good()\n"
00304 + " }\n"
00305 + " transitions {\n"
00306 + " if isnegative >= 0. then select PARAMFAIL\n"
00307 + " select FINI\n"
00308 + " }\n"
00309 + " }\n"
00310 + " state ERROR { entry { do test.assert(false) }\n"
00311 + " }\n"
00312 + " state PARAMFAIL { entry { do test.assert(false) }\n"
00313 + " }\n"
00314 + " state VARFAIL { entry { do test.assert(false) }\n"
00315 + " }\n"
00316 + " state EXITFAIL { entry { do test.assert(false) }\n"
00317 + " }\n"
00318 + " state ENTRYFAIL { entry { do test.assert(false) }\n"
00319 + " }\n"
00320 + " final state FINI {\n"
00321 + " entry {\n"
00322 + " do test.good()\n"
00323 + " }\n"
00324 + " transitions {\n"
00325 + " select INIT\n"
00326 + " }\n"
00327 + " }\n"
00328 + " }\n"
00329 + string("StateMachine Z {\n")
00330 + " param double neg\n"
00331 + " initial state INIT {\n"
00332 + " transitions {\n"
00333 + " if neg >= 0. then select PARAMFAIL\n"
00334 + " select FINI\n"
00335 + " }\n"
00336 + " }\n"
00337 + " state PARAMFAIL { entry { do test.assert(false) }\n"
00338 + " }\n"
00339 + " final state FINI {\n"
00340 + " transitions {\n"
00341 + " select INIT\n"
00342 + " }\n"
00343 + " }\n"
00344 + " }\n"
00345 + string("StateMachine X {\n")
00346 + " param double isnegative\n"
00347 + " var double d_dummy = -2.0\n"
00348 + " var int i_dummy = -1\n"
00349 + " SubMachine Y y1(isnegative = d_dummy)\n"
00350 + " SubMachine Y y2(isnegative = -3.0)\n"
00351 + " SubMachine Y y3(isnegative = isnegative)\n"
00352 + " SubMachine Z z1( neg = d_dummy)\n"
00353 + " initial state INIT {\n"
00354 + " entry {\n"
00355 + " do test.good()\n"
00356 + " do y1.activate()\n"
00357 + " do y2.activate()\n"
00358 + " do y3.activate()\n"
00359 + " do z1.activate()\n"
00360 + " }\n"
00361 + " exit {\n"
00362 + " do y1.start()\n"
00363 + " do y2.start()\n"
00364 + " do y3.start()\n"
00365 + " do z1.start()\n"
00366 + " }\n"
00367 + " transitions {\n"
00368 + " select FINI\n"
00369 + " }\n"
00370 + " }\n"
00371 + " state ERROR { entry { do test.assert(false) }\n"
00372 + " }\n"
00373 + " state PARAMFAIL {\n"
00374 + " entry { \n"
00375 + " do test.assertMsg( y3.isnegative == isnegative, \"y3 parameter not correctly initialised\")\n"
00376 + " do test.assertMsg( y2.isnegative == -3.0, \"y2 parameter not correctly initialised\")\n"
00377 + " do test.assertMsg( y1.isnegative == d_dummy, \"y1 parameter not correctly initialised\")\n"
00378 + " do test.assertMsg( z1.neg == d_dummy, \"z1 parameter not correctly initialised\")\n"
00379 + " }\n"
00380 + " }\n"
00381 + " state VARFAIL { entry { do test.assert(false) }\n"
00382 + " }\n"
00383 + " state EXITFAIL { entry { do test.assert(false) }\n"
00384 + " }\n"
00385 + " state ENTRYFAIL { entry { do test.assert(false) }\n"
00386 + " }\n"
00387 + " final state FINI {\n"
00388 + " entry {\n"
00389 + " do test.good()\n"
00390 + " do y1.stop()\n"
00391 + " do y2.stop()\n"
00392 + " do y3.stop()\n"
00393 + " do z1.stop()\n"
00394 + " }\n"
00395 + " exit {\n"
00396 + " do test.good()\n"
00397 + " do y1.deactivate()\n"
00398 + " do y2.deactivate()\n"
00399 + " do y3.deactivate()\n"
00400 + " do z1.deactivate()\n"
00401 + " }\n"
00402 + " transitions {\n"
00403 + " if z1.neg != d_dummy then select PARAMFAIL\n"
00404 + " if y1.isnegative != d_dummy then select PARAMFAIL\n"
00405 + " if y2.isnegative != -3.0 then select PARAMFAIL\n"
00406 + " if y3.isnegative != isnegative then select PARAMFAIL\n"
00407 + " select INIT\n"
00408 + " }\n"
00409 + " }\n"
00410 + " }\n"
00411 + " RootMachine X x( isnegative = -1.0) \n"
00412 ;
00413
00414 this->doState("x", prog, tc );
00415 this->finishState( "x", tc);
00416 }
00417
00418 BOOST_AUTO_TEST_CASE( testStateEmpty)
00419 {
00420
00421 string prog = string("StateMachine X {\n")
00422 + " initial state INIT {\n"
00423 + " transitions {\n"
00424 + " select TEST;\n"
00425 + " }\n"
00426 + " }\n"
00427 + " state TEST {\n"
00428 + " }\n"
00429 + " final state FINI {\n"
00430 + " }\n"
00431 + " }\n"
00432 + " RootMachine X x\n"
00433 ;
00434 this->doState("x", prog, tc );
00435 this->finishState( "x", tc);
00436 }
00437
00438 BOOST_AUTO_TEST_CASE( testStateEmptyChild)
00439 {
00440
00441 string prog = string("StateMachine Y {\n")
00442 + " initial state INIT {\n"
00443 + " }\n"
00444 + " final state FINI {\n"
00445 + " }\n"
00446 + "}\n"
00447 + "StateMachine X {\n"
00448 + " SubMachine Y y;\n"
00449 + " initial state INIT {\n"
00450 + " }\n"
00451 + " final state FINI {\n"
00452 + " }\n"
00453 + "}\n"
00454 + "RootMachine X x\n"
00455 ;
00456
00457 this->doState("x", prog, tc );
00458 this->finishState( "x", tc);
00459 }
00460
00461 BOOST_AUTO_TEST_CASE( testStateComments)
00462 {
00463
00464 string prog = string("// Start here\n")
00465 + "StateMachine X { //\n"
00466 + " // comment on INIT\n"
00467 + " initial state INIT /* INIT */ { // \n"
00468 + " // comment in INIT\n"
00469 + " entry /* entry */ { // \n"
00470 + " // in entry\n"
00471 + " } // end \n\n"
00472 + "//\n"
00473 + " }\n"
00474 + " // intermediate comment \n"
00475 + " final state FINI // \n"
00476 + " /* ... */\n"
00477 + " {\n"
00478 + "//\n"
00479 + " entry {\n"
00480 + " // in entry\n"
00481 + " /* in entry */\n"
00482 + " }\n\n"
00483 + "//\n"
00484 + " }\n"
00485 + "// final comment\n"
00486 + "//\n"
00487 + "}\n"
00488 + "// instantiate comment\n"
00489 + "//\n"
00490 + "RootMachine X x // end\n"
00491 ;
00492 this->doState("x", prog, tc );
00493 this->finishState( "x", tc);
00494 }
00495
00496 BOOST_AUTO_TEST_CASE( testStateOperations)
00497 {
00498
00499 string prog = string("StateMachine X {\n")
00500 + " initial state INIT {\n"
00501 + " entry {\n"
00502 + " setState( rt_string(\"INIT-ENTRY\") )\n"
00503 + " }\n"
00504 + " transitions {\n"
00505 + " select TEST;\n"
00506 + " }\n"
00507 + " }\n"
00508 + " state TEST {\n"
00509 + " var double dret\n"
00510 + " entry {\n"
00511 + " setState( rt_string(\"TEST-ENTRY\") )\n"
00512 + " methods.m0()\n"
00513 + " methods.m1(1)\n"
00514 + " methods.m2(1,2.0)\n"
00515 + " methods.m3(1,2.0,true)\n"
00516 + " methods.m4(1,2.0,true,\"hello\")\n"
00517 + " methods.m5(1,2.0,true,\"hello\",5.0)\n"
00518 + " methods.m6(1,2.0,true,\"hello\",5.0,'a')\n"
00519 + " dret = methods.m7(1,2.0,true,\"hello\",5.0,'a',7)\n"
00520 + " test.assert( dret == -8.0 )\n"
00521 + " methods.o0()\n"
00522 + " methods.o1(1)\n"
00523 + " methods.o2(1,2.0)\n"
00524 + " methods.o3(1,2.0,true)\n"
00525 + " methods.o4(1,2.0,true,\"hello\")\n"
00526 + " methods.o5(1,2.0,true,\"hello\",5.0)\n"
00527 + " methods.o6(1,2.0,true,\"hello\",5.0,'a')\n"
00528 + " dret = methods.o7(1,2.0,true,\"hello\",5.0,'a',7)\n"
00529 + " test.assert( dret == -8.0 )\n"
00530 + " }\n"
00531 + " run {"
00532 + " setState( rt_string(\"TEST-RUN\") )\n"
00533 + " methods.m0()\n"
00534 + " methods.m1(1)\n"
00535 + " methods.m2(1,2.0)\n"
00536 + " methods.m3(1,2.0,true)\n"
00537 + " methods.m4(1,2.0,true,\"hello\")\n"
00538 + " methods.m5(1,2.0,true,\"hello\",5.0)\n"
00539 + " methods.m6(1,2.0,true,\"hello\",5.0,'a')\n"
00540 + " dret = methods.m7(1,2.0,true,\"hello\",5.0,'a',7)\n"
00541 + " test.assert( dret == -8.0 )\n"
00542 + " methods.o0()\n"
00543 + " methods.o1(1)\n"
00544 + " methods.o2(1,2.0)\n"
00545 + " methods.o3(1,2.0,true)\n"
00546 + " methods.o4(1,2.0,true,\"hello\")\n"
00547 + " methods.o5(1,2.0,true,\"hello\",5.0)\n"
00548 + " methods.o6(1,2.0,true,\"hello\",5.0,'a')\n"
00549 + " dret = methods.o7(1,2.0,true,\"hello\",5.0,'a',7)\n"
00550 + " test.assert( dret == -8.0 )\n"
00551 + " }\n"
00552 + " exit {"
00553 + " setState( rt_string(\"TEST-EXIT\") )\n"
00554 + " methods.m0()\n"
00555 + " methods.m1(1)\n"
00556 + " methods.m2(1,2.0)\n"
00557 + " methods.m3(1,2.0,true)\n"
00558 + " methods.m4(1,2.0,true,\"hello\")\n"
00559 + " methods.m5(1,2.0,true,\"hello\",5.0)\n"
00560 + " methods.m6(1,2.0,true,\"hello\",5.0,'a')\n"
00561 + " dret = methods.m7(1,2.0,true,\"hello\",5.0,'a',7)\n"
00562 + " test.assert( dret == -8.0 )\n"
00563 + " methods.o0()\n"
00564 + " methods.o1(1)\n"
00565 + " methods.o2(1,2.0)\n"
00566 + " methods.o3(1,2.0,true)\n"
00567 + " methods.o4(1,2.0,true,\"hello\")\n"
00568 + " methods.o5(1,2.0,true,\"hello\",5.0)\n"
00569 + " methods.o6(1,2.0,true,\"hello\",5.0,'a')\n"
00570 + " methods.o7(1,2.0,true,\"hello\",5.0,'a',7)\n"
00571 + " }\n"
00572 + " transitions {\n"
00573 + " if true then \n"
00574 + " {"
00575 + " setState( rt_string(\"TEST-TRANSIT\") )\n"
00576 + " methods.m0()\n"
00577 + " methods.m1(1)\n"
00578 + " methods.m2(1,2.0)\n"
00579 + " methods.m3(1,2.0,true)\n"
00580 + " methods.m4(1,2.0,true,\"hello\")\n"
00581 + " methods.m5(1,2.0,true,\"hello\",5.0)\n"
00582 + " methods.m6(1,2.0,true,\"hello\",5.0,'a')\n"
00583 + " dret = methods.m7(1,2.0,true,\"hello\",5.0,'a',7)\n"
00584 + " test.assert( dret == -8.0 )\n"
00585 + " methods.o0()\n"
00586 + " methods.o1(1)\n"
00587 + " methods.o2(1,2.0)\n"
00588 + " methods.o3(1,2.0,true)\n"
00589 + " methods.o4(1,2.0,true,\"hello\")\n"
00590 + " methods.o5(1,2.0,true,\"hello\",5.0)\n"
00591 + " methods.o6(1,2.0,true,\"hello\",5.0,'a')\n"
00592 + " dret = methods.o7(1,2.0,true,\"hello\",5.0,'a',7)\n"
00593 + " test.assert( dret == -8.0 )\n"
00594 + " } select TEST2;\n"
00595 + " }\n"
00596 + " }\n"
00597 + " state TEST2 {\n"
00598 + " entry {\n"
00599 + " setState( rt_string(\"TEST-ENTRY\") )\n"
00600 + " methods.m0()\n"
00601 + " methods.m1(1)\n"
00602 + " methods.m2(1,2.0)\n"
00603 + " methods.m3(1,2.0,true)\n"
00604 + " methods.m4(1,2.0,true,\"hello\")\n"
00605 + " methods.m5(1,2.0,true,\"hello\",5.0)\n"
00606 + " methods.m6(1,2.0,true,\"hello\",5.0,'a')\n"
00607 + " dret = methods.m7(1,2.0,true,\"hello\",5.0,'a',7)\n"
00608 + " test.assert( dret == -8.0 )\n"
00609 + " methods.o0()\n"
00610 + " methods.o1(1)\n"
00611 + " methods.o2(1,2.0)\n"
00612 + " methods.o3(1,2.0,true)\n"
00613 + " methods.o4(1,2.0,true,\"hello\")\n"
00614 + " methods.o5(1,2.0,true,\"hello\",5.0)\n"
00615 + " methods.o6(1,2.0,true,\"hello\",5.0,'a')\n"
00616 + " dret = methods.o7(1,2.0,true,\"hello\",5.0,'a',7)\n"
00617 + " test.assert( dret == -8.0 )\n"
00618 + " }\n"
00619 + " run {"
00620 + " setState( rt_string(\"TEST-RUN\") )\n"
00621 + " methods.m0()\n"
00622 + " methods.m1(1)\n"
00623 + " methods.m2(1,2.0)\n"
00624 + " methods.m3(1,2.0,true)\n"
00625 + " methods.m4(1,2.0,true,\"hello\")\n"
00626 + " methods.m5(1,2.0,true,\"hello\",5.0)\n"
00627 + " methods.m6(1,2.0,true,\"hello\",5.0,'a')\n"
00628 + " dret = methods.m7(1,2.0,true,\"hello\",5.0,'a',7)\n"
00629 + " test.assert( dret == -8.0 )\n"
00630 + " methods.o0()\n"
00631 + " methods.o1(1)\n"
00632 + " methods.o2(1,2.0)\n"
00633 + " methods.o3(1,2.0,true)\n"
00634 + " methods.o4(1,2.0,true,\"hello\")\n"
00635 + " methods.o5(1,2.0,true,\"hello\",5.0)\n"
00636 + " methods.o6(1,2.0,true,\"hello\",5.0,'a')\n"
00637 + " dret = methods.o7(1,2.0,true,\"hello\",5.0,'a',7)\n"
00638 + " test.assert( dret == -8.0 )\n"
00639 + " }\n"
00640 + " exit {"
00641 + " setState( rt_string(\"TEST-EXIT\") )\n"
00642 + " methods.m0()\n"
00643 + " methods.m1(1)\n"
00644 + " methods.m2(1,2.0)\n"
00645 + " methods.m3(1,2.0,true)\n"
00646 + " methods.m4(1,2.0,true,\"hello\")\n"
00647 + " methods.m5(1,2.0,true,\"hello\",5.0)\n"
00648 + " methods.m6(1,2.0,true,\"hello\",5.0,'a')\n"
00649 + " dret = methods.m7(1,2.0,true,\"hello\",5.0,'a',7)\n"
00650 + " test.assert( dret == -8.0 )\n"
00651 + " methods.o0()\n"
00652 + " methods.o1(1)\n"
00653 + " methods.o2(1,2.0)\n"
00654 + " methods.o3(1,2.0,true)\n"
00655 + " methods.o4(1,2.0,true,\"hello\")\n"
00656 + " methods.o5(1,2.0,true,\"hello\",5.0)\n"
00657 + " methods.o6(1,2.0,true,\"hello\",5.0,'a')\n"
00658 + " methods.o7(1,2.0,true,\"hello\",5.0,'a',7)\n"
00659 + " }\n"
00660 + " transitions {\n"
00661 + " if true then \n"
00662 + " {"
00663 + " setState( rt_string(\"TEST-TRANSIT\") )\n"
00664 + " methods.m0()\n"
00665 + " methods.m1(1)\n"
00666 + " methods.m2(1,2.0)\n"
00667 + " methods.m3(1,2.0,true)\n"
00668 + " methods.m4(1,2.0,true,\"hello\")\n"
00669 + " methods.m5(1,2.0,true,\"hello\",5.0)\n"
00670 + " methods.m6(1,2.0,true,\"hello\",5.0,'a')\n"
00671 + " dret = methods.m7(1,2.0,true,\"hello\",5.0,'a',7)\n"
00672 + " test.assert( dret == -8.0 )\n"
00673 + " methods.o0()\n"
00674 + " methods.o1(1)\n"
00675 + " methods.o2(1,2.0)\n"
00676 + " methods.o3(1,2.0,true)\n"
00677 + " methods.o4(1,2.0,true,\"hello\")\n"
00678 + " methods.o5(1,2.0,true,\"hello\",5.0)\n"
00679 + " methods.o6(1,2.0,true,\"hello\",5.0,'a')\n"
00680 + " dret = methods.o7(1,2.0,true,\"hello\",5.0,'a',7)\n"
00681 + " test.assert( dret == -8.0 )\n"
00682 + " } select FINI;\n"
00683 + " }\n"
00684 + " }\n"
00685 + " final state FINI {\n"
00686 + " }\n"
00687 + " }\n"
00688 + " RootMachine X x\n"
00689 ;
00690 parseState( prog, tc, true);
00691
00692 tc->stop();
00693 tc->setActivity( new Activity(0, 0.001) );
00694 tc->start();
00695
00696 StateMachinePtr sm = sa->getStateMachine("x");
00697 BOOST_REQUIRE( sm );
00698 sm->trace(true);
00699 OperationCaller<bool(StateMachine*)> act = tc->provides("x")->getOperation("activate");
00700 OperationCaller<bool(StateMachine*)> autom = tc->provides("x")->getOperation("automatic");
00701 BOOST_CHECK( act(sm.get()) );
00702 BOOST_CHECK( autom(sm.get()) );
00703
00704 sleep(1);
00705
00706 checkState( "x", tc);
00707 BOOST_CHECK( sa->getStateMachine( "x" )->inState("FINI") );
00708 this->finishState( "x", tc, false);
00709 }
00710
00711
00712 BOOST_AUTO_TEST_CASE( testStateTransitions)
00713 {
00714
00715 string prog = string("StateMachine X {\n")
00716 + " initial state INIT {\n"
00717 + " var int i = 0;\n"
00718 + " var int j = 0;\n"
00719 + " var int k = 0;\n"
00720 + " entry {\n"
00721 + " set j = j + 1\n"
00722 + " }\n"
00723 + " run {\n"
00724 + " set k = k + 1\n"
00725 + " }\n"
00726 + " transitions {\n"
00727 + " if i < 5 then {\n"
00728 + " set i = i + 1;\n"
00729 + " } select INIT\n"
00730 + " if i < 10 then {\n"
00731 + " set i = i + 1;\n"
00732 + " }\n"
00733 + " if i < 10 then {\n"
00734 + " } select TRANS_SHOULD_NOT_CHECK\n"
00735 + " if i == 10 then {\n"
00736 + " set i = i + 1;\n"
00737 + " } select TEST_ENTRY\n"
00738 + " }\n"
00739 + " }\n"
00740 + " state TEST_ENTRY {\n"
00741 + " transitions {\n"
00742 + " if k != i then {\n"
00743 + " } select RUN_FAILED\n"
00744 + " if j != 1 then {\n"
00745 + " } select ENTRY_FAILED\n"
00746 + " else select FINI\n"
00747 + " }\n"
00748 + " }\n"
00749 + " state TRANS_SHOULD_NOT_CHECK {\n"
00750 + " entry { do test.assert(false); }\n"
00751 + " }\n"
00752 + " state ENTRY_FAILED {\n"
00753 + " entry { do test.assert(false); }\n"
00754 + " }\n"
00755 + " state RUN_FAILED {\n"
00756 + " entry { do test.assert(false); }\n"
00757 + " }\n"
00758 + " final state FINI {\n"
00759 + " }\n"
00760 + " }\n"
00761 + " RootMachine X x\n"
00762 ;
00763 this->doState("x", prog, tc );
00764 BOOST_CHECK( sa->getStateMachine( "x" )->inState("FINI") );
00765 this->finishState( "x", tc);
00766 }
00767
00768 BOOST_AUTO_TEST_CASE( testStateTransitionStop )
00769 {
00770
00771 string prog = string("StateMachine X {\n")
00772 + " initial state INIT {\n"
00773 + " transitions {\n"
00774 + " if stop() == true then select NEXT\n"
00775 + " }\n"
00776 + " }\n"
00777 + " state NEXT {\n"
00778 + " entry { do test.assert(true); }\n"
00779 + " }\n"
00780 + " final state FINI {\n"
00781 + " entry { do test.assert(true); }\n"
00782 + " }\n"
00783 + " }\n"
00784 + " RootMachine X x\n"
00785 ;
00786 this->doState("x", prog, tc );
00787 BOOST_CHECK( sa->getStateMachine( "x" )->inState("NEXT") );
00788 this->finishState( "x", tc);
00789 }
00790
00791 BOOST_AUTO_TEST_CASE( testStateGlobalTransitions)
00792 {
00793
00794 string prog = string("StateMachine X {\n")
00795 + " var int gi = 0;\n"
00796 + " transitions {\n"
00797
00798 + " if gi < 5 then {\n"
00799 + " set gi = gi + 1;\n"
00800 + " } select INIT\n"
00801
00802 + " if gi < 10 then {\n"
00803 + " if gi < 5 then do test.assert(false);\n"
00804 + " set gi = gi + 1;\n"
00805 + " }\n"
00806 + " if gi < 10 then {\n"
00807 + " do test.assert(false);\n"
00808 + " } select TRANS_SHOULD_NOT_CHECK\n"
00809 + " if gi >= 10 then {\n"
00810 + " } select FINI\n"
00811 + " }\n"
00812 + " initial state INIT {\n"
00813 + " var int i = 0;\n"
00814 + " var int j = 0;\n"
00815 + " var int k = 0;\n"
00816 + " entry {\n"
00817 + " set j = j + 1\n"
00818 + " }\n"
00819 + " run {\n"
00820 + " set k = k + 1\n"
00821 + " }\n"
00822 + " transitions {\n"
00823 + " if i < 5 then {\n"
00824 + " set i = i + 1;\n"
00825 + " } select INIT\n"
00826 + " if i < 10 then {\n"
00827 + " set i = i + 1;\n"
00828 + " }\n"
00829 + " if i < 10 then {\n"
00830 + " } select TRANS_SHOULD_NOT_CHECK\n"
00831 + " }\n"
00832 + " }\n"
00833 + " state TRANS_SHOULD_NOT_CHECK {\n"
00834 + " entry { do test.assert(false); }\n"
00835 + " }\n"
00836 + " state ENTRY_FAILED {\n"
00837 + " entry { do test.assert(false); }\n"
00838 + " }\n"
00839 + " state RUN_FAILED {\n"
00840 + " entry { do test.assert(false); }\n"
00841 + " }\n"
00842 + " final state FINI {\n"
00843 + " }\n"
00844 + " }\n"
00845 + " RootMachine X x\n"
00846 ;
00847 this->doState("x", prog, tc );
00848 BOOST_CHECK( sa->getStateMachine( "x" )->inState("FINI") );
00849 this->finishState( "x", tc);
00850 }
00851
00852
00853 BOOST_AUTO_TEST_CASE( testStateSubStateVars)
00854 {
00855
00856 string prog = string("StateMachine Y {\n")
00857 + " param double isnegative\n"
00858 + " var double t = 1.0\n"
00859 + " initial state INIT {\n"
00860 + " transitions {\n"
00861 + " if isnegative >= 0. then select PARAMFAIL\n"
00862 + " if t >= 0. then select VARFAIL\n"
00863 + " select FINI\n"
00864 + " }\n"
00865 + " exit { set isnegative = +1.0 }\n"
00866 + " }\n"
00867 + " state ERROR { entry { do test.assert(false) }\n"
00868 + " }\n"
00869 + " state PARAMFAIL { entry { do test.assert(false) }\n"
00870 + " }\n"
00871 + " state VARFAIL { entry { do test.assert(false) }\n"
00872 + " }\n"
00873 + " state EXITFAIL { entry { do test.assert(false) }\n"
00874 + " }\n"
00875 + " state ENTRYFAIL { entry { do test.assert(false) }\n"
00876 + " }\n"
00877 + " final state FINI {\n"
00878 + " transitions {\n"
00879 + " if isnegative <= 0. then select PARAMFAIL\n"
00880 + " }\n"
00881 + " }\n"
00882 + " }\n"
00883 + string("StateMachine X {\n")
00884 + " param double isnegative\n"
00885 + " var double d_dummy = -2.0\n"
00886 + " var int i_dummy = -1\n"
00887 + " SubMachine Y y1(isnegative = d_dummy)\n"
00888 + " initial state INIT {\n"
00889 + " entry {\n"
00890 + " do y1.activate()\n"
00891 + " set y1.t = -1.0 \n"
00892 + " }\n"
00893 + " exit {\n"
00894 + " do y1.start()\n"
00895 + " }\n"
00896 + " transitions {\n"
00897 + " select TEST\n"
00898 + " }\n"
00899 + " }\n"
00900 + " state TEST {\n"
00901 + " entry {\n"
00902 + " do yield\n"
00903 + " do test.assert( y1.inState(\"FINI\") )\n"
00904 + " }\n"
00905 + " transitions {\n"
00906 + " select FINI\n"
00907 + " }\n"
00908 + " }\n"
00909 + " final state FINI {\n"
00910 + " entry {\n"
00911 + " do y1.stop()\n"
00912 + " }\n"
00913 + " exit {\n"
00914 + " set y1.isnegative = -1.0 \n"
00915 + " do y1.deactivate()\n"
00916 + " }\n"
00917 + " transitions {\n"
00918 + " select INIT\n"
00919 + " }\n"
00920 + " }\n"
00921 + " }\n"
00922 + " RootMachine X x( isnegative = -1.0) \n"
00923 ;
00924
00925 this->doState("x", prog, tc );
00926 this->finishState( "x", tc);
00927 }
00928
00929 BOOST_AUTO_TEST_CASE( testStateSubStateCommands)
00930 {
00931
00932 string prog = string("StateMachine Y {\n")
00933 + " param double isnegative\n"
00934 + " var double t = 1.0\n"
00935 + " initial state INIT {\n"
00936 + " transitions {\n"
00937 + " if isnegative < 0. then select ISNEGATIVE\n"
00938 + " if t >= 0. then select ISPOSITIVE\n"
00939 + " select DEFAULT\n"
00940 + " }\n"
00941 + " }\n"
00942 + " state ISNEGATIVE {\n"
00943 + " transitions {\n"
00944 + " select INIT\n"
00945 + " }\n"
00946 + " }\n"
00947 + " state ISPOSITIVE {\n"
00948 + " transitions {\n"
00949 + " select INIT\n"
00950 + " }\n"
00951
00952 + " }\n"
00953 + " state DEFAULT {\n"
00954 + " transitions {\n"
00955 + " select FINI\n"
00956 + " }\n"
00957 + " }\n"
00958 + " final state FINI {\n"
00959 + " }\n"
00960 + " }\n"
00961 + string("StateMachine X {\n")
00962 + " SubMachine Y y1(isnegative = -1.0)\n"
00963 + " initial state INIT {\n"
00964 + " entry {\n"
00965 + " set y1.t = -1.0 \n"
00966 + " do y1.activate()\n"
00967 + " do y1.requestState(\"ISNEGATIVE\")\n"
00968 + " do test.assert( y1.inState(\"ISNEGATIVE\") )\n"
00969 + " do y1.requestState(\"INIT\")\n"
00970 + " do test.assert( y1.inState(\"INIT\") )\n"
00971 + " set y1.isnegative = +1.0 \n"
00972 + " try y1.requestState(\"ISNEGATIVE\") \n "
00973 + " catch \n{\n"
00974 + " do test.assert( y1.inState(\"INIT\") )\n"
00975 + " }\n"
00976 + " do test.assert( y1.inState(\"INIT\") )\n"
00977 + " do y1.requestState(\"FINI\")\n"
00978 + " do test.assert( y1.inState(\"FINI\") )\n"
00979 + " }\n"
00980 + " exit {\n"
00981 + " do y1.requestState(\"INIT\")\n"
00982 + " do test.assert( y1.inState(\"INIT\") )\n"
00983 + " set y1.isnegative = +1.0 \n"
00984 + " set y1.t = -1.0 \n"
00985 + " do y1.start()\n"
00986 + " while ! y1.inState(\"FINI\") \n"
00987 + " do nothing\n"
00988 + " }\n"
00989 + " transitions {\n"
00990 + " select FINI\n"
00991 + " }\n"
00992 + " }\n"
00993 + " final state FINI {\n"
00994 + " entry {\n"
00995 + " do y1.stop()\n"
00996 + " }\n"
00997 + " exit {\n"
00998 + " do y1.deactivate()\n"
00999 + " }\n"
01000 + " transitions {\n"
01001 + " select INIT\n"
01002 + " }\n"
01003 + " }\n"
01004 + " }\n"
01005 + " RootMachine X x() \n"
01006 ;
01007
01008 this->doState("x", prog, tc );
01009 this->finishState( "x", tc);
01010 }
01011
01012 #ifdef ORO_SIGNALLING_OPERATIONS
01013 BOOST_AUTO_TEST_CASE( testStateOperationSignalTransition )
01014 {
01015
01016 string prog = string("StateMachine X {\n")
01017 + " var double et = 0.0\n"
01018 + " initial state INIT {\n"
01019 + " transition o_event(et) select FINI\n"
01020 + " }\n"
01021 + " final state FINI {} \n"
01022 + "}\n"
01023 + "RootMachine X x()\n";
01024 this->parseState( prog, tc );
01025 StateMachinePtr sm = sa->getStateMachine("x");
01026 BOOST_REQUIRE( sm );
01027 this->runState("x", tc);
01028 checkState( "x", tc);
01029 OperationCaller<void(double)> mo( tc->provides()->getOperation("o_event") );
01030 mo(3.33);
01031 checkState( "x", tc);
01032 BOOST_CHECK( SimulationThread::Instance()->run(2) );
01033 checkState( "x", tc);
01034 BOOST_CHECK( sm->inState("FINI") );
01035 this->checkState("x",tc);
01036 this->finishState("x", tc);
01037 }
01038
01039 BOOST_AUTO_TEST_CASE( testStateOperationCallerSignalTransition )
01040 {
01041
01042 string prog = string("StateMachine X {\n")
01043 + " var double et = 0.0\n"
01044 + " initial state INIT {\n"
01045 + " transition caller.c_event(et) select FINI\n"
01046 + " }\n"
01047 + " final state FINI {} \n"
01048 + "}\n"
01049 + "RootMachine X x()\n";
01050 this->parseState( prog, tc );
01051 StateMachinePtr sm = sa->getStateMachine("x");
01052 BOOST_REQUIRE( sm );
01053 this->runState("x", tc);
01054 checkState( "x", tc);
01055 BOOST_CHECK( SimulationThread::Instance()->run(2) );
01056 checkState( "x", tc);
01057 OperationCaller<void(double)> mc( caller->provides()->getOperation("c_event") );
01058 mc(6.66);
01059 checkState( "x", tc);
01060 BOOST_CHECK( SimulationThread::Instance()->run(2) );
01061 checkState( "x", tc);
01062 BOOST_CHECK( sm->inState("FINI") );
01063 this->checkState("x",tc);
01064 this->finishState("x", tc);
01065 }
01066
01067 BOOST_AUTO_TEST_CASE( testStateOperationSignalMultiTransition )
01068 {
01069
01070 string prog = string("StateMachine X {\n")
01071 + " initial state INIT {\n"
01072 + " transitions { select STATE1 }\n"
01073 + " }\n"
01074 + " state STATE1 {\n"
01075 + " transition v_event() select STATE2\n"
01076 + " }\n"
01077 + " state STATE2 {\n"
01078 + " transition v_event() select FINI\n"
01079 + " }\n"
01080 + " final state FINI {} \n"
01081 + "}\n"
01082 + "RootMachine X x()\n";
01083 this->parseState( prog, tc );
01084 StateMachinePtr sm = sa->getStateMachine("x");
01085 BOOST_REQUIRE( sm );
01086 sm->trace(true);
01087
01088 this->runState("x", tc);
01089 checkState( "x", tc);
01090 BOOST_CHECK_EQUAL( "STATE1", sm->getCurrentStateName() );
01091
01092 BOOST_CHECK( SimulationThread::Instance()->run(100) );
01093 checkState( "x", tc);
01094 BOOST_CHECK_EQUAL( "STATE1", sm->getCurrentStateName() );
01095
01096 OperationCaller<void(void)> mo( tc->provides()->getOperation("v_event"), tc->engine());
01097 BOOST_REQUIRE( mo.ready() );
01098 mo();
01099 BOOST_CHECK( SimulationThread::Instance()->run(1) );
01100 checkState( "x", tc);
01101 BOOST_CHECK_EQUAL( "STATE2", sm->getCurrentStateName() );
01102
01103 BOOST_CHECK( SimulationThread::Instance()->run(100) );
01104 checkState( "x", tc);
01105 BOOST_CHECK_EQUAL( "STATE2", sm->getCurrentStateName() );
01106
01107 mo();
01108 BOOST_CHECK( SimulationThread::Instance()->run(1) );
01109 checkState( "x", tc);
01110 BOOST_CHECK_EQUAL( "FINI", sm->getCurrentStateName() );
01111 BOOST_CHECK( SimulationThread::Instance()->run(100) );
01112 checkState( "x", tc);
01113 BOOST_CHECK_EQUAL( "FINI", sm->getCurrentStateName() );
01114 this->checkState("x",tc);
01115 this->finishState("x", tc);
01116 }
01117
01118 BOOST_AUTO_TEST_CASE( testStateOperationSignalTransitionPriority )
01119 {
01120
01121 string prog = string("StateMachine X {\n")
01122 + " initial state INIT {\n"
01123 + " transitions { select STATE1 }\n"
01124 + " }\n"
01125 + " state STATE1 {\n"
01126 + " var double d;\n"
01127 + " transition v_event() select STATE2\n"
01128 + " transition v_event() select ERROR\n"
01129 + " transition o_event(d) select ERROR\n"
01130 + " transition v_event() select ERROR\n"
01131 + " }\n"
01132 + " state STATE2 {\n"
01133 + " transition v_event() select FINI\n"
01134 + " transition v_event() select ERROR\n"
01135 + " transition o_event(d) select ERROR\n"
01136 + " transition v_event() select ERROR\n"
01137 + " }\n"
01138 + " state ERROR {} \n"
01139 + " final state FINI {} \n"
01140 + "}\n"
01141 + "RootMachine X x()\n";
01142 this->parseState( prog, tc );
01143 StateMachinePtr sm = sa->getStateMachine("x");
01144 BOOST_REQUIRE( sm );
01145 sm->trace(true);
01146
01147 this->runState("x", tc);
01148 checkState( "x", tc);
01149 BOOST_CHECK_EQUAL( "STATE1", sm->getCurrentStateName() );
01150
01151 BOOST_CHECK( SimulationThread::Instance()->run(100) );
01152 checkState( "x", tc);
01153 BOOST_CHECK_EQUAL( "STATE1", sm->getCurrentStateName() );
01154
01155 OperationCaller<void(void)> mo( tc->provides()->getOperation("v_event"), tc->engine());
01156 OperationCaller<void(double)> mo2( tc->provides()->getOperation("o_event"), tc->engine());
01157 BOOST_REQUIRE( mo.ready() );
01158 mo();
01159 mo();
01160 mo2(3);
01161 mo2(3);
01162 BOOST_CHECK( SimulationThread::Instance()->run(1) );
01163 checkState( "x", tc);
01164 BOOST_CHECK_EQUAL( "STATE2", sm->getCurrentStateName() );
01165
01166 BOOST_CHECK( SimulationThread::Instance()->run(100) );
01167 checkState( "x", tc);
01168 BOOST_CHECK_EQUAL( "STATE2", sm->getCurrentStateName() );
01169
01170 mo();
01171 mo();
01172 mo2(3);
01173 mo2(3);
01174 BOOST_CHECK( SimulationThread::Instance()->run(1) );
01175 checkState( "x", tc);
01176 BOOST_CHECK_EQUAL( "FINI", sm->getCurrentStateName() );
01177 BOOST_CHECK( SimulationThread::Instance()->run(100) );
01178 checkState( "x", tc);
01179 BOOST_CHECK_EQUAL( "FINI", sm->getCurrentStateName() );
01180 this->checkState("x",tc);
01181 this->finishState("x", tc);
01182 }
01183
01184 BOOST_AUTO_TEST_CASE( testStateOperationSignalTransitionAround )
01185 {
01186
01187 string prog = string("StateMachine X {\n")
01188 + " initial state INIT {\n"
01189 + " transitions { select IDLE }\n"
01190 + " }\n"
01191 + " state IDLE {\n"
01192 + " transition v1_event() select STATE1\n"
01193 + " transition v2_event() select STATE2\n"
01194 + " transition v3_event() select STATE3\n"
01195 + " }\n"
01196 + " state STATE1 {\n"
01197 + " transition v_event() select IDLE\n"
01198 + " transition v2_event() select STATE2\n"
01199 + " transition v3_event() select STATE3\n"
01200 + " }\n"
01201 + " state STATE2 {\n"
01202 + " transition v_event() select IDLE\n"
01203 + " transition v1_event() select STATE1\n"
01204 + " transition v3_event() select STATE3\n"
01205 + " }\n"
01206 + " state STATE3 {\n"
01207 + " transition v_event() select IDLE\n"
01208 + " transition v1_event() select STATE1\n"
01209 + " transition v2_event() select STATE2\n"
01210 + " }\n"
01211 + " final state FINI {} \n"
01212 + "}\n"
01213 + "RootMachine X x()\n";
01214 this->parseState( prog, tc );
01215 StateMachinePtr sm = sa->getStateMachine("x");
01216 BOOST_REQUIRE( sm );
01217 this->runState("x", tc);
01218
01219 checkState( "x", tc);
01220 BOOST_CHECK_EQUAL( "IDLE", sm->getCurrentStateName() );
01221 BOOST_CHECK( SimulationThread::Instance()->run(100) );
01222 checkState( "x", tc);
01223 BOOST_CHECK_EQUAL( "IDLE", sm->getCurrentStateName() );
01224
01225 OperationCaller<void(void)> v( tc->provides()->getOperation("v_event"), tc->engine());
01226 BOOST_REQUIRE( v.ready() );
01227 OperationCaller<void(void)> v1( tc->provides()->getOperation("v1_event"), tc->engine());
01228 BOOST_REQUIRE( v1.ready() );
01229 OperationCaller<void(void)> v2( tc->provides()->getOperation("v2_event"), tc->engine());
01230 BOOST_REQUIRE( v2.ready() );
01231 OperationCaller<void(void)> v3( tc->provides()->getOperation("v3_event"), tc->engine());
01232 BOOST_REQUIRE( v3.ready() );
01233
01234 #define DO_EVENT(event, name) \
01235 event(); \
01236 BOOST_CHECK( SimulationThread::Instance()->run(1) ); \
01237 checkState( "x", tc); \
01238 BOOST_CHECK_EQUAL( name, sm->getCurrentStateName() ); \
01239 BOOST_CHECK( SimulationThread::Instance()->run(100) ); \
01240 checkState( "x", tc); \
01241 BOOST_CHECK_EQUAL( name, sm->getCurrentStateName() )
01242
01243 DO_EVENT(v2, "STATE2");
01244 DO_EVENT(v1, "STATE1");
01245 DO_EVENT(v1, "STATE1");
01246 DO_EVENT(v3, "STATE3");
01247 DO_EVENT(v, "IDLE");
01248 DO_EVENT(v3, "STATE3");
01249 DO_EVENT(v, "IDLE");
01250 DO_EVENT(v1, "STATE1");
01251
01252 #undef DO_EVENT
01253
01254 this->checkState("x",tc);
01255 this->finishState("x", tc);
01256 }
01257
01258 BOOST_AUTO_TEST_CASE( testStateOperationSignalTransitionProgram )
01259 {
01260 string prog = string("StateMachine X {\n")
01261 + " var double et = 0.0\n"
01262 + " initial state INIT {\n"
01263 + " transition o_event(et) { test.i = 5; } select FINI\n"
01264 + " }\n"
01265 + " final state FINI {} \n"
01266 + "}\n"
01267 + "RootMachine X x()\n";
01268 this->parseState( prog, tc );
01269 StateMachinePtr sm = sa->getStateMachine("x");
01270 BOOST_REQUIRE( sm );
01271
01272 this->runState("x", tc);
01273 checkState( "x", tc);
01274
01275 OperationCaller<void(double)> mo( tc->provides()->getOperation("o_event"), tc->engine());
01276 mo(3.33);
01277 mo(6.33);
01278 checkState( "x", tc);
01279 BOOST_CHECK( SimulationThread::Instance()->run(10) );
01280 BOOST_CHECK_EQUAL( i, 5 );
01281 checkState( "x", tc);
01282 BOOST_CHECK( sm->inState("FINI") );
01283 this->checkState("x",tc);
01284 this->finishState("x", tc);
01285 }
01286
01287 BOOST_AUTO_TEST_CASE( testStateOperationSignalGuard )
01288 {
01289 string prog = string("StateMachine X {\n")
01290 + " var double et = 0.0\n"
01291 + " initial state INIT {\n"
01292 + " transition o_event(et) if (et == 3.33) then \n"
01293 + " select FINI\n"
01294 + " else select FAIL\n"
01295 + " }\n"
01296 + " final state FINI {} \n"
01297 + " state FAIL {} \n"
01298 + "}\n"
01299 + "RootMachine X x()\n";
01300 this->parseState( prog, tc );
01301 StateMachinePtr sm = sa->getStateMachine("x");
01302 BOOST_REQUIRE( sm );
01303
01304 this->runState("x", tc);
01305 checkState( "x", tc);
01306
01307 OperationCaller<void(double)> mo( tc->provides()->getOperation("o_event") );
01308 mo(3.33);
01309 mo(6.33);
01310 checkState( "x", tc);
01311 BOOST_CHECK( SimulationThread::Instance()->run(10) );
01312 checkState( "x", tc);
01313 BOOST_CHECK( sm->inState("FINI") );
01314 this->checkState("x",tc);
01315 this->finishState("x", tc);
01316 }
01317
01318 BOOST_AUTO_TEST_CASE( testStateOperationCallerSignalGuard )
01319 {
01320 string prog = string("StateMachine X {\n")
01321 + " var double et = 0.0\n"
01322 + " initial state INIT {\n"
01323 + " transition caller.c_event(et) if (et == 3.33) then\n"
01324 + " select FINI\n"
01325 + " else select FAIL\n"
01326 + " }\n"
01327 + " final state FINI {} \n"
01328 + " state FAIL {} \n"
01329 + "}\n"
01330 + "RootMachine X x()\n";
01331 this->parseState( prog, tc );
01332 StateMachinePtr sm = sa->getStateMachine("x");
01333 BOOST_REQUIRE( sm );
01334
01335 this->runState("x", tc);
01336 checkState( "x", tc);
01337
01338 OperationCaller<void(double)> mo( caller->provides()->getOperation("c_event") );
01339 mo(3.33);
01340 checkState( "x", tc);
01341 BOOST_CHECK( SimulationThread::Instance()->run(1000) );
01342 checkState( "x", tc);
01343 BOOST_CHECK( sm->inState("FINI") );
01344 this->checkState("x",tc);
01345 this->finishState("x", tc);
01346 }
01347 #endif
01348
01349 BOOST_AUTO_TEST_CASE( testStateEvents)
01350 {
01351
01352 string prog = string("StateMachine Y {\n")
01353 + " var int t = 0\n"
01354 + " var double et = 0.0\n"
01355 + " var bool eb = false\n"
01356 + " var bool eflag = false\n"
01357 + " transition t_event(t) { do log(\"Global Transition to TESTSELF\");} select TESTSELF\n"
01358 + " transition d_event(et)\n"
01359 + " if et < 0. then { do log(\"Global ISNEGATIVE Transition\");} select ISNEGATIVE\n"
01360 + " else { do log(\"Global ISPOSITIVE Transition\");} select ISPOSITIVE\n"
01361 + " initial state INIT {\n"
01362 + " entry { do log(\"INIT\"); set eb = false; }\n"
01363 + " }\n"
01364 + " state ISNEGATIVE {\n"
01365 + " entry { do log(\"ISNEGATIVE\");}\n"
01366 + " transition b_event(eb)\n"
01367 + " if (eb) then { do log(\"Local ISNEGATIVE->INIT Transition\");} select INIT\n"
01368 + " }\n"
01369 + " state ISPOSITIVE {\n"
01370 + " entry { do log(\"ISPOSITIVE\");}\n"
01371 + " transition b_event(eb)\n"
01372 + " if (eb == true) then { do log(\"Local ISPOSITIVE->INIT Transition for b_event\");} select INIT\n"
01373 #ifdef ORO_SIGNALLING_OPERATIONS
01374 + " transition o_event(et)\n"
01375 + " if ( et == 3.0 ) then { do log(\"Local ISPOSITIVE->INIT Transition for o_event\");} select INIT\n"
01376 #endif
01377 + " }\n"
01378 + " state TESTSELF {\n"
01379 + " entry {\n"
01380 + " do log(\"TESTSELF\");\n"
01381 + " set eflag = !eflag\n"
01382 + " }\n"
01383 + " transition t_event(t) { do log(\"Self Transition in TESTSELF\");} select TESTSELF\n"
01384 + " transition b_event(eb)\n"
01385 + " if (eb == true) then { do log(\"Local TESTSELF->INIT Transition\");} select INIT\n"
01386 + " else { log(\"Failed to select INIT upon event.\");}\n"
01387 + " }\n"
01388 + " final state FINI {\n"
01389 + " entry { do log(\"FINI\");}\n"
01390 + " }\n"
01391 + " }\n"
01392 + string("StateMachine X {\n")
01393 + " SubMachine Y y1()\n"
01394 + " initial state INIT {\n"
01395 + " entry {\n"
01396 + " do y1.trace(true)\n"
01397 + " do y1.activate()\n"
01398 + " do y1.start()\n"
01399 + " do yield\n"
01400 + " }"
01401 + " run {\n"
01402
01403 + " do d_event_source.write(-1.0)\n"
01404 + " do nothing\n"
01405 + " do test.assert( !y1.inState(\"INIT\") )\n"
01406 + " do test.assert( !y1.inState(\"ISPOSITIVE\") )\n"
01407 + " do test.assert( y1.inState(\"ISNEGATIVE\") )\n"
01408 + " do b_event_source.write( true )\n"
01409 + " do yield\n"
01410 + " do test.assert( y1.inState(\"INIT\") )\n"
01411
01412 + " do d_event_source.write(+1.0)\n"
01413 + " do nothing\n"
01414 + " do test.assert( !y1.inState(\"INIT\") )\n"
01415 + " do test.assert( y1.inState(\"ISPOSITIVE\") )\n"
01416 + " do test.assert( !y1.inState(\"ISNEGATIVE\") )\n"
01417 + " if ( !y1.inState(\"ISPOSITIVE\") ) then\n"
01418 + " do test.assertMsg( false, \"Not ISNEGATIVE but \" + y1.getState() )\n"
01419 + " do test.assert( y1.inState(\"ISPOSITIVE\") )\n"
01420 + " do b_event_source.write( true )\n"
01421 + " do yield\n"
01422 + " do test.assert( y1.inState(\"INIT\") )\n"
01423 #ifdef ORO_SIGNALLING_OPERATIONS
01424
01425 + " do d_event_source.write(+1.0)\n"
01426 + " do nothing\n"
01427 + " do test.assert( !y1.inState(\"INIT\") )\n"
01428 + " do test.assert( y1.inState(\"ISPOSITIVE\") )\n"
01429 + " do test.assert( !y1.inState(\"ISNEGATIVE\") )\n"
01430 + " if ( !y1.inState(\"ISPOSITIVE\") ) then\n"
01431 + " do test.assertMsg( false, \"Not ISPOSITIVE but \" + y1.getState() )\n"
01432 + " do test.assert( y1.inState(\"ISPOSITIVE\") )\n"
01433 + " do o_event( 3.0 )\n"
01434 + " do yield\n"
01435 + " do test.assert( y1.inState(\"INIT\") )\n"
01436 #endif
01437
01438 + " set y1.eflag = true;\n"
01439 + " do t_event_source.write(1)\n"
01440 + " do nothing\n"
01441 + " do test.assert( !y1.inState(\"INIT\") )\n"
01442 + " do test.assert( !y1.inState(\"ISPOSITIVE\") )\n"
01443 + " do test.assert( !y1.inState(\"ISNEGATIVE\") )\n"
01444 + " do test.assert( y1.inState(\"TESTSELF\") )\n"
01445 + " do test.assert( y1.eflag == false ) /* first */\n"
01446 + " do t_event_source.write(1)\n"
01447 + " do nothing\n"
01448 + " do test.assert( y1.inState(\"TESTSELF\") )\n"
01449 + " do test.assert( y1.eflag == false ) /* second */\n"
01450 + " do log(\"Trigger b_event.\");\n"
01451 + " do b_event_source.write(true);\n"
01452 + " yield;\n"
01453 + " do test.assert( y1.inState(\"INIT\") ) /* last */\n"
01454 + " }\n"
01455 + " transitions {\n"
01456 + " select FINI\n"
01457 + " }\n"
01458 + " }\n"
01459 + " final state FINI {\n"
01460 + " entry {\n"
01461 + " do y1.deactivate()\n"
01462
01463 + " }\n"
01464 + " transitions {\n"
01465 + " select INIT\n"
01466 + " }\n"
01467 + " }\n"
01468 + " }\n"
01469 + " RootMachine X x() \n"
01470 ;
01471
01472 this->doState("x", prog, tc );
01473
01474 this->finishState( "x", tc);
01475 }
01476
01477 BOOST_AUTO_TEST_SUITE_END()
01478
01479 void StateTest::doState( const std::string& name, const std::string& prog, TaskContext* tc, bool test )
01480 {
01481 BOOST_CHECK( tc->engine() );
01482
01483 parseState( prog, tc, test);
01484 runState(name, tc, test);
01485 checkState(name, tc, test);
01486 }
01487
01488 void StateTest::parseState(const std::string& prog, TaskContext* tc, bool test )
01489 {
01490
01491 try {
01492 sa->loadStateMachines( prog, std::string("state_test.cpp"), true );
01493 }
01494 catch( const file_parse_exception& exc )
01495 {
01496 BOOST_REQUIRE_MESSAGE( !test, exc.what() );
01497 }
01498 catch( const parse_exception& exc )
01499 {
01500 BOOST_REQUIRE_MESSAGE( !test, exc.what() );
01501 }
01502 catch( const program_load_exception& e)
01503 {
01504 BOOST_REQUIRE_MESSAGE( !test, e.what() );
01505 }
01506 catch( const std::exception& e ) {
01507 BOOST_CHECK_MESSAGE( !test , e.what());
01508 BOOST_REQUIRE_MESSAGE( !test, "Uncaught Processor load exception" );
01509 }
01510 }
01511
01512 void StateTest::runState(const std::string& name, TaskContext* tc, bool test )
01513 {
01514 StateMachinePtr sm = sa->getStateMachine(name);
01515 BOOST_REQUIRE( sm );
01516 sm->trace(true);
01517 OperationCaller<bool(StateMachine*)> act = tc->provides(name)->getOperation("activate");
01518 OperationCaller<bool(StateMachine*)> autom = tc->provides(name)->getOperation("automatic");
01519 BOOST_CHECK( act(sm.get()) );
01520 BOOST_CHECK( SimulationThread::Instance()->run(1) );
01521 BOOST_CHECK_MESSAGE( sm->isActive(), "Error : Activate Command for '"+sm->getName()+"' did not have effect." );
01522 BOOST_CHECK( autom(sm.get()) || !test );
01523
01524 BOOST_CHECK( SimulationThread::Instance()->run(1000) );
01525 }
01526
01527 void StateTest::checkState(const std::string& name, TaskContext* tc, bool test )
01528 {
01529 StateMachinePtr sm = sa->getStateMachine(name);
01530 BOOST_REQUIRE( sm );
01531 if ( test ) {
01532
01533 BOOST_CHECK_MESSAGE( sm->isActive(), "Error : State Context '"+sm->getName()+"' did not get activated." );
01534 stringstream errormsg;
01535 int line = sm->getLineNumber();
01536 errormsg <<" in StateMachine "+sm->getName()
01537 <<" in state "<< (sm->currentState() ? sm->currentState()->getName() : "(null)")
01538 <<" on line " << line <<" of that StateMachine:"<<endl;
01539 {
01540 stringstream sctext( sm->getText() );
01541 int cnt = 1;
01542 while ( cnt++ <line && sctext ) {
01543 string garbage;
01544 getline( sctext, garbage, '\n' );
01545 }
01546 getline( sctext, sline, '\n' );
01547 }
01548 errormsg <<"here > " << sline << endl;
01549 if ( sm->inError() ) {
01550 RTT::scripting::DumpObject( tc->provides() );
01551 RTT::scripting::DumpObject( tc->provides(name) );
01552 }
01553 BOOST_CHECK_MESSAGE( sm->inError() == false, "Runtime error (inError() == true) encountered" + errormsg.str() );
01554
01555 StateMachine::ChildList cl = sm->getChildren();
01556 StateMachine::ChildList::iterator clit = cl.begin();
01557 while( clit != cl.end() ) {
01558 line = (*clit)->getLineNumber();
01559 {
01560 stringstream sctext( (*clit)->getText() );
01561 int cnt = 1;
01562 while ( cnt++ <line && sctext ) {
01563 string garbage;
01564 getline( sctext, garbage, '\n' );
01565 }
01566 getline( sctext, sline, '\n' );
01567 }
01568 stringstream cerrormsg;
01569 if ( (*clit)->currentState() )
01570 cerrormsg <<" in child "<< (*clit)->getName() <<" in state "<<(*clit)->currentState()->getName()<< " on line " << (*clit)->getLineNumber() <<" of that StateMachine."<<endl <<"here > " << sline << endl;
01571 else
01572 cerrormsg <<" child "<< (*clit)->getName() << " (deactivated) on line " << (*clit)->getLineNumber() <<" of that StateMachine."<<endl<<"here > " << sline << endl;
01573
01574 BOOST_CHECK_MESSAGE( (*clit)->inError() == false, "Runtime error (inError() == true) encountered" + cerrormsg.str() );
01575 if ( (*clit)->inError() == false && sm->inError() == true) {
01576 cout << "Child Status:" << cerrormsg.str() << endl;
01577 }
01578 ++clit;
01579 }
01580 }
01581 }
01582
01583 void StateTest::finishState(std::string const& name, TaskContext* tc, bool test)
01584 {
01585 StateMachinePtr sm = sa->getStateMachine(name);
01586 BOOST_REQUIRE( sm );
01587 BOOST_CHECK( sa->getStateMachine( name )->stop() );
01588 BOOST_CHECK( SimulationThread::Instance()->run(500) );
01589 if (test) {
01590 stringstream errormsg;
01591 errormsg << " on line " << sm->getLineNumber() <<", status is "<< sa->getStateMachineStatusStr(name) <<endl <<"here > " << sline << endl;;
01592 BOOST_CHECK_MESSAGE( sm->isStopped(), "StateMachine stalled " + errormsg.str() );
01593 }
01594
01595
01596 BOOST_CHECK( sa->getStateMachine( name )->deactivate() );
01597 BOOST_CHECK( SimulationThread::Instance()->run(200) );
01598 if ( sm->isActive() )
01599 BOOST_CHECK( sa->getStateMachine( name )->deactivate() );
01600 BOOST_CHECK( SimulationThread::Instance()->run(200) );
01601 BOOST_CHECK( sa->getStateMachine( name )->isActive() == false );
01602
01603
01604 tc->stop();
01605
01606 try {
01607 BOOST_CHECK( sa->unloadStateMachine( name ) );
01608 }
01609 catch( const program_unload_exception& e)
01610 {
01611 BOOST_REQUIRE_MESSAGE( false, e.what() );
01612 }
01613 catch( ... ) {
01614 BOOST_REQUIRE_MESSAGE( false, "Uncaught Processor unload exception" );
01615 }
01616
01617 }
01618