How to test with UndoManager

Hello everyone!
I faced difficulties in testing code that used UndoManager.
Suppose we want to rollback some actions in runtime if method throws exception.
For the sake of simplicity lets consider a test class with the described behavior that creates the same file twice:

public class MyClass {
     ...

     public void createFileTwice(String name, PsiDirectory directory) {

          ...

          final Throwable[] throwables = new Throwable[1];
          CommandProcessor.getInstance().executeCommand(
               getProject(),
               () -> {
                    try {
                         directory.createFile(name);
                         directory.createFile(name);
                    } catch (Throwable throwable) {
                         throwables[0] = throwable;
                    }
               }, null, null, UndoConfirmationPolicy.DO_NOT_REQUEST_CONFIRMATION;
          );

          if (throwables[0] != null) {
               UndoManager undoManager = UndoManager.getInstance(getProject());
               if (undoManager.isUndoAvailable(null) {
                    undoManager.undo(null);
               }
               throw throwables[0];
          }          

          ...
     }     

     ...
}


If we run application and call this method from an action (extends AnAction class) the file is created after the fisrt execution of createFile method, then after the second one method fails and the file is deleted by undoManager. Method directory.findFile(name) returns null.

But if we run a test extending in our case LightPlatformCodeInsightFixtureTestCase that tests code using this method, undoManager.undo(null) is also executed but the file remains in the directory and method directory.findFile(name) returns the file.

I would be very grateful if you help me to figure out how to make test works.

2 comments
Comment actions Permalink

LightPlatformCodeInsightFixtureTestCase by default executes test code in a WriteCommandAction, so your command (becoming recursive command) is ignored - that's why undo doesn't work. This problem can be solved by overriding isWriteActionRequired() method in your test (and creating write action yourselves), but there could be other issues related to the fact that LightPlatformCodeInsightFixtureTestCase uses 'temp' filesystem implementation - undo operations might not work with it. I'd suggest to use other base class for your test - e.g. CodeInsightTestCase.

0
Comment actions Permalink

Thank you, Dmitry! I've changed my Fixture to CodeInsightFixtureTestCase and that helps.

0

Please sign in to leave a comment.