#include "unittest/TestSuite.h"
#include "utilities/Ranrot.h"
#include <math.h>

static void testStaticRandom() {
	unsigned int uirandResult;
	int irandResult;
	float ufrandResult, frandResult;
	
	sdrand(0);
	uirandResult = uirand();
	TestCase_assert(uirandResult == 2147418111u, "Expected 2147418111 but got %u\n", uirandResult);
	uirandResult = uirand();
	TestCase_assert(uirandResult == 2147352573u, "Expected 2147352573 but got %u\n", uirandResult);
	
	sdrand(0);
	irandResult = irand();
	TestCase_assert(irandResult == -65537, "Expected -65537 but got %d\n", irandResult);
	irandResult = irand();
	TestCase_assert(irandResult == -131075, "Expected -131075 but got %d\n", irandResult);
	
	sdrand(0);
	ufrandResult = ufrand(1.0f);
	TestCase_assert(fabs(ufrandResult - 0.999969f) < 0.00001f, "Expected 0.999969 but got %f\n", ufrandResult);
	ufrandResult = ufrand(1.0f);
	TestCase_assert(fabs(ufrandResult - 0.999939f) < 0.00001f, "Expected 0.999939 but got %f\n", ufrandResult);
	
	sdrand(0);
	frandResult = frand(1.0f);
	TestCase_assert(fabs(frandResult - -0.000031f) < 0.00001f, "Expected -0.000031 but got %f\n", frandResult);
	frandResult = frand(1.0f);
	TestCase_assert(fabs(frandResult - -0.000061f) < 0.00001f, "Expected -0.000061 but got %f\n", frandResult);
	
	sdrand(1000);
	uirandResult = uirand();
	TestCase_assert(uirandResult == 2081883111u, "Expected 2081883111 but got %u\n", uirandResult);
	uirandResult = uirand();
	TestCase_assert(uirandResult == 2147353574u, "Expected 2147353574 but got %u\n", uirandResult);
	
	sdrand(1000);
	irandResult = irand();
	TestCase_assert(irandResult == -65600537, "Expected -65600537 but got %d\n", irandResult);
	irandResult = irand();
	TestCase_assert(irandResult == -130074, "Expected -131075 but got %d\n", irandResult);
	
	sdrand(1000);
	ufrandResult = ufrand(2.0f);
	TestCase_assert(fabs(ufrandResult - 1.938905f) < 0.00001f, "Expected 1.938905 but got %f\n", ufrandResult);
	ufrandResult = ufrand(2.0f);
	TestCase_assert(fabs(ufrandResult - 1.999879f) < 0.00001f, "Expected 1.999879 but got %f\n", ufrandResult);
	
	sdrand(1000);
	frandResult = frand(2.0f);
	TestCase_assert(fabs(frandResult - -0.061095f) < 0.00001f, "Expected -0.061095 but got %f\n", frandResult);
	frandResult = frand(2.0f);
	TestCase_assert(fabs(frandResult - -0.000121f) < 0.00001f, "Expected -0.000121 but got %f\n", frandResult);
	
	sdrand(0);
	stirrand(1);
	uirandResult = uirand();
	TestCase_assert(uirandResult == 2147352573u, "Expected 2147352573 but got %u\n", uirandResult);
	
	sdrand(0);
	stirrand(2);
	uirandResult = uirand();
	TestCase_assert(uirandResult == 2147090425u, "Expected 2147090425 but got %u\n", uirandResult);
}

static void testInstancedRandom() {
	Ranrot ranrot, * ranrotPtr;
	bool success;
	unsigned int uirandResult;
	int irandResult;
	float ufrandResult, frandResult;
	
	memset(&ranrot, 0x00, sizeof(ranrot));
	stemobject_assign_vtable(ranrot, Ranrot);
	success = Ranrot_init(&ranrot);
	TestCase_assert(success, "Expected true but got false");
	TestCase_assert(ranrot.vtable == &Ranrot_class, "Expected %p but got %p", &Ranrot_class, ranrot.vtable);
	
	memset(&ranrot, 0xFF, sizeof(ranrot));
	stemobject_assign_vtable(ranrot, Ranrot);
	success = Ranrot_init(&ranrot);
	TestCase_assert(success, "Expected true but got false");
	TestCase_assert(ranrot.vtable == &Ranrot_class, "Expected %p but got %p", &Ranrot_class, ranrot.vtable);
	
	ranrotPtr = Ranrot_create();
	TestCase_assert(ranrotPtr != NULL, "Expected non-NULL but got NULL");
	if (ranrotPtr == NULL) {return;} // Suppress clang warning
	TestCase_assert(ranrotPtr->vtable == &Ranrot_class, "Expected %p but got %p", &Ranrot_class, ranrotPtr->vtable);
	
	call_virtual(sdrand, &ranrot, 0);
	call_virtual(sdrand, ranrotPtr, 0);
	
	uirandResult = call_virtual(uirand, &ranrot);
	TestCase_assert(uirandResult == 2147418111u, "Expected 2147418111 but got %u\n", uirandResult);
	uirandResult = call_virtual(uirand, &ranrot);
	TestCase_assert(uirandResult == 2147352573u, "Expected 2147352573 but got %u\n", uirandResult);
	
	uirandResult = call_virtual(uirand, ranrotPtr);
	TestCase_assert(uirandResult == 2147418111u, "Expected 2147418111 but got %u\n", uirandResult);
	uirandResult = call_virtual(uirand, ranrotPtr);
	TestCase_assert(uirandResult == 2147352573u, "Expected 2147352573 but got %u\n", uirandResult);
	
	call_virtual(sdrand, &ranrot, 0);
	call_virtual(sdrand, ranrotPtr, 0);
	
	irandResult = call_virtual(irand, &ranrot);
	TestCase_assert(irandResult == -65537, "Expected -65537 but got %d\n", irandResult);
	irandResult = call_virtual(irand, &ranrot);
	TestCase_assert(irandResult == -131075, "Expected -131075 but got %d\n", irandResult);
	
	irandResult = call_virtual(irand, ranrotPtr);
	TestCase_assert(irandResult == -65537, "Expected -65537 but got %d\n", irandResult);
	irandResult = call_virtual(irand, ranrotPtr);
	TestCase_assert(irandResult == -131075, "Expected -131075 but got %d\n", irandResult);
	
	call_virtual(sdrand, &ranrot, 0);
	call_virtual(sdrand, ranrotPtr, 0);
	
	ufrandResult = call_virtual(ufrand, &ranrot, 1.0f);
	TestCase_assert(fabs(ufrandResult - 0.999969f) < 0.00001f, "Expected 0.999969 but got %f\n", ufrandResult);
	ufrandResult = call_virtual(ufrand, &ranrot, 1.0f);
	TestCase_assert(fabs(ufrandResult - 0.999939f) < 0.00001f, "Expected 0.999939 but got %f\n", ufrandResult);
	
	ufrandResult = call_virtual(ufrand, ranrotPtr, 1.0f);
	TestCase_assert(fabs(ufrandResult - 0.999969f) < 0.00001f, "Expected 0.999969 but got %f\n", ufrandResult);
	ufrandResult = call_virtual(ufrand, ranrotPtr, 1.0f);
	TestCase_assert(fabs(ufrandResult - 0.999939f) < 0.00001f, "Expected 0.999939 but got %f\n", ufrandResult);
	
	call_virtual(sdrand, &ranrot, 0);
	call_virtual(sdrand, ranrotPtr, 0);
	
	frandResult = call_virtual(frand, &ranrot, 1.0f);
	TestCase_assert(fabs(frandResult - -0.000031f) < 0.00001f, "Expected -0.000031 but got %f\n", frandResult);
	frandResult = call_virtual(frand, &ranrot, 1.0f);
	TestCase_assert(fabs(frandResult - -0.000061f) < 0.00001f, "Expected -0.000061 but got %f\n", frandResult);
	
	frandResult = call_virtual(frand, ranrotPtr, 1.0f);
	TestCase_assert(fabs(frandResult - -0.000031f) < 0.00001f, "Expected -0.000031 but got %f\n", frandResult);
	frandResult = call_virtual(frand, ranrotPtr, 1.0f);
	TestCase_assert(fabs(frandResult - -0.000061f) < 0.00001f, "Expected -0.000061 but got %f\n", frandResult);
	
	call_virtual(sdrand, &ranrot, 1000);
	call_virtual(sdrand, ranrotPtr, 1000);
	
	uirandResult = call_virtual(uirand, &ranrot);
	TestCase_assert(uirandResult == 2081883111u, "Expected 2081883111 but got %u\n", uirandResult);
	uirandResult = call_virtual(uirand, &ranrot);
	TestCase_assert(uirandResult == 2147353574u, "Expected 2147353574 but got %u\n", uirandResult);
	
	uirandResult = call_virtual(uirand, ranrotPtr);
	TestCase_assert(uirandResult == 2081883111u, "Expected 2081883111 but got %u\n", uirandResult);
	uirandResult = call_virtual(uirand, ranrotPtr);
	TestCase_assert(uirandResult == 2147353574u, "Expected 2147353574 but got %u\n", uirandResult);
	
	call_virtual(sdrand, &ranrot, 1000);
	call_virtual(sdrand, ranrotPtr, 1000);
	
	irandResult = call_virtual(irand, &ranrot);
	TestCase_assert(irandResult == -65600537, "Expected -65600537 but got %d\n", irandResult);
	irandResult = call_virtual(irand, &ranrot);
	TestCase_assert(irandResult == -130074, "Expected -131075 but got %d\n", irandResult);
	
	irandResult = call_virtual(irand, ranrotPtr);
	TestCase_assert(irandResult == -65600537, "Expected -65600537 but got %d\n", irandResult);
	irandResult = call_virtual(irand, ranrotPtr);
	TestCase_assert(irandResult == -130074, "Expected -131075 but got %d\n", irandResult);
	
	call_virtual(sdrand, &ranrot, 1000);
	call_virtual(sdrand, ranrotPtr, 1000);
	
	ufrandResult = call_virtual(ufrand, &ranrot, 2.0f);
	TestCase_assert(fabs(ufrandResult - 1.938905f) < 0.00001f, "Expected 1.938905 but got %f\n", ufrandResult);
	ufrandResult = call_virtual(ufrand, &ranrot, 2.0f);
	TestCase_assert(fabs(ufrandResult - 1.999879f) < 0.00001f, "Expected 1.999879 but got %f\n", ufrandResult);
	
	ufrandResult = call_virtual(ufrand, ranrotPtr, 2.0f);
	TestCase_assert(fabs(ufrandResult - 1.938905f) < 0.00001f, "Expected 1.938905 but got %f\n", ufrandResult);
	ufrandResult = call_virtual(ufrand, ranrotPtr, 2.0f);
	TestCase_assert(fabs(ufrandResult - 1.999879f) < 0.00001f, "Expected 1.999879 but got %f\n", ufrandResult);
	
	call_virtual(sdrand, &ranrot, 1000);
	call_virtual(sdrand, ranrotPtr, 1000);
	
	frandResult = call_virtual(frand, &ranrot, 2.0f);
	TestCase_assert(fabs(frandResult - -0.061095f) < 0.00001f, "Expected -0.061095 but got %f\n", frandResult);
	frandResult = call_virtual(frand, &ranrot, 2.0f);
	TestCase_assert(fabs(frandResult - -0.000121f) < 0.00001f, "Expected -0.000121 but got %f\n", frandResult);
	
	frandResult = call_virtual(frand, ranrotPtr, 2.0f);
	TestCase_assert(fabs(frandResult - -0.061095f) < 0.00001f, "Expected -0.061095 but got %f\n", frandResult);
	frandResult = call_virtual(frand, ranrotPtr, 2.0f);
	TestCase_assert(fabs(frandResult - -0.000121f) < 0.00001f, "Expected -0.000121 but got %f\n", frandResult);
	
	call_virtual(sdrand, &ranrot, 0);
	call_virtual(stirrand, &ranrot, 1);
	call_virtual(sdrand, ranrotPtr, 0);
	call_virtual(stirrand, ranrotPtr, 1);
	uirandResult = call_virtual(uirand, &ranrot);
	TestCase_assert(uirandResult == 2147352573u, "Expected 2147352573 but got %u\n", uirandResult);
	uirandResult = call_virtual(uirand, ranrotPtr);
	TestCase_assert(uirandResult == 2147352573u, "Expected 2147352573 but got %u\n", uirandResult);
	
	call_virtual(sdrand, &ranrot, 0);
	call_virtual(stirrand, &ranrot, 2);
	call_virtual(sdrand, ranrotPtr, 0);
	call_virtual(stirrand, ranrotPtr, 2);
	uirandResult = call_virtual(uirand, &ranrot);
	TestCase_assert(uirandResult == 2147090425u, "Expected 2147090425 but got %u\n", uirandResult);
	uirandResult = call_virtual(uirand, ranrotPtr);
	TestCase_assert(uirandResult == 2147090425u, "Expected 2147090425 but got %u\n", uirandResult);
}

TEST_SUITE(RanrotTest,
           testStaticRandom,
           testInstancedRandom)
