#include <scpp_os.hpp>
#include <scpp_dl.hpp>
#include <scpp_unittest.hpp>

using namespace scpp;


/***
 * DynamicLinkingLoader 単体テスト.
 */
class DynamicLinkingLoaderTest : public TestCase
{
	public:
		DynamicLinkingLoaderTest() {}
		~DynamicLinkingLoaderTest() {}

		void testLoadAndRun()
		{
			DynamicLinkingLoader loader;
#if (SCPP_IS_WINDOWS)
			bool ret = loader.open("kernel32.dll");
			if (!ret)
			{
				Assertion::fail();
			}
			DWORD (*GetTickCount)() = reinterpret_cast<DWORD (*)()>(loader.sym("GetTickCount"));
			DWORD ret1 = GetTickCount();
			DWORD ret2 = GetTickCount();
			Assertion::assertTrue(ret2 >= ret1);

#else
			bool ret = loader.open("libm.so.6");
			if (!ret)
			{
				Assertion::fail();
			}
			double (*pow)(double, double) = reinterpret_cast<double (*)(double, double)>(loader.sym("pow"));
			double res = pow(5, 2);
			double exp = 25;
			Assertion::assertEquals(exp, res);
#endif
		}

		void testLoadAndRunInvalidFunc()
		{
			DynamicLinkingLoader loader;
#if (SCPP_IS_WINDOWS)
			bool ret = loader.open("kernel32.dll");
			if (!ret)
			{
				Assertion::fail();
			}
			dl_func_t func = loader.sym("XXXXXXXXXXXXXXXXXXXXX");
			if (func != 0)
			{
				Assertion::fail();
			}

#else
			bool ret = loader.open("libm.so.6");
			if (!ret)
			{
				Assertion::fail();
			}
			dl_func_t func = loader.sym("XXXXXXXXXXXXXXXXXXXXX");
			if (func != 0)
			{
				Assertion::fail();
			}
#endif
		}


		void testInvalidLoadNoLibrary()
		{
			DynamicLinkingLoader loader;
#if (SCPP_IS_WINDOWS)
			bool ret = loader.open("XXXXXkernel32.dll");
			if (ret)
			{
				Assertion::fail();
			}

#else
			bool ret = loader.open("XXXXXlibm.so.6");
			if (ret)
			{
				Assertion::fail();
			}
#endif
		}


		void testDupLoad()
		{
			DynamicLinkingLoader loader;
#if (SCPP_IS_WINDOWS)
			bool ret = loader.open("kernel32.dll");
			if (!ret) {
				Assertion::fail();
			}
			// 二重にロード
			ret = loader.open("kernel32.dll");
			if (ret)
			{
				Assertion::fail();
			}

#else
			bool ret = loader.open("libm.so.6");
			if (!ret)
			{
				Assertion::fail();
			}
			// 二重にロード
			ret = loader.open("libm.so.6");
			if (ret)
			{
				Assertion::fail();
			}
#endif
		}


		void testNoLoadAndSym()
		{
			DynamicLinkingLoader loader;
#if (SCPP_IS_WINDOWS)
			DWORD (*GetTickCount)() = reinterpret_cast<DWORD (*)()>(loader.sym("GetTickCount"));
			if (GetTickCount)
			{
				Assertion::fail();
			}

#else
			double (*pow)(double, double) = reinterpret_cast<double (*)(double, double)>(loader.sym("pow"));
			if (pow)
			{
				Assertion::fail();
			}

#endif
		}




		void suite()
		{
			RUN_TEST(testLoadAndRun);
			RUN_TEST(testLoadAndRunInvalidFunc);
			RUN_TEST(testInvalidLoadNoLibrary);
			RUN_TEST(testDupLoad);
			RUN_TEST(testNoLoadAndSym);
		}


};

