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.
18 * Created by IntelliJ IDEA.
23 package com.theoryinpractice.testng.ui;
25 import com.intellij.codeInsight.AnnotationUtil;
26 import com.intellij.execution.configurations.ConfigurationPerRunnerSettings;
27 import com.intellij.execution.configurations.RunnerSettings;
28 import com.intellij.execution.testframework.*;
29 import com.intellij.execution.testframework.actions.ScrollToTestSourceAction;
30 import com.intellij.execution.testframework.ui.TestResultsPanel;
31 import com.intellij.openapi.application.ApplicationManager;
32 import com.intellij.openapi.progress.util.ColorProgressBar;
33 import com.intellij.openapi.project.Project;
34 import com.intellij.openapi.util.Computable;
35 import com.intellij.openapi.util.Disposer;
36 import com.intellij.openapi.util.Pass;
37 import com.intellij.openapi.util.text.StringUtil;
38 import com.intellij.psi.*;
39 import com.intellij.psi.util.ClassUtil;
40 import com.intellij.ui.ScrollPaneFactory;
41 import com.intellij.ui.table.TableView;
42 import com.intellij.util.OpenSourceUtil;
43 import com.theoryinpractice.testng.configuration.TestNGConfiguration;
44 import com.theoryinpractice.testng.model.*;
45 import com.theoryinpractice.testng.util.TestNGUtil;
46 import org.jetbrains.annotations.NonNls;
47 import org.testng.remote.strprotocol.MessageHelper;
48 import org.testng.remote.strprotocol.TestResultMessage;
51 import javax.swing.event.TreeSelectionEvent;
52 import javax.swing.event.TreeSelectionListener;
53 import javax.swing.tree.DefaultMutableTreeNode;
54 import javax.swing.tree.TreePath;
56 import java.awt.event.MouseAdapter;
57 import java.awt.event.MouseEvent;
58 import java.text.NumberFormat;
60 import java.util.List;
62 public class TestNGResults extends TestResultsPanel implements TestFrameworkRunningModel {
63 @NonNls private static final String TESTNG_SPLITTER_PROPERTY = "TestNG.Splitter.Proportion";
65 private final TableView resultsTable;
67 private final TestNGResultsTableModel model;
68 private TestNGTestTreeView tree;
70 private final Project project;
73 private final Set<TestProxy> failed = new HashSet<TestProxy>();
74 private final Map<TestResultMessage, List<TestProxy>> started = new HashMap<TestResultMessage, List<TestProxy>>();
75 private TestProxy failedToStart = null;
78 private TestTreeBuilder treeBuilder;
79 private Animator animator;
81 private final TreeRootNode rootNode;
82 private static final String NO_PACKAGE = "No Package";
83 private TestNGResults.OpenSourceSelectionListener openSourceListener;
84 private int myStatus = MessageHelper.PASSED_TEST;
85 private Set<String> startedMethods = new HashSet<String>();
86 private TestProxy myLastSelected;
88 public TestNGResults(final JComponent component,
89 final TestNGConfiguration configuration,
90 final TestNGConsoleView console,
91 final RunnerSettings runnerSettings,
92 final ConfigurationPerRunnerSettings configurationSettings) {
93 super(component, console.getConsole().createConsoleActions(), console.getProperties(),
94 runnerSettings, configurationSettings, TESTNG_SPLITTER_PROPERTY, 0.5f);
95 this.project = configuration.getProject();
97 model = new TestNGResultsTableModel(project);
98 resultsTable = new TableView(model);
99 resultsTable.addMouseListener(new MouseAdapter() {
100 public void mouseClicked(MouseEvent e) {
101 if (e.getClickCount() == 2) {
102 final Object result = resultsTable.getSelectedObject();
103 if (result instanceof TestResultMessage) {
104 final String testClass = ((TestResultMessage)result).getTestClass();
105 final PsiClass psiClass = ClassUtil.findPsiClass(PsiManager.getInstance(project), testClass);
106 if (psiClass != null) {
107 final String method = ((TestResultMessage)result).getMethod();
108 if (method != null) {
109 final PsiMethod[] psiMethods = psiClass.findMethodsByName(method, false);
110 for (PsiMethod psiMethod : psiMethods) {
111 psiMethod.navigate(true);
115 psiClass.navigate(true);
121 rootNode = new TreeRootNode();
122 console.getUnboundOutput().addChild(rootNode);
125 protected JComponent createTestTreeView() {
126 tree = new TestNGTestTreeView();
128 final TestTreeStructure structure = new TestTreeStructure(project, rootNode);
129 tree.attachToModel(this);
130 treeBuilder = new TestTreeBuilder(tree, structure);
131 Disposer.register(this, treeBuilder);
133 animator = new Animator(this, treeBuilder);
135 openSourceListener = new OpenSourceSelectionListener();
136 tree.getSelectionModel().addTreeSelectionListener(openSourceListener);
138 TrackRunningTestUtil.installStopListeners(tree, this, new Pass<AbstractTestProxy>() {
140 public void pass(AbstractTestProxy abstractTestProxy) {
141 myLastSelected = (TestProxy)abstractTestProxy;
149 protected ToolbarPanel createToolbarPanel() {
150 final ToolbarPanel panel = new ToolbarPanel(getProperties(), myRunnerSettings, myConfigurationSettings, this);
151 panel.setModel(this);
155 public TestConsoleProperties getProperties() {
159 protected JComponent createStatisticsPanel() {
160 final JPanel panel = new JPanel(new BorderLayout()); //do not remove wrapper panel
161 panel.add(ScrollPaneFactory.createScrollPane(resultsTable), BorderLayout.CENTER);
165 private void updateStatusLine() {
166 myStatusLine.setText(getStatusLine());
169 public int getStatus() {
173 public String getStatusLine() {
174 StringBuffer sb = new StringBuffer();
175 if (end == 0 && start > 0) {
176 sb.append("Running: ");
179 if (failed.size() > 0) sb.append("Failed: ").append(failed.size()).append(" ");
182 sb.append(count).append(" of ").append(total);
184 if (failed.size() > 0) {
185 sb.append(" Failed: ").append(failed.size());
189 final long time = end - start;
190 sb.append(" (").append(time == 0 ? "0.0 s" : NumberFormat.getInstance().format((double)time / 1000.0) + " s").append(") ");
192 return sb.toString();
195 public TestProxy testStarted(TestResultMessage result) {
196 return testStarted(result, true);
199 public TestProxy testStarted(TestResultMessage result, boolean registerDups) {
200 TestProxy classNode = getPackageClassNodeFor(result);
201 TestProxy proxy = new TestProxy();
202 proxy.setParent(classNode);
203 proxy.setResultMessage(result);
204 synchronized (started) {
206 List<TestProxy> dups = started.get(result);
208 dups = new ArrayList<TestProxy>();
209 started.put(result, dups);
214 final String testMethodDescriptor = result.getTestClass() + result.getMethod();
215 if (startedMethods.contains(testMethodDescriptor)) {
219 startedMethods.add(testMethodDescriptor);
221 animator.setCurrentTestCase(proxy);
222 treeBuilder.addItem(classNode, proxy);
223 treeBuilder.repaintWithParents(proxy);
225 if (count > total) total = count;
226 if (myLastSelected == proxy) {
227 myLastSelected = null;
229 if (myLastSelected == null && TestConsoleProperties.TRACK_RUNNING_TEST.value(myProperties)) {
235 public void addTestResult(final TestResultMessage result, int exceptionMark) {
237 synchronized (started) {
238 final List<TestProxy> dups = started.get(result);
239 testCase = dups == null || dups.isEmpty() ? null : dups.remove(0);
241 if (testCase == null) {
242 final PsiElement element = getPackageClassNodeFor(result).getPsiElement();
243 if (element instanceof PsiClass) {
244 final PsiMethod[] methods = ApplicationManager.getApplication().runReadAction(
245 new Computable<PsiMethod[]>() {
246 public PsiMethod[] compute() {
247 return ((PsiClass)element).findMethodsByName(result.getMethod(), true);
251 if (methods.length > 0 &&
252 methods[0] != null &&
253 !AnnotationUtil.isAnnotated(methods[0], Arrays.asList(TestNGUtil.CONFIG_ANNOTATIONS_FQN))) {
254 for (List<TestProxy> proxies : started.values()) {
255 if (proxies != null) {
256 for (TestProxy proxy : proxies) {
257 if (methods[0].equals(proxy.getPsiElement())) {
264 if (testCase == null) {
265 testCase = testStarted(result, false);
266 testCase.appendStacktrace(result);
272 if (testCase != null) {
273 testCase.setResultMessage(result);
274 testCase.setTearDownFailure(failedToStart != null);
275 failedToStart = null;
277 if (result.getResult() == MessageHelper.FAILED_TEST) {
278 failed.add(testCase);
280 model.addTestResult(result);
283 //do not remember testresultmessage: test hierarchy is not set
284 testCase = new TestProxy(TestProxy.toDisplayText(result, project));
285 testCase.appendStacktrace(result);
286 if (failedToStart != null) {
287 failedToStart.addChild(testCase);
288 failedToStart.setTearDownFailure(true);
291 failedToStart = testCase;
295 testCase.setExceptionMark(exceptionMark);
296 AbstractTestProxy.flushOutput(testCase);
298 if (result.getResult() == MessageHelper.FAILED_TEST) {
299 myStatusLine.setStatusColor(ColorProgressBar.RED);
300 myStatus = MessageHelper.FAILED_TEST;
302 else if (result.getResult() == MessageHelper.SKIPPED_TEST && myStatus == MessageHelper.PASSED_TEST) {
303 myStatus = MessageHelper.SKIPPED_TEST;
305 myStatusLine.setFraction((double)count / total);
309 private TestProxy getPackageClassNodeFor(final TestResultMessage result) {
310 TestProxy owner = treeBuilder.getRoot();
311 final String packageName1 = StringUtil.getPackageName(result.getTestClass());
312 String packageName = packageName1.length() == 0 ? NO_PACKAGE : packageName1;
313 owner = getChildNodeNamed(owner, packageName);
314 if (owner.getPsiElement() == null) {
315 owner.setPsiElement(JavaPsiFacade.getInstance(project).findPackage(packageName));
317 owner = getChildNodeNamed(owner, StringUtil.getShortName(result.getTestClass()));
318 //look up the psiclass now
319 if (owner.getPsiElement() == null) {
320 final TestProxy finalOwner = owner;
321 ApplicationManager.getApplication().runReadAction(new Runnable() {
323 finalOwner.setPsiElement(ClassUtil.findPsiClass(PsiManager.getInstance(project), result.getTestClass()));
330 private TestProxy getChildNodeNamed(TestProxy currentNode, String node) {
331 for (TestProxy child : currentNode.getChildren()) {
332 if (child.getName().equals(node)) {
337 TestProxy child = new TestProxy(node);
338 treeBuilder.addItem(currentNode, child);
342 public void selectTest(TestProxy proxy) {
343 if (proxy == null) return;
344 treeBuilder.select(proxy, null);
347 public void setTotal(int total) {
351 public void start() {
353 start = System.currentTimeMillis();
355 treeBuilder.select(rootNode);
356 rootNode.setInProgress(true);
357 rootNode.setStarted(true);
360 public void finish() {
362 end = System.currentTimeMillis();
364 LvcsHelper.addLabel(this);
366 SwingUtilities.invokeLater(new Runnable() {
368 animator.stopMovie();
371 myStatusLine.setStatusColor(ColorProgressBar.YELLOW);
373 rootNode.setInProgress(false);
374 if (TestNGConsoleProperties.SELECT_FIRST_DEFECT.value(myProperties)) {
375 selectTest(rootNode.getFirstDefect());
378 final DefaultMutableTreeNode node = treeBuilder.getNodeForElement(rootNode);
379 if (node != null && myLastSelected == null) {
380 tree.getSelectionModel().setSelectionPath(new TreePath(node));
388 public void setFilter(final Filter filter) {
389 getTreeStructure().setFilter(filter);
390 treeBuilder.updateFromRoot();
393 public boolean isRunning() {
394 return rootNode.isInProgress();
397 public TestTreeView getTreeView() {
402 public TestTreeBuilder getTreeBuilder() {
406 public boolean hasTestSuites() {
407 return rootNode.getChildren().size() > 0;
410 public TestProxy getRoot() {
414 public void selectAndNotify(final AbstractTestProxy testProxy) {
415 selectTest((TestProxy)testProxy);
418 public TestTreeStructure getTreeStructure() {
419 return (TestTreeStructure)treeBuilder.getTreeStructure();
422 public void rebuildTree() {
423 treeBuilder.updateFromRoot();
427 public void dispose() {
429 tree.getSelectionModel().removeTreeSelectionListener(openSourceListener);
432 public TestProxy getFailedToStart() {
433 return failedToStart;
436 public void setFailedToStart(TestProxy failedToStart) {
437 this.failedToStart = failedToStart;
440 private class OpenSourceSelectionListener implements TreeSelectionListener {
442 public void valueChanged(TreeSelectionEvent e) {
443 TreePath path = e.getPath();
444 if (path == null) return;
445 TestProxy proxy = (TestProxy)tree.getSelectedTest();
446 if (proxy == null) return;
447 if (ScrollToTestSourceAction.isScrollEnabled(TestNGResults.this)) {
448 OpenSourceUtil.openSourcesFrom(tree, false);