diff options
Diffstat (limited to 'platform/testRunner/src/com')
11 files changed, 322 insertions, 121 deletions
diff --git a/platform/testRunner/src/com/intellij/execution/testframework/AbstractTestProxy.java b/platform/testRunner/src/com/intellij/execution/testframework/AbstractTestProxy.java index 73ecdb2ddd8c..7b84c66ae2ac 100644 --- a/platform/testRunner/src/com/intellij/execution/testframework/AbstractTestProxy.java +++ b/platform/testRunner/src/com/intellij/execution/testframework/AbstractTestProxy.java @@ -143,4 +143,16 @@ public abstract class AbstractTestProxy extends CompositePrintable { String getExpected(); String getActual(); } + + public interface AssertEqualsDiffChain { + AssertEqualsMultiDiffViewProvider getPrevious(); + AssertEqualsMultiDiffViewProvider getCurrent(); + AssertEqualsMultiDiffViewProvider getNext(); + void setCurrent(AssertEqualsMultiDiffViewProvider provider); + } + + public interface AssertEqualsMultiDiffViewProvider extends AssertEqualsDiffViewerProvider { + void openMultiDiff(Project project, AssertEqualsDiffChain chain); + String getFilePath(); + } } diff --git a/platform/testRunner/src/com/intellij/execution/testframework/Filter.java b/platform/testRunner/src/com/intellij/execution/testframework/Filter.java index 7d43fcd2a7e1..8dd6363c5940 100644 --- a/platform/testRunner/src/com/intellij/execution/testframework/Filter.java +++ b/platform/testRunner/src/com/intellij/execution/testframework/Filter.java @@ -61,42 +61,49 @@ public abstract class Filter<T extends AbstractTestProxy> { } public static final Filter NO_FILTER = new Filter() { + @Override public boolean shouldAccept(final AbstractTestProxy test) { return true; } }; public static final Filter DEFECT = new Filter() { + @Override public boolean shouldAccept(final AbstractTestProxy test) { return test.isDefect(); } }; public static final Filter IGNORED = new Filter() { + @Override public boolean shouldAccept(final AbstractTestProxy test) { return test.isIgnored(); } }; public static final Filter NOT_PASSED = new Filter() { + @Override public boolean shouldAccept(final AbstractTestProxy test) { return !test.isPassed(); } }; public static final Filter PASSED = new Filter() { + @Override public boolean shouldAccept(final AbstractTestProxy test) { return test.isPassed(); } }; public static final Filter FAILED_OR_INTERRUPTED = new Filter() { + @Override public boolean shouldAccept(final AbstractTestProxy test) { return test.isInterrupted() || test.isDefect(); } }; public static final Filter LEAF = new Filter() { + @Override public boolean shouldAccept(final AbstractTestProxy test) { return test.isLeaf(); } @@ -122,6 +129,7 @@ public abstract class Filter<T extends AbstractTestProxy> { myFilter2 = filter2; } + @Override public boolean shouldAccept(final AbstractTestProxy test) { return myFilter1.shouldAccept(test) && myFilter2.shouldAccept(test); } @@ -134,6 +142,7 @@ public abstract class Filter<T extends AbstractTestProxy> { myFilter = filter; } + @Override public boolean shouldAccept(final AbstractTestProxy test) { return !myFilter.shouldAccept(test); } @@ -148,6 +157,7 @@ public abstract class Filter<T extends AbstractTestProxy> { myFilter2 = filter2; } + @Override public boolean shouldAccept(final AbstractTestProxy test) { return myFilter1.shouldAccept(test) || myFilter2.shouldAccept(test); } diff --git a/platform/testRunner/src/com/intellij/execution/testframework/TestTreeView.java b/platform/testRunner/src/com/intellij/execution/testframework/TestTreeView.java index 839568b4c2a9..5d1d2b346a85 100644 --- a/platform/testRunner/src/com/intellij/execution/testframework/TestTreeView.java +++ b/platform/testRunner/src/com/intellij/execution/testframework/TestTreeView.java @@ -46,6 +46,8 @@ import java.util.ArrayList; import java.util.List; public abstract class TestTreeView extends Tree implements DataProvider, CopyProvider { + public static final DataKey<TestFrameworkRunningModel> MODEL_DATA_KEY = DataKey.create("testFrameworkModel.dataId"); + private TestFrameworkRunningModel myModel; protected abstract TreeCellRenderer getRenderer(TestConsoleProperties properties); @@ -127,7 +129,11 @@ public abstract class TestTreeView extends Tree implements DataProvider, CopyPro return locations.isEmpty() ? null : locations.toArray(new Location[locations.size()]); } } - + + if (MODEL_DATA_KEY.is(dataId)) { + return myModel; + } + final TreePath selectionPath = getSelectionPath(); if (selectionPath == null) return null; final AbstractTestProxy testProxy = getSelectedTest(selectionPath); @@ -162,7 +168,6 @@ public abstract class TestTreeView extends Tree implements DataProvider, CopyPro }); TreeUtil.installActions(this); PopupHandler.installPopupHandler(this, IdeActions.GROUP_TESTTREE_POPUP, ActionPlaces.TESTTREE_VIEW_POPUP); - ViewAssertEqualsDiffAction.registerShortcut(this); } @JdkConstants.TreeSelectionMode diff --git a/platform/testRunner/src/com/intellij/execution/testframework/TestTreeViewAction.java b/platform/testRunner/src/com/intellij/execution/testframework/TestTreeViewAction.java new file mode 100644 index 000000000000..8a700d1b5dbd --- /dev/null +++ b/platform/testRunner/src/com/intellij/execution/testframework/TestTreeViewAction.java @@ -0,0 +1,19 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.execution.testframework; + +public interface TestTreeViewAction { +} diff --git a/platform/testRunner/src/com/intellij/execution/testframework/TestTreeViewActionsPromoter.java b/platform/testRunner/src/com/intellij/execution/testframework/TestTreeViewActionsPromoter.java new file mode 100644 index 000000000000..445c33c682be --- /dev/null +++ b/platform/testRunner/src/com/intellij/execution/testframework/TestTreeViewActionsPromoter.java @@ -0,0 +1,38 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.execution.testframework; + +import com.intellij.openapi.actionSystem.ActionPromoter; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.DataContext; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class TestTreeViewActionsPromoter implements ActionPromoter { + @Override + public List<AnAction> promote(List<AnAction> actions, DataContext context) { + if (AbstractTestProxy.DATA_KEY.getData(context) != null) { + for (AnAction action : actions) { + if (action instanceof TestTreeViewAction) { + return Arrays.asList(action); + } + } + } + return Collections.emptyList(); + } +} diff --git a/platform/testRunner/src/com/intellij/execution/testframework/TestsUIUtil.java b/platform/testRunner/src/com/intellij/execution/testframework/TestsUIUtil.java index 836635a58b0e..cbb0373f34c1 100644 --- a/platform/testRunner/src/com/intellij/execution/testframework/TestsUIUtil.java +++ b/platform/testRunner/src/com/intellij/execution/testframework/TestsUIUtil.java @@ -86,7 +86,7 @@ public class TestsUIUtil { } return false; } - + public static Navigatable getOpenFileDescriptor(final AbstractTestProxy testProxy, final TestFrameworkRunningModel model) { final TestConsoleProperties testConsoleProperties = model.getProperties(); return getOpenFileDescriptor(testProxy, testConsoleProperties, @@ -114,7 +114,7 @@ public class TestsUIUtil { public static void notifyByBalloon(@NotNull final Project project, boolean started, final AbstractTestProxy root, - final TestConsoleProperties properties, + final TestConsoleProperties properties, @Nullable final String comment) { if (project.isDisposed()) return; if (properties == null) return; @@ -231,7 +231,7 @@ public class TestsUIUtil { myType = MessageType.ERROR; } else if (notStartedCount > 0) { - myTitle = !notStarted.isEmpty() ? ExecutionBundle.message("junit.runing.info.failed.to.start.error.message") : "Tests Ignored"; + myTitle = !notStarted.isEmpty() ? ExecutionBundle.message("junit.running.info.failed.to.start.error.message") : "Tests Ignored"; myText = passedCount + " passed, " + notStartedCount + (!notStarted.isEmpty() ? " not started" : " ignored"); myType = notStarted.isEmpty() ? MessageType.WARNING : MessageType.ERROR; } diff --git a/platform/testRunner/src/com/intellij/execution/testframework/actions/AbstractRerunFailedTestsAction.java b/platform/testRunner/src/com/intellij/execution/testframework/actions/AbstractRerunFailedTestsAction.java index 30f8599e2aaf..a7d036b33ef7 100644 --- a/platform/testRunner/src/com/intellij/execution/testframework/actions/AbstractRerunFailedTestsAction.java +++ b/platform/testRunner/src/com/intellij/execution/testframework/actions/AbstractRerunFailedTestsAction.java @@ -34,20 +34,20 @@ import com.intellij.execution.testframework.Filter; import com.intellij.execution.testframework.TestConsoleProperties; import com.intellij.execution.testframework.TestFrameworkRunningModel; import com.intellij.idea.ActionsBundle; -import com.intellij.openapi.Disposable; -import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.actionSystem.ActionManager; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.LangDataKeys; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.options.SettingsEditor; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.ComponentContainer; import com.intellij.openapi.ui.popup.JBPopupFactory; -import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.Getter; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.WriteExternalException; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.ui.components.JBList; -import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.UIUtil; import org.jdom.Element; import org.jetbrains.annotations.NotNull; @@ -57,40 +57,24 @@ import javax.swing.*; import java.awt.*; import java.awt.event.InputEvent; import java.awt.event.MouseEvent; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; import java.util.List; -public class AbstractRerunFailedTestsAction extends AnAction implements AnAction.TransparentUpdate, Disposable { - private static final List<AbstractRerunFailedTestsAction> registry = ContainerUtil.createLockFreeCopyOnWriteList(); - private static final Logger LOG = Logger.getInstance("#com.intellij.execution.junit2.ui.actions.RerunFailedTestsAction"); +public class AbstractRerunFailedTestsAction extends AnAction implements AnAction.TransparentUpdate { + private static final Logger LOG = Logger.getInstance(AbstractRerunFailedTestsAction.class); + private TestFrameworkRunningModel myModel; private Getter<TestFrameworkRunningModel> myModelProvider; protected TestConsoleProperties myConsoleProperties; - protected ExecutionEnvironment myEnvironment; - private final JComponent myParent; - - @SuppressWarnings("UnusedDeclaration") - public AbstractRerunFailedTestsAction() { - //We call this constructor with a little help from reflection. - myParent = null; - } protected AbstractRerunFailedTestsAction(@NotNull ComponentContainer componentContainer) { - myParent = componentContainer.getComponent(); - registry.add(this); - Disposer.register(componentContainer, this); copyFrom(ActionManager.getInstance().getAction("RerunFailedTests")); - registerCustomShortcutSet(getShortcutSet(), myParent); + registerCustomShortcutSet(getShortcutSet(), componentContainer.getComponent()); } - @Override - public void dispose() { - registry.remove(this); - } - - public void init(final TestConsoleProperties consoleProperties, - final ExecutionEnvironment environment) { - myEnvironment = environment; + public void init(TestConsoleProperties consoleProperties) { myConsoleProperties = consoleProperties; } @@ -102,48 +86,27 @@ public class AbstractRerunFailedTestsAction extends AnAction implements AnAction myModelProvider = modelProvider; } - @NotNull - private AbstractRerunFailedTestsAction findActualAction() { - if (myParent != null || registry.isEmpty()) - return this; - List<AbstractRerunFailedTestsAction> candidates = new ArrayList<AbstractRerunFailedTestsAction>(registry); - Collections.sort(candidates, new Comparator<AbstractRerunFailedTestsAction>() { - @Override - public int compare(AbstractRerunFailedTestsAction action1, AbstractRerunFailedTestsAction action2) { - Window window1 = SwingUtilities.windowForComponent(action1.myParent); - Window window2 = SwingUtilities.windowForComponent(action2.myParent); - if (window1 == null) - return 1; - if (window2 == null) - return -1; - boolean showing1 = action1.myParent.isShowing(); - boolean showing2 = action2.myParent.isShowing(); - if (showing1 && !showing2) - return -1; - if (showing2 && !showing1) - return 1; - return (window1.isActive() ? -1 : 1); - } - }); - return candidates.get(0); - } - @Override - public final void update(AnActionEvent e) { - AbstractRerunFailedTestsAction action = findActualAction(); - e.getPresentation().setEnabled(action.isActive(e)); + public final void update(@NotNull AnActionEvent e) { + e.getPresentation().setEnabled(isActive(e)); } private boolean isActive(AnActionEvent e) { - DataContext dataContext = e.getDataContext(); - Project project = CommonDataKeys.PROJECT.getData(dataContext); - if (project == null) return false; + Project project = e.getProject(); + if (project == null) { + return false; + } + TestFrameworkRunningModel model = getModel(); - if (model == null || model.getRoot() == null) return false; - final List<? extends AbstractTestProxy> myAllTests = model.getRoot().getAllTests(); - final Filter filter = getFailuresFilter(); - for (Object test : myAllTests) { - if (filter.shouldAccept((AbstractTestProxy)test)) return true; + if (model == null || model.getRoot() == null) { + return false; + } + Filter filter = getFailuresFilter(); + for (AbstractTestProxy test : model.getRoot().getAllTests()) { + //noinspection unchecked + if (filter.shouldAccept(test)) { + return true; + } } return false; } @@ -151,10 +114,10 @@ public class AbstractRerunFailedTestsAction extends AnAction implements AnAction @NotNull protected List<AbstractTestProxy> getFailedTests(Project project) { TestFrameworkRunningModel model = getModel(); - final List<? extends AbstractTestProxy> myAllTests = model != null - ? model.getRoot().getAllTests() - : Collections.<AbstractTestProxy>emptyList(); - return getFilter(project, model != null ? model.getProperties().getScope() : GlobalSearchScope.allScope(project)).select(myAllTests); + //noinspection unchecked + return getFilter(project, model != null ? model.getProperties().getScope() : GlobalSearchScope.allScope(project)).select(model != null + ? model.getRoot().getAllTests() + : Collections.<AbstractTestProxy>emptyList()); } @NotNull @@ -162,7 +125,7 @@ public class AbstractRerunFailedTestsAction extends AnAction implements AnAction return getFailuresFilter(); } - protected Filter getFailuresFilter() { + protected Filter<?> getFailuresFilter() { if (TestConsoleProperties.INCLUDE_NON_STARTED_IN_RERUN_FAILED.value(myConsoleProperties)) { return Filter.NOT_PASSED.and(Filter.IGNORED.not()).or(Filter.FAILED_OR_INTERRUPTED); } @@ -170,30 +133,27 @@ public class AbstractRerunFailedTestsAction extends AnAction implements AnAction } @Override - public void actionPerformed(AnActionEvent e) { - findActualAction().showPopup(e); - } + public void actionPerformed(@NotNull AnActionEvent e) { + ExecutionEnvironment environment = e.getData(LangDataKeys.EXECUTION_ENVIRONMENT); + if (environment == null) { + return; + } - private void showPopup(AnActionEvent e) { - boolean isDebug = myConsoleProperties.isDebug(); - final MyRunProfile profile = getRunProfile(); + MyRunProfile profile = getRunProfile(environment); if (profile == null) { return; } - final Executor executor = isDebug ? DefaultDebugExecutor.getDebugExecutorInstance() : DefaultRunExecutor.getRunExecutorInstance(); + final ExecutionEnvironmentBuilder environmentBuilder = new ExecutionEnvironmentBuilder(environment).runProfile(profile); final InputEvent event = e.getInputEvent(); if (!(event instanceof MouseEvent) || !event.isShiftDown()) { - final ProgramRunner runner = RunnerRegistry.getInstance().getRunner(executor.getId(), profile); - LOG.assertTrue(runner != null); - performAction(runner, profile, myEnvironment.getExecutor()); + performAction(environmentBuilder); return; } final LinkedHashMap<Executor, ProgramRunner> availableRunners = new LinkedHashMap<Executor, ProgramRunner>(); - final Executor[] executors = new Executor[] {DefaultRunExecutor.getRunExecutorInstance(), DefaultDebugExecutor.getDebugExecutorInstance()}; - for (Executor ex : executors) { + for (Executor ex : new Executor[] {DefaultRunExecutor.getRunExecutorInstance(), DefaultDebugExecutor.getDebugExecutorInstance()}) { final ProgramRunner runner = RunnerRegistry.getInstance().getRunner(ex.getId(), profile); if (runner != null) { availableRunners.put(ex, runner); @@ -201,19 +161,20 @@ public class AbstractRerunFailedTestsAction extends AnAction implements AnAction } if (availableRunners.isEmpty()) { - LOG.error(executor.getActionName() + " is not available now"); - return; + LOG.error(environment.getExecutor().getActionName() + " is not available now"); } - - if (availableRunners.size() == 1) { - performAction(availableRunners.get(executor), profile, executor); - } else { + else if (availableRunners.size() == 1) { + //noinspection ConstantConditions + performAction(environmentBuilder.runner(availableRunners.get(environment.getExecutor()))); + } + else { final JBList list = new JBList(availableRunners.keySet()); list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - list.setSelectedValue(executor, true); + list.setSelectedValue(environment.getExecutor(), true); list.setCellRenderer(new DefaultListCellRenderer() { + @NotNull @Override - public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + public Component getListCellRendererComponent(@NotNull JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { final Component component = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); if (value instanceof Executor) { setText(UIUtil.removeMnemonic(((Executor)value).getStartActionText())); @@ -222,6 +183,7 @@ public class AbstractRerunFailedTestsAction extends AnAction implements AnAction return component; } }); + //noinspection ConstantConditions JBPopupFactory.getInstance().createListPopupBuilder(list) .setTitle("Restart Failed Tests") .setMovable(false) @@ -232,35 +194,39 @@ public class AbstractRerunFailedTestsAction extends AnAction implements AnAction public void run() { final Object value = list.getSelectedValue(); if (value instanceof Executor) { - performAction(availableRunners.get(value), profile, (Executor)value); + //noinspection ConstantConditions + performAction(environmentBuilder.runner(availableRunners.get(value)).executor((Executor)value)); } } }).createPopup().showUnderneathOf(event.getComponent()); } } - private void performAction(ProgramRunner runner, MyRunProfile profile, Executor executor) { + private static void performAction(@NotNull ExecutionEnvironmentBuilder builder) { + ExecutionEnvironment environment = builder.build(); try { - new ExecutionEnvironmentBuilder(myEnvironment) - .runner(runner) - .executor(executor) - .runProfile(profile) - .buildAndExecute(); + environment.getRunner().execute(environment); } - catch (ExecutionException e1) { - LOG.error(e1); + catch (ExecutionException e) { + LOG.error(e); } finally { - profile.clear(); + ((MyRunProfile)environment.getRunProfile()).clear(); } } - @Nullable + @Deprecated public MyRunProfile getRunProfile() { return null; } @Nullable + protected MyRunProfile getRunProfile(@NotNull ExecutionEnvironment environment) { + //noinspection deprecation + return getRunProfile(); + } + + @Nullable public TestFrameworkRunningModel getModel() { if (myModel != null) { return myModel; @@ -293,7 +259,6 @@ public class AbstractRerunFailedTestsAction extends AnAction implements AnAction public void clear() { } - @Override public void checkConfiguration() throws RuntimeConfigurationException { } @@ -351,6 +316,7 @@ public class AbstractRerunFailedTestsAction extends AnAction implements AnAction return myConfiguration.getPredefinedLogFiles(); } + @NotNull @Override public ArrayList<LogFileOptions> getAllLogFiles() { return myConfiguration.getAllLogFiles(); diff --git a/platform/testRunner/src/com/intellij/execution/testframework/actions/RerunFailedTestsAction.java b/platform/testRunner/src/com/intellij/execution/testframework/actions/RerunFailedTestsAction.java new file mode 100644 index 000000000000..af15e3c14ce1 --- /dev/null +++ b/platform/testRunner/src/com/intellij/execution/testframework/actions/RerunFailedTestsAction.java @@ -0,0 +1,12 @@ +package com.intellij.execution.testframework.actions; + +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import org.jetbrains.annotations.NotNull; + +class RerunFailedTestsAction extends AnAction { + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + throw new IllegalStateException("Action only as template"); + } +} diff --git a/platform/testRunner/src/com/intellij/execution/testframework/actions/ViewAssertEqualsDiffAction.java b/platform/testRunner/src/com/intellij/execution/testframework/actions/ViewAssertEqualsDiffAction.java index fd80ea0154db..5d19c5ee0877 100644 --- a/platform/testRunner/src/com/intellij/execution/testframework/actions/ViewAssertEqualsDiffAction.java +++ b/platform/testRunner/src/com/intellij/execution/testframework/actions/ViewAssertEqualsDiffAction.java @@ -16,13 +16,15 @@ package com.intellij.execution.testframework.actions; -import com.intellij.execution.testframework.AbstractTestProxy; +import com.intellij.execution.testframework.*; import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.project.Project; import org.jetbrains.annotations.NonNls; -import javax.swing.*; +import java.util.ArrayList; +import java.util.List; -public class ViewAssertEqualsDiffAction extends AnAction { +public class ViewAssertEqualsDiffAction extends AnAction implements TestTreeViewAction { @NonNls public static final String ACTION_ID = "openAssertEqualsDiff"; public void actionPerformed(final AnActionEvent e) { @@ -30,11 +32,35 @@ public class ViewAssertEqualsDiffAction extends AnAction { if (testProxy != null) { final AbstractTestProxy.AssertEqualsDiffViewerProvider diffViewerProvider = testProxy.getDiffViewerProvider(); if (diffViewerProvider != null) { - diffViewerProvider.openDiff(CommonDataKeys.PROJECT.getData(e.getDataContext())); + final Project project = CommonDataKeys.PROJECT.getData(e.getDataContext()); + if (diffViewerProvider instanceof AbstractTestProxy.AssertEqualsMultiDiffViewProvider) { + final TestFrameworkRunningModel runningModel = TestTreeView.MODEL_DATA_KEY.getData(e.getDataContext()); + final List<AbstractTestProxy.AssertEqualsMultiDiffViewProvider> providers = collectAvailableProviders(runningModel); + final MyAssertEqualsDiffChain diffChain = + providers.size() > 1 ? new MyAssertEqualsDiffChain(providers, (AbstractTestProxy.AssertEqualsMultiDiffViewProvider)diffViewerProvider) : null; + ((AbstractTestProxy.AssertEqualsMultiDiffViewProvider)diffViewerProvider).openMultiDiff(project, diffChain); + } else { + diffViewerProvider.openDiff(project); + } } } } + private static List<AbstractTestProxy.AssertEqualsMultiDiffViewProvider> collectAvailableProviders(TestFrameworkRunningModel model) { + final List<AbstractTestProxy.AssertEqualsMultiDiffViewProvider> providers = new ArrayList<AbstractTestProxy.AssertEqualsMultiDiffViewProvider>(); + if (model != null) { + final AbstractTestProxy root = model.getRoot(); + final List<? extends AbstractTestProxy> allTests = root.getAllTests(); + for (AbstractTestProxy test : allTests) { + final AbstractTestProxy.AssertEqualsDiffViewerProvider provider = test.getDiffViewerProvider(); + if (provider instanceof AbstractTestProxy.AssertEqualsMultiDiffViewProvider) { + providers.add((AbstractTestProxy.AssertEqualsMultiDiffViewProvider)provider); + } + } + } + return providers; + } + public void update(final AnActionEvent e) { final Presentation presentation = e.getPresentation(); final boolean enabled; @@ -55,7 +81,38 @@ public class ViewAssertEqualsDiffAction extends AnAction { presentation.setVisible(enabled); } - public static void registerShortcut(final JComponent component) { - ActionManager.getInstance().getAction(ACTION_ID).registerCustomShortcutSet(CommonShortcuts.ALT_ENTER, component); + private static class MyAssertEqualsDiffChain implements AbstractTestProxy.AssertEqualsDiffChain { + + + private final List<AbstractTestProxy.AssertEqualsMultiDiffViewProvider> myProviders; + private AbstractTestProxy.AssertEqualsMultiDiffViewProvider myProvider; + + public MyAssertEqualsDiffChain(List<AbstractTestProxy.AssertEqualsMultiDiffViewProvider> providers, + AbstractTestProxy.AssertEqualsMultiDiffViewProvider provider) { + myProviders = providers; + myProvider = provider; + } + + @Override + public AbstractTestProxy.AssertEqualsMultiDiffViewProvider getPrevious() { + final int prevIdx = (myProviders.size() + myProviders.indexOf(myProvider) - 1) % myProviders.size(); + return myProviders.get(prevIdx); + } + + @Override + public AbstractTestProxy.AssertEqualsMultiDiffViewProvider getCurrent() { + return myProvider; + } + + @Override + public AbstractTestProxy.AssertEqualsMultiDiffViewProvider getNext() { + final int nextIdx = (myProviders.indexOf(myProvider) + 1) % myProviders.size(); + return myProviders.get(nextIdx); + } + + @Override + public void setCurrent(AbstractTestProxy.AssertEqualsMultiDiffViewProvider provider) { + myProvider = provider; + } } } diff --git a/platform/testRunner/src/com/intellij/execution/testframework/stacktrace/DiffHyperlink.java b/platform/testRunner/src/com/intellij/execution/testframework/stacktrace/DiffHyperlink.java index b60770692d9b..f8ff62996eca 100644 --- a/platform/testRunner/src/com/intellij/execution/testframework/stacktrace/DiffHyperlink.java +++ b/platform/testRunner/src/com/intellij/execution/testframework/stacktrace/DiffHyperlink.java @@ -22,14 +22,20 @@ package com.intellij.execution.testframework.stacktrace; import com.intellij.execution.ExecutionBundle; import com.intellij.execution.filters.HyperlinkInfo; +import com.intellij.execution.testframework.AbstractTestProxy; import com.intellij.execution.testframework.Printable; import com.intellij.execution.testframework.Printer; import com.intellij.execution.ui.ConsoleViewContentType; +import com.intellij.icons.AllIcons; +import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.diff.*; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import javax.swing.*; import java.io.File; public class DiffHyperlink implements Printable { @@ -56,21 +62,93 @@ public class DiffHyperlink implements Printable { myPrintOneLine = printOneLine; } - public void openDiff(final Project project) { + public void openDiff(Project project) { + openMultiDiff(project, null); + } + + public void openMultiDiff(final Project project, + final AbstractTestProxy.AssertEqualsDiffChain chain) { + final SimpleDiffRequest diffData = createRequest(project, chain, myFilePath, myExpected, myActual); + DiffManager.getInstance().getIdeaDiffTool().show(diffData); + } + + private SimpleDiffRequest createRequest(final Project project, + final AbstractTestProxy.AssertEqualsDiffChain chain, + String filePath, String expected, String actual) { String expectedTitle = ExecutionBundle.message("diff.content.expected.title"); final DiffContent expectedContent; final VirtualFile vFile; - if (myFilePath != null && (vFile = LocalFileSystem.getInstance().findFileByPath(myFilePath)) != null) { + if (filePath != null && (vFile = LocalFileSystem.getInstance().findFileByPath(filePath)) != null) { expectedContent = DiffContent.fromFile(project, vFile); expectedTitle += " (" + vFile.getPresentableUrl() + ")"; - } else expectedContent = new SimpleContent(myExpected); + } else { + expectedContent = new SimpleContent(expected); + } final SimpleDiffRequest diffData = new SimpleDiffRequest(project, getTitle()); - diffData.setContents(expectedContent, new SimpleContent(myActual)); + if (chain != null) { + diffData.setToolbarAddons(new DiffRequest.ToolbarAddons() { + @Override + public void customize(DiffToolbar toolbar) { + toolbar.addAction(new NextPrevAction("Compare Previous Failure", AllIcons.Actions.Prevfile, chain) { + { + registerCustomShortcutSet(ActionManager.getInstance().getAction("PreviousTab").getShortcutSet(), null); + } + + @Override + protected AbstractTestProxy.AssertEqualsMultiDiffViewProvider getNextId() { + return chain.getPrevious(); + } + }); + toolbar.addAction(new NextPrevAction("Compare Next Failure", AllIcons.Actions.Nextfile, chain) { + { + registerCustomShortcutSet(ActionManager.getInstance().getAction("NextTab").getShortcutSet(), null); + } + + @Override + protected AbstractTestProxy.AssertEqualsMultiDiffViewProvider getNextId() { + return chain.getNext(); + } + }); + } + }); + } + diffData.setContents(expectedContent, new SimpleContent(actual)); diffData.setContentTitles(expectedTitle, ExecutionBundle.message("diff.content.actual.title")); diffData.addHint(DiffTool.HINT_SHOW_FRAME); diffData.addHint(DiffTool.HINT_DO_NOT_IGNORE_WHITESPACES); diffData.setGroupKey("#com.intellij.execution.junit2.states.ComparisonFailureState$DiffDialog"); - DiffManager.getInstance().getIdeaDiffTool().show(diffData); + return diffData; + } + + abstract class NextPrevAction extends AnAction { + + private final AbstractTestProxy.AssertEqualsDiffChain myChain; + + public NextPrevAction(@Nullable String text, @Nullable Icon icon, + final AbstractTestProxy.AssertEqualsDiffChain chain) { + super(text, text, icon); + myChain = chain; + } + + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + final DiffViewer viewer = e.getData(PlatformDataKeys.DIFF_VIEWER); + final Project project = e.getData(CommonDataKeys.PROJECT); + final AbstractTestProxy.AssertEqualsMultiDiffViewProvider nextProvider = getNextId(); + myChain.setCurrent(nextProvider); + final SimpleDiffRequest nextRequest = + createRequest(project, myChain, nextProvider.getFilePath(), nextProvider.getExpected(), nextProvider.getActual()); + viewer.setDiffRequest(nextRequest); + } + + @Override + public void update(@NotNull AnActionEvent e) { + final DiffViewer viewer = e.getData(PlatformDataKeys.DIFF_VIEWER); + final Project project = e.getData(CommonDataKeys.PROJECT); + e.getPresentation().setEnabled(project != null && viewer != null); + } + + protected abstract AbstractTestProxy.AssertEqualsMultiDiffViewProvider getNextId(); } protected String getTitle() { diff --git a/platform/testRunner/src/com/intellij/execution/testframework/ui/TestResultsPanel.java b/platform/testRunner/src/com/intellij/execution/testframework/ui/TestResultsPanel.java index a7519429381d..1f4b93238f9c 100644 --- a/platform/testRunner/src/com/intellij/execution/testframework/ui/TestResultsPanel.java +++ b/platform/testRunner/src/com/intellij/execution/testframework/ui/TestResultsPanel.java @@ -75,6 +75,7 @@ public abstract class TestResultsPanel extends JPanel implements Disposable { Disposer.register(this, myToolbarPanel); final Splitter splitter = createSplitter(mySplitterProportionProperty, mySplitterDefaultProportion); Disposer.register(this, new Disposable(){ + @Override public void dispose() { remove(splitter); splitter.dispose(); @@ -91,6 +92,7 @@ public abstract class TestResultsPanel extends JPanel implements Disposable { rightPanel.add(SameHeightPanel.wrap(myStatusLine, myToolbarPanel), BorderLayout.NORTH); myStatisticsSplitter = createSplitter(myStatisticsSplitterProportionProperty, 0.5f); new AwtVisitor(myConsole) { + @Override public boolean visit(Component component) { if (component instanceof JScrollPane) { ((JScrollPane) component).putClientProperty(UIUtil.KEEP_BORDER_SIDES, SideBorder.TOP | SideBorder.LEFT); @@ -104,6 +106,7 @@ public abstract class TestResultsPanel extends JPanel implements Disposable { showStatistics(); } myProperties.addListener(TestConsoleProperties.SHOW_STATISTICS, new TestFrameworkPropertyListener<Boolean>() { + @Override public void onChanged(Boolean value) { if (value.booleanValue()) { showStatistics(); @@ -145,6 +148,7 @@ public abstract class TestResultsPanel extends JPanel implements Disposable { return outputTab; } + @Override public void dispose() { } @@ -167,9 +171,9 @@ public abstract class TestResultsPanel extends JPanel implements Disposable { } splitter.addPropertyChangeListener(new PropertyChangeListener() { - public void propertyChange(final PropertyChangeEvent evt) { - if (propertiesComponent == null) return; - if (evt.getPropertyName().equals(Splitter.PROP_PROPORTION)) { + @Override + public void propertyChange(@NotNull final PropertyChangeEvent event) { + if (event.getPropertyName().equals(Splitter.PROP_PROPORTION)) { propertiesComponent.setValue(proportionProperty, String.valueOf(splitter.getProportion())); } } |