$search
00001 /*************************************************************************** 00002 tag: Peter Soetens Mon Jan 10 15:59:51 CET 2005 function_test.cpp 00003 00004 function_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 #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 // Registers the fixture into the 'registry' 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 // + " test.print(\"foo()\")\n" 00111 + " do test.assert( test.isTrue( true ) )\n" 00112 + "}\n" 00113 + "export int foo_ret(double d) { \n" 00114 // + " test.printNumber(\"foo_ret(double d), d is: \", d)\n" 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 // + " test.printNumber(\"foo_args(double d, int v) v is: \", v)\n" 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 // Test call: 00134 { 00135 OperationCaller<void(void)> foo( tc->getOperation("foo"), caller->engine()); 00136 BOOST_CHECK( foo.ready() ); 00137 00138 foo(); 00139 } 00140 #if 0 00141 // Test pure send: 00142 { 00143 OperationCaller<void(void)> foo( tc->getOperation("foo"), caller->engine()); 00144 BOOST_CHECK( foo.ready() ); 00145 00146 foo.send(); 00147 } 00148 00149 // Test send + collect: 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 // Test call: 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 // Test pure send: 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 // Test send + collect: 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 // Test call: 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 // Test pure send: 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 // Test send + collect: 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" // 10 00251 + " else\n" 00252 + " return -1\n" 00253 + " return 4\n" 00254 + "}\n" 00255 + "program x { \n" 00256 + " this.foo()\n" // a void function 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" // 20 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 // Test removing exported function in infinite loop. 00271 BOOST_AUTO_TEST_CASE( testRemoveFunction) 00272 { 00273 string prog = string("export function foo { \n") 00274 + " while (true) { do nothing }\n" // this one yiels politely 00275 + "}\n" 00276 + "program x { \n" 00277 + " this.foo()\n" // this will hang the program's execution being blocked in waitForMessages for foo() to return... should we use a yield point ? Was so before because it were commands... 00278 //+ " this.foo.send()\n" // send/collect not yet supported. 00279 + "}"; 00280 00281 this->doFunction( prog, tc, false ); 00282 BOOST_CHECK( tc->getOperation("foo") ); 00283 // removing the program should lead to removal of the function from the PP. 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" // recursive is forbidden. 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" // recursive is forbidden. 00303 + "}\n" 00304 + "program x { \n" 00305 + " call foo\n" 00306 + "}"; 00307 //progs = prog; 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" // do not reach 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" // we switch val's of a and b here 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 // Test if the foo args are init'ed correctly. 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 // + " call fooA(1.0, \"A\", true)\n" 00385 // + " call fooB(-1, \"B\", false)\n" 00386 + "}"; 00387 00388 this->doFunction( prog, tc ); 00389 this->finishFunction( tc, "x"); 00390 } 00391 00392 BOOST_AUTO_TEST_CASE( testFunctionCallArgs) 00393 { 00394 // Test if the foo args are init'ed correctly. 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 // + " call fooA(1.0, \"A\", true)\n" 00414 // + " call fooB(-1, \"B\", false)\n" 00415 + "}"; 00416 00417 this->doFunction( prog, tc ); 00418 this->finishFunction( tc, "x"); 00419 } 00420 00421 BOOST_AUTO_TEST_CASE( testFunctionFail) 00422 { 00423 // Test if obj-function error is propagated correctly to 00424 // calling program or function 00425 string prog = 00426 string("export function fooA { \n") 00427 + " do test.assert( false )\n" // throws error 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" // error caught. 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" // error caught. 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 // no program necessary here. 00468 //BOOST_REQUIRE_MESSAGE(false , "No program parsed in test."); 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