package org.fxmisc.undo.impl;

import static org.junit.Assert.*;

import java.util.concurrent.CountDownLatch;

import org.fxmisc.undo.UndoManager;
import org.fxmisc.undo.UndoManagerFactory;
import org.junit.Test;
import org.reactfx.EventSource;

public class UndoManagerTest {

    @Test
    public void testMark() {
        EventSource<Integer> changes = new EventSource<>();
        UndoManager um = UndoManagerFactory.fixedSizeHistoryUndoManager(
                changes, c -> c, c -> {}, 4);

        assertTrue(um.atMarkedPositionProperty().get());
        changes.push(1);
        assertFalse(um.atMarkedPositionProperty().get());
        changes.push(2);
        um.mark();
        assertTrue(um.atMarkedPositionProperty().get());
        changes.push(3);
        changes.push(4);
        assertFalse(um.atMarkedPositionProperty().get());
        um.undo();
        um.undo();
        assertTrue(um.atMarkedPositionProperty().get());
        changes.push(3);
        changes.push(4);
        changes.push(5); // overflow
        changes.push(6);
        assertFalse(um.atMarkedPositionProperty().get());
    }

    @Test
    public void zeroHistoryUndoManagerMark() {
        EventSource<Integer> changes = new EventSource<>();
        UndoManager um = UndoManagerFactory.zeroHistoryUndoManager(changes);

        assertTrue(um.atMarkedPositionProperty().get());
        changes.push(1);
        assertFalse(um.atMarkedPositionProperty().get());
        changes.push(2);
        um.mark();
        assertTrue(um.atMarkedPositionProperty().get());
        changes.push(3);
        changes.push(4);
        assertFalse(um.atMarkedPositionProperty().get());
    }

    /**
     * Tests that isAtMarkedPosition() forces atMarkedPositionProperty()
     * become valid.
     */
    @Test
    public void testAtMarkedPositionRevalidation() {
        EventSource<Integer> changes = new EventSource<>();
        UndoManager um = UndoManagerFactory.zeroHistoryUndoManager(changes);

        um.atMarkedPositionProperty().get(); // atMarkedPositionProperty is now valid

        // we are going to expect two invalidations
        CountDownLatch latch = new CountDownLatch(2);
        um.atMarkedPositionProperty().addListener(observable -> latch.countDown());

        changes.push(1); // atMarkedPositionProperty has been invalidated
        assertEquals(1, latch.getCount());

        um.isAtMarkedPosition(); // we want to test whether this caused revalidation of atMarkedPositionProperty

        changes.push(2); // should have caused invalidation of atMarkedPositionProperty
        assertEquals(0, latch.getCount());
    }
}

@@ -237,16 +237,46 @@
 tSource;
+%0Aimport org.reactfx.value.Var;
 %0A%0Apublic
@@ -301,16 +301,738 @@
 Test %7B%0A%0A
+    @Test%0A    public void testUndoInvertsTheChange() %7B%0A        EventSource%3CInteger%3E changes = new EventSource%3C%3E();%0A        Var%3CInteger%3E lastAction = Var.newSimpleVar(null);%0A        UndoManager um = UndoManagerFactory.unlimitedHistoryUndoManager(%0A                changes, i -%3E -i, lastAction::setValue);%0A%0A        changes.push(3);%0A        changes.push(7);%0A        assertNull(lastAction.getValue());%0A%0A        um.undo();%0A        assertEquals(-7, lastAction.getValue().intValue());%0A%0A        um.undo();%0A        assertEquals(-3, lastAction.getValue().intValue());%0A%0A        um.redo();%0A        assertEquals(3, lastAction.getValue().intValue());%0A%0A        um.redo();%0A        assertEquals(7, lastAction.getValue().intValue());%0A    %7D%0A%0A
     @Tes

Add a test case.