#include <thread>
#include <windows.h>

#include "data.h"
#include "episodelistview.h"
#include "ext.h"
#include "util.h"
#include "win.h"

extern CfgA& g_cfg;

struct Test
{
	const char* name = {0};
	char error[64] = {0};
	Test(const char* name) : name(name) {}
};

#define TESTS struct _
#define TEST(id) }; struct id : public Test { id() : Test(#id)
#define FAIL(...) do { Sprintf(error, __VA_ARGS__); return; } while (0)

TESTS
{
	TEST(StrcpyWithSmallerDestination)
	{
		char src[15], dst[10];
		Sprintf(src, "abcdefghijklmn");
		Strcpy(dst, src);
		if (dst[8] != 'i')
			FAIL("dst[8] is not 'i', but '%c'", dst[8]);
		if (dst[9] != 0)
			FAIL("dst is not NUL-terminated");
	}

	TEST(IO)
	{
		extern FileView<ElvDataA> g_fvElv;
		ElvDataA& e1_0 = g_fvElv.At(5);
		ElvDataA& e2_0 = g_fvElv.At(9);

		/* Write two ElvDataA structs to disk. */
		{
			FileView<ElvDataA> fv(L"tmp.dat", 2);
			memcpy(fv+0, &e1_0, sizeof(e1_0));
			memcpy(fv+1, &e2_0, sizeof(e2_0));
		}

		/* Read first ElvDataA struct from disk using
		 * ElvDataA-typed FileView. */
		{
			FileView<ElvDataA> fv(L"tmp.dat", 2);
			const ElvDataA& e1 = *fv;
			if (e1.version != 'a')
				FAIL("version is different");
			if (e1_0.rating != e1.rating)
				FAIL("rating is different (%d/%d)", e1_0.rating, e1.rating);
			if (e1_0.bWatched != e1.bWatched)
				FAIL("bWatched is different");
			if (e1_0.bTVOriginal != e1.bTVOriginal)
				FAIL("bTVOriginal is different");
			if (wcscmp(e1_0.sRating, e1.sRating) != 0)
				FAIL("sRating is different");
			if (wcscmp(e1_0.siEp, e1.siEp) != 0)
				FAIL("siEp is different");
			if (wcscmp(e1_0.title, e1.title) != 0)
				FAIL("title is different");
		}

		/* Read second ElvDataA struct from disk using
		 * unsigned char-typed FileView. */
		{
			FileView<unsigned char> fv(L"tmp.dat", 2*sizeof(ElvDataA));
			ElvDataA& e2 = *reinterpret_cast<ElvDataA*>(&fv.At(sizeof(ElvDataA)));
			if (e2_0.rating != e2.rating)
				FAIL("rating is different (%d/%d)", e2_0.rating, e2.rating);
			if (e2_0.bWatched != e2.bWatched)
				FAIL("bWatched is different");
			if (e2_0.bTVOriginal != e2.bTVOriginal)
				FAIL("bTVOriginal is different");
			if (wcscmp(e2_0.sRating, e2.sRating) != 0)
				FAIL("sRating is different");
			if (wcscmp(e2_0.siEp, e2.siEp) != 0)
				FAIL("siEp is different");
			if (wcscmp(e2_0.title, e2.title) != 0)
				FAIL("title is different");
		}
		//DeleteFile(L"tmp.dat");
	}

// 	TEST(MigrateCfg)
// 	{
// 		FileView<CfgB> fvb = FileView<CfgB>::Initialized(L"cfgb.dat", 1);
// 		CfgA* a = &g_cfg;
// 		CfgB* b = fvb+0;

// #define CPY(member) b->member = a->member;
// #define SCPY(member) Wcscpy(b->member, a->member);

// 		CPY(bViewWatched);
// 		CPY(bViewTVOriginal);
// 		CPY(iSortCol);
// 		CPY(cEp);
// 		CPY(iFocus);
// 		CPY(heightDlv);
// 		SCPY(limitToScreenwriter);
// 		SCPY(root);
// 		SCPY(glob);
// 		SCPY(url);

// #undef CPY
// #undef SCPY
// 	}
};

int RunTests()
{
	const Test tests[] = {
		StrcpyWithSmallerDestination(),
		//IO(),
		//MigrateCfg(),
	};

	printf("Results (%llu tests):\n", sizeof(tests)/sizeof(*tests));

	int cFailed = 0;
	for (const Test& t : tests)
	{
		const char* msg;
		if (t.error[0]) {
			msg = t.error;
			cFailed++;
		} else
			msg = const_cast<char*>("SUCCESS");
		printf("%s: %s\n", t.name, msg);
	}
	printf("%d tests failed.\n", cFailed);

	return cFailed;
}