#include "utilities/UndoTree.h" #include "unittest/TestSuite.h" #include "unittest/TestUndoStateDelta.h" static void verifyInit(UndoTree * object, void * target, unsigned int line) { TestCase_assert(object->vtable == &UndoTree_class, "Expected %p but got %p (line %u)", &UndoTree_class, object->vtable, line); TestCase_assert(object->vtable->dispose == UndoTree_dispose, "Expected %p but got %p (line %u)", UndoTree_dispose, object->vtable->dispose, line); TestCase_assert(object->nodeCount == 0, "Expected 0 but got %u (line %u)", object->nodeCount, line); TestCase_assert(object->currentNodeID == 0, "Expected 0 but got %u (line %u)", object->currentNodeID, line); TestCase_assert(object->target == target, "Expected %p but got %p (line %u)", target, object->target, line); } static void testInit(void) { UndoTree object, * objectPtr; bool success; memset(&object, 0x00, sizeof(object)); stemobject_assign_vtable(object, UndoTree); success = UndoTree_init(&object, (void *) 0x1); TestCase_assertBoolTrue(success); verifyInit(&object, (void *) 0x1, __LINE__); UndoTree_dispose(&object); memset(&object, 0xFF, sizeof(object)); stemobject_assign_vtable(object, UndoTree); success = UndoTree_init(&object, (void *) 0x2); TestCase_assertBoolTrue(success); verifyInit(&object, (void *) 0x2, __LINE__); UndoTree_dispose(&object); objectPtr = UndoTree_create((void *) 0x3); TestCase_assertPointerNonNULL(objectPtr); if (objectPtr == NULL) { return; } // Suppress clang warning verifyInit(objectPtr, (void *) 0x3, __LINE__); UndoTree_dispose(objectPtr); } static void testBasicOperations(void) { UndoTree * undoTree = UndoTree_create((void *) 0x4); TestCase_assertBoolFalse(UndoTree_canUndo(undoTree)); TestCase_assertBoolFalse(UndoTree_canRedo(undoTree)); TestCase_assertUIntEqual(UndoTree_getRedoTimelineCountFromCurrentNode(undoTree), 0); TestCase_assertPointerNULL(UndoTree_getStateDeltaForUndo(undoTree)); TestCase_assertPointerNULL(UndoTree_getStateDeltaForRedo(undoTree)); TestCase_assertPointerNULL(UndoTree_getStateDeltaForRedoWithTimeline(undoTree, 0)); TestCase_assertBoolFalse(UndoTree_undo(undoTree)); TestCase_assertBoolFalse(UndoTree_redo(undoTree)); TestCase_assertBoolFalse(UndoTree_redoWithTimeline(undoTree, 0)); TestCase_assertBoolFalse(UndoTree_traverseToNode(undoTree, 0)); TestUndoStateDelta * stateDelta = TestUndoStateDelta_create(); TestCase_assertUIntEqual(undoTree->currentNodeID, 0); UndoTree_appendNode(undoTree, stateDelta, false); TestCase_assertUIntEqual(undoTree->currentNodeID, 1); TestCase_assertBoolTrue(UndoTree_canUndo(undoTree)); TestCase_assertBoolFalse(UndoTree_canRedo(undoTree)); TestCase_assertUIntEqual(UndoTree_getRedoTimelineCountFromCurrentNode(undoTree), 0); TestCase_assertPointerEqual(UndoTree_getStateDeltaForUndo(undoTree), stateDelta); TestCase_assertPointerNULL(UndoTree_getStateDeltaForRedo(undoTree)); TestCase_assertPointerNULL(UndoTree_getStateDeltaForRedoWithTimeline(undoTree, 0)); TestCase_assertBoolFalse(UndoTree_redo(undoTree)); TestCase_assertBoolFalse(UndoTree_redoWithTimeline(undoTree, 0)); TestCase_assertBoolFalse(UndoTree_traverseToNode(undoTree, 1)); TestCase_assertUIntEqual(stateDelta->revertCallCount, 0); TestCase_assertBoolTrue(UndoTree_undo(undoTree)); TestCase_assertUIntEqual(undoTree->currentNodeID, 0); TestCase_assertUIntEqual(stateDelta->revertCallCount, 1); TestCase_assertPointerEqual(stateDelta->lastTarget, (void *) 0x4); TestCase_assertBoolFalse(UndoTree_canUndo(undoTree)); TestCase_assertBoolTrue(UndoTree_canRedo(undoTree)); TestCase_assertUIntEqual(UndoTree_getRedoTimelineCountFromCurrentNode(undoTree), 1); TestCase_assertPointerNULL(UndoTree_getStateDeltaForUndo(undoTree)); TestCase_assertPointerEqual(UndoTree_getStateDeltaForRedo(undoTree), stateDelta); TestCase_assertPointerEqual(UndoTree_getStateDeltaForRedoWithTimeline(undoTree, 0), stateDelta); TestCase_assertPointerNULL(UndoTree_getStateDeltaForRedoWithTimeline(undoTree, 1)); TestCase_assertBoolFalse(UndoTree_undo(undoTree)); TestCase_assertBoolFalse(UndoTree_redoWithTimeline(undoTree, 1)); TestCase_assertBoolFalse(UndoTree_traverseToNode(undoTree, 0)); TestCase_assertUIntEqual(stateDelta->applyCallCount, 0); undoTree->target = (void *) 0x5; TestCase_assertBoolTrue(UndoTree_redo(undoTree)); TestCase_assertUIntEqual(undoTree->currentNodeID, 1); TestCase_assertUIntEqual(stateDelta->applyCallCount, 1); TestCase_assertPointerEqual(stateDelta->lastTarget, (void *) 0x5); TestCase_assertBoolTrue(UndoTree_undo(undoTree)); TestCase_assertUIntEqual(stateDelta->revertCallCount, 2); TestCase_assertPointerEqual(stateDelta->lastTarget, (void *) 0x5); undoTree->target = (void *) 0x6; TestCase_assertBoolFalse(UndoTree_redoWithTimeline(undoTree, 1)); TestCase_assertBoolTrue(UndoTree_redoWithTimeline(undoTree, 0)); TestCase_assertUIntEqual(undoTree->currentNodeID, 1); TestCase_assertUIntEqual(stateDelta->applyCallCount, 2); TestCase_assertPointerEqual(stateDelta->lastTarget, (void *) 0x6); TestUndoStateDelta * stateDelta2 = TestUndoStateDelta_create(); UndoTree_appendNode(undoTree, stateDelta2, false); TestCase_assertUIntEqual(undoTree->currentNodeID, 2); TestCase_assertBoolTrue(UndoTree_canUndo(undoTree)); TestCase_assertBoolFalse(UndoTree_canRedo(undoTree)); TestCase_assertUIntEqual(UndoTree_getRedoTimelineCountFromCurrentNode(undoTree), 0); TestCase_assertPointerEqual(UndoTree_getStateDeltaForUndo(undoTree), stateDelta2); TestCase_assertPointerNULL(UndoTree_getStateDeltaForRedo(undoTree)); TestCase_assertPointerNULL(UndoTree_getStateDeltaForRedoWithTimeline(undoTree, 0)); TestCase_assertBoolFalse(UndoTree_redo(undoTree)); TestCase_assertBoolFalse(UndoTree_redoWithTimeline(undoTree, 0)); TestCase_assertUIntEqual(stateDelta2->revertCallCount, 0); TestCase_assertBoolTrue(UndoTree_undo(undoTree)); TestCase_assertUIntEqual(undoTree->currentNodeID, 1); TestCase_assertUIntEqual(stateDelta2->revertCallCount, 1); TestCase_assertBoolTrue(UndoTree_canUndo(undoTree)); TestCase_assertBoolTrue(UndoTree_canRedo(undoTree)); TestCase_assertUIntEqual(UndoTree_getRedoTimelineCountFromCurrentNode(undoTree), 1); TestCase_assertPointerEqual(UndoTree_getStateDeltaForUndo(undoTree), stateDelta); TestCase_assertPointerEqual(UndoTree_getStateDeltaForRedo(undoTree), stateDelta2); TestCase_assertPointerEqual(UndoTree_getStateDeltaForRedoWithTimeline(undoTree, 0), stateDelta2); TestCase_assertPointerNULL(UndoTree_getStateDeltaForRedoWithTimeline(undoTree, 1)); TestCase_assertBoolTrue(UndoTree_traverseToNode(undoTree, 0)); TestCase_assertUIntEqual(undoTree->currentNodeID, 0); TestCase_assertUIntEqual(stateDelta->revertCallCount, 3); TestCase_assertBoolTrue(UndoTree_traverseToNode(undoTree, 2)); TestCase_assertUIntEqual(undoTree->currentNodeID, 2); TestCase_assertUIntEqual(stateDelta->applyCallCount, 3); TestCase_assertUIntEqual(stateDelta2->applyCallCount, 1); TestCase_assertUIntEqual(stateDelta->disposeCallCount, 0); TestCase_assertUIntEqual(stateDelta2->disposeCallCount, 0); UndoTree_dispose(undoTree); TestCase_assertUIntEqual(stateDelta->disposeCallCount, 1); TestCase_assertUIntEqual(stateDelta2->disposeCallCount, 1); free(stateDelta); } static void testTimelines(void) { UndoTree * undoTree = UndoTree_create(NULL); TestUndoStateDelta * stateDelta = TestUndoStateDelta_create(); UndoTree_appendNode(undoTree, stateDelta, true); TestCase_assertUIntEqual(stateDelta->revertCallCount, 0); TestCase_assertBoolTrue(UndoTree_undo(undoTree)); TestCase_assertUIntEqual(stateDelta->revertCallCount, 1); TestUndoStateDelta * stateDelta2 = TestUndoStateDelta_create(); TestCase_assertUIntEqual(stateDelta->disposeCallCount, 0); UndoTree_appendNode(undoTree, stateDelta2, true); TestCase_assertUIntEqual(stateDelta->disposeCallCount, 1); free(stateDelta); TestCase_assertUIntEqual(undoTree->nodeCount, 1); TestCase_assertUIntEqual(stateDelta2->revertCallCount, 0); TestCase_assertBoolTrue(UndoTree_undo(undoTree)); TestCase_assertUIntEqual(stateDelta2->revertCallCount, 1); TestCase_assertUIntEqual(UndoTree_getRedoTimelineCountFromCurrentNode(undoTree), 1); stateDelta = TestUndoStateDelta_create(); UndoTree_appendNode(undoTree, stateDelta, false); TestCase_assertUIntEqual(stateDelta->revertCallCount, 0); TestCase_assertBoolTrue(UndoTree_undo(undoTree)); TestCase_assertUIntEqual(stateDelta->revertCallCount, 1); TestCase_assertUIntEqual(UndoTree_getRedoTimelineCountFromCurrentNode(undoTree), 2); TestCase_assertUIntEqual(stateDelta->applyCallCount, 0); TestCase_assertBoolTrue(UndoTree_redo(undoTree)); TestCase_assertUIntEqual(stateDelta->applyCallCount, 1); TestCase_assertUIntEqual(stateDelta->revertCallCount, 1); TestCase_assertBoolTrue(UndoTree_undo(undoTree)); TestCase_assertUIntEqual(stateDelta->revertCallCount, 2); TestCase_assertUIntEqual(stateDelta->applyCallCount, 1); TestCase_assertBoolTrue(UndoTree_redoWithTimeline(undoTree, 1)); TestCase_assertUIntEqual(stateDelta->applyCallCount, 2); TestCase_assertUIntEqual(stateDelta->revertCallCount, 2); TestCase_assertBoolTrue(UndoTree_undo(undoTree)); TestCase_assertUIntEqual(stateDelta->revertCallCount, 3); TestCase_assertUIntEqual(stateDelta2->applyCallCount, 0); TestCase_assertBoolTrue(UndoTree_redoWithTimeline(undoTree, 0)); TestCase_assertUIntEqual(stateDelta2->applyCallCount, 1); TestCase_assertUIntEqual(stateDelta2->revertCallCount, 1); TestCase_assertBoolTrue(UndoTree_undo(undoTree)); TestCase_assertUIntEqual(stateDelta2->revertCallCount, 2); TestCase_assertUIntEqual(stateDelta2->applyCallCount, 1); TestCase_assertBoolTrue(UndoTree_redo(undoTree)); TestCase_assertUIntEqual(stateDelta2->applyCallCount, 2); TestCase_assertUIntEqual(stateDelta2->revertCallCount, 2); TestCase_assertUIntEqual(stateDelta->applyCallCount, 2); TestCase_assertBoolTrue(UndoTree_traverseToNode(undoTree, 3)); TestCase_assertUIntEqual(stateDelta2->revertCallCount, 3); TestCase_assertUIntEqual(stateDelta->applyCallCount, 3); TestUndoStateDelta * stateDelta3 = TestUndoStateDelta_create(); UndoTree_appendNode(undoTree, stateDelta3, false); TestCase_assertBoolTrue(UndoTree_undo(undoTree)); TestUndoStateDelta * stateDelta4 = TestUndoStateDelta_create(); UndoTree_appendNode(undoTree, stateDelta4, false); TestCase_assertBoolTrue(UndoTree_undo(undoTree)); TestCase_assertBoolTrue(UndoTree_undo(undoTree)); TestUndoStateDelta * stateDelta5 = TestUndoStateDelta_create(); TestCase_assertUIntEqual(stateDelta->disposeCallCount, 0); TestCase_assertUIntEqual(stateDelta2->disposeCallCount, 0); TestCase_assertUIntEqual(stateDelta3->disposeCallCount, 0); TestCase_assertUIntEqual(stateDelta4->disposeCallCount, 0); UndoTree_appendNode(undoTree, stateDelta5, true); TestCase_assertUIntEqual(stateDelta->disposeCallCount, 1); TestCase_assertUIntEqual(stateDelta2->disposeCallCount, 1); TestCase_assertUIntEqual(stateDelta3->disposeCallCount, 1); TestCase_assertUIntEqual(stateDelta4->disposeCallCount, 1); free(stateDelta); free(stateDelta2); free(stateDelta3); free(stateDelta4); stateDelta = TestUndoStateDelta_create(); UndoTree_appendNode(undoTree, stateDelta, false); stateDelta2 = TestUndoStateDelta_create(); UndoTree_appendNode(undoTree, stateDelta2, false); stateDelta3 = TestUndoStateDelta_create(); UndoTree_appendNode(undoTree, stateDelta3, false); TestCase_assertBoolTrue(UndoTree_undo(undoTree)); stateDelta4 = TestUndoStateDelta_create(); UndoTree_appendNode(undoTree, stateDelta4, false); TestCase_assertBoolTrue(UndoTree_undo(undoTree)); TestCase_assertBoolTrue(UndoTree_undo(undoTree)); stateDelta5 = TestUndoStateDelta_create(); TestCase_assertUIntEqual(stateDelta2->disposeCallCount, 0); TestCase_assertUIntEqual(stateDelta3->disposeCallCount, 0); TestCase_assertUIntEqual(stateDelta4->disposeCallCount, 0); UndoTree_appendNode(undoTree, stateDelta5, true); TestCase_assertUIntEqual(stateDelta2->disposeCallCount, 1); TestCase_assertUIntEqual(stateDelta3->disposeCallCount, 1); TestCase_assertUIntEqual(stateDelta4->disposeCallCount, 1); free(stateDelta2); free(stateDelta3); free(stateDelta4); TestCase_assertUIntEqual(stateDelta->disposeCallCount, 0); TestCase_assertUIntEqual(stateDelta5->disposeCallCount, 0); UndoTree_dispose(undoTree); TestCase_assertUIntEqual(stateDelta->disposeCallCount, 1); TestCase_assertUIntEqual(stateDelta5->disposeCallCount, 1); free(stateDelta); free(stateDelta5); } TEST_SUITE(UndoTreeTest, testInit, testBasicOperations, testTimelines)