/** @file functor_unittest.cpp
 *  Functionality for testing our functor types
 *	@author Nick Beatty (nbeatty@ea.com)
 *
 *	EABaseTypes
 *	(c) 2011 Electronic Arts Inc. 
 */

#if EA_RUNTIME_TESTING

#include "EABaseTypes/factory.h"
#include "EABaseTypes/datatypes.h"
#include "EABaseTypes/functor.h"
#include "EABaseTypes/closure.h"
#include "EABaseTypes/functioncallwrappers.h"
#include "EABaseTypes/structencoder.h"
#include "EABaseTypes/poduserdata.h"
#include "EABaseTypes/safecomuserdata.h"

#include "unit/unit.h"
#include "coreunit/interface.h"
#include "coreallocator/icoreallocatormacros.h"

#include "ppmalloc/eageneralallocator.h"
#include "ppmalloc/eageneralallocatordebug.h"
#include "coreunit/interface.h"

class MyUserData : public EA::Types::UserData
{
public:

	MyUserData(EA::Types::Factory* factory,
			   bool b,
			   const char* s,
			   int i,
			   float f):EA::Types::UserData(factory),
		mBool(b),
		mStr(factory, s),
		mInt(i),
		mFloat(f)
	{
	}
	
	virtual bool Equals(EA::Types::UserDataIn pCompare)
	{
		if(EA::Type::TypeOf(*this) == pCompare->GetUserDataType())
		{
			MyUserData* compare = static_cast<MyUserData*>(pCompare.GetUnsafePointer());
			return mBool = compare->mBool && mStr == compare->mStr && mInt == compare->mInt && mFloat == compare->mFloat;
		}
		else
		{
			return false;
		}
	}

	virtual EA::Types::BaseTypeReturn Clone() { return new (mFactory) MyUserData(mFactory, mBool, mStr.c_str(), mInt, mFloat); }

	virtual EA::Type::TypeID GetUserDataType() { return EA::Type::TypeOf(*this); }

	bool			mBool;
	EA::String	    mStr;
	int				mInt;
	float			mFloat;
};

struct TestStruct1;

class FunctorUnitTests : public EATest::TestSuite
{
	public:

		FunctorUnitTests()
		{
		}

		virtual void Initialize()
		{
			SuiteName("FunctorUnitTests");
			EATEST_REGISTER("TestFunctor", "Testing No Parameter Functor", FunctorUnitTests, TestFunctor);
			EATEST_REGISTER("TestFunctor1", "Testing 1 Parameter Functor", FunctorUnitTests, TestFunctor1);
			EATEST_REGISTER("TestFunctor2", "Testing 2 Parameter Functor", FunctorUnitTests, TestFunctor2);
			EATEST_REGISTER("TestFunctor3", "Testing 3 Parameter Functor", FunctorUnitTests, TestFunctor3);
			EATEST_REGISTER("TestFunctor4", "Testing 4 Parameter Functor", FunctorUnitTests, TestFunctor4);
			EATEST_REGISTER("TestFunctor5", "Testing 5 Parameter Functor", FunctorUnitTests, TestFunctor5);
			EATEST_REGISTER("TestFunctor6", "Testing 6 Parameter Functor", FunctorUnitTests, TestFunctor6);
		}

		void Setup(void* data)
		{
			CoreUnit::UnitTestInfo* info = static_cast<CoreUnit::UnitTestInfo*>(data);
			EA::Allocator::ICoreAllocator* allocator = info->mAllocator;

			mAllocator = allocator;

			mFactory = EA::Types::CreateDefaultFactory(allocator);
            
            mClosureFunction = EA::Types::ClosureAsFunction(mFactory);
		}

		void Teardown(void* data)
		{
			// must null this now as we are deleting the factory!
			mClosureFunction = NULL;

			CORE_DELETE(mAllocator, mFactory);
		}

		void TestFunctor(void* data);
		void TestFunctor1(void* data);
		void TestFunctor2(void* data);
		void TestFunctor3(void* data);
		void TestFunctor4(void* data);
		void TestFunctor5(void* data);
		void TestFunctor6(void* data);

		static void sMyFunctor();
		void MyFunctor();

		static EA::Types::BaseTypeReturn sMyFunctorA(EA::Types::ArrayIn p);
		EA::Types::BaseTypeReturn MyFunctorA(EA::Types::ArrayIn p);

		static bool sMyFunctorB();
		bool MyFunctorB();

		static void sMyFunctor1(int i);
		void MyFunctor1(int i);

		static int sMyFunctor1I(int i);
		int MyFunctor1I(int i);
        
        static EA::SafeCom::IUnknownReturn sMyFunctor1U(EA::SafeCom::IUnknownIn unknown);
        EA::SafeCom::IUnknownReturn MyFunctor1U(EA::SafeCom::IUnknownIn unknown);

		static void sMyFunctor2(float f, bool b);
		void MyFunctor2(float f, bool b);

		static float sMyFunctor2F(float f, bool b);
		float MyFunctor2F(float f, bool b);
        
        static int* sMyFunctor2IP(int *ip, int i);
        int* MyFunctor2IP(int *ip, int i);

		static void sMyFunctor3(EA::Types::NumberIn i, EA::Types::NumberIn f, EA::Types::BooleanIn b);
		void MyFunctor3(EA::Types::NumberIn i, EA::Types::NumberIn f, EA::Types::BooleanIn b);

		static EA::Types::ArrayReturn sMyFunctor3A(EA::Types::NumberIn i, EA::Types::NumberIn f, EA::Types::BooleanIn b);
		EA::Types::ArrayReturn MyFunctor3A(EA::Types::NumberIn i, EA::Types::NumberIn f, EA::Types::BooleanIn b);

		static void sMyFunctor4(EA::Types::ObjectIn o, EA::Types::ArrayIn a, EA::Types::FunctionIn f, EA::Types::StringIn s);
		void MyFunctor4(EA::Types::ObjectIn o, EA::Types::ArrayIn a, EA::Types::FunctionIn f, EA::Types::StringIn s);

		static EA::Types::ObjectReturn sMyFunctor4O(EA::Types::ObjectIn o, EA::Types::ArrayIn a, EA::Types::FunctionIn f, EA::Types::StringIn s);
		EA::Types::ObjectReturn MyFunctor4O(EA::Types::ObjectIn o, EA::Types::ArrayIn a, EA::Types::FunctionIn f, EA::Types::StringIn s);

		static void sMyFunctor5(EA::String s, const EA::String& sCRef, const EA::String& sRef, int i, const TestStruct1& structure);
		void MyFunctor5(EA::String s, const EA::String& sCRef, const EA::String& sRef, int i, const TestStruct1& structure);

		static EA::String sMyFunctor5S(EA::String s, const EA::String& sCRef, const EA::String& sRef, int i, const TestStruct1& structure);
		EA::String MyFunctor5S(EA::String s, const EA::String& sCRef, const EA::String& sRef, int i, const TestStruct1& structure);

		static void sMyFunctor5U(EA::String s, const EA::String& sCRef, const EA::String& sRef, int i, EA::Types::UserDataIn userData);
		void MyFunctor5U(EA::String s, const EA::String& sCRef, const EA::String& sRef, int i, EA::Types::UserDataIn userData);
		
		static EA::Types::ConstStringReturn sMyFunctor6C(EA::Types::ConstBooleanIn, EA::Types::ConstNumberIn, EA::Types::ConstArrayIn, EA::Types::ConstObjectIn, EA::Types::ConstFunctionIn, EA::Types::ConstUserDataIn);
		EA::Types::ConstStringReturn MyFunctor6C(EA::Types::ConstBooleanIn, EA::Types::ConstNumberIn, EA::Types::ConstArrayIn, EA::Types::ConstObjectIn, EA::Types::ConstFunctionIn, EA::Types::ConstUserDataIn);

		void cb();
        
        EA::Types::Factory* GetFactory() { return mFactory; }
        
private:

		EA::Allocator::ICoreAllocator*	mAllocator;
		EA::Types::Factory*				mFactory;
        EA::Types::FunctionRef          mClosureFunction;
};  

// make the unit test suite instance
FunctorUnitTests FunctorUnitTestsInstance;

// this declaration is so that main.cpp in the game can pretend to use it hence keeping
// this entire translation unit from being excluded from the build
EATest::TestSuite* gFunctorUnitTests = &FunctorUnitTestsInstance;

struct TestStruct1
{
    TestStruct1():
        mBool(false),
        mStr(FunctorUnitTestsInstance.GetFactory()),
        mInt(0),
        mFloat(0) {}
        
	bool			mBool;
	EA::String	    mStr;
	int				mInt;
	float			mFloat;
};

EABASETYPES_STRUCT_BEGIN(TestStruct1)
EABASETYPES_STRUCT_MEMBER(TestStruct1, bool, mBool)
EABASETYPES_STRUCT_MEMBER(TestStruct1, EA::String, mStr)
EABASETYPES_STRUCT_MEMBER(TestStruct1, int, mInt)
EABASETYPES_STRUCT_MEMBER(TestStruct1, float, mFloat)
EABASETYPES_STRUCT_END(TestStruct1)

// *********************************************************************************************
// The test functions
// *********************************************************************************************

void FunctorUnitTests::TestFunctor(void* data)
{
	EA::Types::FunctionRef func = mFactory->Function(sMyFunctor);
	EA::Types::FunctionRef memFunc = mFactory->Function(this, &FunctorUnitTests::MyFunctor);

	func->Call(EA::Types::ArrayIn(NULL));
	memFunc->Call(EA::Types::ArrayIn(NULL));

	EA::Types::FunctionRef funcB = mFactory->Function(sMyFunctorB);
	EA::Types::FunctionRef memFuncB = mFactory->Function(this, &FunctorUnitTests::MyFunctorB);

	EATESTAssert(funcB->Call<bool>() == true, "");
	EATESTAssert(memFuncB->Call<bool>() == true, "");
    
    EA::Types::FunctionRef memFuncBC = mClosureFunction->Call<EA::Types::FunctionReturn>(funcB);
    
    EATESTAssert(memFuncBC->Call<bool>() == true, "");

	EA::Types::ArrayRef p = mFactory->Array();
	p->push_back(1);
	p->push_back(2);
	p->push_back(3);

	EA::Types::FunctionRef funcA = mFactory->Function(sMyFunctorA);
	EA::Types::FunctionRef memFuncA = mFactory->Function(this, &FunctorUnitTests::MyFunctorA);

	EA::Types::BaseTypeRef r = funcA->Call<EA::Types::BaseTypeReturn>(p);
	EATESTAssert(r->GetType() == EA::Types::ARRAY_TYPE && r->AsArray()->size() == 3, "");
	
	r = memFuncA->Call<EA::Types::BaseTypeReturn>(p);
	EATESTAssert(r->GetType() == EA::Types::ARRAY_TYPE && r->AsArray()->size() == 3, "");

	EA::Types::ArrayRef params = mFactory->Array();
	params->push_back(p);

	r = funcA->Call(params);
	EATESTAssert(r->GetType() == EA::Types::ARRAY_TYPE && r->AsArray()->size() == 3, "");

	r = memFuncA->Call(params);
	EATESTAssert(r->GetType() == EA::Types::ARRAY_TYPE && r->AsArray()->size() == 3, "");
    
    EA::Types::FunctionRef memFuncAC = mClosureFunction->Call<EA::Types::FunctionReturn>(memFuncA);
    
    r = memFuncAC->Call<EA::Types::BaseTypeReturn>(p);
	EATESTAssert(r->GetType() == EA::Types::ARRAY_TYPE && r->AsArray()->size() == 3, "");
    
    r = memFuncAC->Call(params);
	EATESTAssert(r->GetType() == EA::Types::ARRAY_TYPE && r->AsArray()->size() == 3, "");
    
    memFuncAC = mClosureFunction->Call<EA::Types::FunctionReturn>(memFuncA, p);
    
    r = memFuncAC->Call<EA::Types::BaseTypeReturn>();
	EATESTAssert(r->GetType() == EA::Types::ARRAY_TYPE && r->AsArray()->size() == 3, "");
}

void FunctorUnitTests::TestFunctor1(void* data)
{
	EA::Types::FunctionRef func = mFactory->Function(sMyFunctor1);
	EA::Types::FunctionRef memFunc = mFactory->Function(this, &FunctorUnitTests::MyFunctor1);

	EA::Types::ArrayRef params = mFactory->Array();
	params->push_back(10);

	func->Call(params);
	memFunc->Call(params);

	EA::Types::FunctionRef funcI = mFactory->Function(sMyFunctor1I);
	EA::Types::FunctionRef memFuncI = mFactory->Function(this, &FunctorUnitTests::MyFunctor1I);

	int r = funcI->Call<int>(10);
	EATESTAssert(r == 10, "");

	r = memFuncI->Call<int>(10);
	EATESTAssert(r == 10, "");
    
    EA::Types::FunctionRef funcU = mFactory->Function(sMyFunctor1U);
    EA::Types::FunctionRef memFuncU = mFactory->Function(this, &FunctorUnitTests::MyFunctor1U);
    
    EA::SafeCom::IUnknownRef unknown = EA::SafeCom::Null;
    
    EA::SafeCom::IUnknownRef result = funcU->Call<EA::SafeCom::IUnknownReturn>(unknown);
    
    EATESTAssert(result == unknown, "");
    
    result = memFuncU->Call<EA::SafeCom::IUnknownReturn>(unknown);
    
    EATESTAssert(result == unknown, "");
    
    params = mFactory->Array();
    
    params->push_back(unknown);
    
    result = funcU->Call(params)->As<EA::SafeCom::IUnknownRef>();
    
    EATESTAssert(result == unknown, "");
    
    result = memFuncU->Call(params)->As<EA::SafeCom::IUnknownRef>();
    
    EATESTAssert(result == unknown, "");
}

void FunctorUnitTests::TestFunctor2(void* data)
{
	EA::Types::FunctionRef func = mFactory->Function(sMyFunctor2);
	EA::Types::FunctionRef memFunc = mFactory->Function(this, &FunctorUnitTests::MyFunctor2);

	EA::Types::ArrayRef params = mFactory->Array();
	params->push_back(1.0f);
	params->push_back(true);

	func->Call(params);
	memFunc->Call(params);

	EA::Types::FunctionRef funcF = mFactory->Function(sMyFunctor2F);
	EA::Types::FunctionRef memFuncF = mFactory->Function(this, &FunctorUnitTests::MyFunctor2F);

	float r = funcF->Call<float>(1.0f, true);
	EATESTAssert(r == 1.0f, "");

	r = memFuncF->Call<float>(1.0f, true);
	EATESTAssert(r == 1.0f, "");
    
    EA::Types::FunctionRef funcIP = mFactory->Function(sMyFunctor2IP);
    EA::Types::FunctionRef memFuncIP = mFactory->Function(this, &FunctorUnitTests::MyFunctor2IP);
    
    int i = 0;
    
    int *ip = funcIP->Call<int*>(&i, 1);
    EATESTAssert(i == 1, "");
    EATESTAssert(ip == &i, "");
    
    i = 0;
    
    ip = memFuncIP->Call<int*>(&i, 1);
    EATESTAssert(i == 1, "");
    EATESTAssert(ip == &i, "");
    
    params = mFactory->Array();
    params->push_back(&i);
    params->push_back(1);
    
    i = 0;
    
    ip = funcIP->Call(params)->As<int*>();
    
    EATESTAssert(i == 1, "");
    EATESTAssert(ip == &i, "");
    
    i = 0;
    
    ip = memFuncIP->Call(params)->As<int*>();
    
    EATESTAssert(i == 1, "");
    EATESTAssert(ip == &i, "");
    
    EA::Types::FunctionRef memFuncIPC = mClosureFunction->Call<EA::Types::FunctionReturn>(memFuncIP);
    
    i = 0;
    
    ip = memFuncIPC->Call<int*>(&i, 1);
    
    EATESTAssert(i == 1, "");
    EATESTAssert(ip == &i, "");
    
    memFuncIPC = mClosureFunction->Call<EA::Types::FunctionReturn>(memFuncIP, &i);
    
    i = 0;
    
    ip = memFuncIPC->Call<int*>(1);
    
    EATESTAssert(i == 1, "");
    EATESTAssert(ip == &i, "");
    
    memFuncIPC = mClosureFunction->Call<EA::Types::FunctionReturn>(memFuncIP, &i, 1);
    
    i = 0;
    
    ip = memFuncIPC->Call<int*>();
    
    EATESTAssert(i == 1, "");
    EATESTAssert(ip == &i, "");
}

void FunctorUnitTests::TestFunctor3(void* data)
{
	EA::Types::FunctionRef func = mFactory->Function(sMyFunctor3);

	EA::Types::FunctionRef memFunc = mFactory->Function(this, &FunctorUnitTests::MyFunctor3);

	EA::Types::ArrayRef params = mFactory->Array();
	params->push_back(100);
	params->push_back(5.6f);
	params->push_back(true);

	func->Call(params);
	memFunc->Call(params);

	EA::Types::FunctionRef funcA = mFactory->Function(sMyFunctor3A);
	EA::Types::FunctionRef memFuncA = mFactory->Function(this, &FunctorUnitTests::MyFunctor3A);

	EA::Types::ArrayRef r = funcA->Call<EA::Types::ArrayReturn>(100, 5.6f, true);

	EATESTAssert((*r)[0]->AsInt() == 100, "");
	EATESTAssert((*r)[1]->AsFloat() == 5.6f, "");
	EATESTAssert((*r)[2]->AsBool() == true, "");

	r = memFuncA->Call<EA::Types::ArrayReturn>(100, 5.6f, true);

	EATESTAssert((*r)[0]->AsInt() == 100, "");
	EATESTAssert((*r)[1]->AsFloat() == 5.6f, "");
	EATESTAssert((*r)[2]->AsBool() == true, "");
}

struct TestStruct2
{
	int	key1;
	int	key2;
	int	key3;
};

EABASETYPES_STRUCT_BEGIN(TestStruct2)
EABASETYPES_STRUCT_MEMBER(TestStruct2, int, key1)
EABASETYPES_STRUCT_MEMBER(TestStruct2, int, key2)
EABASETYPES_STRUCT_MEMBER(TestStruct2, int, key3)
EABASETYPES_STRUCT_END(TestStruct2)

void FunctorUnitTests::TestFunctor4(void* data)
{
	EA::Types::FunctionRef func = mFactory->Function(sMyFunctor4);
	
	EA::Types::FunctionRef memFunc = mFactory->Function(this, &FunctorUnitTests::MyFunctor4);

	EA::Types::ArrayRef params = mFactory->Array();
	EA::Types::ObjectRef obj = params->push_backObject();
	obj->insert("key1", 1);
	obj->insert("key2", 2);
	obj->insert("key3", 3);

	EA::Types::ArrayRef arr = mFactory->Array();
	arr->push_back(1);
	arr->push_back(2);
	arr->push_back(3);
	params->push_back(arr);

	EA::Types::FunctionRef cb = mFactory->Function(this, &FunctorUnitTests::cb);
	
	params->push_back(cb);
	params->push_back("FOO");

	func->Call(params);
	memFunc->Call(params);

	EA::Types::FunctionRef funcO = mFactory->Function(sMyFunctor4O);
	EA::Types::FunctionRef memFuncO = mFactory->Function(this, &FunctorUnitTests::MyFunctor4O);

	EA::Types::BaseTypeRef r = funcO->Call(params);
	EATESTAssert(r->GetType() == EA::Types::OBJECT_TYPE, "");

	EA::Types::ObjectRef rObj = r->AsObject();
	EATESTAssert((*rObj)["key1"]->AsInt() == 1, "");
	EATESTAssert((*rObj)["key2"]->AsInt() == 2, "");
	EATESTAssert((*rObj)["key3"]->AsInt() == 3, "");

	TestStruct2 structure;
	structure.key1 = 1;
	structure.key2 = 2;
	structure.key3 = 3;

	r = 
		memFuncO->Call<EA::Types::ObjectReturn>(
			structure,
			arr,
			cb,
			"FOO");

	EATESTAssert(r->GetType() == EA::Types::OBJECT_TYPE, "");

	rObj = r->AsObject();
	EATESTAssert((*rObj)["key1"]->AsInt() == 1, "");
	EATESTAssert((*rObj)["key2"]->AsInt() == 2, "");
	EATESTAssert((*rObj)["key3"]->AsInt() == 3, "");
}

void FunctorUnitTests::TestFunctor5(void* data)
{
	EA::Types::FunctionRef func = mFactory->Function(sMyFunctor5);
	
	EA::Types::FunctionRef memFunc = mFactory->Function(this, &FunctorUnitTests::MyFunctor5);

	EA::Types::ArrayRef params = mFactory->Array();

	params->push_back("Hello");
	params->push_back("World");
	params->push_back("!!!");
	params->push_back(3);
	
	EA::Types::ObjectRef object = mFactory->Object();
	object->insert("mBool", true);
	object->insert("mStr", "foo");
	object->insert("mInt", 10);
	object->insert("mFloat", 2.0);

	params->push_back(object);

	func->Call(params);
	memFunc->Call(params);

	EA::Types::FunctionRef funcS = mFactory->Function(sMyFunctor5S);
	EA::Types::FunctionRef memFuncS = mFactory->Function(this, &FunctorUnitTests::MyFunctor5S);

	EA::String hello(mFactory, "Hello");
	EA::String world(mFactory, "World");
	EA::String eMarks(mFactory, "!!!");

	TestStruct1 structure;
	structure.mBool = true;
	structure.mStr = "foo";
	structure.mInt = 10;
	structure.mFloat = 2.0;

	EA::String r = funcS->Call<EA::String>(hello, world, eMarks, 3, structure);
	EATESTAssert(r == world, "");

	r = memFuncS->Call<EA::String>(hello, world, eMarks, 3, structure);
	EATESTAssert(r == world, "");

	EA::Types::UserDataRef userData = new (mFactory) MyUserData(mFactory, true, "foo", 10, 2.0);

	EA::Types::FunctionRef funcU = mFactory->Function(sMyFunctor5U);
	EA::Types::FunctionRef memFuncU = mFactory->Function(this, &FunctorUnitTests::MyFunctor5U);

	funcU->Call<void, const EA::String&, const EA::String&, const EA::String&>(hello, world, eMarks, 3, userData);
	EATESTAssert(r == world, "");

	memFuncU->Call<void, const char*, const EA::String&, const EA::String&>(hello.c_str(), world, eMarks, 3, userData);
	EATESTAssert(r == world, "");
}

void FunctorUnitTests::TestFunctor6(void* data)
{
	// just a compile test right now
	EA::Types::ConstBooleanRef b = mFactory->Boolean(true);
	EA::Types::ConstNumberRef n = mFactory->Number(0);
	EA::Types::ConstArrayRef a = mFactory->Array();
	EA::Types::ConstObjectRef o = mFactory->Object();
	EA::Types::ConstFunctionRef f = mFactory->Function(this, &FunctorUnitTests::cb);
	EA::Types::ConstUserDataRef u = new (mFactory) MyUserData(mFactory, true, "foo", 10, 2.0);
	
	EA::Types::FunctionRef func = mFactory->Function(&FunctorUnitTests::sMyFunctor6C);
	
	EA::Types::ConstStringRef s = func->Call<EA::Types::ConstStringReturn>(b, n, a, o, f, u);
	
	func = mFactory->Function(this, &FunctorUnitTests::MyFunctor6C);
	
	s = func->Call<EA::Types::ConstStringReturn>(b, n, a, o, f, u);
}

void FunctorUnitTests::sMyFunctor()
{
	FunctorUnitTestsInstance.MyFunctor();
}

void FunctorUnitTests::MyFunctor()
{
}

EA::Types::BaseTypeReturn FunctorUnitTests::sMyFunctorA(EA::Types::ArrayIn p)
{
	return FunctorUnitTestsInstance.MyFunctorA(p);
}

EA::Types::BaseTypeReturn FunctorUnitTests::MyFunctorA(EA::Types::ArrayIn p)
{
	return p;
}

bool FunctorUnitTests::sMyFunctorB()
{
	return FunctorUnitTestsInstance.MyFunctorB();
}

bool FunctorUnitTests::MyFunctorB()
{
	return true;
}

void FunctorUnitTests::sMyFunctor1(int i)
{
	FunctorUnitTestsInstance.MyFunctor1(i);
}

void FunctorUnitTests::MyFunctor1(int i)
{
	EATESTAssert(i == 10, "");
}

int FunctorUnitTests::sMyFunctor1I(int i)
{
	return FunctorUnitTestsInstance.MyFunctor1I(i);
}

int FunctorUnitTests::MyFunctor1I(int i)
{
	MyFunctor1(i);

	return i;
}

EA::SafeCom::IUnknownReturn FunctorUnitTests::sMyFunctor1U(EA::SafeCom::IUnknownIn unknown)
{
    return FunctorUnitTestsInstance.MyFunctor1U(unknown);
}

EA::SafeCom::IUnknownReturn FunctorUnitTests::MyFunctor1U(EA::SafeCom::IUnknownIn unknown)
{
    return unknown;
}

void FunctorUnitTests::sMyFunctor2(float f, bool b)
{
	FunctorUnitTestsInstance.MyFunctor2(f, b);
}

void FunctorUnitTests::MyFunctor2(float f, bool b)
{
	EATESTAssert(f == 1.0f, "");
	EATESTAssert(b == true, "");
}

float FunctorUnitTests::sMyFunctor2F(float f, bool b)
{
	return FunctorUnitTestsInstance.MyFunctor2F(f, b);
}

float FunctorUnitTests::MyFunctor2F(float f, bool b)
{
	MyFunctor2(f, b);

	return f;
}

int* FunctorUnitTests::sMyFunctor2IP(int *ip, int i)
{
    return FunctorUnitTestsInstance.MyFunctor2IP(ip, i);
}

int* FunctorUnitTests::MyFunctor2IP(int *ip, int i)
{
    *ip = i;
    return ip;
}

void FunctorUnitTests::sMyFunctor3(EA::Types::NumberIn i, EA::Types::NumberIn f, EA::Types::BooleanIn b)
{
	FunctorUnitTestsInstance.MyFunctor3(i, f, b);
}

void FunctorUnitTests::MyFunctor3(EA::Types::NumberIn i, EA::Types::NumberIn f, EA::Types::BooleanIn b)
{
	EATESTAssert(i->AsInt() == 100, "");
	EATESTAssert(f->AsFloat() == 5.6f, "");
	EATESTAssert(b->AsBool() == true, "");
}

EA::Types::ArrayReturn FunctorUnitTests::sMyFunctor3A(EA::Types::NumberIn i, EA::Types::NumberIn f, EA::Types::BooleanIn b)
{
	return FunctorUnitTestsInstance.MyFunctor3A(i, f, b);
}

EA::Types::ArrayReturn FunctorUnitTests::MyFunctor3A(EA::Types::NumberIn i, EA::Types::NumberIn f, EA::Types::BooleanIn b)
{
	MyFunctor3(i, f, b);

	EA::Types::ArrayRef r = mFactory->Array();
	r->push_back(i);
	r->push_back(f);
	r->push_back(b);

	return r;
}

void FunctorUnitTests::sMyFunctor4(EA::Types::ObjectIn o, EA::Types::ArrayIn a, EA::Types::FunctionIn f, EA::Types::StringIn s)
{
	FunctorUnitTestsInstance.MyFunctor4(o, a, f, s);
}

void FunctorUnitTests::MyFunctor4(EA::Types::ObjectIn o, EA::Types::ArrayIn a, EA::Types::FunctionIn f, EA::Types::StringIn s)
{
	EA::Types::Object* n = NULL;
	EATESTAssert(NULL != o, "");
	EATESTAssert(o != NULL, "");
	EATESTAssert(n != o, "");
	EATESTAssert(o != n, "");

	EATESTAssert(o->contains("key1"), "");
	EATESTAssert(o->contains("key2"), "");
	EATESTAssert(o->contains("key3"), "");
	EATESTAssert(a->size() == 3, "");
	EATESTAssert(s->AsEAString() == "FOO", "");
	f->Call(EA::Types::ArrayIn(NULL));
}

EA::Types::ObjectReturn FunctorUnitTests::sMyFunctor4O(EA::Types::ObjectIn o, EA::Types::ArrayIn a, EA::Types::FunctionIn f, EA::Types::StringIn s)
{
	return FunctorUnitTestsInstance.MyFunctor4O(o, a, f, s);
}

EA::Types::ObjectReturn FunctorUnitTests::MyFunctor4O(EA::Types::ObjectIn o, EA::Types::ArrayIn a, EA::Types::FunctionIn f, EA::Types::StringIn s)
{
	MyFunctor4(o, a, f, s);

	return o;
}

void FunctorUnitTests::sMyFunctor5(EA::String s, const EA::String& sCRef, const EA::String& sRef, int i, const TestStruct1& structure)
{
	FunctorUnitTestsInstance.MyFunctor5(s, sCRef, sRef, i, structure);
}

void FunctorUnitTests::MyFunctor5(EA::String s, const EA::String& sCRef, const EA::String& sRef, int i, const TestStruct1& structure)
{
	EATESTAssert(s == "Hello", "");
	EATESTAssert(sCRef == "World", "");
	EATESTAssert(sRef == "!!!", "");
	EATESTAssert(i == 3, "");
	EATESTAssert(structure.mBool == true, "");
	EATESTAssert(structure.mStr == "foo", "");
	EATESTAssert(structure.mInt == 10, "");
	EATESTAssert(structure.mFloat == 2.0, "");
}

EA::String FunctorUnitTests::sMyFunctor5S(EA::String s, const EA::String& sCRef, const EA::String& sRef, int i, const TestStruct1& structure)
{
	return FunctorUnitTestsInstance.MyFunctor5S(s, sCRef, sRef, i, structure);
}

EA::String FunctorUnitTests::MyFunctor5S(EA::String s, const EA::String& sCRef, const EA::String& sRef, int i, const TestStruct1& structure)
{
	MyFunctor5(s, sCRef, sRef, i, structure);
	return sCRef;
}

void FunctorUnitTests::sMyFunctor5U(EA::String s, const EA::String& sCRef, const EA::String& sRef, int i, EA::Types::UserDataIn userData)
{
	FunctorUnitTestsInstance.MyFunctor5U(s, sCRef, sRef, i, userData);
}

void FunctorUnitTests::MyFunctor5U(EA::String s, const EA::String& sCRef, const EA::String& sRef, int i, EA::Types::UserDataIn userData)
{
	MyUserData* u = static_cast<MyUserData*>(userData.GetUnsafePointer());

	EATESTAssert(s == "Hello", "");
	EATESTAssert(sCRef == "World", "");
	EATESTAssert(sRef == "!!!", "");
	EATESTAssert(i == 3, "");
	EATESTAssert(u->mBool == true, "");
	EATESTAssert(u->mStr == "foo", "");
	EATESTAssert(u->mInt == 10, "");
	EATESTAssert(u->mFloat == 2.0, "");
}

EA::Types::ConstStringReturn FunctorUnitTests::sMyFunctor6C(EA::Types::ConstBooleanIn, EA::Types::ConstNumberIn, EA::Types::ConstArrayIn, EA::Types::ConstObjectIn, EA::Types::ConstFunctionIn, EA::Types::ConstUserDataIn)
{
	// this is just a compile test right now
	return FunctorUnitTestsInstance.mFactory->String();
}

EA::Types::ConstStringReturn FunctorUnitTests::MyFunctor6C(EA::Types::ConstBooleanIn, EA::Types::ConstNumberIn, EA::Types::ConstArrayIn, EA::Types::ConstObjectIn, EA::Types::ConstFunctionIn, EA::Types::ConstUserDataIn)
{
	// this is just a compile test right now
	return mFactory->String();
}

void FunctorUnitTests::cb( )
{
}

#endif
