summaryrefslogtreecommitdiff
path: root/sfx2/qa
diff options
context:
space:
mode:
authorFrank Schoenheit [fs] <frank.schoenheit@sun.com>2010-10-22 23:22:52 +0200
committerFrank Schoenheit [fs] <frank.schoenheit@sun.com>2010-10-22 23:22:52 +0200
commit2fb612b570fb29c64c7fce61f52e1cf772f11712 (patch)
tree1c564d444b4e084f2494ee27bd2d1640d75f0d1c /sfx2/qa
parent1caeea031494e004f0eea6d27024e50fde72ec86 (diff)
undoapi: yet more Undo API tests (will this ever end?)
Diffstat (limited to 'sfx2/qa')
-rwxr-xr-xsfx2/qa/complex/sfx2/UndoManager.java600
1 files changed, 370 insertions, 230 deletions
diff --git a/sfx2/qa/complex/sfx2/UndoManager.java b/sfx2/qa/complex/sfx2/UndoManager.java
index 2654dc58df17..5d3aaf2b097a 100755
--- a/sfx2/qa/complex/sfx2/UndoManager.java
+++ b/sfx2/qa/complex/sfx2/UndoManager.java
@@ -30,12 +30,14 @@ package complex.sfx2;
import com.sun.star.document.UndoManagerEvent;
import com.sun.star.document.XUndoAction;
import com.sun.star.lang.EventObject;
+import com.sun.star.lang.XEventListener;
import java.lang.reflect.Constructor;
import org.openoffice.test.tools.OfficeDocument;
import com.sun.star.document.XUndoManagerSupplier;
import complex.sfx2.undo.CalcDocumentTest;
import com.sun.star.document.XUndoManager;
import com.sun.star.document.XUndoManagerListener;
+import com.sun.star.lang.XComponent;
import com.sun.star.lang.XMultiServiceFactory;
import com.sun.star.uno.UnoRuntime;
import com.sun.star.uno.XComponentContext;
@@ -129,10 +131,12 @@ public class UndoManager
public void allActionsCleared( EventObject eo )
{
+ m_wasCleared = true;
}
public void redoActionsCleared( EventObject eo )
{
+ m_redoWasCleared = true;
}
public void enteredUndoContext( UndoManagerEvent i_event )
@@ -181,6 +185,8 @@ public class UndoManager
boolean isDisposed() { return m_isDisposed; }
boolean contextLeft() { return m_leftContext; }
boolean contextCancelled() { return m_cancelledContext; }
+ boolean stackWasCleared() { return m_wasCleared; }
+ boolean redoStackWasCleared() { return m_redoWasCleared; }
void reset()
{
@@ -188,7 +194,7 @@ public class UndoManager
m_activeUndoContexts.clear();
m_mostRecentlyAddedAction = m_mostRecentlyUndone = m_mostRecentlyRedone = null;
// m_isDisposed is not cleared, intentionally
- m_leftContext = m_cancelledContext = false;
+ m_leftContext = m_cancelledContext = m_wasCleared = m_redoWasCleared = false;
}
private int m_undoActionsAdded = 0;
@@ -197,6 +203,8 @@ public class UndoManager
private boolean m_isDisposed = false;
private boolean m_leftContext = false;
private boolean m_cancelledContext = false;
+ private boolean m_wasCleared = false;
+ private boolean m_redoWasCleared = false;
private Stack< String >
m_activeUndoContexts = new Stack<String>();
private String m_mostRecentlyAddedAction = null;
@@ -235,250 +243,333 @@ public class UndoManager
assertFalse( "clearing the Undo manager should result in the impossibility to undo anything", undoManager.isUndoPossible() );
assertFalse( "clearing the Undo manager should result in the impossibility to redo anything", undoManager.isRedoPossible() );
- // try retrieving the comments for the current Undo/Redo - this should fail
- boolean caughtExpected = false;
- try { undoManager.getCurrentUndoActionTitle(); undoManager.getCurrentRedoActionTitle(); }
- catch( final InvalidStateException e ) { caughtExpected = true; }
- assertTrue( "trying the title of the current Undo/Redo action is expected to fail for an empty stack", caughtExpected );
-
final UndoListener listener = new UndoListener();
undoManager.addUndoManagerListener( listener );
- // do a single modification to the document
- {
- test.doSingleModification();
- test.verifySingleModificationDocumentState();
-
- // undo the modification, ensure the listener got the proper notifications
- assertEquals( "We did not yet do a undo!", 0, listener.getUndoActionCount() );
- undoManager.undo();
- assertEquals( "A simple undo does not result in the proper Undo count.", 1, listener.getUndoActionCount() );
-
- // verify the document is in its initial state, again
- test.verifyInitialDocumentState();
-
- // redo the modification, ensure the listener got the proper notifications
- assertEquals( "did not yet do a redo!", 0, listener.getRedoActionCount() );
- undoManager.redo();
- assertEquals( "did a redo, but got no notification of it!", 1, listener.getRedoActionCount() );
-
- // ensure the document is in the proper state, again
- test.verifySingleModificationDocumentState();
+ impl_testSingleModification( test, undoManager, listener );
+ impl_testMultipleModifications( test, undoManager, listener );
+ impl_testCustomUndoActions( test, undoManager, listener );
+ impl_testLocking( test, undoManager, listener );
+ impl_testNestedContexts( undoManager, listener );
+ impl_testErrorHandling( test, undoManager, listener );
+ impl_testContextHandling( undoManager, listener );
+ impl_testStackHandling( undoManager, listener );
+ impl_testClearance( undoManager, listener );
- // now do an Undo via the UI (aka the dispatch API), and see if this works, and notifies the listener as
- // expected
- test.getDocument().getCurrentView().dispatch( ".uno:Undo" );
- test.verifyInitialDocumentState();
- assertEquals( "UI-Undo does not notify the listener", 2, listener.getUndoActionCount() );
- }
-
- // do multiple changes in a row, after entering an Undo context
- {
- listener.reset();
-
- assertEquals( "unexpected initial undo context depth", 0, listener.getUndoContextDepth() );
- undoManager.enterUndoContext( "Batch Changes" );
- assertEquals( "unexpected undo context depth after entering a context", 1, listener.getUndoContextDepth() );
+ // close the document, ensure the Undo manager listener gets notified
+ m_currentDocument.close();
+ assertTrue( "document is closed, but the UndoManagerListener has not been notified of the disposal", listener.isDisposed() );
+ m_currentDocument = null;
+ }
- assertEquals( "entering an Undo context has not been notified properly", "Batch Changes", listener.getCurrentUndoContextTitle() );
- final int modifications = test.doMultipleModifications();
- assertEquals( "unexpected number of undo actions while doing batch changes to the document",
- modifications, listener.getUndoActionsAdded() );
+ private void impl_testSingleModification( final DocumentTest i_test, final XUndoManager i_undoManager, final UndoListener i_listener ) throws com.sun.star.uno.Exception
+ {
+ i_test.doSingleModification();
+ i_test.verifySingleModificationDocumentState();
+
+ // undo the modification, ensure the listener got the proper notifications
+ assertEquals( "We did not yet do a undo!", 0, i_listener.getUndoActionCount() );
+ i_undoManager.undo();
+ assertEquals( "A simple undo does not result in the proper Undo count.",
+ 1, i_listener.getUndoActionCount() );
+
+ // verify the document is in its initial state, again
+ i_test.verifyInitialDocumentState();
+
+ // redo the modification, ensure the listener got the proper notifications
+ assertEquals( "did not yet do a redo!", 0, i_listener.getRedoActionCount() );
+ i_undoManager.redo();
+ assertEquals( "did a redo, but got no notification of it!", 1, i_listener.getRedoActionCount() );
+ // ensure the document is in the proper state, again
+ i_test.verifySingleModificationDocumentState();
+
+ // now do an Undo via the UI (aka the dispatch API), and see if this works, and notifies the listener as
+ // expected
+ i_test.getDocument().getCurrentView().dispatch( ".uno:Undo" );
+ i_test.verifyInitialDocumentState();
+ assertEquals( "UI-Undo does not notify the listener", 2, i_listener.getUndoActionCount() );
+ }
- assertEquals( "seems the document operations touched the undo context depth", 1, listener.getUndoContextDepth() );
- undoManager.leaveUndoContext();
- assertEquals( "unexpected undo context depth after leaving the last context", 0, listener.getUndoContextDepth() );
+ private void impl_testMultipleModifications( final DocumentTest i_test, final XUndoManager i_undoManager, final UndoListener i_listener ) throws com.sun.star.uno.Exception
+ {
+ i_listener.reset();
+ assertEquals( "unexpected initial undo context depth", 0, i_listener.getUndoContextDepth() );
+ i_undoManager.enterUndoContext( "Batch Changes" );
+ assertEquals( "unexpected undo context depth after entering a context",
+ 1, i_listener.getUndoContextDepth() );
+ assertEquals( "entering an Undo context has not been notified properly",
+ "Batch Changes", i_listener.getCurrentUndoContextTitle() );
+
+ final int modifications = i_test.doMultipleModifications();
+ assertEquals( "unexpected number of undo actions while doing batch changes to the document",
+ modifications, i_listener.getUndoActionsAdded() );
+ assertEquals( "seems the document operations touched the undo context depth",
+ 1, i_listener.getUndoContextDepth() );
+
+ i_undoManager.leaveUndoContext();
+ assertEquals( "unexpected undo context depth after leaving the last context",
+ 0, i_listener.getUndoContextDepth() );
+ assertEquals( "no Undo done, yet - still the listener has been notified of an Undo action",
+ 0, i_listener.getUndoActionCount() );
+
+ i_undoManager.undo();
+ assertEquals( "Just did an undo - the listener should have been notified", 1, i_listener.getUndoActionCount() );
+ i_test.verifyInitialDocumentState();
+ }
- assertEquals( "no Undo done, yet - still the listener has been notified of an Undo action", 0, listener.getUndoActionCount() );
- undoManager.undo();
- assertEquals( "Just did an undo - the listener should have been notified", 1, listener.getUndoActionCount() );
+ private void impl_testCustomUndoActions( final DocumentTest i_test, final XUndoManager i_undoManager, final UndoListener i_listener ) throws com.sun.star.uno.Exception
+ {
+ i_undoManager.clear();
+ i_listener.reset();
+ assertFalse( "undo stack not empty after clearing the undo manager", i_undoManager.isUndoPossible() );
+ assertFalse( "redo stack not empty after clearing the undo manager", i_undoManager.isRedoPossible() );
+ assertArrayEquals( ">0 descriptions for an empty undo stack?",
+ new String[0], i_undoManager.getAllUndoActionTitles() );
+ assertArrayEquals( ">0 descriptions for an empty redo stack?",
+ new String[0], i_undoManager.getAllRedoActionTitles() );
+
+ // add two actions, one directly, one within a context
+ final CustomUndoAction action1 = new CustomUndoAction( "UndoAction1" );
+ i_undoManager.addUndoAction( action1 );
+ assertEquals( "Adding an undo action not observed by the listener", 1, i_listener.getUndoActionsAdded() );
+ assertEquals( "Adding an undo action did not notify the proper title",
+ action1.getTitle(), i_listener.getMostRecentlyAddedActionTitle() );
+ final String contextTitle = "Undo Context";
+ i_undoManager.enterUndoContext( contextTitle );
+ final CustomUndoAction action2 = new CustomUndoAction( "UndoAction2" );
+ i_undoManager.addUndoAction( action2 );
+ assertEquals( "Adding an undo action not observed by the listener",
+ 2, i_listener.getUndoActionsAdded() );
+ assertEquals( "Adding an undo action did not notify the proper title",
+ action2.getTitle(), i_listener.getMostRecentlyAddedActionTitle() );
+ i_undoManager.leaveUndoContext();
+
+ // see if the manager has proper descriptions
+ assertArrayEquals( "unexpected Redo descriptions after adding two actions",
+ new String[0], i_undoManager.getAllRedoActionTitles() );
+ assertArrayEquals( "unexpected Undo descriptions after adding two actions",
+ new String[]{contextTitle, action1.getTitle()}, i_undoManager.getAllUndoActionTitles() );
+
+ // undo one action
+ i_undoManager.undo();
+ assertEquals( "improper action title notified during programmatic Undo",
+ contextTitle, i_listener.getMostRecentlyUndoneTitle() );
+ assertTrue( "nested custom undo action has not been undone as expected", action2.undoCalled() );
+ assertFalse( "nested custom undo action has not been undone as expected", action1.undoCalled() );
+ assertArrayEquals( "unexpected Redo descriptions after undoing a nested custom action",
+ new String[]{contextTitle}, i_undoManager.getAllRedoActionTitles() );
+ assertArrayEquals( "unexpected Undo descriptions after undoing a nested custom action",
+ new String[]{action1.getTitle()}, i_undoManager.getAllUndoActionTitles() );
+
+ // undo the second action, via UI dispatches
+ i_test.getDocument().getCurrentView().dispatch( ".uno:Undo" );
+ assertEquals( "improper action title notified during UI Undo", action1.getTitle(), i_listener.getMostRecentlyUndoneTitle() );
+ assertTrue( "nested custom undo action has not been undone as expected", action1.undoCalled() );
+ assertArrayEquals( "unexpected Redo descriptions after undoing the second custom action",
+ new String[]{action1.getTitle(), contextTitle}, i_undoManager.getAllRedoActionTitles() );
+ assertArrayEquals( "unexpected Undo descriptions after undoing the second custom action",
+ new String[0], i_undoManager.getAllUndoActionTitles() );
+
+ // check the actions are disposed when the stacks are cleared
+ i_undoManager.clear();
+ assertTrue( action1.disposed() && action2.disposed() );
- test.verifyInitialDocumentState();
- }
+ }
- // custom Undo actions
- {
- undoManager.clear();
- listener.reset();
- assertFalse( "undo stack not empty after clearing the undo manager", undoManager.isUndoPossible() );
- assertFalse( "redo stack not empty after clearing the undo manager", undoManager.isRedoPossible() );
- assertArrayEquals( ">0 descriptions for an empty undo stack?", new String[0], undoManager.getAllUndoActionTitles() );
- assertArrayEquals( ">0 descriptions for an empty redo stack?", new String[0], undoManager.getAllRedoActionTitles() );
-
- // add two actions, one directly, one within a context
- final CustomUndoAction action1 = new CustomUndoAction( "UndoAction1" );
- undoManager.addUndoAction( action1 );
- assertEquals( "Adding an undo action not observed by the listener", 1, listener.getUndoActionsAdded() );
- assertEquals( "Adding an undo action did not notify the proper title", action1.getTitle(), listener.getMostRecentlyAddedActionTitle() );
-
- final String contextTitle = "Undo Context";
- undoManager.enterUndoContext( contextTitle );
- final CustomUndoAction action2 = new CustomUndoAction( "UndoAction2" );
- undoManager.addUndoAction( action2 );
- assertEquals( "Adding an undo action not observed by the listener", 2, listener.getUndoActionsAdded() );
- assertEquals( "Adding an undo action did not notify the proper title", action2.getTitle(), listener.getMostRecentlyAddedActionTitle() );
- undoManager.leaveUndoContext();
-
- // see if the manager has proper descriptions
- assertArrayEquals( "unexpected Redo descriptions after adding two actions",
- new String[0], undoManager.getAllRedoActionTitles() );
- assertArrayEquals( "unexpected Undo descriptions after adding two actions",
- new String[] { contextTitle, action1.getTitle() }, undoManager.getAllUndoActionTitles() );
-
- // undo one action
- undoManager.undo();
- assertEquals( "improper action title notified during programmatic Undo", contextTitle, listener.getMostRecentlyUndoneTitle() );
- assertTrue( "nested custom undo action has not been undone as expected", action2.undoCalled() );
- assertFalse( "nested custom undo action has not been undone as expected", action1.undoCalled() );
- assertArrayEquals( "unexpected Redo descriptions after undoing a nested custom action",
- new String[] { contextTitle }, undoManager.getAllRedoActionTitles() );
- assertArrayEquals( "unexpected Undo descriptions after undoing a nested custom action",
- new String[] { action1.getTitle() }, undoManager.getAllUndoActionTitles() );
-
- // undo the second action, via UI dispatches
- test.getDocument().getCurrentView().dispatch( ".uno:Undo" );
- assertEquals( "improper action title notified during UI Undo", action1.getTitle(), listener.getMostRecentlyUndoneTitle() );
- assertTrue( "nested custom undo action has not been undone as expected", action1.undoCalled() );
- assertArrayEquals( "unexpected Redo descriptions after undoing the second custom action",
- new String[] { action1.getTitle(), contextTitle }, undoManager.getAllRedoActionTitles() );
- assertArrayEquals( "unexpected Undo descriptions after undoing the second custom action",
- new String[0], undoManager.getAllUndoActionTitles() );
- }
+ private void impl_testLocking( final DocumentTest i_test, final XUndoManager i_undoManager, final UndoListener i_listener ) throws com.sun.star.uno.Exception
+ {
+ i_undoManager.clear();
+ i_listener.reset();
+
+ // implicit Undo actions, triggered by changes to the document
+ assertFalse( "unexpected initial locking state", i_undoManager.isLocked() );
+ i_undoManager.lock();
+ assertTrue( "just locked the manager, why does it lie?", i_undoManager.isLocked() );
+ i_test.doSingleModification();
+ assertEquals( "when the Undo manager is locked, no implicit additions should happen",
+ 0, i_listener.getUndoActionsAdded() );
+ i_undoManager.unlock();
+ assertEquals( "unlock is not expected to add collected actions - they should be discarded",
+ 0, i_listener.getUndoActionsAdded() );
+ assertFalse( "just unlocked the manager, why does it lie?", i_undoManager.isLocked() );
+
+ // explicit Undo actions
+ i_undoManager.lock();
+ i_undoManager.addUndoAction( new CustomUndoAction() );
+ i_undoManager.unlock();
+ assertEquals( "explicit Undo actions are expected to be ignored when the manager is locked",
+ 0, i_listener.getUndoActionsAdded() );
+
+ // Undo contexts while being locked
+ i_undoManager.lock();
+ i_undoManager.enterUndoContext( "Dummy Context" );
+ i_undoManager.enterHiddenUndoContext();
+ assertEquals( "entering Undo contexts should be ignored when the manager is locked", 0, i_listener.getUndoContextDepth() );
+ i_undoManager.leaveUndoContext();
+ i_undoManager.leaveUndoContext();
+ i_undoManager.unlock();
+
+ // |unlock| error handling
+ assertFalse( "internal error: manager should not be locked at this point in time", i_undoManager.isLocked() );
+ boolean caughtExpected = false;
+ try { i_undoManager.unlock(); } catch ( final InvalidStateException e ) { caughtExpected = true; }
+ assertTrue( "unlocking the manager when it is not locked should throw", caughtExpected );
+ }
- // nesting of contexts
- {
- undoManager.clear();
- listener.reset();
- undoManager.enterUndoContext( "context 1" );
- undoManager.enterUndoContext( "context 1.1" );
- final CustomUndoAction action1 = new CustomUndoAction( "action 1.1.1" );
- undoManager.addUndoAction( action1 );
- undoManager.enterUndoContext( "context 1.1.2" );
- final CustomUndoAction action2 = new CustomUndoAction( "action 1.1.2.1" );
- undoManager.addUndoAction( action2 );
- undoManager.leaveUndoContext();
- final CustomUndoAction action3 = new CustomUndoAction( "action 1.1.3" );
- undoManager.addUndoAction( action3 );
- undoManager.leaveUndoContext();
- undoManager.leaveUndoContext();
- final CustomUndoAction action4 = new CustomUndoAction( "action 1.2" );
- undoManager.addUndoAction( action4 );
-
- undoManager.undo();
- assertEquals( "undoing a single action notifies a wrong title", action4.getTitle(), listener.getMostRecentlyUndoneTitle() );
- assertTrue( "custom Undo not called", action4.undoCalled() );
- assertFalse( "too many custom Undos called", action1.undoCalled() || action2.undoCalled() || action3.undoCalled() );
- undoManager.undo();
- assertTrue( "nested actions not properly undone", action1.undoCalled() && action2.undoCalled() && action3.undoCalled() );
- }
+ private void impl_testContextHandling( final XUndoManager i_undoManager, final UndoListener i_listener ) throws com.sun.star.uno.Exception
+ {
+ i_undoManager.clear();
+ i_listener.reset();
+
+ i_undoManager.enterUndoContext( "Undo Context" );
+ assertEquals( "unexpected undo context depth after entering a context", 1, i_listener.getUndoContextDepth() );
+ i_undoManager.addUndoAction( new CustomUndoAction() );
+ i_undoManager.leaveUndoContext();
+ assertTrue( "leaving a non-empty context does not call leftUndoContext", i_listener.contextLeft() );
+ assertFalse( "leaving a non-empty context should not call cancelledUndoContext", i_listener.contextCancelled() );
+ assertEquals( "unexpected undo context depth leaving a non-empty context", 0, i_listener.getUndoContextDepth() );
+
+ i_undoManager.clear();
+ i_listener.reset();
+
+ i_undoManager.enterUndoContext( "Undo Context" );
+ i_undoManager.leaveUndoContext();
+ assertFalse( "leaving an empty context should not call leftUndoContext", i_listener.contextLeft() );
+ assertTrue( "leaving an empty context does not call cancelledUndoContext", i_listener.contextCancelled() );
+ assertFalse( "leaving an empty context should silently remove it, and not contribute to the stack",
+ i_undoManager.isUndoPossible() );
+ }
- // some error handlings
- {
- undoManager.clear();
- listener.reset();
- caughtExpected = false;
- try { undoManager.undo(); } catch ( final InvalidStateException e ) { caughtExpected = true; }
- assertTrue( "undo should throw if no Undo action is on the stack", caughtExpected );
- caughtExpected = false;
- try { undoManager.redo(); } catch ( final InvalidStateException e ) { caughtExpected = true; }
- assertTrue( "redo should throw if no Redo action is on the stack", caughtExpected );
- caughtExpected = false;
- try { undoManager.leaveUndoContext(); } catch ( final InvalidStateException e ) { caughtExpected = true; }
- assertTrue( "leaveUndoContext should throw if no context is currently open", caughtExpected );
- }
+ private void impl_testNestedContexts( final XUndoManager i_undoManager, final UndoListener i_listener ) throws com.sun.star.uno.Exception
+ {
+ i_undoManager.clear();
+ i_listener.reset();
+ i_undoManager.enterUndoContext( "context 1" );
+ i_undoManager.enterUndoContext( "context 1.1" );
+ final CustomUndoAction action1 = new CustomUndoAction( "action 1.1.1" );
+ i_undoManager.addUndoAction( action1 );
+ i_undoManager.enterUndoContext( "context 1.1.2" );
+ final CustomUndoAction action2 = new CustomUndoAction( "action 1.1.2.1" );
+ i_undoManager.addUndoAction( action2 );
+ i_undoManager.leaveUndoContext();
+ final CustomUndoAction action3 = new CustomUndoAction( "action 1.1.3" );
+ i_undoManager.addUndoAction( action3 );
+ i_undoManager.leaveUndoContext();
+ i_undoManager.leaveUndoContext();
+ final CustomUndoAction action4 = new CustomUndoAction( "action 1.2" );
+ i_undoManager.addUndoAction( action4 );
+
+ i_undoManager.undo();
+ assertEquals( "undoing a single action notifies a wrong title", action4.getTitle(), i_listener.getMostRecentlyUndoneTitle() );
+ assertTrue( "custom Undo not called", action4.undoCalled() );
+ assertFalse( "too many custom Undos called", action1.undoCalled() || action2.undoCalled() || action3.undoCalled() );
+ i_undoManager.undo();
+ assertTrue( "nested actions not properly undone", action1.undoCalled() && action2.undoCalled() && action3.undoCalled() );
+ }
- // more on undo contexts
- {
- undoManager.clear();
- listener.reset();
-
- undoManager.enterUndoContext( "Undo Context" );
- assertEquals( "unexpected undo context depth after entering a context", 1, listener.getUndoContextDepth() );
- undoManager.addUndoAction( new CustomUndoAction( "Undo Action" ) );
- undoManager.leaveUndoContext();
- assertTrue( "leaving a non-empty context does not call leftUndoContext", listener.contextLeft() );
- assertFalse( "leaving a non-empty context should not call cancelledUndoContext", listener.contextCancelled() );
- assertEquals( "unexpected undo context depth leaving a non-empty context", 0, listener.getUndoContextDepth() );
-
- undoManager.clear();
- listener.reset();
-
- undoManager.enterUndoContext( "Undo Context" );
- undoManager.leaveUndoContext();
- assertFalse( "leaving an empty context should not call leftUndoContext", listener.contextLeft() );
- assertTrue( "leaving an empty context does not call cancelledUndoContext", listener.contextCancelled() );
- assertFalse( "leaving an empty context should silently remove it, and not contribute to the stack",
- undoManager.isUndoPossible() );
- }
+ private void impl_testErrorHandling( final DocumentTest i_test, final XUndoManager i_undoManager, final UndoListener i_listener ) throws com.sun.star.uno.Exception
+ {
+ i_undoManager.clear();
+ i_listener.reset();
- // stack handling
- {
- undoManager.clear();
- listener.reset();
-
- assertFalse( undoManager.isUndoPossible() ); // just for completeness, those two
- assertFalse( undoManager.isRedoPossible() ); // have been checked above already ...
- undoManager.addUndoAction( new CustomUndoAction( "Undo Action 1" ) );
- assertTrue( undoManager.isUndoPossible() );
- assertFalse( undoManager.isRedoPossible() );
- undoManager.addUndoAction( new CustomUndoAction( "Undo Action 2" ) );
- assertTrue( undoManager.isUndoPossible() );
- assertFalse( undoManager.isRedoPossible() );
- undoManager.undo();
- assertTrue( undoManager.isUndoPossible() );
- assertTrue( undoManager.isRedoPossible() );
- undoManager.undo();
- assertFalse( undoManager.isUndoPossible() );
- assertTrue( undoManager.isRedoPossible() );
- undoManager.addUndoAction( new CustomUndoAction( "Undo Action 3" ) );
- assertTrue( undoManager.isUndoPossible() );
- assertFalse( "adding a new action should have cleared the Redo stack", undoManager.isRedoPossible() );
- }
+ // try retrieving the comments for the current Undo/Redo - this should fail
+ boolean caughtExpected = false;
+ try { i_undoManager.getCurrentUndoActionTitle(); }
+ catch( final InvalidStateException e ) { caughtExpected = true; }
+ assertTrue( "trying the title of the current Undo action is expected to fail for an empty stack", caughtExpected );
- // locking the manager
- {
- undoManager.clear();
- listener.reset();
+ caughtExpected = false;
+ try { i_undoManager.getCurrentRedoActionTitle(); }
+ catch( final InvalidStateException e ) { caughtExpected = true; }
+ assertTrue( "trying the title of the current Redo action is expected to fail for an empty stack", caughtExpected );
+
+ caughtExpected = false;
+ try { i_undoManager.undo(); } catch ( final InvalidStateException e ) { caughtExpected = true; }
+ assertTrue( "undo should throw if no Undo action is on the stack", caughtExpected );
+
+ caughtExpected = false;
+ try { i_undoManager.redo(); } catch ( final InvalidStateException e ) { caughtExpected = true; }
+ assertTrue( "redo should throw if no Redo action is on the stack", caughtExpected );
+
+ caughtExpected = false;
+ try { i_undoManager.leaveUndoContext(); } catch ( final InvalidStateException e ) { caughtExpected = true; }
+ assertTrue( "leaveUndoContext should throw if no context is currently open", caughtExpected );
+
+ caughtExpected = false;
+ try { i_undoManager.addUndoAction( null ); } catch ( com.sun.star.lang.IllegalArgumentException e ) { caughtExpected = true; }
+ assertTrue( "adding a NULL action should be rejected", caughtExpected );
+
+ // an Undo action which throws when undone should propagate this to the API caller
+ i_undoManager.clear();
+ i_undoManager.addUndoAction( new FailingUndoAction() );
+ caughtExpected = false;
+ try { i_undoManager.undo(); } catch ( com.sun.star.uno.RuntimeException e ) { caughtExpected = true; }
+ assertTrue( "RuntimeExceptions in XUndoAction.undo should be propagated at the API", caughtExpected );
+ assertTrue( "an Undo action which fails should not be removed from the stack", i_undoManager.isUndoPossible() );
+
+ // but on the other hand, doing the Undo via UI should not throw
+ i_test.getDocument().getCurrentView().dispatch( ".uno:Undo" );
+ }
- // implicit Undo actions, triggered by changes to the document
- assertFalse( "unexpected initial locking state", undoManager.isLocked() );
- undoManager.lock();
- assertTrue( "just locked the manager, why does it lie?", undoManager.isLocked() );
- test.doSingleModification();
- assertEquals( "when the Undo manager is locked, no implicit additions should happen",
- 0, listener.getUndoActionsAdded() );
- undoManager.unlock();
- assertEquals( "unlock is not expected to add collected actions - they should be discarded",
- 0, listener.getUndoActionsAdded() );
- assertFalse( "just unlocked the manager, why does it lie?", undoManager.isLocked() );
-
- // explicit Undo actions
- undoManager.lock();
- undoManager.addUndoAction( new CustomUndoAction( "Dummy Undo Action" ) );
- undoManager.unlock();
- assertEquals( "explicit Undo actions are expected to be ignored when the manager is locked",
- 0, listener.getUndoActionsAdded() );
-
- // Undo contexts while being locked
- undoManager.lock();
- undoManager.enterUndoContext( "Dummy Context" );
- undoManager.enterHiddenUndoContext();
- assertEquals( "entering Undo contexts should be ignored when the manager is locked", 0, listener.getUndoContextDepth() );
- undoManager.leaveUndoContext();
- undoManager.leaveUndoContext();
- undoManager.unlock();
-
- // |unlock| error handling
- assertFalse( "internal error: manager should not be locked at this point in time", undoManager.isLocked() );
- caughtExpected = false;
- try { undoManager.unlock(); } catch ( final InvalidStateException e ) { caughtExpected = true; }
- assertTrue( "unlocking the manager when it is not locked should throw", caughtExpected );
- }
+ private void impl_testStackHandling( final XUndoManager i_undoManager, final UndoListener i_listener ) throws com.sun.star.uno.Exception
+ {
+ i_undoManager.clear();
+ i_listener.reset();
+
+ assertFalse( i_undoManager.isUndoPossible() ); // just for completeness, those two
+ assertFalse( i_undoManager.isRedoPossible() ); // have been checked before already ...
+ i_undoManager.addUndoAction( new CustomUndoAction() );
+ assertTrue( i_undoManager.isUndoPossible() );
+ assertFalse( i_undoManager.isRedoPossible() );
+ i_undoManager.addUndoAction( new CustomUndoAction() );
+ assertTrue( i_undoManager.isUndoPossible() );
+ assertFalse( i_undoManager.isRedoPossible() );
+ i_undoManager.undo();
+ assertTrue( i_undoManager.isUndoPossible() );
+ assertTrue( i_undoManager.isRedoPossible() );
+ i_undoManager.undo();
+ assertFalse( i_undoManager.isUndoPossible() );
+ assertTrue( i_undoManager.isRedoPossible() );
+ i_undoManager.addUndoAction( new CustomUndoAction() );
+ assertTrue( i_undoManager.isUndoPossible() );
+ assertFalse( "adding a new action should have cleared the Redo stack", i_undoManager.isRedoPossible() );
+ }
- // close the document, ensure the Undo manager listener gets notified
- m_currentDocument.close();
- assertTrue( "document is closed, but the UndoManagerListener has not been notified of the disposal", listener.isDisposed() );
- m_currentDocument = null;
+ private void impl_testClearance( final XUndoManager i_undoManager, final UndoListener i_listener ) throws com.sun.star.uno.Exception
+ {
+ i_undoManager.clear();
+ i_listener.reset();
+
+ // add an action, clear the stack, verify the listener has been called
+ i_undoManager.addUndoAction( new CustomUndoAction() );
+ assertFalse( "clearance listener unexpectedly called", i_listener.stackWasCleared() );
+ assertFalse( "redo-clearance listener unexpectedly called", i_listener.redoStackWasCleared() );
+ i_undoManager.clear();
+ assertTrue( "clearance listener not called as expected", i_listener.stackWasCleared() );
+ assertFalse( "redo-clearance listener unexpectedly called (2)", i_listener.redoStackWasCleared() );
+
+ // ensure the listener is also called if the stack is actually empty at the moment of the call
+ i_listener.reset();
+ assertFalse( i_undoManager.isUndoPossible() );
+ i_undoManager.clear();
+ assertTrue( "clearance listener is also expected to be called if the stack was empty before", i_listener.stackWasCleared() );
+
+ // ensure the proper listeners are called for clearRedo
+ i_listener.reset();
+ i_undoManager.clearRedo();
+ assertFalse( i_listener.stackWasCleared() );
+ assertTrue( i_listener.redoStackWasCleared() );
+
+ // ensure the redo listener is also called upon implicit redo stack clearance
+ i_listener.reset();
+ i_undoManager.addUndoAction( new CustomUndoAction() );
+ i_undoManager.addUndoAction( new CustomUndoAction() );
+ i_undoManager.undo();
+ assertTrue( i_undoManager.isUndoPossible() );
+ assertTrue( i_undoManager.isRedoPossible() );
+ i_undoManager.addUndoAction( new CustomUndoAction() );
+ assertFalse( i_undoManager.isRedoPossible() );
+ assertTrue( "implicit clearance of the Redo stack does not notify listeners", i_listener.redoStackWasCleared() );
}
private XComponentContext getContext()
@@ -512,8 +603,13 @@ public class UndoManager
System.out.println( "--------------------------------------------------------------------------------" );
}
- private static class CustomUndoAction implements XUndoAction
+ private static class CustomUndoAction implements XUndoAction, XComponent
{
+ CustomUndoAction()
+ {
+ m_title = "Custom Undo Action";
+ }
+
CustomUndoAction( final String i_title )
{
m_title = i_title;
@@ -534,12 +630,56 @@ public class UndoManager
m_redoCalled = true;
}
+ public void dispose()
+ {
+ m_disposed = true;
+ }
+
+ public void addEventListener( XEventListener xl )
+ {
+ fail( "addEventListener is not expected to be called in the course of this test" );
+ }
+
+ public void removeEventListener( XEventListener xl )
+ {
+ fail( "removeEventListener is not expected to be called in the course of this test" );
+ }
+
boolean undoCalled() { return m_undoCalled; }
boolean redoCalled() { return m_redoCalled; }
+ boolean disposed() { return m_disposed; }
private final String m_title;
private boolean m_undoCalled = false;
private boolean m_redoCalled = false;
+ private boolean m_disposed = false;
+ }
+
+ private static class FailingUndoAction implements XUndoAction
+ {
+ FailingUndoAction()
+ {
+ }
+
+ public String getTitle()
+ {
+ return "failing undo";
+ }
+
+ public void undo()
+ {
+ impl_throw();
+ }
+
+ public void redo()
+ {
+ impl_throw();
+ }
+
+ private void impl_throw()
+ {
+ throw new com.sun.star.uno.RuntimeException();
+ }
}
private static final OfficeConnection m_connection = new OfficeConnection();