bool Test() { RET_ON_MAX_PORT bool fail = false; int r; asIScriptModule *mod = 0; COutStream out; CBufferedOutStream bout; asIScriptEngine *engine = 0; // Value assignment on the base class where the operands are two different derived classes // Reported by Philip Bennefall { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); RegisterStdString(engine); mod = engine->GetModule("Test", asGM_ALWAYS_CREATE); mod->AddScriptSection("test", "class Base {} \n" "class Derived1 : Base { string a; } \n" "class Derived2 : Base { double a; } \n" "void main() \n" "{ \n" " Derived1 d1; \n" " Derived2 d2; \n" " Base@ b1 = d1, b2 = d2; \n" " b1 = b2; \n" // must not crash application. should raise script exception "} \n"); r = mod->Build(); if( r < 0 ) TEST_FAILED; asIScriptContext *ctx = engine->CreateContext(); r = ExecuteString(engine, "main()", mod, ctx); if( r != asEXECUTION_EXCEPTION ) TEST_FAILED; if( std::string(ctx->GetExceptionString()) != "Mismatching types in value assignment" ) TEST_FAILED; ctx->Release(); engine->Release(); } // A derived class must not be allowed to implement a function with the same // name and parameter list as parent class, but with a different return type. // Reported by Philip Bennefall { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); bout.buffer = ""; engine->SetMessageCallback(asMETHOD(CBufferedOutStream, Callback), &bout, asCALL_THISCALL); mod = engine->GetModule("Test", asGM_ALWAYS_CREATE); mod->AddScriptSection("test", "class P { \n" " int MyFunc(float) { return 0; } \n" "} \n" "class D : P { \n" " float MyFunc(float) { return 0; } \n" "} \n"); r = mod->Build(); if( r >= 0 ) TEST_FAILED; if( bout.buffer != "test (4, 7) : Error : The method in the derived class must have the same return type as in the base class: 'int P::MyFunc(float)'\n" ) { PRINTF("%s", bout.buffer.c_str()); TEST_FAILED; } engine->Release(); } // Basic tests for inheritance { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); RegisterStdString(engine); engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); engine->RegisterGlobalFunction("void print(const string &in)", asFUNCTION(print), asCALL_CDECL); const char *script = "bool baseDestructorCalled = false; \n" "bool baseConstructorCalled = false; \n" "bool baseFloatConstructorCalled = false; \n" "class Base : Intf \n" "{ \n" " int a; \n" " void f1() { a = 1; } \n" " void f2() { a = 0; } \n" " void f3() { a = 3; } \n" " Base() { baseConstructorCalled = true; } \n" " Base(float) { baseFloatConstructorCalled = true; } \n" " ~Base() { baseDestructorCalled = true; } \n" "} \n" "bool derivedDestructorCalled = false; \n" "bool derivedConstructorCalled = false; \n" "class Derived : Base \n" "{ \n" // overload f2() " void f2() { a = 2; } \n" // overload f3() " void f3() { a = 2; } \n" " void func() \n" " { \n" // call Base::f1() " f1(); \n" " assert(a == 1); \n" // call Derived::f2() " f2(); \n" " assert(a == 2); \n" // call Base::f3() " Base::f3(); \n" " assert(a == 3); \n" " } \n" " Derived() {} \n" " Derived(int) { derivedConstructorCalled = true; } \n" " ~Derived() { derivedDestructorCalled = true; } \n" "} \n" "void foo( Base &in a ) \n" "{ \n" " assert( cast<Derived>(a) is null ); \n" "} \n" // Must be possible to call the default constructor, even if not declared "class DerivedGC : BaseGC { DerivedGC() { super(); } } \n" "class BaseGC { BaseGC @b; } \n" "class DerivedS : Base \n" "{ \n" " DerivedS(float) \n" " { \n" // Call Base::Base(float) " if( true ) \n" " super(1.4f); \n" " else \n" " super(); \n" " } \n" "} \n" // Must handle inheritance where the classes have been declared out of order "void func() \n" "{ \n" " Intf@ a = C(); \n" "} \n" "class C : B {} \n" "interface Intf {} \n" "class B : Intf {} \n" // Several levels of inheritance "class C0 \n" "{ \n" " void Dummy() {} \n" "} \n" "class C1 : C0 \n" "{ \n" " void Fun() { print('C1:Fun'); } \n" "} \n" "class C2 : C1 \n" "{ \n" " void Fun() { print('C2:Fun'); } \n" "} \n" "class C3 : C2 \n" "{ \n" " void Call() { Fun(); } \n" "} \n"; mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("script", script); r = mod->Build(); if( r < 0 ) { TEST_FAILED; } // Make sure the bytecode for the ref cast is correct asIScriptFunction *func = mod->GetFunctionByName("foo"); asBYTE expect[] = { asBC_SUSPEND,asBC_PSF,asBC_Cast,asBC_STOREOBJ,asBC_ClrVPtr,asBC_CmpPtr,asBC_TZ,asBC_CpyRtoV4,asBC_FREE,asBC_FREE,asBC_PshV4,asBC_CALLSYS, asBC_SUSPEND,asBC_RET }; if( !ValidateByteCode(func, expect) ) TEST_FAILED; if( TestModule(0, engine) ) { TEST_FAILED; } // Must make sure that the inheritance path is stored/restored with the saved byte code { CBytecodeStream stream(__FILE__"1"); r = mod->SaveByteCode(&stream); if( r < 0 ) { TEST_FAILED; } asIScriptModule *mod2 = engine->GetModule("2", asGM_ALWAYS_CREATE); r = mod2->LoadByteCode(&stream); if( r < 0 ) { TEST_FAILED; } // Both modules should have the same number of functions if( mod->GetFunctionCount() != mod2->GetFunctionCount() ) { TEST_FAILED; asUINT n; PRINTF("First module's functions\n"); for( n = 0; n < (asUINT)mod->GetFunctionCount(); n++ ) { asIScriptFunction *f = mod->GetFunctionByIndex(n); PRINTF("%s\n", f->GetDeclaration()); } PRINTF("\nSecond module's functions\n"); for( n = 0; n < (asUINT)mod2->GetFunctionCount(); n++ ) { asIScriptFunction *f = mod2->GetFunctionByIndex(n); PRINTF("%s\n", f->GetDeclaration()); } } if( TestModule("2", engine) ) { TEST_FAILED; } engine->DiscardModule("2"); } engine->Release(); } // Test final and override { CBufferedOutStream bout; asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(CBufferedOutStream, Callback), &bout, asCALL_THISCALL); asIScriptModule *mod = engine->GetModule("test", asGM_ALWAYS_CREATE); mod->AddScriptSection("test", "final class CFin1 {} \n" // Don't allow inheritance "shared final class CFin2 {} \n" // -"- "class CBase \n" "{ \n" " void finalFunc() final {} \n" // don't allow override this func " void overrideFunc() {} \n" "} \n" "class CD1 : CFin1 {} \n" // Shouldn't work "class CD2 : CBase \n" "{ \n" " void finalFunc() {} \n" // shouldn't work " void overrideFunc(int) override {} \n" // must override "} \n"); int r = mod->Build(); if( r >= 0 ) TEST_FAILED; if( bout.buffer != "test (8, 13) : Error : Can't inherit from class 'CFin1' marked as final\n" "test (9, 7) : Error : Method 'void CBase::finalFunc()' declared as final and cannot be overridden\n" "test (9, 7) : Error : Method 'void CD2::overrideFunc(int)' marked as override but does not replace any base class or interface method\n" ) { PRINTF("%s", bout.buffer.c_str()); TEST_FAILED; } engine->Release(); } fail = Test2() || fail; // Success return fail; }
int main( int argc, char *argv[] ) { char *height_name; char *edge_name; tga_t *heightmap; tga_t *edgemap; int i, j; int num; FILE *h; printf( "===== envpot - build and optimize a environment data =====\n" ); SetCmdArgs( argc, argv ); height_name = GetCmdOpt2( "-h" ); edge_name = GetCmdOpt2( "-e" ); if ( !height_name ) Error( "no heightmap.\n" ); if ( !edge_name ) Error( "no edgemap.\n" ); h = fopen( height_name, "r" ); if ( !h ) Error( "can't open heightmap.\n" ); heightmap = TGA_Read( h ); fclose( h ); h = fopen( edge_name, "r" ); if ( !h ) Error( "can't open edgemap.\n" ); edgemap = TGA_Read( h ); fclose( h ); InitEdgeMap( edgemap ); // InitHeightMap( heightmap ); // SetupCells(); #if 0 num = 0; for ( i = 0; i < 10; i++ ) { for ( j = 0; j < 10; j++ ) { // Vec3dInit( vertices[num++], (random()%1000)/1000.0, 0.0, (random()%1000)/1000.0 ); Vec3dInit( vertices[num++], j/10.0, 0.0, i/10.0 ); } } for ( i = 0; i < 5; i++ ) { for ( j = 0; j < 5; j++ ) { // Vec3dInit( vertices[num++], (random()%1000)/1000.0, 0.0, (random()%1000)/1000.0 ); Vec3dInit( vertices[num++], 0.05+j/10.0, 0.0, 0.05+i/10.0 ); } } vertexnum = num; #endif // Vec2dInit( vertices[0].v, 0.0, 0.0 ); // Vec2dInit( vertices[1].v, 0.0, 1.0 ); // Vec2dInit( vertices[2].v, -1.0, 0.5 ); // Vec2dInit( vertices[3].v, 1.0, 0.5 ); // Vec2dInit( vertices[4].v, 2.0, 0.5 ); // vertexnum = 5; Init2(); handle = fopen( "env_tris", "w" ); Test2(); fprintf( handle, "end" ); fclose( handle ); handle = fopen( "env_vertices", "w" ); WriteVertices(); fclose( handle ); }
bool Test() { bool fail = Test2(); int r; asIScriptEngine *engine; CBufferedOutStream bout; COutStream out; // Two forms of casts: value cast and ref cast // A value cast actually constructs a new object // A ref cast will only reinterpret a handle, without actually constructing any object // Should be possible to tell AngelScript if it may use the behaviour implicitly or not // Since care must be taken with implicit casts, it is not allowed by default, // i.e. asBEHAVE_VALUE_CAST and asBEHAVE_VALUE_CAST_IMPLICIT or // asBEHAVE_REF_CAST and asBEHAVE_REF_CAST_IMPLICIT //---------------------------------------------------------------------------- // VALUE_CAST // TODO: (Test) Cast from primitive to object is an object constructor/factory // TODO: (Test) Cast from object to object can be either object behaviour or object constructor/factory, // depending on which object registers the cast // TODO: (Implement) It shall be possible to register cast operators as explicit casts. The constructor/factory // is by default an explicit cast, but shall be possible to register as implicit cast. // TODO: (Implement) Type constructors should be made explicit cast only, or perhaps not permit casts at all // TODO: (Test) When compiling operators with non-primitives, the compiler should first look for // compatible registered operator behaviours. If not found, the compiler should see if // there is any cast behaviour that allow conversion of the type to a primitive type. // Test 1 // A class can be implicitly cast to a primitive, if registered the VALUE_CAST behaviour engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); r = engine->RegisterGlobalFunction("void assert( bool )", asFUNCTION(Assert), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectType("type", sizeof(int), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_PRIMITIVE); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("type", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(Type_construct0), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("type", asBEHAVE_CONSTRUCT, "void f(int)", asFUNCTION(Type_construct1), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("type", asBEHAVE_IMPLICIT_VALUE_CAST, "int f()", asFUNCTION(Type_castInt), asCALL_GENERIC); assert( r >= 0 ); asIScriptContext *ctx = 0; r = engine->ExecuteString(0, "type t(5); \n" "int a = t; \n" // conversion to primitive in assignment "assert( a == 5 ); \n" "assert( a + t == 10 ); \n" // conversion to primitive with math operation "a -= t; \n" // conversion to primitive with math operation "assert( a == 0 ); \n" "assert( t == int(5) ); \n" // conversion to primitive with comparison "type b(t); \n" // conversion to primitive with parameter "assert( 32 == (1 << t) ); \n" // conversion to primitive with bitwise operation "assert( (int(5) & t) == 5 ); \n" // conversion to primitive with bitwise operation , &ctx); if( r != 0 ) { if( r == 3 ) PrintException(ctx); fail = true; } if( ctx ) ctx->Release(); // Test 2 // A class won't be converted to primitive if there is no obvious target type // ex: t << 1 - It is not known what type t should be converted to // ex: t + t - It is not known what type t should be converted to // ex: t < t - It is not known what type t should be converted to bout.buffer = ""; engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL); r = engine->ExecuteString(0, "type t(5); t << 1; "); if( r >= 0 ) fail = true; if( bout.buffer != "ExecuteString (1, 14) : Error : Illegal operation on 'type&'\n" ) { printf(bout.buffer.c_str()); fail = true; } bout.buffer = ""; r = engine->ExecuteString(0, "type t(5); t + t; "); if( r >= 0 ) fail = true; if( bout.buffer != "ExecuteString (1, 14) : Error : No matching operator that takes the types 'type&' and 'type&' found\n" ) { printf(bout.buffer.c_str()); fail = true; } bout.buffer = ""; r = engine->ExecuteString(0, "type t(5); t < t; "); if( r >= 0 ) fail = true; if( bout.buffer != "ExecuteString (1, 14) : Error : No matching operator that takes the types 'type&' and 'type&' found\n" ) { printf(bout.buffer.c_str()); fail = true; } // Test3 // If an object has a cast to more than one matching primitive type, the cast to the // closest matching type will be used, i.e. Obj has cast to int and to float. A type of // int8 is requested, so the cast to int is used engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); r = engine->ExecuteString(0, "type t(2); assert( (1.0 / t) == (1.0 / 2.0) );"); if( r != asEXECUTION_FINISHED ) fail = true; engine->Release(); // Test4 // It shall not be possible to register a cast behaviour from an object to a boolean type engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); r = engine->RegisterObjectType("type", sizeof(int), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_PRIMITIVE); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("type", asBEHAVE_IMPLICIT_VALUE_CAST, "bool f()", asFUNCTION(Type_castInt), asCALL_GENERIC); if( r != asNOT_SUPPORTED ) { fail = true; } engine->Release(); // Test5 // Exclicit value cast // TODO: This should work for MAX_PORTABILITY as well if( !strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); r = engine->RegisterGlobalFunction("void assert( bool )", asFUNCTION(Assert), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectType("type", sizeof(int), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_PRIMITIVE); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("type", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(Type_construct0), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("type", asBEHAVE_CONSTRUCT, "void f(int)", asFUNCTION(Type_construct1), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterObjectBehaviour("type", asBEHAVE_VALUE_CAST, "int f()", asFUNCTION(Type_castInt), asCALL_GENERIC); assert( r >= 0 ); r = engine->RegisterGlobalBehaviour(asBEHAVE_EQUAL, "bool f(const type &in, const type &in)", asFUNCTION(Type_equal), asCALL_CDECL); assert( r >= 0 ); r = engine->RegisterObjectProperty("type", "int v", 0); // explicit cast to int is allowed r = engine->ExecuteString(0, "type t; t.v = 5; int a = int(t); assert(a == 5);"); if( r < 0 ) fail = true; // as cast to int is allowed, AngelScript also allows cast to float (using cast to int then implicit cast to int) r = engine->ExecuteString(0, "type t; t.v = 5; float a = float(t); assert(a == 5.0f);"); if( r < 0 ) fail = true; // implicit cast to int is not allowed bout.buffer = ""; engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL); r = engine->ExecuteString(0, "type t; int a = t;"); if( r >= 0 ) fail = true; if( bout.buffer != "ExecuteString (1, 17) : Error : Can't implicitly convert from 'type&' to 'int'.\n" ) { printf(bout.buffer.c_str()); fail = true; } /* // Having an implicit constructor with an int param makes it possible to compare the type with int engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); r = engine->ExecuteString(0, "type t(5); assert( t == 5 );"); if( r < 0 ) fail = true; */ engine->Release(); } //----------------------------------------------------------------- // REFERENCE_CAST // TODO: This should work for MAX_PORTABILITY as well if( !strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) { // It must be possible to cast an object handle to another object handle, without // losing the reference to the original object. This is what will allow applications // to register inheritance for registered types. This should be a special // behaviour, i.e. REF_CAST. // How to provide a cast from a base class to a derived class? // The base class may not know about the derived class, so it must // be the derived class that registers the behaviour. // How to provide interface functionalities to registered types? I.e. a class implements // various interfaces, and a handle to one of the interfaces may be converted to a handle // of another interface that is implemented by the class. // TODO: Can't register casts from primitive to primitive engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); // Class A is the base class engine->RegisterObjectType("A", 0, asOBJ_REF); engine->RegisterObjectBehaviour("A", asBEHAVE_FACTORY, "A@f()", asFUNCTION(A::factory), asCALL_CDECL); engine->RegisterObjectBehaviour("A", asBEHAVE_RELEASE, "void f()", asMETHOD(A, release), asCALL_THISCALL); engine->RegisterObjectBehaviour("A", asBEHAVE_ADDREF, "void f()", asMETHOD(A, addref), asCALL_THISCALL); engine->RegisterObjectBehaviour("A", asBEHAVE_ASSIGNMENT, "A& f(const A &in)", asMETHOD(A, assign), asCALL_THISCALL); engine->RegisterObjectMethod("A", "int test()", asMETHOD(A, test), asCALL_THISCALL); // Class B inherits from class A engine->RegisterObjectType("B", 0, asOBJ_REF); engine->RegisterObjectBehaviour("B", asBEHAVE_FACTORY, "B@f()", asFUNCTION(B::factory), asCALL_CDECL); engine->RegisterObjectBehaviour("B", asBEHAVE_RELEASE, "void f()", asMETHOD(B, release), asCALL_THISCALL); engine->RegisterObjectBehaviour("B", asBEHAVE_ADDREF, "void f()", asMETHOD(B, addref), asCALL_THISCALL); engine->RegisterObjectMethod("B", "int test()", asMETHOD(B, test), asCALL_THISCALL); // Test the classes to make sure they work r = engine->ExecuteString(0, "A a; assert(a.test() == 1); B b; assert(b.test() == 2);"); if( r != asEXECUTION_FINISHED ) fail = true; // It should be possible to register a REF_CAST to allow implicit cast // Test IMPLICIT_REF_CAST from subclass to baseclass r = engine->RegisterGlobalBehaviour(asBEHAVE_IMPLICIT_REF_CAST, "A@ f(B@)", asFUNCTION(B::castToA), asCALL_CDECL); assert( r >= 0 ); r = engine->ExecuteString(0, "B b; A@ a = b; assert(a.test() == 2);"); if( r != asEXECUTION_FINISHED ) fail = true; // Test explicit cast with registered IMPLICIT_REF_CAST r = engine->ExecuteString(0, "B b; A@ a = cast<A>(b); assert(a.test() == 2);"); if( r != asEXECUTION_FINISHED ) fail = true; // It should be possible to assign a value of type B // to and variable of type A due to the implicit ref cast r = engine->ExecuteString(0, "A a; B b; a = b;"); if( r != asEXECUTION_FINISHED ) fail = true; // Test REF_CAST from baseclass to subclass r = engine->RegisterGlobalBehaviour(asBEHAVE_REF_CAST, "B@ f(A@)", asFUNCTION(B::AcastToB), asCALL_CDECL); assert( r >= 0 ); r = engine->ExecuteString(0, "B b; A@ a = cast<A>(b); B@ _b = cast<B>(a); assert(_b.test() == 2);"); if( r != asEXECUTION_FINISHED ) fail = true; // Test REF_CAST from baseclass to subclass, where the cast is invalid r = engine->ExecuteString(0, "A a; B@ b = cast<B>(a); assert(@b == null);"); if( r != asEXECUTION_FINISHED ) fail = true; // TODO: This requires implicit value cast // Test passing a value of B to a function expecting its base class // the compiler will automatically create a copy /* const char *script = "void func(A a) {assert(a.test() == 1);}\n"; r = mod->AddScriptSection(0, "script", script, strlen(script)); r = mod->Build(0); if( r < 0 ) fail = true; r = engine->ExecuteString(0, "B b; func(b)"); if( r < 0 ) fail = true; */ // TODO: A handle to A can not be implicitly cast to a handle to B since it was registered as explicit REF_CAST // TODO: It shouldn't be possible to cast away constness engine->Release(); } // Success return fail; }
bool Test() { bool fail = Test2(); int r; COutStream out; asIScriptContext *ctx; // Test to make sure opIndex properly catches null pointer access // http://www.gamedev.net/topic/676729-crash-instead-of-null-pointer-exception-on-opindex/ { asIScriptEngine *engine = asCreateScriptEngine(); RegisterScriptArray(engine, true); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); ctx = engine->CreateContext(); r = ExecuteString(engine, "array<array<int>@> a = {null}; a[0][0] = 1;", 0, ctx); if (r != asEXECUTION_EXCEPTION) TEST_FAILED; else if( GetExceptionInfo(ctx) != "func: void ExecuteString()\n" "modl: \n" "sect: ExecuteString\n" "line: 1\n" "desc: Null pointer access\n" ) { PRINTF("%s", GetExceptionInfo(ctx).c_str()); TEST_FAILED; } ctx->Release(); engine->ShutDownAndRelease(); } // Test GetTypeDeclaration with arrays // http://www.gamedev.net/topic/663428-simplest-way-to-get-variable-type/ { asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); RegisterScriptArray(engine, true); int typeId = engine->GetTypeIdByDecl("array<array<int>@>"); if( typeId < 0 ) TEST_FAILED; std::string typeDecl = engine->GetTypeDeclaration(typeId, true); if( typeDecl != "int[]@[]" ) { PRINTF("%s\n", typeDecl.c_str()); TEST_FAILED; } engine->SetDefaultNamespace("foo"); engine->RegisterEnum("MyEnum"); engine->SetDefaultNamespace(""); typeId = engine->GetTypeIdByDecl("array<foo::MyEnum>"); if( typeId < 0 ) TEST_FAILED; typeDecl = engine->GetTypeDeclaration(typeId, true); if( typeDecl != "foo::MyEnum[]" ) { PRINTF("%s\n", typeDecl.c_str()); TEST_FAILED; } engine->ShutDownAndRelease(); } asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); RegisterScriptArray(engine, true); RegisterScriptString_Generic(engine); engine->RegisterGlobalFunction("void Assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script1, strlen(script1), 0); r = mod->Build(); if( r < 0 ) { TEST_FAILED; PRINTF("%s: Failed to compile the script\n", TESTNAME); } ctx = engine->CreateContext(); r = ExecuteString(engine, "TestArray()", mod, ctx); if( r != asEXECUTION_FINISHED ) { if( r == asEXECUTION_EXCEPTION ) PRINTF("%s", GetExceptionInfo(ctx).c_str()); PRINTF("%s: Failed to execute script\n", TESTNAME); TEST_FAILED; } if( ctx ) ctx->Release(); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script2, strlen(script2), 0); r = mod->Build(); if( r < 0 ) { TEST_FAILED; PRINTF("%s: Failed to compile the script\n", TESTNAME); } r = ExecuteString(engine, "TestArrayException()", mod); if( r != asEXECUTION_EXCEPTION ) { PRINTF("%s: No exception\n", TESTNAME); TEST_FAILED; } mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script3, strlen(script3), 0); r = mod->Build(); if( r < 0 ) { TEST_FAILED; PRINTF("%s: Failed to compile the script\n", TESTNAME); } ctx = engine->CreateContext(); r = ExecuteString(engine, "TestArrayMulti()", mod, ctx); if( r != asEXECUTION_FINISHED ) { PRINTF("%s: Failure\n", TESTNAME); TEST_FAILED; } if( r == asEXECUTION_EXCEPTION ) { PRINTF("%s", GetExceptionInfo(ctx).c_str()); } if( ctx ) ctx->Release(); ctx = 0; mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script4, strlen(script4), 0); r = mod->Build(); if( r < 0 ) { TEST_FAILED; PRINTF("%s: Failed to compile the script\n", TESTNAME); } ctx = engine->CreateContext(); r = ExecuteString(engine, "TestArrayChar()", mod, ctx); if( r != asEXECUTION_FINISHED ) { PRINTF("%s: Failure\n", TESTNAME); TEST_FAILED; } if( r == asEXECUTION_EXCEPTION ) { PRINTF("%s", GetExceptionInfo(ctx).c_str()); } if( ctx ) ctx->Release(); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script5, strlen(script5), 0); r = mod->Build(); if( r < 0 ) TEST_FAILED; ctx = engine->CreateContext(); r = ExecuteString(engine, "TestArrayInitList()", mod, ctx); if( r != asEXECUTION_FINISHED ) TEST_FAILED; if( r == asEXECUTION_EXCEPTION ) PRINTF("%s", GetExceptionInfo(ctx).c_str()); if( ctx ) ctx->Release(); CBufferedOutStream bout; engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script6, strlen(script6), 0); r = mod->Build(); if( r >= 0 ) TEST_FAILED; if( bout.buffer != "TestArray (1, 1) : Info : Compiling void Test()\n" "TestArray (4, 16) : Error : Initialization lists cannot be used with 'int'\n" ) { PRINTF("%s", bout.buffer.c_str()); TEST_FAILED; } // Array object must call default constructor of the script classes engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script7, strlen(script7), 0); r = mod->Build(); if( r < 0 ) TEST_FAILED; r = ExecuteString(engine, "Test()", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; // Test bool[] on Mac OS X with PPC CPU // Submitted by Edward Rudd const char *script8 = "bool[] f(10); \n" "for (int i=0; i<10; i++) { \n" " f[i] = false; \n" "} \n" "Assert(f[0] == false); \n" "Assert(f[1] == false); \n" "f[0] = true; \n" "Assert(f[0] == true); \n" "Assert(f[1] == false); \n"; r = ExecuteString(engine, script8); if( r != asEXECUTION_FINISHED ) TEST_FAILED; // Make sure it is possible to do multiple assignments with the array type r = ExecuteString(engine, "int[] a, b, c; a = b = c;"); if( r < 0 ) TEST_FAILED; engine->Release(); // Test circular reference between types { // Create the script engine asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); RegisterScriptArray(engine, true); // Compile asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("script", "class Hoge" "{" " Hoge(){}" " Hoge(HogeManager&){}" "};" "class HogeManager" "{" " Hoge[] hoges;" "};" , 0); mod->Build(); // Release engine engine->Release(); } // Test multidimensional array initialization { // Create the script engine asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); RegisterScriptArray(engine, true); r = ExecuteString(engine, "int[][] a(2, int[](2)); assert(a[1].length() == 2);\n"); if( r != asEXECUTION_FINISHED ) TEST_FAILED; // Release engine engine->Release(); } // Test array of void { asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); CBufferedOutStream bout; engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL); RegisterScriptArray(engine, false); r = ExecuteString(engine, "array<void> a;"); if( r != -1 ) TEST_FAILED; if( bout.buffer != "ExecuteString (1, 7) : Error : Attempting to instantiate invalid template type 'array<void>'\n" ) { PRINTF("%s", bout.buffer.c_str()); TEST_FAILED; } engine->Release(); } // Success return fail; }
bool Test() { if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) { printf("Skipped due to AS_MAX_PORTABILITY\n"); return false; } bool fail = false; int r; CBufferedOutStream bout; COutStream out; asIScriptModule *mod; asIScriptEngine *engine; engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL); RegisterScriptArray(engine, true); RegisterScriptString(engine); engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); // The getter can return a handle while the setter takes a reference { const char *script = "class Test \n" "{ \n" " string @get_s() { return 'test'; } \n" " void set_s(const string &in) {} \n" "} \n" "void func() \n" "{ \n" " Test t; \n" " string s = t.s; \n" " t.s = s; \n" "} \n"; mod->AddScriptSection("script", script); bout.buffer = ""; r = mod->Build(); if( r < 0 ) { TEST_FAILED; printf("Failed to compile the script\n"); } r = ExecuteString(engine, "Test t; @t.s = 'test';", mod); if( r >= 0 ) { TEST_FAILED; printf("Shouldn't be allowed\n"); } if( bout.buffer != "ExecuteString (1, 14) : Error : It is not allowed to perform a handle assignment on a non-handle property\n" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } } // main1 and main2 should produce the same bytecode const char *script1 = "class Test \n" "{ \n" " int get_prop() { return _prop; } \n" " void set_prop(int v) { _prop = v; } \n" " int _prop; \n" "} \n" "void main1() \n" "{ \n" " Test t; \n" " t.set_prop(42); \n" " assert( t.get_prop() == 42 ); \n" "} \n" "void main2() \n" "{ \n" " Test t; \n" " t.prop = 42; \n" " assert( t.prop == 42 ); \n" "} \n"; mod->AddScriptSection("script", script1); bout.buffer = ""; r = mod->Build(); if( r < 0 ) { TEST_FAILED; printf("Failed to compile the script\n"); } if( bout.buffer != "" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } r = ExecuteString(engine, "main1()", mod); if( r != asEXECUTION_FINISHED ) { TEST_FAILED; } r = ExecuteString(engine, "main2()", mod); if( r != asEXECUTION_FINISHED ) { TEST_FAILED; } // Test compound assignment with accessors (not allowed) const char *script2 = "class Test \n" "{ \n" " void set_prop(int v) { _prop = v; } \n" " int _prop; \n" "} \n" "void main1() \n" "{ \n" " Test t; \n" " t.prop += 42; \n" "} \n"; mod->AddScriptSection("script", script2); bout.buffer = ""; r = mod->Build(); if( r >= 0 ) { TEST_FAILED; } if( bout.buffer != "script (6, 1) : Info : Compiling void main1()\n" "script (9, 10) : Error : Compound assignments with property accessors are not allowed\n" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } // Test get accessor with boolean operators const char *script3 = "class Test \n" "{ \n" " bool get_boolProp() { return true; } \n" "} \n" "void main1() \n" "{ \n" " Test t; \n" " if( t.boolProp ) {} \n" " if( t.boolProp && true ) {} \n" " if( false || t.boolProp ) {} \n" " if( t.boolProp ^^ t.boolProp ) {} \n" " if( !t.boolProp ) {} \n" " t.boolProp ? t.boolProp : t.boolProp; \n" "} \n"; mod->AddScriptSection("script", script3); bout.buffer = ""; r = mod->Build(); if( r < 0 ) { TEST_FAILED; printf("Failed to compile the script\n"); } if( bout.buffer != "" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } // Test get accessor with math operators const char *script4 = "class Test \n" "{ \n" " float get_prop() { return 1.0f; } \n" "} \n" "void main1() \n" "{ \n" " Test t; \n" " float f = t.prop * 1; \n" " f = (t.prop) + 1; \n" " 10 / t.prop; \n" " -t.prop; \n" "} \n"; mod->AddScriptSection("script", script4); bout.buffer = ""; r = mod->Build(); if( r < 0 ) { TEST_FAILED; printf("Failed to compile the script\n"); } if( bout.buffer != "" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } // Test get accessor with bitwise operators const char *script5 = "class Test \n" "{ \n" " uint get_prop() { return 1; } \n" "} \n" "void main1() \n" "{ \n" " Test t; \n" " t.prop << t.prop; \n" " t.prop & t.prop; \n" " ~t.prop; \n" "} \n"; mod->AddScriptSection("script", script5); bout.buffer = ""; r = mod->Build(); if( r < 0 ) { TEST_FAILED; printf("Failed to compile the script\n"); } if( bout.buffer != "" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } // Test multiple get accessors for same property. Should give error // Test multiple set accessors for same property. Should give error const char *script6 = "class Test \n" "{ \n" " uint get_p() {return 0;} \n" " float get_p() {return 0;} \n" " void set_s(float) {} \n" " void set_s(uint) {} \n" "} \n" "void main() \n" "{ \n" " Test t; \n" " t.p; \n" " t.s = 0; \n" "} \n"; mod->AddScriptSection("script", script6); bout.buffer = ""; r = mod->Build(); if( r >= 0 ) { TEST_FAILED; printf("Failed to compile the script\n"); } if( bout.buffer != "script (8, 1) : Info : Compiling void main()\n" "script (11, 4) : Error : Found multiple get accessors for property 'p'\n" "script (11, 4) : Info : uint Test::get_p()\n" "script (11, 4) : Info : float Test::get_p()\n" "script (12, 4) : Error : Found multiple set accessors for property 's'\n" "script (12, 4) : Info : void Test::set_s(float)\n" "script (12, 4) : Info : void Test::set_s(uint)\n" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } // Test mismatching type between get accessor and set accessor. Should give error const char *script7 = "class Test \n" "{ \n" " uint get_p() {return 0;} \n" " void set_p(float) {} \n" "} \n" "void main() \n" "{ \n" " Test t; \n" " t.p; \n" "} \n"; mod->AddScriptSection("script", script7); bout.buffer = ""; r = mod->Build(); if( r >= 0 ) { TEST_FAILED; printf("Failed to compile the script\n"); } if( bout.buffer != "script (6, 1) : Info : Compiling void main()\n" "script (9, 4) : Error : The property 'p' has mismatching types for the get and set accessors\n" "script (9, 4) : Info : uint Test::get_p()\n" "script (9, 4) : Info : void Test::set_p(float)\n" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } // Test only set accessor for read expression // Test only get accessor for write expression const char *script8 = "class Test \n" "{ \n" " uint get_g() {return 0;} \n" " void set_s(float) {} \n" "} \n" "void main() \n" "{ \n" " Test t; \n" " t.g = 0; \n" " t.s + 1; \n" "} \n"; mod->AddScriptSection("script", script8); bout.buffer = ""; r = mod->Build(); if( r >= 0 ) { TEST_FAILED; printf("Failed to compile the script\n"); } if( bout.buffer != "script (6, 1) : Info : Compiling void main()\n" "script (9, 7) : Error : The property has no set accessor\n" "script (10, 7) : Error : The property has no get accessor\n" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } // Test pre and post ++. Should fail, since the expression is not a variable const char *script9 = "class Test \n" "{ \n" " uint get_p() {return 0;} \n" " void set_p(uint) {} \n" "} \n" "void main() \n" "{ \n" " Test t; \n" " t.p++; \n" " --t.p; \n" "} \n"; mod->AddScriptSection("script", script9); bout.buffer = ""; r = mod->Build(); if( r >= 0 ) { TEST_FAILED; printf("Didn't fail to compile the script\n"); } if( bout.buffer != "script (6, 1) : Info : Compiling void main()\n" "script (9, 6) : Error : Invalid reference. Property accessors cannot be used in combined read/write operations\n" "script (10, 3) : Error : Invalid reference. Property accessors cannot be used in combined read/write operations\n" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } // Test using property accessors from within class methods without 'this' // Test accessor where the object is a handle const char *script10 = "class Test \n" "{ \n" " uint get_p() {return 0;} \n" " void set_p(uint) {} \n" " void test() \n" " { \n" " p = 0; \n" " int a = p; \n" " } \n" "} \n" "void func() \n" "{ \n" " Test @a = Test(); \n" " a.p = 1; \n" " int b = a.p; \n" "} \n"; mod->AddScriptSection("script", script10); bout.buffer = ""; r = mod->Build(); if( r < 0 ) { TEST_FAILED; printf("Failed to compile the script\n"); } if( bout.buffer != "" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } r = ExecuteString(engine, "func()", mod); if( r != asEXECUTION_FINISHED ) { TEST_FAILED; } // Test accessors with function arguments (by value, in ref, out ref) const char *script11 = "class Test \n" "{ \n" " uint get_p() {return 0;} \n" " void set_p(uint) {} \n" "} \n" "void func() \n" "{ \n" " Test a(); \n" " byVal(a.p); \n" " inArg(a.p); \n" " outArg(a.p); \n" "} \n" "void byVal(int v) {} \n" "void inArg(int &in v) {} \n" "void outArg(int &out v) {} \n"; mod->AddScriptSection("script", script11); bout.buffer = ""; r = mod->Build(); if( r < 0 ) { TEST_FAILED; printf("Failed to compile the script\n"); } if( bout.buffer != "" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } r = ExecuteString(engine, "func()", mod); if( r != asEXECUTION_FINISHED ) { TEST_FAILED; } // When the property is an object type, then the set accessor should be // used instead of the overloaded assignment operator to set the value. // Properties of object properties, must allow having different // types for get and set. IsEqualExceptConstAndRef should be used. const char *script12 = "class Test \n" "{ \n" " string get_s() {return _s;} \n" " void set_s(const string &in n) {_s = n;} \n" " string _s; \n" "} \n" "void func() \n" "{ \n" " Test t; \n" " t.s = 'hello'; \n" " assert(t.s == 'hello'); \n" "} \n"; mod->AddScriptSection("script", script12); bout.buffer = ""; r = mod->Build(); if( r < 0 ) { TEST_FAILED; printf("Failed to compile the script\n"); } if( bout.buffer != "" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } r = ExecuteString(engine, "func()", mod); if( r != asEXECUTION_FINISHED ) { TEST_FAILED; } // Compound assignments for object properties will not be allowed r = ExecuteString(engine, "Test t; t.s += 'hello';", mod); if( r >= 0 ) { TEST_FAILED; } if( bout.buffer != "ExecuteString (1, 13) : Error : Compound assignments with property accessors are not allowed\n" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } // Test @t.prop = @obj; Property is a handle, and the property is assigned a new handle. Should work const char *script13 = "class Test \n" "{ \n" " string@ get_s() {return _s;} \n" " void set_s(string @n) {@_s = @n;} \n" " string@ _s; \n" "} \n" "void func() \n" "{ \n" " Test t; \n" " string s = 'hello'; \n" " @t.s = @s; \n" // handle assignment " assert(t.s is s); \n" " t.s = 'other'; \n" // value assignment " assert(s == 'other'); \n" "} \n"; mod->AddScriptSection("script", script13); bout.buffer = ""; r = mod->Build(); if( r < 0 ) { TEST_FAILED; printf("Failed to compile the script\n"); } if( bout.buffer != "" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } r = ExecuteString(engine, "func()", mod); if( r != asEXECUTION_FINISHED ) { TEST_FAILED; } // Test accessing members of an object property const char *script14 = "class Test \n" "{ \n" " string get_s() {return _s;} \n" " void set_s(string n) {_s = n;} \n" " string _s; \n" "} \n" "void func() \n" "{ \n" " Test t; \n" " t.s = 'hello'; \n" // value assignment " assert(t.s == 'hello'); \n" " assert(t.s.length() == 5); \n" // this should work as length is const "} \n"; mod->AddScriptSection("script", script14); bout.buffer = ""; r = mod->Build(); if( r < 0 ) { TEST_FAILED; printf("Failed to compile the script\n"); } if( bout.buffer != "" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } r = ExecuteString(engine, "func()", mod); if( r != asEXECUTION_FINISHED ) { TEST_FAILED; } // Test accessing a non-const method on an object through a get accessor // Should at least warn since the object is just a temporary one bout.buffer.c_str(); r = ExecuteString(engine, "Test t; t.s.resize(4);", mod); if( r < 0 ) TEST_FAILED; if( (sizeof(void*) == 4 && bout.buffer != "ExecuteString (1, 13) : Warning : A non-const method is called on temporary object. Changes to the object may be lost.\n" "ExecuteString (1, 13) : Info : void string::resize(uint)\n") || (sizeof(void*) == 8 && bout.buffer != "ExecuteString (1, 13) : Warning : A non-const method is called on temporary object. Changes to the object may be lost.\n" "ExecuteString (1, 13) : Info : void string::resize(uint64)\n") ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } // Test opNeg for object through get accessor const char *script15 = "class Val { int opNeg() const { return -1; } } \n" "class Test \n" "{ \n" " Val get_s() const {return Val();} \n" "} \n" "void func() \n" "{ \n" " Test t; \n" " assert( -t.s == -1 ); \n" "} \n"; mod->AddScriptSection("script", script15); bout.buffer = ""; r = mod->Build(); if( r < 0 ) { TEST_FAILED; printf("Failed to compile the script\n"); } if( bout.buffer != "" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } r = ExecuteString(engine, "func()", mod); if( r != asEXECUTION_FINISHED ) { TEST_FAILED; } // Test index operator for object through get accessor const char *script16 = "class Test \n" "{ \n" " int[] get_s() const { int[] a(1); a[0] = 42; return a; } \n" "} \n" "void func() \n" "{ \n" " Test t; \n" " assert( t.s[0] == 42 ); \n" "} \n"; mod->AddScriptSection("script", script16); bout.buffer = ""; r = mod->Build(); if( r < 0 ) { TEST_FAILED; printf("Failed to compile the script\n"); } if( bout.buffer != "script (5, 1) : Info : Compiling void func()\n" "script (8, 14) : Warning : A non-const method is called on temporary object. Changes to the object may be lost.\n" "script (8, 14) : Info : int& array::opIndex(uint)\n" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } r = ExecuteString(engine, "func()", mod); if( r != asEXECUTION_FINISHED ) { TEST_FAILED; } // Test accessing normal properties for object through get accessor const char *script17 = "class Val { int val; } \n" "class Test \n" "{ \n" " Val get_s() const { Val v; v.val = 42; return v;} \n" "} \n" "void func() \n" "{ \n" " Test t; \n" " assert( t.s.val == 42 ); \n" "} \n"; mod->AddScriptSection("script", script17); bout.buffer = ""; r = mod->Build(); if( r < 0 ) { TEST_FAILED; printf("Failed to compile the script\n"); } if( bout.buffer != "" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } r = ExecuteString(engine, "func()", mod); if( r != asEXECUTION_FINISHED ) { TEST_FAILED; } // Test const/non-const get and set accessors const char *script18 = "class Test \n" "{ \n" " int get_p() { return 42; } \n" " int get_c() const { return 42; } \n" " void set_s(int) {} \n" "} \n" "void func() \n" "{ \n" " const Test @t = @Test(); \n" " assert( t.p == 42 ); \n" // Fail " assert( t.c == 42 ); \n" // Success " t.s = 42; \n" // Fail "} \n"; mod->AddScriptSection("script", script18); bout.buffer = ""; r = mod->Build(); if( r >= 0 ) TEST_FAILED; if( bout.buffer != "script (7, 1) : Info : Compiling void func()\n" "script (10, 15) : Error : Non-const method call on read-only object reference\n" "script (10, 15) : Info : int Test::get_p()\n" "script (12, 7) : Error : Non-const method call on read-only object reference\n" "script (12, 7) : Info : void Test::set_s(int)\n" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } // Test accessor with property of the same name const char *script19 = "int direction; \n" "void set_direction(int val) { direction = val; } \n" "void test_set() \n" "{ \n" " direction = 9; \n" // calls the set_direction property accessor "} \n" "void test_get() \n" "{ \n" " assert( direction == 9 ); \n" // fails, since there is no get accessor "} \n"; mod->AddScriptSection("script", script19); bout.buffer = ""; r = mod->Build(); if( r >= 0 ) TEST_FAILED; if( bout.buffer != "script (7, 1) : Info : Compiling void test_get()\n" "script (9, 21) : Error : The property has no get accessor\n" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } const char *script20 = "class Test { \n" " int direction; \n" " void set_direction(int val) { direction = val; } \n" "} \n"; mod->AddScriptSection("script", script20); bout.buffer = ""; r = mod->Build(); if( r < 0 ) TEST_FAILED; if( bout.buffer != "" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } r = ExecuteString(engine, "Test t; t.set_direction(3);", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; // TODO: Test non-const get accessor for object type with const overloaded dual operator // TODO: Test get accessor that returns a reference (only from application func to start with) // TODO: Test property accessor with inout references. Shouldn't be allowed as the value is not a valid reference // TODO: Test set accessor with parameter declared as out ref (shouldn't be found) // TODO: What should be done with expressions like t.prop; Should the get accessor be called even though // the value is never used? // TODO: Accessing a class member from within the property accessor with the same name as the property // shouldn't call the accessor again. Instead it should access the real member. FindPropertyAccessor() // shouldn't find any if the function being compiler is the property accessor itself engine->Release(); // Test property accessor on temporary object handle { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); RegisterStdString(engine); const char *script = "class Obj { void set_opacity(float v) {} }\n" "Obj @GetObject() { return @Obj(); } \n"; asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("script", script); r = mod->Build(); if( r < 0 ) TEST_FAILED; r = ExecuteString(engine, "GetObject().opacity = 1.0f;", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->Release(); } // Test bug reported by Scarabus2 // The bug was an incorrect reusage of temporary variable by the // property get accessor when compiling a binary operator { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); const char *script = "class Object { \n" " Object() {rot = 0;} \n" " void set_rotation(float r) {rot = r;} \n" " float get_rotation() const {return rot;} \n" " float rot; } \n"; asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("script", script); r = mod->Build(); if( r < 0 ) TEST_FAILED; r = ExecuteString(engine, "Object obj; \n" "float elapsed = 1.0f; \n" "float temp = obj.rotation + elapsed * 1.0f; \n" "obj.rotation = obj.rotation + elapsed * 1.0f; \n" "assert( obj.rot == 1 ); \n", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->Release(); } // Test global property accessor { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); const char *script = "int _s = 0; \n" "int get_s() { return _s; } \n" "void set_s(int v) { _s = v; } \n"; asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("script", script); r = mod->Build(); if( r < 0 ) TEST_FAILED; r = ExecuteString(engine, "s = 10; assert( s == 10 );", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->Release(); // The global property accessors are available to initialize global // variables, but can possibly throw an exception if used inappropriately. // This test also verifies that circular references between global // properties and functions is properly resolved by the GC. engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(CBufferedOutStream, Callback), &bout, asCALL_THISCALL); RegisterStdString(engine); bout.buffer = ""; script = "string _s = s; \n" "string get_s() { return _s; } \n"; mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("script", script); r = mod->Build(); if( r != asINIT_GLOBAL_VARS_FAILED ) TEST_FAILED; if( bout.buffer != "script (1, 13) : Error : Failed to initialize global variable '_s'\n" "script (2, 0) : Info : Exception 'Null pointer access' in 'string get_s()'\n" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } engine->Release(); } // Test property accessor for object in array { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); RegisterScriptArray(engine, true); engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); const char *script = "class MyObj { bool get_Active() { return true; } } \n"; asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("script", script); r = mod->Build(); if( r < 0 ) TEST_FAILED; r = ExecuteString(engine, "MyObj[] a(1); if( a[0].Active == true ) { } if( a[0].get_Active() == true ) { }", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->Release(); } // Test property accessor from within class method { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); const char *script = "class Vector3 \n" "{ \n" " float x; \n" " float y; \n" " float z; \n" "}; \n" "class Hoge \n" "{ \n" " const Vector3 get_pos() { return mPos; } \n" " const Vector3 foo() { return pos; } \n" " const Vector3 zoo() { return get_pos(); } \n" " Vector3 mPos; \n" "}; \n" "void main() \n" "{ \n" " Hoge h; \n" " Vector3 vec; \n" " vec = h.zoo(); \n" // ok " vec = h.foo(); \n" // runtime exception "} \n"; asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("script", script); r = mod->Build(); if( r < 0 ) TEST_FAILED; r = ExecuteString(engine, "main", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->Release(); } // Test property accessor in type conversion { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); RegisterScriptArray(engine, true); const char *script = "class sound \n" "{ \n" " int get_pitch() { return 1; } \n" " void set_pitch(int p) {} \n" "} \n" "void main() \n" "{ \n" " sound[] sounds(1) ; \n" " sounds[0].pitch = int(sounds[0].pitch)/2; \n" "} \n"; asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("script", script); r = mod->Build(); if( r < 0 ) TEST_FAILED; r = ExecuteString(engine, "main", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->Release(); } // Test property accessor in type conversion (2) { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); const char *script = "class sound \n" "{ \n" " const int &get_id() const { return i; } \n" " int i; \n" "} \n" "void main() \n" "{ \n" " sound s; \n" " if( s.id == 1 ) \n" " return; \n" "} \n"; asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("script", script); r = mod->Build(); if( r < 0 ) TEST_FAILED; r = ExecuteString(engine, "main", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->Release(); } // Test property accessors for opIndex { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); RegisterScriptArray(engine, false); RegisterScriptString(engine); engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); const char *script = "class CTest \n" "{ \n" " CTest() { arr.resize(5); } \n" " int get_opIndex(int i) const { return arr[i]; } \n" " void set_opIndex(int i, int v) { arr[i] = v; } \n" " array<int> arr; \n" "} \n" "void main() \n" "{ \n" " CTest s; \n" " s[0] = 42; \n" " assert( s[0] == 42 ); \n" " s[1] = 24; \n" " assert( s[1] == 24 ); \n" "} \n"; asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("script", script); r = mod->Build(); if( r < 0 ) TEST_FAILED; r = ExecuteString(engine, "main", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->Release(); } // Test global property accessors with index argument { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); RegisterScriptArray(engine, false); RegisterScriptString(engine); engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); const char *script = " int get_arr(int i) { arr.resize(5); return arr[i]; } \n" " void set_arr(int i, int v) { arr.resize(5); arr[i] = v; } \n" " array<int> arr; \n" "void main() \n" "{ \n" " arr[0] = 42; \n" " assert( arr[0] == 42 ); \n" " arr[1] = 24; \n" " assert( arr[1] == 24 ); \n" "} \n"; asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("script", script); r = mod->Build(); if( r < 0 ) TEST_FAILED; r = ExecuteString(engine, "main()", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->Release(); } // Test member property accessors with index argument { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); RegisterScriptArray(engine, false); RegisterScriptString(engine); engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); const char *script = "class CTest \n" "{ \n" " CTest() { arr.resize(5); } \n" " int get_arr(int i) { return arr[i]; } \n" " void set_arr(int i, int v) { arr[i] = v; } \n" " private array<int> arr; \n" " void test() \n" " { \n" " arr[0] = 42; \n" " assert( arr[0] == 42 ); \n" " arr[1] = 24; \n" " assert( arr[1] == 24 ); \n" " } \n" "} \n" "void main() \n" "{ \n" " CTest s; \n" " s.arr[0] = 42; \n" " assert( s.arr[0] == 42 ); \n" " s.arr[1] = 24; \n" " assert( s.arr[1] == 24 ); \n" " s.test(); \n" "} \n"; asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("script", script); r = mod->Build(); if( r < 0 ) TEST_FAILED; r = ExecuteString(engine, "main()", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->Release(); } // Test member property accessors with ++ where the set accessor takes a reference { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(CBufferedOutStream, Callback), &bout, asCALL_THISCALL); bout.buffer = ""; const char *script = "class CTest \n" "{ \n" " double _vol; \n" " double get_vol() const { return _vol; } \n" " void set_vol(double &in v) { _vol = v; } \n" "} \n" "CTest t; \n" "void main() \n" "{ \n" " for( t.vol = 0; t.vol < 10; t.vol++ ); \n" "} \n"; asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("script", script); r = mod->Build(); if( r >= 0 ) TEST_FAILED; if( bout.buffer != "script (8, 1) : Info : Compiling void main()\n" "script (10, 36) : Error : Invalid reference. Property accessors cannot be used in combined read/write operations\n" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } engine->Release(); } fail = Test2() || fail; // Success return fail; }
bool Test() { bool fail = false; fail = Test2() || fail; int r; COutStream out; CBufferedOutStream bout; asIScriptContext *ctx; asIScriptEngine *engine; // Compile array with default value in list { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); RegisterScriptString(engine); // ref type RegisterScriptArray(engine, false); engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); r = ExecuteString(engine, "array<string> a = {'a', , 'c', , 'e'}; assert( a[1] == '' );"); if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->Release(); } // Compile array with default value in list { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); RegisterStdString(engine); // value type RegisterScriptArray(engine, false); engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); r = ExecuteString(engine, "array<string> a = {'a', , 'c', , 'e'}; assert( a[1] == '' );"); if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->Release(); } // Compile nested array init list { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); RegisterScriptArray(engine, false); r = ExecuteString(engine, "array<array<int>> a = {{1,2},{3,4}};"); if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->Release(); } { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); RegisterScriptString(engine); RegisterScriptArray(engine, false); engine->RegisterGlobalFunction("void Assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); // Test sorting on array of handles mod->AddScriptSection(TESTNAME, "class Test { \n" " Test(int v) {val = v;} \n" " int opCmp(const Test & o) const { return val - o.val; } \n" " int val; \n" "} \n"); r = mod->Build(); if( r < 0 ) TEST_FAILED; ctx = engine->CreateContext(); r = ExecuteString(engine, "array<Test @> a = { Test(1), Test(4), Test(2), null, Test(3) }; \n" "a.sortAsc(); \n" "Assert( a[0] is null ); \n" "Assert( a[1].val == 1 ); \n" "Assert( a[2].val == 2 ); \n" "Assert( a[3].val == 3 ); \n" "Assert( a[4].val == 4 ); \n", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; if( r == asEXECUTION_EXCEPTION ) PrintException(ctx); ctx->Release(); // Test different signatures on opCmp and opEquals mod->AddScriptSection(TESTNAME, "class C \n" "{ \n" " C(int i) {i_ = i;} \n" // " bool opEquals (const C &in other) const\n" // " { \n" // " return i_ == other.i_; \n" // " } \n" // " int opCmp (const C &in other) const\n" // " { \n" // " return i_ - other.i_; \n" // " } \n" " bool opEquals (const C @ other) const\n" " { \n" " return i_ == other.i_; \n" " } \n" " int opCmp (const C @ other) const\n" " { \n" " return i_ - other.i_; \n" " } \n" " int i_; \n" "} \n" "void main (void) \n" "{ \n" " array<const C @> a2; \n" " a2.insertLast(@C(2)); \n" " a2.insertLast(@C(1)); \n" " a2.sortAsc(); \n" " Assert( a2[0].i_ == 1 ); \n" " Assert( a2[1].i_ == 2 ); \n" " C f(2); \n" " Assert( a2.find(f) == 1 ); \n" "} \n"); r = mod->Build(); if( r < 0 ) TEST_FAILED; ctx = engine->CreateContext(); r = ExecuteString(engine, "main()", mod, ctx); if( r != asEXECUTION_FINISHED ) TEST_FAILED; if( r == asEXECUTION_EXCEPTION ) PrintException(ctx); ctx->Release(); // Multiple tests in one mod->AddScriptSection(TESTNAME, script1, strlen(script1), 0); r = mod->Build(); if( r < 0 ) { TEST_FAILED; printf("%s: Failed to compile the script\n", TESTNAME); } ctx = engine->CreateContext(); r = ExecuteString(engine, "TestArray()", mod, ctx); if( r != asEXECUTION_FINISHED ) { if( r == asEXECUTION_EXCEPTION ) PrintException(ctx); printf("%s: Failed to execute script\n", TESTNAME); TEST_FAILED; } if( ctx ) ctx->Release(); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script2, strlen(script2), 0); r = mod->Build(); if( r < 0 ) { TEST_FAILED; printf("%s: Failed to compile the script\n", TESTNAME); } r = ExecuteString(engine, "TestArrayException()", mod); if( r != asEXECUTION_EXCEPTION ) { printf("%s: No exception\n", TESTNAME); TEST_FAILED; } // Must be possible to declare array of arrays mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script3, strlen(script3), 0); r = mod->Build(); if( r < 0 ) { TEST_FAILED; printf("%s: Failed to compile the script\n", TESTNAME); } ctx = engine->CreateContext(); r = ExecuteString(engine, "TestArrayMulti()", mod, ctx); if( r != asEXECUTION_FINISHED ) { printf("%s: Failure\n", TESTNAME); TEST_FAILED; } if( r == asEXECUTION_EXCEPTION ) { PrintException(ctx); } if( ctx ) ctx->Release(); ctx = 0; mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script4, strlen(script4), 0); r = mod->Build(); if( r < 0 ) { TEST_FAILED; printf("%s: Failed to compile the script\n", TESTNAME); } ctx = engine->CreateContext(); r = ExecuteString(engine, "TestArrayChar()", mod, ctx); if( r != asEXECUTION_FINISHED ) { printf("%s: Failure\n", TESTNAME); TEST_FAILED; } if( r == asEXECUTION_EXCEPTION ) { PrintException(ctx); } if( ctx ) ctx->Release(); // Initialization lists must work for array template mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script5, strlen(script5), 0); r = mod->Build(); if( r < 0 ) TEST_FAILED; ctx = engine->CreateContext(); r = ExecuteString(engine, "TestArrayInitList()", mod, ctx); if( r != asEXECUTION_FINISHED ) TEST_FAILED; if( r == asEXECUTION_EXCEPTION ) PrintException(ctx); if( ctx ) ctx->Release(); engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script6, strlen(script6), 0); r = mod->Build(); if( r >= 0 ) TEST_FAILED; if( bout.buffer != "Test_Addon_ScriptArray (1, 1) : Info : Compiling void Test()\n" "Test_Addon_ScriptArray (3, 20) : Error : Initialization lists cannot be used with 'array<int>@'\n" "Test_Addon_ScriptArray (4, 21) : Error : Initialization lists cannot be used with 'int'\n" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } // Array object must call default constructor of the script classes engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script7, strlen(script7), 0); r = mod->Build(); if( r < 0 ) TEST_FAILED; r = ExecuteString(engine, "Test()", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; // Test bool[] on Mac OS X with PPC CPU // Submitted by Edward Rudd const char *script8 = "array<bool> f(10); \n" "for (int i=0; i<10; i++) { \n" " f[i] = false; \n" "} \n" "Assert(f[0] == false); \n" "Assert(f[1] == false); \n" "f[0] = true; \n" "Assert(f[0] == true); \n" "Assert(f[1] == false); \n"; r = ExecuteString(engine, script8, mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; // Test reserve() { const char *script = "array<int> f; \n" "f.reserve(10); \n" "for( uint n = 0; n < 10; n++ ) \n" " f.insertAt(n, n); \n" "Assert( f.length() == 10 ); \n"; r = ExecuteString(engine, script, mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; } // Make sure it is possible to do multiple assignments with the array type r = ExecuteString(engine, "array<int> a, b, c; a = b = c;"); if( r < 0 ) TEST_FAILED; // Must support syntax as: array<array<int>>, i.e. without white space between the closing angled brackets. r = ExecuteString(engine, "array<array<int>> a(2); Assert( a.length() == 2 );"); if( r < 0 ) TEST_FAILED; // Must support arrays of handles r = ExecuteString(engine, "array<array<int>@> a(1); @a[0] = @array<int>(4);"); if( r < 0 ) TEST_FAILED; // Do not allow the instantiation of a template with a subtype that cannot be created bout.buffer = ""; engine->SetMessageCallback(asMETHOD(CBufferedOutStream, Callback), &bout, asCALL_THISCALL); engine->RegisterObjectType("single", 0, asOBJ_REF | asOBJ_NOHANDLE); r = ExecuteString(engine, "array<single> a;"); if( r >= 0 ) TEST_FAILED; if( bout.buffer != "ExecuteString (1, 7) : Error : Can't instanciate template 'array' with subtype 'single'\n" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } engine->Release(); } // Test too large arrays { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); RegisterScriptArray(engine, false); ctx = engine->CreateContext(); r = ExecuteString(engine, "array<int> a; a.resize(0xFFFFFFFF);", 0, ctx); if( r != asEXECUTION_EXCEPTION ) TEST_FAILED; else if( strcmp(ctx->GetExceptionString(), "Too large array size") != 0 ) TEST_FAILED; r = ExecuteString(engine, "array<int> a(0xFFFFFFFF);", 0, ctx); if( r != asEXECUTION_EXCEPTION ) TEST_FAILED; else if( strcmp(ctx->GetExceptionString(), "Too large array size") != 0 ) TEST_FAILED; r = ExecuteString(engine, "array<int> list;\n" "list.resize(3);\n" "list.reserve(-1);\n", 0, ctx); if( r != asEXECUTION_EXCEPTION ) TEST_FAILED; else if( strcmp(ctx->GetExceptionString(), "Too large array size") != 0 ) TEST_FAILED; ctx->Release(); engine->Release(); } // Test garbage collect with script class that holds array member { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); RegisterScriptArray(engine, false); asIScriptModule *mod = engine->GetModule("module", asGM_ALWAYS_CREATE); const char *script = "class MyTest \n" "{ \n" " array<int> myList; \n" "} \n"; mod->AddScriptSection("script", script); r = mod->Build(); if( r < 0 ) TEST_FAILED; asIScriptObject *obj = (asIScriptObject*)engine->CreateScriptObject(mod->GetObjectTypeByName("MyTest")); obj->Release(); engine->Release(); } // Test the default value constructor { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); RegisterScriptArray(engine, false); engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); asIScriptModule *mod = engine->GetModule("module", asGM_ALWAYS_CREATE); engine->SetEngineProperty(asEP_OPTIMIZE_BYTECODE, false); const char *script = "void main() \n" "{ \n" " array<int> arr(2, 42); \n" " assert(arr[0] == 42); \n" " assert(arr[1] == 42); \n" " array<array<int>> arr2(2, array<int>(2)); \n" " assert(arr2[0].length() == 2); \n" " assert(arr2[1].length() == 2); \n" " array<array<int>@> arr3(2, arr); \n" " assert(arr3[0] is arr); \n" " assert(arr3[1] is arr); \n" "} \n"; mod->AddScriptSection("script", script); r = mod->Build(); if( r < 0 ) TEST_FAILED; r = ExecuteString(engine, "main()", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->Release(); } // Test potential memory leak situation with circular reference between types { // Create the script engine asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); // Register array class RegisterScriptArray(engine, false); // Compile asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("script", "class Hoge" "{" " HogeManager@ hogeManager;" "};" "class HogeManager" "{" " array< Hoge >@ hoges;" "};" , 0); mod->Build(); // Release engine engine->Release(); } // Test creating script array from application { if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) { printf("Subtest: Skipped due to AS_MAX_PORTABILITY\n"); } else { asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); RegisterScriptArray(engine, false); RegisterScriptString(engine); r = engine->RegisterGlobalFunction("array<string@>@ CreateArrayOfStrings()", asFUNCTION(CreateArrayOfStrings), asCALL_CDECL); assert( r >= 0 ); r = ExecuteString(engine, "array<string@>@ arr = CreateArrayOfStrings()"); if( r != asEXECUTION_FINISHED ) TEST_FAILED; // Release engine engine->Release(); } } // Test insertAt, removeAt { asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); RegisterScriptArray(engine, false); RegisterScriptString(engine); engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); r = ExecuteString(engine, "array<string> arr = {'1','2','3'}; \n" "arr.insertAt(1, 'test'); \n" "assert( arr[1] == 'test' );\n" "arr.insertAt(4, '4'); \n" "assert( arr[4] == '4' );\n" "arr.removeAt(0); \n" "assert( arr[0] == 'test' );\n" "assert( arr[3] == '4' );\n"); if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->Release(); } // This test was failing on XBOX 360 { asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); RegisterScriptArray(engine, true); const char *script = "class ArrayOf \n" "{ \n" " uint8[] _boolList; \n" " int _numOfStockedObject; \n" " ArrayOf(int arraySizeMax) \n" " { \n" " _boolList.resize(arraySizeMax); \n" " _numOfStockedObject = 0; \n" " for(int i = 0; i < arraySizeMax; ++i) \n" " { \n" " _boolList[i] = 0; \n" " } \n" " } \n" "} \n"; asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("script", script); r = mod->Build(); if( r < 0 ) TEST_FAILED; r = ExecuteString(engine, "ArrayOf(100)", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->Release(); } // Array should call subtypes' opAssign when it exists { asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); RegisterScriptArray(engine, true); engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); const char *script = "int calls = 0; \n" "class Value \n" "{ \n" " int val; \n" " Value(int v) {val = v;} \n" " Value() {} \n" " Value &opAssign(const Value &in o) { calls++; return this; } \n" "} \n"; asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("script", script); r = mod->Build(); if( r < 0 ) TEST_FAILED; r = ExecuteString(engine, "array<Value> arr = {Value(2), Value(3), Value(0)}; \n" "assert( calls == 0 ); \n" "array<Value> arr2; \n" "arr2 = arr; \n" "assert( calls == 3 ); \n", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->Release(); } // test sorting { asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); RegisterScriptArray(engine, true); engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); const char *script = "class Value \n" "{ \n" " int val; \n" " Value(int v) {val = v;} \n" " Value() {} \n" " int opCmp(const Value &in o) {return val - o.val;} \n" "} \n"; asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("script", script); r = mod->Build(); if( r < 0 ) TEST_FAILED; r = ExecuteString(engine, "Value[] arr = {Value(2), Value(3), Value(0)}; \n" "arr.sortAsc(); \n" "assert(arr[0].val == 0); \n" "assert(arr[1].val == 2); \n" "assert(arr[2].val == 3);", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->Release(); } // Test { asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); RegisterScriptArray(engine, true); engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); const char *script = "bool TestSort() \n" "{ \n" " array<int> A = {1, 5, 2, 4, 3}; \n" " array<int> B = {1, 5, 2, 4, 3}; \n" " A.sortAsc(); \n" " B.sortDesc(); \n" " return \n" " A[0] == 1 && A[1] == 2 && A[2] == 3 && A[3] == 4 && A[4] == 5 && \n" " B[0] == 5 && B[1] == 4 && B[2] == 3 && B[3] == 2 && B[4] == 1; \n" "} \n" "bool TestReverse() \n" "{ \n" " array<int> A = {5, 4, 3, 2, 1}; \n" " A.reverse(); \n" " return A[0] == 1 && A[1] == 2 && A[2] == 3 && A[3] == 4 && A[4] == 5; \n" "} \n" "class cOpCmp \n" "{ \n" " cOpCmp() \n" " { \n" " a = 0; \n" " b = 0.0; \n" " } \n" " cOpCmp(int _a, float _b) \n" " { \n" " a = _a; \n" " b = _b; \n" " } \n" " void set(int _a, float _b) \n" " { \n" " a = _a; \n" " b = _b; \n" " } \n" " int opCmp(cOpCmp &in other) \n" " { \n" " return a - other.a; \n" " } \n" " int a; \n" " float b; \n" "} \n" "class cOpEquals \n" "{ \n" " cOpEquals() \n" " { \n" " a = 0; \n" " b = 0.0; \n" " } \n" " cOpEquals(int _a, float _b) \n" " { \n" " a = _a; \n" " b = _b; \n" " } \n" " void set(int _a, float _b) \n" " { \n" " a = _a; \n" " b = _b; \n" " } \n" " bool opEquals(cOpEquals &in other) \n" " { \n" " return a == other.a; \n" " } \n" " int a; \n" " float b; \n" "} \n" "bool TestFind() \n" "{ \n" " array<int> A = {5, 8, 3, 2, 0, 0, 2, 1}; \n" " if (A.find(10) != -1) \n" " return false; \n" " if (A.find(0) != 4) \n" " return false; \n" " if (A.find(1, 8) != 1) \n" " return false; \n" " if (A.find(2, 8) != -1) \n" " return false; \n" " array<cOpCmp> CMP(5); \n" " CMP[0].set(0, 0.0); \n" " CMP[1].set(1, 0.0); \n" " CMP[2].set(2, 0.0); \n" " CMP[3].set(3, 0.0); \n" " CMP[4].set(4, 0.0); \n" " if (CMP.find(cOpCmp(5, 0.0)) != -1) \n" " return false; \n" " if (CMP.find(2, cOpCmp(2, 1.0)) != 2) \n" " return false; \n" " if (CMP.find(3, cOpCmp(2, 1.0)) != -1) \n" " return false; \n" " array<cOpEquals> EQ(5); \n" " EQ[0].set(0, 0.0); \n" " EQ[1].set(1, 0.0); \n" " EQ[2].set(2, 0.0); \n" " EQ[3].set(3, 0.0); \n" " EQ[4].set(4, 0.0); \n" " if (EQ.find(cOpEquals(5, 0.0)) != -1) \n" " return false; \n" " if (EQ.find(2, cOpEquals(2, 1.0)) != 2) \n" " return false; \n" " if (EQ.find(3, cOpEquals(2, 1.0)) != -1) \n" " return false; \n" " return true; \n" "} \n" "int main() \n" "{ \n" " assert( TestSort() ); \n" " assert( TestReverse() ); \n" " assert( TestFind() ); \n" " return 789; \n" "} \n"; asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("script", script); r = mod->Build(); if( r < 0 ) TEST_FAILED; r = ExecuteString(engine, "assert( main() == 789 ); \n", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->Release(); } // Test array, with objects that don't have default constructor/factory { asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(CBufferedOutStream, Callback), &bout, asCALL_THISCALL); RegisterScriptArray(engine, true); engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); const char *script = "class CTest \n" "{ \n" " CTest(int v) {} \n" // With an explicit non-default constructor the compiler won't create the default constructor "} \n" "array<CTest> arr; \n"; asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("script", script); bout.buffer = ""; r = mod->Build(); if( r > 0 ) TEST_FAILED; if( bout.buffer != "script (5, 7) : Error : Can't instanciate template 'array' with subtype 'CTest'\n" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } engine->Release(); } { asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(CBufferedOutStream, Callback), &bout, asCALL_THISCALL); RegisterScriptArray(engine, true); const char *script = "class T { }; \n" "array<T> arr; \n"; asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("script", script); bout.buffer = ""; r = mod->Build(); if( r < 0 ) TEST_FAILED; if( bout.buffer != "" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } r = ExecuteString(engine, "array<T> arr(1); \n", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->Release(); } // Test problem with arrays of enums reported by Philip Bennefall { const char *script = "enum fruit \n" "{ \n" " APPLE, ORANGE, BANANA \n" "} \n" "void main() \n" "{ \n" " fruit[] basket; \n" " basket.insertLast(APPLE); \n" " basket.insertLast(ORANGE); \n" " basket.sortDesc(); \n" " int index = basket.find(APPLE); \n" " assert( index == 1 ); \n" "} \n"; asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(CBufferedOutStream, Callback), &bout, asCALL_THISCALL); RegisterScriptArray(engine, true); engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("script", script); bout.buffer = ""; r = mod->Build(); if( r < 0 ) TEST_FAILED; if( bout.buffer != "" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } r = ExecuteString(engine, "main()", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->Release(); } // Test problem with arrays and opEquals reported by Philip Bennefall { const char *script = "class fish \n" "{ \n" " bool opEquals(fish@ other) \n" // handles should be supported too " { \n" " return false; \n" " } \n" "} \n" "void main() \n" "{ \n" " fish[] ocean(100); \n" " fish nemo; \n" " int index = ocean.find(nemo); \n" "} \n"; asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(CBufferedOutStream, Callback), &bout, asCALL_THISCALL); RegisterScriptArray(engine, true); asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("script", script); bout.buffer = ""; r = mod->Build(); if( r < 0 ) TEST_FAILED; if( bout.buffer != "" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } r = ExecuteString(engine, "main()", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->Release(); } // Test problem with arrays and opEquals reported by Philip Bennefall { const char *script = "class fish \n" "{ \n" " bool opEquals(fish@ other) \n" " { \n" " return false; \n" " } \n" "} \n" "void main() \n" "{ \n" " fish@[] ocean(100); \n" " for(uint i=0; i<ocean.length(); i++) \n" " { \n" " fish fred; \n" " @(ocean[i]) = fred; \n" " } \n" " fish nemo; \n" " int index = ocean.find(nemo); \n" "} \n"; asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(CBufferedOutStream, Callback), &bout, asCALL_THISCALL); RegisterScriptArray(engine, true); asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("script", script); bout.buffer = ""; r = mod->Build(); if( r < 0 ) TEST_FAILED; if( bout.buffer != "" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } r = ExecuteString(engine, "main()", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->Release(); } // Test problem with arrays and opAssign reported by Philip Bennefall { const char *script = "array<uint> a, b = {0,1,2,3}; \n" "a.reserve(10); \n" "a = b; \n" "assert( a.length() == b.length() ); \n" "assert( a.length() == 4 ); \n" "for( uint n = 0; n < a.length(); n++ ) \n" " assert( a[n] == n ); \n"; asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); RegisterScriptArray(engine, true); engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); r = ExecuteString(engine, script); if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->Release(); } // Test findByRef { const char *script = "class Obj {} \n" "array<int> ia = {1,2,3}; \n" "array<Obj> oa = {Obj(), Obj()}; \n" "array<Obj@> ha = {Obj(), Obj()}; \n"; asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); RegisterScriptArray(engine, true); engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); asIScriptModule *mod = engine->GetModule("mod", asGM_ALWAYS_CREATE); mod->AddScriptSection("test", script); r = mod->Build(); if( r < 0 ) TEST_FAILED; r = ExecuteString(engine, "assert( ia.findByRef(ia[1]) == -1 ); \n" "Obj @obj = oa[1]; assert( oa.findByRef(obj) == 1 ); \n" "@obj = ha[1]; assert( ha.findByRef(obj) == 1 ); \n" "ha.insertLast(null); assert( ha.findByRef(null) == 2 ); \n", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->Release(); } // Success return fail; }
int TestMain () { Test1(); // requires malloc initialization so should be first Test2(); TestKeyDtor(); return Harness::Done; }
bool Test() { bool fail = false; if( !fail ) fail = Test2(); int r; asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); COutStream out; CBufferedOutStream bout; engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); RegisterScriptString_Generic(engine); engine->RegisterGlobalFunction("void Assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); // Register an interface from the application r = engine->RegisterInterface("appintf"); assert( r >= 0 ); r = engine->RegisterInterfaceMethod("appintf", "void test()"); assert( r >= 0 ); // Test working example asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script1, strlen(script1), 0); r = mod->Build(); if( r < 0 ) TEST_FAILED; r = ExecuteString(engine, "test()", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; // Test calling the interface method from the application asIObjectType *type = engine->GetModule(0)->GetObjectTypeByName("myclass"); asIScriptObject *obj = (asIScriptObject*)engine->CreateScriptObject(type); int intfTypeId = engine->GetModule(0)->GetTypeIdByDecl("myintf"); type = engine->GetObjectTypeById(intfTypeId); asIScriptFunction *func = type->GetMethodByDecl("void test()"); asIScriptContext *ctx = engine->CreateContext(); r = ctx->Prepare(func); if( r < 0 ) TEST_FAILED; ctx->SetObject(obj); ctx->Execute(); if( r != asEXECUTION_FINISHED ) TEST_FAILED; intfTypeId = engine->GetTypeIdByDecl("appintf"); type = engine->GetObjectTypeById(intfTypeId); func = type->GetMethodByDecl("void test()"); r = ctx->Prepare(func); if( r < 0 ) TEST_FAILED; ctx->SetObject(obj); ctx->Execute(); if( r != asEXECUTION_FINISHED ) TEST_FAILED; if( ctx ) ctx->Release(); if( obj ) obj->Release(); // Test class that don't implement all functions of the interface. // Test instanciating an interface. Shouldn't work. // Test that classes don't implement the same interface twice // Try copying an interface variable to another. Shouldn't work. // Test implicit conversion from class to interface that is not being implemented. Should give compiler error // Test implicit conversion from interface to class. Should give compiler error. engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script2, strlen(script2), 0); r = mod->Build(); if( r >= 0 ) TEST_FAILED; if( bout.buffer != "TestInterface (5, 7) : Error : Missing implementation of 'void intf::test()'\n" "TestInterface (9, 1) : Info : Compiling void test(intf&inout)\n" "TestInterface (11, 9) : Error : Interface 'intf' cannot be instantiated\n" "TestInterface (13, 6) : Error : No appropriate opAssign method found in 'intf' for value assignment\n" "TestInterface (15, 16) : Error : Can't implicitly convert from 'myclass&' to 'nointf@&'.\n" "TestInterface (16, 16) : Error : Can't implicitly convert from 'intf@&' to 'myclass@&'.\n" ) { PRINTF("%s", bout.buffer.c_str()); TEST_FAILED; } engine->Release(); // Test cast for both temporary handle and non-temporary handle { const char *script = "interface ScriptLogic {} \n" "class PlayerLogic : ScriptLogic {} \n" "ScriptLogic @getScriptObject() { return PlayerLogic(); } \n"; engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); RegisterStdString(engine); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script); r = mod->Build(); if( r < 0 ) TEST_FAILED; // Non-temporary handle r = ExecuteString(engine, "ScriptLogic @c = getScriptObject(); cast<PlayerLogic>(c);", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; // Temporary handle r = ExecuteString(engine, "cast<PlayerLogic>(getScriptObject());", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->Release(); } // It should be possible to inherit the implementation of an interface method { const char *script = "interface I { void method(); } \n" "class B { void method() {} } \n" "class D : B, I {} \n" "D d; \n"; engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection(TESTNAME, script); r = mod->Build(); if( r < 0 ) TEST_FAILED; engine->Release(); } // Allow script declared interfaces to inherit from other interfaces { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); const char *script = "interface A { void a(); } \n" "interface B : A { void b(); } \n" "class C : B {} \n"; // Must implement both a() and b() bout.buffer = ""; mod->AddScriptSection(TESTNAME, script); r = mod->Build(); if( r >= 0 ) TEST_FAILED; if( bout.buffer != "TestInterface (3, 7) : Error : Missing implementation of 'void B::b()'\n" "TestInterface (3, 7) : Error : Missing implementation of 'void A::a()'\n" ) { PRINTF("%s", bout.buffer.c_str()); TEST_FAILED; } // Don't allow shared interface to implement non-shared interface script = "interface A {} \n" "shared interface B : A {} \n"; bout.buffer = ""; mod->AddScriptSection(TESTNAME, script); r = mod->Build(); if( r >= 0 ) TEST_FAILED; if( bout.buffer != "TestInterface (2, 22) : Error : Shared type cannot implement non-shared interface 'A'\n" ) { PRINTF("%s", bout.buffer.c_str()); TEST_FAILED; } // Implicit casts to an inherited interface should work script = "interface A {} \n" "interface B : A {} \n" "void func() \n" "{ \n" " A@ a; B@ b; \n" " @a = b; \n" "} \n"; bout.buffer = ""; mod->AddScriptSection(TESTNAME, script); r = mod->Build(); if( r < 0 ) TEST_FAILED; if( bout.buffer != "" ) { PRINTF("%s", bout.buffer.c_str()); TEST_FAILED; } // Don't allow circular inheritance script = "interface A : C {} \n" "interface B : A {} \n" "interface C : B {} \n"; bout.buffer = ""; mod->AddScriptSection(TESTNAME, script); r = mod->Build(); if( r >= 0 ) TEST_FAILED; if( bout.buffer != "TestInterface (3, 15) : Error : Can't implement itself, or another interface that implements this interface\n" ) { PRINTF("%s", bout.buffer.c_str()); TEST_FAILED; } engine->Release(); } // http://www.gamedev.net/topic/638959-interface-inheritance-issue/ { engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL); engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("test", "shared interface ielement \n" "{ \n" " int func1(); \n" "} \n" "shared interface iscreen : ielement \n" "{ \n" " int func2(); \n" "} \n" "mixin class celementbase \n" "{ \n" " int func1() { return 1; } \n" "} \n" "class cscreen : celementbase, iscreen \n" "{ \n" " int func2() { return 2; } \n" "} \n" "void stuff( iscreen@ scr ) \n" "{ \n" " assert( scr.func1() == 1 ); \n" " assert( scr.func2() == 2 ); \n" "} \n"); bout.buffer = ""; r = mod->Build(); if( r < 0 ) TEST_FAILED; if( bout.buffer != "" ) { PRINTF("%s", bout.buffer.c_str()); TEST_FAILED; } r = ExecuteString(engine, "cscreen s; stuff(s);", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->Release(); } // Success return fail; }
bool Test() { bool fail = Test2(); int r; COutStream out; asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL); RegisterScriptString(engine); engine->RegisterGlobalFunction("void Assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("script", script, strlen(script)); r = mod->Build(); if( r < 0 ) TEST_FAILED; r = ExecuteString(engine, "uint8 newmask = 0xFF, mask = 0x15; Assert( (newmask & ~mask) == 0xEA );"); if( r != asEXECUTION_FINISHED ) TEST_FAILED; r = ExecuteString(engine, "uint8 newmask = 0xFF; newmask = newmask & (~mask2) & (~mask3) & (~mask5); Assert( newmask == 0xD3 );", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; r = ExecuteString(engine, "uint8 newmask = 0XFE; Assert( (newmask & mask0) == 0 );", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; r = ExecuteString(engine, "uint8 b = 0xFF; b &= ~mask4; BitsTest(b);", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; engine->RegisterGlobalFunction("uint8 ReturnByte(uint8)", asFUNCTION(ReturnByte), asCALL_GENERIC); engine->RegisterGlobalFunction("uint16 ReturnWord(uint16)", asFUNCTION(ReturnWord), asCALL_GENERIC); mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("script", script2, strlen(script2)); engine->SetEngineProperty(asEP_OPTIMIZE_BYTECODE, false); r = mod->Build(); if( r < 0 ) TEST_FAILED; r = ExecuteString(engine, "Test()", mod); if( r != asEXECUTION_FINISHED ) TEST_FAILED; // bitwise operators should maintain signed/unsigned type of left hand operand CBufferedOutStream bout; engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL); r = ExecuteString(engine, "int a = 0, b = 0; bool c = (a < (b>>1));"); if( r < 0 ) TEST_FAILED; r = ExecuteString(engine, "uint a = 0, b = 0; bool c = (a < (b>>1));"); if( r < 0 ) TEST_FAILED; if( bout.buffer != "" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } engine->Release(); // Success return fail; }
/*---------------------------------------------------------------------- | main +---------------------------------------------------------------------*/ int main(int argc, char** argv) { NPT_COMPILER_UNUSED(argc); NPT_HttpRequestHandler *handler, *custom_handler; NPT_Reference<NPT_DataBuffer> buffer; NPT_Size size; bool result; PLT_RingBufferStreamReference ringbuffer_stream(new PLT_RingBufferStream()); /* parse command line */ ParseCommandLine(argv); /* create http server */ PLT_HttpServer http_server(Options.port?Options.port:80); NPT_String url = "http://127.0.0.1:" + NPT_String::FromInteger(http_server.GetPort()); NPT_String custom_url = url; if (!Options.path.IsEmpty()) { /* extract folder path */ int index1 = Options.path.ReverseFind('\\'); int index2 = Options.path.ReverseFind('/'); if (index1 <= 0 && index2 <=0) { fprintf(stderr, "ERROR: invalid path\n"); exit(1); } NPT_FileInfo info; NPT_CHECK_SEVERE(NPT_File::GetInfo(Options.path, &info)); /* add file request handler */ handler = new NPT_HttpFileRequestHandler( Options.path.Left(index1>index2?index1:index2), "/"); http_server.AddRequestHandler(handler, "/", true); /* build url*/ url += "/" + Options.path.SubString((index1>index2?index1:index2)+1); } else { /* create random data */ buffer = new NPT_DataBuffer(32768); buffer->SetDataSize(32768); /* add static handler */ handler = new NPT_HttpStaticRequestHandler(buffer->GetData(), buffer->GetDataSize(), "text/xml"); http_server.AddRequestHandler(handler, "/test"); /* build url*/ url += "/test"; } /* add custom handler */ NPT_InputStreamReference stream(ringbuffer_stream); custom_handler = new PLT_HttpCustomRequestHandler(stream, "text/xml"); http_server.AddRequestHandler(custom_handler, "/custom"); custom_url += "/custom"; /* start server */ NPT_CHECK_SEVERE(http_server.Start()); /* a task manager for the tests downloader */ PLT_TaskManager task_manager; /* small delay to let the server start */ NPT_System::Sleep(NPT_TimeInterval(1, 0)); /* execute tests */ result = Test1(&task_manager, url.GetChars(), size); if (!result) return -1; result = Test2(&task_manager, url.GetChars(), size); if (!result) return -1; result = Test3(&task_manager, custom_url.GetChars(), ringbuffer_stream, size); if (!result) return -1; NPT_System::Sleep(NPT_TimeInterval(1, 0)); http_server.Stop(); delete handler; delete custom_handler; return 0; }
bool TestSdp() { if( Test( "v=0\r\n" "o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n" "s=SDP Seminar\r\n" "i=A Seminar on the session description protocol\r\n" "u=http://www.example.com/seminars/sdp.pdf\r\n" "[email protected] (Jane Doe)\r\n" "c=IN IP4 224.2.17.12/127\r\n" "t=2873397496 2873404696\r\n" "a=recvonly\r\n" "m=audio 49170 RTP/AVP 0\r\n" "m=video 51372 RTP/AVP 99\r\n" "a=rtpmap:99 h263-1998/90000\r\n", "v=0\r\n" "o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n" "s=SDP Seminar\r\n" "i=A Seminar on the session description protocol\r\n" "u=http://www.example.com/seminars/sdp.pdf\r\n" "[email protected] (Jane Doe)\r\n" "c=IN IP4 224.2.17.12/127\r\n" "t=2873397496 2873404696\r\n" "a=recvonly\r\n" "m=audio 49170 RTP/AVP 0\r\n" "m=video 51372 RTP/AVP 99\r\n" "a=rtpmap:99 h263-1998/90000\r\n" ) == false ) return false; if( Test( "v=0\r\n" "o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n" "s=SDP Seminar\r\n" "i=A Seminar on the session description protocol\r\n" "u=http://www.example.com/seminars/sdp.pdf\r\n" "[email protected] (Jane Doe)\r\n" "c=IN IP4 224.2.17.12/127\r\n" "b=X-YZ:128\r\n", "v=0\r\n" "o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n" "s=SDP Seminar\r\n" "i=A Seminar on the session description protocol\r\n" "u=http://www.example.com/seminars/sdp.pdf\r\n" "[email protected] (Jane Doe)\r\n" "c=IN IP4 224.2.17.12/127\r\n" "b=X-YZ:128\r\n" ) == false ) return false; if( Test( "v=0\r\n" "o=CiscoSystemsSIP-GW-UserAgent 7393 3874 IN IP4 192.10.228.41\r\n" "s=SIP Call\r\n" "c=IN IP4 192.10.228.41\r\n" "t=0 0\r\n" "m=audio 24864 RTP/AVP 0 101\r\n" "c=IN IP4 192.10.228.41\r\n" "a=rtpmap:0 PCMU/8000\r\n" "a=rtpmap:101 telephone-event/8000\r\n" "a=fmtp:101 0-16\r\n" "a=ptime:20\r\n" "\r\n" "--uniqueBoundary\r\n" "Content-Type: application/gtd\r\n" "Content-Disposition: signal;handling=optional\r\n" "\r\n" "IAM,\r\n" "PRN,isdn*,,NET5*,\r\n" "USI,rate,c,s,c,1\r\n" "USI,lay1,alaw\r\n" "TMR,00\r\n" "CPN,00,,1,2936\r\n" "CGN,04,,1,y,4,01075066103\r\n" "CPC,09\r\n" "FCI,,,,,,,y,\r\n" "GCI,5c2f3c7d861811e789221005ca2bd880\r\n" "--uniqueBoundary\r\n", "v=0\r\n" "o=CiscoSystemsSIP-GW-UserAgent 7393 3874 IN IP4 192.10.228.41\r\n" "s=SIP Call\r\n" "c=IN IP4 192.10.228.41\r\n" "t=0 0\r\n" "m=audio 24864 RTP/AVP 0 101\r\n" "c=IN IP4 192.10.228.41\r\n" "a=rtpmap:0 PCMU/8000\r\n" "a=rtpmap:101 telephone-event/8000\r\n" "a=fmtp:101 0-16\r\n" "a=ptime:20\r\n" ) == false ) return false; Test2( "v=0\r\n" "o=- 3593775777 3593775777 IN IP4 192.168.184.129\r\n" "s=media\r\n" "c=IN IP4 192.168.184.129\r\n" "t=0 0\r\n" "a=X-nat:0\r\n" "m=audio 11263 RTP/AVP 103 102 104 117 3 0 8 9 101\r\n" "a=rtcp:11264 IN IP4 192.168.184.129\r\n" "a=rtpmap:103 speex/16000\r\n" "a=rtpmap:102 speex/8000\r\n" "a=rtpmap:104 speex/32000\r\n" "a=rtpmap:117 iLBC/8000\r\n" "a=fmtp:117 mode=30\r\n" "a=rtpmap:3 GSM/8000\r\n" "a=rtpmap:0 PCMU/8000\r\n" "a=rtpmap:8 PCMA/8000\r\n" "a=rtpmap:9 G722/8000\r\n" "a=sendrecv\r\n" "a=rtpmap:101 telephone-event/8000\r\n" "a=fmtp:101 0-15\r\n" ); Test3( "v=0\r\n" "o=- 3593775777 3593775777 IN IP4 192.168.184.129\r\n" "s=media\r\n" "c=IN IP4 192.168.184.129\r\n" "t=0 0\r\n" "a=X-nat:0\r\n" "m=video 11263 RTP/AVP 97\r\n" "a=rtpmap:97 H264/90000\r\n" "a=fmtp:97 profile-level-id=428016;max-br=5000;max-mbps=490000;max-fs=9000;max-smbps=490000;max-fps=6000;max-rcmd-nalu-size=3456000\r\n" ); CSdpAttributeCrypto clsCrypto; const char * pszCrypto = "1 AES_CM_128_HMAC_SHA1_80 inline:7s65riA38OlE4U5OepU5zgaoMvzOL19nSQqeursI"; if( clsCrypto.Parse( pszCrypto, (int)strlen(pszCrypto) ) == -1 ) { printf( "crypto[%s] parser error\n", pszCrypto ); return false; } if( strcmp( clsCrypto.m_strTag.c_str(), "1" ) || strcmp( clsCrypto.m_strCryptoSuite.c_str(), "AES_CM_128_HMAC_SHA1_80" ) || strcmp( clsCrypto.m_strKey.c_str(), "7s65riA38OlE4U5OepU5zgaoMvzOL19nSQqeursI" ) ) { printf( "crypto[%s] parser result error\n", pszCrypto ); return false; } if( TestAudioMedia( "v=0\r\n" "o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\r\n" "s=SDP Seminar\r\n" "i=A Seminar on the session description protocol\r\n" "u=http://www.example.com/seminars/sdp.pdf\r\n" "[email protected] (Jane Doe)\r\n" "c=IN IP4 224.2.17.12/127\r\n" "t=2873397496 2873404696\r\n" "a=recvonly\r\n" "m=audio 49170 RTP/AVP 0\r\n" "m=video 51372 RTP/AVP 99\r\n" "a=rtpmap:99 h263-1998/90000\r\n" ) == false ) return false; if( Test4( "v=0\r\n" "o=- 3593775777 3593775777 IN IP4 192.168.184.129\r\n" "s=media\r\n" "c=IN IP4 192.168.184.129\r\n" "t=0 0\r\n" "a=X-nat:0\r\n" "m=audio 11263 RTP/AVP 103 102 104 117 3 0 8 9 101\r\n" "a=rtcp:11264 IN IP4 192.168.184.129\r\n" "a=rtpmap:103 speex/16000\r\n" "a=rtpmap:102 speex/8000\r\n" "a=rtpmap:104 speex/32000\r\n" "a=rtpmap:117 iLBC/8000\r\n" "a=fmtp:117 mode=30\r\n" "a=rtpmap:3 GSM/8000\r\n" "a=rtpmap:0 PCMU/8000\r\n" "a=rtpmap:8 PCMA/8000\r\n" "a=rtpmap:9 G722/8000\r\n" "a=sendrecv\r\n" "a=rtpmap:101 telephone-event/8000\r\n" "a=fmtp:101 0-15\r\n" , "v=0\r\n" "o=- 3593775777 3593775777 IN IP4 192.168.184.129\r\n" "s=media\r\n" "c=IN IP4 192.168.184.129\r\n" "t=0 0\r\n" "a=X-nat:0\r\n" "m=audio 11263 RTP/AVP 8 101\r\n" "a=rtcp:11264 IN IP4 192.168.184.129\r\n" "a=rtpmap:8 PCMA/8000\r\n" "a=sendrecv\r\n" "a=rtpmap:101 telephone-event/8000\r\n" "a=fmtp:101 0-15\r\n") == false ) return false; if( TestTopCodec( "v=0\r\n" "o=- 3593775777 3593775777 IN IP4 192.168.184.129\r\n" "s=media\r\n" "c=IN IP4 192.168.184.129\r\n" "t=0 0\r\n" "a=X-nat:0\r\n" "m=audio 11263 RTP/AVP 103 102 104 117 3 0 8 9 101\r\n" "a=rtcp:11264 IN IP4 192.168.184.129\r\n" "a=rtpmap:103 speex/16000\r\n" "a=rtpmap:102 speex/8000\r\n" "a=rtpmap:104 speex/32000\r\n" "a=rtpmap:117 iLBC/8000\r\n" "a=fmtp:117 mode=30\r\n" "a=rtpmap:3 GSM/8000\r\n" "a=rtpmap:0 PCMU/8000\r\n" "a=rtpmap:8 PCMA/8000\r\n" "a=rtpmap:9 G722/8000\r\n" "a=sendrecv\r\n" "a=rtpmap:101 telephone-event/8000\r\n" "a=fmtp:101 0-15\r\n" , "v=0\r\n" "o=- 3593775777 3593775777 IN IP4 192.168.184.129\r\n" "s=media\r\n" "c=IN IP4 192.168.184.129\r\n" "t=0 0\r\n" "a=X-nat:0\r\n" "m=audio 11263 RTP/AVP 8 103 102 104 117 3 0 9 101\r\n" "a=rtcp:11264 IN IP4 192.168.184.129\r\n" "a=rtpmap:8 PCMA/8000\r\n" "a=rtpmap:103 speex/16000\r\n" "a=rtpmap:102 speex/8000\r\n" "a=rtpmap:104 speex/32000\r\n" "a=rtpmap:117 iLBC/8000\r\n" "a=fmtp:117 mode=30\r\n" "a=rtpmap:3 GSM/8000\r\n" "a=rtpmap:0 PCMU/8000\r\n" "a=rtpmap:9 G722/8000\r\n" "a=sendrecv\r\n" "a=rtpmap:101 telephone-event/8000\r\n" "a=fmtp:101 0-15\r\n", 8 ) == false ) return false; if( TestTopCodec( "v=0\r\n" "o=- 3593775777 3593775777 IN IP4 192.168.184.129\r\n" "s=media\r\n" "c=IN IP4 192.168.184.129\r\n" "t=0 0\r\n" "a=X-nat:0\r\n" "m=audio 11263 RTP/AVP 103 102 104 117 3 0 8 9 101\r\n" "a=rtcp:11264 IN IP4 192.168.184.129\r\n" "a=rtpmap:103 speex/16000\r\n" "a=rtpmap:102 speex/8000\r\n" "a=rtpmap:104 speex/32000\r\n" "a=rtpmap:117 iLBC/8000\r\n" "a=fmtp:117 mode=30\r\n" "a=rtpmap:3 GSM/8000\r\n" "a=rtpmap:0 PCMU/8000\r\n" "a=rtpmap:8 PCMA/8000\r\n" "a=rtpmap:9 G722/8000\r\n" "a=sendrecv\r\n" "a=rtpmap:101 telephone-event/8000\r\n" "a=fmtp:101 0-15\r\n" , "v=0\r\n" "o=- 3593775777 3593775777 IN IP4 192.168.184.129\r\n" "s=media\r\n" "c=IN IP4 192.168.184.129\r\n" "t=0 0\r\n" "a=X-nat:0\r\n" "m=audio 11263 RTP/AVP 117 103 102 104 3 0 8 9 101\r\n" "a=rtcp:11264 IN IP4 192.168.184.129\r\n" "a=rtpmap:117 iLBC/8000\r\n" "a=fmtp:117 mode=30\r\n" "a=rtpmap:103 speex/16000\r\n" "a=rtpmap:102 speex/8000\r\n" "a=rtpmap:104 speex/32000\r\n" "a=rtpmap:3 GSM/8000\r\n" "a=rtpmap:0 PCMU/8000\r\n" "a=rtpmap:8 PCMA/8000\r\n" "a=rtpmap:9 G722/8000\r\n" "a=sendrecv\r\n" "a=rtpmap:101 telephone-event/8000\r\n" "a=fmtp:101 0-15\r\n", 117 ) == false ) return false; if( TestTopCodec( "v=0\r\n" "o=- 3593775777 3593775777 IN IP4 192.168.184.129\r\n" "s=media\r\n" "c=IN IP4 192.168.184.129\r\n" "t=0 0\r\n" "a=X-nat:0\r\n" "m=audio 11263 RTP/AVP 8 101\r\n" "a=rtpmap:8 PCMA/8000\r\n" "a=sendrecv\r\n" "a=rtpmap:101 telephone-event/8000\r\n" "a=fmtp:101 0-15\r\n" , "v=0\r\n" "o=- 3593775777 3593775777 IN IP4 192.168.184.129\r\n" "s=media\r\n" "c=IN IP4 192.168.184.129\r\n" "t=0 0\r\n" "a=X-nat:0\r\n" "m=audio 11263 RTP/AVP 8 101\r\n" "a=rtpmap:8 PCMA/8000\r\n" "a=sendrecv\r\n" "a=rtpmap:101 telephone-event/8000\r\n" "a=fmtp:101 0-15\r\n", 8 ) == false ) return false; if( TestTopCodec( "v=0\r\n" "o=- 3593775777 3593775777 IN IP4 192.168.184.129\r\n" "s=media\r\n" "c=IN IP4 192.168.184.129\r\n" "t=0 0\r\n" "a=X-nat:0\r\n" "m=audio 11263 RTP/AVP 103 102 104 117 3 0 8 9 101\r\n" "a=rtcp:11264 IN IP4 192.168.184.129\r\n" "a=rtpmap:103 speex/16000\r\n" "a=rtpmap:102 speex/8000\r\n" "a=rtpmap:104 speex/32000\r\n" "a=rtpmap:117 iLBC/8000\r\n" "a=fmtp:117 mode=30\r\n" "a=rtpmap:3 GSM/8000\r\n" "a=rtpmap:0 PCMU/8000\r\n" "a=rtpmap:8 PCMA/8000\r\n" "a=rtpmap:9 G722/8000\r\n" "a=sendrecv\r\n" "a=rtpmap:101 telephone-event/8000\r\n" "a=fmtp:101 0-15\r\n" , "v=0\r\n" "o=- 3593775777 3593775777 IN IP4 192.168.184.129\r\n" "s=media\r\n" "c=IN IP4 192.168.184.129\r\n" "t=0 0\r\n" "a=X-nat:0\r\n" "m=audio 11263 RTP/AVP 103 102 104 117 3 0 8 9 101\r\n" "a=rtcp:11264 IN IP4 192.168.184.129\r\n" "a=rtpmap:103 speex/16000\r\n" "a=rtpmap:102 speex/8000\r\n" "a=rtpmap:104 speex/32000\r\n" "a=rtpmap:117 iLBC/8000\r\n" "a=fmtp:117 mode=30\r\n" "a=rtpmap:3 GSM/8000\r\n" "a=rtpmap:0 PCMU/8000\r\n" "a=rtpmap:8 PCMA/8000\r\n" "a=rtpmap:9 G722/8000\r\n" "a=sendrecv\r\n" "a=rtpmap:101 telephone-event/8000\r\n" "a=fmtp:101 0-15\r\n", 300 ) == false ) return false; return true; }
// CHECK: @_ZN9BaseClass2t1E = constant {{.*}} { i32 3, i8 1, i8 1, i8 1, double 4.000000e+00, i8 1, i32 5 }, align 8 extern constexpr Test1 t1 = Test1(); struct DN : D, N {}; struct DND : DN, X<D,0> {}; struct DNN : DN, X<N,0> {}; // CHECK: @_ZN9BaseClass3dndE = constant {{.*}} { double 4.000000e+00, i32 3, double 4.000000e+00 } extern constexpr DND dnd = DND(); // Note, N subobject is laid out in DN subobject's tail padding. // CHECK: @_ZN9BaseClass3dnnE = constant {{.*}} { double 4.000000e+00, i32 3, i32 3 } extern constexpr DNN dnn = DNN(); struct E {}; struct Test2 : X<E,0>, X<E,1>, X<E,2>, X<E,3> {}; // CHECK: @_ZN9BaseClass2t2E = constant {{.*}} undef extern constexpr Test2 t2 = Test2(); struct __attribute((packed)) PackedD { double y = 2; }; struct Test3 : C, PackedD { constexpr Test3() {} }; // CHECK: @_ZN9BaseClass2t3E = constant <{ i8, double }> <{ i8 1, double 2.000000e+00 }> extern constexpr Test3 t3 = Test3(); } namespace Array { // CHECK: @_ZN5Array3arrE = constant [2 x i32] [i32 4, i32 0] extern constexpr int arr[2] = { 4 }; // CHECK: @_ZN5Array1cE = constant [6 x [4 x i8]] [{{.*}} c"foo\00", [4 x i8] c"a\00\00\00", [4 x i8] c"bar\00", [4 x i8] c"xyz\00", [4 x i8] c"b\00\00\00", [4 x i8] c"123\00"] extern constexpr char c[6][4] = { "foo", "a", { "bar" }, { 'x', 'y', 'z' }, { "b" }, '1', '2', '3' }; // CHECK: @_ZN5Array2ucE = constant [4 x i8] c"foo\00"
bool Test() { if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) { printf("%s: Skipped due to AS_MAX_PORTABILITY\n", "TestInheritance"); return false; } bool fail = false; int r; asIScriptModule *mod = 0; COutStream out; asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); RegisterStdString(engine); engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); engine->RegisterGlobalFunction("void print(const string &in)", asFUNCTION(print), asCALL_CDECL); const char *script = "bool baseDestructorCalled = false; \n" "bool baseConstructorCalled = false; \n" "bool baseFloatConstructorCalled = false; \n" "class Base : Intf \n" "{ \n" " int a; \n" " void f1() { a = 1; } \n" " void f2() { a = 0; } \n" " void f3() { a = 3; } \n" " Base() { baseConstructorCalled = true; } \n" " Base(float) { baseFloatConstructorCalled = true; } \n" " ~Base() { baseDestructorCalled = true; } \n" "} \n" "bool derivedDestructorCalled = false; \n" "bool derivedConstructorCalled = false; \n" "class Derived : Base \n" "{ \n" // overload f2() " void f2() { a = 2; } \n" // overload f3() " void f3() { a = 2; } \n" " void func() \n" " { \n" // call Base::f1() " f1(); \n" " assert(a == 1); \n" // call Derived::f2() " f2(); \n" " assert(a == 2); \n" // call Base::f3() " Base::f3(); \n" " assert(a == 3); \n" " } \n" " Derived() {} \n" " Derived(int) { derivedConstructorCalled = true; } \n" " ~Derived() { derivedDestructorCalled = true; } \n" "} \n" "void foo( Base &in a ) \n" "{ \n" " assert( cast<Derived>(a) is null ); \n" "} \n" // Must be possible to call the default constructor, even if not declared "class DerivedGC : BaseGC { DerivedGC() { super(); } } \n" "class BaseGC { BaseGC @b; } \n" "class DerivedS : Base \n" "{ \n" " DerivedS(float) \n" " { \n" // Call Base::Base(float) " if( true ) \n" " super(1.4f); \n" " else \n" " super(); \n" " } \n" "} \n" // Must handle inheritance where the classes have been declared out of order "void func() \n" "{ \n" " Intf@ a = C(); \n" "} \n" "class C : B {} \n" "interface Intf {} \n" "class B : Intf {} \n" // Several levels of inheritance "class C0 \n" "{ \n" " void Dummy() {} \n" "} \n" "class C1 : C0 \n" "{ \n" " void Fun() { print('C1:Fun'); } \n" "} \n" "class C2 : C1 \n" "{ \n" " void Fun() { print('C2:Fun'); } \n" "} \n" "class C3 : C2 \n" "{ \n" " void Call() { Fun(); } \n" "} \n"; mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("script", script); r = mod->Build(); if( r < 0 ) { TEST_FAILED; } if( TestModule(0, engine) ) { TEST_FAILED; } // Must make sure that the inheritance path is stored/restored with the saved byte code { CBytecodeStream stream(__FILE__"1"); r = mod->SaveByteCode(&stream); if( r < 0 ) { TEST_FAILED; } asIScriptModule *mod2 = engine->GetModule("2", asGM_ALWAYS_CREATE); r = mod2->LoadByteCode(&stream); if( r < 0 ) { TEST_FAILED; } // Both modules should have the same number of functions if( mod->GetFunctionCount() != mod2->GetFunctionCount() ) { TEST_FAILED; asUINT n; printf("First module's functions\n"); for( n = 0; n < (asUINT)mod->GetFunctionCount(); n++ ) { asIScriptFunction *f = mod->GetFunctionByIndex(n); printf("%s\n", f->GetDeclaration()); } printf("\nSecond module's functions\n"); for( n = 0; n < (asUINT)mod2->GetFunctionCount(); n++ ) { asIScriptFunction *f = mod2->GetFunctionByIndex(n); printf("%s\n", f->GetDeclaration()); } } if( TestModule("2", engine) ) { TEST_FAILED; } engine->DiscardModule("2"); } engine->Release(); // Test final and override { CBufferedOutStream bout; asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(CBufferedOutStream, Callback), &bout, asCALL_THISCALL); asIScriptModule *mod = engine->GetModule("test", asGM_ALWAYS_CREATE); mod->AddScriptSection("test", "final class CFin1 {} \n" // Don't allow inheritance "shared final class CFin2 {} \n" // -"- "class CBase \n" "{ \n" " void finalFunc() final {} \n" // don't allow override this func " void overrideFunc() {} \n" "} \n" "class CD1 : CFin1 {} \n" // Shouldn't work "class CD2 : CBase \n" "{ \n" " void finalFunc() {} \n" // shouldn't work " void overrideFunc(int) override {} \n" // must override "} \n"); int r = mod->Build(); if( r >= 0 ) TEST_FAILED; if( bout.buffer != "test (8, 13) : Error : Can't inherit from class 'CFin1' marked as final\n" "test (9, 7) : Error : Method 'void CBase::finalFunc()' declared as final and cannot be overridden\n" "test (9, 7) : Error : Method 'void CD2::overrideFunc(int)' marked as override but does not replace any base class or interface method\n" ) { printf("%s", bout.buffer.c_str()); TEST_FAILED; } engine->Release(); } fail = Test2() || fail; // Success return fail; }