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