#include "document/DocumentDirtyState.h"
#include "unittest/TestSuite.h"
#include <limits.h>

static void testInit(void) {
	DocumentDirtyState * dirtyState = DocumentDirtyState_create(1);
	TestCase_assertUIntEqual(dirtyState->fieldCount, 1);
	TestCase_assertPointerNonNULL(dirtyState->fields);
	TestCase_assertUIntEqual(dirtyState->fields[0], 0);
	TestCase_assertUIntEqual(dirtyState->masterValue, 0);
	DocumentDirtyState_dispose(dirtyState);
	
	dirtyState = DocumentDirtyState_create(2);
	TestCase_assertUIntEqual(dirtyState->fieldCount, 2);
	TestCase_assertPointerNonNULL(dirtyState->fields);
	TestCase_assertUIntEqual(dirtyState->fields[0], 0);
	TestCase_assertUIntEqual(dirtyState->fields[1], 0);
	TestCase_assertUIntEqual(dirtyState->masterValue, 0);
	DocumentDirtyState_dispose(dirtyState);
}

static void testCopy(void) {
	DocumentDirtyState * dirtyState = DocumentDirtyState_create(1);
	dirtyState->fields[0] = 4;
	dirtyState->masterValue = 2;
	DocumentDirtyState * copy = DocumentDirtyState_copy(dirtyState);
	DocumentDirtyState_dispose(dirtyState);
	TestCase_assertUIntEqual(copy->fieldCount, 1);
	TestCase_assertUIntEqual(copy->fields[0], 4);
	TestCase_assertUIntEqual(copy->masterValue, 2);
	DocumentDirtyState_dispose(copy);
	
	dirtyState = DocumentDirtyState_create(2);
	dirtyState->fields[0] = 1;
	dirtyState->fields[1] = 2;
	dirtyState->masterValue = 3;
	copy = DocumentDirtyState_copy(dirtyState);
	TestCase_assertUIntEqual(copy->fieldCount, 2);
	TestCase_assertUIntEqual(copy->fields[0], 1);
	TestCase_assertUIntEqual(copy->fields[1], 2);
	TestCase_assertUIntEqual(copy->masterValue, 3);
	
	dirtyState->fields[0] = 5;
	dirtyState->fields[1] = 3;
	dirtyState->masterValue = 7;
	DocumentDirtyState_copyStateFrom(copy, dirtyState);
	TestCase_assertUIntEqual(copy->fields[0], 5);
	TestCase_assertUIntEqual(copy->fields[1], 3);
	TestCase_assertUIntEqual(copy->masterValue, 7);
	
	dirtyState->fields[0] = 1;
	dirtyState->fields[1] = 1;
	dirtyState->masterValue = 1;
	DocumentDirtyState_copyStateFrom(copy, dirtyState);
	DocumentDirtyState_dispose(dirtyState);
	TestCase_assertUIntEqual(copy->fields[0], 1);
	TestCase_assertUIntEqual(copy->fields[1], 1);
	TestCase_assertUIntEqual(copy->masterValue, 1);
	DocumentDirtyState_dispose(copy);
}

static void testIsEqual(void) {
	DocumentDirtyState * dirtyState1 = DocumentDirtyState_create(2);
	DocumentDirtyState * dirtyState2 = DocumentDirtyState_create(2);
	TestCase_assertBoolTrue(DocumentDirtyState_isEqual(dirtyState1, dirtyState2));
	dirtyState1->fields[0] = 1;
	TestCase_assertBoolFalse(DocumentDirtyState_isEqual(dirtyState1, dirtyState2));
	dirtyState2->fields[0] = 1;
	dirtyState2->fields[1] = 1;
	TestCase_assertBoolFalse(DocumentDirtyState_isEqual(dirtyState1, dirtyState2));
	dirtyState1->fields[1] = 1;
	dirtyState1->masterValue = 1;
	TestCase_assertBoolFalse(DocumentDirtyState_isEqual(dirtyState1, dirtyState2));
	dirtyState2->masterValue = 1;
	TestCase_assertBoolTrue(DocumentDirtyState_isEqual(dirtyState1, dirtyState2));
	DocumentDirtyState_dispose(dirtyState1);
	DocumentDirtyState_dispose(dirtyState2);
}

static void testGetChangedBits(void) {
	DocumentDirtyState * dirtyState1 = DocumentDirtyState_create(3);
	DocumentDirtyState * dirtyState2 = DocumentDirtyState_create(3);
	DocumentDirtyStateBits changedBits = DocumentDirtyState_getChangedBits(dirtyState1, dirtyState2);
	TestCase_assertUIntEqual(changedBits, 0x0);
	
	dirtyState1->fields[0] = 1;
	changedBits = DocumentDirtyState_getChangedBits(dirtyState1, dirtyState2);
	TestCase_assertUIntEqual(changedBits, 0x1);
	
	dirtyState2->fields[0] = 1;
	dirtyState2->fields[1] = 1;
	changedBits = DocumentDirtyState_getChangedBits(dirtyState1, dirtyState2);
	TestCase_assertUIntEqual(changedBits, 0x2);
	
	dirtyState1->fields[0] = 3;
	dirtyState1->fields[1] = 1;
	dirtyState1->fields[2] = 4;
	changedBits = DocumentDirtyState_getChangedBits(dirtyState1, dirtyState2);
	TestCase_assertUIntEqual(changedBits, 0x5);
	DocumentDirtyState_dispose(dirtyState1);
	DocumentDirtyState_dispose(dirtyState2);
}

static void testInvalidate(void) {
	DocumentDirtyState * dirtyState = DocumentDirtyState_create(1);
	DocumentDirtyState_invalidate(dirtyState);
	TestCase_assertUIntEqual(dirtyState->fields[0], UINT_MAX);
	TestCase_assertUIntEqual(dirtyState->masterValue, UINT_MAX);
	DocumentDirtyState_dispose(dirtyState);
	
	dirtyState = DocumentDirtyState_create(2);
	DocumentDirtyState_invalidate(dirtyState);
	TestCase_assertUIntEqual(dirtyState->fields[0], UINT_MAX);
	TestCase_assertUIntEqual(dirtyState->fields[1], UINT_MAX);
	TestCase_assertUIntEqual(dirtyState->masterValue, UINT_MAX);
	DocumentDirtyState_dispose(dirtyState);
}

static void testAdvance(void) {
	DocumentDirtyState * dirtyState = DocumentDirtyState_create(3);
	TestCase_assertUIntEqual(dirtyState->fields[0], 0);
	TestCase_assertUIntEqual(dirtyState->fields[1], 0);
	TestCase_assertUIntEqual(dirtyState->fields[2], 0);
	TestCase_assertUIntEqual(dirtyState->masterValue, 0);
	DocumentDirtyState_advance(dirtyState, 0x1);
	TestCase_assertUIntEqual(dirtyState->fields[0], 1);
	TestCase_assertUIntEqual(dirtyState->fields[1], 0);
	TestCase_assertUIntEqual(dirtyState->fields[2], 0);
	TestCase_assertUIntEqual(dirtyState->masterValue, 1);
	
	DocumentDirtyState_advance(dirtyState, 0x6);
	TestCase_assertUIntEqual(dirtyState->fields[0], 1);
	TestCase_assertUIntEqual(dirtyState->fields[1], 1);
	TestCase_assertUIntEqual(dirtyState->fields[2], 1);
	TestCase_assertUIntEqual(dirtyState->masterValue, 2);
	
	DocumentDirtyState_advance(dirtyState, 0x5);
	TestCase_assertUIntEqual(dirtyState->fields[0], 2);
	TestCase_assertUIntEqual(dirtyState->fields[1], 1);
	TestCase_assertUIntEqual(dirtyState->fields[2], 2);
	TestCase_assertUIntEqual(dirtyState->masterValue, 3);
	DocumentDirtyState_dispose(dirtyState);
}

TEST_SUITE(DocumentDirtyStateTest,
           testInit,
           testCopy,
           testIsEqual,
           testGetChangedBits,
           testInvalidate,
           testAdvance)
