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; }
bool Test() { bool fail = false; int r; asIScriptModule *mod = 0; COutStream out; asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION); engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL); engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); 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(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"; mod = engine->GetModule(0, asGM_ALWAYS_CREATE); mod->AddScriptSection("script", script); r = mod->Build(); if( r < 0 ) { fail = true; } if( TestModule(0, engine) ) { fail = true; } // 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 ) { fail = true; } asIScriptModule *mod2 = engine->GetModule("2", asGM_ALWAYS_CREATE); r = mod2->LoadByteCode(&stream); if( r < 0 ) { fail = true; } // Both modules should have the same number of functions if( mod->GetFunctionCount() != mod2->GetFunctionCount() ) { fail = true; asUINT n; printf("First module's functions\n"); for( n = 0; n < (asUINT)mod->GetFunctionCount(); n++ ) { asIScriptFunction *f = mod->GetFunctionDescriptorByIndex(n); printf("%s\n", f->GetDeclaration()); } printf("\nSecond module's functions\n"); for( n = 0; n < (asUINT)mod2->GetFunctionCount(); n++ ) { asIScriptFunction *f = mod2->GetFunctionDescriptorByIndex(n); printf("%s\n", f->GetDeclaration()); } } if( TestModule("2", engine) ) { fail = true; } engine->DiscardModule("2"); } engine->Release(); fail = Test2() || fail; // Success return fail; }
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; }