1 package org.apache.maven.surefire.junit;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.lang.reflect.InvocationHandler;
23 import java.lang.reflect.Method;
24 import java.util.HashSet;
25 import java.util.Set;
26
27 import org.apache.maven.surefire.report.LegacyPojoStackTraceWriter;
28 import org.apache.maven.surefire.report.ReportEntry;
29 import org.apache.maven.surefire.report.RunListener;
30 import org.apache.maven.surefire.report.SimpleReportEntry;
31 import org.apache.maven.surefire.report.StackTraceWriter;
32
33 import static org.apache.maven.surefire.report.SimpleReportEntry.withException;
34 import static org.apache.maven.surefire.util.internal.TestClassMethodNameUtils.extractClassName;
35 import static org.apache.maven.surefire.util.internal.TestClassMethodNameUtils.extractMethodName;
36
37
38
39
40
41 public class TestListenerInvocationHandler
42 implements InvocationHandler
43 {
44
45 private static final String START_TEST = "startTest";
46
47 private static final String ADD_FAILURE = "addFailure";
48
49 private static final String ADD_ERROR = "addError";
50
51 private static final String END_TEST = "endTest";
52
53 private final Set<FailedTest> failedTestsSet = new HashSet<>();
54
55 private RunListener reporter;
56
57 private static final Class[] EMPTY_CLASS_ARRAY = { };
58
59 private static final Object[] EMPTY_STRING_ARRAY = { };
60
61 private static class FailedTest
62 {
63 private Object testThatFailed;
64
65 private Thread threadOnWhichTestFailed;
66
67 FailedTest( Object testThatFailed, Thread threadOnWhichTestFailed )
68 {
69 if ( testThatFailed == null )
70 {
71 throw new NullPointerException( "testThatFailed is null" );
72 }
73
74 if ( threadOnWhichTestFailed == null )
75 {
76 throw new NullPointerException( "threadOnWhichTestFailed is null" );
77 }
78
79 this.testThatFailed = testThatFailed;
80
81 this.threadOnWhichTestFailed = threadOnWhichTestFailed;
82 }
83
84 @Override
85 public boolean equals( Object obj )
86 {
87 boolean retVal = true;
88
89 if ( obj == null || getClass() != obj.getClass() )
90 {
91 retVal = false;
92 }
93 else
94 {
95 FailedTest ft = (FailedTest) obj;
96
97 if ( ft.testThatFailed != testThatFailed )
98 {
99 retVal = false;
100 }
101 else if ( !ft.threadOnWhichTestFailed.equals( threadOnWhichTestFailed ) )
102 {
103 retVal = false;
104 }
105 }
106
107 return retVal;
108 }
109
110 @Override
111 public int hashCode()
112 {
113 return threadOnWhichTestFailed.hashCode();
114 }
115 }
116
117 public TestListenerInvocationHandler( RunListener reporter )
118 {
119 if ( reporter == null )
120 {
121 throw new NullPointerException( "reporter is null" );
122 }
123
124 this.reporter = reporter;
125 }
126
127 @Override
128 public Object invoke( Object proxy, Method method, Object[] args )
129 throws Throwable
130 {
131 String methodName = method.getName();
132
133 switch ( methodName )
134 {
135 case START_TEST:
136 handleStartTest( args );
137 break;
138 case ADD_ERROR:
139 handleAddError( args );
140 break;
141 case ADD_FAILURE:
142 handleAddFailure( args );
143 break;
144 case END_TEST:
145 handleEndTest( args );
146 break;
147 default:
148 break;
149 }
150
151 return null;
152 }
153
154
155 private void handleStartTest( Object[] args )
156 {
157 ReportEntry report = createStartEndReportEntry( args );
158
159 reporter.testStarting( report );
160 }
161
162
163 private void handleAddError( Object[] args )
164 throws ReflectiveOperationException
165 {
166 ReportEntry report = toReportEntryWithException( args );
167
168 reporter.testError( report );
169
170 failedTestsSet.add( new FailedTest( args[0], Thread.currentThread() ) );
171 }
172
173 private static LegacyPojoStackTraceWriter toStackTraceWriter( Object[] args )
174 throws ReflectiveOperationException
175 {
176 String testName;
177
178 try
179 {
180 Method m = args[0].getClass().getMethod( "getName", EMPTY_CLASS_ARRAY );
181 testName = (String) m.invoke( args[0], EMPTY_STRING_ARRAY );
182 }
183 catch ( NoSuchMethodException e )
184 {
185 testName = "UNKNOWN";
186 }
187
188 return new LegacyPojoStackTraceWriter( args[0].getClass().getName(), testName, (Throwable) args[1] );
189 }
190
191 private void handleAddFailure( Object[] args )
192 throws ReflectiveOperationException
193 {
194 ReportEntry report = toReportEntryWithException( args );
195
196 reporter.testFailed( report );
197
198 failedTestsSet.add( new FailedTest( args[0], Thread.currentThread() ) );
199 }
200
201 private void handleEndTest( Object[] args )
202 {
203 boolean testHadFailed = failedTestsSet.remove( new FailedTest( args[0], Thread.currentThread() ) );
204
205 if ( !testHadFailed )
206 {
207 ReportEntry report = createStartEndReportEntry( args );
208
209 reporter.testSucceeded( report );
210 }
211 }
212
213 private static ReportEntry toReportEntryWithException( Object[] args )
214 throws ReflectiveOperationException
215 {
216 String description = args[0].toString();
217 String className = extractClassName( description );
218 String methodName = extractMethodName( description );
219 StackTraceWriter stackTraceWriter = toStackTraceWriter( args );
220 return withException( className, null, methodName, null, stackTraceWriter );
221 }
222
223 private static SimpleReportEntry createStartEndReportEntry( Object[] args )
224 {
225 String description = args[0].toString();
226 return new SimpleReportEntry( extractClassName( description ), null, extractMethodName( description ), null );
227 }
228 }