#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_assertFloatEqual(color3f.red, 0.0f);
	TestCase_assertFloatEqual(color3f.green, 0.5f);
	TestCase_assertFloatEqual(color3f.blue, 1.0f);
	color3f = COLOR3f(0.25f, 0.75f, 0.125f);
	TestCase_assertFloatEqual(color3f.red, 0.25f);
	TestCase_assertFloatEqual(color3f.green, 0.75f);
	TestCase_assertFloatEqual(color3f.blue, 0.125f);
	color3f = C3f(0.0f, 0.5f, 1.0f);
	TestCase_assertFloatEqual(color3f.red, 0.0f);
	TestCase_assertFloatEqual(color3f.green, 0.5f);
	TestCase_assertFloatEqual(color3f.blue, 1.0f);
	color3f = C3f(0.25f, 0.75f, 0.125f);
	TestCase_assertFloatEqual(color3f.red, 0.25f);
	TestCase_assertFloatEqual(color3f.green, 0.75f);
	TestCase_assertFloatEqual(color3f.blue, 0.125f);
	
	Color3ub color3ub = COLOR3ub(0x00, 0x7F, 0xFF);
	TestCase_assertXIntEqual(color3ub.red, 0x00);
	TestCase_assertXIntEqual(color3ub.green, 0x7F);
	TestCase_assertXIntEqual(color3ub.blue, 0xFF);
	color3ub = COLOR3ub(0x3F, 0xBF, 0x1F);
	TestCase_assertXIntEqual(color3ub.red, 0x3F);
	TestCase_assertXIntEqual(color3ub.green, 0xBF);
	TestCase_assertXIntEqual(color3ub.blue, 0x1F);
	color3ub = C3ub(0x00, 0x7F, 0xFF);
	TestCase_assertXIntEqual(color3ub.red, 0x00);
	TestCase_assertXIntEqual(color3ub.green, 0x7F);
	TestCase_assertXIntEqual(color3ub.blue, 0xFF);
	color3ub = C3ub(0x3F, 0xBF, 0x1F);
	TestCase_assertXIntEqual(color3ub.red, 0x3F);
	TestCase_assertXIntEqual(color3ub.green, 0xBF);
	TestCase_assertXIntEqual(color3ub.blue, 0x1F);
	
	Color4f color4f = COLOR4f(0.0f, 0.5f, 1.0f, 0.25f);
	TestCase_assertFloatEqual(color4f.red, 0.0f);
	TestCase_assertFloatEqual(color4f.green, 0.5f);
	TestCase_assertFloatEqual(color4f.blue, 1.0f);
	TestCase_assertFloatEqual(color4f.alpha, 0.25f);
	color4f = COLOR4f(0.25f, 0.75f, 0.125f, 0.625f);
	TestCase_assertFloatEqual(color4f.red, 0.25f);
	TestCase_assertFloatEqual(color4f.green, 0.75f);
	TestCase_assertFloatEqual(color4f.blue, 0.125f);
	TestCase_assertFloatEqual(color4f.alpha, 0.625f);
	color4f = C4f(0.0f, 0.5f, 1.0f, 0.25f);
	TestCase_assertFloatEqual(color4f.red, 0.0f);
	TestCase_assertFloatEqual(color4f.green, 0.5f);
	TestCase_assertFloatEqual(color4f.blue, 1.0f);
	TestCase_assertFloatEqual(color4f.alpha, 0.25f);
	color4f = C4f(0.25f, 0.75f, 0.125f, 0.625f);
	TestCase_assertFloatEqual(color4f.red, 0.25f);
	TestCase_assertFloatEqual(color4f.green, 0.75f);
	TestCase_assertFloatEqual(color4f.blue, 0.125f);
	TestCase_assertFloatEqual(color4f.alpha, 0.625f);
	
	Color4ub color4ub = COLOR4ub(0x00, 0x7F, 0xFF, 0x3F);
	TestCase_assertXIntEqual(color4ub.red, 0x00);
	TestCase_assertXIntEqual(color4ub.green, 0x7F);
	TestCase_assertXIntEqual(color4ub.blue, 0xFF);
	TestCase_assertXIntEqual(color4ub.alpha, 0x3F);
	color4ub = COLOR4ub(0x3F, 0xBF, 0x1F, 0x9F);
	TestCase_assertXIntEqual(color4ub.red, 0x3F);
	TestCase_assertXIntEqual(color4ub.green, 0xBF);
	TestCase_assertXIntEqual(color4ub.blue, 0x1F);
	TestCase_assertXIntEqual(color4ub.alpha, 0x9F);
	color4ub = C4ub(0x00, 0x7F, 0xFF, 0x3F);
	TestCase_assertXIntEqual(color4ub.red, 0x00);
	TestCase_assertXIntEqual(color4ub.green, 0x7F);
	TestCase_assertXIntEqual(color4ub.blue, 0xFF);
	TestCase_assertXIntEqual(color4ub.alpha, 0x3F);
	color4ub = C4ub(0x3F, 0xBF, 0x1F, 0x9F);
	TestCase_assertXIntEqual(color4ub.red, 0x3F);
	TestCase_assertXIntEqual(color4ub.green, 0xBF);
	TestCase_assertXIntEqual(color4ub.blue, 0x1F);
	TestCase_assertXIntEqual(color4ub.alpha, 0x9F);
	
	color3f = COLOR3f_UINT8(0x00, 0x7F, 0xFF);
	TestCase_assertFloatApproximate(color3f.red, 0.0f, TOLERANCE);
	TestCase_assertFloatApproximate(color3f.green, (float) 0x7F / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color3f.blue, 1.0f, TOLERANCE);
	color3f = COLOR3f_UINT8(0x3F, 0xBF, 0x1F);
	TestCase_assertFloatApproximate(color3f.red, (float) 0x3F / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color3f.green, (float) 0xBF / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color3f.blue, (float) 0x1F / (float) 0xFF, TOLERANCE);
	color3f = C3f_U8(0x00, 0x7F, 0xFF);
	TestCase_assertFloatApproximate(color3f.red, 0.0f, TOLERANCE);
	TestCase_assertFloatApproximate(color3f.green, (float) 0x7F / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color3f.blue, 1.0f, TOLERANCE);
	color3f = C3f_U8(0x3F, 0xBF, 0x1F);
	TestCase_assertFloatApproximate(color3f.red, (float) 0x3F / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color3f.green, (float) 0xBF / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color3f.blue, (float) 0x1F / (float) 0xFF, TOLERANCE);
	
	color4f = COLOR4f_UINT8(0x00, 0x7F, 0xFF, 0x3F);
	TestCase_assertFloatApproximate(color4f.red, 0.0f, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.green, (float) 0x7F / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.blue, 1.0f, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.alpha, (float) 0x3F / (float) 0xFF, TOLERANCE);
	color4f = COLOR4f_UINT8(0x3F, 0xBF, 0x1F, 0x9F);
	TestCase_assertFloatApproximate(color4f.red, (float) 0x3F / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.green, (float) 0xBF / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.blue, (float) 0x1F / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.alpha, (float) 0x9F / (float) 0xFF, TOLERANCE);
	color4f = C4f_U8(0x00, 0x7F, 0xFF, 0x3F);
	TestCase_assertFloatApproximate(color4f.red, 0.0f, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.green, (float) 0x7F / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.blue, 1.0f, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.alpha, (float) 0x3F / (float) 0xFF, TOLERANCE);
	color4f = C4f_U8(0x3F, 0xBF, 0x1F, 0x9F);
	TestCase_assertFloatApproximate(color4f.red, (float) 0x3F / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.green, (float) 0xBF / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.blue, (float) 0x1F / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.alpha, (float) 0x9F / (float) 0xFF, TOLERANCE);
	
	color4f = COLOR4f_PREMULTIPLIED(0.25f, 0.5f, 0.75f, 0.5f);
	TestCase_assertFloatEqual(color4f.red, 0.125f);
	TestCase_assertFloatEqual(color4f.green, 0.25f);
	TestCase_assertFloatEqual(color4f.blue, 0.375f);
	TestCase_assertFloatEqual(color4f.alpha, 0.5f);
	color4f = COLOR4f_PREMULTIPLIED(0.75f, 0.25f, 0.5f, 1.0f);
	TestCase_assertFloatEqual(color4f.red, 0.75f);
	TestCase_assertFloatEqual(color4f.green, 0.25f);
	TestCase_assertFloatEqual(color4f.blue, 0.5f);
	TestCase_assertFloatEqual(color4f.alpha, 1.0f);
	color4f = C4f_P(0.25f, 0.5f, 0.75f, 0.5f);
	TestCase_assertFloatEqual(color4f.red, 0.125f);
	TestCase_assertFloatEqual(color4f.green, 0.25f);
	TestCase_assertFloatEqual(color4f.blue, 0.375f);
	TestCase_assertFloatEqual(color4f.alpha, 0.5f);
	color4f = C4f_P(0.75f, 0.25f, 0.5f, 1.0f);
	TestCase_assertFloatEqual(color4f.red, 0.75f);
	TestCase_assertFloatEqual(color4f.green, 0.25f);
	TestCase_assertFloatEqual(color4f.blue, 0.5f);
	TestCase_assertFloatEqual(color4f.alpha, 1.0f);
	
	color4f = COLOR4f_UINT8_PREMULTIPLIED(0x3F, 0x7F, 0xBF, 0x7F);
	TestCase_assertFloatApproximate(color4f.red, (float) 0x3F * 0x7F / 0xFF / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.green, (float) 0x7F * 0x7F / 0xFF / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.blue, (float) 0xBF * 0x7F / 0xFF / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.alpha, (float) 0x7F / (float) 0xFF, TOLERANCE);
	color4f = COLOR4f_UINT8_PREMULTIPLIED(0xBF, 0x3F, 0x7F, 0xFF);
	TestCase_assertFloatApproximate(color4f.red, (float) 0xBF / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.green, (float) 0x3F / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.blue, (float) 0x7F / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.alpha, (float) 0xFF / (float) 0xFF, TOLERANCE);
	color4f = C4f_U8_P(0x3F, 0x7F, 0xBF, 0x7F);
	TestCase_assertFloatApproximate(color4f.red, (float) 0x3F * 0x7F / 0xFF / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.green, (float) 0x7F * 0x7F / 0xFF / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.blue, (float) 0xBF * 0x7F / 0xFF / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.alpha, (float) 0x7F / (float) 0xFF, TOLERANCE);
	color4f = C4f_U8_P(0xBF, 0x3F, 0x7F, 0xFF);
	TestCase_assertFloatApproximate(color4f.red, (float) 0xBF / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.green, (float) 0x3F / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.blue, (float) 0x7F / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.alpha, (float) 0xFF / (float) 0xFF, TOLERANCE);
	
	color4ub = COLOR4ub_PREMULTIPLIED(0x3F, 0x7F, 0xBF, 0x7F);
	TestCase_assertXIntEqual(color4ub.red, 0x3F * 0x7F / 0xFF);
	TestCase_assertXIntEqual(color4ub.green, 0x7F * 0x7F / 0xFF);
	TestCase_assertXIntEqual(color4ub.blue, 0xBF * 0x7F / 0xFF);
	TestCase_assertXIntEqual(color4ub.alpha, 0x7F);
	color4ub = COLOR4ub_PREMULTIPLIED(0xBF, 0x3F, 0x7F, 0xFF);
	TestCase_assertXIntEqual(color4ub.red, 0xBF);
	TestCase_assertXIntEqual(color4ub.green, 0x3F);
	TestCase_assertXIntEqual(color4ub.blue, 0x7F);
	TestCase_assertXIntEqual(color4ub.alpha, 0xFF);
	color4ub = C4ub_P(0x3F, 0x7F, 0xBF, 0x7F);
	TestCase_assertXIntEqual(color4ub.red, 0x3F * 0x7F / 0xFF);
	TestCase_assertXIntEqual(color4ub.green, 0x7F * 0x7F / 0xFF);
	TestCase_assertXIntEqual(color4ub.blue, 0xBF * 0x7F / 0xFF);
	TestCase_assertXIntEqual(color4ub.alpha, 0x7F);
	color4ub = C4ub_P(0xBF, 0x3F, 0x7F, 0xFF);
	TestCase_assertXIntEqual(color4ub.red, 0xBF);
	TestCase_assertXIntEqual(color4ub.green, 0x3F);
	TestCase_assertXIntEqual(color4ub.blue, 0x7F);
	TestCase_assertXIntEqual(color4ub.alpha, 0xFF);
	
	color3ub = COLOR3ub_UINT32(0x007FFF);
	TestCase_assertXIntEqual(color3ub.red, 0x00);
	TestCase_assertXIntEqual(color3ub.green, 0x7F);
	TestCase_assertXIntEqual(color3ub.blue, 0xFF);
	color3ub = COLOR3ub_UINT32(0x3FBF1F);
	TestCase_assertXIntEqual(color3ub.red, 0x3F);
	TestCase_assertXIntEqual(color3ub.green, 0xBF);
	TestCase_assertXIntEqual(color3ub.blue, 0x1F);
	color3ub = C3ub_U32(0x007FFF);
	TestCase_assertXIntEqual(color3ub.red, 0x00);
	TestCase_assertXIntEqual(color3ub.green, 0x7F);
	TestCase_assertXIntEqual(color3ub.blue, 0xFF);
	color3ub = C3ub_U32(0x3FBF1F);
	TestCase_assertXIntEqual(color3ub.red, 0x3F);
	TestCase_assertXIntEqual(color3ub.green, 0xBF);
	TestCase_assertXIntEqual(color3ub.blue, 0x1F);
	
	color3f = COLOR3f_UINT32(0x007FFF);
	TestCase_assertFloatApproximate(color3f.red, 0.0f, TOLERANCE);
	TestCase_assertFloatApproximate(color3f.green, (float) 0x7F / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color3f.blue, 1.0f, TOLERANCE);
	color3f = COLOR3f_UINT32(0x3FBF1F);
	TestCase_assertFloatApproximate(color3f.red, (float) 0x3F / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color3f.green, (float) 0xBF / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color3f.blue, (float) 0x1F / (float) 0xFF, TOLERANCE);
	color3f = C3f_U32(0x007FFF);
	TestCase_assertFloatApproximate(color3f.red, 0.0f, TOLERANCE);
	TestCase_assertFloatApproximate(color3f.green, (float) 0x7F / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color3f.blue, 1.0f, TOLERANCE);
	color3f = C3f_U32(0x3FBF1F);
	TestCase_assertFloatApproximate(color3f.red, (float) 0x3F / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color3f.green, (float) 0xBF / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color3f.blue, (float) 0x1F / (float) 0xFF, TOLERANCE);
	
	color4ub = COLOR4ub_UINT32(0x007FFF3F);
	TestCase_assertXIntEqual(color4ub.red, 0x00);
	TestCase_assertXIntEqual(color4ub.green, 0x7F);
	TestCase_assertXIntEqual(color4ub.blue, 0xFF);
	TestCase_assertXIntEqual(color4ub.alpha, 0x3F);
	color4ub = COLOR4ub_UINT32(0x3FBF1F9F);
	TestCase_assertXIntEqual(color4ub.red, 0x3F);
	TestCase_assertXIntEqual(color4ub.green, 0xBF);
	TestCase_assertXIntEqual(color4ub.blue, 0x1F);
	TestCase_assertXIntEqual(color4ub.alpha, 0x9F);
	color4ub = C4ub_U32(0x007FFF3F);
	TestCase_assertXIntEqual(color4ub.red, 0x00);
	TestCase_assertXIntEqual(color4ub.green, 0x7F);
	TestCase_assertXIntEqual(color4ub.blue, 0xFF);
	TestCase_assertXIntEqual(color4ub.alpha, 0x3F);
	color4ub = C4ub_U32(0x3FBF1F9F);
	TestCase_assertXIntEqual(color4ub.red, 0x3F);
	TestCase_assertXIntEqual(color4ub.green, 0xBF);
	TestCase_assertXIntEqual(color4ub.blue, 0x1F);
	TestCase_assertXIntEqual(color4ub.alpha, 0x9F);
	
	color4ub = COLOR4ub_UINT32_PREMULTIPLIED(0x3F7FBF7F);
	TestCase_assertXIntEqual(color4ub.red, 0x3F * 0x7F / 0xFF);
	TestCase_assertXIntEqual(color4ub.green, 0x7F * 0x7F / 0xFF);
	TestCase_assertXIntEqual(color4ub.blue, 0xBF * 0x7F / 0xFF);
	TestCase_assertXIntEqual(color4ub.alpha, 0x7F);
	color4ub = COLOR4ub_UINT32_PREMULTIPLIED(0xBF3F7FFF);
	TestCase_assertXIntEqual(color4ub.red, 0xBF);
	TestCase_assertXIntEqual(color4ub.green, 0x3F);
	TestCase_assertXIntEqual(color4ub.blue, 0x7F);
	TestCase_assertXIntEqual(color4ub.alpha, 0xFF);
	color4ub = C4ub_U32_P(0x3F7FBF7F);
	TestCase_assertXIntEqual(color4ub.red, 0x3F * 0x7F / 0xFF);
	TestCase_assertXIntEqual(color4ub.green, 0x7F * 0x7F / 0xFF);
	TestCase_assertXIntEqual(color4ub.blue, 0xBF * 0x7F / 0xFF);
	TestCase_assertXIntEqual(color4ub.alpha, 0x7F);
	color4ub = C4ub_U32_P(0xBF3F7FFF);
	TestCase_assertXIntEqual(color4ub.red, 0xBF);
	TestCase_assertXIntEqual(color4ub.green, 0x3F);
	TestCase_assertXIntEqual(color4ub.blue, 0x7F);
	TestCase_assertXIntEqual(color4ub.alpha, 0xFF);
	
	color4f = COLOR4f_UINT32(0x007FFF3F);
	TestCase_assertFloatApproximate(color4f.red, 0.0f, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.green, (float) 0x7F / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.blue, 1.0f, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.alpha, (float) 0x3F / (float) 0xFF, TOLERANCE);
	color4f = COLOR4f_UINT32(0x3FBF1F9F);
	TestCase_assertFloatApproximate(color4f.red, (float) 0x3F / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.green, (float) 0xBF / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.blue, (float) 0x1F / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.alpha, (float) 0x9F / (float) 0xFF, TOLERANCE);
	color4f = C4f_U32(0x007FFF3F);
	TestCase_assertFloatApproximate(color4f.red, 0.0f, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.green, (float) 0x7F / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.blue, 1.0f, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.alpha, (float) 0x3F / (float) 0xFF, TOLERANCE);
	color4f = C4f_U32(0x3FBF1F9F);
	TestCase_assertFloatApproximate(color4f.red, (float) 0x3F / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.green, (float) 0xBF / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.blue, (float) 0x1F / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.alpha, (float) 0x9F / (float) 0xFF, TOLERANCE);
	
	color4f = COLOR4f_UINT32_PREMULTIPLIED(0x3F7FBF7F);
	TestCase_assertFloatApproximate(color4f.red, (float) 0x3F * 0x7F / 0xFF / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.green, (float) 0x7F * 0x7F / 0xFF / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.blue, (float) 0xBF * 0x7F / 0xFF / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.alpha, (float) 0x7F / (float) 0xFF, TOLERANCE);
	color4f = COLOR4f_UINT32_PREMULTIPLIED(0xBF3F7FFF);
	TestCase_assertFloatApproximate(color4f.red, (float) 0xBF / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.green, (float) 0x3F / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.blue, (float) 0x7F / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.alpha, (float) 0xFF / (float) 0xFF, TOLERANCE);
	color4f = C4f_U32_P(0x3F7FBF7F);
	TestCase_assertFloatApproximate(color4f.red, (float) 0x3F * 0x7F / 0xFF / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.green, (float) 0x7F * 0x7F / 0xFF / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.blue, (float) 0xBF * 0x7F / 0xFF / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.alpha, (float) 0x7F / (float) 0xFF, TOLERANCE);
	color4f = C4f_U32_P(0xBF3F7FFF);
	TestCase_assertFloatApproximate(color4f.red, (float) 0xBF / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.green, (float) 0x3F / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.blue, (float) 0x7F / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.alpha, (float) 0xFF / (float) 0xFF, TOLERANCE);
	
	color3f = COLOR3f_WHITE;
	TestCase_assertFloatEqual(color3f.red, 1.0f);
	TestCase_assertFloatEqual(color3f.green, 1.0f);
	TestCase_assertFloatEqual(color3f.blue, 1.0f);
	color3f = COLOR3f_BLACK;
	TestCase_assertFloatEqual(color3f.red, 0.0f);
	TestCase_assertFloatEqual(color3f.green, 0.0f);
	TestCase_assertFloatEqual(color3f.blue, 0.0f);
	
	color3ub = COLOR3ub_WHITE;
	TestCase_assertXIntEqual(color3ub.red, 0xFF);
	TestCase_assertXIntEqual(color3ub.green, 0xFF);
	TestCase_assertXIntEqual(color3ub.blue, 0xFF);
	color3ub = COLOR3ub_BLACK;
	TestCase_assertXIntEqual(color3ub.red, 0x00);
	TestCase_assertXIntEqual(color3ub.green, 0x00);
	TestCase_assertXIntEqual(color3ub.blue, 0x00);
	
	color4f = COLOR4f_WHITE;
	TestCase_assertFloatEqual(color4f.red, 1.0f);
	TestCase_assertFloatEqual(color4f.green, 1.0f);
	TestCase_assertFloatEqual(color4f.blue, 1.0f);
	TestCase_assertFloatEqual(color4f.alpha, 1.0f);
	color4f = COLOR4f_BLACK;
	TestCase_assertFloatEqual(color4f.red, 0.0f);
	TestCase_assertFloatEqual(color4f.green, 0.0f);
	TestCase_assertFloatEqual(color4f.blue, 0.0f);
	TestCase_assertFloatEqual(color4f.alpha, 1.0f);
	color4f = COLOR4f_TRANSPARENT;
	TestCase_assertFloatEqual(color4f.red, 0.0f);
	TestCase_assertFloatEqual(color4f.green, 0.0f);
	TestCase_assertFloatEqual(color4f.blue, 0.0f);
	TestCase_assertFloatEqual(color4f.alpha, 0.0f);
	
	color4ub = COLOR4ub_WHITE;
	TestCase_assertXIntEqual(color4ub.red, 0xFF);
	TestCase_assertXIntEqual(color4ub.green, 0xFF);
	TestCase_assertXIntEqual(color4ub.blue, 0xFF);
	TestCase_assertXIntEqual(color4ub.alpha, 0xFF);
	color4ub = COLOR4ub_BLACK;
	TestCase_assertXIntEqual(color4ub.red, 0x00);
	TestCase_assertXIntEqual(color4ub.green, 0x00);
	TestCase_assertXIntEqual(color4ub.blue, 0x00);
	TestCase_assertXIntEqual(color4ub.alpha, 0xFF);
	color4ub = COLOR4ub_TRANSPARENT;
	TestCase_assertXIntEqual(color4ub.red, 0x00);
	TestCase_assertXIntEqual(color4ub.green, 0x00);
	TestCase_assertXIntEqual(color4ub.blue, 0x00);
	TestCase_assertXIntEqual(color4ub.alpha, 0x00);
}

static void testConversions(void) {
	Color3f color3f = COLOR3f_TRUNCATE(C4f(0.0f, 0.25f, 0.5f, 0.75f));
	TestCase_assertFloatEqual(color3f.red, 0.0f);
	TestCase_assertFloatEqual(color3f.green, 0.25f);
	TestCase_assertFloatEqual(color3f.blue, 0.5f);
	color3f = COLOR3f_TRUNCATE(C4f(1.0f, 0.75f, 0.25f, 0.125f));
	TestCase_assertFloatEqual(color3f.red, 1.0f);
	TestCase_assertFloatEqual(color3f.green, 0.75f);
	TestCase_assertFloatEqual(color3f.blue, 0.25f);
	
	Color4f color4f = COLOR4f_EXTEND3(C3f(0.0f, 0.25f, 0.5f), 0.75f);
	TestCase_assertFloatEqual(color4f.red, 0.0f);
	TestCase_assertFloatEqual(color4f.green, 0.25f);
	TestCase_assertFloatEqual(color4f.blue, 0.5f);
	TestCase_assertFloatEqual(color4f.alpha, 0.75f);
	color4f = COLOR4f_EXTEND3(C3f(1.0f, 0.75f, 0.25f), 0.125f);
	TestCase_assertFloatEqual(color4f.red, 1.0f);
	TestCase_assertFloatEqual(color4f.green, 0.75f);
	TestCase_assertFloatEqual(color4f.blue, 0.25f);
	TestCase_assertFloatEqual(color4f.alpha, 0.125f);
	
	color4f = COLOR4f_EXTEND3_PREMULTIPLY(C3f(0.0f, 0.25f, 0.5f), 0.5f);
	TestCase_assertFloatEqual(color4f.red, 0.0f);
	TestCase_assertFloatEqual(color4f.green, 0.125f);
	TestCase_assertFloatEqual(color4f.blue, 0.25f);
	TestCase_assertFloatEqual(color4f.alpha, 0.5f);
	color4f = COLOR4f_EXTEND3_PREMULTIPLY(C3f(1.0f, 0.75f, 0.25f), 0.25f);
	TestCase_assertFloatEqual(color4f.red, 0.25f);
	TestCase_assertFloatEqual(color4f.green, 0.1875f);
	TestCase_assertFloatEqual(color4f.blue, 0.0625f);
	TestCase_assertFloatEqual(color4f.alpha, 0.25f);
	
	Color3ub color3ub = COLOR3ub_TRUNCATE(C4ub(0x00, 0x3F, 0x7F, 0xBF));
	TestCase_assertXIntEqual(color3ub.red, 0x00);
	TestCase_assertXIntEqual(color3ub.green, 0x3F);
	TestCase_assertXIntEqual(color3ub.blue, 0x7F);
	color3ub = COLOR3ub_TRUNCATE(C4ub(0xFF, 0xBF, 0x3F, 0x1F));
	TestCase_assertXIntEqual(color3ub.red, 0xFF);
	TestCase_assertXIntEqual(color3ub.green, 0xBF);
	TestCase_assertXIntEqual(color3ub.blue, 0x3F);
	
	Color4ub color4ub = COLOR4ub_EXTEND3(C3ub(0x00, 0x3F, 0x7F), 0xBF);
	TestCase_assertXIntEqual(color4ub.red, 0x00);
	TestCase_assertXIntEqual(color4ub.green, 0x3F);
	TestCase_assertXIntEqual(color4ub.blue, 0x7F);
	TestCase_assertXIntEqual(color4ub.alpha, 0xBF);
	color4ub = COLOR4ub_EXTEND3(C3ub(0xFF, 0xBF, 0x3F), 0x1F);
	TestCase_assertXIntEqual(color4ub.red, 0xFF);
	TestCase_assertXIntEqual(color4ub.green, 0xBF);
	TestCase_assertXIntEqual(color4ub.blue, 0x3F);
	TestCase_assertXIntEqual(color4ub.alpha, 0x1F);
	
	color4ub = COLOR4ub_EXTEND3_PREMULTIPLY(C3ub(0x00, 0x3F, 0x7F), 0x7F);
	TestCase_assertXIntEqual(color4ub.red, 0x00);
	TestCase_assertXIntEqual(color4ub.green, 0x1F);
	TestCase_assertXIntEqual(color4ub.blue, 0x3F);
	TestCase_assertXIntEqual(color4ub.alpha, 0x7F);
	color4ub = COLOR4ub_EXTEND3_PREMULTIPLY(C3ub(0xFF, 0xBF, 0x3F), 0x3F);
	TestCase_assertXIntEqual(color4ub.red, 0x3F);
	TestCase_assertXIntEqual(color4ub.green, 0x2F);
	TestCase_assertXIntEqual(color4ub.blue, 0x0F);
	TestCase_assertXIntEqual(color4ub.alpha, 0x3F);
	
	color3f = Color3ub_toColor3f(C3ub(0x3F, 0x7F, 0xBF));
	TestCase_assertFloatApproximate(color3f.red, (float) 0x3F / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color3f.green, (float) 0x7F / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color3f.blue, (float) 0xBF / (float) 0xFF, TOLERANCE);
	color3f = Color3ub_toColor3f(C3ub(0x00, 0x3F, 0x7F));
	TestCase_assertFloatApproximate(color3f.red, (float) 0x00 / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color3f.green, (float) 0x3F / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color3f.blue, (float) 0x7F / (float) 0xFF, TOLERANCE);
	color3ub = Color3f_toColor3ub(C3f(0.25f, 0.5f, 0.75f));
	TestCase_assertXIntEqual(color3ub.red, 0x40);
	TestCase_assertXIntEqual(color3ub.green, 0x80);
	TestCase_assertXIntEqual(color3ub.blue, 0xBF);
	color3ub = Color3f_toColor3ub(C3f(0.0f, 0.25f, 0.5f));
	TestCase_assertXIntEqual(color3ub.red, 0x00);
	TestCase_assertXIntEqual(color3ub.green, 0x40);
	TestCase_assertXIntEqual(color3ub.blue, 0x80);
	color4f = Color4ub_toColor4f(C4ub(0x3F, 0x7F, 0xBF, 0xFF));
	TestCase_assertFloatApproximate(color4f.red, (float) 0x3F / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.green, (float) 0x7F / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.blue, (float) 0xBF / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.alpha, (float) 0xFF / (float) 0xFF, TOLERANCE);
	color4f = Color4ub_toColor4f(C4ub(0x00, 0x3F, 0x7F, 0xBF));
	TestCase_assertFloatApproximate(color4f.red, (float) 0x00 / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.green, (float) 0x3F / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.blue, (float) 0x7F / (float) 0xFF, TOLERANCE);
	TestCase_assertFloatApproximate(color4f.alpha, (float) 0xBF / (float) 0xFF, TOLERANCE);
	color4ub = Color4f_toColor4ub(C4f(0.25f, 0.5f, 0.75f, 1.0f));
	TestCase_assertXIntEqual(color4ub.red, 0x40);
	TestCase_assertXIntEqual(color4ub.green, 0x80);
	TestCase_assertXIntEqual(color4ub.blue, 0xBF);
	TestCase_assertXIntEqual(color4ub.alpha, 0xFF);
	color4ub = Color4f_toColor4ub(C4f(0.0f, 0.25f, 0.5f, 0.75f));
	TestCase_assertXIntEqual(color4ub.red, 0x00);
	TestCase_assertXIntEqual(color4ub.green, 0x40);
	TestCase_assertXIntEqual(color4ub.blue, 0x80);
	TestCase_assertXIntEqual(color4ub.alpha, 0xBF);
	
	color3ub = Color3ub_fromUInt32(0x1F3F5F);
	TestCase_assertXIntEqual(color3ub.red, 0x1F);
	TestCase_assertXIntEqual(color3ub.green, 0x3F);
	TestCase_assertXIntEqual(color3ub.blue, 0x5F);
	color3ub = Color3ub_fromUInt32(0x3F7FBF);
	TestCase_assertXIntEqual(color3ub.red, 0x3F);
	TestCase_assertXIntEqual(color3ub.green, 0x7F);
	TestCase_assertXIntEqual(color3ub.blue, 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_assertXIntEqual(color4ub.red, 0x1F);
	TestCase_assertXIntEqual(color4ub.green, 0x3F);
	TestCase_assertXIntEqual(color4ub.blue, 0x5F);
	TestCase_assertXIntEqual(color4ub.alpha, 0x7F);
	color4ub = Color4ub_fromUInt32(0x3F7FBFFF);
	TestCase_assertXIntEqual(color4ub.red, 0x3F);
	TestCase_assertXIntEqual(color4ub.green, 0x7F);
	TestCase_assertXIntEqual(color4ub.blue, 0xBF);
	TestCase_assertXIntEqual(color4ub.alpha, 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_assertFloatEqual(color3f.red, 0.125f);
	TestCase_assertFloatEqual(color3f.green, 0.25f);
	TestCase_assertFloatEqual(color3f.blue, 0.375f);
	color3f = Color3f_interpolate(C3f(1.0f, 0.5f, 0.0f), C3f(0.5f, 0.0f, 1.0f), 0.25f);
	TestCase_assertFloatEqual(color3f.red, 0.875f);
	TestCase_assertFloatEqual(color3f.green, 0.375f);
	TestCase_assertFloatEqual(color3f.blue, 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_assertFloatEqual(color4f.red, 0.125f);
	TestCase_assertFloatEqual(color4f.green, 0.25f);
	TestCase_assertFloatEqual(color4f.blue, 0.375f);
	TestCase_assertFloatEqual(color4f.alpha, 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_assertFloatEqual(color4f.red, 0.875f);
	TestCase_assertFloatEqual(color4f.green, 0.375f);
	TestCase_assertFloatEqual(color4f.blue, 0.25f);
	TestCase_assertFloatEqual(color4f.alpha, 1.0f);
	
	Color3ub color3ub = Color3ub_interpolate(C3ub(0x00, 0x00, 0x00), C3ub(0x3F, 0x7F, 0xBF), 0.5f);
	TestCase_assertXIntEqual(color3ub.red, 0x20);
	TestCase_assertXIntEqual(color3ub.green, 0x40);
	TestCase_assertXIntEqual(color3ub.blue, 0x60);
	color3ub = Color3ub_interpolate(C3ub(0xFF, 0x7F, 0x00), C3ub(0x7F, 0x00, 0xFF), 0.25f);
	TestCase_assertXIntEqual(color3ub.red, 0xDF);
	TestCase_assertXIntEqual(color3ub.green, 0x5F);
	TestCase_assertXIntEqual(color3ub.blue, 0x40);
	
	Color4ub color4ub = Color4ub_interpolate(C4ub(0x00, 0x00, 0x00, 0x00), C4ub(0x3F, 0x7F, 0xBF, 0xFF), 0.5f);
	TestCase_assertXIntEqual(color4ub.red, 0x20);
	TestCase_assertXIntEqual(color4ub.green, 0x40);
	TestCase_assertXIntEqual(color4ub.blue, 0x60);
	TestCase_assertXIntEqual(color4ub.alpha, 0x80);
	color4ub = Color4ub_interpolate(C4ub(0xFF, 0x7F, 0x00, 0xFF), C4ub(0x7F, 0x00, 0xFF, 0xFF), 0.25f);
	TestCase_assertXIntEqual(color4ub.red, 0xDF);
	TestCase_assertXIntEqual(color4ub.green, 0x5F);
	TestCase_assertXIntEqual(color4ub.blue, 0x40);
	TestCase_assertXIntEqual(color4ub.alpha, 0xFF);
}

static void testMultiply(void) {
	Color3f color3f = Color3f_multiply(C3f(1.0f, 0.5f, 0.25f), C3f(0.5f, 0.25f, 2.0f));
	TestCase_assertFloatEqual(color3f.red, 0.5f);
	TestCase_assertFloatEqual(color3f.green, 0.125f);
	TestCase_assertFloatEqual(color3f.blue, 0.5f);
	color3f = Color3f_multiply(C3f(0.0f, 1.0f, 3.0f), C3f(1.0f, 0.75f, 3.0f));
	TestCase_assertFloatEqual(color3f.red, 0.0f);
	TestCase_assertFloatEqual(color3f.green, 0.75f);
	TestCase_assertFloatEqual(color3f.blue, 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_assertFloatEqual(color4f.red, 0.5f);
	TestCase_assertFloatEqual(color4f.green, 0.125f);
	TestCase_assertFloatEqual(color4f.blue, 0.5f);
	TestCase_assertFloatEqual(color4f.alpha, 0.125f);
	color4f = Color4f_multiply(C4f(0.0f, 1.0f, 3.0f, 0.5f), C4f(1.0f, 0.75f, 3.0f, 0.5f));
	TestCase_assertFloatEqual(color4f.red, 0.0f);
	TestCase_assertFloatEqual(color4f.green, 0.75f);
	TestCase_assertFloatEqual(color4f.blue, 9.0f);
	TestCase_assertFloatEqual(color4f.alpha, 0.25f);
	
	color3f = Color3f_multiplyScalar(C3f(0.125f, 0.25f, 0.5f), 2.0f);
	TestCase_assertFloatEqual(color3f.red, 0.25f);
	TestCase_assertFloatEqual(color3f.green, 0.5f);
	TestCase_assertFloatEqual(color3f.blue, 1.0f);
	color3f = Color3f_multiplyScalar(C3f(1.0f, 0.5f, 0.25f), 0.5f);
	TestCase_assertFloatEqual(color3f.red, 0.5f);
	TestCase_assertFloatEqual(color3f.green, 0.25f);
	TestCase_assertFloatEqual(color3f.blue, 0.125f);
	
	color4f = Color4f_multiplyScalar(C4f(0.125f, 0.25f, 0.5f, 1.0f), 2.0f);
	TestCase_assertFloatEqual(color4f.red, 0.25f);
	TestCase_assertFloatEqual(color4f.green, 0.5f);
	TestCase_assertFloatEqual(color4f.blue, 1.0f);
	TestCase_assertFloatEqual(color4f.alpha, 2.0f);
	color4f = Color4f_multiplyScalar(C4f(1.0f, 0.5f, 0.25f, 0.0f), 0.5f);
	TestCase_assertFloatEqual(color4f.red, 0.5f);
	TestCase_assertFloatEqual(color4f.green, 0.25f);
	TestCase_assertFloatEqual(color4f.blue, 0.125f);
	TestCase_assertFloatEqual(color4f.alpha, 0.0f);
}

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

static void testHSV(void) {
	HSVColor3f hsv3f = HSVCOLOR3f(0.0f, 0.5f, 1.0f);
	TestCase_assertFloatEqual(hsv3f.hue, 0.0f);
	TestCase_assertFloatEqual(hsv3f.saturation, 0.5f);
	TestCase_assertFloatEqual(hsv3f.value, 1.0f);
	hsv3f = HSVCOLOR3f(1.0f, 0.25f, 0.5f);
	TestCase_assertFloatEqual(hsv3f.hue, 1.0f);
	TestCase_assertFloatEqual(hsv3f.saturation, 0.25f);
	TestCase_assertFloatEqual(hsv3f.value, 0.5f);
	hsv3f = HSVC3f(0.0f, 0.5f, 1.0f);
	TestCase_assertFloatEqual(hsv3f.hue, 0.0f);
	TestCase_assertFloatEqual(hsv3f.saturation, 0.5f);
	TestCase_assertFloatEqual(hsv3f.value, 1.0f);
	hsv3f = HSVC3f(1.0f, 0.25f, 0.5f);
	TestCase_assertFloatEqual(hsv3f.hue, 1.0f);
	TestCase_assertFloatEqual(hsv3f.saturation, 0.25f);
	TestCase_assertFloatEqual(hsv3f.value, 0.5f);
	
	hsv3f = Color3f_RGBToHSV(C3f(0.0f, 1.0f, 0.0f));
	TestCase_assertFloatEqual(hsv3f.hue, 2.0f);
	TestCase_assertFloatEqual(hsv3f.saturation, 1.0f);
	TestCase_assertFloatEqual(hsv3f.value, 1.0f);
	hsv3f = Color3f_RGBToHSV(C3f(0.25f, 0.375f, 0.5f));
	TestCase_assertFloatApproximate(hsv3f.hue, 3.5f, TOLERANCE);
	TestCase_assertFloatApproximate(hsv3f.saturation, 0.5f, TOLERANCE);
	TestCase_assertFloatApproximate(hsv3f.value, 0.5f, TOLERANCE);
	
	Color3f color3f = Color3f_HSVToRGB(HSVC3f(2.0f, 1.0f, 1.0f));
	TestCase_assertFloatEqual(color3f.red, 0.0f);
	TestCase_assertFloatEqual(color3f.green, 1.0f);
	TestCase_assertFloatEqual(color3f.blue, 0.0f);
	color3f = Color3f_HSVToRGB(HSVC3f(3.5f, 0.5f, 0.5f));
	TestCase_assertFloatApproximate(color3f.red, 0.25f, TOLERANCE);
	TestCase_assertFloatApproximate(color3f.green, 0.375f, TOLERANCE);
	TestCase_assertFloatApproximate(color3f.blue, 0.5f, TOLERANCE);
	
	hsv3f = Color4f_RGBAToHSV(C4f(0.0f, 1.0f, 0.0f, 1.0f));
	TestCase_assertFloatEqual(hsv3f.hue, 2.0f);
	TestCase_assertFloatEqual(hsv3f.saturation, 1.0f);
	TestCase_assertFloatEqual(hsv3f.value, 1.0f);
	hsv3f = Color4f_RGBAToHSV(C4f(0.25f, 0.375f, 0.5f, 0.5f));
	TestCase_assertFloatApproximate(hsv3f.hue, 3.5f, TOLERANCE);
	TestCase_assertFloatApproximate(hsv3f.saturation, 0.5f, TOLERANCE);
	TestCase_assertFloatApproximate(hsv3f.value, 0.5f, TOLERANCE);
	
	Color4f color4f = Color4f_HSVToRGBA(HSVC3f(2.0f, 1.0f, 1.0f), 1.0f);
	TestCase_assertFloatEqual(color4f.red, 0.0f);
	TestCase_assertFloatEqual(color4f.green, 1.0f);
	TestCase_assertFloatEqual(color4f.blue, 0.0f);
	TestCase_assertFloatEqual(color4f.alpha, 1.0f);
	color4f = Color4f_HSVToRGBA(HSVC3f(3.5f, 0.5f, 0.5f), 0.5f);
	TestCase_assertFloatApproximate(color3f.red, 0.25f, TOLERANCE);
	TestCase_assertFloatApproximate(color3f.green, 0.375f, TOLERANCE);
	TestCase_assertFloatApproximate(color3f.blue, 0.5f, TOLERANCE);
	TestCase_assertFloatEqual(color4f.alpha, 0.5f);
}

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_assertFloatApproximate(hsv3f.hue, 0.5f, TOLERANCE);
	TestCase_assertFloatApproximate(hsv3f.saturation, 0.5f, TOLERANCE);
	TestCase_assertFloatApproximate(hsv3f.value, 0.5f, TOLERANCE);
	
	hsv3f = HSVColor3f_interpolate(HSVC3f(2.0f, 2.0f, 2.0f), HSVC3f(3.0f, 3.0f, 3.0f), 0.25f);
	TestCase_assertFloatApproximate(hsv3f.hue, 2.25f, TOLERANCE);
	TestCase_assertFloatApproximate(hsv3f.saturation, 2.25f, TOLERANCE);
	TestCase_assertFloatApproximate(hsv3f.value, 2.25f, TOLERANCE);
	
	hsv3f = HSVColor3f_interpolate(HSVC3f(5.0f, 1.0f, 1.0f), HSVC3f(0.0f, 1.0f, 1.0f), 0.5f);
	TestCase_assertFloatApproximate(hsv3f.hue, 5.5f, TOLERANCE);
	TestCase_assertFloatApproximate(hsv3f.saturation, 1.0f, TOLERANCE);
	TestCase_assertFloatApproximate(hsv3f.value, 1.0f, TOLERANCE);
	
	hsv3f = HSVColor3f_interpolate(HSVC3f(5.0f, 1.0f, 1.0f), HSVC3f(1.0f, 1.0f, 1.0f), 0.25f);
	TestCase_assertFloatApproximate(hsv3f.hue, 5.5f, TOLERANCE);
	TestCase_assertFloatApproximate(hsv3f.saturation, 1.0f, TOLERANCE);
	TestCase_assertFloatApproximate(hsv3f.value, 1.0f, TOLERANCE);
	
	hsv3f = HSVColor3f_interpolate(HSVC3f(5.0f, 1.0f, 1.0f), HSVC3f(1.0f, 1.0f, 1.0f), 0.75f);
	TestCase_assertFloatApproximate(hsv3f.hue, 0.5f, TOLERANCE);
	TestCase_assertFloatApproximate(hsv3f.saturation, 1.0f, TOLERANCE);
	TestCase_assertFloatApproximate(hsv3f.value, 1.0f, TOLERANCE);
	
	hsv3f = HSVColor3f_interpolate(HSVC3f(1.0f, 1.0f, 1.0f), HSVC3f(5.0f, 1.0f, 1.0f), 0.25f);
	TestCase_assertFloatApproximate(hsv3f.hue, 0.5f, TOLERANCE);
	TestCase_assertFloatApproximate(hsv3f.saturation, 1.0f, TOLERANCE);
	TestCase_assertFloatApproximate(hsv3f.value, 1.0f, TOLERANCE);
	
	hsv3f = HSVColor3f_interpolate(HSVC3f(1.0f, 1.0f, 1.0f), HSVC3f(5.0f, 1.0f, 1.0f), 0.75f);
	TestCase_assertFloatApproximate(hsv3f.hue, 5.5f, TOLERANCE);
	TestCase_assertFloatApproximate(hsv3f.saturation, 1.0f, TOLERANCE);
	TestCase_assertFloatApproximate(hsv3f.value, 1.0f, TOLERANCE);
	
	
	Color3f rgb3f = Color3f_interpolateHSV(C3f(1.0f, 0.0f, 0.0f), C3f(0.0f, 1.0f, 0.0f), 0.5f);
	TestCase_assertFloatApproximate(rgb3f.red, 1.0f, TOLERANCE);
	TestCase_assertFloatApproximate(rgb3f.green, 1.0f, TOLERANCE);
	TestCase_assertFloatApproximate(rgb3f.blue, 0.0f, TOLERANCE);
	
	rgb3f = Color3f_interpolateHSV(C3f(0.0f, 0.5f, 0.0f), C3f(0.0f, 0.0f, 1.0f), 0.75f);
	TestCase_assertFloatApproximate(rgb3f.red, 0.0f, TOLERANCE);
	TestCase_assertFloatApproximate(rgb3f.green, 0.4375f, TOLERANCE);
	TestCase_assertFloatApproximate(rgb3f.blue, 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_assertFloatApproximate(rgb4f.red, 1.0f, TOLERANCE);
	TestCase_assertFloatApproximate(rgb4f.green, 1.0f, TOLERANCE);
	TestCase_assertFloatApproximate(rgb4f.blue, 0.0f, TOLERANCE);
	TestCase_assertFloatApproximate(rgb4f.alpha, 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_assertFloatApproximate(rgb4f.red, 0.0f, TOLERANCE);
	TestCase_assertFloatApproximate(rgb4f.green, 0.4375f, TOLERANCE);
	TestCase_assertFloatApproximate(rgb4f.blue, 0.875f, TOLERANCE);
	TestCase_assertFloatApproximate(rgb4f.alpha, 0.25f, TOLERANCE);
	
	
	rgb3f = Color3f_interpolateHSV(C3f(0.0f, 1.0f, 0.0f), C3f(0.0f, 0.0f, 0.0f), 0.25f);
	TestCase_assertFloatApproximate(rgb3f.red, 0.1875f, TOLERANCE);
	TestCase_assertFloatApproximate(rgb3f.green, 0.75f, TOLERANCE);
	TestCase_assertFloatApproximate(rgb3f.blue, 0.1875f, TOLERANCE);
	
	rgb3f = Color3f_interpolateHSV(C3f(0.0f, 0.0f, 0.0f), C3f(0.0f, 0.0f, 1.0f), 0.75f);
	TestCase_assertFloatApproximate(rgb3f.red, 0.1875f, TOLERANCE);
	TestCase_assertFloatApproximate(rgb3f.green, 0.1875f, TOLERANCE);
	TestCase_assertFloatApproximate(rgb3f.blue, 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_assertFloatApproximate(rgb4f.red, 0.1875f, TOLERANCE);
	TestCase_assertFloatApproximate(rgb4f.green, 0.75f, TOLERANCE);
	TestCase_assertFloatApproximate(rgb4f.blue, 0.1875f, TOLERANCE);
	TestCase_assertFloatApproximate(rgb4f.alpha, 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_assertFloatApproximate(rgb4f.red, 0.1875f, TOLERANCE);
	TestCase_assertFloatApproximate(rgb4f.green, 0.1875f, TOLERANCE);
	TestCase_assertFloatApproximate(rgb4f.blue, 0.75f, TOLERANCE);
	TestCase_assertFloatApproximate(rgb4f.alpha, 1.0f, TOLERANCE);
}

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