1 23 24 package net.sourceforge.cobertura.reporting.html; 25 26 import java.io.BufferedReader ; 27 import java.io.File ; 28 import java.io.FileNotFoundException ; 29 import java.io.FileOutputStream ; 30 import java.io.FileReader ; 31 import java.io.IOException ; 32 import java.io.PrintStream ; 33 import java.text.DateFormat ; 34 import java.text.DecimalFormat ; 35 import java.text.NumberFormat ; 36 import java.util.Collection ; 37 import java.util.Collections ; 38 import java.util.Date ; 39 import java.util.Iterator ; 40 import java.util.SortedSet ; 41 import java.util.TreeSet ; 42 import java.util.Vector ; 43 44 import net.sourceforge.cobertura.coveragedata.ClassData; 45 import net.sourceforge.cobertura.coveragedata.CoverageData; 46 import net.sourceforge.cobertura.coveragedata.PackageData; 47 import net.sourceforge.cobertura.coveragedata.ProjectData; 48 import net.sourceforge.cobertura.coveragedata.SourceFileData; 49 import net.sourceforge.cobertura.reporting.ComplexityCalculator; 50 import net.sourceforge.cobertura.reporting.html.files.CopyFiles; 51 import net.sourceforge.cobertura.util.FileFinder; 52 import net.sourceforge.cobertura.util.Header; 53 54 import org.apache.log4j.Logger; 55 56 public class HTMLReport 57 { 58 59 private static final Logger LOGGER = Logger.getLogger(HTMLReport.class); 60 61 private File destinationDir; 62 63 private FileFinder finder; 64 65 private ComplexityCalculator complexity; 66 67 private ProjectData projectData; 68 69 72 public HTMLReport(ProjectData projectData, File outputDir, 73 FileFinder finder, ComplexityCalculator complexity) 74 throws Exception 75 { 76 this.destinationDir = outputDir; 77 this.finder = finder; 78 this.complexity = complexity; 79 this.projectData = projectData; 80 81 CopyFiles.copy(outputDir); 82 generatePackageList(); 83 generateSourceFileLists(); 84 generateOverviews(); 85 generateSourceFiles(); 86 } 87 88 private String generatePackageName(PackageData packageData) 89 { 90 if (packageData.getName().equals("")) 91 return "(default)"; 92 return packageData.getName(); 93 } 94 95 private void generatePackageList() throws IOException 96 { 97 File file = new File (destinationDir, "frame-packages.html"); 98 PrintStream out = null; 99 100 try 101 { 102 out = new PrintStream (new FileOutputStream (file)); 103 104 out 105 .println("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\""); 106 out 107 .println(" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">"); 108 109 out 110 .println("<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">"); 111 out.println("<head>"); 112 out 113 .println("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />"); 114 out.println("<title>Coverage Report</title>"); 115 out 116 .println("<link title=\"Style\" type=\"text/css\" rel=\"stylesheet\" HREF=\"css/main.css\" />"); 117 out.println("</head>"); 118 out.println("<body>"); 119 out.println("<h5>Packages</h5>"); 120 out.println("<table width=\"100%\">"); 121 out.println("<tr>"); 122 out 123 .println("<td nowrap=\"nowrap\"><a HREF=\"frame-summary.html\" onclick='parent.sourceFileList.location.href=\"frame-sourcefiles.html\"' target=\"summary\">All</a></td>"); 124 out.println("</tr>"); 125 126 Iterator iter = projectData.getPackages().iterator(); 127 while (iter.hasNext()) 128 { 129 PackageData packageData = (PackageData)iter.next(); 130 String url1 = "frame-summary-" + packageData.getName() 131 + ".html"; 132 String url2 = "frame-sourcefiles-" + packageData.getName() 133 + ".html"; 134 out.println("<tr>"); 135 out.println("<td nowrap=\"nowrap\"><a HREF=\"" + url1 136 + "\" onclick='parent.sourceFileList.location.href=\"" 137 + url2 + "\"' target=\"summary\">" 138 + generatePackageName(packageData) + "</a></td>"); 139 out.println("</tr>"); 140 } 141 out.println("</table>"); 142 out.println("</body>"); 143 out.println("</html>"); 144 } 145 finally 146 { 147 if (out != null) 148 { 149 out.close(); 150 } 151 } 152 } 153 154 private void generateSourceFileLists() throws IOException 155 { 156 generateSourceFileList(null); 157 Iterator iter = projectData.getPackages().iterator(); 158 while (iter.hasNext()) 159 { 160 PackageData packageData = (PackageData)iter.next(); 161 generateSourceFileList(packageData); 162 } 163 } 164 165 private void generateSourceFileList(PackageData packageData) 166 throws IOException 167 { 168 String filename; 169 Collection sourceFiles; 170 if (packageData == null) 171 { 172 filename = "frame-sourcefiles.html"; 173 sourceFiles = projectData.getSourceFiles(); 174 } 175 else 176 { 177 filename = "frame-sourcefiles-" + packageData.getName() + ".html"; 178 sourceFiles = packageData.getSourceFiles(); 179 } 180 181 Vector sortedSourceFiles = new Vector (); 185 sortedSourceFiles.addAll(sourceFiles); 186 Collections.sort(sortedSourceFiles, 187 new SourceFileDataBaseNameComparator()); 188 189 File file = new File (destinationDir, filename); 190 PrintStream out = null; 191 try 192 { 193 out = new PrintStream (new FileOutputStream (file)); 194 195 out 196 .println("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\""); 197 out 198 .println(" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">"); 199 200 out.println("<html>"); 201 out.println("<head>"); 202 out 203 .println("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"/>"); 204 out.println("<title>Coverage Report Classes</title>"); 205 out 206 .println("<link title=\"Style\" type=\"text/css\" rel=\"stylesheet\" HREF=\"css/main.css\"/>"); 207 out.println("</head>"); 208 out.println("<body>"); 209 out.println("<h5>"); 210 out.println(packageData == null ? "All Packages" 211 : generatePackageName(packageData)); 212 out.println("</h5>"); 213 out.println("<div class=\"separator\"> </div>"); 214 out.println("<h5>Classes</h5>"); 215 if (!sortedSourceFiles.isEmpty()) 216 { 217 out.println("<table width=\"100%\">"); 218 out.println("<tbody>"); 219 220 for (Iterator iter = sortedSourceFiles.iterator(); iter 221 .hasNext();) 222 { 223 SourceFileData sourceFileData = (SourceFileData)iter.next(); 224 out.println("<tr>"); 225 String percentCovered; 226 if (sourceFileData.getNumberOfValidLines() > 0) 227 percentCovered = getPercentValue(sourceFileData 228 .getLineCoverageRate()); 229 else 230 percentCovered = "N/A"; 231 out 232 .println("<td nowrap=\"nowrap\"><a target=\"summary\" HREF=\"" 233 + sourceFileData.getNormalizedName() 234 + ".html\">" 235 + sourceFileData.getBaseName() 236 + "</a> <i>(" 237 + percentCovered 238 + ")</i></td>"); 239 out.println("</tr>"); 240 } 241 out.println("</tbody>"); 242 out.println("</table>"); 243 } 244 245 out.println("</body>"); 246 out.println("</html>"); 247 } 248 finally 249 { 250 if (out != null) 251 { 252 out.close(); 253 } 254 } 255 } 256 257 private void generateOverviews() throws IOException 258 { 259 generateOverview(null); 260 Iterator iter = projectData.getPackages().iterator(); 261 while (iter.hasNext()) 262 { 263 PackageData packageData = (PackageData)iter.next(); 264 generateOverview(packageData); 265 } 266 } 267 268 private void generateOverview(PackageData packageData) throws IOException 269 { 270 Iterator iter; 271 272 String filename; 273 if (packageData == null) 274 { 275 filename = "frame-summary.html"; 276 } 277 else 278 { 279 filename = "frame-summary-" + packageData.getName() + ".html"; 280 } 281 File file = new File (destinationDir, filename); 282 PrintStream out = null; 283 284 try 285 { 286 out = new PrintStream (new FileOutputStream (file)); 287 288 out 289 .println("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\""); 290 out 291 .println(" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">"); 292 293 out.println("<html>"); 294 out.println("<head>"); 295 out 296 .println("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"/>"); 297 out.println("<title>Coverage Report</title>"); 298 out 299 .println("<link title=\"Style\" type=\"text/css\" rel=\"stylesheet\" HREF=\"css/main.css\"/>"); 300 out 301 .println("<link title=\"Style\" type=\"text/css\" rel=\"stylesheet\" HREF=\"css/sortabletable.css\"/>"); 302 out 303 .println("<script type=\"text/javascript\" SRC=\"js/popup.js\"></script>"); 304 out 305 .println("<script type=\"text/javascript\" SRC=\"js/sortabletable.js\"></script>"); 306 out 307 .println("<script type=\"text/javascript\" SRC=\"js/customsorttypes.js\"></script>"); 308 out.println("</head>"); 309 out.println("<body>"); 310 311 out.print("<h5>Coverage Report - "); 312 out.print(packageData == null ? "All Packages" 313 : generatePackageName(packageData)); 314 out.println("</h5>"); 315 out.println("<div class=\"separator\"> </div>"); 316 out.println("<table class=\"report\" id=\"packageResults\">"); 317 out.println(generateTableHeader("Package", true)); 318 out.println("<tbody>"); 319 320 SortedSet packages; 321 if (packageData == null) 322 { 323 out.println(generateTableRowForTotal()); 325 326 packages = projectData.getPackages(); 328 } 329 else 330 { 331 packages = projectData.getSubPackages(packageData.getName()); 333 } 334 335 iter = packages.iterator(); 337 while (iter.hasNext()) 338 { 339 PackageData subPackageData = (PackageData)iter.next(); 340 out.println(generateTableRowForPackage(subPackageData)); 341 } 342 343 out.println("</tbody>"); 344 out.println("</table>"); 345 out.println("<script type=\"text/javascript\">"); 346 out 347 .println("var packageTable = new SortableTable(document.getElementById(\"packageResults\"),"); 348 out 349 .println(" [\"String\", \"Number\", \"Percentage\", \"Percentage\", \"FormattedNumber\"]);"); 350 out.println("packageTable.sort(0);"); 351 out.println("</script>"); 352 353 Collection sourceFiles; 355 if (packageData == null) 356 { 357 PackageData defaultPackage = (PackageData)projectData 358 .getChild(""); 359 if (defaultPackage != null) 360 { 361 sourceFiles = defaultPackage.getSourceFiles(); 362 } 363 else 364 { 365 sourceFiles = new TreeSet (); 366 } 367 } 368 else 369 { 370 sourceFiles = packageData.getSourceFiles(); 371 } 372 373 if (sourceFiles.size() > 0) 375 { 376 out.println("<div class=\"separator\"> </div>"); 377 out.println("<table class=\"report\" id=\"classResults\">"); 378 out.println(generateTableHeader("Classes in this Package", 379 false)); 380 out.println("<tbody>"); 381 382 iter = sourceFiles.iterator(); 383 while (iter.hasNext()) 384 { 385 SourceFileData sourceFileData = (SourceFileData)iter.next(); 386 out.println(generateTableRowsForSourceFile(sourceFileData)); 387 } 388 389 out.println("</tbody>"); 390 out.println("</table>"); 391 out.println("<script type=\"text/javascript\">"); 392 out 393 .println("var classTable = new SortableTable(document.getElementById(\"classResults\"),"); 394 out 395 .println(" [\"String\", \"Percentage\", \"Percentage\", \"FormattedNumber\"]);"); 396 out.println("classTable.sort(0);"); 397 out.println("</script>"); 398 } 399 400 out.println(generateFooter()); 401 402 out.println("</body>"); 403 out.println("</html>"); 404 } 405 finally 406 { 407 if (out != null) 408 { 409 out.close(); 410 } 411 } 412 } 413 414 private void generateSourceFiles() 415 { 416 Iterator iter = projectData.getSourceFiles().iterator(); 417 while (iter.hasNext()) 418 { 419 SourceFileData sourceFileData = (SourceFileData)iter.next(); 420 try 421 { 422 generateSourceFile(sourceFileData); 423 } 424 catch (IOException e) 425 { 426 LOGGER.info("Could not generate HTML file for source file " 427 + sourceFileData.getName() + ": " 428 + e.getLocalizedMessage()); 429 } 430 } 431 } 432 433 private void generateSourceFile(SourceFileData sourceFileData) 434 throws IOException 435 { 436 if (!sourceFileData.containsInstrumentationInfo()) 437 { 438 LOGGER.info("Data file does not contain instrumentation " 439 + "information for the file " + sourceFileData.getName() 440 + ". Ensure this class was instrumented, and this " 441 + "data file contains the instrumentation information."); 442 } 443 444 String filename = sourceFileData.getNormalizedName() + ".html"; 445 File file = new File (destinationDir, filename); 446 PrintStream out = null; 447 448 try 449 { 450 out = new PrintStream (new FileOutputStream (file)); 451 452 out 453 .println("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\""); 454 out 455 .println(" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">"); 456 457 out.println("<html>"); 458 out.println("<head>"); 459 out 460 .println("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"/>"); 461 out.println("<title>Coverage Report</title>"); 462 out 463 .println("<link title=\"Style\" type=\"text/css\" rel=\"stylesheet\" HREF=\"css/main.css\"/>"); 464 out 465 .println("<script type=\"text/javascript\" SRC=\"js/popup.js\"></script>"); 466 out.println("</head>"); 467 out.println("<body>"); 468 out.print("<h5>Coverage Report - "); 469 String classPackageName = sourceFileData.getPackageName(); 470 if ((classPackageName != null) && classPackageName.length() > 0) 471 { 472 out.print(classPackageName + "."); 473 } 474 out.print(sourceFileData.getBaseName()); 475 out.println("</h5>"); 476 477 out.println("<div class=\"separator\"> </div>"); 479 out.println("<table class=\"report\">"); 480 out.println(generateTableHeader("Classes in this File", false)); 481 out.println(generateTableRowsForSourceFile(sourceFileData)); 482 out.println("</table>"); 483 484 487 out.println("<div class=\"separator\"> </div>"); 489 out.println(generateHtmlizedJavaSource(sourceFileData)); 490 491 out.println(generateFooter()); 492 493 out.println("</body>"); 494 out.println("</html>"); 495 } 496 finally 497 { 498 if (out != null) 499 { 500 out.close(); 501 } 502 } 503 } 504 505 private String generateHtmlizedJavaSource(SourceFileData sourceFileData) 506 { 507 File sourceFile = null; 508 try 509 { 510 sourceFile = finder.getFileForSource(sourceFileData.getName()); 511 } 512 catch (IOException e) 513 { 514 return "<p>Unable to locate " + sourceFileData.getName() 515 + ". Have you specified the source directory?</p>"; 516 } 517 518 BufferedReader br = null; 519 try 520 { 521 br = new BufferedReader (new FileReader (sourceFile)); 522 } 523 catch (FileNotFoundException e) 524 { 525 return "<p>Unable to open " + sourceFile.getAbsolutePath() + "</p>"; 526 } 527 528 StringBuffer ret = new StringBuffer (); 529 ret 530 .append("<table cellspacing=\"0\" cellpadding=\"0\" class=\"src\">\n"); 531 try 532 { 533 String lineStr; 534 JavaToHtml javaToHtml = new JavaToHtml(); 535 int lineNumber = 1; 536 while ((lineStr = br.readLine()) != null) 537 { 538 ret.append("<tr>"); 539 if (sourceFileData.isValidSourceLineNumber(lineNumber)) 540 { 541 long numberOfHits = sourceFileData.getHitCount(lineNumber); 542 ret.append(" <td class=\"numLineCover\"> " 543 + lineNumber + "</td>"); 544 if (numberOfHits > 0) 545 { 546 ret.append(" <td class=\"nbHitsCovered\"> " 547 + numberOfHits + "</td>"); 548 ret 549 .append(" <td class=\"src\"><pre class=\"src\"> " 550 + javaToHtml.process(lineStr) 551 + "</pre></td>"); 552 } 553 else 554 { 555 ret.append(" <td class=\"nbHitsUncovered\"> " 556 + numberOfHits + "</td>"); 557 ret 558 .append(" <td class=\"src\"><pre class=\"src\"><span class=\"srcUncovered\"> " 559 + javaToHtml.process(lineStr) 560 + "</span></pre></td>"); 561 } 562 } 563 else 564 { 565 ret.append(" <td class=\"numLine\"> " + lineNumber 566 + "</td>"); 567 ret.append(" <td class=\"nbHits\"> </td>\n"); 568 ret.append(" <td class=\"src\"><pre class=\"src\"> " 569 + javaToHtml.process(lineStr) + "</pre></td>"); 570 } 571 ret.append("</tr>\n"); 572 lineNumber++; 573 } 574 } 575 catch (IOException e) 576 { 577 ret.append("<tr><td>Error reading from file " 578 + sourceFile.getAbsolutePath() + ": " 579 + e.getLocalizedMessage() + "</td></tr>\n"); 580 } 581 finally 582 { 583 try 584 { 585 br.close(); 586 } 587 catch (IOException e) 588 { 589 } 590 } 591 592 ret.append("</table>\n"); 593 594 return ret.toString(); 595 } 596 597 private static String generateFooter() 598 { 599 return "<div class=\"footer\">Report generated by " 600 + "<a HREF=\"http://cobertura.sourceforge.net/\" target=\"_top\">Cobertura</a> " 601 + Header.version() + " on " 602 + DateFormat.getInstance().format(new Date ()) + ".</div>"; 603 } 604 605 private static String generateTableHeader(String title, 606 boolean showColumnForNumberOfClasses) 607 { 608 StringBuffer ret = new StringBuffer (); 609 ret.append("<thead>"); 610 ret.append("<tr>"); 611 ret.append(" <td class=\"heading\">" + title + "</td>"); 612 if (showColumnForNumberOfClasses) 613 { 614 ret.append(" <td class=\"heading\"># Classes</td>"); 615 } 616 ret.append(" <td class=\"heading\">" 617 + generateHelpURL("Line Coverage", 618 "The percent of lines executed by this test run.") 619 + "</td>"); 620 ret.append(" <td class=\"heading\">" 621 + generateHelpURL("Branch Coverage", 622 "The percent of branches executed by this test run.") 623 + "</td>"); 624 ret 625 .append(" <td class=\"heading\">" 626 + generateHelpURL( 627 "Complexity", 628 "Average McCabe's cyclomatic code complexity for all methods. This is basically a count of the number of different code paths in a method (incremented by 1 for each if statement, while loop, etc.)") 629 + "</td>"); 630 ret.append("</tr>"); 631 ret.append("</thead>"); 632 return ret.toString(); 633 } 634 635 private static String generateHelpURL(String text, String description) 636 { 637 StringBuffer ret = new StringBuffer (); 638 boolean popupTooltips = false; 639 if (popupTooltips) 640 { 641 ret 642 .append("<a class=\"hastooltip\" HREF=\"help.html\" onclick=\"popupwindow('help.html'); return false;\">"); 643 ret.append(text); 644 ret.append("<span>" + description + "</span>"); 645 ret.append("</a>"); 646 } 647 else 648 { 649 ret 650 .append("<a class=\"dfn\" HREF=\"help.html\" onclick=\"popupwindow('help.html'); return false;\">"); 651 ret.append(text); 652 ret.append("</a>"); 653 } 654 return ret.toString(); 655 } 656 657 private String generateTableRowForTotal() 658 { 659 StringBuffer ret = new StringBuffer (); 660 double ccn = complexity.getCCNForProject(projectData); 661 662 ret.append(" <tr>"); 663 ret.append("<td><b>All Packages</b></td>"); 664 ret.append("<td class=\"value\">" 665 + projectData.getNumberOfSourceFiles() + "</td>"); 666 ret.append(generateTableColumnsFromData(projectData, ccn)); 667 ret.append("</tr>"); 668 return ret.toString(); 669 } 670 671 private String generateTableRowForPackage(PackageData packageData) 672 { 673 StringBuffer ret = new StringBuffer (); 674 String url1 = "frame-summary-" + packageData.getName() + ".html"; 675 String url2 = "frame-sourcefiles-" + packageData.getName() + ".html"; 676 double ccn = complexity.getCCNForPackage(packageData); 677 678 ret.append(" <tr>"); 679 ret.append("<td><a HREF=\"" + url1 680 + "\" onclick='parent.sourceFileList.location.href=\"" + url2 681 + "\"'>" + generatePackageName(packageData) + "</a></td>"); 682 ret.append("<td class=\"value\">" + packageData.getNumberOfChildren() 683 + "</td>"); 684 ret.append(generateTableColumnsFromData(packageData, ccn)); 685 ret.append("</tr>"); 686 return ret.toString(); 687 } 688 689 private String generateTableRowsForSourceFile(SourceFileData sourceFileData) 690 { 691 StringBuffer ret = new StringBuffer (); 692 String sourceFileName = sourceFileData.getNormalizedName(); 693 double ccn = complexity.getCCNForSourceFile(sourceFileData); 695 696 Iterator iter = sourceFileData.getClasses().iterator(); 697 while (iter.hasNext()) 698 { 699 ClassData classData = (ClassData)iter.next(); 700 ret 701 .append(generateTableRowForClass(classData, sourceFileName, 702 ccn)); 703 } 704 705 return ret.toString(); 706 } 707 708 private String generateTableRowForClass(ClassData classData, 709 String sourceFileName, double ccn) 710 { 711 StringBuffer ret = new StringBuffer (); 712 713 ret.append(" <tr>"); 714 ret.append("<td><a HREF=\"" + sourceFileName 716 + ".html\">" + classData.getBaseName() + "</a></td>"); 717 ret.append(generateTableColumnsFromData(classData, ccn)); 718 ret.append("</tr>\n"); 719 return ret.toString(); 720 } 721 722 732 private static String generateTableColumnsFromData(CoverageData coverageData, 733 double ccn) 734 { 735 int numLinesCovered = coverageData.getNumberOfCoveredLines(); 736 int numLinesValid = coverageData.getNumberOfValidLines(); 737 int numBranchesCovered = coverageData.getNumberOfCoveredBranches(); 738 int numBranchesValid = coverageData.getNumberOfValidBranches(); 739 740 return "<td>" + generatePercentResult(numLinesCovered, numLinesValid) 743 +"</td><td>" 744 + generatePercentResult(numBranchesCovered, numBranchesValid) 745 + "</td><td class=\"value\"><span class=\"hidden\">" 746 + ccn + ";</span>" + getDoubleValue(ccn) + "</td>"; 747 } 748 749 757 private static String generatePercentResult(int dividend, int divisor) 758 { 759 StringBuffer sb = new StringBuffer (); 760 761 sb.append("<table cellpadding=\"0px\" cellspacing=\"0px\" class=\"percentgraph\"><tr class=\"percentgraph\"><td align=\"right\" class=\"percentgraph\" width=\"40\">"); 762 if (divisor > 0) 763 sb.append(getPercentValue((double)dividend / divisor)); 764 else 765 sb.append(generateHelpURL( 766 "N/A", 767 "Line coverage and branch coverage will appear as \"Not Applicable\" when Cobertura can not find line number information in the .class file. This happens for stub and skeleton classes, interfaces, or when the class was not compiled with \"debug=true.\"")); 768 sb.append("</td><td class=\"percentgraph\"><div class=\"percentgraph\">"); 769 if (divisor > 0) 770 { 771 sb.append("<div class=\"greenbar\" style=\"width:" 772 + (dividend * 100 / divisor) + "px\">"); 773 sb.append("<span class=\"text\">"); 774 sb.append(dividend); 775 sb.append("/"); 776 sb.append(divisor); 777 } 778 else 779 { 780 sb.append("<div class=\"na\" style=\"width:100px\">"); 781 sb.append("<span class=\"text\">"); 782 sb.append(generateHelpURL( 783 "N/A", 784 "Line coverage and branch coverage will appear as \"Not Applicable\" when Cobertura can not find line number information in the .class file. This happens for stub and skeleton classes, interfaces, or when the class was not compiled with \"debug=true.\"")); 785 } 786 sb.append("</span></div></div></td></tr></table>"); 787 788 return sb.toString(); 789 } 790 791 private static String getDoubleValue(double value) 792 { 793 NumberFormat formatter; 794 formatter = new DecimalFormat (); 795 return formatter.format(value); 796 } 797 798 private static String getPercentValue(double value) 799 { 800 NumberFormat formatter; 801 formatter = NumberFormat.getPercentInstance(); 802 return formatter.format(value); 803 } 804 805 } 806 | Popular Tags |