00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
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
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
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& )
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
00106
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
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
00129 BOOST_AUTO_TEST_CASE(test_getProgramText)
00130 {
00131
00132
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
00143 BOOST_AUTO_TEST_CASE_EXPECTED_FAILURES(test_getProgramText_runScript, 1)
00144 BOOST_AUTO_TEST_CASE(test_getProgramText_runScript)
00145 {
00146
00147
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
00161
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)"
00183 + "}";
00184
00185 this->doProgram( prog, tc );
00186 this->finishProgram( tc, "x");
00187 }
00188
00189 BOOST_AUTO_TEST_CASE(testProgramFailure)
00190 {
00191
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
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"
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"
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"
00231 + " do test.fail() \n"
00232 + "do test.resetI()\n"
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
00238
00239 + "return "
00240 + "}";
00241 this->doProgram( prog, tc );
00242 this->finishProgram( tc, "x");
00243 }
00244
00245 BOOST_AUTO_TEST_CASE(testProgramBreak)
00246 {
00247
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"
00254 + " }\n"
00255 + "if test.i != 50 then \n"
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"
00264 + " }\n"
00265 + "if test.i != 50 then \n"
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"
00273 + " }\n"
00274 + " if test.i != 50 then \n"
00275 + " do test.fail() \n"
00276 + " if test.i == 50 then \n"
00277 + " break \n"
00278 + " do test.fail() \n"
00279 + " }\n"
00280 + "if test.i != 50 then \n"
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
00291 string prog = string("program x { \n")
00292 + "do test.resetI()\n"
00293
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
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
00311 + "for (var int j = 0; j != 100 ; j = test.increase() ) {\n"
00312 + "}\n"
00313 + "if test.i != 100 then \n"
00314 + " do test.fail() \n"
00315 + "if j != 100 then \n"
00316 + " do test.fail() \n"
00317 + "do test.resetI()\n"
00318
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
00333 + "while (test.increase() != 200) {\n"
00334 + " for (var int j3 = 0; j3 != 100 ; j3 = j3 + 1 ) {\n"
00335 + " }\n"
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
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
00356 + "for (var int j4 = 0; j4 != 100 ; j4 = j4 + 1 ) {\n"
00357 + " test.resetI()\n"
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
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"
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
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
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"
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
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"
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"
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"
00455 + " do y.step()\n"
00456 + " do yield\n"
00457 + " do y.step()\n"
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
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
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
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
00525 + "while (sh.collectIfDone(r) != SendSuccess)\n"
00526 + "yield \n"
00527 + "test.assertEqual( r , 2 )\n"
00528 + "set sh = test.increaseCmd.send()\n"
00529
00530 + "while (sh.collectIfDone(tvar_i) != SendSuccess)\n"
00531 + "yield \n"
00532 + "test.assertEqual( tvar_i, 3 )\n"
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
00571 loopProgram( pi );
00572 }
00573 }
00574
00575 void ProgramTest::loopProgram( ProgramInterfacePtr f)
00576 {
00577
00578
00579
00580
00581 int loops = 100;
00582 f->reset();
00583 while ( loops-- != 0 ) {
00584 while ( !f->isStopped() && !f->inError() )
00585 f->execute();
00586 f->reset();
00587
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 }