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
;
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
) {
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() {
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
);
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
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() {
130 public Location
getLocation(final Project project
) {
131 //determines location of test proxy
133 //TODO multiresolve support
135 if (myLocationUrl
== 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();
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());
165 public boolean isSuite() {
169 public SMTestProxy
getParent() {
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
>();
182 for (SMTestProxy child
: getChildren()) {
183 allTests
.addAll(child
.getAllTests());
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;
199 public Integer
getDuration() {
200 // Returns duration value for tests
201 // or cached duration for suites
202 if (myDurationIsCached
|| !isSuite()) {
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;
218 * Sets duration of test
219 * @param duration In milliseconds
221 public void setDuration(final int duration
) {
222 invalidateCachedDurationForContainerSuites();
225 myDurationIsCached
= true;
226 myDuration
= (duration
>= 0) ? duration
: null;
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
244 // if isn't in other finished state (ignored, failed or passed)
245 myState
= TestPassedState
.INSTACE
;
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
) {
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
) {
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) {
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
) {
303 if (myChildren
== null) {
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
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
);
363 public String
getPresentableName() {
364 return TestsPresentationUtil
.getPresentableName(this);
368 public String
toString() {
369 return getPresentableName();
373 * Process was terminated
375 public void setTerminated() {
376 if (myState
.isFinal()) {
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();
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
) {
410 private boolean containsFailedTests() {
411 final List
<?
extends SMTestProxy
> children
= getChildren();
412 for (SMTestProxy child
: children
) {
413 if (child
.getMagnitudeInfo() == TestStateInfo
.Magnitude
.FAILED_INDEX
) {
421 * Determines site state after it has been finished
424 private AbstractState
determineSuiteStateOnFinished() {
425 final AbstractState state
;
427 state
= SuiteFinishedState
.EMPTY_SUITE
;
430 // Test suit contains errors if at least one of its tests contains error
431 if (containsErrorTests()) {
432 state
= SuiteFinishedState
.ERROR_SUITE
;
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
;
441 state
= SuiteFinishedState
.PASSED_SUITE
;
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
470 myDurationIsCached
= false;
472 // Invalidates duration of container suite
473 final SMTestProxy containerSuite
= getParent();
474 if (containerSuite
!= null) {
475 containerSuite
.invalidateCachedDurationForContainerSuites();