コード例 #1
0
bool Test()
{
	bool fail = false;
	int r;
	COutStream out;
	asIScriptContext *ctx;
	asIScriptEngine *engine;
	CBufferedOutStream bout;
	asIScriptModule *mod;

	// ---------------------------------------------
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		RegisterScriptArray(engine, true);
		RegisterScriptString_Generic(engine);
		RegisterScriptAny(engine);
		engine->RegisterGlobalFunction("void Assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);
		r = engine->RegisterGlobalFunction("void SetMyAny(any@)", asFUNCTION(SetMyAny), asCALL_GENERIC); assert( r >= 0 );

		mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
		mod->AddScriptSection("TestAny", script1, strlen(script1), 0);
		engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);
		r = mod->Build();
		if( r < 0 )
		{
			TEST_FAILED;
			PRINTF("%s: Failed to compile the script\n", "TestAny");
		}
		ctx = engine->CreateContext();
		r = ExecuteString(engine, "TestAny()", mod, ctx);
		if( r != asEXECUTION_FINISHED )
		{
			if( r == asEXECUTION_EXCEPTION )
				PrintException(ctx);

			TEST_FAILED;
			PRINTF("%s: Execution failed\n", "TestAny");
		}
		if( ctx ) ctx->Release();
		engine->Release();
	}

	//--------------------------------------------------
	// Verify that the GC can handle circles with any structures
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		RegisterScriptArray(engine, true);
		RegisterScriptString_Generic(engine);
		RegisterScriptAny(engine);
		engine->RegisterGlobalFunction("void Assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);
		r = engine->RegisterGlobalFunction("void SetMyAny(any@)", asFUNCTION(SetMyAny), asCALL_GENERIC); assert( r >= 0 );

		mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
		mod->AddScriptSection("TestAny", script2, strlen(script2), 0);
		engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);
		r = mod->Build();
		if( r < 0 )
		{
			TEST_FAILED;
			PRINTF("%s: Failed to compile the script\n", "TestAny");
		}
		ctx = engine->CreateContext();
		r = ExecuteString(engine, "TestAny()", mod, ctx);
		if( r != asEXECUTION_FINISHED )
		{
			if( r == asEXECUTION_EXCEPTION )
				PrintException(ctx);

			TEST_FAILED;
			PRINTF("%s: Execution failed\n", "TestAny");
		}
		if( ctx ) ctx->Release();
		
		asUINT gcCurrentSize, gcTotalDestroyed, gcTotalDetected;
		engine->GetGCStatistics(&gcCurrentSize, &gcTotalDestroyed, &gcTotalDetected);
		engine->GarbageCollect();
		engine->GetGCStatistics(&gcCurrentSize, &gcTotalDestroyed, &gcTotalDetected);

		if( !fail )
			assert( gcCurrentSize == 0 && gcTotalDestroyed == 8 && gcTotalDetected == 7 );

		engine->Release();
	}

	//-------------------------------------------------------
	// Don't allow const handle to retrieve()
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		RegisterScriptArray(engine, true);
		RegisterScriptString_Generic(engine);
		RegisterScriptAny(engine);
		engine->RegisterGlobalFunction("void Assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);
		r = engine->RegisterGlobalFunction("void SetMyAny(any@)", asFUNCTION(SetMyAny), asCALL_GENERIC); assert( r >= 0 );

		mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
		mod->AddScriptSection("TestAny", script3, strlen(script3), 0);
		engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL);
		r = mod->Build();
		if( r < 0 )
		{
			TEST_FAILED;
			PRINTF("%s: Failed to Build()\n", "TestAny");
		}
		if( bout.buffer != "TestAny (5, 1) : Info    : Compiling void TestAny()\n"
				   "TestAny (9, 15) : Warning : Argument cannot be assigned. Output will be discarded.\n" )
		{
			PRINTF("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		engine->Release();
	}

	//--------------------------------------------------------
	// Make sure it is possible to pass any to the application
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		RegisterScriptArray(engine, true);
		RegisterScriptString_Generic(engine);
		RegisterScriptAny(engine);
		engine->RegisterGlobalFunction("void Assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);
		r = engine->RegisterGlobalFunction("void SetMyAny(any@)", asFUNCTION(SetMyAny), asCALL_GENERIC); assert( r >= 0 );

		mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
		mod->AddScriptSection("TestAny", script4, strlen(script4), 0);
		engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);
		r = mod->Build();
		if( r < 0 )
		{
			TEST_FAILED;
			PRINTF("%s: Failed to compile\n", "TestAny");
		}
		
		r = ExecuteString(engine, "TestAny()", mod);
		if( r != asEXECUTION_FINISHED )
		{
			TEST_FAILED;
			PRINTF("%s: Failed to execute\n", "TestAny");
		}

		if( myAny )
		{
			int typeId = myAny->GetTypeId();

			if( !(typeId & asTYPEID_OBJHANDLE) )
				TEST_FAILED;
			if( (typeId & asTYPEID_MASK_OBJECT) != asTYPEID_APPOBJECT )
				TEST_FAILED;

			const char *decl = engine->GetTypeDeclaration(typeId);
			if( (decl == 0) || (strcmp(decl, "string@") != 0) )
			{
				TEST_FAILED;
				PRINTF("%s: Failed to return the correct type\n", "TestAny");
			}

			int typeId2 = engine->GetTypeIdByDecl("string@");
			if( typeId != typeId2 )
			{
				TEST_FAILED;
				PRINTF("%s: Failed to return the correct type\n", "TestAny");
			}

			CScriptString *str = 0;
			myAny->Retrieve((void*)&str, typeId);

			if( str->buffer != "test" )
			{
				TEST_FAILED;
				PRINTF("%s: Failed to set the string correctly\n", "TestAny");
			}

			if( str ) str->Release();

			myAny->Release();
			myAny = 0;
		}
		else
			TEST_FAILED;

		//--------------------------------------
		// Make sure the any type can store primitives as well
		r = ExecuteString(engine, "any a; a.store(1); int b; a.retrieve(b); Assert(b == 1);");
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		engine->Release();
	}

	// Test storing value type
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);

		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);

		RegisterScriptMath3D(engine);
		RegisterScriptAny(engine);

		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

		mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
	
		const char *script =
			"void main() \n"
			"{ \n"
			" any storage; \n"
			" storage.store(vector3(1,1,1)); \n"
			"} \n";

		mod->AddScriptSection("script", script);
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		ctx = engine->CreateContext();
		r = ExecuteString(engine, "main()", mod, ctx);
		if( r != asEXECUTION_FINISHED )
		{
			if( r == asEXECUTION_EXCEPTION )
				PrintException(ctx);
			TEST_FAILED;
		}
		ctx->Release();

		engine->Release();
	}

	// Test storing null pointer
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);

		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);
		RegisterScriptAny(engine);

		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

		r = ExecuteString(engine, "any a; a.store(null);", 0);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		engine->Release();
	}

	// Success
 	return fail;
}
コード例 #2
0
bool Test()
{
	bool fail = false;
	int r;
	COutStream out;
	CBufferedOutStream bout;
	asIScriptEngine *engine;

	// Ordinary tests
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);
		RegisterScriptWeakRef(engine);
		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

		const char *script =
			"class Test {} \n"
			"void main() { \n"
			"  Test @t = Test(); \n"
			"  weakref<Test> r(t); \n"
			"  assert( r.get() !is null ); \n"
			"  @t = null; \n"
			"  assert( r.get() is null ); \n"
			"} \n";

		asIScriptModule *mod = engine->GetModule("test", asGM_ALWAYS_CREATE);
		mod->AddScriptSection(TESTNAME, script);
		r = mod->Build();
		if( r < 0 )
		{
			TEST_FAILED;
			PRINTF("%s: Failed to compile the script\n", TESTNAME);
		}

		r = ExecuteString(engine, "main()", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		engine->Release();
	}

	// It shouldn't be possible to instanciate the weakref for types that do not support it
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL);
		bout.buffer = "";
		RegisterScriptWeakRef(engine);
		RegisterStdString(engine);
		RegisterScriptArray(engine, false);
		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

		const char *script =
			"class Test {} \n"
			"void main() { \n"
			"  weakref<int> a; \n"         // fail
			"  weakref<string> b; \n"      // fail
			"  weakref<Test@> c; \n"       // fail
			"  weakref<array<Test>> d; \n" // fail
			"} \n";

		asIScriptModule *mod = engine->GetModule("test", asGM_ALWAYS_CREATE);
		mod->AddScriptSection(TESTNAME, script);
		r = mod->Build();
		if( r >= 0 )
			TEST_FAILED;

		if( bout.buffer != "Test_Addon_WeakRef (2, 1) : Info    : Compiling void main()\n"
						   "Test_Addon_WeakRef (3, 11) : Error   : Can't instantiate template 'weakref' with subtype 'int'\n"
						   "Test_Addon_WeakRef (4, 11) : Error   : Can't instantiate template 'weakref' with subtype 'string'\n"
						   "Test_Addon_WeakRef (5, 11) : Error   : Can't instantiate template 'weakref' with subtype 'Test@'\n"
						   "weakref (0, 0) : Error   : The subtype doesn't support weak references\n"
						   "Test_Addon_WeakRef (6, 11) : Error   : Can't instantiate template 'weakref' with subtype 'array<Test>'\n" )
		{
			PRINTF("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		engine->Release();
	}

	// Test registering app type with weak ref
#ifndef AS_MAX_PORTABILITY
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);
		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

		engine->RegisterObjectType("MyClass", 0, asOBJ_REF);
		engine->RegisterObjectBehaviour("MyClass", asBEHAVE_FACTORY, "MyClass @f()", asFUNCTION(MyClass::Factory), asCALL_CDECL);
		engine->RegisterObjectBehaviour("MyClass", asBEHAVE_ADDREF, "void f()", asMETHOD(MyClass, AddRef), asCALL_THISCALL);
		engine->RegisterObjectBehaviour("MyClass", asBEHAVE_RELEASE, "void f()", asMETHOD(MyClass, Release), asCALL_THISCALL);
		engine->RegisterObjectBehaviour("MyClass", asBEHAVE_GET_WEAKREF_FLAG, "int &f()", asMETHOD(MyClass, GetWeakRefFlag), asCALL_THISCALL);

		RegisterScriptWeakRef(engine);

		const char *script =
			"void main() { \n"
			"  MyClass @t = MyClass(); \n"
			"  weakref<MyClass> r(t); \n"
			"  assert( r.get() !is null ); \n"
			"  @t = null; \n"
			"  assert( r.get() is null ); \n"
			"} \n";

		asIScriptModule *mod = engine->GetModule("test", asGM_ALWAYS_CREATE);
		mod->AddScriptSection(TESTNAME, script);
		r = mod->Build();
		if( r < 0 )
		{
			TEST_FAILED;
			PRINTF("%s: Failed to compile the script\n", TESTNAME);
		}

		r = ExecuteString(engine, "main()", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		engine->Release();
	}
#endif

	// TODO: weak: It should be possible to declare a script class to not allow weak references, and as such save the memory for the internal pointer
	// TODO: weak: add engine property to turn off automatic support for weak references to all script classes

	// Success
	return fail;
}
コード例 #3
0
bool Test()
{
	RET_ON_MAX_PORT

	bool fail = false;
	int r;
	COutStream out;
	asIScriptEngine *engine;
	asIScriptModule *mod;
	asIScriptContext *ctx;
	CBufferedOutStream bout;
	const char *script;

	// Test invalid use of function pointer
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(CBufferedOutStream, Callback), &bout, asCALL_THISCALL);

		bout.buffer = "";
		mod = engine->GetModule("mod", asGM_ALWAYS_CREATE);
		mod->AddScriptSection("test",
			"void func2() { \n"
			"  func; \n"
			"} \n"
			"void func() {} \n");
		r = mod->Build();
		if( r >= 0 )
			TEST_FAILED;

		if( bout.buffer != "test (1, 1) : Info    : Compiling void func2()\n"
						   "test (2, 3) : Error   : Invalid expression: ambiguous name\n" )
		{
			PRINTF("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		engine->Release();
	}

	// Test value comparison for function pointers
/*
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);

		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

		mod = engine->GetModule("mod", asGM_ALWAYS_CREATE);
		mod->AddScriptSection("test",
			"funcdef void CALLBACK(); \n"
			"void func1() {} \n"
			"void func2() {} \n");
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		r = ExecuteString(engine, "CALLBACK@ c1 = func1, c2 = func1; \n"
								  "assert( c1 == c2 ); \n", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		// TODO: Test that two different function pointers give false
		// TODO: Test for delegate objects

		engine->Release();
	}
*/

	// Proper error message when trying to pass class method as function pointer directly
	// http://www.gamedev.net/topic/655390-is-there-a-bug-with-function-callbacks/
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(CBufferedOutStream, Callback), &bout, asCALL_THISCALL);
		
		bout.buffer = "";

		mod = engine->GetModule("mod", asGM_ALWAYS_CREATE);
		mod->AddScriptSection("test",
			"funcdef void CALLBACK(int); \n"
			"class Test { \n"
			"  void Init() { \n"
			"    SetCallback(MyCallback); \n" // This should fail, since delegate is necessary
			"  } \n"
			"  void MyCallback(int) {} \n"
			"} \n"
			"void SetCallback(CALLBACK @) {} \n");
		r = mod->Build();
		if( r >= 0 )
			TEST_FAILED;

		if( bout.buffer != "test (3, 3) : Info    : Compiling void Test::Init()\n"
						   "test (4, 5) : Error   : No matching signatures to 'SetCallback(Test::MyCallback)'\n"
						   "test (4, 5) : Error   : Can't pass class method as arg directly. Use a delegate object instead\n" )
		{
			PRINTF("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		engine->Release();
	}

	// opEquals with funcdef
	// http://www.gamedev.net/topic/647797-difference-between-xopequalsy-and-xy-with-funcdefs/
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);
		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

		mod = engine->GetModule("mod", asGM_ALWAYS_CREATE);
		mod->AddScriptSection("test",
			"funcdef void CALLBACK(); \n"
			"class Test { \n"
			"  bool opEquals(CALLBACK @f) { \n"
			"    return f is func; \n"
			"  } \n"
			"  CALLBACK @func; \n"
			"} \n"
			"void func() {} \n");
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		r = ExecuteString(engine, "Test t; \n"
			                      "@t.func = func; \n"
								  "assert( t == func );", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		mod = engine->GetModule("mod", asGM_ALWAYS_CREATE);
		mod->AddScriptSection("test",
			"funcdef void CALLBACK(); \n"
			"class Test { \n"
			"  bool opEquals(CALLBACK @f) { \n"
			"    return f is func; \n"
			"  } \n"
			"  CALLBACK @func; \n"
			"} \n"
			"namespace ns { \n"
			"void func() {} \n"
			"} \n");
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		r = ExecuteString(engine, "Test t; \n"
								  "@t.func = ns::func; \n"
								  "assert( t == ns::func );", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		engine->Release();
	}

	// Test funcdefs and namespaces
	// http://www.gamedev.net/topic/644586-application-function-returning-a-funcdef-handle-crashes-when-called-in-as/
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);
		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

		mod = engine->GetModule("mod", asGM_ALWAYS_CREATE);
		mod->AddScriptSection("test",
			"bool called = false; \n"
			"funcdef void simpleFuncDef(); \n"
			"namespace foo { \n"
			"  void simpleFunction() { called = true; } \n"
			"} \n"
			"void takeSimpleFuncDef(simpleFuncDef@ f) { f(); } \n"
			"void main() { \n"
			"  takeSimpleFuncDef(foo::simpleFunction); \n"
			"  assert( called ); \n"
			"} \n");
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;
		r = ExecuteString(engine, "main()", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		mod->AddScriptSection("test",
			"bool called = false; \n"
			"funcdef void simpleFuncDef();\n"
			"namespace foo {\n"
			"  void simpleFunction() { called = true; }\n"
			"}\n"
			"void main() {\n"
			"  simpleFuncDef@ bar = foo::simpleFunction;\n"
			"  bar(); \n"
			"  assert( called ); \n"
			"}\n");
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;
		r = ExecuteString(engine, "main()", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;
		engine->Release();
	}

	// Test registering global property of funcdef type
	// http://www.gamedev.net/topic/644586-application-function-returning-a-funcdef-handle-crashes-when-called-in-as/
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);

		asIScriptFunction *f = 0;
		engine->RegisterFuncdef("void myfunc()");
		r = engine->RegisterGlobalProperty("myfunc @f", &f);
		if( r < 0 )
			TEST_FAILED;

		mod = engine->GetModule("mod", asGM_ALWAYS_CREATE);
		mod->AddScriptSection("test",
			"void func() {} \n");
		mod->Build();

		r = ExecuteString(engine, "@f = func; \n", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		if( f == 0 )
			TEST_FAILED;
		if( strcmp(f->GetName(), "func") != 0 )
			TEST_FAILED;

		f->Release();
		f = 0;

		engine->Release();
	}

	// Test casting with funcdefs
	// http://www.gamedev.net/topic/644586-application-function-returning-a-funcdef-handle-crashes-when-called-in-as/
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);
		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

		mod = engine->GetModule("mod", asGM_ALWAYS_CREATE);
		mod->AddScriptSection("test",
			"funcdef void myfunc1(); \n"
			"funcdef void myfunc2(); \n"
			"funcdef void myfunc3(); \n"
			"bool called = false; \n"
			"void func() { called = true; } \n"
			"void main() \n"
			"{ \n"
			"  myfunc1 @f1 = func; \n"
			"  myfunc2 @f2 = cast<myfunc2>(f1); \n" // explicit cast
			"  myfunc3 @f3 = f2; \n"                // implicit cast
			"  assert( f1 is f2 ); \n"
			"  assert( f2 is f3 ); \n"
			"  assert( f3 is func ); \n"
			"  f3(); \n"
			"  assert( called ); \n"
			"} \n");
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		r = ExecuteString(engine, "main()", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		engine->Release();
	}

	// Don't allow application to register additional behaviours to funcdefs
	// http://www.gamedev.net/topic/644586-application-function-returning-a-funcdef-handle-crashes-when-called-in-as/
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(CBufferedOutStream, Callback), &bout, asCALL_THISCALL);
		bout.buffer = "";

		engine->RegisterObjectType("jjOBJ", 0, asOBJ_REF | asOBJ_NOCOUNT);
		engine->RegisterFuncdef("void jjBEHAVIOR(jjOBJ@)");
		engine->RegisterFuncdef("void DifferentFunctionPointer()");
		r = engine->RegisterObjectBehaviour("jjBEHAVIOR", asBEHAVE_IMPLICIT_REF_CAST, "DifferentFunctionPointer@ a()", asFUNCTION(0), asCALL_CDECL_OBJLAST);
		if( r >= 0 )
			TEST_FAILED;

		if( bout.buffer != " (0, 0) : Error   : Failed in call to function 'RegisterObjectBehaviour' with 'jjBEHAVIOR' and 'DifferentFunctionPointer@ a()' (Code: -12)\n" )
			TEST_FAILED;

		engine->Release();
	}

	// Test delegate function pointers for object methods
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(CBufferedOutStream, Callback), &bout, asCALL_THISCALL);
		bout.buffer = "";

		RegisterScriptArray(engine, false);
		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);
		RegisterStdString(engine);

		mod = engine->GetModule("test", asGM_ALWAYS_CREATE);
		mod->AddScriptSection("test",
			"class Test { \n"
			"  void method() {} \n"
			"  int func(int) { return 0; } \n"
			"  void func() { called = true; } \n" // The compiler should pick the right overload
			"  bool called = false; \n"
			"} \n"
			"funcdef void CALLBACK(); \n"
			"void main() { \n"
			"  Test t; \n"
			"  CALLBACK @cb = CALLBACK(t.func); \n" // instanciate a delegate
			"  cb(); \n" // invoke the delegate
			"  assert( t.called ); \n"
			"} \n");
		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;

		// Must be possible to save/load bytecode
		CBytecodeStream stream("test");
		mod->SaveByteCode(&stream);

		mod = engine->GetModule("test2", asGM_ALWAYS_CREATE);
		r = mod->LoadByteCode(&stream);
		if( r < 0 )
			TEST_FAILED;

		r = ExecuteString(engine, "main()", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		// Must be possible to create delegate from within class method, i.e. implicit this.method
		bout.buffer = "";
		mod->AddScriptSection("test",
			"funcdef void CALL(); \n"
			"class Test { \n"
			"  bool called = false; \n"
			"  void callMe() { called = true; } \n"
			"  CALL @GetCallback() { return CALL(callMe); } \n"
			"} \n"
			"void main() { \n"
			"  Test t; \n"
			"  CALL @cb = t.GetCallback(); \n"
			"  cb(); \n"
			"  assert( t.called ); \n"
			"} \n");
		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;

		// A delegate to own method held as member of class must be properly resolved by gc
		bout.buffer = "";
		mod->AddScriptSection("test",
			"funcdef void CALL(); \n"
			"class Test { \n"
			"  void call() {}; \n"
			"  CALL @c; \n"
			"} \n"
			"void main() { \n"
			"  Test t; \n"
			"  @t.c = CALL(t.call); \n"
			"} \n");
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;
		if( bout.buffer != "" )
		{
			PRINTF("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		engine->GarbageCollect();

		asUINT currSize, totalDestr, totalDetect;
		engine->GetGCStatistics(&currSize, &totalDestr, &totalDetect);

		r = ExecuteString(engine, "main()", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		engine->GarbageCollect();

		asUINT currSize2, totalDestr2, totalDetect2;
		engine->GetGCStatistics(&currSize2, &totalDestr2, &totalDetect2);

		if( totalDetect2 == totalDetect )
			TEST_FAILED;

		// Must be possible to call delegate from application
		mod->AddScriptSection("test",
			"funcdef void CALL(); \n"
			"class Test { \n"
			"  bool called = false; \n"
			"  void call() { called = true; } \n"
			"} \n"
			"Test t; \n"
			"CALL @callback = CALL(t.call); \n");
		r = mod->Build();
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		int idx = mod->GetGlobalVarIndexByDecl("CALL @callback");
		if( idx < 0 )
			TEST_FAILED;

		asIScriptFunction *callback = *(asIScriptFunction**)mod->GetAddressOfGlobalVar(idx);
		if( callback == 0 )
			TEST_FAILED;
		if( callback->GetFuncType() != asFUNC_DELEGATE )
			TEST_FAILED;
		if( callback->GetDelegateObject() == 0 )
			TEST_FAILED;
		if( std::string(callback->GetDelegateFunction()->GetDeclaration()) != "void Test::call()" )
			TEST_FAILED;

		ctx = engine->CreateContext();
		ctx->Prepare(callback);
		r = ctx->Execute();
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;
		ctx->Release();

		r = ExecuteString(engine, "assert( t.called );", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		// Must be possible to create the delegate from the application
		asIScriptObject *obj = (asIScriptObject*)mod->GetAddressOfGlobalVar(mod->GetGlobalVarIndexByDecl("Test t"));
		asIScriptFunction *func = obj->GetObjectType()->GetMethodByName("call");
		asIScriptFunction *delegate = engine->CreateDelegate(func, obj);
		if( delegate == 0 )
			TEST_FAILED;
		delegate->Release();

		// Must be possible to create delegate for registered type too
		mod->AddScriptSection("test",
			"funcdef bool EMPTY(); \n"
			"void main() { \n"
			"  array<int> a; \n"
			"  EMPTY @empty = EMPTY(a.isEmpty); \n"
			"  assert( empty() == true ); \n"
			"  a.insertLast(42); \n"
			"  assert( empty() == false ); \n"
			"} \n");
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		r = ExecuteString(engine, "main()", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		// Must not be possible to create delegate with const object and non-const method
		bout.buffer = "";
		mod->AddScriptSection("test",
			"funcdef void F(); \n"
			"class Test { \n"
			"  void f() {} \n"
			"} \n"
			"void main() { \n"
			" const Test @t; \n"
			" F @f = F(t.f); \n" // t is read-only, so this delegate must not be allowed
			"} \n");
		r = mod->Build();
		if( r >= 0 )
			TEST_FAILED;

		// TODO: Error message should be better, so it is understood that the error is because of const object
		if( bout.buffer != "test (5, 1) : Info    : Compiling void main()\n"
		                   "test (7, 9) : Error   : No matching signatures to 'void F()'\n" )
		{
			PRINTF("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		// Must not be possible to create delegates for non-reference types
		bout.buffer = "";
		mod->AddScriptSection("test",
			"funcdef bool CB(); \n"
			"string s; \n"
			"CB @cb = CB(s.isEmpty); \n");
		r = mod->Build();
		if( r >= 0 )
			TEST_FAILED;

		if( bout.buffer != "test (3, 5) : Info    : Compiling CB@ cb\n"
		                   "test (3, 10) : Error   : Can't create delegate for types that do not support handles\n" )
		{
			PRINTF("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		engine->Release();
	}

	// Test ordinary function pointers for global functions
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);
		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);
		mod = engine->GetModule(0, asGM_ALWAYS_CREATE);

		// Test the declaration of new function signatures
		script = "funcdef void functype();\n"
		// It must be possible to declare variables of the funcdef type
				 "functype @myFunc = null;\n"
		// It must be possible to initialize the function pointer directly
				 "functype @myFunc1 = @func;\n"
		 		 "void func() { called = true; }\n"
				 "bool called = false;\n"
		// It must be possible to compare the function pointer with another
				 "void main() { \n"
				 "  assert( myFunc1 !is null ); \n"
				 "  assert( myFunc1 is func ); \n"
		// It must be possible to call a function through the function pointer
	    		 "  myFunc1(); \n"
				 "  assert( called ); \n"
		// Local function pointer variables are also possible
				 "  functype @myFunc2 = @func;\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;

		// It must be possible to save the byte code with function handles
		CBytecodeStream bytecode(__FILE__"1");
		mod->SaveByteCode(&bytecode);
		{
			asIScriptModule *mod2 = engine->GetModule("mod2", asGM_ALWAYS_CREATE);
			mod2->LoadByteCode(&bytecode);
			r = ExecuteString(engine, "main()", mod2);
			if( r != asEXECUTION_FINISHED )
				TEST_FAILED;
		}

		// Test function pointers as members of classes. It should be possible to call the function
		// from within a class method. It should also be possible to call it from outside through the . operator.
		script = "funcdef void FUNC();       \n"
				 "class CMyObj               \n"
				 "{                          \n"
				 "  CMyObj() { @f = @func; } \n"
				 "  FUNC@ f;                 \n"
				 "  void test()              \n"
				 "  {                        \n"
				 "    this.f();              \n"
				 "    f();                   \n"
				 "    CMyObj o;              \n"
				 "    o.f();                 \n"
				 "    main();                \n"
				 "    assert( called == 4 ); \n"
				 "  }                        \n"
				 "}                          \n"
				 "void main()                \n"
				 "{                          \n"
				 "  CMyObj o;                \n"
				 "  o.f();                   \n"
				 "}                          \n"
				 "int called = 0;            \n"
				 "void func() { called++; }  \n";
		mod->AddScriptSection("script", script);
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;
		asIScriptContext *ctx = engine->CreateContext();
		r = ExecuteString(engine, "CMyObj o; o.test();", mod, ctx);
		if( r != asEXECUTION_FINISHED )
		{
			TEST_FAILED;
			if( r == asEXECUTION_EXCEPTION )
				PrintException(ctx);
		}
		ctx->Release();

		// It must not be possible to declare a non-handle variable of the funcdef type
		engine->SetMessageCallback(asMETHOD(CBufferedOutStream, Callback), &bout, asCALL_THISCALL);
		bout.buffer = "";
		script = "funcdef void functype();\n"
				 "functype myFunc;\n";
		mod->AddScriptSection("script", script);
		r = mod->Build();
		if( r >= 0 )
			TEST_FAILED;
		if( bout.buffer != "script (2, 1) : Error   : Data type can't be 'functype'\n"
						   "script (2, 10) : Info    : Compiling functype myFunc\n"
						   "script (2, 10) : Error   : No default constructor for object of type 'functype'.\n" )
		{
			PRINTF("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		// It must not be possible to invoke the funcdef
		bout.buffer = "";
		script = "funcdef void functype();\n"
				 "void func() { functype(); } \n";
		mod->AddScriptSection("script", script);
		r = mod->Build();
		if( r >= 0 )
			TEST_FAILED;
		if( bout.buffer != "script (2, 1) : Info    : Compiling void func()\n"
						   "script (2, 15) : Error   : No matching signatures to 'functype()'\n" )
		{
			PRINTF("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		// Test that a funcdef can't have the same name as other global entities
		bout.buffer = "";
		script = "funcdef void test();  \n"
				 "int test; \n";
		mod->AddScriptSection("script", script);
		r = mod->Build();
		if( r >= 0 )
			TEST_FAILED;
		if( bout.buffer != "script (2, 5) : Error   : Name conflict. 'test' is a funcdef.\n" )
		{
			PRINTF("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		// It is possible to take the address of class methods, but not to assign to funcdef variable
		bout.buffer = "";
		script = 
			"funcdef void F(); \n"
		    "class t { \n"
			"  void func() { \n"
			"    @func; \n"
			"    F @f = @func; \n"
            "    } \n"
			"} \n";
		mod->AddScriptSection("script", script);
		r = mod->Build();
		if( r >= 0 )
			TEST_FAILED;
		// TODO: The error message should be better
		if( bout.buffer != "script (3, 3) : Info    : Compiling void t::func()\n"
			               "script (4, 5) : Error   : Invalid expression: ambiguous name\n"
		                   "script (5, 12) : Error   : Can't implicitly convert from 't' to 'F@&'.\n" )
		{
			PRINTF("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		// A more complex sample
		bout.buffer = "";
		script = 
			"funcdef bool CALLBACK(int, int); \n"
			"funcdef bool CALLBACK2(CALLBACK @); \n"
			"void main() \n"
			"{ \n"
			"	CALLBACK @func = @myCompare; \n"
			"	CALLBACK2 @func2 = @test; \n"
			"	func2(func); \n"
			"} \n"
			"bool test(CALLBACK @func) \n"
			"{ \n"
			"	return func(1, 2); \n"
			"} \n"
			"bool myCompare(int a, int b) \n"
			"{ \n"
			"	return a > b; \n"
			"} \n";
		mod->AddScriptSection("script", script);
		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;

		// It must be possible to register the function signature from the application
		r = engine->RegisterFuncdef("void AppCallback()");
		if( r < 0 )
			TEST_FAILED;

		r = engine->RegisterGlobalFunction("void ReceiveFuncPtr(AppCallback @)", asFUNCTION(ReceiveFuncPtr), asCALL_CDECL); assert( r >= 0 );

		// It must be possible to use the registered funcdef
		// It must be possible to receive a function pointer for a registered func def
		bout.buffer = "";
		script = 
			"void main() \n"
			"{ \n"
			"	AppCallback @func = @test; \n"
			"   func(); \n"
			"   ReceiveFuncPtr(func); \n"
			"} \n"
			"void test() \n"
			"{ \n"
			"} \n";
		mod->AddScriptSection("script", script);
		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;

		if( !receivedFuncPtrIsOK )
			TEST_FAILED;

		mod->SaveByteCode(&bytecode);
		{
			receivedFuncPtrIsOK = false;
			asIScriptModule *mod2 = engine->GetModule("mod2", asGM_ALWAYS_CREATE);
			mod2->LoadByteCode(&bytecode);
			r = ExecuteString(engine, "main()", mod2);
			if( r != asEXECUTION_FINISHED )
				TEST_FAILED;

			if( !receivedFuncPtrIsOK )
				TEST_FAILED;
		}

		// The compiler should be able to determine the right function overload
		// by the destination of the function pointer
		bout.buffer = "";
		mod->AddScriptSection("test",
		         "funcdef void f(); \n"
				 "f @fp = @func;  \n"
				 "bool called = false; \n"
				 "void func() { called = true; }    \n"
				 "void func(int) {} \n");
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;
		if( bout.buffer != "" )
		{
			PRINTF("%s", bout.buffer.c_str());
			TEST_FAILED;
		}
		r = ExecuteString(engine, "fp(); assert( called );", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		//----------------------------------------------------------
		// TODO: Future improvements below

		// If the function referred to when taking a function pointer is removed from the module,
		// the code must not be invalidated. After removing func() from the module, it must still 
		// be possible to execute func2()
		script = "funcdef void FUNC(); \n"
				 "void func() {} \n";
				 "void func2() { FUNC@ f = @func; f(); } \n";

		// Test that the function in a function pointer isn't released while the function 
		// is being executed, even though the function pointer itself is cleared
		script = "DYNFUNC@ funcPtr;        \n"
				 "funcdef void DYNFUNC(); \n"
				 "@funcPtr = @CompileDynFunc('void func() { @funcPtr = null; }'); \n";

		// Test that it is possible to declare the function signatures out of order
		// This also tests the circular reference between the function signatures
		script = "funcdef void f1(f2@) \n"
				 "funcdef void f2(f1@) \n";

		// It must be possible to identify a function handle type from the type id

		// It must be possible enumerate the function definitions in the module, 
		// and to enumerate the parameters the function accepts

		// A funcdef defined in multiple modules must share the id and signature so that a function implemented 
		// in one module can be called from another module by storing the handle in the funcdef variable

		// An interface that takes a funcdef as parameter must still have its typeid shared if the funcdef can also be shared
		// If the funcdef takes an interface as parameter, it must still be shared

		// Must have a generic function pointer that can store any signature. The function pointer
		// can then be dynamically cast to the correct function signature so that the function it points
		// to can be invoked.

		engine->Release();
	}

	// Test function pointers with virtual property accessors
	// http://www.gamedev.net/topic/639243-funcdef-inside-shared-interface-interface-already-implement-warning/
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);

		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

		mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
		mod->AddScriptSection("test",
			"funcdef void funcdef1( ifuncdef1_1& i ); \n"
			"shared interface ifuncdef1_1 \n"
			"{ \n"
			"    ifuncdef1_2@ events { get; set; } \n"
			"    void crashme(); \n"
			"} \n"
			"shared interface ifuncdef1_2 \n"
			"{ \n"
			"    funcdef1@ f { get; set; } \n"
			"} \n"
			"class cfuncdef1_1 : ifuncdef1_1 \n"
			"{ \n"
			"    ifuncdef1_2@ _events_; \n"
			"    cfuncdef1_1() { @this._events_ = cfuncdef1_2(); } \n"
			"    ifuncdef1_2@ get_events() { return( this._events_ ); } \n"
			"    void set_events( ifuncdef1_2@ events ) { @this._events_ = events; } \n"
			"    void crashme() \n"
			"    { \n"
			"         if( this._events_ !is null && this._events_.f !is null ) \n"
			"         { \n"
			"            this.events.f( this ); \n"
//			"            this.get_events().get_f()( this ); \n" // This should produce the same bytecode as the above
			"         } \n"
			"    } \n"
			"} \n"
			"class cfuncdef1_2 : ifuncdef1_2 \n"
			"{ \n"
			"    funcdef1@ ff; \n"
			"    cfuncdef1_2() { @ff = null; } \n"
			"    funcdef1@ get_f() { return( @this.ff ); } \n"
			"    void set_f( funcdef1@ _f ) { @this.ff = _f; } \n"
			"} \n"
			"void start() \n"
			"{ \n"
			"    ifuncdef1_1@ i = cfuncdef1_1(); \n"
			"    @i.events.f = end; \n" // TODO: Shouldn't this give an error? It's attempting to do an value assignment to a function pointer
			"    i.crashme(); \n"
			"} \n"
			"bool called = false; \n"
			"void end( ifuncdef1_1& i  ) \n"
			"{ \n"
			"    called = true; \n"
			"} \n");

		r = mod->Build(); 
		if( r < 0 )
			TEST_FAILED;

		ctx = engine->CreateContext();
		r = ExecuteString(engine, "start(); assert( called );", mod, ctx);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;
		if( r == asEXECUTION_EXCEPTION )
			PrintException(ctx, true);
		ctx->Release();

		CBytecodeStream stream(__FILE__"1");
		
		r = mod->SaveByteCode(&stream);
		if( r < 0 )
			TEST_FAILED;
		
		engine->Release();

		// Load the bytecode 
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);
		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

		stream.Restart();
		mod = engine->GetModule("A", asGM_ALWAYS_CREATE);
		r = mod->LoadByteCode(&stream);
		if( r < 0 )
			TEST_FAILED;

		ctx = engine->CreateContext();
		r = ExecuteString(engine, "start(); assert( called );", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;
		ctx->Release();

		stream.Restart();
		mod = engine->GetModule("B", asGM_ALWAYS_CREATE);
		r = mod->LoadByteCode(&stream);
		if( r < 0 )
			TEST_FAILED;

		ctx = engine->CreateContext();
		r = ExecuteString(engine, "start(); assert( called );", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;
		ctx->Release();

		engine->Release();
	}

	// Test clean up with registered function definitions
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		RegisterScriptString(engine);
		r = engine->RegisterFuncdef("void MSG_NOTIFY_CB(const string& strCommand, const string& strTarget)"); assert(r>=0);

		engine->Release();
	}

	// Test registering function pointer as property
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		r = engine->RegisterFuncdef("void fptr()");
		r = engine->RegisterGlobalProperty("fptr f", 0);
		if( r >= 0 ) TEST_FAILED;
		engine->RegisterObjectType("obj", 0, asOBJ_REF);
		r = engine->RegisterObjectProperty("obj", "fptr f", 0);
		if( r >= 0 ) TEST_FAILED;

		engine->Release();
	}

	// Test passing handle to function pointer
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);
		mod = engine->GetModule(0, asGM_ALWAYS_CREATE);

		mod->AddScriptSection("script",
			"class CTempObj             \n"
			"{                          \n"
			"  int Temp;                \n"
			"}                          \n"
			"funcdef void FUNC2(CTempObj@);\n"
			"class CMyObj               \n"
			"{                          \n"
			"  CMyObj() { @f2= @func2; }\n"
			"  FUNC2@ f2;               \n"
			"}                          \n"
			"void main()                \n"
			"{                          \n"
			"  CMyObj o;                \n"
			"  CTempObj t;              \n"
			"  o.f2(t);                 \n"
			"  assert( called == 1 );   \n"
			"}                          \n"
			"int called = 0;            \n"
			"void func2(CTempObj@ Obj)  \n"
			"{ called++; }              \n");

		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		r = ExecuteString(engine, "main()", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		engine->Release();
	}

	// Test out of order declaration with function pointers
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);
		mod = engine->GetModule(0, asGM_ALWAYS_CREATE);

		mod->AddScriptSection("script",
			"funcdef void FUNC2(CTempObj@);\n"
			"class CTempObj {}             \n");

		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		engine->Release();
	}

	// It must be possible calling system functions through pointers too
	{
		asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);

		engine->RegisterFuncdef("bool fun(bool)");
		engine->RegisterGlobalFunction("bool assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

		r = ExecuteString(engine, "fun @f = assert; f(true);");
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		engine->Release();
	}

	// It should be possible to call functions through function pointers returned by an expression
	// http://www.gamedev.net/topic/627386-bug-with-parsing-of-callable-expressions/
	{
		asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);
		RegisterScriptArray(engine, false);
		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

		mod = engine->GetModule(0, asGM_ALWAYS_CREATE);

		mod->AddScriptSection("Test",
			"funcdef void F(int); \n"
			"array<F@> arr(1); \n"
			"F@ g()            \n"
			"{                 \n"
			"  return test;    \n"
			"}                 \n"
			"void test(int a)  \n"
			"{                 \n"
			"  assert(a == 42); \n"
			"  called++;       \n"
			"}                 \n"
			"int called = 0;   \n"
			"void f()          \n"
			"{                 \n"
			"  @arr[0] = test; \n"
			"  arr[0](42);     \n"
			"  g()(42);        \n"
			"  F@ p; \n"
			"  (@p = arr[0])(42);     \n"
			"  (@p = g())(42);        \n"
			"}                        \n");

	//	engine->SetEngineProperty(asEP_OPTIMIZE_BYTECODE, false);
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		r = ExecuteString(engine, "f()", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		int idx = mod->GetGlobalVarIndexByName("called");
		int *called = (int*)mod->GetAddressOfGlobalVar(idx);
		if( *called != 4 )
			TEST_FAILED;

		engine->Release();
	}

	// Global function pointers must not overload local class methods
	// Local variables take precedence over class methods
	// http://www.gamedev.net/topic/626746-function-call-operators-in-the-future/
	{
		const char *script = 
			"funcdef void FUNC(); \n"
			"FUNC @func; \n"
			"class Class \n"
			"{ \n"
			"  void func() {} \n"
			"  void method() \n"
			"  { \n"
			"    func(); \n"       // Should call Class::func()
			"  } \n"
			"  void func2() {} \n"
			"  void method2() \n"
			"  { \n"
			"    FUNC @func2; \n"
			"    func2(); \n"      // Should call variable func2
			"  } \n"
			"} \n";

		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);

		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);

		mod = engine->GetModule("test", asGM_ALWAYS_CREATE);
		mod->AddScriptSection("test", script);
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		r = ExecuteString(engine, "Class c; c.method();", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		r = ExecuteString(engine, "Class c; c.method2();", mod);
		if( r != asEXECUTION_EXCEPTION )
			TEST_FAILED;

		engine->Release();
	}

	// Success
 	return fail;
}
コード例 #4
0
bool Test()
{
	bool fail = false;
	int r;
	COutStream out;
 	asIScriptEngine *engine;
	asIScriptModule *mod;
	asIScriptContext *ctx;
	
	// Simulate a step-by-step execution with variable inspection
	{
		CMyDebugger debug;
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);
		RegisterStdString(engine);
		RegisterScriptArray(engine, true);

		debug.RegisterToStringCallback(engine->GetObjectTypeByName("string"), StringToString);
		debug.RegisterToStringCallback(engine->GetObjectTypeByName("array"), ArrayToString);

		const char *script = 
			"void func(int a, const int &in b, string c, const string &in d, type @e, type &f, type @&in g) \n"
			"{ \n"
			"  array<int> arr = {1,2,3}; \n"
			"} \n"
			"string glob = 'test';\n"
			"class type {} \n";

		mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
		mod->AddScriptSection("script", script);
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		ctx = engine->CreateContext();
		ctx->SetLineCallback(asMETHOD(CMyDebugger, LineCallback), &debug, asCALL_THISCALL);

		debug.InterpretCommand("s", ctx);

		r = ExecuteString(engine, "type t; func(1, 2, 'c', 'd', t, t, t)", mod, ctx);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		if( debug.output != "ExecuteString:1; void ExecuteString()\n"
							"ExecuteString:1; void ExecuteString()\n"
							"string glob = (len=4) \"test\"\n"
							"script:0; type@ type()\n"
							"string glob = (len=4) \"test\"\n"
							"script:0; type::type()\n"
							"type t = {XXXXXXXX}\n"
							"ExecuteString:1; void ExecuteString()\n"
							"int a = 1\n"
							"const int& b = 2\n"
							"string c = (len=1) \"c\"\n"
							"const string& d = (len=1) \"d\"\n"
							"type@ e = {XXXXXXXX}\n"
							"type& f = {XXXXXXXX}\n"
							"type@& g = {XXXXXXXX}\n"
							"string glob = (len=4) \"test\"\n"
							"script:3; void func(int, const int&in, string, const string&in, type@, type&inout, type@&in)\n"
							"int a = 1\n"
							"const int& b = 2\n"
							"string c = (len=1) \"c\"\n"
							"const string& d = (len=1) \"d\"\n"
							"type@ e = {XXXXXXXX}\n"
							"type& f = {XXXXXXXX}\n"
							"type@& g = {XXXXXXXX}\n"
							"string glob = (len=4) \"test\"\n"
							"script:3; void func(int, const int&in, string, const string&in, type@, type&inout, type@&in)\n"
							"{unnamed}:0; int[]@ factstub(int&in) { repeat int }\n"
							"int a = 1\n"
							"const int& b = 2\n"
							"string c = (len=1) \"c\"\n"
							"const string& d = (len=1) \"d\"\n"
							"type@ e = {XXXXXXXX}\n"
							"type& f = {XXXXXXXX}\n"
							"type@& g = {XXXXXXXX}\n"
							"int[] arr = {YYYYYYYY}\n"
							"(len=3) [1, 2, 3]\n"
							"string glob = (len=4) \"test\"\n"
							"script:4; void func(int, const int&in, string, const string&in, type@, type&inout, type@&in)\n"
							"type t = {XXXXXXXX}\n"
							"ExecuteString:2; void ExecuteString()\n" )
		{
			PRINTF("%s", debug.output.c_str());
			TEST_FAILED;
		}

		ctx->Release();
	
		engine->Release();
	}

	// Test inspecting a script object
	// http://www.gamedev.net/topic/627854-debugger-crashes-when-evaluating-uninitialized-object-expression/
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);
		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

		mod = engine->GetModule("test", asGM_ALWAYS_CREATE);
		mod->AddScriptSection("test",
			"class CTest \n"
			"{ \n"
			"  CTest() { value = 42; } \n"
			"  int value; \n"
			"} \n"
			"int t = 24; \n"
			"void Func() \n"
			"{ \n"
			"  CTest t; \n"
			"  assert( t.value == 42 ); \n"
			"} \n"
			"namespace foo { float pi = 3.14f; } \n");
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		CMyDebugger2 debug;

		ctx = engine->CreateContext();
		ctx->SetLineCallback(asMETHOD(CMyDebugger, LineCallback), &debug, asCALL_THISCALL);

		// Set a break point on the line where the object will be created
		debug.InterpretCommand("b test:9", ctx);

		// Set a break point after the object has been created
		debug.InterpretCommand("b test:10", ctx);

		ctx->Prepare(mod->GetFunctionByName("Func"));

		// Before the function is actually executed the variables don't exist
		if( ctx->IsVarInScope(0) )
			TEST_FAILED;
		if( ctx->GetAddressOfVar(0) )
			TEST_FAILED;

		// It will break twice on line 8. Once when setting up the function stack frame, and then on the first line that is executed
		// TODO: The first SUSPEND in the bytecode should be optimized away as it is unnecessary
		for( int n = 0; n < 2; n++ )
		{
			r = ctx->Execute();
			if( r != asEXECUTION_SUSPENDED )
				TEST_FAILED;
			
			// Now we should be on the line where the object will be created created
			if( ctx->GetLineNumber() != 9 )
				TEST_FAILED;
			else
			{
				// The address should be null
				asIScriptObject *obj = (asIScriptObject*)ctx->GetAddressOfVar(0);
				if( obj != 0 )
					TEST_FAILED;

				debug.PrintValue("t", ctx);
			}
		}

		r = ctx->Execute();
		if( r != asEXECUTION_SUSPENDED )
			TEST_FAILED;

		// Now we should be on the line after the object has been created
		if( ctx->GetLineNumber() != 10 )
			TEST_FAILED;
		else
		{
			if( !ctx->IsVarInScope(0) )
				TEST_FAILED;

			asIScriptObject *obj = (asIScriptObject*)ctx->GetAddressOfVar(0);
			if( obj == 0 )
				TEST_FAILED;
			if( *(int*)obj->GetAddressOfProperty(0) != 42 )
				TEST_FAILED;

			debug.PrintValue("t", ctx);       // Print the value of the local variable
			debug.PrintValue("::t", ctx);     // Print the value of the global variable
			debug.PrintValue("foo::pi", ctx); // Print the value of the global variable in namespace
		}

		if( debug.output != "Setting break point in file 'test' at line 9\n"
							"Setting break point in file 'test' at line 10\n"
							"Reached break point 0 in file 'test' at line 9\n"
							"test:9; void Func()\n"
							"24\n"
							"Reached break point 0 in file 'test' at line 9\n"
							"test:9; void Func()\n"
							"24\n"
							"Reached break point 1 in file 'test' at line 10\n"
							"test:10; void Func()\n"
							"{XXXXXXXX}\n"
							"  int value = 42\n"
							"24\n"
							"3.14\n")
		{
			PRINTF("%s", debug.output.c_str());
			TEST_FAILED;
		}

		ctx->Release();

		engine->Release();
	}

	return fail;
}
コード例 #5
0
ファイル: test_unsaferef.cpp プロジェクト: Kaperstone/warsow
bool Test()
{
	bool fail = false;
	int r;

	COutStream out;
	CBufferedOutStream bout;

 	asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
	engine->SetEngineProperty(asEP_ALLOW_UNSAFE_REFERENCES, 1);
	engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);
	RegisterScriptArray(engine, true);
	RegisterScriptString(engine);

	r = engine->RegisterGlobalFunction("void Assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); assert( r >= 0 );

	asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
	mod->AddScriptSection(TESTNAME, script1);
	r = mod->Build();
	if( r < 0 )
	{
		TEST_FAILED;
		printf("%s: Failed to compile the script\n", TESTNAME);
	}
	asIScriptContext *ctx = engine->CreateContext();
	r = ExecuteString(engine, "Test()", mod, ctx);
	if( r != asEXECUTION_FINISHED )
	{
		TEST_FAILED;
		printf("%s: Execution failed: %d\n", TESTNAME, r);
	}

	if( ctx ) ctx->Release();

	engine->Release();

	// Test value class with unsafe ref
	{
		asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetEngineProperty(asEP_ALLOW_UNSAFE_REFERENCES, 1);
		engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);
		RegisterScriptMath3D(engine);

		asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
		mod->AddScriptSection(TESTNAME, 
			"class Good \n"
			"{ \n"
			"  vector3 _val; \n"
			"  Good(const vector3& in val) \n"
			"  { \n"
			"    _val = val; \n"
			"  }  \n"
			"};  \n"
			"class Bad  \n"
			"{  \n"
			"  vector3 _val;  \n"
			"  Bad(const vector3& val)  \n"
			"  {  \n"
			"    _val = val;  \n"
			"  }  \n"
			"}; \n"
			"void test()  \n"
			"{ \n"
			"  // runs fine  \n"
			"  for (int i = 0; i < 2; i++)  \n"
			"    Good(vector3(1, 2, 3));  \n"
			"  // causes vm stack corruption  \n"
			"  for (int i = 0; i < 2; i++)  \n"
			"    Bad(vector3(1, 2, 3));  \n"
			"} \n");

		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		r = ExecuteString(engine, "test()", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		engine->Release();
	}

	// Test ref to primitives
	{
		bout.buffer = "";
		asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetEngineProperty(asEP_ALLOW_UNSAFE_REFERENCES, 1);
		engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL);

		asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
		mod->AddScriptSection(TESTNAME, 
			"void func(){ \n"
			"  float a; \n"
			"  uint8 b; \n"
			"  int c; \n"
			"  funcA(c, a, b); \n"
			"} \n"
			"void funcA(float& a, uint8& b, int& c) {} \n");

		r = mod->Build();
		if( r >= 0 )
			TEST_FAILED;

		if( bout.buffer != "TestUnsafeRef (1, 1) : Info    : Compiling void func()\n"
		                   "TestUnsafeRef (5, 3) : Error   : No matching signatures to 'funcA(int, float, uint8)'\n"
		                   "TestUnsafeRef (5, 3) : Info    : Candidates are:\n"
		                   "TestUnsafeRef (5, 3) : Info    : void funcA(float&inout, uint8&inout, int&inout)\n" )
		{
			printf("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		engine->Release();
	}

	// Test problem found by TheAtom
	// Passing an inout reference to a handle to a function wasn't working properly
	{
		bout.buffer = "";
		asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetEngineProperty(asEP_ALLOW_UNSAFE_REFERENCES, 1);
		engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL);
		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

		asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
		mod->AddScriptSection(TESTNAME, 
			"class T { int a; } \n"
			"void f(T@& p) { \n"
			"  T t; \n"
			"  t.a = 42; \n"
			"  @p = t; \n" // or p=t; in which case t is copied
			"} \n");

		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		if( bout.buffer != "" )
		{
			printf("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		r = ExecuteString(engine, "T @t; f(t); assert( t.a == 42 );\n", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		engine->Release();		
	}

	// Success
	return fail;
}
コード例 #6
0
ファイル: test_dump.cpp プロジェクト: quarnster/angelscript
bool Test()
{
    bool fail = false;
    int r;
    COutStream out;

    const char *script =
        "void Test() {} \n"
        "class A : I { void i(float) {} void a(int) {} float f; } \n"
        "class B : A { B(int) {} } \n"
        "interface I { void i(float); } \n"
        "float a; \n"
        "const float aConst = 3.141592f; \n"
        "I@ i; \n"
        "enum E { eval = 0, eval2 = 2 } \n"
        "E e; \n"
        "typedef float real; \n"
        "real pi = 3.14f; \n"
        "import void ImpFunc() from \"mod\"; \n";

    asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
    engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);

    RegisterScriptArray(engine, true);
    RegisterStdString(engine);

    float f;
    engine->RegisterTypedef("myFloat", "float");
    engine->RegisterGlobalProperty("myFloat f", &f);
    engine->RegisterGlobalProperty("const float myConst", &f);
    engine->RegisterGlobalFunction("void func(int &in)", asFUNCTION(0), asCALL_GENERIC);

    engine->BeginConfigGroup("test");
    engine->RegisterGlobalFunction("void func2()", asFUNCTION(0), asCALL_GENERIC);
    engine->EndConfigGroup();

    engine->RegisterEnum("myEnum");
    engine->RegisterEnumValue("myEnum", "value1", 1);
    engine->RegisterEnumValue("myEnum", "value2", 2);

    engine->RegisterFuncdef("void Callback(int a, int b)");

    engine->RegisterInterface("MyIntf");
    engine->RegisterInterfaceMethod("MyIntf", "void func() const");

    asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE);

    mod->AddScriptSection("script", script);
    r = mod->Build();
    if( r < 0 )
        TEST_FAILED;

    WriteConfigToFile(engine, "AS_DEBUG/config.txt");

    DumpModule(mod);

    // Save/Restore the bytecode and then test again for the loaded bytecode
    CBytecodeStream stream(__FILE__"1");
    mod->SaveByteCode(&stream);

    mod = engine->GetModule("2", asGM_ALWAYS_CREATE);
    mod->LoadByteCode(&stream);

    DumpModule(mod);

    engine->Release();

    return fail;
}
コード例 #7
0
bool Test()
{
	bool fail = false;
	asIScriptEngine *engine;
	int r;
	COutStream out;
	CBufferedOutStream bout;

	{
		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 func() { return var; } \n"
			"int func2() { return var; } \n"
			"int var = 0; \n"
			"class cl { cl() {v = 0;} int v; } \n"
			"interface i {} \n"
			"enum e { e1 = 0 } \n"
			"funcdef void fd(); \n"
			// Namespaces allow same entities to be declared again
			"namespace a { \n"
			"  int func() { return var; } \n" // Should find the global var in the same namespace
			"  int func2() { return func(); } \n" // Should find the global function in the same namespace
			"  int var = 1; \n"
			"  class cl { cl() {v = 1;} int v; } \n"
			"  interface i {} \n"
			"  enum e { e1 = 1 } \n"
			"  funcdef void fd(); \n"
			"  ::e MyFunc() { return ::e1; } \n"
			// Nested namespaces are allowed
			"  namespace b { \n"
			"    int var = 2; \n"
			"    void funcParams(int a, float b) { a+b; } \n"
			"  } \n"
			// Accessing global variables from within a namespace is also possible
			"  int getglobalvar() { return ::var; } \n"
			"} \n"
			// The class should be able to declare methods to return and take types from other namespaces
			"class MyClass { \n"
			"  a::e func(a::e val) { return val; } \n"
			"  ::e func(::e val) { return val; } \n"
			"} \n"
			// Global functions must also be able to return and take types from other namespaces
			"a::e MyFunc(a::e val) { return val; } \n"
			// It's possible to specify exactly which one is wanted
			"cl gc; \n"
			"a::cl gca; \n"
			"void main() \n"
			"{ \n"
			"  assert(var == 0); \n"
			"  assert(::var == 0); \n"
			"  assert(a::var == 1); \n"
			"  assert(a::b::var == 2); \n"
			"  assert(func() == 0); \n"
			"  assert(a::func() == 1); \n"
			"  assert(func2() == 0); \n"
			"  assert(a::func2() == 1); \n"
			"  assert(e1 == 0); \n"
			"  assert(::e1 == 0); \n"
			"  assert(e::e1 == 0); \n"
			"  assert(::e::e1 == 0); \n"
			"  assert(a::e1 == 1); \n"
			"  assert(a::e::e1 == 1); \n"
			"  cl c; \n"
			"  a::cl ca; \n"
			"  assert(c.v == 0); \n"
			"  assert(ca.v == 1); \n"
			"  assert(gc.v == 0); \n"
			"  assert(gca.v == 1); \n"
			"  assert(a::getglobalvar() == 0); \n"
			"} \n";

		asIScriptModule *mod = engine->GetModule("mod", asGM_ALWAYS_CREATE);
		mod->AddScriptSection("", script);
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		r = ExecuteString(engine, "main()", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;
	
		// Retrieving entities should work properly with namespace
		mod->SetDefaultNamespace("a");
		asIScriptFunction *f1 = mod->GetFunctionByDecl("int func()");
		asIScriptFunction *f2 = mod->GetFunctionByDecl("int a::func()");
		asIScriptFunction *f3 = mod->GetFunctionByName("func");
		if( f1 == 0 || f1 != f2 || f1 != f3 )
			TEST_FAILED;

		int v1 = mod->GetGlobalVarIndexByName("var");
		int v2 = mod->GetGlobalVarIndexByDecl("int var");
		int v3 = mod->GetGlobalVarIndexByDecl("int a::var");
		if( v1 < 0 || v1 != v2 || v1 != v3 )
			TEST_FAILED;

		int t1 = mod->GetTypeIdByDecl("cl");
		int t2 = mod->GetTypeIdByDecl("a::cl");
		if( t1 < 0 || t1 != t2 )
			TEST_FAILED;

		// Functions with parameters must work too
		asIScriptFunction *f = mod->GetFunctionByDecl("void a::b::funcParams(int, float)");
		if( f == 0 || std::string(f->GetDeclaration(true, true)) != "void a::b::funcParams(int, float)" )
			TEST_FAILED;

		// Test saving and loading 
		CBytecodeStream s("");
		mod->SaveByteCode(&s);

		asIScriptModule *mod2 = engine->GetModule("mod2", asGM_ALWAYS_CREATE);
		r = mod2->LoadByteCode(&s);
		if( r < 0 )
			TEST_FAILED;

		r = ExecuteString(engine, "main()", mod2);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		engine->Release();
	}

	// Test registering interface with namespace
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);
		
		r = engine->SetDefaultNamespace("test"); assert( r >= 0 );

		r = engine->RegisterObjectType("t", 0, asOBJ_REF); assert( r >= 0 );
		r = engine->RegisterObjectBehaviour("t", asBEHAVE_ADDREF, "void f()", asFUNCTION(0), asCALL_GENERIC); assert( r >= 0 );
		r = engine->RegisterObjectMethod("t", "void f()", asFUNCTION(0), asCALL_GENERIC); assert( r >= 0 );
		r = engine->RegisterObjectProperty("t", "int a", 0); assert( r >= 0 );
		int t1 = engine->GetTypeIdByDecl("t");
		int t2 = engine->GetTypeIdByDecl("test::t");
		if( t1 < 0 || t1 != t2 )
			TEST_FAILED;
		
		r = engine->RegisterInterface("i"); assert( r >= 0 );
		r = engine->RegisterInterfaceMethod("i", "void f()"); assert( r >= 0 );
		t1 = engine->GetTypeIdByDecl("test::i");
		if( t1 < 0 )
			TEST_FAILED;

		r = engine->RegisterEnum("e"); assert( r >= 0 );
		r = engine->RegisterEnumValue("e", "e1", 0); assert( r >= 0 );
		t1 = engine->GetTypeIdByDecl("test::e");
		if( t1 < 0 )
			TEST_FAILED;

		r = engine->RegisterFuncdef("void f()"); assert( r >= 0 );
		t1 = engine->GetTypeIdByDecl("test::f");
		if( t1 < 0 )
			TEST_FAILED;

		r = engine->RegisterGlobalFunction("void gf()", asFUNCTION(0), asCALL_GENERIC); assert( r >= 0 );
		asIScriptFunction *f1 = engine->GetGlobalFunctionByDecl("void test::gf()");
		asIScriptFunction *f2 = engine->GetGlobalFunctionByDecl("void gf()");
		if( f1 == 0 || f1 != f2 )
			TEST_FAILED;

		r = engine->RegisterGlobalProperty("int gp", (void*)1); assert( r >= 0 );
		int g1 = engine->GetGlobalPropertyIndexByName("gp");
		int g2 = engine->GetGlobalPropertyIndexByDecl("int gp");
		int g3 = engine->GetGlobalPropertyIndexByDecl("int test::gp");
		if( g1 < 0 || g1 != g2 || g1 != g3 )
			TEST_FAILED;

		r = engine->RegisterTypedef("td", "int"); assert( r >= 0 );
		t1 = engine->GetTypeIdByDecl("test::td");
		if( t1 < 0 )
			TEST_FAILED;

		engine->Release();
	}


	// Test accessing registered properties in different namespaces from within function in another namespace
	// http://www.gamedev.net/topic/624376-accessing-global-property-from-within-script-namespace/
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(CBufferedOutStream, Callback), &bout, asCALL_THISCALL);

		int a = 0, b = 0;
		r = engine->RegisterGlobalProperty("int a", &a);
		r = engine->SetDefaultNamespace("test");
		r = engine->RegisterGlobalProperty("int b", &b);

		asIScriptModule *mod = engine->GetModule("mod", asGM_ALWAYS_CREATE);
		mod->AddScriptSection("test", 
			"namespace script { \n"
			"void func() \n"
			"{ \n"
			"  a = 1; \n"
			"} \n"
			"} \n");
		bout.buffer = "";
		r = mod->Build();
		if( r >= 0 )
			TEST_FAILED;
		// TODO: Should have better error message. Perhaps show variables declared in other scopes
		if( bout.buffer != "test (2, 1) : Info    : Compiling void func()\n"
						   "test (4, 3) : Error   : 'a' is not declared\n" )
		{
			printf("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		mod->AddScriptSection("test", 
			"namespace script { \n"
			"void func() \n"
			"{ \n"
			"  ::a = 1; \n"
			"  test::b = 2; \n"
			"} \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, "script::func()", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		if( a != 1 || b != 2 )
			TEST_FAILED;

		engine->Release();		
	}

	// Test registering enum with the same name in two different namespaces
	// http://www.gamedev.net/topic/625214-enum-collision-across-namespaces/
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);

		engine->SetDefaultNamespace("A");
		r = engine->RegisterEnum("ENUM"); assert( r >= 0 );
		r = engine->RegisterEnumValue("ENUM", "VALUE", 1); assert( r >= 0 );

		engine->SetDefaultNamespace("B");
		r = engine->RegisterEnum("ENUM"); assert( r >= 0 );
		r = engine->RegisterEnumValue("ENUM", "VALUE", 2); assert( r >= 0 );

		engine->SetDefaultNamespace("");

		r = engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); assert( r >= 0 );

		r = ExecuteString(engine, "int a = A::ENUM::VALUE; assert(a == 1)", 0, 0);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		r = ExecuteString(engine, "int b = B::ENUM::VALUE; assert(b == 2)", 0, 0);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		// It shouldn't be necessary to inform the name of the enum 
		// type as the engine property is not set to enforce that
		r = ExecuteString(engine, "int a = A::VALUE; assert(a == 1)", 0, 0);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		r = ExecuteString(engine, "int b = B::VALUE; assert(b == 2)", 0, 0);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;


		engine->SetMessageCallback(asMETHOD(CBufferedOutStream, Callback), &bout, asCALL_THISCALL);
		bout.buffer = "";
		engine->SetEngineProperty(asEP_REQUIRE_ENUM_SCOPE, true);
		r = ExecuteString(engine, "int a = A::VALUE; assert(a == 1)", 0, 0);
		if( r >= 0 )
			TEST_FAILED;

		if( bout.buffer != "ExecuteString (1, 9) : Error   : 'A::VALUE' is not declared\n"
		                   "ExecuteString (1, 28) : Warning : 'a' is not initialized.\n" )
		{
			printf("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		
		engine->Release();
	}

	// http://www.gamedev.net/topic/626970-2240-cannot-instantiate-a-class-outside-of-its-namespace/
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);

		asIScriptModule *mod = engine->GetModule("mod", asGM_ALWAYS_CREATE);
		mod->AddScriptSection("test", 
			"namespace TestNamespace \n"
			"{ \n"
			"        class MyHappyClass \n"
			"        { \n"
			"                MyHappyClass () \n"
			"                { \n"
			"                } \n"
			"                void DoSomething () \n"
			"                { \n"
			"                } \n"
			"        } \n"
			"} \n"
			"void main () \n"
			"{ \n"
			"        TestNamespace::MyHappyClass ClassInstance; \n"
			" \n"
			"        ClassInstance.DoSomething (); \n"
			"} \n");
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		engine->Release();
	}

	// http://www.gamedev.net/topic/626314-compiler-error-when-using-namespace-with-the-array-addon/
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);
		RegisterScriptArray(engine, true);

		asIScriptModule *mod = engine->GetModule("mod", asGM_ALWAYS_CREATE);
		mod->AddScriptSection("test", 
			"namespace A \n"
			"{ \n"
			"        class Test {} \n"
			"} \n"
			"void main () \n"
			"{ \n"
			"  array<A::Test@> a; \n"
			"  A::Test@[] b; \n"
			"} \n");
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		engine->Release();
	}

	// It should be possible to register types with the same name in different namespaces
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);
		
		r = engine->RegisterObjectType("TestObj", 0, asOBJ_REF);
		if( r < 0 ) TEST_FAILED;

		engine->SetDefaultNamespace("A");
		r = engine->RegisterObjectType("TestObj", 0, asOBJ_REF);
		if( r < 0 ) TEST_FAILED;

		r = engine->RegisterObjectType("TestObj", 0, asOBJ_REF);
		if( r != asALREADY_REGISTERED ) TEST_FAILED;

		engine->SetDefaultNamespace("");
		asIObjectType *o1 = engine->GetObjectTypeByName("TestObj");
		engine->SetDefaultNamespace("A");
		asIObjectType *o2 = engine->GetObjectTypeByName("TestObj");
		if( o1 == 0 || o2 == 0 )
			TEST_FAILED;
		if( o1 == o2 )
			TEST_FAILED;

		engine->Release();
	}

	// Dynamically adding functions/variables to modules should also support namespaces
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);

		asIScriptModule *mod = engine->GetModule("test", asGM_ALWAYS_CREATE);
		asIScriptFunction *f1;
		r = mod->CompileFunction("", "void func() {}", 0, asCOMP_ADD_TO_MODULE, &f1);
		if( r < 0 ) TEST_FAILED;

		mod->SetDefaultNamespace("A");
		asIScriptFunction *f2;
		r = mod->CompileFunction("", "void func() {}", 0, asCOMP_ADD_TO_MODULE, &f2);
		if( r < 0 ) TEST_FAILED;


		mod->SetDefaultNamespace("");
		asIScriptFunction *f3 = mod->GetFunctionByName("func");
		mod->SetDefaultNamespace("A");
		asIScriptFunction *f4 = mod->GetFunctionByName("func");

		if( f1 != f3 ) TEST_FAILED;
		if( f2 != f4 ) TEST_FAILED;
		if( f1 == f2 ) TEST_FAILED;

		// The functions received from CompileFunction must be released
		if( f1 ) f1->Release();
		if( f2 ) f2->Release();

		mod->SetDefaultNamespace("");
		r = mod->CompileGlobalVar("", "int var;", 0);
		if( r < 0 ) TEST_FAILED;

		mod->SetDefaultNamespace("A");
		r = mod->CompileGlobalVar("", "int var;", 0);
		if( r < 0 ) TEST_FAILED;

		mod->SetDefaultNamespace("");
		int v1 = mod->GetGlobalVarIndexByName("var");
		mod->SetDefaultNamespace("A");
		int v2 = mod->GetGlobalVarIndexByName("var");

		if( v1 < 0 || v2 < 0 ) TEST_FAILED;
		if( v1 == v2 ) TEST_FAILED;

		engine->Release();
	}

	// Inheritance from class in a different namespace
	// http://www.gamedev.net/topic/626970-2240-cannot-instantiate-a-class-outside-of-its-namespace/
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);

		asIScriptModule *mod = engine->GetModule("test", asGM_ALWAYS_CREATE);

		mod->AddScriptSection("test",
			"namespace A \n"
			"{ \n"
			"  interface i {} \n"
			"  class a {} \n"
			"  class a2 : a, i {} \n"
			"} \n"
			"class b : A::a, A::i {} \n"
			"namespace C \n"
			"{ \n"
			"  class c : ::b {} \n"
			"} \n");

		r = mod->Build();
		if( r < 0 ) 
			TEST_FAILED;

		asIObjectType *type = mod->GetObjectTypeByName("b");
		if( type == 0 )
			TEST_FAILED;
		else
		{
			mod->SetDefaultNamespace("A");
			if( !type->DerivesFrom(mod->GetObjectTypeByName("a")) )
				TEST_FAILED;
			if( !type->Implements(mod->GetObjectTypeByName("i")) )
				TEST_FAILED;
		}

		engine->Release();
	}

	// Registering types with namespaces
	// http://www.gamedev.net/topic/628401-problem-binding-two-similarly-named-objects-in-different-namespaces/
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);

		engine->SetDefaultNamespace("A");
		engine->RegisterEnum("ETest");
		engine->RegisterObjectType("CTest", 0, asOBJ_REF| asOBJ_NOCOUNT);
		r = engine->RegisterObjectProperty("CTest", "ETest e", 0);
		if( r < 0 )
			TEST_FAILED;
		engine->RegisterObjectType("CTest2", 0, asOBJ_REF| asOBJ_NOCOUNT);
		if( r < 0 )
			TEST_FAILED;
		r = engine->RegisterObjectMethod("CTest2", "ETest Method(ETest)", asFUNCTION(0), asCALL_GENERIC);
		if( r < 0 )
			TEST_FAILED;

		// Make sure it's possible to retrieve the enum again
		int typeId;
		const char *ns;
		const char *e = engine->GetEnumByIndex(0, &typeId, &ns);
		if( std::string(e) != "ETest" )
			TEST_FAILED;
		if( std::string(ns) != "A" )
			TEST_FAILED;
		if( typeId != engine->GetTypeIdByDecl("ETest") )
			TEST_FAILED;
		engine->SetDefaultNamespace("");
		e = engine->GetEnumByIndex(0, &typeId, &ns);
		if( std::string(e) != "ETest" )
			TEST_FAILED;
		if( std::string(ns) != "A" )
			TEST_FAILED;
		if( typeId != engine->GetTypeIdByDecl("A::ETest") )
			TEST_FAILED;

		engine->Release();
	}

	// Registering properties using types from other namespaces
	// http://www.gamedev.net/topic/629088-looks-like-bug-with-namespaces-in-revision-1380/
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);

		RegisterStdString(engine);

		engine->SetDefaultNamespace("mynamespace");
		r = engine->RegisterGlobalProperty("::string val", (void*)1);
		// TODO: Once recursive searches in the namespaces is implemented the scope operator is not needed
		if( r < 0 )
			TEST_FAILED;

		engine->Release();
	}

	// Test problem reported by Andrew Ackermann
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);

		const char *script = 
			"namespace Test { \n"
			"  class A { \n"
			"  } \n"
			"}; \n"
			"void init() { \n"
			"  Test::A@ a = Test::A(); \n"
			"} \n";

		asIScriptModule *mod = engine->GetModule("mod", asGM_ALWAYS_CREATE);
		mod->AddScriptSection("test", script);
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		engine->Release();
	}

	// Test property accessors with namespaces
	// http://www.gamedev.net/topic/635042-indexed-property-accessors-and-namespaces/
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(CBufferedOutStream, Callback), &bout, asCALL_THISCALL);
		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

		const char *script = 
			"int get_foo() { return 42; } \n"
			"namespace nm { int get_foo2() { return 42; } } \n"
			"void test() { \n"
			"  assert( foo == 42 ); \n"      // ok
			"  assert( ::foo == 42 ); \n"    // ok
			"  assert( nm::foo == 42 ); \n"  // should fail to compile
			"  assert( nm::foo2 == 42 ); \n" // ok
			"  assert( foo2 == 42 ); \n"     // should fail to compile
			"} \n"
			"namespace nm { \n"
			"void test2() { \n"
			"  ::assert( foo == 42 ); \n"      // should fail to compile
			"  ::assert( ::foo == 42 ); \n"    // ok
			"  ::assert( nm::foo == 42 ); \n"  // should fail to compile
			"  ::assert( nm::foo2 == 42 ); \n" // ok
			"  ::assert( foo2 == 42 ); \n"     // ok
			"} \n"
			"} \n";

		bout.buffer = "";
		asIScriptModule *mod = engine->GetModule("mod", asGM_ALWAYS_CREATE);
		mod->AddScriptSection("test", script);
		r = mod->Build();
		if( r >= 0 )
			TEST_FAILED;

		if( bout.buffer != "test (3, 1) : Info    : Compiling void test()\n"
						   "test (6, 11) : Error   : 'nm::foo' is not declared\n"
						   "test (8, 11) : Error   : 'foo2' is not declared\n"
						   "test (11, 1) : Info    : Compiling void test2()\n"
						   "test (12, 13) : Error   : 'foo' is not declared\n"
						   "test (14, 13) : Error   : 'nm::foo' is not declared\n" )
		{
			printf("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		// Indexed property accessors
		script = 
			"int get_foo(uint) { return 42; } \n"
			"namespace nm { int get_foo2(uint) { return 42; } } \n"
			"void test() { \n"
			"  assert( foo[0] == 42 ); \n"      // ok
			"  assert( ::foo[0] == 42 ); \n"    // ok
			"  assert( nm::foo[0] == 42 ); \n"  // should fail to compile
			"  assert( nm::foo2[0] == 42 ); \n" // ok
			"  assert( foo2[0] == 42 ); \n"     // should fail to compile
			"} \n"
			"namespace nm { \n"
			"void test2() { \n"
			"  ::assert( foo[0] == 42 ); \n"      // should fail to compile
			"  ::assert( ::foo[0] == 42 ); \n"    // ok
			"  ::assert( nm::foo[0] == 42 ); \n"  // should fail to compile
			"  ::assert( nm::foo2[0] == 42 ); \n" // ok
			"  ::assert( foo2[0] == 42 ); \n"     // ok
			"} \n"
			"} \n";

		bout.buffer = "";
		mod = engine->GetModule("mod", asGM_ALWAYS_CREATE);
		mod->AddScriptSection("test", script);
		r = mod->Build();
		if( r >= 0 )
			TEST_FAILED;

		if( bout.buffer != "test (3, 1) : Info    : Compiling void test()\n"
						   "test (6, 11) : Error   : 'nm::foo' is not declared\n"
						   "test (8, 11) : Error   : 'foo2' is not declared\n"
						   "test (11, 1) : Info    : Compiling void test2()\n"
						   "test (12, 13) : Error   : 'foo' is not declared\n"
						   "test (14, 13) : Error   : 'nm::foo' is not declared\n" )
		{
			printf("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		engine->Release();
	}

	// Test types in namespace
	// http://www.gamedev.net/topic/636336-member-function-chaining/
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(CBufferedOutStream, Callback), &bout, asCALL_THISCALL);
		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

		const char *script = 
			"namespace Default { \n"
			"  void func(ButtonRenderer @) {} \n"
			"  void Init() \n"
			"  { \n"
			"    func(ButtonRenderer()); \n"
			"  } \n"
			"  class ButtonRenderer {} \n"
			"} \n";

		bout.buffer = "";
		asIScriptModule *mod = engine->GetModule("mod", asGM_ALWAYS_CREATE);
		mod->AddScriptSection("test", script);
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		if( bout.buffer != "" )
		{
			printf("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		engine->Release();
	}

	// Success
	return fail;
}
コード例 #8
0
ファイル: test_arrayintf.cpp プロジェクト: Kaperstone/warsow
bool Test()
{
	bool fail = false;
	int r;
	COutStream out;

 	asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
	engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);

	RegisterScriptArray(engine, true);
	RegisterScriptString(engine);

	engine->RegisterGlobalProperty("float[] @floatArray", &floatArray);
	engine->RegisterGlobalProperty("string[] @stringArray", &stringArray);

	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;
	}
	else
	{
		if( (floatArray->GetArrayTypeId() & asTYPEID_MASK_OBJECT) != asTYPEID_TEMPLATE )
			TEST_FAILED;

		if( floatArray->GetArrayTypeId() != engine->GetTypeIdByDecl("float[]") )
			TEST_FAILED;

		if( floatArray->GetElementTypeId() != engine->GetTypeIdByDecl("float") )
			TEST_FAILED;

		if( floatArray->GetSize() != 2 )
			TEST_FAILED;

		if( *(float*)floatArray->At(0) != 1.1f )
			TEST_FAILED;

		if( *(float*)floatArray->At(1) != 1.2f )
			TEST_FAILED;

		if( stringArray->GetArrayTypeId() != engine->GetTypeIdByDecl("string[]") )
			TEST_FAILED;

		if( stringArray->GetElementTypeId() != engine->GetTypeIdByDecl("string") )
			TEST_FAILED;

		if( stringArray->GetSize() != 1 )
			TEST_FAILED;

		if( ((CScriptString*)stringArray->At(0))->buffer != "test" )
			TEST_FAILED;

		stringArray->Resize(2);
	}

	if( floatArray )
		floatArray->Release();
	if( stringArray )
		stringArray->Release();

	engine->Release();

	// Success
	return fail;
}
コード例 #9
0
void Test()
{
	printf("---------------------------------------------\n");
	printf("%s\n\n", TESTNAME);
	printf("AngelScript 2.25.0 WIP 7: 16.17 secs\n");
	printf("AngelScript 2.25.0 WIP 8: 15.22 secs (hint for discarding temp variables)\n");
	printf("AngelScript 2.25.0 WIP 9: 15.07 secs (improved bytecode optimization)\n");

 	asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);

	COutStream out;
	engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);

	RegisterScriptArray(engine, true);
	RegisterStdString(engine);

//	engine->SetEngineProperty(asEP_OPTIMIZE_BYTECODE, false);

	////////////////////////////////////////////
	printf("\nGenerating...\n");

	string script;
	script += "int var; \n";
	script += "int func(int, int, int, int, int, int, int, int) { return 0; } \n";
	script += "void main() { \n";
	script += buildSwitch(numLevels);
	script += "} \n";

	int lines = 0;
	for( unsigned int n = 0; n < script.size(); n++ )
		if( script[n] == '\n' ) lines++;
	printf("Number of lines: %d\n", lines);

	////////////////////////////////////////////
	printf("\nBuilding...\n");

	double time = GetSystemTimer();

	asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
	mod->AddScriptSection(TESTNAME, script.c_str(), script.size(), 0);
	int r = mod->Build();

	time = GetSystemTimer() - time;

	if( r != 0 )
		printf("Build failed\n", TESTNAME);
	else
		printf("Time = %f secs\n", time);

	////////////////////////////////////////////
	printf("\nSaving...\n");

	time = GetSystemTimer();

	CBytecodeStream stream("");
	mod->SaveByteCode(&stream);

	time = GetSystemTimer() - time;
	printf("Time = %f secs\n", time);
	printf("Size = %d\n", int(stream.buffer.size()));

	////////////////////////////////////////////
	printf("\nLoading...\n");

	time = GetSystemTimer();

	asIScriptModule *mod2 = engine->GetModule(0, asGM_ALWAYS_CREATE);
	mod2->LoadByteCode(&stream);

	time = GetSystemTimer() - time;
	printf("Time = %f secs\n", time);

	engine->Release();
}
コード例 #10
0
void Test()
{
	printf("---------------------------------------------\n");
	printf("%s\n\n", TESTNAME);
	printf("AngelScript 2.25.1 WIP 0: 1.59 secs\n");
	printf("AngelScript 2.25.1 WIP 1: 1.66 secs (local bytecode optimizations)\n");
	printf("AngelScript 2.25.1 WIP 2: 1.60 secs (reversed order)\n");
	printf("AngelScript 2.28.1 WIP:   1.08 secs\n");

	asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);

	COutStream out;
	engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);

	RegisterScriptArray(engine, true);
	RegisterStdString(engine);
	engine->RegisterGlobalFunction("void print(const string &in)", asFUNCTION(print), asCALL_CDECL);

	////////////////////////////////////////////
	printf("\nGenerating...\n");

	const int numArrays = 2;
#ifdef _DEBUG
	const int numElements = 10;
#else
	const int numElements = 100000;
#endif

	string script;
    std::stringstream script_buffer;
    for (unsigned i = 0; i < numArrays; i++)
    {
        script_buffer << "int[] array_" << i << " = {";
        if (numElements > 0)
        {
            script_buffer << 0;
        }
        for (unsigned j = 1; j < numElements; j++)
        {
            script_buffer << ", " << j;
        }
        script_buffer << "};";
    }
    script_buffer << std::endl << "int main() { print (\"elem 999 = \" + array_0[999] + \"\\n\"); return 0; }";
    script = script_buffer.str();

	////////////////////////////////////////////
	printf("\nBuilding...\n");

	double time = GetSystemTimer();

	asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
	mod->AddScriptSection(TESTNAME, script.c_str(), script.size(), 0);
	int r = mod->Build();

	time = GetSystemTimer() - time;

	if( r != 0 )
		printf("Build failed\n", TESTNAME);
	else
		printf("Time = %f secs\n", time);

	////////////////////////////////////////////
	printf("\nSaving...\n");

	time = GetSystemTimer();

	CBytecodeStream stream("");
	mod->SaveByteCode(&stream);

	time = GetSystemTimer() - time;
	printf("Time = %f secs\n", time);
	printf("Size = %d\n", int(stream.buffer.size()));

	////////////////////////////////////////////
	printf("\nLoading...\n");

	time = GetSystemTimer();

	asIScriptModule *mod2 = engine->GetModule(0, asGM_ALWAYS_CREATE);
	mod2->LoadByteCode(&stream);

	time = GetSystemTimer() - time;
	printf("Time = %f secs\n", time);

	engine->Release();
}
コード例 #11
0
bool Test()
{
	bool fail = false;
	int r;
	CBufferedOutStream bout;
	COutStream out;
	asIScriptModule *mod;

	float val;

	// Test access masks for delegates without the first bit set
	// http://www.gamedev.net/topic/673050-bug-with-access-masks/
	{
		asIScriptEngine *engine = asCreateScriptEngine();
		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);

		RegisterScriptArray(engine, true);
		RegisterStdString(engine);

		engine->RegisterGlobalFunction("void Print(const string& in s)", asFUNCTION(0), asCALL_GENERIC);

		mod = engine->GetModule("test", asGM_ALWAYS_CREATE);
		mod->SetAccessMask(2);
		mod->AddScriptSection("test",
			"funcdef void Foo();\n"
			"Foo@ g_pFoo = null;\n"
			"class Bar\n"
			"{\n"
			"	Bar()\n"
			"	{\n"
			"		@g_pFoo = Foo(this.bar);\n"
			"	}\n"
			"	void bar()\n"
			"	{\n"
			"	}\n"
			"}\n"
			"void test()\n"
			"{\n"
			"	Bar bar;\n"
			"	g_pFoo();\n"
			"}\n");
		r = mod->Build();
		if (r < 0)
			TEST_FAILED;
		
		engine->ShutDownAndRelease();
	}

	//------------
	// Test global properties
	asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
	engine->SetDefaultAccessMask(1);
	engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);

	r = engine->BeginConfigGroup("group"); assert( r >= 0 );
	r = engine->RegisterGlobalProperty("float val", &val); assert( r >= 0 );
	r = engine->EndConfigGroup(); assert( r >= 0 );

	// Make sure the default access is granted
	r = ExecuteString(engine, "val = 1.3f"); 
	if( r < 0 )
		TEST_FAILED;

	// Make sure the default access can be turned off
	engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL);
	
	mod = engine->GetModule("ExecuteString", asGM_ALWAYS_CREATE);
	mod->SetAccessMask(2); 

	r = ExecuteString(engine, "val = 1.0f", mod);
	if( r >= 0 )
		TEST_FAILED;

	if( bout.buffer != "ExecuteString (1, 1) : Error   : No matching symbol 'val'\n")
		TEST_FAILED;

	// Make sure the default access can be overridden
	engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);
	mod->SetAccessMask(1); 

	r = ExecuteString(engine, "val = 1.0f", mod);
	if( r < 0 )
		TEST_FAILED;

	engine->Release();

	//----------
	// Test global functions
	engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
	engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);
	engine->SetDefaultAccessMask(2);

	r = engine->BeginConfigGroup("group"); assert( r >= 0 );
	r = engine->RegisterGlobalFunction("void Func()", asFUNCTION(Func), asCALL_GENERIC); assert( r >= 0 );
	r = engine->EndConfigGroup(); assert( r >= 0 );

	mod = engine->GetModule("ExecuteString", asGM_ALWAYS_CREATE);
	mod->SetAccessMask(1); 

	engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL);
	bout.buffer = "";
	r = ExecuteString(engine, "Func()", mod);
	if( r >= 0 )
		TEST_FAILED;

	if (bout.buffer != "ExecuteString (1, 1) : Error   : No matching symbol 'Func'\n")
	{
		PRINTF("%s", bout.buffer.c_str());
		TEST_FAILED;
	}

	mod->SetAccessMask(2);

	engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);
	r = ExecuteString(engine, "Func()", mod);
	if( r < 0 )
		TEST_FAILED;

	engine->Release();

	//------------
	// Test object types
	engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
	engine->SetDefaultAccessMask(1);
	engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);

	r = engine->BeginConfigGroup("group"); assert( r >= 0 );
	r = engine->RegisterObjectType("mytype", sizeof(int), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_PRIMITIVE); assert( r >= 0 );
	r = engine->EndConfigGroup(); assert( r >= 0 );

	mod = engine->GetModule("ExecuteString", asGM_ALWAYS_CREATE);
	mod->SetAccessMask(2); 

	engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL);
	bout.buffer = "";
	r = ExecuteString(engine, "mytype a", mod);
	if( r >= 0 )
		TEST_FAILED;

	if( bout.buffer != "ExecuteString (1, 1) : Error   : Type 'mytype' is not available for this module\n")
		TEST_FAILED;

	engine->Release();

	//------------
	// Test class members in different config groups
	engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
	engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);

	r = engine->RegisterObjectType("mytype", sizeof(int), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_PRIMITIVE); assert( r >= 0 );

	r = engine->SetDefaultAccessMask(2);
	r = engine->RegisterObjectMethod("mytype", "mytype opAdd(mytype &in)", asFUNCTION(TypeAdd), asCALL_GENERIC); assert( r >= 0 );
	r = engine->RegisterObjectProperty("mytype", "int val", 0); assert( r >= 0 );
	
	mod = engine->GetModule("ExecuteString", asGM_ALWAYS_CREATE);
	mod->SetAccessMask(1); 

	engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL);
	bout.buffer = "";
	r = ExecuteString(engine, "mytype a; a + a; a.val + a.val; a.opAdd(a);", mod);

	// It should be possible to disallow individual class methods
	if( r >= 0 )
		TEST_FAILED;

	if( bout.buffer != "ExecuteString (1, 13) : Error   : No matching operator that takes the types 'mytype' and 'mytype' found\n"
		               "ExecuteString (1, 19) : Error   : 'val' is not a member of 'mytype'\n"
					   "ExecuteString (1, 35) : Error   : No matching symbol 'opAdd'\n" )
	{
		PRINTF("%s", bout.buffer.c_str());
		TEST_FAILED;
	}

	engine->Release();

	// Success
	return fail;
}
コード例 #12
0
bool Test()
{
	RET_ON_MAX_PORT

	bool fail = false;
	COutStream out;
	CBufferedOutStream bout;
	int r;
	asIScriptEngine *engine = 0;

	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);
		RegisterStdString(engine);
		RegisterScriptArray(engine, false);
		RegisterScriptFile(engine);
		RegisterScriptFileSystem(engine);
		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

		asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
		mod->AddScriptSection("test", 
			"void main() { \n"
			"  filesystem fs; \n"										// starts in applications working dir
			"  array<string> dirs = fs.getDirs(); \n"
			"  assert( dirs.find('scripts') >= 0 ); \n"
			"  fs.changeCurrentPath('scripts'); \n"						// move to the sub directory
			"  array<string> files = fs.getFiles(); \n"					// get the script files in the directory
			"  assert( files.length() == 2 ); \n"
			"  file f; \n"
			"  f.open('scripts/include.as', 'r'); \n"
			"  string str = f.readLine(); \n"
			"  str = str.substr(3, 25); \n"
			"  assert( str == 'void MyIncludedFunction()' ); \n"
			"} \n");
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		asIScriptContext *ctx = engine->CreateContext();
		r = ExecuteString(engine, "main()", mod, ctx);
		if( r != asEXECUTION_FINISHED )
		{
			if( r == asEXECUTION_EXCEPTION && ctx->GetExceptionLineNumber() == 4 )
				PRINTF("Failed to find the sub directory 'scripts'. Are you running the test from the correct folder?\n");
			else
				TEST_FAILED;
		}
		ctx->Release();

		if( bout.buffer != "" )
		{
			PRINTF("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		engine->Release();
	}

	{
		asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);
		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);
		RegisterStdString(engine);
		RegisterScriptFile(engine);

		const char *script =
			"file f;                                                  \n"
			"int r = f.open(\"scripts/TestExecuteScript.as\", \"r\"); \n"
			"if( r >= 0 ) {                                           \n"
			"  assert( f.getSize() > 0 );                             \n"
			"  string s1 = f.readString(10000);                       \n"
			"  assert( s1.length() == uint(f.getSize()) );            \n"
			"  f.close();                                             \n"
			"  f.open('scripts/TestExecuteScript.as', 'r');           \n"
			"  string s2;                                             \n"
			"  while( !f.isEndOfFile() )                              \n"
			"  {                                                      \n"
			"    string s3 = f.readLine();                            \n"
			"    s2 += s3;                                            \n"
			"  }                                                      \n"
			"  assert( s1 == s2 );                                    \n"
			"  f.close();                                             \n"
			"}                                                        \n";

		r = ExecuteString(engine, script);
		if( r != asEXECUTION_FINISHED )
		{
			TEST_FAILED;
		}

		engine->Release();
	}

	return fail;
}
コード例 #13
0
void Test()
{
	printf("---------------------------------------------\n");
	printf("%s\n\n", TESTNAME);
	printf("AngelScript 2.25.1 WIP 0: 0.34 secs\n");
	printf("AngelScript 2.25.1 WIP 1: 0.33 secs (local bytecode optimizations)\n");
	printf("AngelScript 2.25.1 WIP 2: 0.32 secs (reversed order)\n");


 	asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);

	COutStream out;
	engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);

	RegisterScriptArray(engine, true);
	RegisterStdString(engine);

	////////////////////////////////////////////
	printf("\nGenerating...\n");

	const int numSymbols = 10000;

	string script;
	script.reserve(numSymbols * 30);

    for( int i = 0; i < numSymbols; i++ )
    {
		char buf[500];
		sprintf(buf, "const int const_%d = %d;\n", i, i);
		script += buf;
    }

	////////////////////////////////////////////
	printf("\nBuilding...\n");

	double time = GetSystemTimer();

	asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
	mod->AddScriptSection(TESTNAME, script.c_str(), script.size(), 0);
	int r = mod->Build();

	time = GetSystemTimer() - time;

	if( r != 0 )
		printf("Build failed\n", TESTNAME);
	else
		printf("Time = %f secs\n", time);

	////////////////////////////////////////////
	printf("\nSaving...\n");

	time = GetSystemTimer();

	CBytecodeStream stream("");
	mod->SaveByteCode(&stream);

	time = GetSystemTimer() - time;
	printf("Time = %f secs\n", time);
	printf("Size = %d\n", int(stream.buffer.size()));

	////////////////////////////////////////////
	printf("\nLoading...\n");

	time = GetSystemTimer();

	asIScriptModule *mod2 = engine->GetModule(0, asGM_ALWAYS_CREATE);
	mod2->LoadByteCode(&stream);

	time = GetSystemTimer() - time;
	printf("Time = %f secs\n", time);

	engine->Release();
}
コード例 #14
0
ファイル: test_int8.cpp プロジェクト: FrankStain/angelscript
bool Test()
{
	RET_ON_MAX_PORT

	int r;
	bool fail = false;
	COutStream out;

 	asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
	
	engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);
	RegisterScriptArray(engine, true);
	RegisterScriptString(engine);
	engine->RegisterGlobalFunction("void Assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

	// We'll test two things with this function
	// 1. The native interface is able to pass byte parameters correctly
	// 2. The native interface is able to return byte values correctly
	engine->RegisterGlobalFunction("int8 RetInt8(int8)", asFUNCTION(RetInt8), asCALL_CDECL);

	char var = 0;
	engine->RegisterGlobalProperty("int8 gvar", &var);

	ExecuteString(engine, "gvar = RetInt8(1)");
	if( var != 1 )
	{
		PRINTF("failed to return value correctly\n");
		TEST_FAILED;
	}
	
	ExecuteString(engine, "Assert(RetInt8(1) == 1)");

	
	// Test to make sure bools can be passed to member functions properly
	engine->RegisterObjectType("Int8Tester", 0, asOBJ_REF | asOBJ_NOHANDLE);
	engine->RegisterObjectMethod("Int8Tester", "void Test1(int8)", asMETHOD(TestInt8Class, Test1), asCALL_THISCALL);
	engine->RegisterObjectMethod("Int8Tester", "void Test0(int8)", asMETHOD(TestInt8Class, Test0), asCALL_THISCALL);	
	TestInt8Class testInt8;
	r = engine->RegisterGlobalProperty("Int8Tester TestInt8Class", &testInt8 );
	if( r < 0 ) TEST_FAILED;
	asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
	mod->AddScriptSection("script", script3, strlen(script3));
	r = mod->Build();
	if( r < 0 )
	{
		TEST_FAILED;
	}
	else
	{
		r = ExecuteString(engine, "TestInt8ToMember();", mod);
		if( r != asEXECUTION_FINISHED ) TEST_FAILED;

		if( testInt8.m_fail ) TEST_FAILED;
	}

	// Shift operations with int8 should result in int32
	r = ExecuteString(engine, "uint8[] buf={1,2,3,4,5,6}; "
                                 "uint32 ver; "
                                 "ver = buf[0]; "
                                 "ver |= buf[1]<<8; "
                                 "ver |= buf[2]<<16; "
                                 "ver |= buf[3]<<24; "
								 "Assert(ver == 0x04030201);"); // If this is changed to 0x01020304 Avira accuses the compiled obj file as virus
	if( r != asEXECUTION_FINISHED )
	{
		TEST_FAILED;
	}


	engine->Release();

	return fail;
}
コード例 #15
0
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;
}
コード例 #16
0
bool Test()
{
	bool fail = false;
	int r;

 	asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
	RegisterScriptArray(engine, true);
	RegisterScriptString_Generic(engine);
	engine->RegisterGlobalFunction("void Assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);
	engine->RegisterGlobalFunction("double atof(const string &in)",asFUNCTION(StringToDouble),asCALL_GENERIC);

	COutStream out;

	asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
	mod->AddScriptSection(TESTNAME, script1, strlen(script1), 0);
	engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);
	r = mod->Build();
	if( r < 0 )
	{
		TEST_FAILED;
		PRINTF("%s: Failed to compile the script\n", TESTNAME);
	}

	asIScriptContext *ctx = engine->CreateContext();
	r = ExecuteString(engine, "TestArrayHandle()", 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);
	engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);
	r = mod->Build();
	if( r < 0 )
	{
		TEST_FAILED;
		PRINTF("%s: Failed to compile the script\n", TESTNAME);
	}

	ctx = engine->CreateContext();
	r = ExecuteString(engine, "TestArrayHandle2()", 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();

	engine->Release();

	// 
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);
		RegisterScriptArray(engine, true);
		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);
		engine->SetEngineProperty(asEP_OPTIMIZE_BYTECODE, false);

		const char *script = 
			"class Node \n"
			"{ \n"
			"  Node@[]@ GetSubnodes() { return subNodes; } \n"
			"  Node@[] subNodes; \n"
			"  int member; \n"
			"} \n"
			"void TestFunc(Node@ input) \n"
			"{ \n"
			"  Node@[]@ nodearray; \n"
			"  Node@ subnode; \n"
			"  // Case 1. Works as expected \n"
			"  @nodearray = @input.GetSubnodes(); \n"
			"  @subnode = @nodearray[0]; \n"
			"  int value1 = subnode.member; // <- ok \n"
			"  assert( value1 == 42 ); \n"
			"  // Case 2. Wrong address sent to following operations on 'subnode' \n"
			"  @subnode = @input.GetSubnodes()[0]; \n"
			"  int value2 = subnode.member; // <- weird behavior \n"
			"  assert( value2 == 42 ); \n"
			"} \n";

		mod = engine->GetModule("mod", asGM_ALWAYS_CREATE);
		mod->AddScriptSection("script", script);
		r = mod->Build();
		if( r < 0 ) 
		{
			TEST_FAILED;
		}
		else
		{
			asIScriptContext *ctx = engine->CreateContext();
			r = ExecuteString(engine, "Node n; \n"
				                      "n.subNodes.resize(1); \n"
									  "@n.subNodes[0] = @Node(); \n"
									  "n.subNodes[0].member = 42; \n"
									  "TestFunc(n); \n", mod, ctx);
			if( r != asEXECUTION_FINISHED )
			{
				TEST_FAILED;
				if( r == asEXECUTION_EXCEPTION )
					PrintException(ctx);
			}
			ctx->Release();
		}

		engine->Release();
	}

	// Success
	return fail;
}
コード例 #17
0
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;
}
コード例 #18
0
bool Test()
{
	if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") )
	{
		// Skipping this due to not supporting native calling conventions
		printf("Skipped due to AS_MAX_PORTABILITY\n");
		return false;
	}

	bool fail = false;
	int r;
	int suspendId, exceptionId;

 	asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);

	engine->RegisterObjectType("Object", sizeof(CObject), asOBJ_VALUE | asOBJ_APP_CLASS_CD);	
	r = engine->RegisterObjectType("RefObj", sizeof(CRefObject), asOBJ_REF); assert(r >= 0);
	if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") )
	{
		engine->RegisterObjectBehaviour("Object", asBEHAVE_CONSTRUCT, "void f(int)", asFUNCTION(Construct2), asCALL_GENERIC);
		engine->RegisterObjectBehaviour("Object", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(Construct_gen), asCALL_GENERIC);
		engine->RegisterObjectBehaviour("Object", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(Destruct_gen), asCALL_GENERIC);
		engine->RegisterObjectMethod("Object", "Object &opAssign(const Object &in)", asFUNCTION(Assign_gen), asCALL_GENERIC);
		r = engine->RegisterObjectBehaviour("RefObj", asBEHAVE_FACTORY, "RefObj@ f()", asFUNCTION(RefObjFactory_gen), asCALL_GENERIC); assert(r >= 0);
		r = engine->RegisterObjectBehaviour("RefObj", asBEHAVE_ADDREF, "void f()", asFUNCTION(AddRef_gen), asCALL_GENERIC); assert(r >= 0);
		r = engine->RegisterObjectBehaviour("RefObj", asBEHAVE_RELEASE, "void f()", asFUNCTION(Release_gen), asCALL_GENERIC); assert(r >= 0);
		engine->RegisterGlobalFunction("void RaiseException()", asFUNCTION(RaiseException), asCALL_GENERIC);
		suspendId   = engine->RegisterGlobalFunction("Object SuspendObj()", asFUNCTION(SuspendObj_gen), asCALL_GENERIC);
		exceptionId = engine->RegisterGlobalFunction("Object ExceptionObj()", asFUNCTION(ExceptionObj_gen), asCALL_GENERIC);
		engine->RegisterGlobalFunction("RefObj@ ExceptionHandle()", asFUNCTION(ExceptionHandle_gen), asCALL_GENERIC);
	}
	else
	{
		engine->RegisterObjectBehaviour("Object", asBEHAVE_CONSTRUCT, "void f(int)", asFUNCTION(Construct2), asCALL_GENERIC);
		engine->RegisterObjectBehaviour("Object", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(Construct), asCALL_CDECL_OBJLAST);
		engine->RegisterObjectBehaviour("Object", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(Destruct), asCALL_CDECL_OBJLAST);
		engine->RegisterObjectMethod("Object", "Object &opAssign(const Object &in)", asFUNCTION(Assign_gen), asCALL_GENERIC);
		r = engine->RegisterObjectBehaviour("RefObj", asBEHAVE_FACTORY, "RefObj@ f()", asFUNCTION(RefObjFactory), asCALL_CDECL); assert(r >= 0);
		r = engine->RegisterObjectBehaviour("RefObj", asBEHAVE_ADDREF, "void f()", asMETHOD(CRefObject, AddRef), asCALL_THISCALL); assert(r >= 0);
		r = engine->RegisterObjectBehaviour("RefObj", asBEHAVE_RELEASE, "void f()", asMETHOD(CRefObject, Release), asCALL_THISCALL); assert(r >= 0);
		engine->RegisterGlobalFunction("void RaiseException()", asFUNCTION(RaiseException), asCALL_CDECL);
		suspendId   = engine->RegisterGlobalFunction("Object SuspendObj()", asFUNCTION(SuspendObj), asCALL_CDECL);
		exceptionId = engine->RegisterGlobalFunction("Object ExceptionObj()", asFUNCTION(ExceptionObj), asCALL_CDECL);
		engine->RegisterGlobalFunction("RefObj@ ExceptionHandle()", asFUNCTION(ExceptionHandle), asCALL_CDECL);
	}



	COutStream out;

	asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
	mod->AddScriptSection(TESTNAME, script1, strlen(script1), 0);
	mod->AddScriptSection(TESTNAME, script2, strlen(script2), 0);
	engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);
	r = mod->Build();
	if( r < 0 )
	{
		TEST_FAILED;
		printf("%s: Failed to compile the script\n", TESTNAME);
	}

	// The object has been initialized
	r = ExecuteString(engine, "Test1()", mod);
	if( r != asEXECUTION_EXCEPTION )
	{
		printf("%s: Failed\n", TESTNAME);
		TEST_FAILED;
	}

	// The object has not yet been initialized
	r = ExecuteString(engine, "Test2()", mod);
	if( r != asEXECUTION_EXCEPTION )
	{
		printf("%s: Failed\n", TESTNAME);
		TEST_FAILED;
	}

	// An object has been initialized and passed by value to function that throws exception
	r = ExecuteString(engine, "Test3()", mod);
	if( r != asEXECUTION_EXCEPTION )
	{
		printf("%s: Failed\n", TESTNAME);
		TEST_FAILED;
	}

	// An object has been initialized and passed by value to a function, but 
	// the function cannot be called due to the stack being full
	engine->SetEngineProperty(asEP_MAX_STACK_SIZE, sizeof(void*));
	r = ExecuteString(engine, "Test3()", mod);
	if( r != asEXECUTION_EXCEPTION )
	{
		printf("%s: Failed\n", TESTNAME);
		TEST_FAILED;
	}

	// An object is allocated and initialized with a call to 
	// a function that returns an object by value. The function 
	// suspends the thread. The context is then aborted.
	asIScriptContext *ctx = engine->CreateContext();
	engine->SetEngineProperty(asEP_MAX_STACK_SIZE, 0);
	r = ExecuteString(engine, "Test4()", mod, ctx);
	if( r != asEXECUTION_SUSPENDED )
	{
		printf("%s: Failed\n", TESTNAME);
		TEST_FAILED;
	}
	ctx->Abort();
	ctx->Release();

	// An object is allocated and initialized with a call to 
	// a function that returns an object by value. The function 
	// sets a script exception.
	r = ExecuteString(engine, "Test5()", mod);
	if( r != asEXECUTION_EXCEPTION )
	{
		printf("%s: Failed\n", TESTNAME);
		TEST_FAILED;
	}

	// The object constructor sets the exception
	r = ExecuteString(engine, "Test6()", mod);
	if( r != asEXECUTION_EXCEPTION )
	{
		printf("%s: Failed\n", TESTNAME);
		TEST_FAILED;
	}

	// A function that is supposed to return a handle sets an exception
	r = ExecuteString(engine, "Test7()", mod);
	if( r != asEXECUTION_EXCEPTION )
	{
		printf("%s: Failed\n", TESTNAME);
		TEST_FAILED;
	}

    // Attempt to call method on null class pointer
	mod->AddScriptSection("script", script3, strlen(script3));
	r = mod->Build();
	if( r < 0 ) TEST_FAILED;
	r = ExecuteString(engine, "calc()", mod);
	if( r != asEXECUTION_EXCEPTION )
	{
		printf("%s: Failed\n", TESTNAME);
		TEST_FAILED;
	}

	// Exception happens after value object has already been destroyed
	r = ExecuteString(engine, "{\n"
		                      "  Object o;\n"
                              "}\n"
							  "RaiseException();");
	if( r != asEXECUTION_EXCEPTION )
		TEST_FAILED;

	// Exception happens after the value object has been destroyed and, 
	// the same position would also be used again after the exception
	r = ExecuteString(engine, "{ Object o; } \n"
		                      "RaiseException(); \n"
							  "Object o; \n");
	if( r != asEXECUTION_EXCEPTION )
		TEST_FAILED;

	// The code has two places where the object is destroyed, one in the if case, and 
	// and one at the end of the function. If the code doesn't go in to the if case,
	// and the exception happens afterwards, the exception handler must not think the
	// object was already destroyed.
	r = ExecuteString(engine, "Object o; bool a = false; \n"
		                      "if( a ) return; \n"
							  "RaiseException(); \n");
	if( r != asEXECUTION_EXCEPTION )
		TEST_FAILED;

	// Calling a function that returns an object directly must release the object upon releasing the context
	ctx = engine->CreateContext();
	ctx->Prepare(engine->GetFunctionById(suspendId));
	ctx->Execute();
	ctx->Release();

	// Calling a function that returns an object but raised an exception shouldn't try to destroy the object
	ctx = engine->CreateContext();
	ctx->Prepare(engine->GetFunctionById(exceptionId));
	ctx->Execute();
	ctx->Release();

 	engine->Release();

	// Test proper release of function pointers on exception
	{
		COutStream out;

		asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);

		engine->RegisterGlobalFunction("void RaiseException()", asFUNCTION(RaiseException), asCALL_CDECL);

		asIScriptModule *mod = engine->GetModule("mod", asGM_ALWAYS_CREATE);
		mod->AddScriptSection("script", 
			"funcdef void func_t(); \n"
			"void main() \n"
			"{ \n"
			"  func_t @f = main; \n"
			"  RaiseException(); \n"
			"} \n");

		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		r = ExecuteString(engine, "main()", mod);
		if( r != asEXECUTION_EXCEPTION )
			TEST_FAILED;
		
		engine->Release();
	}

	// Test problem reported by FDsagizi
	// http://www.gamedev.net/topic/631801-pod-type-and-null-pointer-exception-bug-with-call-destructor/
	{
		COutStream out;
		asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);

		engine->RegisterObjectType("TestLink", sizeof(CObject), asOBJ_VALUE | asOBJ_APP_CLASS_CD);	
		engine->RegisterObjectBehaviour("TestLink", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(Construct), asCALL_CDECL_OBJLAST);
		engine->RegisterObjectBehaviour("TestLink", asBEHAVE_CONSTRUCT, "void f(const TestLink &in)", asFUNCTION(CopyConstruct), asCALL_CDECL_OBJLAST);
		engine->RegisterObjectBehaviour("TestLink", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(Destruct), asCALL_CDECL_OBJLAST);

		asIScriptModule *mod = engine->GetModule("mod", asGM_ALWAYS_CREATE);
		mod->AddScriptSection("test",
			"class Object3 \n"
			"{ \n"
			"    Object3( TestLink str ) \n"
			"    { \n"
			"        Object3 @null_object = null; \n"
			"        null_object.Do(); \n"
			"    } \n"
			"    void Do() {} \n"
			"} \n"
			"void Main() \n"
			"{ \n"
			"   Object3 @oo = Object3( TestLink() ); \n"
			"} \n");
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		CObject_constructCount = 0;
		CObject_destructCount = 0;

		asIScriptContext *ctx = engine->CreateContext();
		r = ExecuteString(engine, "Main()", mod, ctx);
		if( r != asEXECUTION_EXCEPTION )
			TEST_FAILED;

		if( CObject_constructCount != 2 ||
			CObject_destructCount != 1 )
			TEST_FAILED;

		ctx->Release();

		if( CObject_constructCount != 2 ||
			CObject_destructCount != 2 )
			TEST_FAILED;

		CBytecodeStream stream(__FILE__"1");
		r = mod->SaveByteCode(&stream);
		if( r < 0 )
			TEST_FAILED;
		
		r = mod->LoadByteCode(&stream); 
		if( r < 0 )
			TEST_FAILED;

		CObject_constructCount = 0;
		CObject_destructCount = 0;

		ctx = engine->CreateContext();
		r = ExecuteString(engine, "Main()", mod, ctx);
		if( r != asEXECUTION_EXCEPTION )
			TEST_FAILED;

		if( CObject_constructCount != 2 ||
			CObject_destructCount != 1 )
			TEST_FAILED;

		ctx->Release();

		engine->Release();
	}

	// Test failure when allocating very large array
	{
		COutStream out;
		asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);

		RegisterScriptArray(engine, true);

		asIScriptModule *mod = engine->GetModule("mod", asGM_ALWAYS_CREATE);
		mod->AddScriptSection("script",
			"class test\n"
			"{\n"
			"  double x;\n"
			"  double y;\n"
			"  double z;\n"
			"  double other;\n"
			"}\n"
			"void main()\n"
			"{\n"
			"  test[] list(1000000000);\n"
			"}\n");

		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		r = ExecuteString(engine, "main()", mod);
		if( r != asEXECUTION_EXCEPTION )
			TEST_FAILED;

		engine->Release();
	}

	// Success
	return fail;
}
コード例 #19
0
bool Test()
{
	bool fail = false;
	int r;

	COutStream out;
	CBufferedOutStream bout;

 	asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
	engine->SetEngineProperty(asEP_ALLOW_UNSAFE_REFERENCES, 1);
	engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);
	RegisterScriptArray(engine, true);
	RegisterScriptString(engine);

	r = engine->RegisterGlobalFunction("void Assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); assert( r >= 0 );

	asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
	mod->AddScriptSection(TESTNAME, script1);
	r = mod->Build();
	if( r < 0 )
	{
		TEST_FAILED;
		printf("%s: Failed to compile the script\n", TESTNAME);
	}
	asIScriptContext *ctx = engine->CreateContext();
	r = ExecuteString(engine, "Test()", mod, ctx);
	if( r != asEXECUTION_FINISHED )
	{
		TEST_FAILED;
		printf("%s: Execution failed: %d\n", TESTNAME, r);
	}

	if( ctx ) ctx->Release();

	engine->Release();

	// Test value class with unsafe ref
	{
		asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetEngineProperty(asEP_ALLOW_UNSAFE_REFERENCES, 1);
		engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);
		RegisterScriptMath3D(engine);

		asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
		mod->AddScriptSection(TESTNAME, 
			"class Good \n"
			"{ \n"
			"  vector3 _val; \n"
			"  Good(const vector3& in val) \n"
			"  { \n"
			"    _val = val; \n"
			"  }  \n"
			"};  \n"
			"class Bad  \n"
			"{  \n"
			"  vector3 _val;  \n"
			"  Bad(const vector3& val)  \n"
			"  {  \n"
			"    _val = val;  \n"
			"  }  \n"
			"}; \n"
			"void test()  \n"
			"{ \n"
			"  // runs fine  \n"
			"  for (int i = 0; i < 2; i++)  \n"
			"    Good(vector3(1, 2, 3));  \n"
			"  // causes vm stack corruption  \n"
			"  for (int i = 0; i < 2; i++)  \n"
			"    Bad(vector3(1, 2, 3));  \n"
			"} \n");

		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		r = ExecuteString(engine, "test()", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		engine->Release();
	}

	// Test ref to primitives
	{
		bout.buffer = "";
		asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetEngineProperty(asEP_ALLOW_UNSAFE_REFERENCES, 1);
		engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL);

		asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
		mod->AddScriptSection(TESTNAME, 
			"void func(){ \n"
			"  float a; \n"
			"  uint8 b; \n"
			"  int c; \n"
			"  funcA(c, a, b); \n"
			"} \n"
			"void funcA(float& a, uint8& b, int& c) {} \n");

		r = mod->Build();
		if( r >= 0 )
			TEST_FAILED;

		if( bout.buffer != "TestUnsafeRef (1, 1) : Info    : Compiling void func()\n"
		                   "TestUnsafeRef (5, 3) : Error   : No matching signatures to 'funcA(int, float, uint8)'\n"
		                   "TestUnsafeRef (5, 3) : Info    : Candidates are:\n"
		                   "TestUnsafeRef (5, 3) : Info    : void funcA(float&inout, uint8&inout, int&inout)\n" )
		{
			printf("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		engine->Release();
	}

	// Test problem found by TheAtom
	// Passing an inout reference to a handle to a function wasn't working properly
	{
		bout.buffer = "";
		asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetEngineProperty(asEP_ALLOW_UNSAFE_REFERENCES, 1);
		engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL);
		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

		asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
		mod->AddScriptSection(TESTNAME, 
			"class T { int a; } \n"
			"void f(T@& p) { \n"
			"  T t; \n"
			"  t.a = 42; \n"
			"  @p = t; \n" // or p=t; in which case t is copied
			"} \n");

		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		if( bout.buffer != "" )
		{
			printf("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		r = ExecuteString(engine, "T @t; f(t); assert( t.a == 42 );\n", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		engine->Release();		
	}

	// http://www.gamedev.net/topic/624722-bug-with/
	{
		bout.buffer = "";
		asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetEngineProperty(asEP_ALLOW_UNSAFE_REFERENCES, 1);
		engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL);
		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

		asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
		mod->AddScriptSection(TESTNAME, 
			"class T { T() { val = 123; } int val; } \n"
			"T g_t; \n"
			"T &GetTest() { return g_t; } \n"
			"void f(T@& t) { \n"
			"  assert( t.val == 123 ); \n"
			"} \n"
			"void func() { \n"
			"  f(GetTest()); \n"
			"  f(@GetTest()); \n"
			"  T @t = GetTest(); \n"
			"  f(t); \n"
			"} \n");

		r = mod->Build();
		if( r >= 0 )
			TEST_FAILED;

		if( bout.buffer != "TestUnsafeRef (7, 1) : Info    : Compiling void func()\n"
						   "TestUnsafeRef (8, 3) : Error   : No matching signatures to 'f(T)'\n"
						   "TestUnsafeRef (8, 3) : Info    : Candidates are:\n"
						   "TestUnsafeRef (8, 3) : Info    : void f(T@&inout)\n" )
		{
			printf("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		engine->Release();		
	}

	// http://www.gamedev.net/topic/624722-bug-with/
	{
		bout.buffer = "";
		asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetEngineProperty(asEP_ALLOW_UNSAFE_REFERENCES, 1);
		engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL);
		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

		asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
		mod->AddScriptSection(TESTNAME, 
			"class T { T() { val = 123; } int val; } \n"
			"T g_t; \n"
			"T &GetTest() { return g_t; } \n"
			"void f(T@& t) { \n"
			"  assert( t.val == 123 ); \n"
			"} \n"
			"void func() { \n"
			"  f(cast<T>(GetTest())); \n"
			"  f(@GetTest()); \n"
			"} \n");

		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		if( bout.buffer != "" )
		{
			printf("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		asIScriptContext *ctx = engine->CreateContext();
		r = ExecuteString(engine, "func()", mod, ctx);
		if( r != asEXECUTION_FINISHED )
		{
			TEST_FAILED;
			if( r == asEXECUTION_EXCEPTION )
				PrintException(ctx, true);
		}
		ctx->Release();

		engine->Release();		
	}

	// http://www.gamedev.net/topic/636443-there-is-no-copy-operator-for-the-type-val-available/
	{
		bout.buffer = "";
		asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetEngineProperty(asEP_ALLOW_UNSAFE_REFERENCES, 1);
		engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL);
		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

		engine->RegisterObjectType("Val", sizeof(int), asOBJ_VALUE | asOBJ_APP_PRIMITIVE);
		engine->RegisterObjectBehaviour("Val", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(0), asCALL_GENERIC);
		// With unsafe references the copy constructor doesn't have to be in, it can be inout too
		engine->RegisterObjectBehaviour("Val", asBEHAVE_CONSTRUCT, "void f(const Val &)", asFUNCTION(0), asCALL_GENERIC);
		engine->RegisterObjectBehaviour("Val", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(0), asCALL_GENERIC);

		asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
		mod->AddScriptSection(TESTNAME, 
			"Val GetVal() \n"
			"{ \n"
			"    Val ret; \n"
			"    return ret; \n"
			"} \n");

		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		if( bout.buffer != "" )
		{
			printf("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		engine->Release();		
	}

	// Test with copy constructor that takes unsafe reference
	// http://www.gamedev.net/topic/638613-asassert-in-file-as-compillercpp-line-675/
	{
		bout.buffer = "";
		asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetEngineProperty(asEP_ALLOW_UNSAFE_REFERENCES, 1);
		engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL);

		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

		r = engine->RegisterObjectType("string", sizeof(Str), asOBJ_VALUE | asOBJ_APP_CLASS_CDAK); assert( r >= 0 );
		r = engine->RegisterStringFactory("string", asFUNCTION(Str::StringFactory), asCALL_CDECL); assert( r >= 0 );
		r = engine->RegisterObjectBehaviour("string", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(Str::StringConstruct), asCALL_CDECL_OBJLAST); assert( r >= 0 );
		// Copy constructor takes an unsafe reference
		r = engine->RegisterObjectBehaviour("string", asBEHAVE_CONSTRUCT, "void f(const string &)", asFUNCTION(Str::StringCopyConstruct), asCALL_CDECL_OBJLAST); assert( r >= 0 );
		r = engine->RegisterObjectBehaviour("string", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(Str::StringDestruct), asCALL_CDECL_OBJLAST); assert( r >= 0 );
		r = engine->RegisterObjectMethod("string", "bool opEquals(const string &in)", asMETHOD(Str, opEquals), asCALL_THISCALL);

		asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
		mod->AddScriptSection(TESTNAME, 
			"void SetTexture( string txt ) { assert( txt == 'test' ); } \n"
			"void startGame( ) \n"
			"{ \n"
			"   SetTexture('test'); \n"
			"} \n");

		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		if( bout.buffer != "" )
		{
			printf("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		r = ExecuteString(engine, "startGame();", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		engine->Release();
	}

	// Test with assignment operator that takes unsafe reference
	{
		bout.buffer = "";
		asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetEngineProperty(asEP_ALLOW_UNSAFE_REFERENCES, 1);
		engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL);

		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

		r = engine->RegisterObjectType("string", sizeof(Str), asOBJ_VALUE | asOBJ_APP_CLASS_CDAK); assert( r >= 0 );
		r = engine->RegisterStringFactory("string", asFUNCTION(Str::StringFactory), asCALL_CDECL); assert( r >= 0 );
		r = engine->RegisterObjectBehaviour("string", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(Str::StringConstruct), asCALL_CDECL_OBJLAST); assert( r >= 0 );
		r = engine->RegisterObjectBehaviour("string", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(Str::StringDestruct), asCALL_CDECL_OBJLAST); assert( r >= 0 );
		// Assignment operator takes an unsafe reference
		r = engine->RegisterObjectMethod("string", "string &opAssign(const string &)", asMETHOD(Str, opAssign), asCALL_THISCALL); assert( r >= 0 );
		r = engine->RegisterObjectMethod("string", "bool opEquals(const string &in)", asMETHOD(Str, opEquals), asCALL_THISCALL);

		asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
		mod->AddScriptSection(TESTNAME, 
			"void SetTexture( string txt ) { assert( txt == 'test' ); } \n"
			"void startGame( ) \n"
			"{ \n"
			"   SetTexture('test'); \n"
			"} \n");

		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		if( bout.buffer != "" )
		{
			printf("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		r = ExecuteString(engine, "startGame();", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		engine->Release();
	}

	// Success
	return fail;
}
コード例 #20
0
bool Test()
{
	bool fail = Test2();
	int r;

	asIScriptModule *mod = 0;

	asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
	RegisterScriptArray(engine, true);
	RegisterScriptString(engine);

	engine->RegisterGlobalFunction("void Assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

	COutStream out;
	CBufferedOutStream bout;
	engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);

	// Test declaring multiple properties in same declaration separated by ,
	{
		mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
		mod->AddScriptSection(TESTNAME, 
			"class A { \n"
			"  int a, b, c; \n"
			"  void f() { a = b = c; } \n"
			"} \n");

		r = mod->Build();
		if( r < 0 ) TEST_FAILED;
	}


	mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
	mod->AddScriptSection(TESTNAME, script1);
	r = mod->Build();
	if( r < 0 ) TEST_FAILED;

	// Verify that GetObjectTypeByIndex recognizes the script class
	if( mod->GetObjectTypeCount() != 1 )
		TEST_FAILED;
	asIObjectType *type = mod->GetObjectTypeByIndex(0);
	if( strcmp(type->GetName(), "Test") != 0 )
		TEST_FAILED;

	asIScriptContext *ctx = engine->CreateContext();
	r = ExecuteString(engine, "TestStruct()", mod, ctx);
	if( r != asEXECUTION_FINISHED ) 
	{
		if( r == asEXECUTION_EXCEPTION ) PrintException(ctx);
		TEST_FAILED;
	}
	if( ctx ) ctx->Release();

	bout.buffer = "";
	mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
	mod->AddScriptSection(TESTNAME, script2);
	engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL);
	r = mod->Build();
	if( r >= 0 || bout.buffer != "TestScriptStruct (3, 4) : Error   : Class properties cannot be declared as const\n" ) TEST_FAILED;

	mod->AddScriptSection(TESTNAME, script3);
	engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);
	r = mod->Build();
	if( r < 0 ) TEST_FAILED;
	r = ExecuteString(engine, "TestArrayInStruct()", mod);
	if( r != 0 ) TEST_FAILED;

	mod->AddScriptSection(TESTNAME, script4, strlen(script4), 0);
	r = mod->Build();
	if( r < 0 ) TEST_FAILED;
	r = ExecuteString(engine, "Test()", mod);
	if( r != 0 ) TEST_FAILED;

	bout.buffer = "";
	mod->AddScriptSection(TESTNAME, script5, strlen(script5), 0);
	engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL);
	r = mod->Build();
	if( r >= 0 || bout.buffer != 
		"TestScriptStruct (2, 7) : Error   : Name conflict. 'A' is a class.\n"
		"TestScriptStruct (6, 9) : Error   : Name conflict. 'a' is an object property.\n" ) TEST_FAILED;

	bout.buffer = "";
	mod->AddScriptSection(TESTNAME, script6, strlen(script6), 0);
	r = mod->Build();
	if( r >= 0 || bout.buffer !=
		"TestScriptStruct (1, 7) : Error   : Illegal member type\n"
		"TestScriptStruct (5, 7) : Error   : Illegal member type\n" ) TEST_FAILED;

	mod->AddScriptSection(TESTNAME, script7, strlen(script7), 0);
	engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);
	r = mod->Build();
	if( r < 0 ) TEST_FAILED;
	ctx = engine->CreateContext();
	r = ExecuteString(engine, "TestHandleInStruct()", mod, ctx);
	if( r != 0 )
	{
		if( r == asEXECUTION_EXCEPTION )
		{
			printf("%s\n", ctx->GetExceptionString());
		}
		TEST_FAILED;
	}
	if( ctx ) ctx->Release();

	mod->AddScriptSection(TESTNAME, script8, strlen(script8), 0);
	r = mod->Build();
	if( r < 0 ) TEST_FAILED;
	r = ExecuteString(engine, "TestHandleInStruct2()", mod);
	if( r != 0 ) TEST_FAILED;

	mod->AddScriptSection(TESTNAME, script9, strlen(script9), 0);
	r = mod->Build();
	if( r < 0 ) TEST_FAILED;
	r = ExecuteString(engine, "Test()", mod);
	if( r != 0 ) TEST_FAILED;

	bout.buffer = "";
	mod->AddScriptSection(TESTNAME, script10, strlen(script10), 0);
	engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL);
	r = mod->Build();
	if( r >= 0 ) TEST_FAILED;
	if( bout.buffer != "TestScriptStruct (1, 7) : Error   : Illegal member type\n" ) TEST_FAILED;

	bout.buffer = "";
	mod->AddScriptSection(TESTNAME, script11, strlen(script11), 0);
	r = mod->Build();
	if( r >= 0 ) TEST_FAILED;
	if( bout.buffer != "TestScriptStruct (5, 1) : Info    : Compiling void Test()\nTestScriptStruct (9, 11) : Error   : Reference is read-only\n" ) TEST_FAILED;

	mod->AddScriptSection(TESTNAME, script12, strlen(script12), 0);
	mod->AddScriptSection(TESTNAME, script13, strlen(script13), 0);
	engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);
	r = mod->Build();
	if( r < 0 ) TEST_FAILED;

	// The garbage collection doesn't have to be invoked immediately. Modules
	// can even be discarded before calling the garbage collector.
	engine->GarbageCollect();
	
	// Make sure it is possible to copy a script class that contains an object handle
	mod->AddScriptSection(TESTNAME, script14, strlen(script14), 0);
	r = mod->Build();
	if( r < 0 ) TEST_FAILED;
	r = ExecuteString(engine, "A a; B b; @a.b = @b; b.val = 1; A a2; a2 = a; Assert(a2.b.val == 1);", mod);
	if( r != asEXECUTION_FINISHED )
		TEST_FAILED;

	// Make sure it is possible to copy a script class that contains an array
	const char *script15 = 
		"class Some \n"
        "{ \n"
        "    int[] i; // need be array \n"
        "} \n"
        "void main() \n"
        "{ \n"
        "    Some e; \n"
        "    e=some(e); // crash \n"
        "} \n"
        "Some@ some(Some@ e) \n"
        "{ \n"
        "    return e; \n"
        "} \n";

	mod->AddScriptSection(TESTNAME, script15);
	r = mod->Build();
	if( r < 0 ) TEST_FAILED;
	r = ExecuteString(engine, "main()", mod);
	if( r != asEXECUTION_FINISHED )
		TEST_FAILED;

	engine->Release();

	// A script class must be able to have a registered ref type as a local member
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL);
		RegisterScriptString(engine);

		const char *script = "class C { string s; }";
		mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
		mod->AddScriptSection("s", script);

		bout.buffer = "";
		r = mod->Build();
		if( r < 0 ) 
			TEST_FAILED;

		if( bout.buffer != "" )
		{
			printf("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		if( !fail )
		{
			r = ExecuteString(engine, "C c; c.s = 'test';", mod);
			if( r != asEXECUTION_FINISHED )
			{
				TEST_FAILED;
			}
		}

		engine->Release();
	}

	// Test private properties
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL);

		const char *script = "class C { \n"
			                 "private int a; \n"
							 "void func() { a = 1; } }\n"
							 "void main() { C c; c.a = 2; }";
		mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
		mod->AddScriptSection("s", script);

		bout.buffer = "";
		r = mod->Build();
		if( r >= 0 ) 
			TEST_FAILED;

		if( bout.buffer != "s (4, 1) : Info    : Compiling void main()\n"
		                   "s (4, 21) : Error   : Illegal access to private property 'a'\n" )
		{
			printf("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		engine->Release();
	}

	// Test private methods
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(CBufferedOutStream, Callback), &bout, asCALL_THISCALL);

		const char *script = "class C { \n"
							 "  private void func() {} \n"
							 "  void func2() { func(); } } \n"
							 "void main() { C c; c.func(); } \n";
		mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
		mod->AddScriptSection("s", script);

		bout.buffer = "";
		r = mod->Build();
		if( r >= 0 )
			TEST_FAILED;

		if( bout.buffer != "s (4, 1) : Info    : Compiling void main()\n"
		                   "s (4, 20) : Error   : Illegal call to private method 'void C::func()'\n" )
		{
			printf("%s", bout.buffer.c_str());
			TEST_FAILED;
		}

		engine->Release();
	}

	// Test private methods that return a value
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(CBufferedOutStream, Callback), &bout, asCALL_THISCALL);
		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

		const char *script = "class C { \n"
			"  int a(int i) { return ABS(i); } \n"
			"  private int ABS(int i) \n"
			"  { \n"
			"    if(i <= 0) return (-1 * i); \n"
			"    else return i; \n"
			"  } \n"
			"} \n";

		mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
		mod->AddScriptSection("s", 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, "C c; assert( c.a(-10) == 10 );", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		engine->Release();
	}

	// Test private methods with inheritance
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(CBufferedOutStream, Callback), &bout, asCALL_THISCALL);
		engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);

		const char *script = 
			"bool alreadyCalled = false; \n"
			"class CBar \n"
			"{ \n"
			" CBar() \n"
			" { \n"
			"  assert(alreadyCalled == false); \n"
			"  alreadyCalled = true; \n"
			" } \n"
			" void Foo() \n"
			" { \n"
			" } \n"
			"}; \n"
			"class CDerivedBar : CBar \n"
			"{ \n"
			" CDerivedBar() \n"
			" { \n"
			" } \n"
			" private void ImNotAnOverrideOfTheBaseClass() \n"
			" { \n"
			" } \n"
			" private void Foo() \n" 
			" { \n"
			" } \n"
			"}; \n";

		asIScriptModule *mod = engine->GetModule("t", asGM_ALWAYS_CREATE);
		mod->AddScriptSection("script", script);
		mod->Build();

		asIScriptContext *ctx = engine->CreateContext();
		r = ExecuteString(engine, "CDerivedBar bar; bar.Foo(); ", mod, ctx);
		if( r != asEXECUTION_FINISHED )
		{
			if( r == asEXECUTION_EXCEPTION )
				PrintException(ctx, true);
			TEST_FAILED;
		}
		ctx->Release();
 
		engine->Release();
	}

	// Default constructor and opAssign shouldn't be provided if a non-default constructor is implemented
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(CBufferedOutStream, Callback), &bout, asCALL_THISCALL);

		const char *script = 
			"class CBar \n"
			"{ \n"
			" CBar(int a) {}\n"
			"}; \n"
			"void func() \n"
			"{ \n"
			"  CBar a; \n" // not ok
			"  CBar b(1); \n" // ok
			"  CBar c = CBar(1); \n" // not ok
			"  b = b; \n" // not ok
			"  CBar d(CBar()); \n" // not ok
			"}; \n";

		asIScriptModule *mod = engine->GetModule("t", asGM_ALWAYS_CREATE);
		mod->AddScriptSection("script", script);

		bout.buffer = "";
		r = mod->Build();
		if( r >= 0 )
			TEST_FAILED;

		if( bout.buffer != "script (5, 1) : Info    : Compiling void func()\n"
						   "script (7, 8) : Error   : No default constructor for object of type 'CBar'.\n"
						   "script (9, 8) : Error   : No default constructor for object of type 'CBar'.\n"
						   "script (9, 8) : Error   : There is no copy operator for the type 'CBar' available.\n"
						   "script (10, 5) : Error   : There is no copy operator for the type 'CBar' available.\n"
						   "script (11, 10) : Error   : No matching signatures to 'CBar()'\n"
						   "script (11, 10) : Info    : Candidates are:\n"
						   "script (11, 10) : Info    : CBar@ CBar(int)\n" )
		{
			printf("%s", bout.buffer.c_str());
			TEST_FAILED;
		}
 
		engine->Release();
	}

	// Success
	return fail;
}
コード例 #21
0
ファイル: test_array.cpp プロジェクト: FrankStain/angelscript
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;
}
コード例 #22
0
bool Test()
{
	bool fail = Test2();
	int r;
	COutStream out;
	CBufferedOutStream bout;
	asIScriptContext *ctx;

 	asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
	
	engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);

	RegisterScriptString(engine);
	RegisterScriptArray(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 )
	{
		fail = true;
		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);
		fail = true;
	}
	if( ctx ) ctx->Release();

	mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
	mod->AddScriptSection(TESTNAME, script2, strlen(script2), 0);
	r = mod->Build();
	if( r < 0 )
	{
		fail = true;
		printf("%s: Failed to compile the script\n", TESTNAME);
	}

	r = ExecuteString(engine, "TestArrayException()", mod);
	if( r != asEXECUTION_EXCEPTION )
	{
		printf("%s: No exception\n", TESTNAME);
		fail = true;
	}

	// 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 )
	{
		fail = true;
		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);
		fail = true;
	}
	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 )
	{
		fail = true;
		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);
		fail = true;
	}
	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 ) fail = true;
	ctx = engine->CreateContext();
	r = ExecuteString(engine, "TestArrayInitList()", mod, ctx);
	if( r != asEXECUTION_FINISHED ) fail = true;
	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 ) fail = true;
	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(bout.buffer.c_str());
		fail = true;
	}

	// 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 ) 
		fail = true;
	r = ExecuteString(engine, "Test()", mod);
	if( r != asEXECUTION_FINISHED )
		fail = true;
		
	// 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 )
		fail = true;

	// 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 )
		fail = true;

	// 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 )
		fail = true;

	// Must support arrays of handles
	r = ExecuteString(engine, "array<array<int>@> a(1); @a[0] = @array<int>(4);");
	if( r < 0 )
		fail = true;

	// 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 )
		fail = true;
	if( bout.buffer != "ExecuteString (1, 7) : Error   : Can't instanciate template 'array' with subtype 'single'\n" )
	{
		printf(bout.buffer.c_str());
		fail = true;
	}

	engine->Release();

	// Test too large arrays
	{
		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		RegisterScriptArray(engine);

		ctx = engine->CreateContext();
		r = ExecuteString(engine, "array<int> a; a.resize(0xFFFFFFFF);", 0, ctx);
		if( r != asEXECUTION_EXCEPTION )
		{
			fail = true;
		}
		else if( strcmp(ctx->GetExceptionString(), "Too large array size") != 0 )
		{
			fail = true;
		}

		r = ExecuteString(engine, "array<int> a(0xFFFFFFFF);", 0, ctx);
		if( r != asEXECUTION_EXCEPTION )
		{
			fail = true;
		}
		else if( strcmp(ctx->GetExceptionString(), "Too large array size") != 0 )
		{
			fail = true;
		}

		ctx->Release();
		engine->Release();
	}


	// Success
	return fail;
}
コード例 #23
0
bool Test()
{
	bool fail = false;
	int r;
	asIScriptEngine *engine;
	CBufferedOutStream bout;

 	engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
	engine->ClearMessageCallback(); // Make sure this works
	engine->SetMessageCallback(asMETHOD(CBufferedOutStream,Callback), &bout, asCALL_THISCALL);

	RegisterScriptArray(engine, true);
	engine->RegisterGlobalFunction("void assert(bool)", asFUNCTION(Assert), asCALL_GENERIC);
	asIScriptFunction *func = engine->GetGlobalFunctionByDecl("void assert(bool)");
	if( func == 0 ) TEST_FAILED;
	if( std::string(func->GetDeclaration()) != "void assert(bool)" ) TEST_FAILED;


	r = engine->RegisterGlobalFunction("void func(mytype)", asFUNCTION(0), asCALL_GENERIC);
	if( r >= 0 ) TEST_FAILED;

	r = engine->RegisterGlobalFunction("void func(int &)", asFUNCTION(0), asCALL_GENERIC);
	if( !engine->GetEngineProperty(asEP_ALLOW_UNSAFE_REFERENCES) )
	{
		if( r >= 0 ) TEST_FAILED;
	}
	else
	{
		if( r < 0 ) TEST_FAILED;
	}
	
	r = engine->RegisterObjectType("mytype", 0, asOBJ_REF);
	if( r < 0 ) TEST_FAILED;

	r = engine->RegisterObjectBehaviour("mytype", asBEHAVE_CONSTRUCT, "void f(othertype)", asFUNCTION(0), asCALL_GENERIC);
	if( r >= 0 ) TEST_FAILED;

	r = engine->RegisterObjectMethod("mytype", "type opAdd(int) const", asFUNCTION(0), asCALL_GENERIC);
	if( r >= 0 ) TEST_FAILED;

	r = engine->RegisterGlobalProperty("type a", (void*)1);
	if( r >= 0 ) TEST_FAILED;

	r = engine->RegisterObjectMethod("mytype", "void method(int &)", asFUNCTION(0), asCALL_GENERIC);
	if( !engine->GetEngineProperty(asEP_ALLOW_UNSAFE_REFERENCES) )
	{
		if( r >= 0 ) TEST_FAILED;
	}
	else
	{
		if( r < 0 ) TEST_FAILED;
	}

	r = engine->RegisterObjectProperty("mytype", "type a", 0);
	if( r >= 0 ) TEST_FAILED;

	r = engine->RegisterStringFactory("type", asFUNCTION(0), asCALL_GENERIC);
	if( r >= 0 ) TEST_FAILED;

	// Verify the output messages
	if( !engine->GetEngineProperty(asEP_ALLOW_UNSAFE_REFERENCES) )
	{
		if( bout.buffer != "System function (1, 11) : Error   : Identifier 'mytype' is not a data type in global namespace\n"
			               " (0, 0) : Error   : Failed in call to function 'RegisterGlobalFunction' with 'void func(mytype)' (Code: -10)\n"
						   "System function (1, 15) : Error   : Only object types that support object handles can use &inout. Use &in or &out instead\n"
						   " (0, 0) : Error   : Failed in call to function 'RegisterGlobalFunction' with 'void func(int &)' (Code: -10)\n"
						   "System function (1, 8) : Error   : Identifier 'othertype' is not a data type in global namespace\n"
						   " (0, 0) : Error   : Failed in call to function 'RegisterObjectBehaviour' with 'mytype' and 'void f(othertype)' (Code: -10)\n"
						   "System function (1, 1) : Error   : Identifier 'type' is not a data type in global namespace\n"
						   " (0, 0) : Error   : Failed in call to function 'RegisterObjectMethod' with 'mytype' and 'type opAdd(int) const' (Code: -10)\n"
						   "Property (1, 1) : Error   : Identifier 'type' is not a data type in global namespace\n"
						   " (0, 0) : Error   : Failed in call to function 'RegisterGlobalProperty' with 'type a' (Code: -10)\n"
						   "System function (1, 17) : Error   : Only object types that support object handles can use &inout. Use &in or &out instead\n"
						   " (0, 0) : Error   : Failed in call to function 'RegisterObjectMethod' with 'mytype' and 'void method(int &)' (Code: -10)\n"
						   "Property (1, 1) : Error   : Identifier 'type' is not a data type in global namespace\n"
						   " (0, 0) : Error   : Failed in call to function 'RegisterObjectProperty' with 'mytype' and 'type a' (Code: -10)\n"
						   " (1, 1) : Error   : Identifier 'type' is not a data type in global namespace\n"
						   " (0, 0) : Error   : Failed in call to function 'RegisterStringFactory' with 'type' (Code: -12)\n" )
		{
			PRINTF("%s", bout.buffer.c_str());
			TEST_FAILED;
		}
	}
	else
	{
		if( bout.buffer != "System function (1, 11) : Error   : Identifier 'mytype' is not a data type\n"
						   "System function (1, 8) : Error   : Identifier 'othertype' is not a data type\n"
						   "System function (1, 1) : Error   : Identifier 'type' is not a data type\n"
						   "System function (1, 8) : Error   : Identifier 'type' is not a data type\n"
						   "Property (1, 1) : Error   : Identifier 'type' is not a data type\n"
						   "Property (1, 1) : Error   : Identifier 'type' is not a data type\n"
						   " (1, 1) : Error   : Identifier 'type' is not a data type\n")
			TEST_FAILED;
	}

	engine->Release();

	// Success
 	return fail;
}
コード例 #24
0
bool Test()
{
	bool fail = false;

    // Create the script engine
    asIScriptEngine *engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
 
    // Register Function
    RegisterScriptString(engine);
    engine->RegisterGlobalFunction("void Print(string &in)", asFUNCTION(PrintString_Generic), asCALL_GENERIC);
 
    // Compile
    asIScriptModule *mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
    mod->AddScriptSection("script", 
        "class Obj{};"
        "class Hoge"
        "{"
        "    Hoge(){ Print('ctor\\n'); }"
        "    ~Hoge(){ Print('dtor\\n'); }"
        "    Obj@ obj;"
        "};"
        "void main()"
        "{"
        "    Hoge hoge;"
        "};"
        , 0);
    mod->Build();
 
    // Context Create
    asIScriptContext *ctx = engine->CreateContext();
 
    // Loop
    for( asUINT n = 0; n < 3; n++ )
    {
        // Execute
        //printf("----- execute\n");
        ctx->Prepare(mod->GetFunctionIdByDecl("void main()"));
        ctx->Execute();
 
        // GC
        const int GC_STEP_COUNT_PER_FRAME = 100;
        for ( int i = 0; i < GC_STEP_COUNT_PER_FRAME; ++i )
        {
            engine->GarbageCollect(asGC_ONE_STEP);
        }
        
        // Check status
        {
            asUINT currentSize = asUINT();
            asUINT totalDestroyed = asUINT();
            asUINT totalDetected = asUINT();
            engine->GetGCStatistics(&currentSize , &totalDestroyed , &totalDetected );
			if( currentSize    != 8 ||
				totalDestroyed != n+1 ||
				totalDetected  != 0 )
				TEST_FAILED;
            //printf("(%lu,%lu,%lu)\n" , currentSize , totalDestroyed , totalDetected );
        }
    }

    // Release 
    ctx->Release();
    engine->Release();

	// Test 
	{	
		COutStream out;
		int r;

		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);
		RegisterScriptArray(engine, true);

		mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
		mod->AddScriptSection(0, 
			"interface ITest\n"
			"{\n"
			"}\n"
			"class Test : ITest\n"
			"{\n"
			"	ITest@[] arr;\n"
			"	void Set(ITest@ e)\n"
			"	{\n"
			"		arr.resize(1);\n"
			"		@arr[0]=e;\n"
			"	}\n"
			"}\n"
			"void main()\n"
			"{\n"
			"	Test@ t=Test();\n"
			"	t.Set(t);\n"
			"}\n");
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		asUINT currentSize;
		engine->GetGCStatistics(&currentSize);
		
		r = ExecuteString(engine, "main()", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		engine->GetGCStatistics(&currentSize);

		engine->Release();
	}

	// Test attempted access of global variable after it has been destroyed
	{	
		COutStream out;
		int r;

		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);
		RegisterScriptArray(engine, true);
		RegisterStdString(engine);
		engine->RegisterGlobalFunction("void Log(const string &in)", asFUNCTION(PrintString_Generic), asCALL_GENERIC);

		mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
		mod->AddScriptSection(0, 
			"class Big \n"
			"{ \n"
			"  Big() \n"
			"  { \n"
			"    Log('Big instance created\\n'); \n"
			"  } \n"
			"  ~Big() \n"
			"  { \n"
			"    Log('Big instance being destroyed\\n'); \n"
			"  } \n"
			"  void exec() \n"
			"  { \n"
			"    Log('executed\\n'); \n"
			"  } \n"
			"} \n"
			"Big big; \n" // Global object
			"class SomeClass \n"
			"{ \n"
			"  SomeClass@ handle; \n" // Make sure SomeClass is garbage collected
			"  SomeClass() {} \n"
			"  ~SomeClass() \n"
			"  { \n"
			"    Log('Before attempting access to global var\\n'); \n"
			"    big.exec(); \n" // As the module has already been destroyed, the global variable won't exist anymore, thus raising a null pointer exception here
			"    Log('SomeClass instance being destroyed\\n'); \n" // This won't be called
			"  } \n"
			"} \n"
			"void test_main() \n"
			"{ \n"
			"  SomeClass @something = @SomeClass(); \n" // Instanciate the object. It will only be destroyed by the GC
			"} \n");
		r = mod->Build();
		if( r < 0 )
			TEST_FAILED;

		r = ExecuteString(engine, "test_main()", mod);
		if( r != asEXECUTION_FINISHED )
			TEST_FAILED;

		// The global variables in the module will be destroyed first. The objects in the GC that 
		// tries to access them should throw exception, but should not cause the application to crash
		called = 0;
		engine->Release();
		if( called != 2 )
			TEST_FAILED;
	}
/*
	{
		// This test forces a memory leak due to not registering the GC behaviours for the CFoo class
		COutStream out;
		int r;

		engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
		engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);

		engine->RegisterInterface("IMyInterface"); 
		engine->RegisterObjectType("CFoo", sizeof(CFoo), asOBJ_REF); 
		engine->RegisterObjectBehaviour("CFoo", asBEHAVE_ADDREF, "void f()", asMETHOD(CFoo, AddRef), asCALL_THISCALL); 
		engine->RegisterObjectBehaviour("CFoo", asBEHAVE_RELEASE, "void f()", asMETHOD(CFoo, Release), asCALL_THISCALL); 
		engine->RegisterObjectBehaviour("CFoo", asBEHAVE_FACTORY, "CFoo@ f()", asFUNCTION(&CFoo::CreateObject), asCALL_CDECL);       
		engine->RegisterObjectMethod("CFoo", "void SetObject(IMyInterface@)", asMETHOD(CFoo, SetScriptObject), asCALL_THISCALL); 

		const char *script = 
			"CBar test; \n"
			"class CBase : IMyInterface \n"
			"{ \n"
			"  IMyInterface@ m_dummy; \n" // Comment only this and everything is ok
			"} \n"
			"class CBar : CBase \n"
			"{ \n"
			"  CBar() \n"
			"  { \n"
			"    m_foo.SetObject(this); \n" // Comment only this and everything is ok
			"  } \n"
			"  CFoo m_foo; \n"
			"}; ";

		asIScriptModule *mod = engine->GetModule("test", asGM_ALWAYS_CREATE);
		mod->AddScriptSection("test", script);
		r = mod->Build();

		engine->Release();
	}
*/
	return fail;
}
コード例 #25
0
bool Test()
{
	if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") )
	{
		printf("%s: Skipped due to AS_MAX_PORTABILITY\n", TESTNAME);
		return false;
	}
	bool fail = false;
	int r;
	COutStream out;
	asIScriptEngine *engine;
	asIScriptModule *mod;
	asIScriptContext *ctx;

 	engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);

	RegisterScriptString(engine);

	r = engine->RegisterObjectType("refclass", sizeof(CRefClass), asOBJ_REF); assert(r >= 0);
	r = engine->RegisterObjectBehaviour("refclass", asBEHAVE_FACTORY, "refclass@ f()", asFUNCTION(Factory), asCALL_CDECL); assert(r >= 0);
	r = engine->RegisterObjectBehaviour("refclass", asBEHAVE_ADDREF, "void f()", asMETHOD(CRefClass, AddRef), asCALL_THISCALL); assert(r >= 0);
	r = engine->RegisterObjectBehaviour("refclass", asBEHAVE_RELEASE, "void f()", asMETHOD(CRefClass, Release), asCALL_THISCALL); assert(r >= 0);
	r = engine->RegisterObjectMethod("refclass", "refclass &opAssign(refclass &in)", asMETHOD(CRefClass, operator=), asCALL_THISCALL); assert(r >= 0);
	r = engine->RegisterObjectMethod("refclass", "refclass &Do()", asMETHOD(CRefClass,Do), asCALL_THISCALL); assert(r >= 0);
	r = engine->RegisterObjectMethod("refclass", "refclass &opAdd(refclass &in)", asFUNCTION(CRefClass::Add), asCALL_CDECL_OBJFIRST); assert(r >= 0);

	r = engine->RegisterGlobalFunction("void Assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); assert( r >= 0 );

	mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
	mod->AddScriptSection(TESTNAME, script1, strlen(script1), 0);
	engine->SetMessageCallback(asMETHOD(COutStream,Callback), &out, asCALL_THISCALL);
	r = mod->Build();
	if( r < 0 )
	{
		TEST_FAILED;
		printf("%s: Failed to compile the script\n", TESTNAME);
	}

	ctx = engine->CreateContext();
	r = ExecuteString(engine, "TestObjHandle()", mod, ctx);
	if( r != asEXECUTION_FINISHED )
	{
		if( r == asEXECUTION_EXCEPTION )
			PrintException(ctx);

		TEST_FAILED;
		printf("%s: Execution failed\n", TESTNAME);
	}
	if( ctx ) ctx->Release();

	// Call TestObjReturnHandle() from the application to verify that references are updated as necessary
	ctx = engine->CreateContext();
	ctx->Prepare(engine->GetModule(0)->GetFunctionByDecl("refclass@ TestObjReturnHandle(refclass@)"));
	CRefClass *refclass = new CRefClass();

	ctx->SetArgObject(0, refclass);

	r = ctx->Execute();
	if( r != asEXECUTION_FINISHED )
	{
		if( r == asEXECUTION_EXCEPTION )
			PrintException(ctx);

		TEST_FAILED;
		printf("%s: Execution failed\n", TESTNAME);
	}
	if( refclass->refCount != 2 )
	{
		TEST_FAILED;
		printf("%s: Ref count is wrong\n", TESTNAME);
	}

	refclass->Release();
	if( ctx ) ctx->Release();

	// Test returning a reference to the object from an object method
	r = engine->GarbageCollect();
	asUINT gcCurrentSize;
	engine->GetGCStatistics(&gcCurrentSize, 0, 0);
	assert( gcCurrentSize == 0 ); 

	r = ExecuteString(engine, "refclass ref; ref.Do()");
	if( r != asEXECUTION_FINISHED )
	{
		TEST_FAILED;
	}

	engine->Release();

	//--------------------
	engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
	engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);
	RegisterScriptArray(engine, true);
	r = engine->RegisterGlobalFunction("void Assert(bool)", asFUNCTION(Assert), asCALL_GENERIC); assert( r >= 0 );
	mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
	mod->AddScriptSection(TESTNAME, script5, strlen(script5), 0);
	r = mod->Build();
	if( r < 0 ) TEST_FAILED;
	r = ExecuteString(engine, "Test()", mod);
	if( r != asEXECUTION_FINISHED ) TEST_FAILED;
	engine->Release();

	//----------------------
	// It should be allowed to have a global function return a handle to a const object
	engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
	engine->SetMessageCallback(asMETHOD(COutStream, Callback), &out, asCALL_THISCALL);
	const char *scriptC = "class T {} const T@ func() {return T();}";
	mod = engine->GetModule(0, asGM_ALWAYS_CREATE);
	mod->AddScriptSection("script", scriptC, strlen(scriptC));
	r = mod->Build();
	if( r < 0 ) TEST_FAILED;
	engine->Release();

	//---------------------
	// These tests are designed to make sure ambiguities with handles is avoided
	CBufferedOutStream bout;
	engine = asCreateScriptEngine(ANGELSCRIPT_VERSION);
	engine->SetMessageCallback(asMETHOD(CBufferedOutStream, Callback), &bout, asCALL_THISCALL);

	r = engine->RegisterObjectType("A", sizeof(CRefClass), asOBJ_REF); assert(r >= 0);
	r = engine->RegisterObjectBehaviour("A", asBEHAVE_FACTORY, "A@ f()", asFUNCTION(Factory), asCALL_CDECL); assert(r >= 0);
	r = engine->RegisterObjectBehaviour("A", asBEHAVE_ADDREF, "void f()", asMETHOD(CRefClass, AddRef), asCALL_THISCALL); assert(r >= 0);
	r = engine->RegisterObjectBehaviour("A", asBEHAVE_RELEASE, "void f()", asMETHOD(CRefClass, Release), asCALL_THISCALL); assert(r >= 0);
	r = engine->RegisterObjectMethod("A", "A &opAssign(const A &in)", asMETHOD(CRefClass, operator=), asCALL_THISCALL); assert(r >= 0);

	bout.buffer = "";
	r = ExecuteString(engine, "A a; a == null;");    // Should give warning
	if( r < 0 || bout.buffer == "" )
	{
		TEST_FAILED;
	}
	bout.buffer = "";
	r = ExecuteString(engine, "A a; null == a;");    // Should give warning
	if( r < 0 || bout.buffer == "" )
	{
		TEST_FAILED;
	}
	bout.buffer = "";
	r = ExecuteString(engine, "A a; @a == null;");   // OK
	if( r < 0 || bout.buffer != "" )
	{
		TEST_FAILED;
	}
	bout.buffer = "";
	r = ExecuteString(engine, "A a; null == @a;");   // OK
	if( r < 0 || bout.buffer != "" )
	{
		TEST_FAILED;
	}
	bout.buffer = "";
	r = ExecuteString(engine, "A a; @a == a;");      // Should give warning
	if( r < 0 || bout.buffer == "" )
	{
		TEST_FAILED;
	}
	bout.buffer = "";
	r = ExecuteString(engine, "A a; a == @a;");      // Should give warning
	if( r < 0 || bout.buffer == "" )
	{
		TEST_FAILED;
	}
	bout.buffer = "";
	r = ExecuteString(engine, "A a; @a == @a;");     // OK
	if( r < 0 || bout.buffer != "" )
	{
		TEST_FAILED;
	}
	bout.buffer = "";
	r = ExecuteString(engine, "A @a = null;");       // OK
	if( r < 0 || bout.buffer != "" )
	{
		TEST_FAILED;
	}
	bout.buffer = "";
	r = ExecuteString(engine, "A a; A @b = a;");     // OK
	if( r < 0 || bout.buffer != "" )
	{
		TEST_FAILED;
	}
	bout.buffer = "";
	r = ExecuteString(engine, "A a; A @b = @a;");    // OK
	if( r < 0 || bout.buffer != "" )
	{
		TEST_FAILED;
	}
	bout.buffer = "";
	r = ExecuteString(engine, "A a; A b = @b;");     // Should give error
	if( r >= 0 || bout.buffer == "" )
	{
		TEST_FAILED;
	}
	bout.buffer = "";
	r = ExecuteString(engine, "A @a, b; @a = @b;");  // OK
	if( r < 0 || bout.buffer != "" )
	{
		TEST_FAILED;
	}
	bout.buffer = "";
	r = ExecuteString(engine, "A @a, b; @a = b;");   // OK
	if( r < 0 || bout.buffer != "" )
	{
		TEST_FAILED;
	}
	bout.buffer = "";
	r = ExecuteString(engine, "A @a, b; a = @b;");   // Should give error
	if( r >= 0 || bout.buffer == "" )
	{
		TEST_FAILED;
	}

	bout.buffer = "";
	r = ExecuteString(engine, "A a; null is a;");    // OK
	if( r < 0 || bout.buffer != "" )
	{
		TEST_FAILED;
	}
	bout.buffer = "";
	r = ExecuteString(engine, "A a; a !is null;");    // OK
	if( r < 0 || bout.buffer != "" )
	{
		TEST_FAILED;
	}

	engine->Release();

	// Success
	return fail;
}