1. utility class was renamed. 2. location provider util class was refactored for...
[fedora-idea.git] / platform / smRunner / src / com / intellij / execution / testframework / sm / runner / SMTestProxy.java
blob8ffba72416ff6ae9b3a88c4614daa06969b85522
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;
18 import com.intellij.execution.Location;
19 import com.intellij.execution.testframework.*;
20 import com.intellij.execution.testframework.sm.TestsLocationProviderUtil;
21 import com.intellij.execution.testframework.sm.runner.states.*;
22 import com.intellij.execution.testframework.sm.runner.ui.TestsPresentationUtil;
23 import com.intellij.execution.testframework.ui.PrintableTestProxy;
24 import com.intellij.execution.ui.ConsoleViewContentType;
25 import com.intellij.ide.util.EditSourceUtil;
26 import com.intellij.openapi.diagnostic.Logger;
27 import com.intellij.openapi.extensions.Extensions;
28 import com.intellij.openapi.project.Project;
29 import com.intellij.openapi.util.Key;
30 import com.intellij.pom.Navigatable;
31 import com.intellij.testIntegration.TestLocationProvider;
32 import org.jetbrains.annotations.NotNull;
33 import org.jetbrains.annotations.Nullable;
35 import java.util.ArrayList;
36 import java.util.Collections;
37 import java.util.List;
39 /**
40 * @author: Roman Chernyatchik
42 public class SMTestProxy extends CompositePrintable implements PrintableTestProxy {
43 private static final Logger LOG = Logger.getInstance(SMTestProxy.class.getName());
45 private List<SMTestProxy> myChildren;
46 private SMTestProxy myParent;
48 private AbstractState myState = NotRunState.getInstance();
49 private final String myName;
50 private Integer myDuration = null; // duration is unknown
51 @Nullable private final String myLocationUrl;
52 private boolean myDurationIsCached = false; // is used for separating unknown and unset duration
55 private Printer myPrinter = Printer.DEAF;
57 private final boolean myIsSuite;
59 public SMTestProxy(final String testName, final boolean isSuite,
60 @Nullable final String locationUrl) {
61 myName = testName;
62 myIsSuite = isSuite;
63 myLocationUrl = locationUrl;
66 public boolean isInProgress() {
67 //final SMTestProxy parent = getParent();
69 return myState.isInProgress();
72 public boolean isDefect() {
73 return myState.isDefect();
76 public boolean shouldRun() {
77 return true;
80 public int getMagnitude() {
81 // Is used by some of Tests Filters
83 //WARN: It is Hack, see PoolOfTestStates, API is necessary
84 return getMagnitudeInfo().getValue();
87 public TestStateInfo.Magnitude getMagnitudeInfo() {
88 return myState.getMagnitude();
91 public boolean isLeaf() {
92 return myChildren == null || myChildren.isEmpty();
95 public boolean isPassed() {
96 return myState.getMagnitude() == TestStateInfo.Magnitude.SKIPPED_INDEX ||
97 myState.getMagnitude() == TestStateInfo.Magnitude.COMPLETE_INDEX ||
98 myState.getMagnitude() == TestStateInfo.Magnitude.PASSED_INDEX;
101 public void addChild(final SMTestProxy child) {
102 if (myChildren == null) {
103 myChildren = new ArrayList<SMTestProxy>();
105 myChildren.add(child);
107 // add printable
109 // add link to child's future output in correct place
110 // actually if after this suite will obtain output
111 // it will place it after this child and before future child
112 addLast(child);
114 // add child
116 //TODO reset children cache
117 child.setParent(this);
118 // if parent is being printed then all childs output
119 // should be also send to the same printer
120 if (myPrinter != Printer.DEAF) {
121 child.setPrintLinstener(myPrinter);
125 public String getName() {
126 return myName;
129 @Nullable
130 public Location getLocation(final Project project) {
131 //determines location of test proxy
133 //TODO multiresolve support
135 if (myLocationUrl == null) {
136 return null;
139 final String protocolId = TestsLocationProviderUtil.extractProtocol(myLocationUrl);
140 final String path = TestsLocationProviderUtil.extractPath(myLocationUrl);
142 if (protocolId != null && path != null) {
143 for (TestLocationProvider provider : Extensions.getExtensions(TestLocationProvider.EP_NAME)) {
144 final List<Location> locations = provider.getLocation(protocolId, path, project);
145 if (!locations.isEmpty()) {
146 return locations.iterator().next();
151 return null;
154 @Nullable
155 public Navigatable getDescriptor(final Location location) {
156 // by location gets navigatable element.
157 // It can be file or place in file (e.g. when OPEN_FAILURE_LINE is enabled)
159 if (location != null) {
160 return EditSourceUtil.getDescriptor(location.getPsiElement());
162 return null;
165 public boolean isSuite() {
166 return myIsSuite;
169 public SMTestProxy getParent() {
170 return myParent;
173 public List<? extends SMTestProxy> getChildren() {
174 return myChildren != null ? myChildren : Collections.<SMTestProxy>emptyList();
177 public List<SMTestProxy> getAllTests() {
178 final List<SMTestProxy> allTests = new ArrayList<SMTestProxy>();
180 allTests.add(this);
182 for (SMTestProxy child : getChildren()) {
183 allTests.addAll(child.getAllTests());
186 return allTests;
190 public void setStarted() {
191 myState = !myIsSuite ? TestInProgressState.TEST : new SuiteInProgressState(this);
195 * Calculates and caches duration of test or suite
196 * @return null if duration is unknown, otherwise duration value in milliseconds;
198 @Nullable
199 public Integer getDuration() {
200 // Returns duration value for tests
201 // or cached duration for suites
202 if (myDurationIsCached || !isSuite()) {
203 return myDuration;
206 //For suites counts and caches durations of its children. Also it evaluates partial duration,
207 //i.e. if duration is unknown it will be ignored in summary value.
208 //If duration for all children is unknown summary duration will be also unknown
209 //if one of children is ignored - it's duration will be 0 and if child wasn't run,
210 //then it's duration will be unknown
211 myDuration = calcSuiteDuration();
212 myDurationIsCached = true;
214 return myDuration;
218 * Sets duration of test
219 * @param duration In milliseconds
221 public void setDuration(final int duration) {
222 invalidateCachedDurationForContainerSuites();
224 if (!isSuite()) {
225 myDurationIsCached = true;
226 myDuration = (duration >= 0) ? duration : null;
227 return;
230 // Not allow to diractly set duration for suites.
231 // It should be the sum of children. This requirement is only
232 // for safety of current model and may be changed
233 LOG.warn("Unsupported operation");
236 public void setFinished() {
237 if (myState.isFinal()) {
238 // we shouldn't fire new printable because final state
239 // has been already fired
240 return;
243 if (!isSuite()) {
244 // if isn't in other finished state (ignored, failed or passed)
245 myState = TestPassedState.INSTACE;
246 } else {
247 //Test Suite
248 myState = determineSuiteStateOnFinished();
250 // prints final state additional info
251 fireOnNewPrintable(myState);
254 public void setTestFailed(@NotNull final String localizedMessage,
255 @NotNull final String stackTrace, final boolean testError) {
256 myState = testError
257 ? new TestErrorState(localizedMessage, stackTrace)
258 : new TestFailedState(localizedMessage, stackTrace);
259 fireOnNewPrintable(myState);
262 public void setTestIgnored(@NotNull final String ignoreComment,
263 @Nullable final String stackTrace) {
264 myState = new TestIgnoredState(ignoreComment, stackTrace);
265 fireOnNewPrintable(myState);
268 public void setParent(@Nullable final SMTestProxy parent) {
269 myParent = parent;
272 public List<? extends SMTestProxy> getChildren(@Nullable final Filter filter) {
273 final List<? extends SMTestProxy> allChildren = getChildren();
275 if (filter == Filter.NO_FILTER || filter == null) {
276 return allChildren;
279 final List<SMTestProxy> selectedChildren = new ArrayList<SMTestProxy>();
280 for (SMTestProxy child : allChildren) {
281 if (filter.shouldAccept(child)) {
282 selectedChildren.add(child);
286 if ((selectedChildren.isEmpty())) {
287 return Collections.<SMTestProxy>emptyList();
289 return selectedChildren;
292 public boolean wasLaunched() {
293 return myState.wasLaunched();
296 public boolean isRoot() {
297 return getParent() == null;
300 public void setPrintLinstener(final Printer printer) {
301 myPrinter = printer;
303 if (myChildren == null) {
304 return;
307 for (ChangingPrintable child : myChildren) {
308 child.setPrintLinstener(printer);
313 * Prints this proxy and all its children on given printer
314 * @param printer Printer
316 public void printOn(final Printer printer) {
317 super.printOn(printer);
319 //Tests State, that provide and formats additional output
320 myState.printOn(printer);
324 * Stores printable information in internal buffer and notifies
325 * proxy's printer about new text available
326 * @param printable Printable info
328 @Override
329 public void addLast(final Printable printable) {
330 super.addLast(printable);
331 fireOnNewPrintable(printable);
334 public void addStdOutput(final String output, final Key outputType) {
335 addLast(new Printable() {
336 public void printOn(final Printer printer) {
337 printer.print(output, ConsoleViewContentType.getConsoleViewType(outputType));
342 public void addStdErr(final String output) {
343 addLast(new Printable() {
344 public void printOn(final Printer printer) {
345 printer.print(output, ConsoleViewContentType.ERROR_OUTPUT);
350 public void addSystemOutput(final String output) {
351 addLast(new Printable() {
352 public void printOn(final Printer printer) {
353 printer.print(output, ConsoleViewContentType.SYSTEM_OUTPUT);
358 private void fireOnNewPrintable(final Printable printable) {
359 myPrinter.onNewAvailable(printable);
362 @NotNull
363 public String getPresentableName() {
364 return TestsPresentationUtil.getPresentableName(this);
367 @Override
368 public String toString() {
369 return getPresentableName();
373 * Process was terminated
375 public void setTerminated() {
376 if (myState.isFinal()) {
377 return;
379 myState = TerminatedState.INSTANCE;
380 final List<? extends SMTestProxy> children = getChildren();
381 for (SMTestProxy child : children) {
382 child.setTerminated();
384 fireOnNewPrintable(myState);
387 public boolean wasTerminated() {
388 return myState.wasTerminated();
391 @Nullable
392 protected String getLocationUrl() {
393 return myLocationUrl;
397 * Check if suite contains error tests or suites
398 * @return True if contains
400 private boolean containsErrorTests() {
401 final List<? extends SMTestProxy> children = getChildren();
402 for (SMTestProxy child : children) {
403 if (child.getMagnitudeInfo() == TestStateInfo.Magnitude.ERROR_INDEX) {
404 return true;
407 return false;
410 private boolean containsFailedTests() {
411 final List<? extends SMTestProxy> children = getChildren();
412 for (SMTestProxy child : children) {
413 if (child.getMagnitudeInfo() == TestStateInfo.Magnitude.FAILED_INDEX) {
414 return true;
417 return false;
421 * Determines site state after it has been finished
422 * @return New state
424 private AbstractState determineSuiteStateOnFinished() {
425 final AbstractState state;
426 if (isLeaf()) {
427 state = SuiteFinishedState.EMPTY_SUITE;
428 } else {
429 if (isDefect()) {
430 // Test suit contains errors if at least one of its tests contains error
431 if (containsErrorTests()) {
432 state = SuiteFinishedState.ERROR_SUITE;
433 }else {
434 // if suite contains failed tests - all suite should be
435 // consider as failed
436 state = containsFailedTests()
437 ? SuiteFinishedState.FAILED_SUITE
438 : SuiteFinishedState.WITH_IGNORED_TESTS_SUITE;
440 } else {
441 state = SuiteFinishedState.PASSED_SUITE;
444 return state;
447 @Nullable
448 private Integer calcSuiteDuration() {
449 int partialDuration = 0;
450 boolean durationOfChildrenIsUnknown = true;
452 for (SMTestProxy child : getChildren()) {
453 final Integer duration = child.getDuration();
454 if (duration != null) {
455 durationOfChildrenIsUnknown = false;
456 partialDuration += duration.intValue();
459 // Lets convert partial duration in integer object. Negative partial duration
460 // means that duration of all children is unknown
461 return durationOfChildrenIsUnknown ? null : partialDuration;
465 * Recursively invalidates cached duration for container(parent) suites
467 private void invalidateCachedDurationForContainerSuites() {
468 // Invalidates duration of this suite
469 myDuration = null;
470 myDurationIsCached = false;
472 // Invalidates duration of container suite
473 final SMTestProxy containerSuite = getParent();
474 if (containerSuite != null) {
475 containerSuite.invalidateCachedDurationForContainerSuites();