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