1 | |
package org.apache.maven.plugins.surefire.report; |
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
13 | |
|
14 | |
|
15 | |
|
16 | |
|
17 | |
|
18 | |
|
19 | |
|
20 | |
|
21 | |
|
22 | |
import java.io.File; |
23 | |
import java.text.NumberFormat; |
24 | |
import java.util.Iterator; |
25 | |
import java.util.List; |
26 | |
import java.util.Locale; |
27 | |
import java.util.Map; |
28 | |
import java.util.ResourceBundle; |
29 | |
import java.util.StringTokenizer; |
30 | |
import org.apache.maven.doxia.markup.HtmlMarkup; |
31 | |
import org.apache.maven.doxia.sink.Sink; |
32 | |
import org.apache.maven.doxia.sink.SinkEventAttributeSet; |
33 | |
import org.apache.maven.doxia.sink.SinkEventAttributes; |
34 | |
import org.apache.maven.reporting.MavenReportException; |
35 | |
|
36 | |
|
37 | |
|
38 | |
|
39 | |
public class SurefireReportGenerator |
40 | |
{ |
41 | |
private final SurefireReportParser report; |
42 | |
|
43 | |
private List<ReportTestSuite> testSuites; |
44 | |
|
45 | |
private final boolean showSuccess; |
46 | |
|
47 | |
private final String xrefLocation; |
48 | |
|
49 | |
private static final int LEFT = Sink.JUSTIFY_LEFT; |
50 | |
|
51 | |
public SurefireReportGenerator( List<File> reportsDirectories, Locale locale, boolean showSuccess, |
52 | |
String xrefLocation ) |
53 | 4 | { |
54 | 4 | report = new SurefireReportParser( reportsDirectories, locale ); |
55 | |
|
56 | 4 | this.xrefLocation = xrefLocation; |
57 | |
|
58 | 4 | this.showSuccess = showSuccess; |
59 | 4 | } |
60 | |
|
61 | |
public void doGenerateReport( ResourceBundle bundle, Sink sink ) |
62 | |
throws MavenReportException |
63 | |
{ |
64 | 4 | testSuites = report.parseXMLReportFiles(); |
65 | |
|
66 | 4 | sink.head(); |
67 | |
|
68 | 4 | sink.title(); |
69 | 4 | sink.text( bundle.getString( "report.surefire.header" ) ); |
70 | 4 | sink.title_(); |
71 | |
|
72 | 4 | sink.head_(); |
73 | |
|
74 | 4 | sink.body(); |
75 | |
|
76 | 4 | SinkEventAttributeSet atts = new SinkEventAttributeSet(); |
77 | 4 | atts.addAttribute( SinkEventAttributes.TYPE, "text/javascript" ); |
78 | 4 | sink.unknown( "script", new Object[]{ HtmlMarkup.TAG_TYPE_START }, atts ); |
79 | 4 | sink.unknown( "cdata", new Object[]{ HtmlMarkup.CDATA_TYPE, javascriptToggleDisplayCode() }, null ); |
80 | 4 | sink.unknown( "script", new Object[]{ HtmlMarkup.TAG_TYPE_END }, null ); |
81 | |
|
82 | 4 | sink.section1(); |
83 | 4 | sink.sectionTitle1(); |
84 | 4 | sink.text( bundle.getString( "report.surefire.header" ) ); |
85 | 4 | sink.sectionTitle1_(); |
86 | 4 | sink.section1_(); |
87 | |
|
88 | 4 | constructSummarySection( bundle, sink ); |
89 | |
|
90 | 4 | Map<String, List<ReportTestSuite>> suitePackages = report.getSuitesGroupByPackage( testSuites ); |
91 | 4 | if ( !suitePackages.isEmpty() ) |
92 | |
{ |
93 | 4 | constructPackagesSection( bundle, sink, suitePackages ); |
94 | |
} |
95 | |
|
96 | 4 | if ( !testSuites.isEmpty() ) |
97 | |
{ |
98 | 4 | constructTestCasesSection( bundle, sink ); |
99 | |
} |
100 | |
|
101 | 4 | List<ReportTestCase> failureList = report.getFailureDetails( testSuites ); |
102 | 4 | if ( !failureList.isEmpty() ) |
103 | |
{ |
104 | 4 | constructFailureDetails( sink, bundle, failureList ); |
105 | |
} |
106 | |
|
107 | 4 | sink.body_(); |
108 | |
|
109 | 4 | sink.flush(); |
110 | |
|
111 | 4 | sink.close(); |
112 | 4 | } |
113 | |
|
114 | |
private void constructSummarySection( ResourceBundle bundle, Sink sink ) |
115 | |
{ |
116 | 4 | Map<String, String> summary = report.getSummary( testSuites ); |
117 | |
|
118 | 4 | sink.section1(); |
119 | 4 | sink.sectionTitle1(); |
120 | 4 | sink.text( bundle.getString( "report.surefire.label.summary" ) ); |
121 | 4 | sink.sectionTitle1_(); |
122 | |
|
123 | 4 | sinkAnchor( sink, "Summary" ); |
124 | |
|
125 | 4 | constructHotLinks( sink, bundle ); |
126 | |
|
127 | 4 | sinkLineBreak( sink ); |
128 | |
|
129 | 4 | sink.table(); |
130 | |
|
131 | 4 | sink.tableRows( new int[]{ LEFT, LEFT, LEFT, LEFT, LEFT, LEFT }, true ); |
132 | |
|
133 | 4 | sink.tableRow(); |
134 | |
|
135 | 4 | sinkHeader( sink, bundle.getString( "report.surefire.label.tests" ) ); |
136 | |
|
137 | 4 | sinkHeader( sink, bundle.getString( "report.surefire.label.errors" ) ); |
138 | |
|
139 | 4 | sinkHeader( sink, bundle.getString( "report.surefire.label.failures" ) ); |
140 | |
|
141 | 4 | sinkHeader( sink, bundle.getString( "report.surefire.label.skipped" ) ); |
142 | |
|
143 | 4 | sinkHeader( sink, bundle.getString( "report.surefire.label.successrate" ) ); |
144 | |
|
145 | 4 | sinkHeader( sink, bundle.getString( "report.surefire.label.time" ) ); |
146 | |
|
147 | 4 | sink.tableRow_(); |
148 | |
|
149 | 4 | sink.tableRow(); |
150 | |
|
151 | 4 | sinkCell( sink, summary.get( "totalTests" ) ); |
152 | |
|
153 | 4 | sinkCell( sink, summary.get( "totalErrors" ) ); |
154 | |
|
155 | 4 | sinkCell( sink, summary.get( "totalFailures" ) ); |
156 | |
|
157 | 4 | sinkCell( sink, summary.get( "totalSkipped" ) ); |
158 | |
|
159 | 4 | sinkCell( sink, summary.get( "totalPercentage" ) + "%" ); |
160 | |
|
161 | 4 | sinkCell( sink, summary.get( "totalElapsedTime" ) ); |
162 | |
|
163 | 4 | sink.tableRow_(); |
164 | |
|
165 | 4 | sink.tableRows_(); |
166 | |
|
167 | 4 | sink.table_(); |
168 | |
|
169 | 4 | sink.lineBreak(); |
170 | |
|
171 | 4 | sink.paragraph(); |
172 | 4 | sink.text( bundle.getString( "report.surefire.text.note1" ) ); |
173 | 4 | sink.paragraph_(); |
174 | |
|
175 | 4 | sinkLineBreak( sink ); |
176 | |
|
177 | 4 | sink.section1_(); |
178 | 4 | } |
179 | |
|
180 | |
private void constructPackagesSection( ResourceBundle bundle, Sink sink, |
181 | |
Map<String, List<ReportTestSuite>> suitePackages ) |
182 | |
{ |
183 | 4 | NumberFormat numberFormat = report.getNumberFormat(); |
184 | |
|
185 | 4 | sink.section1(); |
186 | 4 | sink.sectionTitle1(); |
187 | 4 | sink.text( bundle.getString( "report.surefire.label.packagelist" ) ); |
188 | 4 | sink.sectionTitle1_(); |
189 | |
|
190 | 4 | sinkAnchor( sink, "Package_List" ); |
191 | |
|
192 | 4 | constructHotLinks( sink, bundle ); |
193 | |
|
194 | 4 | sinkLineBreak( sink ); |
195 | |
|
196 | 4 | sink.table(); |
197 | |
|
198 | 4 | sink.tableRows( new int[]{ LEFT, LEFT, LEFT, LEFT, LEFT, LEFT, LEFT }, true ); |
199 | |
|
200 | 4 | sink.tableRow(); |
201 | |
|
202 | 4 | sinkHeader( sink, bundle.getString( "report.surefire.label.package" ) ); |
203 | |
|
204 | 4 | sinkHeader( sink, bundle.getString( "report.surefire.label.tests" ) ); |
205 | |
|
206 | 4 | sinkHeader( sink, bundle.getString( "report.surefire.label.errors" ) ); |
207 | |
|
208 | 4 | sinkHeader( sink, bundle.getString( "report.surefire.label.failures" ) ); |
209 | |
|
210 | 4 | sinkHeader( sink, bundle.getString( "report.surefire.label.skipped" ) ); |
211 | |
|
212 | 4 | sinkHeader( sink, bundle.getString( "report.surefire.label.successrate" ) ); |
213 | |
|
214 | 4 | sinkHeader( sink, bundle.getString( "report.surefire.label.time" ) ); |
215 | |
|
216 | 4 | sink.tableRow_(); |
217 | |
|
218 | 4 | for ( Map.Entry<String, List<ReportTestSuite>> entry : suitePackages.entrySet() ) |
219 | |
{ |
220 | 4 | sink.tableRow(); |
221 | |
|
222 | 4 | String packageName = entry.getKey(); |
223 | |
|
224 | 4 | List<ReportTestSuite> testSuiteList = entry.getValue(); |
225 | |
|
226 | 4 | Map<String, String> packageSummary = report.getSummary( testSuiteList ); |
227 | |
|
228 | 4 | sinkCellLink( sink, packageName, "#" + packageName ); |
229 | |
|
230 | 4 | sinkCell( sink, packageSummary.get( "totalTests" ) ); |
231 | |
|
232 | 4 | sinkCell( sink, packageSummary.get( "totalErrors" ) ); |
233 | |
|
234 | 4 | sinkCell( sink, packageSummary.get( "totalFailures" ) ); |
235 | |
|
236 | 4 | sinkCell( sink, packageSummary.get( "totalSkipped" ) ); |
237 | |
|
238 | 4 | sinkCell( sink, packageSummary.get( "totalPercentage" ) + "%" ); |
239 | |
|
240 | 4 | sinkCell( sink, packageSummary.get( "totalElapsedTime" ) ); |
241 | |
|
242 | 4 | sink.tableRow_(); |
243 | 4 | } |
244 | |
|
245 | 4 | sink.tableRows_(); |
246 | |
|
247 | 4 | sink.table_(); |
248 | |
|
249 | 4 | sink.lineBreak(); |
250 | |
|
251 | 4 | sink.paragraph(); |
252 | 4 | sink.text( bundle.getString( "report.surefire.text.note2" ) ); |
253 | 4 | sink.paragraph_(); |
254 | |
|
255 | 4 | for ( Map.Entry<String, List<ReportTestSuite>> entry : suitePackages.entrySet() ) |
256 | |
{ |
257 | 4 | String packageName = entry.getKey(); |
258 | |
|
259 | 4 | List<ReportTestSuite> testSuiteList = entry.getValue(); |
260 | |
|
261 | 4 | sink.section2(); |
262 | 4 | sink.sectionTitle2(); |
263 | 4 | sink.text( packageName ); |
264 | 4 | sink.sectionTitle2_(); |
265 | |
|
266 | 4 | sinkAnchor( sink, packageName ); |
267 | |
|
268 | 4 | boolean showTable = false; |
269 | |
|
270 | 4 | for ( ReportTestSuite suite : testSuiteList ) |
271 | |
{ |
272 | 4 | if ( showSuccess || suite.getNumberOfErrors() != 0 || suite.getNumberOfFailures() != 0 ) |
273 | |
{ |
274 | 4 | showTable = true; |
275 | |
|
276 | 4 | break; |
277 | |
} |
278 | |
} |
279 | |
|
280 | 4 | if ( showTable ) |
281 | |
{ |
282 | 4 | sink.table(); |
283 | |
|
284 | 4 | sink.tableRows( new int[]{ LEFT, LEFT, LEFT, LEFT, LEFT, LEFT, LEFT, LEFT }, true ); |
285 | |
|
286 | 4 | sink.tableRow(); |
287 | |
|
288 | 4 | sinkHeader( sink, "" ); |
289 | |
|
290 | 4 | sinkHeader( sink, bundle.getString( "report.surefire.label.class" ) ); |
291 | |
|
292 | 4 | sinkHeader( sink, bundle.getString( "report.surefire.label.tests" ) ); |
293 | |
|
294 | 4 | sinkHeader( sink, bundle.getString( "report.surefire.label.errors" ) ); |
295 | |
|
296 | 4 | sinkHeader( sink, bundle.getString( "report.surefire.label.failures" ) ); |
297 | |
|
298 | 4 | sinkHeader( sink, bundle.getString( "report.surefire.label.skipped" ) ); |
299 | |
|
300 | 4 | sinkHeader( sink, bundle.getString( "report.surefire.label.successrate" ) ); |
301 | |
|
302 | 4 | sinkHeader( sink, bundle.getString( "report.surefire.label.time" ) ); |
303 | |
|
304 | 4 | sink.tableRow_(); |
305 | |
|
306 | 4 | for ( ReportTestSuite suite : testSuiteList ) |
307 | |
{ |
308 | 4 | if ( showSuccess || suite.getNumberOfErrors() != 0 || suite.getNumberOfFailures() != 0 ) |
309 | |
{ |
310 | |
|
311 | 4 | sink.tableRow(); |
312 | |
|
313 | 4 | sink.tableCell(); |
314 | |
|
315 | 4 | sink.link( "#" + suite.getPackageName() + suite.getName() ); |
316 | |
|
317 | 4 | if ( suite.getNumberOfErrors() > 0 ) |
318 | |
{ |
319 | 4 | sinkIcon( "error", sink ); |
320 | |
} |
321 | 0 | else if ( suite.getNumberOfFailures() > 0 ) |
322 | |
{ |
323 | 0 | sinkIcon( "junit.framework", sink ); |
324 | |
} |
325 | 0 | else if ( suite.getNumberOfSkipped() > 0 ) |
326 | |
{ |
327 | 0 | sinkIcon( "skipped", sink ); |
328 | |
} |
329 | |
else |
330 | |
{ |
331 | 0 | sinkIcon( "success", sink ); |
332 | |
} |
333 | |
|
334 | 4 | sink.link_(); |
335 | |
|
336 | 4 | sink.tableCell_(); |
337 | |
|
338 | 4 | sinkCellLink( sink, suite.getName(), "#" + suite.getPackageName() + suite.getName() ); |
339 | |
|
340 | 4 | sinkCell( sink, Integer.toString( suite.getNumberOfTests() ) ); |
341 | |
|
342 | 4 | sinkCell( sink, Integer.toString( suite.getNumberOfErrors() ) ); |
343 | |
|
344 | 4 | sinkCell( sink, Integer.toString( suite.getNumberOfFailures() ) ); |
345 | |
|
346 | 4 | sinkCell( sink, Integer.toString( suite.getNumberOfSkipped() ) ); |
347 | |
|
348 | 4 | String percentage = |
349 | |
report.computePercentage( suite.getNumberOfTests(), suite.getNumberOfErrors(), |
350 | |
suite.getNumberOfFailures(), suite.getNumberOfSkipped() ); |
351 | 4 | sinkCell( sink, percentage + "%" ); |
352 | |
|
353 | 4 | sinkCell( sink, numberFormat.format( suite.getTimeElapsed() ) ); |
354 | |
|
355 | 4 | sink.tableRow_(); |
356 | 4 | } |
357 | |
} |
358 | |
|
359 | 4 | sink.tableRows_(); |
360 | |
|
361 | 4 | sink.table_(); |
362 | |
} |
363 | |
|
364 | 4 | sink.section2_(); |
365 | 4 | } |
366 | |
|
367 | 4 | sinkLineBreak( sink ); |
368 | |
|
369 | 4 | sink.section1_(); |
370 | 4 | } |
371 | |
|
372 | |
private void constructTestCasesSection( ResourceBundle bundle, Sink sink ) |
373 | |
{ |
374 | 4 | NumberFormat numberFormat = report.getNumberFormat(); |
375 | |
|
376 | 4 | sink.section1(); |
377 | 4 | sink.sectionTitle1(); |
378 | 4 | sink.text( bundle.getString( "report.surefire.label.testcases" ) ); |
379 | 4 | sink.sectionTitle1_(); |
380 | |
|
381 | 4 | sinkAnchor( sink, "Test_Cases" ); |
382 | |
|
383 | 4 | constructHotLinks( sink, bundle ); |
384 | |
|
385 | 4 | for ( ReportTestSuite suite : testSuites ) |
386 | |
{ |
387 | 4 | List<ReportTestCase> testCases = suite.getTestCases(); |
388 | |
|
389 | 4 | if ( testCases != null && !testCases.isEmpty() ) |
390 | |
{ |
391 | 4 | sink.section2(); |
392 | 4 | sink.sectionTitle2(); |
393 | 4 | sink.text( suite.getName() ); |
394 | 4 | sink.sectionTitle2_(); |
395 | |
|
396 | 4 | sinkAnchor( sink, suite.getPackageName() + suite.getName() ); |
397 | |
|
398 | 4 | boolean showTable = false; |
399 | |
|
400 | 4 | for ( ReportTestCase testCase : testCases ) |
401 | |
{ |
402 | 7 | if ( testCase.getFailure() != null || showSuccess ) |
403 | |
{ |
404 | 4 | showTable = true; |
405 | |
|
406 | 4 | break; |
407 | |
} |
408 | |
} |
409 | |
|
410 | 4 | if ( showTable ) |
411 | |
{ |
412 | 4 | sink.table(); |
413 | |
|
414 | 4 | sink.tableRows( new int[]{ LEFT, LEFT, LEFT }, true ); |
415 | |
|
416 | 4 | for ( ReportTestCase testCase : testCases ) |
417 | |
{ |
418 | 32 | if ( testCase.getFailure() != null || showSuccess ) |
419 | |
{ |
420 | 26 | sink.tableRow(); |
421 | |
|
422 | 26 | sink.tableCell(); |
423 | |
|
424 | 26 | Map<String, Object> failure = testCase.getFailure(); |
425 | |
|
426 | 26 | if ( failure != null ) |
427 | |
{ |
428 | 8 | sink.link( "#" + testCase.getFullName() ); |
429 | |
|
430 | 8 | sinkIcon( (String) failure.get( "type" ), sink ); |
431 | |
|
432 | 8 | sink.link_(); |
433 | |
} |
434 | |
else |
435 | |
{ |
436 | 18 | sinkIcon( "success", sink ); |
437 | |
} |
438 | |
|
439 | 26 | sink.tableCell_(); |
440 | |
|
441 | 26 | if ( failure != null ) |
442 | |
{ |
443 | 8 | sink.tableCell(); |
444 | |
|
445 | 8 | sinkLink( sink, testCase.getName(), "#" + testCase.getFullName() ); |
446 | |
|
447 | 8 | SinkEventAttributeSet atts = new SinkEventAttributeSet(); |
448 | 8 | atts.addAttribute( SinkEventAttributes.CLASS, "detailToggle" ); |
449 | 8 | atts.addAttribute( SinkEventAttributes.STYLE, "display:inline" ); |
450 | 8 | sink.unknown( "div", new Object[]{ HtmlMarkup.TAG_TYPE_START }, atts ); |
451 | |
|
452 | 8 | sink.link( "javascript:toggleDisplay('" + toHtmlId( testCase.getFullName() ) + "');" ); |
453 | |
|
454 | 8 | atts = new SinkEventAttributeSet(); |
455 | 8 | atts.addAttribute( SinkEventAttributes.STYLE, "display:inline;" ); |
456 | 8 | atts.addAttribute( SinkEventAttributes.ID, toHtmlId( testCase.getFullName() ) + "off" ); |
457 | 8 | sink.unknown( "span", new Object[]{ HtmlMarkup.TAG_TYPE_START }, atts ); |
458 | 8 | sink.text( " + " ); |
459 | 8 | sink.unknown( "span", new Object[]{ HtmlMarkup.TAG_TYPE_END }, null ); |
460 | |
|
461 | 8 | atts = new SinkEventAttributeSet(); |
462 | 8 | atts.addAttribute( SinkEventAttributes.STYLE, "display:none;" ); |
463 | 8 | atts.addAttribute( SinkEventAttributes.ID, toHtmlId( testCase.getFullName() ) + "on" ); |
464 | 8 | sink.unknown( "span", new Object[]{ HtmlMarkup.TAG_TYPE_START }, atts ); |
465 | 8 | sink.text( " - " ); |
466 | 8 | sink.unknown( "span", new Object[]{ HtmlMarkup.TAG_TYPE_END }, null ); |
467 | |
|
468 | 8 | sink.text( "[ Detail ]" ); |
469 | 8 | sink.link_(); |
470 | |
|
471 | 8 | sink.unknown( "div", new Object[]{ HtmlMarkup.TAG_TYPE_END }, null ); |
472 | |
|
473 | 8 | sink.tableCell_(); |
474 | 8 | } |
475 | |
else |
476 | |
{ |
477 | 18 | sinkCell( sink, testCase.getName() ); |
478 | |
} |
479 | |
|
480 | 26 | sinkCell( sink, numberFormat.format( testCase.getTime() ) ); |
481 | |
|
482 | 26 | sink.tableRow_(); |
483 | |
|
484 | 26 | if ( failure != null ) |
485 | |
{ |
486 | 8 | sink.tableRow(); |
487 | |
|
488 | 8 | sinkCell( sink, "" ); |
489 | 8 | sinkCell( sink, (String) failure.get( "message" ) ); |
490 | 8 | sinkCell( sink, "" ); |
491 | 8 | sink.tableRow_(); |
492 | |
|
493 | 8 | List<String> detail = (List<String>) failure.get( "detail" ); |
494 | 8 | if ( detail != null ) |
495 | |
{ |
496 | |
|
497 | 8 | sink.tableRow(); |
498 | 8 | sinkCell( sink, "" ); |
499 | |
|
500 | 8 | sink.tableCell(); |
501 | 8 | SinkEventAttributeSet atts = new SinkEventAttributeSet(); |
502 | 8 | atts.addAttribute( SinkEventAttributes.ID, |
503 | |
toHtmlId( testCase.getFullName() ) + "error" ); |
504 | 8 | atts.addAttribute( SinkEventAttributes.STYLE, "display:none;" ); |
505 | 8 | sink.unknown( "div", new Object[]{ HtmlMarkup.TAG_TYPE_START }, atts ); |
506 | |
|
507 | 8 | sink.verbatim( null ); |
508 | 8 | for ( String line : detail ) |
509 | |
{ |
510 | 36 | sink.text( line ); |
511 | 36 | sink.lineBreak(); |
512 | |
} |
513 | 8 | sink.verbatim_(); |
514 | |
|
515 | 8 | sink.unknown( "div", new Object[]{ HtmlMarkup.TAG_TYPE_END }, null ); |
516 | 8 | sink.tableCell_(); |
517 | |
|
518 | 8 | sinkCell( sink, "" ); |
519 | |
|
520 | 8 | sink.tableRow_(); |
521 | |
} |
522 | |
} |
523 | 32 | } |
524 | |
} |
525 | |
|
526 | 4 | sink.tableRows_(); |
527 | |
|
528 | 4 | sink.table_(); |
529 | |
} |
530 | |
|
531 | 4 | sink.section2_(); |
532 | |
} |
533 | 4 | } |
534 | |
|
535 | 4 | sinkLineBreak( sink ); |
536 | |
|
537 | 4 | sink.section1_(); |
538 | 4 | } |
539 | |
|
540 | |
|
541 | |
private String toHtmlId( String id ) |
542 | |
{ |
543 | 32 | return id.replace( ".", "_" ); |
544 | |
} |
545 | |
|
546 | |
private void constructFailureDetails( Sink sink, ResourceBundle bundle, List<ReportTestCase> failureList ) |
547 | |
{ |
548 | 4 | Iterator<ReportTestCase> failIter = failureList.iterator(); |
549 | |
|
550 | 4 | if ( failIter != null ) |
551 | |
{ |
552 | 4 | sink.section1(); |
553 | 4 | sink.sectionTitle1(); |
554 | 4 | sink.text( bundle.getString( "report.surefire.label.failuredetails" ) ); |
555 | 4 | sink.sectionTitle1_(); |
556 | |
|
557 | 4 | sinkAnchor( sink, "Failure_Details" ); |
558 | |
|
559 | 4 | constructHotLinks( sink, bundle ); |
560 | |
|
561 | 4 | sinkLineBreak( sink ); |
562 | |
|
563 | 4 | sink.table(); |
564 | |
|
565 | 4 | sink.tableRows( new int[]{ LEFT, LEFT }, true ); |
566 | |
|
567 | 12 | while ( failIter.hasNext() ) |
568 | |
{ |
569 | 8 | ReportTestCase tCase = failIter.next(); |
570 | |
|
571 | 8 | Map<String, Object> failure = tCase.getFailure(); |
572 | |
|
573 | 8 | sink.tableRow(); |
574 | |
|
575 | 8 | sink.tableCell(); |
576 | |
|
577 | 8 | String type = (String) failure.get( "type" ); |
578 | 8 | sinkIcon( type, sink ); |
579 | |
|
580 | 8 | sink.tableCell_(); |
581 | |
|
582 | 8 | sinkCellAnchor( sink, tCase.getName(), tCase.getFullName() ); |
583 | |
|
584 | 8 | sink.tableRow_(); |
585 | |
|
586 | 8 | String message = (String) failure.get( "message" ); |
587 | |
|
588 | 8 | sink.tableRow(); |
589 | |
|
590 | 8 | sinkCell( sink, "" ); |
591 | |
|
592 | 8 | StringBuilder sb = new StringBuilder(); |
593 | 8 | sb.append( type ); |
594 | |
|
595 | 8 | if ( message != null ) |
596 | |
{ |
597 | 8 | sb.append( ": " ); |
598 | 8 | sb.append( message ); |
599 | |
} |
600 | |
|
601 | 8 | sinkCell( sink, sb.toString() ); |
602 | |
|
603 | 8 | sink.tableRow_(); |
604 | |
|
605 | 8 | List<String> detail = (List<String>) failure.get( "detail" ); |
606 | 8 | if ( detail != null ) |
607 | |
{ |
608 | 8 | boolean firstLine = true; |
609 | |
|
610 | 8 | String techMessage = ""; |
611 | 8 | for ( String line : detail ) |
612 | |
{ |
613 | 36 | techMessage = line; |
614 | 36 | if ( firstLine ) |
615 | |
{ |
616 | 8 | firstLine = false; |
617 | |
} |
618 | |
else |
619 | |
{ |
620 | 28 | sink.text( " " ); |
621 | |
} |
622 | |
} |
623 | |
|
624 | 8 | sink.tableRow(); |
625 | |
|
626 | 8 | sinkCell( sink, "" ); |
627 | |
|
628 | 8 | sink.tableCell(); |
629 | 8 | SinkEventAttributeSet atts = new SinkEventAttributeSet(); |
630 | 8 | atts.addAttribute( SinkEventAttributes.ID, tCase.getName() + "error" ); |
631 | 8 | sink.unknown( "div", new Object[]{ HtmlMarkup.TAG_TYPE_START }, atts ); |
632 | |
|
633 | 8 | if ( xrefLocation != null ) |
634 | |
{ |
635 | 4 | String path = tCase.getFullClassName().replace( '.', '/' ); |
636 | |
|
637 | 4 | sink.link( xrefLocation + "/" + path + ".html#" + |
638 | |
getErrorLineNumber( tCase.getFullName(), techMessage ) ); |
639 | |
} |
640 | 8 | sink.text( |
641 | |
tCase.getFullClassName() + ":" + getErrorLineNumber( tCase.getFullName(), techMessage ) ); |
642 | |
|
643 | 8 | if ( xrefLocation != null ) |
644 | |
{ |
645 | 4 | sink.link_(); |
646 | |
} |
647 | 8 | sink.unknown( "div", new Object[]{ HtmlMarkup.TAG_TYPE_END }, null ); |
648 | |
|
649 | 8 | sink.tableCell_(); |
650 | |
|
651 | 8 | sink.tableRow_(); |
652 | |
} |
653 | 8 | } |
654 | |
|
655 | 4 | sink.tableRows_(); |
656 | |
|
657 | 4 | sink.table_(); |
658 | |
} |
659 | |
|
660 | 4 | sinkLineBreak( sink ); |
661 | |
|
662 | 4 | sink.section1_(); |
663 | 4 | } |
664 | |
|
665 | |
private String getErrorLineNumber( String className, String source ) |
666 | |
{ |
667 | 12 | StringTokenizer tokenizer = new StringTokenizer( source ); |
668 | |
|
669 | 12 | String lineNo = ""; |
670 | |
|
671 | 24 | while ( tokenizer.hasMoreTokens() ) |
672 | |
{ |
673 | 24 | String token = tokenizer.nextToken(); |
674 | 24 | if ( token.startsWith( className ) ) |
675 | |
{ |
676 | 12 | int idx = token.indexOf( ":" ); |
677 | 12 | lineNo = token.substring( idx + 1, token.indexOf( ")" ) ); |
678 | 12 | break; |
679 | |
} |
680 | 12 | } |
681 | 12 | return lineNo; |
682 | |
} |
683 | |
|
684 | |
private void constructHotLinks( Sink sink, ResourceBundle bundle ) |
685 | |
{ |
686 | 16 | if ( !testSuites.isEmpty() ) |
687 | |
{ |
688 | 16 | sink.paragraph(); |
689 | |
|
690 | 16 | sink.text( "[" ); |
691 | 16 | sinkLink( sink, bundle.getString( "report.surefire.label.summary" ), "#Summary" ); |
692 | 16 | sink.text( "]" ); |
693 | |
|
694 | 16 | sink.text( " [" ); |
695 | 16 | sinkLink( sink, bundle.getString( "report.surefire.label.packagelist" ), "#Package_List" ); |
696 | 16 | sink.text( "]" ); |
697 | |
|
698 | 16 | sink.text( " [" ); |
699 | 16 | sinkLink( sink, bundle.getString( "report.surefire.label.testcases" ), "#Test_Cases" ); |
700 | 16 | sink.text( "]" ); |
701 | |
|
702 | 16 | sink.paragraph_(); |
703 | |
} |
704 | 16 | } |
705 | |
|
706 | |
private void sinkLineBreak( Sink sink ) |
707 | |
{ |
708 | 28 | sink.lineBreak(); |
709 | 28 | } |
710 | |
|
711 | |
private void sinkIcon( String type, Sink sink ) |
712 | |
{ |
713 | 38 | sink.figure(); |
714 | |
|
715 | 38 | if ( type.startsWith( "junit.framework" ) || "skipped".equals( type ) ) |
716 | |
{ |
717 | 8 | sink.figureGraphics( "images/icon_warning_sml.gif" ); |
718 | |
} |
719 | 30 | else if ( type.startsWith( "success" ) ) |
720 | |
{ |
721 | 18 | sink.figureGraphics( "images/icon_success_sml.gif" ); |
722 | |
} |
723 | |
else |
724 | |
{ |
725 | 12 | sink.figureGraphics( "images/icon_error_sml.gif" ); |
726 | |
} |
727 | |
|
728 | 38 | sink.figure_(); |
729 | 38 | } |
730 | |
|
731 | |
private void sinkHeader( Sink sink, String header ) |
732 | |
{ |
733 | 84 | sink.tableHeaderCell(); |
734 | 84 | sink.text( header ); |
735 | 84 | sink.tableHeaderCell_(); |
736 | 84 | } |
737 | |
|
738 | |
private void sinkCell( Sink sink, String text ) |
739 | |
{ |
740 | 180 | sink.tableCell(); |
741 | 180 | sink.text( text ); |
742 | 180 | sink.tableCell_(); |
743 | 180 | } |
744 | |
|
745 | |
private void sinkLink( Sink sink, String text, String link ) |
746 | |
{ |
747 | 64 | sink.link( link ); |
748 | 64 | sink.text( text ); |
749 | 64 | sink.link_(); |
750 | 64 | } |
751 | |
|
752 | |
private void sinkCellLink( Sink sink, String text, String link ) |
753 | |
{ |
754 | 8 | sink.tableCell(); |
755 | 8 | sinkLink( sink, text, link ); |
756 | 8 | sink.tableCell_(); |
757 | 8 | } |
758 | |
|
759 | |
private void sinkCellAnchor( Sink sink, String text, String anchor ) |
760 | |
{ |
761 | 8 | sink.tableCell(); |
762 | 8 | sinkAnchor( sink, anchor ); |
763 | 8 | sink.text( text ); |
764 | 8 | sink.tableCell_(); |
765 | 8 | } |
766 | |
|
767 | |
private void sinkAnchor( Sink sink, String anchor ) |
768 | |
{ |
769 | 32 | sink.anchor( anchor ); |
770 | 32 | sink.anchor_(); |
771 | 32 | } |
772 | |
|
773 | |
private static String javascriptToggleDisplayCode() |
774 | |
{ |
775 | 4 | final StringBuilder str = new StringBuilder( 64 ); |
776 | |
|
777 | |
|
778 | |
|
779 | 4 | str.append( "\n" ); |
780 | 4 | str.append( "function toggleDisplay(elementId) {\n" ); |
781 | 4 | str.append( " var elm = document.getElementById(elementId + 'error');\n" ); |
782 | 4 | str.append( " if (elm && typeof elm.style != \"undefined\") {\n" ); |
783 | 4 | str.append( " if (elm.style.display == \"none\") {\n" ); |
784 | 4 | str.append( " elm.style.display = \"\";\n" ); |
785 | 4 | str.append( " document.getElementById(elementId + 'off').style.display = \"none\";\n" ); |
786 | 4 | str.append( " document.getElementById(elementId + 'on').style.display = \"inline\";\n" ); |
787 | 4 | str.append( " }" ); |
788 | 4 | str.append( " else if (elm.style.display == \"\") {" ); |
789 | 4 | str.append( " elm.style.display = \"none\";\n" ); |
790 | 4 | str.append( " document.getElementById(elementId + 'off').style.display = \"inline\";\n" ); |
791 | 4 | str.append( " document.getElementById(elementId + 'on').style.display = \"none\";\n" ); |
792 | 4 | str.append( " } \n" ); |
793 | 4 | str.append( " } \n" ); |
794 | 4 | str.append( " }\n" ); |
795 | 4 | str.append( "//" ); |
796 | |
|
797 | 4 | return str.toString(); |
798 | |
} |
799 | |
} |