00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "unit.hpp"
00021 #include "operations_fixture.hpp"
00022
00023
00024 #include <scripting/Parser.hpp>
00025 #include <scripting/FunctionGraph.hpp>
00026 #include <scripting/ScriptingService.hpp>
00027 #include <Service.hpp>
00028 #include <OperationCaller.hpp>
00029
00030 class FunctionsFixture : public OperationsFixture
00031 {
00032 public:
00033 FunctionsFixture()
00034 : sa( ScriptingService::Create(tc) )
00035 {
00036 tc->stop();
00037 tc->setActivity(new SimulationActivity(0.01));
00038 SimulationThread::Instance()->stop();
00039 tc->start();
00040 }
00041 Parser parser;
00042 ScriptingService::shared_ptr sa;
00043
00044 void doFunction( const std::string& prog, TaskContext*, bool test=true );
00045 void finishFunction( TaskContext* , std::string );
00046 void loopProgram( ProgramInterfacePtr );
00047 };
00048
00049 BOOST_FIXTURE_TEST_SUITE( FunctionsFixtureSuite, FunctionsFixture )
00050
00051
00052 BOOST_AUTO_TEST_CASE( testSimpleFunction)
00053 {
00054 string prog = string("function foo { \n")
00055 + " do test.assert( test.isTrue( true ) )\n"
00056 + "}\n"
00057 + "program x { \n"
00058 + " call foo\n"
00059 + "}";
00060
00061 this->doFunction( prog, tc );
00062 this->finishFunction( tc, "x");
00063 }
00064
00065 BOOST_AUTO_TEST_CASE( testSimpleReturnFunction)
00066 {
00067 string prog = string("int foo { \n")
00068 + " test.assert( test.isTrue( true ) )\n"
00069 + " return 3\n"
00070 + "}\n"
00071 + "\n"
00072 + "program x { \n"
00073 + " test.assert(true);\n"
00074 + " call foo\n"
00075 + " test.assert(true);\n"
00076 + "}";
00077
00078 this->doFunction( prog, tc );
00079 this->finishFunction( tc, "x");
00080 }
00081
00082 BOOST_AUTO_TEST_CASE( testExportFunction)
00083 {
00084 string prog = string("export function foo { \n")
00085 + " do test.assert( test.isTrue( true ) )\n"
00086 + "}\n"
00087 + "export function foo_args() { \n"
00088 + " do test.assert( test.isTrue( true ) )\n"
00089 + "}\n"
00090 + "program x { \n"
00091 + " do this.foo()\n"
00092 + " do this.foo_args()\n"
00093 + "}";
00094
00095 this->doFunction( prog, tc );
00096 BOOST_CHECK( tc->getOperation("foo") );
00097 this->finishFunction( tc, "x");
00098 }
00099
00100 #ifdef ORO_REMOTING
00101
00107 BOOST_AUTO_TEST_CASE( testOnlyExportFunction)
00108 {
00109 string prog = string("export function foo { \n")
00110
00111 + " do test.assert( test.isTrue( true ) )\n"
00112 + "}\n"
00113 + "export int foo_ret(double d) { \n"
00114
00115 + " if (true) then\n"
00116 + " return 3\n"
00117 + " else\n"
00118 + " return 5\n"
00119 + "}\n"
00120 + "export int foo_args(double d, int v) { \n"
00121
00122 + " var double r = 10\n"
00123 + " if ( d == 3.0 && v == 6) then\n"
00124 + " set r = +1\n"
00125 + " else\n"
00126 + " set r = -1\n"
00127 + " return r;\n"
00128 + "}\n";
00129
00130 this->doFunction( prog, tc );
00131 BOOST_CHECK( tc->getOperation("foo") );
00132
00133
00134 {
00135 OperationCaller<void(void)> foo( tc->getOperation("foo"), caller->engine());
00136 BOOST_CHECK( foo.ready() );
00137
00138 foo();
00139 }
00140 #if 0
00141
00142 {
00143 OperationCaller<void(void)> foo( tc->getOperation("foo"), caller->engine());
00144 BOOST_CHECK( foo.ready() );
00145
00146 foo.send();
00147 }
00148
00149
00150 {
00151 OperationCaller<void(void)> foo( tc->getOperation("foo"), caller->engine());
00152 BOOST_CHECK( foo.ready() );
00153
00154 SendHandle<void(void)> sh = foo.send();
00155 BOOST_CHECK_EQUAL( sh.collect(), SendSuccess);
00156 }
00157 #endif
00158
00159 {
00160 OperationCaller<int(double)> foo_ret( tc->getOperation("foo_ret"), caller->engine());
00161 BOOST_CHECK( foo_ret.ready() );
00162
00163 int i = 0;
00164 i = foo_ret(3.0);
00165 BOOST_CHECK_EQUAL( i, 3 );
00166 }
00167 #if 0
00168
00169 {
00170 OperationCaller<int(double)> foo_ret( tc->getOperation("foo_ret"), caller->engine());
00171 BOOST_CHECK( foo_ret.ready() );
00172
00173 int i = 0;
00174 foo_ret.send(3.0);
00175 }
00176
00177
00178 {
00179 OperationCaller<int(double)> foo_ret( tc->getOperation("foo_ret"), caller->engine());
00180 BOOST_CHECK( foo_ret.ready() );
00181
00182 int i = 0;
00183 SendHandle<int(double)> sh = foo_ret.send(3.0);
00184 BOOST_CHECK_EQUAL( sh.collect(i), SendSuccess);
00185 BOOST_CHECK_EQUAL( i, 3 );
00186 }
00187 #endif
00188
00189 {
00190 BOOST_CHECK( tc->getOperation("foo_args") );
00191 OperationCaller<int(double,int)> foo_args( tc->getOperation("foo_args"), caller->engine());
00192 BOOST_CHECK( foo_args.ready() );
00193
00194 int i = 0;
00195 i = foo_args(-3.0, -6);
00196 BOOST_CHECK_EQUAL( i, -1);
00197
00198 i = 0;
00199 i = foo_args(3.0, 6);
00200 BOOST_CHECK_EQUAL( i, +1);
00201 }
00202 #if 0
00203
00204 {
00205 BOOST_CHECK( tc->getOperation("foo_args") );
00206 OperationCaller<int(double,int)> foo_args( tc->getOperation("foo_args"), caller->engine());
00207 BOOST_CHECK( foo_args.ready() );
00208
00209 foo_args.send(-3.0, -6);
00210 foo_args.send(3.0, 6);
00211 }
00212
00213
00214 {
00215 BOOST_CHECK( tc->getOperation("foo_args") );
00216 OperationCaller<int(double,int)> foo_args( tc->getOperation("foo_args"), caller->engine());
00217 BOOST_CHECK( foo_args.ready() );
00218
00219 int i = 0;
00220 SendHandle<int(double,int)> sh = foo_args.send(-3.0, -6);
00221 BOOST_CHECK_EQUAL( sh.collect(i), SendSuccess);
00222 BOOST_CHECK_EQUAL( i, -1);
00223
00224 i = 0;
00225 sh = foo_args.send(3.0, 6);
00226 BOOST_CHECK_EQUAL( sh.collect(i), SendSuccess);
00227 BOOST_CHECK_EQUAL( i, +1);
00228 }
00229 #endif
00230 }
00231 #endif
00232
00236 BOOST_AUTO_TEST_CASE( testReturnExportFunction)
00237 {
00238 string prog = string("export function foo { \n")
00239 + " do test.assert( test.isTrue( true ) )\n"
00240 + "}\n"
00241 + "export int foo_ret() { \n"
00242 + " if (true) then\n"
00243 + " return 3\n"
00244 + " else\n"
00245 + " return 5\n"
00246 + "}\n"
00247 + "export int foo_args(double d, int v) { \n"
00248 + " do test.assert( test.isTrue( true ) )\n"
00249 + " if ( d == 3.0 && v == 6) then\n"
00250 + " return +1\n"
00251 + " else\n"
00252 + " return -1\n"
00253 + " return 4\n"
00254 + "}\n"
00255 + "program x { \n"
00256 + " this.foo()\n"
00257 + " this.foo_ret()\n"
00258 + " this.foo_args(3.0,6)\n"
00259 + " test.assertEqual(this.foo_ret(), 3 )\n"
00260 + " test.assertEqual(this.foo_args(3.0,6), 1)\n"
00261 + " test.assertEqual(this.foo_args(0.0,0), -1)\n"
00262 + "}";
00263
00264 this->doFunction( prog, tc );
00265 BOOST_CHECK( tc->getOperation("foo") );
00266 this->finishFunction( tc, "x");
00267 }
00268
00269 #if 0
00270
00271 BOOST_AUTO_TEST_CASE( testRemoveFunction)
00272 {
00273 string prog = string("export function foo { \n")
00274 + " while (true) { do nothing }\n"
00275 + "}\n"
00276 + "program x { \n"
00277 + " this.foo()\n"
00278
00279 + "}";
00280
00281 this->doFunction( prog, tc, false );
00282 BOOST_CHECK( tc->getOperation("foo") );
00283
00284 this->finishFunction( tc, "x");
00285 }
00286 #endif
00287 BOOST_AUTO_TEST_CASE( testRecFunction)
00288 {
00289 string prog = string("export function foo { \n")
00290 + " do this.foo()\n"
00291 + "}\n"
00292 + "program x { \n"
00293 + " do foo\n"
00294 + "}";
00295
00296 try {
00297 parser.parseProgram( prog, tc );
00298 }
00299 catch( ... )
00300 {
00301 prog = string("function foo { \n")
00302 + " call foo\n"
00303 + "}\n"
00304 + "program x { \n"
00305 + " call foo\n"
00306 + "}";
00307
00308 try {
00309 parser.parseProgram( prog, tc );
00310 }
00311 catch( ... )
00312 {
00313 return;
00314 }
00315 BOOST_CHECK_MESSAGE( false, "Recursive 'call' function was accepted, while it is illegal." );
00316 }
00317 BOOST_CHECK_MESSAGE( false , "Recursive 'do' function was accepted, while it is illegal.");
00318 }
00319
00320 BOOST_AUTO_TEST_CASE( testCallFunction)
00321 {
00322 string prog = string("function foo(int a, string b, bool c) { \n")
00323 + " do test.assert( test.isTrue( true ) )\n"
00324 + " if true then\n"
00325 + " return\n"
00326 + " do test.assert(false)\n"
00327 + "}\n"
00328 + "program x { \n"
00329 + " call foo( 1, \"hello\", true)\n"
00330 + "}";
00331
00332 this->doFunction( prog, tc );
00333 this->finishFunction( tc, "x");
00334 }
00335
00336 BOOST_AUTO_TEST_CASE( testFunctionStack)
00337 {
00338 string prog = string("export function foo { \n")
00339 +" var double a = 1.234\n"
00340 +" var double b = 4.321\n"
00341 +" do test.assert( a == 1.234 )\n"
00342 +" do test.assert( b == 4.321 )\n"
00343 +" set a = 2.134\n"
00344 +" set b = 3.421\n"
00345 +" do test.assert( a == 2.134 )\n"
00346 +" do test.assert( b == 3.421 )\n"
00347 + "}\n"
00348 + "program x { \n"
00349 +" var double b = 1.234\n"
00350 +" var double a = 4.321\n"
00351 + " do foo()\n"
00352 +" do test.assert( b == 1.234 )\n"
00353 +" do test.assert( a == 4.321 )\n"
00354 + " do foo()\n"
00355 + " set a = 0.0\n"
00356 + " set b = 1.0\n"
00357 +" do test.assert( b == 1.0 )\n"
00358 +" do test.assert( a == 0.0 )\n"
00359 + "}";
00360
00361 this->doFunction( prog, tc );
00362 this->finishFunction( tc, "x");
00363 }
00364
00365
00366 BOOST_AUTO_TEST_CASE( testFunctionExportArgs)
00367 {
00368
00369 string prog =
00370 string("export function fooA(int a, string b, bool c) { \n")
00371 + " do test.assertMsg( c, \"c not true\" )\n"
00372 + " do test.assertMsg( a == 1, \"a not 1\" )\n"
00373 + " do test.assertMsg( b == \"A\", \"b not A\" )\n"
00374 + "}\n"
00375 + "export function fooB(int a, string b, bool c) { \n"
00376 + " do test.assertMsg( !c, \"c not false\" )\n"
00377 + " do test.assertMsg( a == -1, \"a not -1\" )\n"
00378 + " do test.assertMsg( b == \"B\", \"b not B\" )\n"
00379 + " do fooA(1, \"A\", true)\n"
00380 + "}\n"
00381 + "program x { \n"
00382 + " do fooA(1, \"A\", true)\n"
00383 + " do fooB(-1, \"B\", false)\n"
00384
00385
00386 + "}";
00387
00388 this->doFunction( prog, tc );
00389 this->finishFunction( tc, "x");
00390 }
00391
00392 BOOST_AUTO_TEST_CASE( testFunctionCallArgs)
00393 {
00394
00395 string prog =
00396 string("function fooA(int a, string b, bool c) { \n")
00397 + " do test.assert( c )\n"
00398 + " do test.assert( a == 1 )\n"
00399 + " do test.assert( b == \"A\" )\n"
00400 + "}\n"
00401 + "function fooB(int a, string b, bool c) { \n"
00402 + " do test.assert( !c )\n"
00403 + " var int i = 1\n"
00404 + " var string s = \"A\"\n"
00405 + " var bool tf = true\n"
00406 + " call fooA(i, s, tf)\n"
00407 + " do test.assert( a == -1 )\n"
00408 + " do test.assert( b == \"B\" )\n"
00409 + "}\n"
00410 + "program x { \n"
00411 + " call fooA(1, \"A\", true)\n"
00412 + " call fooB(-1, \"B\", false)\n"
00413
00414
00415 + "}";
00416
00417 this->doFunction( prog, tc );
00418 this->finishFunction( tc, "x");
00419 }
00420
00421 BOOST_AUTO_TEST_CASE( testFunctionFail)
00422 {
00423
00424
00425 string prog =
00426 string("export function fooA { \n")
00427 + " do test.assert( false )\n"
00428 + "}\n"
00429 + "export function fooB { \n"
00430 + " do fooA()\n"
00431 + "}\n"
00432 + "program x { \n"
00433 + " var bool success = false\n"
00434 + " try fooA()\n"
00435 + " catch \n"
00436 + " set success = true\n"
00437 + " do test.assertMsg(success,\"Program script did not detect exported function failure.\")\n"
00438 + " set success = false\n"
00439 + " try fooB()\n"
00440 + " catch\n"
00441 + " set success = true\n"
00442 + " do test.assertMsg(success,\"Program script did not detect exported function failure.\")\n"
00443 + "}";
00444
00445 this->doFunction( prog, tc );
00446 this->finishFunction( tc, "x");
00447 }
00448
00449 BOOST_AUTO_TEST_SUITE_END()
00450
00451 void FunctionsFixture::doFunction( const std::string& prog, TaskContext* tc, bool test )
00452 {
00453 BOOST_REQUIRE( tc->engine() );
00454 Parser::ParsedPrograms pg_list;
00455 try {
00456 pg_list = parser.parseProgram( prog, tc );
00457 }
00458 catch( const file_parse_exception& exc )
00459 {
00460 BOOST_REQUIRE_MESSAGE( false , exc.what() );
00461 }
00462 catch( ... ) {
00463 BOOST_REQUIRE_MESSAGE( false, "Unknown exception thrown by Parser.");
00464 }
00465 if ( pg_list.empty() )
00466 {
00467
00468
00469 return;
00470 }
00471
00472 BOOST_REQUIRE( sa->loadProgram( *pg_list.begin() ) );
00473 BOOST_CHECK( sa->getProgram( (*pg_list.begin())->getName() )->start() );
00474
00475 BOOST_CHECK( SimulationThread::Instance()->run(1000) );
00476
00477 if (test ) {
00478 stringstream errormsg;
00479 errormsg << " on line " << sa->getProgram("x")->getLineNumber() <<" of program 'x' (or of a function 'called' by x)."<<endl;
00480 BOOST_REQUIRE_MESSAGE( sa->getProgramStatus("x") != ProgramInterface::Status::error , "Runtime Error Status encountered" + errormsg.str());
00481 BOOST_REQUIRE_MESSAGE( sa->getProgramStatus("x") == ProgramInterface::Status::stopped, "Program stalled" + errormsg.str() );
00482 }
00483 }
00484
00485 void FunctionsFixture::finishFunction(TaskContext* tc, std::string prog_name)
00486 {
00487 BOOST_REQUIRE( sa->getProgram(prog_name) );
00488 sa->getProgram( prog_name )->stop();
00489 sa->unloadProgram( prog_name );
00490 }
00491
00492