void Engine::init() { _engine->SetMessageCallback(asMETHOD(Engine, messageCallback), this, asCALL_THISCALL); RegisterStdString(_engine); RegisterScriptHandle(_engine); RegisterScriptAny(_engine); }
int qasCreateScriptEngine( qboolean *as_max_portability ) { enginehandle_t *eh; asIScriptEngine *engine; // register the global memory allocation and deallocation functions asSetGlobalMemoryFunctions( qasAlloc, qasFree ); // always new // ask for angelscript initialization and script engine creation engine = asCreateScriptEngine( ANGELSCRIPT_VERSION ); if( !engine ) return -1; eh = ( enginehandle_t * )QAS_Malloc( sizeof( enginehandle_t ) ); eh->handle = numRegisteredEngines++; eh->next = engineHandlesHead; engineHandlesHead = eh; eh->engine = engine; eh->max_portability = qfalse; if( strstr( asGetLibraryOptions(), "AS_MAX_PORTABILITY" ) ) { QAS_Printf( "* angelscript library with AS_MAX_PORTABILITY detected\n" ); eh->max_portability = qtrue; } if( as_max_portability ) *as_max_portability = eh->max_portability; // The script compiler will write any compiler messages to the callback. eh->engine->SetMessageCallback( asFUNCTION( qasGenericMessageCallback ), 0, asCALL_CDECL ); PreRegisterMathAddon( engine ); PreRegisterScriptArrayAddon( engine, true ); PreRegisterStringAddon( engine ); PreRegisterDictionaryAddon( engine ); PreRegisterTimeAddon( engine ); PreRegisterScriptAny( engine ); PreRegisterVec3Addon( engine ); PreRegisterCvarAddon( engine ); PreRegisterStringUtilsAddon( engine ); RegisterMathAddon( engine ); RegisterScriptArrayAddon( engine, true ); RegisterStringAddon( engine ); RegisterDictionaryAddon( engine ); RegisterTimeAddon( engine ); RegisterScriptAny( engine ); RegisterVec3Addon( engine ); RegisterCvarAddon( engine ); RegisterStringUtilsAddon( engine ); return eh->handle; }
asIScriptEngine *qasCreateEngine( bool *asMaxPortability ) { asIScriptEngine *engine; // register the global memory allocation and deallocation functions asSetGlobalMemoryFunctions( qasAlloc, qasFree ); // always new // ask for angelscript initialization and script engine creation engine = asCreateScriptEngine( ANGELSCRIPT_VERSION ); if( !engine ) return NULL; if( strstr( asGetLibraryOptions(), "AS_MAX_PORTABILITY" ) ) { QAS_Printf( "* angelscript library with AS_MAX_PORTABILITY detected\n" ); engine->Release(); return NULL; } *asMaxPortability = false; // The script compiler will write any compiler messages to the callback. engine->SetMessageCallback( asFUNCTION( qasMessageCallback ), 0, asCALL_CDECL ); engine->SetEngineProperty( asEP_ALWAYS_IMPL_DEFAULT_CONSTRUCT, 1 ); PreRegisterMathAddon( engine ); PreRegisterScriptArray( engine, true ); PreRegisterStringAddon( engine ); PreRegisterScriptDictionary( engine ); PreRegisterTimeAddon( engine ); PreRegisterScriptAny( engine ); PreRegisterVec3Addon( engine ); PreRegisterCvarAddon( engine ); PreRegisterStringUtilsAddon( engine ); RegisterMathAddon( engine ); RegisterScriptArray( engine, true ); RegisterStringAddon( engine ); RegisterScriptDictionary( engine ); RegisterTimeAddon( engine ); RegisterScriptAny( engine ); RegisterVec3Addon( engine ); RegisterCvarAddon( engine ); RegisterStringUtilsAddon( engine ); return engine; }
bool Test() { RET_ON_MAX_PORT bool fail = false; int r; COutStream out; CBufferedOutStream bout; // asIScriptContext *ctx; asIScriptEngine *engine; // asIScriptModule *mod; // Test circular reference between grid and ref { engine = asCreateScriptEngine(); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); RegisterScriptHandle(engine); RegisterScriptGrid(engine); // Create the circular reference r = ExecuteString(engine, "grid<ref> a; a.resize(1,1); @a[0,0] = a;"); if (r != asEXECUTION_FINISHED) TEST_FAILED; engine->GarbageCollect(); asUINT currSize, totDestroy, totDetect; engine->GetGCStatistics(&currSize, &totDestroy, &totDetect); if (currSize != 0 || totDestroy != 1 || totDetect != 1) TEST_FAILED; engine->ShutDownAndRelease(); } // Test empty initialization list // http://www.gamedev.net/topic/658849-empty-array-initialization/ { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); RegisterScriptGrid(engine); r = ExecuteString(engine, "grid<int> a = {};"); // Valid 0x0 grid if( r != asEXECUTION_FINISHED ) TEST_FAILED; r = ExecuteString(engine, "grid<int> a = {{}};"); // Valid 0x1 grid if( r != asEXECUTION_FINISHED ) TEST_FAILED; r = ExecuteString(engine, "grid<int> a = {{},{}};"); // Valid 0x2 grid if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->Release(); } // Test grid object forcibly destroyed by garbage collector // http://www.gamedev.net/topic/657955-a-quite-specific-bug/ { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); RegisterScriptGrid(engine); RegisterScriptAny(engine); RegisterScriptArray(engine, false); asIScriptModule *mod = engine->GetModule("test", asGM_ALWAYS_CREATE); mod->AddScriptSection("test", "class B {} \n" "class A \n" "{ \n" " any a; \n" " grid<B@> t(10, 10); \n" " A() \n" " { \n" " a.store(@this); \n" " } \n" "} \n" "array<A@> arr; \n" "void main() \n" "{ \n" " arr.insertLast(@A()); \n" "} \n"); r = mod->Build(); if( r < 0 ) TEST_FAILED; // The type B is not really garbage collected asITypeInfo *t = mod->GetTypeInfoByDecl("B"); if( t == 0 || (t->GetFlags() & asOBJ_GC) ) TEST_FAILED; // grid<B> is not garbage collected since B is not t = mod->GetTypeInfoByDecl("grid<B>"); if( t == 0 || (t->GetFlags() & asOBJ_GC) ) TEST_FAILED; // grid<B@> is however garbage collected because it is not possible to know // that no class derived from B can't form a circular reference with it. t = mod->GetTypeInfoByDecl("grid<B@>"); if( t == 0 || !(t->GetFlags() & asOBJ_GC) ) TEST_FAILED; r = ExecuteString(engine, "main()", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->Release(); } // Test resize { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); RegisterScriptGrid(engine); RegisterStdString(engine); engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); r = ExecuteString(engine, "grid<string> g; \n" "g.resize(1,1); \n" "g[0,0] = 'hello'; \n" "g.resize(2,2); \n" "assert( g[0,0] == 'hello' ); \n" "g[1,1] = 'there'; \n" "g.resize(1,1); \n" "assert( g.width() == 1 && g.height() == 1 ); \n"); if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->Release(); } // Test initialization lists { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); RegisterScriptGrid(engine); RegisterStdString(engine); engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); r = ExecuteString(engine, "grid<int8> g = {{1,2,3},{4,5,6},{7,8,9}}; \n" "assert( g[0,0] == 1 ); \n" "assert( g[2,2] == 9 ); \n" "assert( g[0,2] == 7 ); \n"); if( r != asEXECUTION_FINISHED ) TEST_FAILED; r = ExecuteString(engine, "grid<string> g = {{'1','2'},{'4','5'}}; \n" "assert( g[0,0] == '1' ); \n" "assert( g[1,1] == '5' ); \n" "assert( g[0,1] == '4' ); \n"); if( r != asEXECUTION_FINISHED ) TEST_FAILED; r = ExecuteString(engine, "grid<grid<int>@> g = {{grid<int> = {{1}}, grid<int> = {{2}}}, {grid<int> = {{3}}, grid<int> = {{4}}}}; \n" "assert( g[0,0][0,0] == 1 ); \n" "assert( g[1,1][0,0] == 4 ); \n"); if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->Release(); } // Success return fail; }
bool Test() { bool fail = false; int r; COutStream out; asIScriptContext *ctx; asIScriptEngine *engine; CBufferedOutStream bout; // --------------------------------------------- engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); RegisterScriptArray(engine, true); RegisterScriptString_Generic(engine); RegisterScriptAny(engine); engine->RegisterGlobalFunction("void Assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); r = engine->RegisterGlobalFunction("void SetMyAny(any@)", asFUNCTION(SetMyAny), asCALL_GENERIC); assert( r >= 0 ); asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("TestAny", script1, strlen(script1), 0); engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); r = mod->Build(); if( r < 0 ) { TEST_FAILED; printf("%s: Failed to compile the script\n", "TestAny"); } ctx = engine->CreateContext(); r = ExecuteString(engine, "TestAny()", mod, ctx); if( r != asEXECUTION_FINISHED ) { if( r == asEXECUTION_EXCEPTION ) PrintException(ctx); TEST_FAILED; printf("%s: Execution failed\n", "TestAny"); } if( ctx ) ctx->Release(); engine->Release(); //-------------------------------------------------- // Verify that the GC can handle circles with any structures engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); RegisterScriptArray(engine, true); RegisterScriptString_Generic(engine); RegisterScriptAny(engine); engine->RegisterGlobalFunction("void Assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); r = engine->RegisterGlobalFunction("void SetMyAny(any@)", asFUNCTION(SetMyAny), asCALL_GENERIC); assert( r >= 0 ); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("TestAny", script2, strlen(script2), 0); engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); r = mod->Build(); if( r < 0 ) { TEST_FAILED; printf("%s: Failed to compile the script\n", "TestAny"); } ctx = engine->CreateContext(); r = ExecuteString(engine, "TestAny()", mod, ctx); if( r != asEXECUTION_FINISHED ) { if( r == asEXECUTION_EXCEPTION ) PrintException(ctx); TEST_FAILED; printf("%s: Execution failed\n", "TestAny"); } if( ctx ) ctx->Release(); asUINT gcCurrentSize, gcTotalDestroyed, gcTotalDetected; engine->GetGCStatistics(&gcCurrentSize, &gcTotalDestroyed, &gcTotalDetected); engine->GarbageCollect(); engine->GetGCStatistics(&gcCurrentSize, &gcTotalDestroyed, &gcTotalDetected); if( !fail ) assert( gcCurrentSize == 8 && gcTotalDestroyed == 8 && gcTotalDetected == 7 ); engine->Release(); //------------------------------------------------------- // Don't allow const handle to retrieve() engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); RegisterScriptArray(engine, true); RegisterScriptString_Generic(engine); RegisterScriptAny(engine); engine->RegisterGlobalFunction("void Assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); r = engine->RegisterGlobalFunction("void SetMyAny(any@)", asFUNCTION(SetMyAny), asCALL_GENERIC); assert( r >= 0 ); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("TestAny", script3, strlen(script3), 0); engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL); r = mod->Build(); if( r < 0 ) { TEST_FAILED; printf("%s: Failed to Build()\n", "TestAny"); } if( bout.buffer != "TestAny (5, 1) : Info : Compiling void TestAny()\n" "TestAny (9, 15) : Warning : Argument cannot be assigned. Output will be discarded.\n" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } engine->Release(); //-------------------------------------------------------- // Make sure it is possible to pass any to the application engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); RegisterScriptArray(engine, true); RegisterScriptString_Generic(engine); RegisterScriptAny(engine); engine->RegisterGlobalFunction("void Assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); r = engine->RegisterGlobalFunction("void SetMyAny(any@)", asFUNCTION(SetMyAny), asCALL_GENERIC); assert( r >= 0 ); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("TestAny", script4, strlen(script4), 0); engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); r = mod->Build(); if( r < 0 ) { TEST_FAILED; printf("%s: Failed to compile\n", "TestAny"); } r = ExecuteString(engine, "TestAny()", mod); if( r != asEXECUTION_FINISHED ) { TEST_FAILED; printf("%s: Failed to execute\n", "TestAny"); } if( myAny ) { int typeId = myAny->GetTypeId(); if( !(typeId & asTYPEID_OBJHANDLE) ) TEST_FAILED; if( (typeId & asTYPEID_MASK_OBJECT) != asTYPEID_APPOBJECT ) TEST_FAILED; const char *decl = engine->GetTypeDeclaration(typeId); if( (decl == 0) || (strcmp(decl, "string@") != 0) ) { TEST_FAILED; printf("%s: Failed to return the correct type\n", "TestAny"); } int typeId2 = engine->GetTypeIdByDecl("string@"); if( typeId != typeId2 ) { TEST_FAILED; printf("%s: Failed to return the correct type\n", "TestAny"); } CScriptString *str = 0; myAny->Retrieve((void*)&str, typeId); if( str->buffer != "test" ) { TEST_FAILED; printf("%s: Failed to set the string correctly\n", "TestAny"); } if( str ) str->Release(); myAny->Release(); myAny = 0; } else TEST_FAILED; //-------------------------------------- // Make sure the any type can store primitives as well r = ExecuteString(engine, "any a; a.store(1); int b; a.retrieve(b); Assert(b == 1);"); if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->Release(); { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); RegisterScriptMath3D(engine); RegisterScriptAny(engine); engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); const char *script = "void main() \n" "{ \n" " any storage; \n" " storage.store(vector3(1,1,1)); \n" "} \n"; mod->AddScriptSection("script", script); r = mod->Build(); if( r < 0 ) TEST_FAILED; ctx = engine->CreateContext(); r = ExecuteString(engine, "main()", mod, ctx); if( r != asEXECUTION_FINISHED ) { if( r == asEXECUTION_EXCEPTION ) PrintException(ctx); TEST_FAILED; } ctx->Release(); engine->Release(); } // Success return fail; }
bool Test() { bool fail = Test2(); int r; COutStream out; CBufferedOutStream bout; // Test that removing a group doesn't remove other functions // http://www.gamedev.net/topic/657987-bug-new-functions-not-accessibly-by-getglobalfunctionbyindex-after-removing-different-configuration-group/ { asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); // register 3 script functions a(), b() and c() r = engine->RegisterGlobalFunction("void a()", asFUNCTION(0), asCALL_GENERIC); assert(r>=0); r = engine->RegisterGlobalFunction("void b()", asFUNCTION(0), asCALL_GENERIC); assert(r>=0); r = engine->RegisterGlobalFunction("void c()", asFUNCTION(0), asCALL_GENERIC); assert(r>=0); asIScriptFunction *func = engine->GetGlobalFunctionByIndex(0); if( func == 0 || string(func->GetName()) != "a" ) TEST_FAILED; func = engine->GetGlobalFunctionByIndex(1); if( func == 0 || string(func->GetName()) != "b" ) TEST_FAILED; func = engine->GetGlobalFunctionByIndex(2); if( func == 0 || string(func->GetName()) != "c" ) TEST_FAILED; // Add a dynamic group, then remove it r = engine->BeginConfigGroup("myconfig"); assert(r>=0); r = engine->RegisterGlobalFunction("void x()", asFUNCTION(0), asCALL_GENERIC); assert(r>=0); r = engine->RegisterGlobalFunction("void y()", asFUNCTION(0), asCALL_GENERIC); assert(r>=0); r = engine->EndConfigGroup(); assert(r>=0); r = engine->RemoveConfigGroup("myconfig"); assert(r>=0); // original functions should still be available func = engine->GetGlobalFunctionByIndex(0); if( func == 0 || string(func->GetName()) != "a" ) TEST_FAILED; func = engine->GetGlobalFunctionByIndex(1); if( func == 0 || string(func->GetName()) != "b" ) TEST_FAILED; func = engine->GetGlobalFunctionByIndex(2); if( func == 0 || string(func->GetName()) != "c" ) TEST_FAILED; // add some more functions in the default group r = engine->RegisterGlobalFunction("void d()", asFUNCTION(0), asCALL_GENERIC); assert(r>=0); r = engine->RegisterGlobalFunction("void e()", asFUNCTION(0), asCALL_GENERIC); assert(r>=0); r = engine->RegisterGlobalFunction("void f()", asFUNCTION(0), asCALL_GENERIC); assert(r>=0); // original functions should still be available func = engine->GetGlobalFunctionByIndex(0); if( func == 0 || string(func->GetName()) != "a" ) TEST_FAILED; func = engine->GetGlobalFunctionByIndex(1); if( func == 0 || string(func->GetName()) != "b" ) TEST_FAILED; func = engine->GetGlobalFunctionByIndex(2); if( func == 0 || string(func->GetName()) != "c" ) TEST_FAILED; // new functions must also be available func = engine->GetGlobalFunctionByIndex(3); if( func == 0 || string(func->GetName()) != "d" ) TEST_FAILED; func = engine->GetGlobalFunctionByIndex(4); if( func == 0 || string(func->GetName()) != "e" ) TEST_FAILED; func = engine->GetGlobalFunctionByIndex(5); if( func == 0 || string(func->GetName()) != "f" ) TEST_FAILED; engine->Release(); } // Test dynamic config groups with function definitions used for callbacks // http://www.gamedev.net/topic/618909-assertion-failure-in-as-configgroupcpp/ { asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(CBufferedOutStream, Callback), &bout, asCALL_THISCALL); engine->BeginConfigGroup("gr"); engine->RegisterObjectType("type", 0, asOBJ_REF); #ifndef AS_MAX_PORTABILITY engine->RegisterObjectBehaviour("type", asBEHAVE_ADDREF, "void f()", asMETHOD(Type,AddRef), asCALL_THISCALL); engine->RegisterObjectBehaviour("type", asBEHAVE_RELEASE, "void f()", asMETHOD(Type,Release), asCALL_THISCALL); #else engine->RegisterObjectBehaviour("type", asBEHAVE_ADDREF, "void f()", WRAP_MFN(Type,AddRef), asCALL_GENERIC); engine->RegisterObjectBehaviour("type", asBEHAVE_RELEASE, "void f()", WRAP_MFN(Type,Release), asCALL_GENERIC); #endif engine->RegisterFuncdef("void fun(type @)"); engine->RegisterObjectProperty("type", "fun @callback", asOFFSET(Type,callback)); engine->EndConfigGroup(); asIScriptModule *mod = engine->GetModule("mod", asGM_ALWAYS_CREATE); mod->AddScriptSection("s", "void func(type @) {} \n" "void main(type @t) \n" "{ \n" " @t.callback = func; \n" "} \n"); r = mod->Build(); if( r < 0 ) TEST_FAILED; Type *t = new Type(); // Call the function that sets the callback on the object asIScriptFunction *m = mod->GetFunctionByName("main"); asIScriptContext *ctx = engine->CreateContext(); ctx->Prepare(m); ctx->SetArgObject(0, t); r = ctx->Execute(); if( r != asEXECUTION_FINISHED ) TEST_FAILED; ctx->Release(); // Release the engine, while the object holding the callback is still alive engine->Release(); t->Release(); // The engine will warn about the callback not being released before the engine if( bout.buffer != " (0, 0) : Warning : There is an external reference to an object in module 'mod', preventing it from being deleted\n" " (0, 0) : Info : The function in previous message is named 'func'. The func type is 1\n" ) { PRINTF("%s", bout.buffer.c_str()); TEST_FAILED; } } //------------ // Test global function asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); r = engine->BeginConfigGroup("group1"); assert( r >= 0 ); r = engine->RegisterGlobalFunction("void MyFunc()", asFUNCTION(MyFunc), asCALL_GENERIC); assert( r >= 0 ); r = engine->EndConfigGroup(); assert( r >= 0 ); engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script1, strlen(script1), 0); r = mod->Build(); if( r < 0 ) { TEST_FAILED; } r = engine->RemoveConfigGroup("group1"); assert( r == asCONFIG_GROUP_IS_IN_USE ); engine->DiscardModule(0); engine->GarbageCollect(); r = engine->RemoveConfigGroup("group1"); assert( r >= 0 ); bout.buffer = ""; engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script1, strlen(script1), 0); r = mod->Build(); if( r >= 0 || bout.buffer != "TestDynamicConfig (1, 1) : Info : Compiling void Test()\n" "TestDynamicConfig (3, 3) : Error : No matching symbol 'MyFunc'\n" ) { PRINTF("%s", bout.buffer.c_str()); TEST_FAILED; } engine->Release(); //---------------- // Test global property engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); r = engine->BeginConfigGroup("group1"); assert( r >= 0 ); r = engine->RegisterGlobalProperty("int global", (void*)1); assert( r >= 0 ); r = engine->EndConfigGroup(); assert( r >= 0 ); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script2, strlen(script2), 0); engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); r = mod->Build(); if( r < 0 ) { TEST_FAILED; } r = engine->RemoveConfigGroup("group1"); assert( r == asCONFIG_GROUP_IS_IN_USE ); engine->DiscardModule(0); engine->GarbageCollect(); r = engine->RemoveConfigGroup("group1"); assert( r >= 0 ); bout.buffer = ""; mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script2, strlen(script2), 0); engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL); r = mod->Build(); if( r >= 0 || bout.buffer != "TestDynamicConfig (1, 1) : Info : Compiling void Test()\n" "TestDynamicConfig (3, 3) : Error : No matching symbol 'global'\n" ) { PRINTF("%s", bout.buffer.c_str()); TEST_FAILED; } // Try registering the property again r = engine->BeginConfigGroup("group1"); assert( r >= 0 ); r = engine->RegisterGlobalProperty("int global", (void*)1); assert( r >= 0 ); r = engine->EndConfigGroup(); assert( r >= 0 ); engine->Release(); //------------- // Test object types engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); r = engine->BeginConfigGroup("group1"); assert( r >= 0 ); r = engine->RegisterObjectType("mytype", sizeof(int), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_PRIMITIVE); r = engine->EndConfigGroup(); assert( r >= 0 ); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script3, strlen(script3), 0); engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); r = mod->Build(); if( r < 0 ) { TEST_FAILED; } r = engine->RemoveConfigGroup("group1"); assert( r == asCONFIG_GROUP_IS_IN_USE ); engine->DiscardModule(0); engine->GarbageCollect(); r = engine->RemoveConfigGroup("group1"); assert( r >= 0 ); bout.buffer = ""; mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script3, strlen(script3), 0); engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL); r = mod->Build(); if( r >= 0 || bout.buffer != "TestDynamicConfig (1, 1) : Info : Compiling void Test()\n" "TestDynamicConfig (3, 3) : Error : Identifier 'mytype' is not a data type\n" ) { PRINTF("%s", bout.buffer.c_str()); TEST_FAILED; } engine->Release(); //------------------ // Test global behaviours engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); RegisterScriptString_Generic(engine); r = engine->BeginConfigGroup("group1"); assert( r >= 0 ); r = engine->RegisterObjectType("mytype", sizeof(int), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_PRIMITIVE); r = engine->RegisterObjectMethod("mytype", "string@ opAdd_r(const string &in)", asFUNCTION(MyFunc), asCALL_GENERIC); assert( r >= 0 ); r = engine->EndConfigGroup(); assert( r >= 0 ); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script4, strlen(script4), 0); engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); r = mod->Build(); if( r < 0 ) { TEST_FAILED; } r = engine->RemoveConfigGroup("group1"); assert( r == asCONFIG_GROUP_IS_IN_USE ); engine->DiscardModule(0); engine->GarbageCollect(); r = engine->RemoveConfigGroup("group1"); assert( r >= 0 ); // Register the type again, but without the operator overload r = engine->BeginConfigGroup("group1"); assert( r >= 0 ); r = engine->RegisterObjectType("mytype", sizeof(int), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_PRIMITIVE); r = engine->EndConfigGroup(); assert( r >= 0 ); bout.buffer = ""; mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script4, strlen(script4), 0); engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL); r = mod->Build(); if( r >= 0 || bout.buffer != "TestDynamicConfig (1, 1) : Info : Compiling void Test()\n" "TestDynamicConfig (5, 9) : Error : No matching operator that takes the types 'string&' and 'mytype' found\n" ) { PRINTF("%s", bout.buffer.c_str()); TEST_FAILED; } engine->Release(); //------------------ // Test object types held by external variable, i.e. any CScriptAny *any = 0; engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); RegisterScriptAny(engine); engine->BeginConfigGroup("group1"); r = engine->RegisterObjectType("mytype", sizeof(int), asOBJ_REF); r = engine->RegisterObjectBehaviour("mytype", asBEHAVE_FACTORY, "mytype @f()", asFUNCTION(Factory), asCALL_GENERIC); r = engine->RegisterObjectBehaviour("mytype", asBEHAVE_ADDREF, "void f()", asFUNCTION(AddRef), asCALL_GENERIC); r = engine->RegisterObjectBehaviour("mytype", asBEHAVE_RELEASE, "void f()", asFUNCTION(Release), asCALL_GENERIC); any = (CScriptAny*)engine->CreateScriptObject(engine->GetTypeInfoByName("any")); r = engine->RegisterGlobalProperty("any g_any", any); engine->EndConfigGroup(); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(0, script5); engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); r = mod->Build(); if( r < 0 ) TEST_FAILED; r = ExecuteString(engine, "Test()", mod); if( r != asEXECUTION_FINISHED ) { TEST_FAILED; } engine->DiscardModule(0); engine->GarbageCollect(); int *o = 0; any->Retrieve(&o, engine->GetTypeIdByDecl("mytype@")); if( o == 0 ) TEST_FAILED; if( --(*o) != 1 ) TEST_FAILED; // The mytype variable is still stored in the any variable so we shouldn't be allowed to remove it's configuration group r = engine->RemoveConfigGroup("group1"); assert( r < 0 ); any->Release(); engine->GarbageCollect(); // Now it should be possible to remove the group r = engine->RemoveConfigGroup("group1"); assert( r >= 0 ); engine->Release(); //------------- // Test array types engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); RegisterScriptArray(engine, true); r = engine->BeginConfigGroup("group1"); assert( r >= 0 ); r = engine->RegisterObjectType("int[]", sizeof(int), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_PRIMITIVE); r = engine->EndConfigGroup(); assert( r >= 0 ); asITypeInfo *ot = engine->GetTypeInfoByDecl("int[]"); if( ot->GetSubTypeId() != asTYPEID_INT32 ) TEST_FAILED; mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script6, strlen(script6), 0); engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); r = mod->Build(); if( r < 0 ) { TEST_FAILED; } r = engine->RemoveConfigGroup("group1"); assert( r == asCONFIG_GROUP_IS_IN_USE ); engine->DiscardModule(0); engine->GarbageCollect(); r = engine->RemoveConfigGroup("group1"); assert( r >= 0 ); engine->Release(); //------------- // Test object types in struct members engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); r = engine->BeginConfigGroup("group1"); assert( r >= 0 ); r = engine->RegisterObjectType("mytype", sizeof(int), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_PRIMITIVE); r = engine->EndConfigGroup(); assert( r >= 0 ); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script7, strlen(script7), 0); engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); r = mod->Build(); if( r < 0 ) { TEST_FAILED; } r = engine->RemoveConfigGroup("group1"); assert( r == asCONFIG_GROUP_IS_IN_USE ); engine->DiscardModule(0); engine->GarbageCollect(); r = engine->RemoveConfigGroup("group1"); assert( r >= 0 ); bout.buffer = ""; mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script7, strlen(script7), 0); engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL); r = mod->Build(); if( r >= 0 || bout.buffer != "TestDynamicConfig (3, 3) : Error : Identifier 'mytype' is not a data type in global namespace\n" ) { PRINTF("%s", bout.buffer.c_str()); TEST_FAILED; } engine->Release(); //------------- // Test object types in function declarations engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); r = engine->BeginConfigGroup("group1"); assert( r >= 0 ); r = engine->RegisterObjectType("mytype", sizeof(int), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_PRIMITIVE); r = engine->EndConfigGroup(); assert( r >= 0 ); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script8, strlen(script8), 0); engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); r = mod->Build(); if( r < 0 ) { TEST_FAILED; } r = engine->RemoveConfigGroup("group1"); assert( r == asCONFIG_GROUP_IS_IN_USE ); engine->DiscardModule(0); engine->GarbageCollect(); r = engine->RemoveConfigGroup("group1"); assert( r >= 0 ); bout.buffer = ""; mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script8, strlen(script8), 0); engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL); r = mod->Build(); if( r >= 0 || bout.buffer != "TestDynamicConfig (1, 11) : Error : Identifier 'mytype' is not a data type in global namespace\n" ) { PRINTF("%s", bout.buffer.c_str()); TEST_FAILED; } engine->Release(); //------------- // Test object types in script arrays engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); RegisterScriptArray(engine, true); r = engine->BeginConfigGroup("group1"); assert( r >= 0 ); r = engine->RegisterObjectType("mytype", sizeof(int), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_PRIMITIVE); r = engine->EndConfigGroup(); assert( r >= 0 ); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script9, strlen(script9), 0); engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); r = mod->Build(); if( r < 0 ) { TEST_FAILED; } r = engine->RemoveConfigGroup("group1"); assert( r == asCONFIG_GROUP_IS_IN_USE ); engine->DiscardModule(0); engine->GarbageCollect(); r = engine->RemoveConfigGroup("group1"); assert( r >= 0 ); bout.buffer = ""; mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script9, strlen(script9), 0); engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL); r = mod->Build(); if( r >= 0 || bout.buffer != "TestDynamicConfig (1, 1) : Info : Compiling void Test()\n" "TestDynamicConfig (3, 4) : Error : Identifier 'mytype' is not a data type\n" ) { PRINTF("%s", bout.buffer.c_str()); TEST_FAILED; } engine->Release(); //------------------ // Test object types held by external variable, i.e. any engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); RegisterScriptArray(engine, true); RegisterScriptAny(engine); engine->BeginConfigGroup("group1"); r = engine->RegisterObjectType("mytype", sizeof(int), asOBJ_VALUE | asOBJ_POD); any = (CScriptAny*)engine->CreateScriptObject(engine->GetTypeInfoByName("any")); r = engine->RegisterGlobalProperty("any g_any", any); engine->EndConfigGroup(); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script10); engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); r = mod->Build(); if( r < 0 ) TEST_FAILED; r = ExecuteString(engine, "Test()", mod); if( r != asEXECUTION_FINISHED ) { TEST_FAILED; } engine->DiscardModule(0); engine->GarbageCollect(); CScriptArray *array = 0; any->Retrieve(&array, engine->GetTypeIdByDecl("mytype[]@")); if( array == 0 ) { TEST_FAILED; } else array->Release(); engine->GarbageCollect(); // The mytype variable is still stored in the any variable so we shouldn't be allowed to remove it's configuration group r = engine->RemoveConfigGroup("group1"); assert( r < 0 ); any->Release(); engine->GarbageCollect(); // Now it should be possible to remove the group r = engine->RemoveConfigGroup("group1"); assert( r >= 0 ); engine->Release(); //------------------- // Test references between config groups engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->BeginConfigGroup("group1"); r = engine->RegisterObjectType("mytype", sizeof(int), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_PRIMITIVE); assert( r >= 0 ); engine->EndConfigGroup(); engine->BeginConfigGroup("group2"); r = engine->RegisterGlobalFunction("void func(mytype)", asFUNCTION(0), asCALL_GENERIC); assert( r >= 0 ); engine->EndConfigGroup(); r = engine->RemoveConfigGroup("group1"); assert( r == asCONFIG_GROUP_IS_IN_USE ); r = engine->RemoveConfigGroup("group2"); assert( r <= 0 ); r = engine->RemoveConfigGroup("group1"); assert( r <= 0 ); engine->Release(); //-------------------- // Test situation where the default group references a dynamic group. It will then be impossible // to remove the dynamic group, but the application must still be able to release the engine. engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->BeginConfigGroup("group1"); r = engine->RegisterObjectType("mytype", sizeof(int), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_PRIMITIVE); assert( r >= 0 ); engine->EndConfigGroup(); r = engine->RegisterGlobalFunction("void func(mytype)", asFUNCTION(0), asCALL_GENERIC); assert( r >= 0 ); r = engine->RemoveConfigGroup("group1"); assert( r == asCONFIG_GROUP_IS_IN_USE ); engine->Release(); //---------------------- // Test that it is possible to repeat the registration of the config group engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); r = engine->BeginConfigGroup("g1"); assert( r >= 0 ); RegisterScriptString_Generic(engine); r = engine->EndConfigGroup(); assert( r >= 0 ); r = ExecuteString(engine, "string a = \"test\""); assert( r == asEXECUTION_FINISHED ); r = engine->GarbageCollect(); assert( r >= 0 ); r = engine->RemoveConfigGroup("g1"); assert( r >= 0 ); // again.. r = engine->BeginConfigGroup("g1"); assert( r >= 0 ); RegisterScriptString_Generic(engine); r = engine->EndConfigGroup(); assert( r >= 0 ); r = ExecuteString(engine, "string a = \"test\""); assert( r == asEXECUTION_FINISHED ); r = engine->GarbageCollect(); assert( r >= 0 ); r = engine->RemoveConfigGroup("g1"); assert( r >= 0 ); engine->Release(); //----------------------------- // Test that it isn't possible to register the same property in two different groups engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->BeginConfigGroup("a"); r = engine->RegisterGlobalProperty("int a", (void*)1); assert( r >= 0 ); engine->EndConfigGroup(); r = engine->RegisterGlobalProperty("int a", (void*)1); assert( r < 0 ); engine->Release(); //------------------------------ // Test that ExecuteString doesn't lock dynamic config groups engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); r = engine->BeginConfigGroup("g1"); assert( r >= 0 ); RegisterScriptString_Generic(engine); r = engine->EndConfigGroup(); assert( r >= 0 ); r = ExecuteString(engine, "string a = \"test\""); assert( r == asEXECUTION_FINISHED ); // Garbage collect and remove config group before discarding module r = engine->GarbageCollect(); assert( r >= 0 ); r = engine->RemoveConfigGroup("g1"); assert( r >= 0 ); engine->Release(); //----------------------- // Make sure the clean-up works when there a groups using types in the default group engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); RegisterStdString(engine); engine->BeginConfigGroup("g"); r = engine->RegisterGlobalFunction("void SaveLesson(const string &in)", asFUNCTION(0), asCALL_GENERIC); assert( r >= 0 ); engine->EndConfigGroup(); engine->Release(); //------------------------- // Test registering object members in a group // http://www.gamedev.net/topic/636396-config-groups-and-object-property-accessors/ engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->RegisterObjectType("type", 0, asOBJ_REF | asOBJ_NOCOUNT); // TODO: It should be possible to register methods and properties in different groups from where the type itself was registered engine->BeginConfigGroup("g"); engine->RegisterObjectMethod("type", "void func()", asFUNCTION(0), asCALL_GENERIC); engine->EndConfigGroup(); asITypeInfo *type = engine->GetTypeInfoByName("type"); if( type->GetMethodCount() != 1 ) TEST_FAILED; r = engine->RemoveConfigGroup("g"); if( r < 0 ) TEST_FAILED; // TODO: Currently the method is not removed as the method will be placed in the same group as the type. When this changes, the method should be removed if( type->GetMethodCount() != 1 ) TEST_FAILED; engine->Release(); // Success return fail; }
bool Test3() { if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) { printf("%s: Skipped due to AS_MAX_PORTABILITY\n", "TestRZ"); return false; } bool fail = false; int r; COutStream out; const char *script = "interface IMyInterface { void SomeFunc(); } \n" "class MyBaseClass : IMyInterface { ~MyBaseClass(){ Print(); } void SomeFunc(){} } \n" "class MyDerivedClass : MyBaseClass \n" "{ \n" " IMyInterface@ m_obj; \n" " MyDerivedClass(){} \n" " void SetObj( IMyInterface@ obj ) { @m_obj = obj; } \n" " void ClearObj(){ @m_obj = null; } \n" "} \n" "void SomeOtherFunction(){}\n" "any@ GetClass(){ \n" " MyDerivedClass x; \n" " any a( @x ); \n" " return a;\n" "} \n"; const char *script2 = "class AClass { void Blah(){} void Blah2(){} void Blah3(){} void Blah4(){} void Blah5(){} }\n" "void SomeBlahFunc(){ }\n"; asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); RegisterStdString(engine); RegisterScriptAny(engine); engine->RegisterGlobalFunction( "void Print()", asFUNCTION(Print), asCALL_CDECL ); asIScriptModule *mod = engine->GetModule( "test", asGM_ALWAYS_CREATE ); mod->AddScriptSection("script", script); r = mod->Build(); // create two instances of our classes int funcId = mod->GetFunctionIdByDecl( "any@ GetClass()" ); asIScriptObject* objA; int objATypeId; GetClassInstance( engine, funcId, objA, objATypeId ); asIScriptObject* objB; int objBTypeId; GetClassInstance( engine, funcId, objB, objBTypeId ); // resolve method functions we want to call asIObjectType* typeA = engine->GetObjectTypeById( objATypeId ); int setFuncId = typeA->GetMethodIdByDecl( "void SetObj( IMyInterface@ obj )" ); int clearFuncId = typeA->GetMethodIdByDecl( "void ClearObj()" ); // set our objB into objA { asIScriptContext* ctxt = engine->CreateContext(); r = ctxt->Prepare( setFuncId ); r = ctxt->SetObject( objA ); r = ctxt->SetArgObject( 0, objB ); r = ctxt->Execute(); ctxt->Release(); } // release objB... objB->Release(); objB = NULL; objBTypeId = 0; // clear objB from objA { asIScriptContext* ctxt = engine->CreateContext(); r = ctxt->Prepare( clearFuncId ); r = ctxt->SetObject( objA ); r = ctxt->Execute(); ctxt->Release(); } // release objA objA->Release(); objA = NULL; objATypeId = 0; // There are still objects held alive in the GC unsigned int gcCount; engine->GetGCStatistics(&gcCount); assert( gcCount == 16 ); // The script class types and functions are also in the gc // discard the module - no longer in use // The module will be discarded, but the functions that the live objects use will remain r = engine->DiscardModule("test"); if( r < 0 ) TEST_FAILED; // Do a couple of more builds, so that the memory freed by DiscardModule is reused otherwise // the problem may not occur, as the memory is still there, even though it was freed // create a module mod = engine->GetModule( "test2", asGM_ALWAYS_CREATE ); mod->AddScriptSection( "script", script2 ); r = mod->Build(); // recreate the module mod = engine->GetModule( "test", asGM_ALWAYS_CREATE ); mod->AddScriptSection("script", script); r = mod->Build(); // run the garbage collector to 'clean things up' r = engine->GarbageCollect(asGC_FULL_CYCLE); // Print is called by each script class' destructor, even though the module has already been discarded if( g_printCount != 2 ) TEST_FAILED; // we're done engine->Release(); return fail; }
bool Test1() { bool fail = false; int r = 0; COutStream out; asIScriptEngine *engine; int refCount; asIScriptObject *myGame = 0; engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); RegisterScriptArray(engine, true); RegisterScriptAny(engine); asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("script", script1, strlen(script1)); r = mod->Build(); if( r < 0 ) { TEST_FAILED; } // Calling the garbage collector mustn't free the object types, even though they are not used yet int tid1 = engine->GetModule(0)->GetTypeIdByDecl("MyGame@[]"); engine->GarbageCollect(); int tid2 = engine->GetModule(0)->GetTypeIdByDecl("MyGame@[]"); if( tid1 != tid2 ) { printf("Object type was released incorrectly by GC\n"); TEST_FAILED; } // Make sure ref count is properly updated asIScriptContext *ctx = engine->CreateContext(); ctx->Prepare(engine->GetModule(0)->GetFunctionIdByName("CreateInstance")); r = ctx->Execute(); if( r != asEXECUTION_FINISHED ) { printf("execution failed\n"); TEST_FAILED; } else { CScriptAny *any = *(CScriptAny**)ctx->GetAddressOfReturnValue(); int typeId = any->GetTypeId(); if( !(typeId & asTYPEID_OBJHANDLE) ) { printf("not a handle\n"); TEST_FAILED; } // Retrieve will increment the reference count for us any->Retrieve(&myGame, typeId); // What is the refcount? myGame->AddRef(); refCount = myGame->Release(); // GC, any, global, application if( refCount != 4 ) { printf("ref count is wrong\n"); TEST_FAILED; } // Clear the reference that the any object holds (this is not necessary) double zero = 0.0; any->Store(zero); // What is the refcount? myGame->AddRef(); refCount = myGame->Release(); // GC, global, application if( refCount != 3 ) { printf("ref count is wrong\n"); TEST_FAILED; } } // Call abort on the context to free up resources (this is not necessary) ctx->Abort(); // What is the refcount? myGame->AddRef(); refCount = myGame->Release(); // GC, global, application if( refCount != 3 ) { printf("ref count is wrong\n"); TEST_FAILED; } // Release the context ctx->Release(); ctx = 0; // What is the refcount? myGame->AddRef(); refCount = myGame->Release(); // GC, global, application if( refCount != 3 ) { printf("ref count is wrong\n"); TEST_FAILED; } // Call garbage collection engine->GarbageCollect(); // What is the refcount? myGame->AddRef(); refCount = myGame->Release(); // GC, global, application if( refCount != 3 ) { printf("ref count is wrong\n"); TEST_FAILED; } // Discard the module, freeing the global variable engine->DiscardModule(0); // What is the refcount? myGame->AddRef(); refCount = myGame->Release(); // GC, application if( refCount != 2 ) { printf("ref count is wrong\n"); TEST_FAILED; } // Release the game object refCount = myGame->Release(); // GC if( refCount != 1 ) { printf("ref count is wrong\n"); TEST_FAILED; } // Release engine engine->Release(); engine = 0; // Success return fail; }
bool Test() { bool fail = false; int r; asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); RegisterScriptString_Generic(engine); RegisterScriptAny(engine); engine->RegisterGlobalFunction("void Assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); engine->RegisterGlobalFunction("void print(const string &in)", asFUNCTION(print), asCALL_GENERIC); engine->RegisterGlobalFunction("void Analyze(any &inout)", asFUNCTION(Analyze), asCALL_GENERIC); COutStream out; CBufferedOutStream bout; engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script1, strlen(script1), 0); r = mod->Build(); if( r < 0 ) TEST_FAILED; asIScriptContext *ctx = engine->CreateContext(); r = ExecuteString(engine, "Test()", mod, ctx); if( r != asEXECUTION_FINISHED ) { if( r == asEXECUTION_EXCEPTION ) PrintException(ctx); TEST_FAILED; } if( ctx ) ctx->Release(); // Make sure that the error message for wrong constructor name works bout.buffer = ""; engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, "class t{ s() {} };", 18, 0); r = mod->Build(); if( r >= 0 ) TEST_FAILED; if( bout.buffer != "TestScriptClassMethod (1, 10) : Error : The name of constructors and destructors must be the same as the class\n" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } // Make sure the default constructor can be overloaded engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); mod = engine->GetModule("test", asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script2, strlen(script2), 0); r = mod->Build(); if( r < 0 ) TEST_FAILED; r = ExecuteString(engine, "Test()", mod); if( r != asEXECUTION_FINISHED ) { TEST_FAILED; } asIObjectType *type = engine->GetModule("test")->GetObjectTypeByName("myclass"); asIScriptObject *s = (asIScriptObject*)engine->CreateScriptObject(type); if( s == 0 ) TEST_FAILED; else { // Validate the property int *v = 0; int n = s->GetPropertyCount(); for( int c = 0; c < n; c++ ) { std::string str = "value"; if( str == s->GetPropertyName(c) ) { v = (int*)s->GetAddressOfProperty(c); if( *v != 1 ) TEST_FAILED; } } // Call the script class method if( type->GetMethodCount() != 2 ) TEST_FAILED; asIScriptFunction *method = type->GetMethodByDecl("void method2()"); if( method == 0 ) TEST_FAILED; else { asIScriptContext *ctx = engine->CreateContext(); ctx->Prepare(method); ctx->SetObject(s); int r = ctx->Execute(); if( r != asEXECUTION_FINISHED ) TEST_FAILED; if( (!v) || (*v != 3) ) TEST_FAILED; ctx->Release(); } s->Release(); } engine->Release(); //---------------------------------- engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); RegisterScriptAny(engine); engine->RegisterGlobalFunction("void Assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("test3", script3, strlen(script3), 0); r = mod->Build(); if( r < 0 ) TEST_FAILED; int typeId = engine->GetModule(0)->GetTypeIdByDecl("myclass"); type = engine->GetObjectTypeById(typeId); asIScriptFunction *mtd = type->GetMethodByDecl("void func()"); asIScriptObject *obj = (asIScriptObject *)engine->GetModule(0)->GetAddressOfGlobalVar(engine->GetModule(0)->GetGlobalVarIndexByName("c")); if( mtd == 0 || obj == 0 ) TEST_FAILED; else { asIScriptContext *ctx = engine->CreateContext(); ctx->Prepare(mtd); ctx->SetObject(obj); r = ctx->Execute(); if( r != asEXECUTION_FINISHED ) TEST_FAILED; ctx->Release(); } type = engine->GetObjectTypeById(typeId); mtd = type->GetMethodByDecl("void func(int, int)"); if( mtd == 0 || obj == 0 ) TEST_FAILED; else { asIScriptContext *ctx = engine->CreateContext(); ctx->Prepare(mtd); ctx->SetObject(obj); ctx->SetArgDWord(0, 1); ctx->SetArgDWord(1, 1); r = ctx->Execute(); if( r != asEXECUTION_FINISHED ) TEST_FAILED; ctx->Release(); } engine->Release(); //---------------------------- // Verify that global functions and class methods with the same name doesn't conflict engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); RegisterScriptAny(engine); engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("test4", script4, strlen(script4), 0); r = mod->Build(); if( r < 0 ) TEST_FAILED; asIScriptFunction *func = mod->GetFunctionByDecl("void func()"); if( func == 0 ) TEST_FAILED; engine->Release(); //---------------------------- // Accessing member variables without this engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); RegisterScriptAny(engine); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); engine->RegisterGlobalFunction("void Assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("test5", script5, strlen(script5), 0); r = mod->Build(); if( r < 0 ) TEST_FAILED; r = ExecuteString(engine, "test()", mod); if( r != asEXECUTION_FINISHED ) { TEST_FAILED; } engine->Release(); //----------------------------- // Name conflict with class method and object type engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); RegisterScriptString(engine); engine->RegisterGlobalFunction("void print(const string &in)", asFUNCTION(print), asCALL_GENERIC); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("test6", script6, strlen(script6), 0); r = mod->Build(); if( r < 0 ) TEST_FAILED; outbuffer = ""; r = ExecuteString(engine, "Test t; t.Set(1); t.Test2();", mod); if( r != asEXECUTION_FINISHED ) { TEST_FAILED; } if( outbuffer != "Test::Set\nTest::Set\nSet::Set\n" ) { printf("%s", outbuffer.c_str()); TEST_FAILED; } engine->Release(); //------------------------------ // The scope operator should permit calling global functions if the class has a method of the same name engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); const char *script = "class A { \n" " void func() { \n" " g = 0; \n" " testScope(); \n" " assert(g == 3); \n" " ::testScope(); \n" " assert(g == 2); \n" " } \n" " void testScope() { g = 3; } \n" "} \n" "void testScope() { g = 2; } \n" "int g; \n"; mod->AddScriptSection("script", script); r = mod->Build(); if( r < 0 ) { TEST_FAILED; } r = ExecuteString(engine, "A a; a.func(); assert( g == 2 );", mod); if( r != asEXECUTION_FINISHED ) { TEST_FAILED; } engine->Release(); //--------------------------- // It should not be possible to declare a method with the same name as the class { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(CBufferedOutStream, Callback), &bout, asCALL_THISCALL); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); const char *script = "class A { \n" " void A() {} \n" "} \n"; mod->AddScriptSection("script", script); bout.buffer = ""; r = mod->Build(); if( r >= 0 ) TEST_FAILED; if( bout.buffer != "script (2, 3) : Error : The method cannot be named with the class name\n" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } engine->Release(); } // Success return fail; }