1 package com
.intellij
.execution
.testframework
.sm
.runner
;
3 import com
.intellij
.execution
.process
.ProcessOutputTypes
;
4 import com
.intellij
.execution
.testframework
.AbstractTestProxy
;
5 import com
.intellij
.execution
.testframework
.sm
.SMRunnerUtil
;
6 import com
.intellij
.openapi
.application
.Application
;
7 import com
.intellij
.openapi
.application
.ApplicationManager
;
8 import com
.intellij
.openapi
.diagnostic
.Logger
;
9 import com
.intellij
.openapi
.util
.Key
;
10 import org
.jetbrains
.annotations
.NotNull
;
11 import org
.jetbrains
.annotations
.Nullable
;
12 import org
.jetbrains
.annotations
.TestOnly
;
17 * @author: Roman Chernyatchik
19 * This class fires events to RTestUnitEventsListener in EventDispatch thread
21 public class GeneralToSMTRunnerEventsConvertor
implements GeneralTestEventsProcessor
{
22 private static final Logger LOG
= Logger
.getInstance(GeneralToSMTRunnerEventsConvertor
.class.getName());
24 private final Map
<String
, SMTestProxy
> myRunningTestsFullNameToProxy
= new HashMap
<String
, SMTestProxy
>();
26 private final Set
<AbstractTestProxy
> myFailedTestsSet
= new HashSet
<AbstractTestProxy
>();
28 private final TestSuiteStack mySuitesStack
= new TestSuiteStack();
29 private final List
<SMTRunnerEventsListener
> myEventsListeners
= new ArrayList
<SMTRunnerEventsListener
>();
30 private final SMTestProxy myTestsRootNode
;
31 private boolean myIsTestingFinished
;
33 public GeneralToSMTRunnerEventsConvertor(@NotNull final SMTestProxy testsRootNode
) {
34 myTestsRootNode
= testsRootNode
;
37 public void addEventsListener(final SMTRunnerEventsListener listener
) {
38 myEventsListeners
.add(listener
);
41 public void onStartTesting() {
42 SMRunnerUtil
.addToInvokeLater(new Runnable() {
44 mySuitesStack
.pushSuite(myTestsRootNode
);
45 myTestsRootNode
.setStarted();
48 fireOnTestingStarted();
53 public void onFinishTesting() {
54 SMRunnerUtil
.addToInvokeLater(new Runnable() {
56 if (myIsTestingFinished
) {
57 // has been already invoked!
60 myIsTestingFinished
= true;
62 // We don't know whether process was destroyed by user
63 // or it finished after all tests have been run
64 // Lets assume, if at finish all suites except root suite are passed
65 // then all is ok otherwise process was terminated by user
66 if (!myTestsRootNode
.equals(mySuitesStack
.getCurrentSuite())) {
67 myTestsRootNode
.setTerminated();
68 myRunningTestsFullNameToProxy
.clear();
70 mySuitesStack
.clear();
71 myTestsRootNode
.setFinished();
75 fireOnTestingFinished();
80 public void onTestStarted(final String testName
, final String locationUrl
) {
81 SMRunnerUtil
.addToInvokeLater(new Runnable() {
83 final String fullName
= getFullTestName(testName
);
85 if (myRunningTestsFullNameToProxy
.containsKey(fullName
)) {
87 LOG
.warn("Test [" + fullName
+ "] has been already started");
91 final SMTestProxy parentSuite
= getCurrentSuite();
94 final SMTestProxy testProxy
= new SMTestProxy(testName
, false, locationUrl
);
95 parentSuite
.addChild(testProxy
);
96 // adds to running tests map
97 myRunningTestsFullNameToProxy
.put(fullName
, testProxy
);
100 testProxy
.setStarted();
103 fireOnTestStarted(testProxy
);
108 public void onSuiteStarted(final String suiteName
, final String locationUrl
) {
109 SMRunnerUtil
.addToInvokeLater(new Runnable() {
111 final SMTestProxy parentSuite
= getCurrentSuite();
113 final SMTestProxy newSuite
= new SMTestProxy(suiteName
, true, locationUrl
);
114 parentSuite
.addChild(newSuite
);
116 mySuitesStack
.pushSuite(newSuite
);
119 newSuite
.setStarted();
122 fireOnSuiteStarted(newSuite
);
127 public void onTestFinished(final String testName
, final int duration
) {
128 SMRunnerUtil
.addToInvokeLater(new Runnable() {
130 final String fullTestName
= getFullTestName(testName
);
131 final SMTestProxy testProxy
= getProxyByFullTestName(fullTestName
);
132 if (testProxy
== null) {
133 LOG
.warn("Test wasn't started! TestFinished event: name = {" + testName
+ "}. " +
134 cannotFindFullTestNameMsg(fullTestName
));
138 testProxy
.setDuration(duration
);
139 testProxy
.setFinished();
140 myRunningTestsFullNameToProxy
.remove(fullTestName
);
143 fireOnTestFinished(testProxy
);
148 public void onSuiteFinished(final String suiteName
) {
149 SMRunnerUtil
.addToInvokeLater(new Runnable() {
151 final SMTestProxy mySuite
= mySuitesStack
.popSuite(suiteName
);
152 mySuite
.setFinished();
155 fireOnSuiteFinished(mySuite
);
160 public void onUncapturedOutput(final String text
, final Key outputType
) {
161 SMRunnerUtil
.addToInvokeLater(new Runnable() {
163 //if we can locate test - we will send outout to it, otherwise to current test suite
164 final SMTestProxy currentProxy
;
165 if (myRunningTestsFullNameToProxy
.size() == 1) {
167 currentProxy
= myRunningTestsFullNameToProxy
.values().iterator().next();
171 // ProcessHandler can fire output available event before processStarted event
172 currentProxy
= mySuitesStack
.isEmpty() ? myTestsRootNode
: getCurrentSuite();
175 if (ProcessOutputTypes
.STDERR
.equals(outputType
)) {
176 currentProxy
.addStdErr(text
);
177 } else if (ProcessOutputTypes
.SYSTEM
.equals(outputType
)) {
178 currentProxy
.addSystemOutput(text
);
180 currentProxy
.addStdOutput(text
, outputType
);
186 public void onTestFailure(final String testName
,
187 final String localizedMessage
, final String stackTrace
,
188 final boolean isTestError
) {
189 SMRunnerUtil
.addToInvokeLater(new Runnable() {
191 final String fullTestName
= getFullTestName(testName
);
192 final SMTestProxy testProxy
= getProxyByFullTestName(fullTestName
);
193 if (testProxy
== null) {
194 LOG
.warn("Test wasn't started! TestFailure event: name = {" + testName
+ "}" +
195 ", message = {" + localizedMessage
+ "}" +
196 ", stackTrace = {" + stackTrace
+ "}. " +
197 cannotFindFullTestNameMsg(fullTestName
));
200 // if wasn't processed
201 if (myFailedTestsSet
.contains(testProxy
)) {
203 LOG
.warn("Duplicate failure for test [" + fullTestName
+ "]: msg = " + localizedMessage
+ ", stacktrace = " + stackTrace
);
207 testProxy
.setTestFailed(localizedMessage
, stackTrace
, isTestError
);
210 myFailedTestsSet
.add(testProxy
);
213 fireOnTestFailed(testProxy
);
218 public void onTestIgnored(final String testName
, final String ignoreComment
,
219 @Nullable final String stackTrace
) {
220 SMRunnerUtil
.addToInvokeLater(new Runnable() {
222 final String fullTestName
= getFullTestName(testName
);
223 final SMTestProxy testProxy
= getProxyByFullTestName(fullTestName
);
224 if (testProxy
== null) {
225 LOG
.warn("Test wasn't started! " +
226 "TestIgnored event: name = {" + testName
+ "}, " +
227 "message = {" + ignoreComment
+ "}. " +
228 cannotFindFullTestNameMsg(fullTestName
));
232 testProxy
.setTestIgnored(ignoreComment
, stackTrace
);
235 fireOnTestIgnored(testProxy
);
240 public void onTestOutput(final String testName
,
241 final String text
, final boolean stdOut
) {
242 SMRunnerUtil
.addToInvokeLater(new Runnable() {
244 final String fullTestName
= getFullTestName(testName
);
245 final SMTestProxy testProxy
= getProxyByFullTestName(fullTestName
);
246 if (testProxy
== null) {
247 LOG
.warn("Test wasn't started! TestOutput event: name = {" + testName
+ "}, " +
248 "isStdOut = " + stdOut
+ ", " +
249 "text = {" + text
+ "}. " +
250 cannotFindFullTestNameMsg(fullTestName
));
255 testProxy
.addStdOutput(text
, ProcessOutputTypes
.STDOUT
);
257 testProxy
.addStdErr(text
);
263 public void onTestsCountInSuite(final int count
) {
264 SMRunnerUtil
.addToInvokeLater(new Runnable() {
266 fireOnTestsCountInSuite(count
);
272 protected final SMTestProxy
getCurrentSuite() {
273 final SMTestProxy currentSuite
= mySuitesStack
.getCurrentSuite();
275 if (currentSuite
!= null) {
279 // current suite shouldn't be null otherwise test runner isn't correct
280 // or may be we are in debug mode
281 LOG
.warn("Current suite is undefined. Root suite will be used.");
282 return myTestsRootNode
;
286 protected String
getFullTestName(final String testName
) {
287 // Test name should be unique
291 protected int getRunningTestsQuantity() {
292 return myRunningTestsFullNameToProxy
.size();
295 protected Set
<AbstractTestProxy
> getFailedTestsSet() {
296 return Collections
.unmodifiableSet(myFailedTestsSet
);
300 protected SMTestProxy
getProxyByFullTestName(final String fullTestName
) {
301 return myRunningTestsFullNameToProxy
.get(fullTestName
);
305 protected void clearInternalSuitesStack() {
306 mySuitesStack
.clear();
309 private String
cannotFindFullTestNameMsg(String fullTestName
) {
310 return "Cant find running test for ["
312 + "]. Current running tests: {"
313 + dumpRunningTestsNames() + "}";
316 private StringBuilder
dumpRunningTestsNames() {
317 final Set
<String
> names
= myRunningTestsFullNameToProxy
.keySet();
318 final StringBuilder namesDump
= new StringBuilder();
319 for (String name
: names
) {
320 namesDump
.append('[').append(name
).append(']').append(',');
325 private void fireOnTestingStarted() {
326 for (SMTRunnerEventsListener listener
: myEventsListeners
) {
327 listener
.onTestingStarted(myTestsRootNode
);
331 private void fireOnTestingFinished() {
332 for (SMTRunnerEventsListener listener
: myEventsListeners
) {
333 listener
.onTestingFinished(myTestsRootNode
);
337 private void fireOnTestsCountInSuite(final int count
) {
338 for (SMTRunnerEventsListener listener
: myEventsListeners
) {
339 listener
.onTestsCountInSuite(count
);
344 private void fireOnTestStarted(final SMTestProxy test
) {
345 for (SMTRunnerEventsListener listener
: myEventsListeners
) {
346 listener
.onTestStarted(test
);
350 private void fireOnTestFinished(final SMTestProxy test
) {
351 for (SMTRunnerEventsListener listener
: myEventsListeners
) {
352 listener
.onTestFinished(test
);
356 private void fireOnTestFailed(final SMTestProxy test
) {
357 for (SMTRunnerEventsListener listener
: myEventsListeners
) {
358 listener
.onTestFailed(test
);
362 private void fireOnTestIgnored(final SMTestProxy test
) {
363 for (SMTRunnerEventsListener listener
: myEventsListeners
) {
364 listener
.onTestIgnored(test
);
368 private void fireOnSuiteStarted(final SMTestProxy suite
) {
369 for (SMTRunnerEventsListener listener
: myEventsListeners
) {
370 listener
.onSuiteStarted(suite
);
374 private void fireOnSuiteFinished(final SMTestProxy suite
) {
375 for (SMTRunnerEventsListener listener
: myEventsListeners
) {
376 listener
.onSuiteFinished(suite
);
381 * Remove listeners, etc
383 public void dispose() {
384 SMRunnerUtil
.addToInvokeLater(new Runnable() {
386 myEventsListeners
.clear();
388 if (!myRunningTestsFullNameToProxy
.isEmpty()) {
389 final Application application
= ApplicationManager
.getApplication();
390 if (!application
.isHeadlessEnvironment() && !application
.isUnitTestMode()) {
391 LOG
.warn("Not all events were processed! " + dumpRunningTestsNames());
394 myRunningTestsFullNameToProxy
.clear();
395 mySuitesStack
.clear();