#include "gamemath/Color.h"
#include "unittest/TestSuite.h"

#define TOLERANCE 0.0001f

static void testConstructors(void) {
	Color3f color3f = COLOR3f(0.0f, 0.5f, 1.0f);
	TestCase_assertColor3fEqual(color3f, C3f(0.0f, 0.5f, 1.0f));
	color3f = COLOR3f(0.25f, 0.75f, 0.125f);
	TestCase_assertColor3fEqual(color3f, C3f(0.25f, 0.75f, 0.125f));
	color3f = C3f(0.0f, 0.5f, 1.0f);
	TestCase_assertColor3fEqual(color3f, C3f(0.0f, 0.5f, 1.0f));
	color3f = C3f(0.25f, 0.75f, 0.125f);
	TestCase_assertColor3fEqual(color3f, C3f(0.25f, 0.75f, 0.125f));
	
	Color3ub color3ub = COLOR3ub(0x00, 0x7F, 0xFF);
	TestCase_assertColor3ubEqual(color3ub, C3ub(0x00, 0x7F, 0xFF));
	color3ub = COLOR3ub(0x3F, 0xBF, 0x1F);
	TestCase_assertColor3ubEqual(color3ub, C3ub(0x3F, 0xBF, 0x1F));
	color3ub = C3ub(0x00, 0x7F, 0xFF);
	TestCase_assertColor3ubEqual(color3ub, C3ub(0x00, 0x7F, 0xFF));
	color3ub = C3ub(0x3F, 0xBF, 0x1F);
	TestCase_assertColor3ubEqual(color3ub, C3ub(0x3F, 0xBF, 0x1F));
	
	Color4f color4f = COLOR4f(0.0f, 0.5f, 1.0f, 0.25f);
	TestCase_assertColor4fEqual(color4f, C4f(0.0f, 0.5f, 1.0f, 0.25f));
	color4f = COLOR4f(0.25f, 0.75f, 0.125f, 0.625f);
	TestCase_assertColor4fEqual(color4f, C4f(0.25f, 0.75f, 0.125f, 0.625f));
	color4f = C4f(0.0f, 0.5f, 1.0f, 0.25f);
	TestCase_assertColor4fEqual(color4f, C4f(0.0f, 0.5f, 1.0f, 0.25f));
	color4f = C4f(0.25f, 0.75f, 0.125f, 0.625f);
	TestCase_assertColor4fEqual(color4f, C4f(0.25f, 0.75f, 0.125f, 0.625f));
	
	Color4ub color4ub = COLOR4ub(0x00, 0x7F, 0xFF, 0x3F);
	TestCase_assertColor4ubEqual(color4ub, C4ub(0x00, 0x7F, 0xFF, 0x3F));
	color4ub = COLOR4ub(0x3F, 0xBF, 0x1F, 0x9F);
	TestCase_assertColor4ubEqual(color4ub, C4ub(0x3F, 0xBF, 0x1F, 0x9F));
	color4ub = C4ub(0x00, 0x7F, 0xFF, 0x3F);
	TestCase_assertColor4ubEqual(color4ub, C4ub(0x00, 0x7F, 0xFF, 0x3F));
	color4ub = C4ub(0x3F, 0xBF, 0x1F, 0x9F);
	TestCase_assertColor4ubEqual(color4ub, C4ub(0x3F, 0xBF, 0x1F, 0x9F));
	
	color3f = COLOR3f_UINT8(0x00, 0x7F, 0xFF);
	TestCase_assertColor3fApproximate(color3f, C3f(0.0f, (float) 0x7F / (float) 0xFF, 1.0f), TOLERANCE);
	color3f = COLOR3f_UINT8(0x3F, 0xBF, 0x1F);
	TestCase_assertColor3fApproximate(color3f, C3f((float) 0x3F / (float) 0xFF, (float) 0xBF / (float) 0xFF, (float) 0x1F / (float) 0xFF), TOLERANCE);
	color3f = C3f_U8(0x00, 0x7F, 0xFF);
	TestCase_assertColor3fApproximate(color3f, C3f(0.0f, (float) 0x7F / (float) 0xFF, 1.0f), TOLERANCE);
	color3f = C3f_U8(0x3F, 0xBF, 0x1F);
	TestCase_assertColor3fApproximate(color3f, C3f((float) 0x3F / (float) 0xFF, (float) 0xBF / (float) 0xFF, (float) 0x1F / (float) 0xFF), TOLERANCE);
	
	color4f = COLOR4f_UINT8(0x00, 0x7F, 0xFF, 0x3F);
	TestCase_assertColor4fApproximate(color4f, C4f(0.0f, (float) 0x7F / (float) 0xFF, 1.0f, (float) 0x3F / (float) 0xFF), TOLERANCE);
	color4f = COLOR4f_UINT8(0x3F, 0xBF, 0x1F, 0x9F);
	TestCase_assertColor4fApproximate(color4f, C4f((float) 0x3F / (float) 0xFF, (float) 0xBF / (float) 0xFF, (float) 0x1F / (float) 0xFF, (float) 0x9F / (float) 0xFF), TOLERANCE);
	color4f = C4f_U8(0x00, 0x7F, 0xFF, 0x3F);
	TestCase_assertColor4fApproximate(color4f, C4f(0.0f, (float) 0x7F / (float) 0xFF, 1.0f, (float) 0x3F / (float) 0xFF), TOLERANCE);
	color4f = C4f_U8(0x3F, 0xBF, 0x1F, 0x9F);
	TestCase_assertColor4fApproximate(color4f, C4f((float) 0x3F / (float) 0xFF, (float) 0xBF / (float) 0xFF, (float) 0x1F / (float) 0xFF, (float) 0x9F / (float) 0xFF), TOLERANCE);
	
	color4f = COLOR4f_PREMULTIPLIED(0.25f, 0.5f, 0.75f, 0.5f);
	TestCase_assertColor4fEqual(color4f, C4f(0.125f, 0.25f, 0.375f, 0.5f));
	color4f = COLOR4f_PREMULTIPLIED(0.75f, 0.25f, 0.5f, 1.0f);
	TestCase_assertColor4fEqual(color4f, C4f(0.75f, 0.25f, 0.5f, 1.0f));
	color4f = C4f_P(0.25f, 0.5f, 0.75f, 0.5f);
	TestCase_assertColor4fEqual(color4f, C4f(0.125f, 0.25f, 0.375f, 0.5f));
	color4f = C4f_P(0.75f, 0.25f, 0.5f, 1.0f);
	TestCase_assertColor4fEqual(color4f, C4f(0.75f, 0.25f, 0.5f, 1.0f));
	
	color4f = COLOR4f_UINT8_PREMULTIPLIED(0x3F, 0x7F, 0xBF, 0x7F);
	TestCase_assertColor4fApproximate(color4f, C4f((float) 0x3F * 0x7F / 0xFF / (float) 0xFF, (float) 0x7F * 0x7F / 0xFF / (float) 0xFF, (float) 0xBF * 0x7F / 0xFF / (float) 0xFF, (float) 0x7F / (float) 0xFF), TOLERANCE);
	color4f = COLOR4f_UINT8_PREMULTIPLIED(0xBF, 0x3F, 0x7F, 0xFF);
	TestCase_assertColor4fApproximate(color4f, C4f((float) 0xBF / (float) 0xFF, (float) 0x3F / (float) 0xFF, (float) 0x7F / (float) 0xFF, (float) 0xFF / (float) 0xFF), TOLERANCE);
	color4f = C4f_U8_P(0x3F, 0x7F, 0xBF, 0x7F);
	TestCase_assertColor4fApproximate(color4f, C4f((float) 0x3F * 0x7F / 0xFF / (float) 0xFF, (float) 0x7F * 0x7F / 0xFF / (float) 0xFF, (float) 0xBF * 0x7F / 0xFF / (float) 0xFF, (float) 0x7F / (float) 0xFF), TOLERANCE);
	color4f = C4f_U8_P(0xBF, 0x3F, 0x7F, 0xFF);
	TestCase_assertColor4fApproximate(color4f, C4f((float) 0xBF / (float) 0xFF, (float) 0x3F / (float) 0xFF, (float) 0x7F / (float) 0xFF, (float) 0xFF / (float) 0xFF), TOLERANCE);
	
	color4ub = COLOR4ub_PREMULTIPLIED(0x3F, 0x7F, 0xBF, 0x7F);
	TestCase_assertColor4ubEqual(color4ub, C4ub(0x3F * 0x7F / 0xFF, 0x7F * 0x7F / 0xFF, 0xBF * 0x7F / 0xFF, 0x7F));
	color4ub = COLOR4ub_PREMULTIPLIED(0xBF, 0x3F, 0x7F, 0xFF);
	TestCase_assertColor4ubEqual(color4ub, C4ub(0xBF, 0x3F, 0x7F, 0xFF));
	color4ub = C4ub_P(0x3F, 0x7F, 0xBF, 0x7F);
	TestCase_assertColor4ubEqual(color4ub, C4ub(0x3F * 0x7F / 0xFF, 0x7F * 0x7F / 0xFF, 0xBF * 0x7F / 0xFF, 0x7F));
	color4ub = C4ub_P(0xBF, 0x3F, 0x7F, 0xFF);
	TestCase_assertColor4ubEqual(color4ub, C4ub(0xBF, 0x3F, 0x7F, 0xFF));
	
	color3ub = COLOR3ub_UINT32(0x007FFF);
	TestCase_assertColor3ubEqual(color3ub, C3ub(0x00, 0x7F, 0xFF));
	color3ub = COLOR3ub_UINT32(0x3FBF1F);
	TestCase_assertColor3ubEqual(color3ub, C3ub(0x3F, 0xBF, 0x1F));
	color3ub = C3ub_U32(0x007FFF);
	TestCase_assertColor3ubEqual(color3ub, C3ub(0x00, 0x7F, 0xFF));
	color3ub = C3ub_U32(0x3FBF1F);
	TestCase_assertColor3ubEqual(color3ub, C3ub(0x3F, 0xBF, 0x1F));
	
	color3f = COLOR3f_UINT32(0x007FFF);
	TestCase_assertColor3fApproximate(color3f, C3f(0.0f, (float) 0x7F / (float) 0xFF, 1.0f), TOLERANCE);
	color3f = COLOR3f_UINT32(0x3FBF1F);
	TestCase_assertColor3fApproximate(color3f, C3f((float) 0x3F / (float) 0xFF, (float) 0xBF / (float) 0xFF, (float) 0x1F / (float) 0xFF), TOLERANCE);
	color3f = C3f_U32(0x007FFF);
	TestCase_assertColor3fApproximate(color3f, C3f(0.0f, (float) 0x7F / (float) 0xFF, 1.0f), TOLERANCE);
	color3f = C3f_U32(0x3FBF1F);
	TestCase_assertColor3fApproximate(color3f, C3f((float) 0x3F / (float) 0xFF, (float) 0xBF / (float) 0xFF, (float) 0x1F / (float) 0xFF), TOLERANCE);
	
	color4ub = COLOR4ub_UINT32(0x007FFF3F);
	TestCase_assertColor4ubEqual(color4ub, C4ub(0x00, 0x7F, 0xFF, 0x3F));
	color4ub = COLOR4ub_UINT32(0x3FBF1F9F);
	TestCase_assertColor4ubEqual(color4ub, C4ub(0x3F, 0xBF, 0x1F, 0x9F));
	color4ub = C4ub_U32(0x007FFF3F);
	TestCase_assertColor4ubEqual(color4ub, C4ub(0x00, 0x7F, 0xFF, 0x3F));
	color4ub = C4ub_U32(0x3FBF1F9F);
	TestCase_assertColor4ubEqual(color4ub, C4ub(0x3F, 0xBF, 0x1F, 0x9F));
	
	color4ub = COLOR4ub_UINT32_PREMULTIPLIED(0x3F7FBF7F);
	TestCase_assertColor4ubEqual(color4ub, C4ub(0x3F * 0x7F / 0xFF, 0x7F * 0x7F / 0xFF, 0xBF * 0x7F / 0xFF, 0x7F));
	color4ub = COLOR4ub_UINT32_PREMULTIPLIED(0xBF3F7FFF);
	TestCase_assertColor4ubEqual(color4ub, C4ub(0xBF, 0x3F, 0x7F, 0xFF));
	color4ub = C4ub_U32_P(0x3F7FBF7F);
	TestCase_assertColor4ubEqual(color4ub, C4ub(0x3F * 0x7F / 0xFF, 0x7F * 0x7F / 0xFF, 0xBF * 0x7F / 0xFF, 0x7F));
	color4ub = C4ub_U32_P(0xBF3F7FFF);
	TestCase_assertColor4ubEqual(color4ub, C4ub(0xBF, 0x3F, 0x7F, 0xFF));
	
	color4f = COLOR4f_UINT32(0x007FFF3F);
	TestCase_assertColor4fApproximate(color4f, C4f(0.0f, (float) 0x7F / (float) 0xFF, 1.0f, (float) 0x3F / (float) 0xFF), TOLERANCE);
	color4f = COLOR4f_UINT32(0x3FBF1F9F);
	TestCase_assertColor4fApproximate(color4f, C4f((float) 0x3F / (float) 0xFF, (float) 0xBF / (float) 0xFF, (float) 0x1F / (float) 0xFF, (float) 0x9F / (float) 0xFF), TOLERANCE);
	color4f = C4f_U32(0x007FFF3F);
	TestCase_assertColor4fApproximate(color4f, C4f(0.0f, (float) 0x7F / (float) 0xFF, 1.0f, (float) 0x3F / (float) 0xFF), TOLERANCE);
	color4f = C4f_U32(0x3FBF1F9F);
	TestCase_assertColor4fApproximate(color4f, C4f((float) 0x3F / (float) 0xFF, (float) 0xBF / (float) 0xFF, (float) 0x1F / (float) 0xFF, (float) 0x9F / (float) 0xFF), TOLERANCE);
	
	color4f = COLOR4f_UINT32_PREMULTIPLIED(0x3F7FBF7F);
	TestCase_assertColor4fApproximate(color4f, C4f((float) 0x3F * 0x7F / 0xFF / (float) 0xFF, (float) 0x7F * 0x7F / 0xFF / (float) 0xFF, (float) 0xBF * 0x7F / 0xFF / (float) 0xFF, (float) 0x7F / (float) 0xFF), TOLERANCE);
	color4f = COLOR4f_UINT32_PREMULTIPLIED(0xBF3F7FFF);
	TestCase_assertColor4fApproximate(color4f, C4f((float) 0xBF / (float) 0xFF, (float) 0x3F / (float) 0xFF, (float) 0x7F / (float) 0xFF, (float) 0xFF / (float) 0xFF), TOLERANCE);
	color4f = C4f_U32_P(0x3F7FBF7F);
	TestCase_assertColor4fApproximate(color4f, C4f((float) 0x3F * 0x7F / 0xFF / (float) 0xFF, (float) 0x7F * 0x7F / 0xFF / (float) 0xFF, (float) 0xBF * 0x7F / 0xFF / (float) 0xFF, (float) 0x7F / (float) 0xFF), TOLERANCE);
	color4f = C4f_U32_P(0xBF3F7FFF);
	TestCase_assertColor4fApproximate(color4f, C4f((float) 0xBF / (float) 0xFF, (float) 0x3F / (float) 0xFF, (float) 0x7F / (float) 0xFF, (float) 0xFF / (float) 0xFF), TOLERANCE);
	
	color3f = COLOR3f_WHITE;
	TestCase_assertColor3fEqual(color3f, C3f(1.0f, 1.0f, 1.0f));
	color3f = COLOR3f_BLACK;
	TestCase_assertColor3fEqual(color3f, C3f(0.0f, 0.0f, 0.0f));
	
	color3ub = COLOR3ub_WHITE;
	TestCase_assertColor3ubEqual(color3ub, C3ub(0xFF, 0xFF, 0xFF));
	color3ub = COLOR3ub_BLACK;
	TestCase_assertColor3ubEqual(color3ub, C3ub(0x00, 0x00, 0x00));
	
	color4f = COLOR4f_WHITE;
	TestCase_assertColor4fEqual(color4f, C4f(1.0f, 1.0f, 1.0f, 1.0f));
	color4f = COLOR4f_BLACK;
	TestCase_assertColor4fEqual(color4f, C4f(0.0f, 0.0f, 0.0f, 1.0f));
	color4f = COLOR4f_TRANSPARENT;
	TestCase_assertColor4fEqual(color4f, C4f(0.0f, 0.0f, 0.0f, 0.0f));
	
	color4ub = COLOR4ub_WHITE;
	TestCase_assertColor4ubEqual(color4ub, C4ub(0xFF, 0xFF, 0xFF, 0xFF));
	color4ub = COLOR4ub_BLACK;
	TestCase_assertColor4ubEqual(color4ub, C4ub(0x00, 0x00, 0x00, 0xFF));
	color4ub = COLOR4ub_TRANSPARENT;
	TestCase_assertColor4ubEqual(color4ub, C4ub(0x00, 0x00, 0x00, 0x00));
}

static void testConversions(void) {
	Color3f color3f = COLOR3f_TRUNCATE(C4f(0.0f, 0.25f, 0.5f, 0.75f));
	TestCase_assertColor3fEqual(color3f, C3f(0.0f, 0.25f, 0.5f));
	color3f = COLOR3f_TRUNCATE(C4f(1.0f, 0.75f, 0.25f, 0.125f));
	TestCase_assertColor3fEqual(color3f, C3f(1.0f, 0.75f, 0.25f));
	
	Color4f color4f = COLOR4f_EXTEND3(C3f(0.0f, 0.25f, 0.5f), 0.75f);
	TestCase_assertColor4fEqual(color4f, C4f(0.0f, 0.25f, 0.5f, 0.75f));
	color4f = COLOR4f_EXTEND3(C3f(1.0f, 0.75f, 0.25f), 0.125f);
	TestCase_assertColor4fEqual(color4f, C4f(1.0f, 0.75f, 0.25f, 0.125f));
	
	color4f = COLOR4f_EXTEND3_PREMULTIPLY(C3f(0.0f, 0.25f, 0.5f), 0.5f);
	TestCase_assertColor4fEqual(color4f, C4f(0.0f, 0.125f, 0.25f, 0.5f));
	color4f = COLOR4f_EXTEND3_PREMULTIPLY(C3f(1.0f, 0.75f, 0.25f), 0.25f);
	TestCase_assertColor4fEqual(color4f, C4f(0.25f, 0.1875f, 0.0625f, 0.25f));
	
	Color3ub color3ub = COLOR3ub_TRUNCATE(C4ub(0x00, 0x3F, 0x7F, 0xBF));
	TestCase_assertColor3ubEqual(color3ub, C3ub(0x00, 0x3F, 0x7F));
	color3ub = COLOR3ub_TRUNCATE(C4ub(0xFF, 0xBF, 0x3F, 0x1F));
	TestCase_assertColor3ubEqual(color3ub, C3ub(0xFF, 0xBF, 0x3F));
	
	Color4ub color4ub = COLOR4ub_EXTEND3(C3ub(0x00, 0x3F, 0x7F), 0xBF);
	TestCase_assertColor4ubEqual(color4ub, C4ub(0x00, 0x3F, 0x7F, 0xBF));
	color4ub = COLOR4ub_EXTEND3(C3ub(0xFF, 0xBF, 0x3F), 0x1F);
	TestCase_assertColor4ubEqual(color4ub, C4ub(0xFF, 0xBF, 0x3F, 0x1F));
	
	color4ub = COLOR4ub_EXTEND3_PREMULTIPLY(C3ub(0x00, 0x3F, 0x7F), 0x7F);
	TestCase_assertColor4ubEqual(color4ub, C4ub(0x00, 0x1F, 0x3F, 0x7F));
	color4ub = COLOR4ub_EXTEND3_PREMULTIPLY(C3ub(0xFF, 0xBF, 0x3F), 0x3F);
	TestCase_assertColor4ubEqual(color4ub, C4ub(0x3F, 0x2F, 0x0F, 0x3F));
	
	color3f = Color3ub_toColor3f(C3ub(0x3F, 0x7F, 0xBF));
	TestCase_assertColor3fApproximate(color3f, C3f((float) 0x3F / (float) 0xFF, (float) 0x7F / (float) 0xFF, (float) 0xBF / (float) 0xFF), TOLERANCE);
	color3f = Color3ub_toColor3f(C3ub(0x00, 0x3F, 0x7F));
	TestCase_assertColor3fApproximate(color3f, C3f((float) 0x00 / (float) 0xFF, (float) 0x3F / (float) 0xFF, (float) 0x7F / (float) 0xFF), TOLERANCE);
	color3ub = Color3f_toColor3ub(C3f(0.25f, 0.5f, 0.75f));
	TestCase_assertColor3ubEqual(color3ub, C3ub(0x40, 0x80, 0xBF));
	color3ub = Color3f_toColor3ub(C3f(0.0f, 0.25f, 0.5f));
	TestCase_assertColor3ubEqual(color3ub, C3ub(0x00, 0x40, 0x80));
	color4f = Color4ub_toColor4f(C4ub(0x3F, 0x7F, 0xBF, 0xFF));
	TestCase_assertColor4fApproximate(color4f, C4f((float) 0x3F / (float) 0xFF, (float) 0x7F / (float) 0xFF, (float) 0xBF / (float) 0xFF, (float) 0xFF / (float) 0xFF), TOLERANCE);
	color4f = Color4ub_toColor4f(C4ub(0x00, 0x3F, 0x7F, 0xBF));
	TestCase_assertColor4fApproximate(color4f, C4f((float) 0x00 / (float) 0xFF, (float) 0x3F / (float) 0xFF, (float) 0x7F / (float) 0xFF, (float) 0xBF / (float) 0xFF), TOLERANCE);
	color4ub = Color4f_toColor4ub(C4f(0.25f, 0.5f, 0.75f, 1.0f));
	TestCase_assertColor4ubEqual(color4ub, C4ub(0x40, 0x80, 0xBF, 0xFF));
	color4ub = Color4f_toColor4ub(C4f(0.0f, 0.25f, 0.5f, 0.75f));
	TestCase_assertColor4ubEqual(color4ub, C4ub(0x00, 0x40, 0x80, 0xBF));
	
	color3ub = Color3ub_fromUInt32(0x1F3F5F);
	TestCase_assertColor3ubEqual(color3ub, C3ub(0x1F, 0x3F, 0x5F));
	color3ub = Color3ub_fromUInt32(0x3F7FBF);
	TestCase_assertColor3ubEqual(color3ub, C3ub(0x3F, 0x7F, 0xBF));
	
	uint32_t uint32 = Color3ub_toUInt32(C3ub(0x1F, 0x3F, 0x5F));
	TestCase_assertXIntEqual(uint32, 0x1F3F5F);
	uint32 = Color3ub_toUInt32(C3ub(0x3F, 0x7F, 0xBF));
	TestCase_assertXIntEqual(uint32, 0x3F7FBF);
	
	color4ub = Color4ub_fromUInt32(0x1F3F5F7F);
	TestCase_assertColor4ubEqual(color4ub, C4ub(0x1F, 0x3F, 0x5F, 0x7F));
	color4ub = Color4ub_fromUInt32(0x3F7FBFFF);
	TestCase_assertColor4ubEqual(color4ub, C4ub(0x3F, 0x7F, 0xBF, 0xFF));
	
	uint32 = Color4ub_toUInt32(C4ub(0x1F, 0x3F, 0x5F, 0x7F));
	TestCase_assertXIntEqual(uint32, 0x1F3F5F7F);
	uint32 = Color4ub_toUInt32(C4ub(0x3F, 0x7F, 0xBF, 0xFF));
	TestCase_assertXIntEqual(uint32, 0x3F7FBFFF);
}

static void testIsEqual(void) {
	TestCase_assertBoolTrue(Color3f_isEqual(C3f(0.0f, 0.25f, 0.5f), C3f(0.0f, 0.25f, 0.5f)));
	TestCase_assertBoolFalse(Color3f_isEqual(C3f(0.0f, 0.25f, 0.5f), C3f(0.1f, 0.25f, 0.5f)));
	TestCase_assertBoolFalse(Color3f_isEqual(C3f(0.0f, 0.25f, 0.5f), C3f(0.0f, 0.5f, 0.5f)));
	TestCase_assertBoolFalse(Color3f_isEqual(C3f(0.0f, 0.25f, 0.5f), C3f(0.0f, 0.25f, 1.0f)));
	
	TestCase_assertBoolTrue(Color4f_isEqual(C4f(0.0f, 0.25f, 0.5f, 0.75f), C4f(0.0f, 0.25f, 0.5f, 0.75f)));
	TestCase_assertBoolFalse(Color4f_isEqual(C4f(0.0f, 0.25f, 0.5f, 0.75f), C4f(0.1f, 0.25f, 0.5f, 0.75f)));
	TestCase_assertBoolFalse(Color4f_isEqual(C4f(0.0f, 0.25f, 0.5f, 0.75f), C4f(0.0f, 0.5f, 0.5f, 0.75f)));
	TestCase_assertBoolFalse(Color4f_isEqual(C4f(0.0f, 0.25f, 0.5f, 0.75f), C4f(0.0f, 0.25f, 1.0f, 0.75f)));
	TestCase_assertBoolFalse(Color4f_isEqual(C4f(0.0f, 0.25f, 0.5f, 0.75f), C4f(0.0f, 0.25f, 0.5f, 0.875f)));
}

static void testInterpolate(void) {
	Color3f color3f = Color3f_interpolate(C3f(0.0f, 0.0f, 0.0f), C3f(0.25f, 0.5f, 0.75f), 0.5f);
	TestCase_assertColor3fEqual(color3f, C3f(0.125f, 0.25f, 0.375f));
	color3f = Color3f_interpolate(C3f(1.0f, 0.5f, 0.0f), C3f(0.5f, 0.0f, 1.0f), 0.25f);
	TestCase_assertColor3fEqual(color3f, C3f(0.875f, 0.375f, 0.25f));
	
	Color4f color4f = Color4f_interpolate(C4f(0.0f, 0.0f, 0.0f, 0.0f), C4f(0.25f, 0.5f, 0.75f, 1.0f), 0.5f);
	TestCase_assertColor4fEqual(color4f, C4f(0.125f, 0.25f, 0.375f, 0.5f));
	color4f = Color4f_interpolate(C4f(1.0f, 0.5f, 0.0f, 1.0f), C4f(0.5f, 0.0f, 1.0f, 1.0f), 0.25f);
	TestCase_assertColor4fEqual(color4f, C4f(0.875f, 0.375f, 0.25f, 1.0f));
	
	Color3ub color3ub = Color3ub_interpolate(C3ub(0x00, 0x00, 0x00), C3ub(0x3F, 0x7F, 0xBF), 0.5f);
	TestCase_assertColor3ubEqual(color3ub, C3ub(0x20, 0x40, 0x60));
	color3ub = Color3ub_interpolate(C3ub(0xFF, 0x7F, 0x00), C3ub(0x7F, 0x00, 0xFF), 0.25f);
	TestCase_assertColor3ubEqual(color3ub, C3ub(0xDF, 0x5F, 0x40));
	
	Color4ub color4ub = Color4ub_interpolate(C4ub(0x00, 0x00, 0x00, 0x00), C4ub(0x3F, 0x7F, 0xBF, 0xFF), 0.5f);
	TestCase_assertColor4ubEqual(color4ub, C4ub(0x20, 0x40, 0x60, 0x80));
	color4ub = Color4ub_interpolate(C4ub(0xFF, 0x7F, 0x00, 0xFF), C4ub(0x7F, 0x00, 0xFF, 0xFF), 0.25f);
	TestCase_assertColor4ubEqual(color4ub, C4ub(0xDF, 0x5F, 0x40, 0xFF));
}

static void testMultiply(void) {
	Color3f color3f = Color3f_multiply(C3f(1.0f, 0.5f, 0.25f), C3f(0.5f, 0.25f, 2.0f));
	TestCase_assertColor3fEqual(color3f, C3f(0.5f, 0.125f, 0.5f));
	color3f = Color3f_multiply(C3f(0.0f, 1.0f, 3.0f), C3f(1.0f, 0.75f, 3.0f));
	TestCase_assertColor3fEqual(color3f, C3f(0.0f, 0.75f, 9.0f));
	
	Color4f color4f = Color4f_multiply(C4f(1.0f, 0.5f, 0.25f, 0.125f), C4f(0.5f, 0.25f, 2.0f, 1.0f));
	TestCase_assertColor4fEqual(color4f, C4f(0.5f, 0.125f, 0.5f, 0.125f));
	color4f = Color4f_multiply(C4f(0.0f, 1.0f, 3.0f, 0.5f), C4f(1.0f, 0.75f, 3.0f, 0.5f));
	TestCase_assertColor4fEqual(color4f, C4f(0.0f, 0.75f, 9.0f, 0.25f));
	
	color3f = Color3f_multiplyScalar(C3f(0.125f, 0.25f, 0.5f), 2.0f);
	TestCase_assertColor3fEqual(color3f, C3f(0.25f, 0.5f, 1.0f));
	color3f = Color3f_multiplyScalar(C3f(1.0f, 0.5f, 0.25f), 0.5f);
	TestCase_assertColor3fEqual(color3f, C3f(0.5f, 0.25f, 0.125f));
	
	color4f = Color4f_multiplyScalar(C4f(0.125f, 0.25f, 0.5f, 1.0f), 2.0f);
	TestCase_assertColor4fEqual(color4f, C4f(0.25f, 0.5f, 1.0f, 2.0f));
	color4f = Color4f_multiplyScalar(C4f(1.0f, 0.5f, 0.25f, 0.0f), 0.5f);
	TestCase_assertColor4fEqual(color4f, C4f(0.5f, 0.25f, 0.125f, 0.0f));
}

static void testPremultiply(void) {
	Color4f color4f = Color4f_premultiply(C4f(0.25f, 0.5f, 1.0f, 0.5f));
	TestCase_assertColor4fEqual(color4f, C4f(0.125f, 0.25f, 0.5f, 0.5f));
	color4f = Color4f_premultiply(C4f(1.0f, 0.75f, 0.5f, 0.25f));
	TestCase_assertColor4fEqual(color4f, C4f(0.25f, 0.1875f, 0.125f, 0.25f));
	
	Color4ub color4ub = Color4ub_premultiply(C4ub(0x3F, 0x7F, 0xFF, 0x7F));
	TestCase_assertColor4ubEqual(color4ub, C4ub(0x1F, 0x3F, 0x7F, 0x7F));
	color4ub = Color4ub_premultiply(C4ub(0xFF, 0xBF, 0x7F, 0x3F));
	TestCase_assertColor4ubEqual(color4ub, C4ub(0x3F, 0x2F, 0x1F, 0x3F));
	
	color4f = Color4f_unpremultiply(C4f(0.125f, 0.25f, 0.5f, 0.5f));
	TestCase_assertColor4fEqual(color4f, C4f(0.25f, 0.5f, 1.0f, 0.5f));
	color4f = Color4f_unpremultiply(C4f(0.25f, 0.1875f, 0.125f, 0.25f));
	TestCase_assertColor4fEqual(color4f, C4f(1.0f, 0.75f, 0.5f, 0.25f));
	
	color4ub = Color4ub_unpremultiply(C4ub(0x1F, 0x3F, 0x7F, 0x7F));
	TestCase_assertColor4ubEqual(color4ub, C4ub(0x3E, 0x7E, 0xFF, 0x7F));
	color4ub = Color4ub_unpremultiply(C4ub(0x3F, 0x2F, 0x1F, 0x3F));
	TestCase_assertColor4ubEqual(color4ub, C4ub(0xFF, 0xBE, 0x7D, 0x3F));
	
	color4f = Color4f_unpremultiply(C4f(0.125f, 0.25f, 0.5f, 0.0f));
	TestCase_assertColor4fEqual(color4f, C4f(0.125f, 0.25f, 0.5f, 0.0f));
	
	color4ub = Color4ub_unpremultiply(C4ub(0x1F, 0x3F, 0x7F, 0x00));
	TestCase_assertColor4ubEqual(color4ub, C4ub(0x1F, 0x3F, 0x7F, 0x00));
}

static void testHSV(void) {
	HSVColor3f hsv3f = HSVCOLOR3f(0.0f, 0.5f, 1.0f);
	TestCase_assertHSVColor3fEqual(hsv3f, HSVC3f(0.0f, 0.5f, 1.0f));
	hsv3f = HSVCOLOR3f(1.0f, 0.25f, 0.5f);
	TestCase_assertHSVColor3fEqual(hsv3f, HSVC3f(1.0f, 0.25f, 0.5f));
	hsv3f = HSVC3f(0.0f, 0.5f, 1.0f);
	TestCase_assertHSVColor3fEqual(hsv3f, HSVC3f(0.0f, 0.5f, 1.0f));
	hsv3f = HSVC3f(1.0f, 0.25f, 0.5f);
	TestCase_assertHSVColor3fEqual(hsv3f, HSVC3f(1.0f, 0.25f, 0.5f));
	
	hsv3f = Color3f_RGBToHSV(C3f(0.0f, 1.0f, 0.0f));
	TestCase_assertHSVColor3fEqual(hsv3f, HSVC3f(2.0f, 1.0f, 1.0f));
	hsv3f = Color3f_RGBToHSV(C3f(0.25f, 0.375f, 0.5f));
	TestCase_assertHSVColor3fApproximate(hsv3f, HSVC3f(3.5f, 0.5f, 0.5f), TOLERANCE);
	
	Color3f color3f = Color3f_HSVToRGB(HSVC3f(2.0f, 1.0f, 1.0f));
	TestCase_assertColor3fEqual(color3f, C3f(0.0f, 1.0f, 0.0f));
	color3f = Color3f_HSVToRGB(HSVC3f(3.5f, 0.5f, 0.5f));
	TestCase_assertColor3fApproximate(color3f, C3f(0.25f, 0.375f, 0.5f), TOLERANCE);
	
	hsv3f = Color4f_RGBAToHSV(C4f(0.0f, 1.0f, 0.0f, 1.0f));
	TestCase_assertHSVColor3fEqual(hsv3f, HSVC3f(2.0f, 1.0f, 1.0f));
	hsv3f = Color4f_RGBAToHSV(C4f(0.25f, 0.375f, 0.5f, 0.5f));
	TestCase_assertHSVColor3fApproximate(hsv3f, HSVC3f(3.5f, 0.5f, 0.5f), TOLERANCE);
	
	Color4f color4f = Color4f_HSVToRGBA(HSVC3f(2.0f, 1.0f, 1.0f), 1.0f);
	TestCase_assertColor4fEqual(color4f, C4f(0.0f, 1.0f, 0.0f, 1.0f));
	color4f = Color4f_HSVToRGBA(HSVC3f(3.5f, 0.5f, 0.5f), 0.5f);
	TestCase_assertColor4fApproximate(color4f, C4f(0.25f, 0.375f, 0.5f, 0.5f), TOLERANCE);
}

static void testHSVInterpolation(void) {
	HSVColor3f hsv3f = HSVColor3f_interpolate(HSVC3f(0.0f, 0.0f, 0.0f), HSVC3f(1.0f, 1.0f, 1.0f), 0.5f);
	TestCase_assertHSVColor3fApproximate(hsv3f, HSVC3f(0.5f, 0.5f, 0.5f), TOLERANCE);
	
	hsv3f = HSVColor3f_interpolate(HSVC3f(2.0f, 2.0f, 2.0f), HSVC3f(3.0f, 3.0f, 3.0f), 0.25f);
	TestCase_assertHSVColor3fApproximate(hsv3f, HSVC3f(2.25f, 2.25f, 2.25f), TOLERANCE);
	
	hsv3f = HSVColor3f_interpolate(HSVC3f(5.0f, 1.0f, 1.0f), HSVC3f(0.0f, 1.0f, 1.0f), 0.5f);
	TestCase_assertHSVColor3fApproximate(hsv3f, HSVC3f(5.5f, 1.0f, 1.0f), TOLERANCE);
	
	hsv3f = HSVColor3f_interpolate(HSVC3f(5.0f, 1.0f, 1.0f), HSVC3f(1.0f, 1.0f, 1.0f), 0.25f);
	TestCase_assertHSVColor3fApproximate(hsv3f, HSVC3f(5.5f, 1.0f, 1.0f), TOLERANCE);
	
	hsv3f = HSVColor3f_interpolate(HSVC3f(5.0f, 1.0f, 1.0f), HSVC3f(1.0f, 1.0f, 1.0f), 0.75f);
	TestCase_assertHSVColor3fApproximate(hsv3f, HSVC3f(0.5f, 1.0f, 1.0f), TOLERANCE);
	
	hsv3f = HSVColor3f_interpolate(HSVC3f(1.0f, 1.0f, 1.0f), HSVC3f(5.0f, 1.0f, 1.0f), 0.25f);
	TestCase_assertHSVColor3fApproximate(hsv3f, HSVC3f(0.5f, 1.0f, 1.0f), TOLERANCE);
	
	hsv3f = HSVColor3f_interpolate(HSVC3f(1.0f, 1.0f, 1.0f), HSVC3f(5.0f, 1.0f, 1.0f), 0.75f);
	TestCase_assertHSVColor3fApproximate(hsv3f, HSVC3f(5.5f, 1.0f, 1.0f), TOLERANCE);
	
	
	Color3f rgb3f = Color3f_interpolateHSV(C3f(1.0f, 0.0f, 0.0f), C3f(0.0f, 1.0f, 0.0f), 0.5f);
	TestCase_assertColor3fApproximate(rgb3f, C3f(1.0f, 1.0f, 0.0f), TOLERANCE);
	
	rgb3f = Color3f_interpolateHSV(C3f(0.0f, 0.5f, 0.0f), C3f(0.0f, 0.0f, 1.0f), 0.75f);
	TestCase_assertColor3fApproximate(rgb3f, C3f(0.0f, 0.4375f, 0.875f), TOLERANCE);
	
	
	Color4f rgb4f = Color4f_interpolateHSV(C4f(1.0f, 0.0f, 0.0f, 0.5f), C4f(0.0f, 1.0f, 0.0f, 1.0f), 0.5f);
	TestCase_assertColor4fApproximate(rgb4f, C4f(1.0f, 1.0f, 0.0f, 0.75f), TOLERANCE);
	
	rgb4f = Color4f_interpolateHSV(C4f(0.0f, 0.5f, 0.0f, 1.0f), C4f(0.0f, 0.0f, 1.0f, 0.0f), 0.75f);
	TestCase_assertColor4fApproximate(rgb4f, C4f(0.0f, 0.4375f, 0.875f, 0.25f), TOLERANCE);
	
	
	rgb3f = Color3f_interpolateHSV(C3f(0.0f, 1.0f, 0.0f), C3f(0.0f, 0.0f, 0.0f), 0.25f);
	TestCase_assertColor3fApproximate(rgb3f, C3f(0.1875f, 0.75f, 0.1875f), TOLERANCE);
	
	rgb3f = Color3f_interpolateHSV(C3f(0.0f, 0.0f, 0.0f), C3f(0.0f, 0.0f, 1.0f), 0.75f);
	TestCase_assertColor3fApproximate(rgb3f, C3f(0.1875f, 0.1875f, 0.75f), TOLERANCE);
	
	rgb4f = Color4f_interpolateHSV(C4f(0.0f, 1.0f, 0.0f, 1.0f), C4f(0.0f, 0.0f, 0.0f, 1.0f), 0.25f);
	TestCase_assertColor4fApproximate(rgb4f, C4f(0.1875f, 0.75f, 0.1875f, 1.0f), TOLERANCE);
	
	rgb4f = Color4f_interpolateHSV(C4f(0.0f, 0.0f, 0.0f, 1.0f), C4f(0.0f, 0.0f, 1.0f, 1.0f), 0.75f);
	TestCase_assertColor4fApproximate(rgb4f, C4f(0.1875f, 0.1875f, 0.75f, 1.0f), TOLERANCE);
}

TEST_SUITE(ColorTest,
           testConstructors,
           testConversions,
           testIsEqual,
           testInterpolate,
           testMultiply,
           testPremultiply,
           testHSV,
           testHSVInterpolation)
