$search
00001 /*************************************************************************** 00002 tag: Peter Soetens Mon Jan 10 15:59:51 CET 2005 program_test.cpp 00003 00004 program_test.cpp - description 00005 ------------------- 00006 begin : Mon January 10 2005 00007 copyright : (C) 2005 Peter Soetens 00008 email : peter.soetens@mech.kuleuven.ac.be 00009 00010 *************************************************************************** 00011 * * 00012 * This program is free software; you can redistribute it and/or modify * 00013 * it under the terms of the GNU General Public License as published by * 00014 * the Free Software Foundation; either version 2 of the License, or * 00015 * (at your option) any later version. * 00016 * * 00017 ***************************************************************************/ 00018 00019 00020 #include "unit.hpp" 00021 00022 #include <iostream> 00023 #include <sstream> 00024 #include <string> 00025 00026 #include <scripting/Parser.hpp> 00027 #include <scripting/FunctionGraph.hpp> 00028 #include <scripting/ScriptingService.hpp> 00029 #include <extras/SimulationThread.hpp> 00030 #include <extras/SimulationActivity.hpp> 00031 #include <Service.hpp> 00032 00033 #include <TaskContext.hpp> 00034 #include <OperationCaller.hpp> 00035 #include "operations_fixture.hpp" 00036 00037 using namespace RTT; 00038 using namespace RTT::detail; 00039 using namespace std; 00040 00041 00042 00043 class ProgramTest : public OperationsFixture 00044 { 00045 public: 00046 Parser parser; 00047 ScriptingService::shared_ptr sa; 00048 int var_i; 00049 int const_i; 00050 00051 void doProgram( const std::string& prog, TaskContext*, bool test=true ); 00052 void finishProgram( TaskContext* , std::string ); 00053 void loopProgram( ProgramInterfacePtr ); 00054 00055 ProgramTest() 00056 : sa( ScriptingService::Create(tc) ) 00057 { 00058 tc->stop(); 00059 BOOST_REQUIRE( tc->setActivity(new SimulationActivity(0.01)) ); 00060 BOOST_REQUIRE( tc->start() ); 00061 tc->provides()->addService( sa ); 00062 tc->provides()->addAttribute("tvar_i", var_i); 00063 tc->provides()->addConstant("tconst_i", const_i); 00064 // ltc has a test object 00065 00066 const_i = -1; 00067 var_i = -1; 00068 i = 0; 00069 SimulationThread::Instance()->stop(); 00070 } 00071 00072 ~ProgramTest() 00073 { 00074 } 00075 00076 }; 00077 00078 BOOST_FIXTURE_TEST_SUITE( ProgramTestSuite, ProgramTest ) 00079 // Registers the fixture into the 'registry' 00080 00081 BOOST_AUTO_TEST_CASE(testEmptyProgram) 00082 { 00083 string prog = ""; 00084 Parser::ParsedPrograms pg_list; 00085 try { 00086 pg_list = parser.parseProgram( prog, tc ); 00087 } 00088 catch( const file_parse_exception& /*exc*/ ) 00089 { 00090 BOOST_CHECK( false ); 00091 } 00092 if ( !pg_list.empty() ) 00093 { 00094 BOOST_CHECK( false ); 00095 } 00096 } 00097 00098 BOOST_AUTO_TEST_CASE(testReturnProgram) 00099 { 00100 string prog = "program x { return \n }"; 00101 this->doProgram( prog, tc ); 00102 this->finishProgram( tc, "x"); 00103 } 00104 00105 // check that loading a faulty program causes an exception 00106 // and that the program is not present as a service in tc 00107 BOOST_AUTO_TEST_CASE(testProgramError) 00108 { 00109 string prog = "program x { not_exist = 10\n }"; 00110 Parser::ParsedPrograms pg_list; 00111 BOOST_CHECK_THROW(pg_list = parser.parseProgram( prog, tc ),file_parse_exception); 00112 BOOST_CHECK( pg_list.empty() ); 00113 BOOST_REQUIRE( tc->provides()->hasService("x") == false); 00114 00115 BOOST_CHECK( sa->runScript(prog) == false); 00116 BOOST_REQUIRE( tc->provides()->hasService("x") == false); 00117 } 00118 00119 // same as above, but with runScript 00120 BOOST_AUTO_TEST_CASE(testrunScriptError) 00121 { 00122 string prog = "tvar_i = 33\n program x { not_exist = 10\n } \n tvar_i = 66\n"; 00123 BOOST_CHECK( sa->eval(prog) == false); 00124 BOOST_CHECK_EQUAL( var_i, 33 ); 00125 BOOST_REQUIRE( tc->provides()->hasService("x") == false); 00126 } 00127 00128 // tests if the text is properly saved 00129 BOOST_AUTO_TEST_CASE(test_getProgramText) 00130 { 00131 // a program which should never fail 00132 // test this methods. 00133 string prog = string("/** This is the test_getProgramText to parse */\nprogram x { \n") 00134 + " true\n" 00135 + "}"; 00136 00137 this->doProgram( prog, tc ); 00138 BOOST_CHECK_EQUAL( sa->getProgramText("x"), prog ); 00139 this->finishProgram( tc, "x"); 00140 } 00141 00142 // tests if the text is properly saved in runScript 00143 BOOST_AUTO_TEST_CASE_EXPECTED_FAILURES(test_getProgramText_runScript, 1) 00144 BOOST_AUTO_TEST_CASE(test_getProgramText_runScript) 00145 { 00146 // a program which should never fail 00147 // test this methods. 00148 string prog = string("/** This is the test_getProgramText_runScript to parse */\nprogram x { \n") 00149 + " true\n" 00150 + "}\n"; 00151 00152 string evaled = string("tvar_i = 33\n") + prog + "tvar_i = 66\n"; 00153 00154 BOOST_CHECK( sa->eval(evaled) == true); 00155 BOOST_CHECK_EQUAL( sa->getProgramText("x"), evaled + "\n" ); 00156 } 00157 00158 BOOST_AUTO_TEST_CASE(testParseProgram) 00159 { 00160 // a program which should never fail 00161 // test this methods. 00162 string prog = string("program x { \n") 00163 + " do true\n" 00164 + " do test.assert( true )\n" 00165 + " do test.increase()\n" 00166 + " do test.resetI()\n" 00167 + " do test.assert( test.isTrue( true ) )\n" 00168 + " do test.assert( test.i == 0 )\n" 00169 + " do test.increase()\n" 00170 + " do test.assert( test.i == 1 )\n" 00171 + " do test.resetI()\n" 00172 + " do test.assert( test.i == 0 )\n" 00173 + " if test.increase() + test.increase() + test.increase() != 6 then \n " 00174 + " do test.assert( false )\n" 00175 + " do test.assert( test.isTrue( true ) )\n" 00176 + " do test.resetI()\n" 00177 + " do test.assert( test.i == 0 )\n" 00178 + " if test.increase() + test.increase() + test.increase() != 6 then \n " 00179 + " do test.assert( false )\n" 00180 + " if true then\n" 00181 + " return\n" 00182 + " do test.assert(false)" // do not reach 00183 + "}"; 00184 00185 this->doProgram( prog, tc ); 00186 this->finishProgram( tc, "x"); 00187 } 00188 00189 BOOST_AUTO_TEST_CASE(testProgramFailure) 00190 { 00191 //also small test for program without newlines 00192 string prog = string("program x { do test.fail();}"); 00193 00194 this->doProgram( prog, tc, false ); 00195 00196 BOOST_CHECK( sa->getProgramStatus("x") == ProgramInterface::Status::error ); 00197 00198 this->finishProgram( tc, "x"); 00199 } 00200 BOOST_AUTO_TEST_CASE(testProgramCondition) 00201 { 00202 // see if checking a remote condition works 00203 string prog = string("program x { \n") 00204 + "if test.isTrue(true) then \n" 00205 + " do test.good() \n" 00206 + "else \n" 00207 + " do test.fail() \n" 00208 + "if test.isTrue(false) then \n" 00209 + " do test.fail() \n" 00210 + "else \n" 00211 + " do test.good() \n" 00212 + "if test.isTrue(true) then \n" //10 00213 + " if test.isTrue(true) then \n" 00214 + " if test.isTrue(false) then \n" 00215 + " do test.fail() \n" 00216 + " else \n" 00217 + " if test.isTrue(false) then \n" 00218 + " do test.fail() \n" 00219 + " else \n" 00220 + " do test.good() \n" 00221 + " else \n" 00222 + " do test.fail() \n" //20 00223 + "else \n" 00224 + " do test.fail() \n" 00225 + "var bool trig = false \n" 00226 + "do test.resetI()\n" 00227 + "while test.increase() != 100 && !trig \n" 00228 + " if test.i == 50 then \n" 00229 + " set trig = true \n" 00230 + "if test.i != 51 then \n" // the test.increase() will first increment i to 51, and then we detect trig. 00231 + " do test.fail() \n" 00232 + "do test.resetI()\n" //30 00233 + "set trig = false\n" 00234 + "for (var int j = 0; j != 100 && !trig ; set j = test.increase() )\n" 00235 + " if j == 50 then \n" 00236 + " set trig = true \n" 00237 // + "if test.i != 51 then \n" // require same result as with ISO C 00238 // + " do test.fail() \n" 00239 + "return " 00240 + "}"; 00241 this->doProgram( prog, tc ); 00242 this->finishProgram( tc, "x"); 00243 } 00244 00245 BOOST_AUTO_TEST_CASE(testProgramBreak) 00246 { 00247 // see if break statement works 00248 string prog = string("program x { \n") 00249 + "do test.resetI()\n" 00250 + "while (test.increase() != 100)\n" 00251 + " if test.i == 50 then {\n" 00252 + " break\n" 00253 + " do test.fail() \n" // do not reach. 00254 + " }\n" 00255 + "if test.i != 50 then \n" // break on 50 00256 + " do test.fail() \n" 00257 + "do test.resetI()\n" 00258 + "for (var int j = 0; j != 100 ; set j = test.increase() )\n" 00259 + " if j != 50 then \n" 00260 + " do nothing \n" 00261 + " else {\n" 00262 + " break \n" 00263 + " do test.fail() \n" // do not reach. 00264 + " }\n" 00265 + "if test.i != 50 then \n" // break on 50 00266 + " do test.fail() \n" 00267 + "do test.resetI()\n" 00268 + "while test.increase() != 100 {\n" 00269 + " while test.increase() != 100 \n" 00270 + " if test.i == 50 then {\n" 00271 + " break \n" 00272 + " do test.fail() \n" // do not reach. 00273 + " }\n" 00274 + " if test.i != 50 then \n" // break on 50 00275 + " do test.fail() \n" 00276 + " if test.i == 50 then \n" 00277 + " break \n" 00278 + " do test.fail() \n" // do not reach. 00279 + " }\n" 00280 + "if test.i != 50 then \n" // break on 50 00281 + " do test.fail() \n" 00282 + "return \n" 00283 + "}"; 00284 this->doProgram( prog, tc ); 00285 this->finishProgram( tc, "x"); 00286 } 00287 00288 BOOST_AUTO_TEST_CASE(testProgramLoops) 00289 { 00290 // see if (nested) loop statements work 00291 string prog = string("program x { \n") 00292 + "do test.resetI()\n" 00293 // single while loop 00294 + "while (test.increase() != 100) {\n" 00295 + "}\n" 00296 + "if test.i != 100 then \n" 00297 + " do test.fail() \n" 00298 + "do test.resetI()\n" 00299 // double while loop 00300 + "while (test.increase() != 200) {\n" 00301 + " while (test.i < 100) {\n" 00302 + " test.increase()\n" 00303 + " }\n" 00304 + " if test.i < 100 then \n" 00305 + " do test.fail() \n" 00306 + "}\n" 00307 + "if test.i != 200 then \n" 00308 + " do test.fail() \n" 00309 + "do test.resetI()\n" 00310 // single for loop 00311 + "for (var int j = 0; j != 100 ; j = test.increase() ) {\n" 00312 + "}\n" 00313 + "if test.i != 100 then \n" // 20 00314 + " do test.fail() \n" 00315 + "if j != 100 then \n" 00316 + " do test.fail() \n" 00317 + "do test.resetI()\n" 00318 // double for loop 00319 + "for ( j = 0; j != 100 ; j = test.increase() ) {\n" 00320 + " for (var int j2 = 0; j2 != 100 ; j2 = j2 + 1 ) {\n" 00321 + " }\n" 00322 + " if j2 != 100 then \n" 00323 + " do test.fail() \n" 00324 + "}\n" 00325 + "if test.i != 100 then \n" 00326 + " do test.fail() \n" 00327 + "if j != 100 then \n" 00328 + " do test.fail() \n" 00329 + "if j2 != 100 then \n" 00330 + " do test.fail() \n" 00331 + "do test.resetI()\n" 00332 // for loop in while loop 00333 + "while (test.increase() != 200) {\n" 00334 + " for (var int j3 = 0; j3 != 100 ; j3 = j3 + 1 ) {\n" 00335 + " }\n" // 40 00336 + "}\n" 00337 + "if test.i != 200 then \n" 00338 + " do test.fail() \n" 00339 + "if j3 != 100 then \n" 00340 + " do test.fail() \n" 00341 + "do test.resetI()\n" 00342 // for loop in while loop + break in for 00343 + "while (test.increase() != 200) {\n" 00344 + " for (var int j3b = 0; j3b != 100 ; j3b = j3b + 1 ) {\n" 00345 + " if j3b == 50 then break \n" 00346 + " }\n" 00347 + " if j3b != 50 then \n" 00348 + " do test.fail() \n" 00349 + "}\n" 00350 + "if test.i != 200 then \n" 00351 + " do test.fail() \n" 00352 + "if j3b != 50 then \n" 00353 + " do test.fail() \n" 00354 + "do test.resetI()\n" 00355 // while loop in for loop 00356 + "for (var int j4 = 0; j4 != 100 ; j4 = j4 + 1 ) {\n" 00357 + " test.resetI()\n" // 60 00358 + " while (test.increase() != 200) {\n" 00359 + " }\n" 00360 + "}\n" 00361 + "if test.i != 200 then \n" 00362 + " do test.fail() \n" 00363 + "if j4 != 100 then \n" 00364 + " do test.fail() \n" 00365 + "do test.resetI()\n" 00366 // while loop in for loop + break in while 00367 + "for (var int j5 = 0; j5 != 100 ; j5 = j5 + 1 ) {\n" 00368 + " test.resetI()\n" 00369 + " while (test.increase() != 200) {\n" 00370 + " if test.i == 50 then break \n" 00371 + " }\n" 00372 + " if test.i != 50 then test.fail() \n" 00373 + "}\n" 00374 + "if test.i != 50 then \n" 00375 + " do test.fail() \n" 00376 + "if j5 != 100 then {\n" 00377 + " do test.print(\" j5 is:\" + j5 ) \n" 00378 + " do test.fail() \n" // 80 00379 + " }\n" 00380 + "do test.resetI()\n" 00381 + "}"; 00382 this->doProgram( prog, tc ); 00383 this->finishProgram( tc, "x"); 00384 } 00385 00386 BOOST_AUTO_TEST_CASE(testProgramAnd) 00387 { 00388 // see if checking a remote condition works 00389 string prog = string("program x { do test.good()\n") 00390 + " && test.good() \n" 00391 + " && test.good() \n" 00392 + " }"; 00393 this->doProgram( prog, tc ); 00394 this->finishProgram( tc, "x"); 00395 } 00396 00397 BOOST_AUTO_TEST_CASE(testProgramTry) 00398 { 00399 // see if checking a remote condition works 00400 string prog = string("program progtry { try test.fail()\n") 00401 + "try test.good() \n" 00402 + " && test.fail() \n" 00403 + " && test.good() \n" 00404 + "try test.good() \n" 00405 + " && test.fail() \n" 00406 + "try test.good() \n" 00407 + " && test.fail() \n" 00408 + " && test.fail() catch { \n" 00409 + " try test.good() \n" 00410 + " && test.good() \n" 00411 + " && test.good() catch {\n" 00412 + " do test.fail()\n" 00413 + " }\n" 00414 + "}\n" 00415 + "do test.resetI() \n" 00416 + "try test.good() \n" 00417 + " && test.fail() \n" 00418 + " && test.good() catch { \n" 00419 + " do test.increase()\n" 00420 + "}\n" 00421 + "if test.i == 0 then\n" // check if catch was reached 00422 + " do test.fail()\n" 00423 + "}"; 00424 this->doProgram( prog, tc ); 00425 this->finishProgram( tc, "progtry"); 00426 } 00427 00428 BOOST_AUTO_TEST_CASE(testProgramToProgram) 00429 { 00430 // test a program which starts/stops another program. 00431 string prog = string("program y { do test.good() \n") 00432 + " do test.resetI()\n" 00433 + " do test.assert( test.i == 0 )\n" 00434 + "}"; 00435 00436 string prog2 = string("program x {\n") 00437 + " do test.assert( test.i == 0 )\n" 00438 + " do test.increase()\n" 00439 + " do test.assert( test.i == 1 )\n" 00440 + " do y.start()\n" // test start-stop 00441 + " do yield\n" 00442 + " do test.assert( test.i == 0 )\n" 00443 + " do y.stop()\n" 00444 + " do test.increase()\n" 00445 + " do y.pause()\n" // test pause-step // 10 00446 + " do yield\n" 00447 + " do test.assert( y.isPaused() )\n" 00448 + " do test.assert( test.i == 1 )\n" 00449 + " do y.step()\n" 00450 + " do yield\n" 00451 + " do test.assert( test.i == 1 )\n" 00452 + " do y.step()\n" 00453 + " do yield\n" 00454 + " do test.assertEqual( test.i, 0 )\n" // if this fails, stepping is broken 00455 + " do y.step()\n" 00456 + " do yield\n" 00457 + " do y.step()\n" // 20 00458 + " do yield\n" 00459 + " do test.assert( !y.isRunning() )\n" 00460 + "}"; 00461 00462 this->doProgram( prog, tc ); 00463 this->doProgram( prog2, tc ); 00464 this->finishProgram( tc, "x"); 00465 this->finishProgram( tc, "y"); 00466 } 00467 00468 BOOST_AUTO_TEST_CASE(testProgramCallFoo) 00469 { 00470 // see if modifying an attribute works. 00471 string prog = string("export function foo {\n") 00472 + " do test.assert( tvar_i == +2 ) \n" 00473 + " do test.assert( tvar_i != tconst_i ) \n" 00474 + " set tvar_i = +4\n" 00475 + " do test.assert( tvar_i == +4 ) \n" 00476 + "}\n" 00477 + "program x { \n" 00478 + "do test.assert( tvar_i == -1 ) \n" 00479 + "do test.assert( tvar_i == tconst_i ) \n" 00480 + "set tvar_i = +2\n" 00481 + "do test.assert( tvar_i == +2 )\n" 00482 + "call foo()\n" 00483 + "}"; 00484 this->doProgram( prog, tc ); 00485 Attribute<int> i = tc->provides()->getAttribute("tvar_i"); 00486 BOOST_REQUIRE_EQUAL( 4, i.get() ); 00487 this->finishProgram( tc, "x"); 00488 } 00489 00490 BOOST_AUTO_TEST_CASE(testProgramDoFoo) 00491 { 00492 // see if modifying an attribute works. 00493 string prog = string("export function foo {\n") 00494 + " do test.assert( tvar_i == +2 ) \n" 00495 + " do test.assert( tvar_i != tconst_i ) \n" 00496 + " set tvar_i = +4\n" 00497 + " do test.assert( tvar_i == +4 ) \n" 00498 + "}\n" 00499 + "program x { \n" 00500 + "do test.assert( tvar_i == -1 ) \n" 00501 + "do test.assert( tvar_i == tconst_i ) \n" 00502 + "set tvar_i = +2\n" 00503 + "do test.assert( tvar_i == +2 )\n" 00504 + "do foo()\n" 00505 + "}"; 00506 this->doProgram( prog, tc ); 00507 Attribute<int> i = tc->provides()->getAttribute("tvar_i"); 00508 BOOST_REQUIRE_EQUAL( 4, i.get() ); 00509 this->finishProgram( tc, "x"); 00510 } 00511 00512 BOOST_AUTO_TEST_CASE(testSend) 00513 { 00514 // see if modifying an attribute works. 00515 string prog = string("") 00516 + "program x { \n" 00517 + "test.assertEqual( test.i, 0 )\n" 00518 + "test.increaseCmd.send() \n" 00519 + "yield \n" 00520 + "test.assertEqual( test.i, 1 )\n" 00521 + "var SendHandle sh\n" 00522 + "set sh = test.increaseCmd.send()\n" 00523 + "var int r = 0\n" 00524 //+ "sh.collect(r)\n" // hangs 00525 + "while (sh.collectIfDone(r) != SendSuccess)\n" 00526 + "yield \n" 00527 + "test.assertEqual( r , 2 )\n" 00528 + "set sh = test.increaseCmd.send()\n" 00529 //+ "sh.collect(tvar_i)\n" // hangs 00530 + "while (sh.collectIfDone(tvar_i) != SendSuccess)\n" 00531 + "yield \n" 00532 + "test.assertEqual( tvar_i, 3 )\n" // i is 3 but r isn't. 00533 + "}"; 00534 this->doProgram( prog, tc ); 00535 BOOST_REQUIRE_EQUAL( i, 3 ); 00536 BOOST_REQUIRE_EQUAL( var_i, 3 ); 00537 this->finishProgram( tc, "x"); 00538 } 00539 00540 BOOST_AUTO_TEST_SUITE_END() 00541 00542 void ProgramTest::doProgram( const std::string& prog, TaskContext* tc, bool test ) 00543 { 00544 BOOST_CHECK( tc->engine() ); 00545 00546 Parser::ParsedPrograms pg_list; 00547 try { 00548 pg_list = parser.parseProgram( prog, tc ); 00549 } 00550 catch( const file_parse_exception& exc ) 00551 { 00552 BOOST_REQUIRE_MESSAGE( false, exc.what() ); 00553 } 00554 if ( pg_list.empty() ) 00555 { 00556 BOOST_REQUIRE_MESSAGE( false, "No program could be found by the parser." ); 00557 } 00558 ProgramInterfacePtr pi = *pg_list.begin(); 00559 00560 sa->loadProgram( pi ); 00561 BOOST_CHECK( pi->start() ); 00562 BOOST_CHECK( SimulationThread::Instance()->run(1000) ); 00563 00564 if (test ) { 00565 stringstream errormsg; 00566 errormsg << " on line " << pi->getLineNumber() <<"."<<endl; 00567 BOOST_REQUIRE_MESSAGE( pi->getStatus() != ProgramInterface::Status::error , "Runtime error encountered" + errormsg.str()); 00568 BOOST_CHECK_MESSAGE( pi->getStatus() == ProgramInterface::Status::stopped , "Program stalled " + errormsg.str()); 00569 00570 // Xtra test, only do it if all previous went ok : 00571 loopProgram( pi ); 00572 } 00573 } 00574 00575 void ProgramTest::loopProgram( ProgramInterfacePtr f) 00576 { 00577 //std::cerr <<std::endl<< "Looping " << f->getName(); 00578 // especially handy for performance testing : 00579 // This bypasses the processor however, does not 00580 // measure its performance. 00581 int loops = 100; 00582 f->reset(); 00583 while ( loops-- != 0 ) { 00584 while ( !f->isStopped() && !f->inError() ) 00585 f->execute(); 00586 f->reset(); 00587 //std::cerr << "."; 00588 } 00589 } 00590 00591 00592 void ProgramTest::finishProgram(TaskContext* tc, std::string prog_name) 00593 { 00594 BOOST_REQUIRE( sa->getProgram(prog_name) ); 00595 BOOST_CHECK( sa->getProgram( prog_name )->stop() ); 00596 BOOST_CHECK( sa->unloadProgram( prog_name ) ); 00597 00598 }