$search
00001 /*************************************************************************** 00002 * * 00003 * This program is free software; you can redistribute it and/or modify * 00004 * it under the terms of the GNU General Public License as published by * 00005 * the Free Software Foundation; either version 2 of the License, or * 00006 * (at your option) any later version. * 00007 * * 00008 ***************************************************************************/ 00009 00010 #include "unit.hpp" 00011 00012 #include <rtt-config.h> 00013 #include <extras/SimulationThread.hpp> 00014 #include <extras/SimulationActivity.hpp> 00015 #include <scripting/StateMachine.hpp> 00016 #include <scripting/ParsedStateMachine.hpp> 00017 #include <scripting/DumpObject.hpp> 00018 #include <scripting/Parser.hpp> 00019 00020 #include <Service.hpp> 00021 #include <TaskContext.hpp> 00022 #include <OperationCaller.hpp> 00023 #include <Port.hpp> 00024 #include <scripting/ScriptingService.hpp> 00025 #include "operations_fixture.hpp" 00026 00027 #include <string> 00028 #include <iostream> 00029 #include <sstream> 00030 00031 using namespace RTT; 00032 using namespace RTT::detail; 00033 using namespace std; 00034 00035 class StateTest 00036 : public OperationsFixture 00037 { 00038 public: 00039 Parser parser; 00040 ScriptingService::shared_ptr sa; 00041 00042 void doState(const std::string& name, const std::string& prog, TaskContext*, bool test=true ); 00043 void parseState( const std::string& prog, TaskContext*, bool test=true ); 00044 void runState(const std::string& name, TaskContext*, bool test=true ); 00045 void checkState( const std::string& name, TaskContext*, bool test=true ); 00046 void finishState( std::string const& name, TaskContext*, bool test=true ); 00047 00048 std::string sline; 00049 public: 00050 StateTest() 00051 : 00052 sa( ScriptingService::Create(tc) ) 00053 { 00054 tc->stop(); 00055 tc->setActivity( new SimulationActivity(0.001) ); 00056 00057 tc->start(); 00058 i = 0; 00059 SimulationThread::Instance()->stop(); 00060 } 00061 ~StateTest(){ 00062 } 00063 }; 00064 00065 BOOST_FIXTURE_TEST_SUITE( RtStringTestSuite, StateTest ) 00066 00067 BOOST_AUTO_TEST_CASE( testCreateRtString ) 00068 { 00069 string prog = string("StateMachine X {\n") 00070 + " initial state INIT {\n" 00071 + " var rt_string s1\n" 00072 + " transitions { select FINI }\n" 00073 + " }\n" 00074 + " final state FINI {\n" 00075 + " }\n" 00076 + " }\n" 00077 + " RootMachine X x\n" // instantiate a non hierarchical SC 00078 ; 00079 00080 this->doState("x", prog, tc ); 00081 this->finishState( "x", tc ); 00082 } 00083 00084 BOOST_AUTO_TEST_CASE( testCreateRtstringOfFixedSize ) 00085 { 00086 string prog = string("StateMachine X {\n") 00087 + " initial state INIT {\n" 00088 + " var rt_string s1(22)\n" 00089 + " transitions { select FINI }\n" 00090 + " }\n" 00091 + " final state FINI {\n" 00092 + " }\n" 00093 + " }\n" 00094 + " RootMachine X x\n" // instantiate a non hierarchical SC 00095 ; 00096 00097 this->doState("x", prog, tc ); 00098 this->finishState( "x", tc ); 00099 } 00100 00101 #if 0 00102 // this is incorrect syntax: 00103 BOOST_AUTO_TEST_CASE( testCreateRtstringFromCharPtr ) 00104 { 00105 string prog = string("StateMachine X {\n") 00106 + " initial state INIT {\n" 00107 + " var rt_string s1(\"hello world\")\n" 00108 + " transitions { select FINI }\n" 00109 + " }\n" 00110 + " final state FINI {\n" 00111 + " }\n" 00112 + " }\n" 00113 + " RootMachine X x\n" // instantiate a non hierarchical SC 00114 ; 00115 this->doState("x", prog, tc ); 00116 this->finishState( "x", tc ); 00117 } 00118 #endif 00119 00120 BOOST_AUTO_TEST_CASE( testCreateRtstringFromRtString ) 00121 { 00122 string prog = string("StateMachine X {\n") 00123 + " initial state INIT {\n" 00124 + " var rt_string s1 = rt_string(\"hello world\")\n" 00125 + " transitions { select FINI }\n" 00126 + " }\n" 00127 + " final state FINI {\n" 00128 + " }\n" 00129 + " }\n" 00130 + " RootMachine X x\n" // instantiate a non hierarchical SC 00131 ; 00132 00133 this->doState("x", prog, tc ); 00134 this->finishState( "x", tc ); 00135 } 00136 00137 BOOST_AUTO_TEST_CASE( testConcatRtstring ) 00138 { 00139 string prog = string("StateMachine X {\n") 00140 + " initial state INIT {\n" 00141 + " var rt_string s1\n" 00142 + " entry {\n" 00143 + " s1 = rt_string(\"Multiply \")\n" 00144 + " s1 = s1 + 10\n" 00145 + " s1 = s1 + rt_string(\" times \")\n" 00146 + " s1 = s1 + 33.3\n" 00147 + " s1 = rt_string(\"Now: \") + 1 + rt_string(\"st \") + s1 + '!'\n" 00148 + " }\n" 00149 + " transitions { select FINI }\n" 00150 + " }\n" 00151 + " final state FINI {\n" 00152 + " }\n" 00153 + " }\n" 00154 + " RootMachine X x\n" // instantiate a non hierarchical SC 00155 ; 00156 00157 this->doState("x", prog, tc ); 00158 this->finishState( "x", tc ); 00159 } 00160 00161 BOOST_AUTO_TEST_CASE( testRtstringConversion ) 00162 { 00163 string prog = string("StateMachine X {\n") 00164 + " initial state INIT {\n" 00165 + " var rt_string rts1\n" 00166 + " var string s1\n" 00167 + " entry {\n" 00168 + " s1 = \"s1\"\n" 00169 + " rts1 = rt_string(\"rts1\")\n" 00170 + " test.assert(s1 == \"s1\")\n" 00171 + " test.assert(rts1 == rt_string(\"rts1\"))\n" 00172 + " s1 = string(rts1)\n" 00173 + " test.assert(s1 == string(rts1))\n" 00174 + " test.assert(s1 == \"rts1\")\n" 00175 + " s1 = \"s1\"\n" 00176 + " rts1 = rt_string(s1)\n" 00177 + " test.assert(rts1 == rt_string(\"s1\"))\n" 00178 + " s1 = string( rt_string(\" s1 \") )\n" 00179 + " rts1 = rt_string( string(\" rts1 \") )\n" 00180 + " test.assert(s1 == \" s1 \")\n" 00181 + " test.assert(rts1 == rt_string(\" rts1 \"))\n" 00182 + " }\n" 00183 + " transitions { select FINI }\n" 00184 + " }\n" 00185 + " final state FINI {\n" 00186 + " }\n" 00187 + " }\n" 00188 + " RootMachine X x\n" // instantiate a non hierarchical SC 00189 ; 00190 00191 this->doState("x", prog, tc ); 00192 this->finishState( "x", tc ); 00193 } 00194 00195 00196 BOOST_AUTO_TEST_SUITE_END() 00197 00198 void StateTest::doState( const std::string& name, const std::string& prog, TaskContext* tc, bool test ) 00199 { 00200 BOOST_CHECK( tc->engine() ); 00201 00202 parseState( prog, tc, test); 00203 runState(name, tc, test); 00204 checkState(name, tc, test); 00205 } 00206 00207 void StateTest::parseState(const std::string& prog, TaskContext* tc, bool test ) 00208 { 00209 // Alternative way: test ScriptingService as well. 00210 try { 00211 sa->loadStateMachines( prog, std::string("state_test.cpp"), true ); 00212 } 00213 catch( const file_parse_exception& exc ) 00214 { 00215 BOOST_REQUIRE_MESSAGE( !test, exc.what() ); 00216 } 00217 catch( const parse_exception& exc ) 00218 { 00219 BOOST_REQUIRE_MESSAGE( !test, exc.what() ); 00220 } 00221 catch( const program_load_exception& e) 00222 { 00223 BOOST_REQUIRE_MESSAGE( !test, e.what() ); 00224 } 00225 catch( const std::exception& e ) { 00226 BOOST_CHECK_MESSAGE( !test , e.what()); 00227 BOOST_REQUIRE_MESSAGE( !test, "Uncaught Processor load exception" ); 00228 } 00229 } 00230 00231 void StateTest::runState(const std::string& name, TaskContext* tc, bool test ) 00232 { 00233 StateMachinePtr sm = sa->getStateMachine(name); 00234 BOOST_REQUIRE( sm ); 00235 sm->trace(true); 00236 OperationCaller<bool(StateMachine*)> act = tc->provides(name)->getOperation("activate"); 00237 OperationCaller<bool(StateMachine*)> autom = tc->provides(name)->getOperation("automatic"); 00238 BOOST_CHECK( act(sm.get()) ); 00239 BOOST_CHECK( SimulationThread::Instance()->run(1) ); 00240 BOOST_CHECK_MESSAGE( sm->isActive(), "Error : Activate Command for '"+sm->getName()+"' did not have effect." ); 00241 BOOST_CHECK( autom(sm.get()) || !test ); 00242 00243 BOOST_CHECK( SimulationThread::Instance()->run(1000) ); 00244 } 00245 00246 void StateTest::checkState(const std::string& name, TaskContext* tc, bool test ) 00247 { 00248 StateMachinePtr sm = sa->getStateMachine(name); 00249 BOOST_REQUIRE( sm ); 00250 if ( test ) { 00251 // check error status of parent : 00252 BOOST_CHECK_MESSAGE( sm->isActive(), "Error : State Context '"+sm->getName()+"' did not get activated." ); 00253 stringstream errormsg; 00254 int line = sm->getLineNumber(); 00255 errormsg <<" in StateMachine "+sm->getName() 00256 <<" in state "<< (sm->currentState() ? sm->currentState()->getName() : "(null)") 00257 <<" on line " << line <<" of that StateMachine:"<<endl; 00258 { 00259 stringstream sctext( sm->getText() ); 00260 int cnt = 1; 00261 while ( cnt++ <line && sctext ) { 00262 string garbage; 00263 getline( sctext, garbage, '\n' ); 00264 } 00265 getline( sctext, sline, '\n' ); 00266 } 00267 errormsg <<"here > " << sline << endl; 00268 if ( sm->inError() ) { 00269 RTT::scripting::DumpObject( tc->provides() ); 00270 RTT::scripting::DumpObject( tc->provides(name) ); 00271 } 00272 BOOST_CHECK_MESSAGE( sm->inError() == false, "Runtime error (inError() == true) encountered" + errormsg.str() ); 00273 // check error status of all children: 00274 StateMachine::ChildList cl = sm->getChildren(); 00275 StateMachine::ChildList::iterator clit = cl.begin(); 00276 while( clit != cl.end() ) { 00277 line = (*clit)->getLineNumber(); 00278 { 00279 stringstream sctext( (*clit)->getText() ); 00280 int cnt = 1; 00281 while ( cnt++ <line && sctext ) { 00282 string garbage; 00283 getline( sctext, garbage, '\n' ); 00284 } 00285 getline( sctext, sline, '\n' ); 00286 } 00287 stringstream cerrormsg; 00288 if ( (*clit)->currentState() ) 00289 cerrormsg <<" in child "<< (*clit)->getName() <<" in state "<<(*clit)->currentState()->getName()<< " on line " << (*clit)->getLineNumber() <<" of that StateMachine."<<endl <<"here > " << sline << endl; 00290 else 00291 cerrormsg <<" child "<< (*clit)->getName() << " (deactivated) on line " << (*clit)->getLineNumber() <<" of that StateMachine."<<endl<<"here > " << sline << endl; 00292 00293 BOOST_CHECK_MESSAGE( (*clit)->inError() == false, "Runtime error (inError() == true) encountered" + cerrormsg.str() ); 00294 if ( (*clit)->inError() == false && sm->inError() == true) { 00295 cout << "Child Status:" << cerrormsg.str() << endl; 00296 } 00297 ++clit; 00298 } 00299 } 00300 } 00301 00302 void StateTest::finishState(std::string const& name, TaskContext* tc, bool test) 00303 { 00304 StateMachinePtr sm = sa->getStateMachine(name); 00305 BOOST_REQUIRE( sm ); 00306 BOOST_CHECK( sa->getStateMachine( name )->stop() ); 00307 BOOST_CHECK( SimulationThread::Instance()->run(500) ); 00308 if (test) { 00309 stringstream errormsg; 00310 errormsg << " on line " << sm->getLineNumber() <<", status is "<< sa->getStateMachineStatusStr(name) <<endl <<"here > " << sline << endl;; 00311 BOOST_CHECK_MESSAGE( sm->isStopped(), "StateMachine stalled " + errormsg.str() ); 00312 } 00313 // you can call deactivate even when the proc is not running. 00314 // but deactivation may be 'in progress if exit state has commands in it. 00315 BOOST_CHECK( sa->getStateMachine( name )->deactivate() ); 00316 BOOST_CHECK( SimulationThread::Instance()->run(200) ); 00317 if ( sm->isActive() ) 00318 BOOST_CHECK( sa->getStateMachine( name )->deactivate() ); 00319 BOOST_CHECK( SimulationThread::Instance()->run(200) ); 00320 BOOST_CHECK( sa->getStateMachine( name )->isActive() == false ); 00321 00322 // only stop now, since deactivate won't work if simtask not running. 00323 tc->stop(); 00324 00325 try { 00326 BOOST_CHECK( sa->unloadStateMachine( name ) ); 00327 } 00328 catch( const program_unload_exception& e) 00329 { 00330 BOOST_REQUIRE_MESSAGE( false, e.what() ); 00331 } 00332 catch( ... ) { 00333 BOOST_REQUIRE_MESSAGE( false, "Uncaught Processor unload exception" ); 00334 } 00335 00336 }