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 "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
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"
00114 + " initial state INIT {\n"
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
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"
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"
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"
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"
00195 + " }\n"
00196 + " }\n"
00197 + " }\n"
00198
00199 + " RootMachine X x( isten = 10, isok = true, isflse=false, isnegative = -1.0) \n"
00200 ;
00201
00202 this->doState("x", prog, tc );
00203 this->finishState( "x", tc );
00204 }
00205
00206 BOOST_AUTO_TEST_CASE( testStateFailure)
00207 {
00208
00209
00210
00211 string prog = string("StateMachine X {\n")
00212 + " initial state INIT {\n"
00213 + " entry {\n"
00214 + " do test.increase()\n"
00215 + " do test.assert( test.i != 1)\n"
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"
00245 ;
00246
00247
00248 const int max = 7;
00249 int x = 0;
00250 while ( i < max && x < max) {
00251 this->doState("x", prog, tc, false );
00252
00253
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
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"
00377 ;
00378
00379 this->doState("x", prog, tc );
00380 this->finishState( "x", tc);
00381 }
00382
00383 BOOST_AUTO_TEST_CASE( testStateEmpty)
00384 {
00385
00386 string prog = string("StateMachine X {\n")
00387 + " initial state INIT {\n"
00388 + " transitions {\n"
00389 + " select TEST;\n"
00390 + " }\n"
00391 + " }\n"
00392 + " state TEST {\n"
00393 + " }\n"
00394 + " final state FINI {\n"
00395 + " }\n"
00396 + " }\n"
00397 + " RootMachine X x\n"
00398 ;
00399 this->doState("x", prog, tc );
00400 this->finishState( "x", tc);
00401 }
00402
00403 BOOST_AUTO_TEST_CASE( testStateEmptyChild)
00404 {
00405
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
00429 string prog = string("StateMachine X {\n")
00430 + " initial state INIT {\n"
00431 + " var int i = 0;\n"
00432 + " var int j = 0;\n"
00433 + " var int k = 0;\n"
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"
00443 + " } select INIT\n"
00444 + " if i < 10 then {\n"
00445 + " set i = i + 1;\n"
00446 + " }\n"
00447 + " if i < 10 then {\n"
00448 + " } select TRANS_SHOULD_NOT_CHECK\n"
00449 + " if i == 10 then {\n"
00450 + " set i = i + 1;\n"
00451 + " } select TEST_ENTRY\n"
00452 + " }\n"
00453 + " }\n"
00454 + " state TEST_ENTRY {\n"
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"
00464 + " entry { do test.assert(false); }\n"
00465 + " }\n"
00466 + " state ENTRY_FAILED {\n"
00467 + " entry { do test.assert(false); }\n"
00468 + " }\n"
00469 + " state RUN_FAILED {\n"
00470 + " entry { do test.assert(false); }\n"
00471 + " }\n"
00472 + " final state FINI {\n"
00473 + " }\n"
00474 + " }\n"
00475 + " RootMachine X x\n"
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
00485 string prog = string("StateMachine X {\n")
00486 + " initial state INIT {\n"
00487 + " transitions {\n"
00488 + " if stop() == true then select NEXT\n"
00489 + " }\n"
00490 + " }\n"
00491 + " state NEXT {\n"
00492 + " entry { do test.assert(true); }\n"
00493 + " }\n"
00494 + " final state FINI {\n"
00495 + " entry { do test.assert(true); }\n"
00496 + " }\n"
00497 + " }\n"
00498 + " RootMachine X x\n"
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
00508 string prog = string("StateMachine X {\n")
00509 + " var int gi = 0;\n"
00510 + " transitions {\n"
00511
00512 + " if gi < 5 then {\n"
00513 + " set gi = gi + 1;\n"
00514 + " } select INIT\n"
00515
00516 + " if gi < 10 then {\n"
00517 + " if gi < 5 then do test.assert(false);\n"
00518 + " set gi = gi + 1;\n"
00519 + " }\n"
00520 + " if gi < 10 then {\n"
00521 + " do test.assert(false);\n"
00522 + " } select TRANS_SHOULD_NOT_CHECK\n"
00523 + " if gi >= 10 then {\n"
00524 + " } select FINI\n"
00525 + " }\n"
00526 + " initial state INIT {\n"
00527 + " var int i = 0;\n"
00528 + " var int j = 0;\n"
00529 + " var int k = 0;\n"
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"
00539 + " } select INIT\n"
00540 + " if i < 10 then {\n"
00541 + " set i = i + 1;\n"
00542 + " }\n"
00543 + " if i < 10 then {\n"
00544 + " } select TRANS_SHOULD_NOT_CHECK\n"
00545 + " }\n"
00546 + " }\n"
00547 + " state TRANS_SHOULD_NOT_CHECK {\n"
00548 + " entry { do test.assert(false); }\n"
00549 + " }\n"
00550 + " state ENTRY_FAILED {\n"
00551 + " entry { do test.assert(false); }\n"
00552 + " }\n"
00553 + " state RUN_FAILED {\n"
00554 + " entry { do test.assert(false); }\n"
00555 + " }\n"
00556 + " final state FINI {\n"
00557 + " }\n"
00558 + " }\n"
00559 + " RootMachine X x\n"
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
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"
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"
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"
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"
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"
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"
00633 + " }\n"
00634 + " }\n"
00635 + " }\n"
00636 + " RootMachine X x( isnegative = -1.0) \n"
00637 ;
00638
00639 this->doState("x", prog, tc );
00640 this->finishState( "x", tc);
00641 }
00642
00643 BOOST_AUTO_TEST_CASE( testStateSubStateCommands)
00644 {
00645
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
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")
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"
00689 + " }\n"
00690 + " do test.assert( y1.inState(\"INIT\") )\n"
00691 + " do y1.requestState(\"FINI\")\n"
00692 + " do test.assert( y1.inState(\"FINI\") )\n"
00693 + " }\n"
00694 + " exit {\n"
00695 + " do y1.requestState(\"INIT\")\n"
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"
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"
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
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"
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"
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
00767 this->runState("x", tc);
00768 checkState( "x", tc);
00769
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"
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
00795 this->runState("x", tc);
00796 checkState( "x", tc);
00797
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
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"
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"
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"
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"
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"
00852 + string("StateMachine X {\n")
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"
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"
00881 + " do yield\n"
00882 + " do test.assert( y1.inState(\"INIT\") )\n"
00883 #ifdef ORO_SIGNALLING_OPERATIONS
00884
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"
00894 + " do yield\n"
00895 + " do test.assert( y1.inState(\"INIT\") )\n"
00896 #endif
00897
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"
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
00923 + " }\n"
00924 + " transitions {\n"
00925 + " select INIT\n"
00926 + " }\n"
00927 + " }\n"
00928 + " }\n"
00929 + " RootMachine X x() \n"
00930 ;
00931
00932 this->doState("x", prog, tc );
00933
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
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
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
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
01055
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
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