fixed [IDEADEV-41319] test runner: do not show green balloon and green progress bar...
[fedora-idea.git] / platform / smRunner / src / com / intellij / execution / testframework / sm / runner / ui / SMTestRunnerResultsForm.java
blob3ebd4baa0c9fb69d133897ae77eb3e59d204644a
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.intellij.execution.testframework.sm.runner.ui;
18 import com.intellij.execution.configurations.ConfigurationPerRunnerSettings;
19 import com.intellij.execution.configurations.RunConfigurationBase;
20 import com.intellij.execution.configurations.RunnerSettings;
21 import com.intellij.execution.testframework.*;
22 import com.intellij.execution.testframework.sm.SMRunnerUtil;
23 import com.intellij.execution.testframework.sm.runner.SMTRunnerEventsListener;
24 import com.intellij.execution.testframework.sm.runner.SMTRunnerTreeBuilder;
25 import com.intellij.execution.testframework.sm.runner.SMTRunnerTreeStructure;
26 import com.intellij.execution.testframework.sm.runner.SMTestProxy;
27 import com.intellij.execution.testframework.sm.runner.ui.statistics.StatisticsPanel;
28 import com.intellij.execution.testframework.ui.AbstractTestTreeBuilder;
29 import com.intellij.execution.testframework.ui.PrintableTestProxy;
30 import com.intellij.execution.testframework.ui.TestResultsPanel;
31 import com.intellij.execution.testframework.ui.TestsProgressAnimator;
32 import com.intellij.openapi.Disposable;
33 import com.intellij.openapi.actionSystem.AnAction;
34 import com.intellij.openapi.application.ModalityState;
35 import com.intellij.openapi.progress.util.ColorProgressBar;
36 import com.intellij.openapi.project.Project;
37 import com.intellij.openapi.util.Disposer;
38 import com.intellij.openapi.wm.IdeFocusManager;
39 import org.jetbrains.annotations.NonNls;
40 import org.jetbrains.annotations.NotNull;
41 import org.jetbrains.annotations.Nullable;
43 import javax.swing.*;
44 import javax.swing.event.TreeSelectionEvent;
45 import javax.swing.event.TreeSelectionListener;
46 import java.awt.*;
47 import java.awt.event.InputEvent;
48 import java.awt.event.KeyEvent;
49 import java.text.DateFormat;
50 import java.text.SimpleDateFormat;
51 import java.util.*;
52 import java.util.List;
54 /**
55 * @author: Roman Chernyatchik
57 public class SMTestRunnerResultsForm extends TestResultsPanel implements TestFrameworkRunningModel, TestResultsViewer, SMTRunnerEventsListener {
58 @NonNls private static final String DEFAULT_SM_RUNNER_SPLITTER_PROPERTY = "SMTestRunner.Splitter.Proportion";
60 private SMTRunnerTestTreeView myTreeView;
62 private TestsProgressAnimator myAnimator;
64 /**
65 * Fake parent suite for all tests and suites
67 private final SMTestProxy myTestsRootNode;
68 private SMTRunnerTreeBuilder myTreeBuilder;
69 private final TestConsoleProperties myConsoleProperties;
71 private final List<EventsListener> myEventListeners = new ArrayList<EventsListener>();
73 private PropagateSelectionHandler myShowStatisticForProxyHandler;
75 private final Project myProject;
77 private int myTestsCurrentCount;
78 private int myTestsTotal = 0;
79 private int myTestsFailuresCount;
80 private long myStartTime;
81 private long myEndTime;
82 private StatisticsPanel myStatisticsPane;
84 // custom progress
85 private String myCurrentCustomProgressCategory;
86 private Set<String> myMentionedCategories = new LinkedHashSet<String>();
88 public SMTestRunnerResultsForm(final RunConfigurationBase runConfiguration,
89 @NotNull final JComponent console,
90 final TestConsoleProperties consoleProperties,
91 final RunnerSettings runnerSettings,
92 final ConfigurationPerRunnerSettings configurationSettings) {
93 this(runConfiguration, console, AnAction.EMPTY_ARRAY, consoleProperties, runnerSettings, configurationSettings, null);
96 public SMTestRunnerResultsForm(final RunConfigurationBase runConfiguration,
97 @NotNull final JComponent console,
98 AnAction[] consoleActions,
99 final TestConsoleProperties consoleProperties,
100 final RunnerSettings runnerSettings,
101 final ConfigurationPerRunnerSettings configurationSettings,
102 final String splitterPropertyName) {
103 super(console, consoleActions, consoleProperties, runnerSettings, configurationSettings,
104 splitterPropertyName != null ? DEFAULT_SM_RUNNER_SPLITTER_PROPERTY : splitterPropertyName, 0.5f);
105 myConsoleProperties = consoleProperties;
107 myProject = runConfiguration.getProject();
109 //Create tests common suite root
110 //noinspection HardCodedStringLiteral
111 myTestsRootNode = new SMTestProxy("[root]", true, null);
113 // Fire selection changed and move focus on SHIFT+ENTER
114 //TODO[romeo] improve
116 final ArrayList<Component> components = new ArrayList<Component>();
117 components.add(myTreeView);
118 components.add(myTabs.getComponent());
119 myContentPane.setFocusTraversalPolicy(new MyFocusTraversalPolicy(components));
120 myContentPane.setFocusCycleRoot(true);
124 @Override
125 public void initUI() {
126 super.initUI();
128 final KeyStroke shiftEnterKey = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.SHIFT_MASK);
129 SMRunnerUtil.registerAsAction(shiftEnterKey, "show-statistics-for-test-proxy",
130 new Runnable() {
131 public void run() {
132 showStatisticsForSelectedProxy();
135 myTreeView);
138 protected ToolbarPanel createToolbarPanel() {
139 return new SMTRunnerToolbarPanel(myConsoleProperties, myRunnerSettings, myConfigurationSettings, this, this);
142 protected JComponent createTestTreeView() {
143 myTreeView = new SMTRunnerTestTreeView();
145 myTreeView.setLargeModel(true);
146 myTreeView.attachToModel(this);
147 myTreeView.setTestResultsViewer(this);
149 final SMTRunnerTreeStructure structure = new SMTRunnerTreeStructure(myProject, myTestsRootNode);
150 myTreeBuilder = new SMTRunnerTreeBuilder(myTreeView, structure);
151 Disposer.register(this, myTreeBuilder);
152 myAnimator = new MyAnimator(this, myTreeBuilder);
154 return myTreeView;
157 protected JComponent createStatisticsPanel() {
158 // Statistics tab
159 final StatisticsPanel statisticsPane = new StatisticsPanel(myProject, this);
160 // handler to select in results viewer by statistics pane events
161 statisticsPane.addPropagateSelectionListener(createSelectMeListener());
162 // handler to select test statistics pane by result viewer events
163 setShowStatisticForProxyHandler(statisticsPane.createSelectMeListener());
165 myStatisticsPane = statisticsPane;
166 return myStatisticsPane.getContentPane();
169 public StatisticsPanel getStatisticsPane() {
170 return myStatisticsPane;
173 public void addTestsTreeSelectionListener(final TreeSelectionListener listener) {
174 myTreeView.getSelectionModel().addTreeSelectionListener(listener);
178 * Is used for navigation from tree view to other UI components
179 * @param handler
181 public void setShowStatisticForProxyHandler(final PropagateSelectionHandler handler) {
182 myShowStatisticForProxyHandler = handler;
186 * Returns root node, fake parent suite for all tests and suites
187 * @return
188 * @param testsRoot
190 public void onTestingStarted(@NotNull SMTestProxy testsRoot) {
191 myAnimator.setCurrentTestCase(myTestsRootNode);
193 // Status line
194 myStatusLine.setStatusColor(ColorProgressBar.GREEN);
196 // Tests tree
197 selectAndNotify(myTestsRootNode);
199 myStartTime = System.currentTimeMillis();
200 final Date today = new Date(myStartTime);
201 myTestsRootNode.addSystemOutput("Testing started at "
202 + DateFormat.getTimeInstance(SimpleDateFormat.SHORT).format(today)
203 + " ...\n");
205 updateStatusLabel();
207 fireOnTestingStarted();
210 public void onTestingFinished(@NotNull SMTestProxy testsRoot) {
211 myEndTime = System.currentTimeMillis();
213 if (myTestsTotal == 0) {
214 myTestsTotal = myTestsCurrentCount;
215 myStatusLine.setFraction(1);
217 updateStatusLabel();
219 if (myTestsRootNode.getChildren().size() == 0) {
220 // no tests found
221 myStatusLine.setStatusColor(ColorProgressBar.RED);
224 myAnimator.stopMovie();
225 myTreeBuilder.updateFromRoot();
227 LvcsHelper.addLabel(this);
229 fireOnTestingFinished();
232 public void onTestsCountInSuite(final int count) {
233 updateCountersAndProgressOnTestCount(count, false);
237 * Adds test to tree and updates status line.
238 * Test proxy should be initialized, proxy parent must be some suite (already added to tree)
240 * @param testProxy Proxy
242 public void onTestStarted(@NotNull final SMTestProxy testProxy) {
243 updateCountersAndProgressOnTestStarted(false);
245 _addTestOrSuite(testProxy);
247 fireOnTestNodeAdded(testProxy);
250 public void onTestFailed(@NotNull final SMTestProxy test) {
251 updateCountersAndProgressOnTestFailed(false);
254 public void onTestIgnored(@NotNull final SMTestProxy test) {
255 //Do nothing
259 * Adds suite to tree
260 * Suite proxy should be initialized, proxy parent must be some suite (already added to tree)
261 * If parent is null, then suite will be added to tests root.
263 * @param newSuite Tests suite
265 public void onSuiteStarted(@NotNull final SMTestProxy newSuite) {
266 _addTestOrSuite(newSuite);
269 public void onCustomProgressTestsCategory(@Nullable String categoryName, int testCount) {
270 myCurrentCustomProgressCategory = categoryName;
271 updateCountersAndProgressOnTestCount(testCount, true);
274 public void onCustomProgressTestStarted() {
275 updateCountersAndProgressOnTestStarted(true);
278 public void onCustomProgressTestFailed() {
279 updateCountersAndProgressOnTestFailed(true);
282 public void onTestFinished(@NotNull final SMTestProxy test) {
283 //Do nothing
286 public void onSuiteFinished(@NotNull final SMTestProxy suite) {
287 //Do nothing
290 public SMTestProxy getTestsRootNode() {
291 return myTestsRootNode;
294 public TestConsoleProperties getProperties() {
295 return myConsoleProperties;
298 public void setFilter(final Filter filter) {
299 // is usded by Test Runner actions, e.g. hide passed, etc
300 final SMTRunnerTreeStructure treeStructure = myTreeBuilder.getRTestUnitTreeStructure();
301 treeStructure.setFilter(filter);
302 myTreeBuilder.updateFromRoot();
305 public boolean isRunning() {
306 return getRoot().isInProgress();
309 public TestTreeView getTreeView() {
310 return myTreeView;
313 public boolean hasTestSuites() {
314 return getRoot().getChildren().size() > 0;
317 @NotNull
318 public AbstractTestProxy getRoot() {
319 return myTestsRootNode;
323 * Manual test proxy selectio in tests tree. E.g. do select root node on
324 * testing started or do select current node if TRACK_RUNNING_TEST is enabled
327 * Will select proxy in Event Dispatch Thread. Invocation of this
328 * method may be not in event dispatch thread
329 * @param testProxy Test or suite
331 public void selectAndNotify(@Nullable final AbstractTestProxy testProxy) {
332 selectWithoutNotify(testProxy);
334 // Is used by Statistic tab to differ use selection in tree
335 // from manual selection from API (e.g. test runner events)
336 showStatisticsForSelectedProxy(testProxy, false);
339 public void addEventsListener(final EventsListener listener) {
340 myEventListeners.add(listener);
341 addTestsTreeSelectionListener(new TreeSelectionListener() {
342 public void valueChanged(final TreeSelectionEvent e) {
343 //We should fire event only if it was generated by this component,
344 //e.g. it is focused. Otherwise it is side effect of selecing proxy in
345 //try by other component
346 //if (myTreeView.isFocusOwner()) {
347 @Nullable final PrintableTestProxy selectedProxy = (PrintableTestProxy)getTreeView().getSelectedTest();
348 listener.onSelected(selectedProxy, SMTestRunnerResultsForm.this, SMTestRunnerResultsForm.this);
354 public void dispose() {
355 super.dispose();
356 myShowStatisticForProxyHandler = null;
357 myEventListeners.clear();
360 public void showStatisticsForSelectedProxy() {
361 TestConsoleProperties.SHOW_STATISTICS.set(myProperties, true);
362 final AbstractTestProxy selectedProxy = myTreeView.getSelectedTest();
363 showStatisticsForSelectedProxy(selectedProxy, true);
366 private void showStatisticsForSelectedProxy(final AbstractTestProxy selectedProxy,
367 final boolean requestFocus) {
368 if (selectedProxy instanceof SMTestProxy && myShowStatisticForProxyHandler != null) {
369 myShowStatisticForProxyHandler.handlePropagateSelectionRequest((SMTestProxy)selectedProxy, this, requestFocus);
373 protected int getTestsCurrentCount() {
374 return myTestsCurrentCount;
377 protected int getTestsFailuresCount() {
378 return myTestsFailuresCount;
381 protected Color getTestsStatusColor() {
382 return myStatusLine.getStatusColor();
385 protected int getTestsTotal() {
386 return myTestsTotal;
389 public Set<String> getMentionedCategories() {
390 return myMentionedCategories;
393 protected long getStartTime() {
394 return myStartTime;
397 protected long getEndTime() {
398 return myEndTime;
401 private void _addTestOrSuite(@NotNull final SMTestProxy newTestOrSuite) {
403 final SMTestProxy parentSuite = newTestOrSuite.getParent();
404 assert parentSuite != null;
406 // Tree
407 myTreeBuilder.updateTestsSubtree(parentSuite);
408 myTreeBuilder.repaintWithParents(newTestOrSuite);
410 myAnimator.setCurrentTestCase(newTestOrSuite);
413 private void fireOnTestNodeAdded(final SMTestProxy test) {
414 for (EventsListener eventListener : myEventListeners) {
415 eventListener.onTestNodeAdded(this, test);
419 private void fireOnTestingFinished() {
420 for (EventsListener eventListener : myEventListeners) {
421 eventListener.onTestingFinished(this);
425 private void fireOnTestingStarted() {
426 for (EventsListener eventListener : myEventListeners) {
427 eventListener.onTestingStarted(this);
431 private void selectWithoutNotify(final AbstractTestProxy testProxy) {
432 if (testProxy == null) {
433 return;
436 SMRunnerUtil.runInEventDispatchThread(new Runnable() {
437 public void run() {
438 myTreeBuilder.select(testProxy, null);
440 }, ModalityState.NON_MODAL);
443 private void updateStatusLabel() {
444 if (myTestsFailuresCount > 0) {
445 myStatusLine.setStatusColor(ColorProgressBar.RED);
447 myStatusLine.setText(TestsPresentationUtil.getProgressStatus_Text(myStartTime, myEndTime,
448 myTestsTotal, myTestsCurrentCount,
449 myTestsFailuresCount, myMentionedCategories));
453 * for java unit tests
455 public void performUpdate() {
456 myTreeBuilder.performUpdate();
460 * On event change selection and probably requests focus. Is used when we want
461 * navigate from other component to this
462 * @return Listener
464 public PropagateSelectionHandler createSelectMeListener() {
465 return new PropagateSelectionHandler() {
466 public void handlePropagateSelectionRequest(@Nullable final SMTestProxy selectedTestProxy, @NotNull final Object sender,
467 final boolean requestFocus) {
468 SMRunnerUtil.addToInvokeLater(new Runnable() {
469 public void run() {
470 selectWithoutNotify(selectedTestProxy);
472 // Request focus if necessary
473 if (requestFocus) {
474 //myTreeView.requestFocusInWindow();
475 IdeFocusManager.getInstance(myProject).requestFocus(myTreeView, true);
484 private static class MyAnimator extends TestsProgressAnimator {
485 public MyAnimator(final Disposable parentDisposable, final AbstractTestTreeBuilder builder) {
486 super(parentDisposable);
487 init(builder);
491 private void updateCountersAndProgressOnTestCount(final int count, final boolean isCustomMessage) {
492 if (!isModeConsistent(isCustomMessage)) return;
494 //This is for beter support groups of TestSuites
495 //Each group notifies about it's size
496 myTestsTotal += count;
497 updateStatusLabel();
500 private void updateCountersAndProgressOnTestStarted(final boolean isCustomMessage) {
501 if (!isModeConsistent(isCustomMessage)) return;
503 // for mixed tests results : mention category only if it contained tests
504 myMentionedCategories.add(myCurrentCustomProgressCategory != null ? myCurrentCustomProgressCategory : TestsPresentationUtil.DEFAULT_TESTS_CATEGORY);
506 // Counters
507 myTestsCurrentCount++;
509 // fix total count if it is corrupted
510 // but if test count wasn't set at all let's process such case separately
511 if (myTestsCurrentCount > myTestsTotal && myTestsTotal != 0) {
512 myTestsTotal = myTestsCurrentCount;
515 // update progress
516 if (myTestsTotal != 0) {
517 // if total is set
518 myStatusLine.setFraction((double)myTestsCurrentCount / myTestsTotal);
519 } else {
520 // just set progress in the middle to show user that tests are running
521 myStatusLine.setFraction(0.5);
523 updateStatusLabel();
526 private void updateCountersAndProgressOnTestFailed(final boolean isCustomMessage) {
527 if (!isModeConsistent(isCustomMessage)) return;
529 myTestsFailuresCount++;
530 updateStatusLabel();
533 private boolean isModeConsistent(boolean isCustomMessage) {
534 // check that we are in consistent mode
535 return isCustomMessage != (myCurrentCustomProgressCategory == null);
539 private static class MyFocusTraversalPolicy extends FocusTraversalPolicy {
540 final List<Component> myComponents;
542 private MyFocusTraversalPolicy(final List<Component> components) {
543 myComponents = components;
546 public Component getComponentAfter(final Container container, final Component component) {
547 return myComponents.get((myComponents.indexOf(component) + 1) % myComponents.size());
550 public Component getComponentBefore(final Container container, final Component component) {
551 final int prevIndex = myComponents.indexOf(component) - 1;
552 final int normalizedIndex = prevIndex < 0 ? myComponents.size() - 1 : prevIndex;
554 return myComponents.get(normalizedIndex);
557 public Component getFirstComponent(final Container container) {
558 return myComponents.get(0);
561 public Component getLastComponent(final Container container) {
562 return myComponents.get(myComponents.size() - 1);
565 public Component getDefaultComponent(final Container container) {
566 return getFirstComponent(container);