From dae4651f605dc12731720b0cc34a5926b12319f9 Mon Sep 17 00:00:00 2001
From: boli <boli@localhost>
Date: Tue, 09 Jan 2007 22:19:24 +0000
Subject: [PATCH] Added various enhancements to the coveragediff utility: 1. coveragediff is now an ant task that is run after the test*withcoverage targets. It can be disabled with -Dtest.diff.disabled= 2. coveragediff now calls svn internally. By default it looks for svn in your path. You can specify where svn is manually by using the -Dtest.diff.svnpath property. You can also specify what files are diffed by using the -Dtest.diff.srcpath property. 3. the testcustom* targets are removed and the test* should now be used. If no no -Dtest.* properties are set, it runs the default set of tests just like before.  4. coveragediff now generates an html report to build/diff/reports/.  5. coveragediff now calculates coverage for modified lines overall and by file. It also lists overall number of lines modified and deleted. 6. coveragediff can function without coverage data. It will issue an warning and just generate the report w/o any coverage info. Users can use the coveragediff ant target just to generate a graphical diff.

---
 opends/build-tools/src/org/opends/build/tools/CoverageDiff.java |  823 ++++++++++++++++++++++++++++++++++++++++++++++------------
 1 files changed, 652 insertions(+), 171 deletions(-)

diff --git a/opends/build-tools/src/org/opends/build/tools/CoverageDiff.java b/opends/build-tools/src/org/opends/build/tools/CoverageDiff.java
index 274e425..6f82c5d 100644
--- a/opends/build-tools/src/org/opends/build/tools/CoverageDiff.java
+++ b/opends/build-tools/src/org/opends/build/tools/CoverageDiff.java
@@ -1,59 +1,163 @@
 package org.opends.build.tools;
 
-import com.vladium.emma.*;
 import com.vladium.emma.report.*;
+import com.vladium.emma.report.html.doc.*;
 import com.vladium.emma.data.*;
 import com.vladium.util.IntObjectMap;
 
 import java.io.*;
-import java.util.Iterator;
-import java.util.ArrayList;
+import java.util.*;
 
-public class CoverageDiff {
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.BuildException;
+
+public class CoverageDiff extends Task {
 
 
-  private static boolean verbose = false;
+  private boolean verbose = false;
+  private boolean enabled = true;
 
-  public static void main(String[] args) {
+  private final int COVERED_MOD_EXE_LINES = 0;
+  private final int MOD_EXE_LINES = 1;
+  private final int MOD_LINES = 2;
+  private final int DEL_LINES = 3;
 
-    if(args.length < 1 || args[0] == null)
+  private final String ENCODING = "ISO-8859-1";
+  private final int IO_BUF_SIZE = 32 * 1024;
+  private final LinkedHashMap<String, SrcFileItem> emmaSrcMap =
+      new LinkedHashMap<String, SrcFileItem>();
+  private final LinkedHashMap<String, Double[]> modCoverageMap =
+      new LinkedHashMap<String, Double[]>();
+
+  private final String CSS = "TABLE,TD,TH {border-style:solid; border-color:black;} " +
+            "TD,TH {background:white;margin:0;line-height:100%;padding-left:0.5em;padding-right:0.5em;} " +
+            "TD {border-width:0 1px 0 0;} TH {border-width:1px 1px 1px 0;} " +
+            "TR TD.h {color:red;} " +
+            "TABLE {border-spacing:0; border-collapse:collapse;border-width:0 0 1px 1px;} " +
+            "P,H1,H2,H3,TH {font-family:verdana,arial,sans-serif;font-size:10pt;} " +
+            "TD {font-family:courier,monospace;font-size:10pt;} " +
+            "TABLE.hdft {border-spacing:0;border-collapse:collapse;border-style:none;} " +
+            "TABLE.hdft TH,TABLE.hdft TD {border-style:none;line-height:normal;} " +
+            "TABLE.hdft TH.tl,TABLE.hdft TD.tl {background:#6699CC;color:white;} " +
+            "TABLE.hdft TD.nv {background:#6633DD;color:white;} " +
+            ".nv A:link {color:white;} .nv A:visited {color:white;} " +
+            ".nv A:active {color:yellow;} " +
+            "TABLE.hdft A:link {color:white;} " +
+            "TABLE.hdft A:visited {color:white;} " +
+            "TABLE.hdft A:active {color:yellow;} " +
+            ".in {color:#356085;} " +
+            "TABLE.s TD {padding-left:0.25em;padding-right:0.25em;} " +
+            "TABLE.s TD.ddt {padding-left:0.25em;padding-right:0.25em;color:#AAAAAA;}" +
+            "TABLE.s TD.ds {padding-left:0.25em;padding-right:0.25em;text-align:right;background:#F0F0F0;} " +
+            "TABLE.s TD.dm {padding-left:0.25em;padding-right:0.25em;text-align:right;background:#BCCFF9;} " +
+            "TABLE.s TD.dd {padding-left:0.25em;padding-right:0.25em;text-align:right;background:#AAAAAA;color:#FFFFFF} " +
+            "TABLE.s TH {padding-left:0.25em;padding-right:0.25em;text-align:left;background:#F0F0F0;} " +
+            "TABLE.s TD.cz {background:#FF9999;} " +
+            "TABLE.s TD.cp {background:#FFFF88;} " +
+            "TABLE.s TD.cc {background:#CCFFCC;} " +
+            "A:link {color:#0000EE;text-decoration:none;} " +
+            "A:visited {color:#0000EE;text-decoration:none;} " +
+            "A:hover {color:#0000EE;text-decoration:underline;} " +
+            "TABLE.cn {border-width:0 0 1px 0;} " +
+            "TABLE.s {border-width:1px 0 1px 1px;} " +
+            "TD.h {color:red;border-width:0 1px 0 0;} " +
+            "TD.f {border-width:0 1px 0 1px;} " +
+            "TD.hf {color:red;border-width:0 1px 0 1px;} " +
+            "TH.f {border-width:1px 1px 1px 1px;} " +
+            "TR.cis TD {background:#F0F0F0;} " +
+            "TR.cis TD {border-width:1px 1px 1px 0;} " +
+            "TR.cis TD.h {color:red;border-width:1px 1px 1px 0;} " +
+            "TR.cis TD.f {border-width:1px 1px 1px 1px;} " +
+            "TR.cis TD.hf {color:red;border-width:1px 1px 1px 1px;} " +
+            "TD.b {border-style:none;background:transparent;line-height:50%;}  " +
+            "TD.bt {border-width:1px 0 0 0;background:transparent;line-height:50%;} " +
+            "TR.o TD {background:#F0F0F0;}" +
+            "TABLE.it {border-style:none;}" +
+            "TABLE.it TD,TABLE.it TH {border-style:none;}";
+
+  private File emmaDataPath;
+  private File outputPath;
+  private File diffPath;
+  private File svnPath;
+
+  public void setEmmaDataPath(String file)
+  {
+    emmaDataPath = new File(file);
+  }
+
+  public void setOutputPath(String file)
+  {
+    outputPath = new File(file);
+  }
+
+  public void setDiffPath(String file)
+  {
+    diffPath = new File(file);
+  }
+
+  public void setSvnPath(String file)
+  {
+    svnPath = new File(file);
+  }
+
+  public void setVerbose(String bol)
+  {
+    verbose = bol.toLowerCase().equals("true");
+  }
+
+  public void setEnabled(String bol)
+  {
+    enabled = bol.toLowerCase().equals("true");
+  }
+
+  public void execute() throws BuildException
+  {
+    if(emmaDataPath == null)
     {
-      System.out.println("Please specify emma data location");
+      throw new BuildException("emmaDataPath attribute is not set. It must be set to the path of the EMMA data directory");
+    }
+    if(outputPath == null)
+    {
+      throw new BuildException("outputPath attribute is not set. It must be set to a valid directory where the report will be generated");
+    }
+
+    if(!enabled)
+    {
       return;
     }
+
     IReportDataView emmaDataView = null;
     try
     {
-      emmaDataView = loadEmmaData(new File(args[0].trim()));
-
+        emmaDataView = loadEmmaData(emmaDataPath);
     }
     catch(IOException ie)
     {
-      System.out.println("An error occured while loading EMMA data: " + ie.toString());
+      System.out.println("WARNING: An error occured while loading EMMA " +
+          "data. Report will not contain any coverage information.");
     }
 
-    if(emmaDataView == null)
+    try
     {
-      System.out.println(System.in);
+      processDiffOutput(getDiffOutputReader(), emmaDataView);
     }
-    else
+    catch(IOException ie)
     {
-      try
-      {
-        processDiffOutput(new BufferedReader(new InputStreamReader(System.in)), emmaDataView);
-      }
-      catch(IOException ie)
-      {
-        System.out.println("An error occured while processing diff output: " + ie.toString());
-      }
+      throw new BuildException("An error occured while processing diff output: " + ie.toString(), ie);
     }
   }
 
 
-  private static IReportDataView loadEmmaData(File emmaCoverageDataDir) throws IOException {
+  private IReportDataView loadEmmaData(File emmaCoverageDataDir) throws IOException
+  {
+    if(emmaCoverageDataDir == null)
+    {
+      throw new IOException("Emma Converage Data Directory is null");
+    }
+
     File[] emmaCoverageDataFiles = emmaCoverageDataDir.listFiles();
     int emmaCoverageDataFileCount = 0;
-    IReportDataView m_view = null;
+    IReportDataView m_view;
     IMetaData mdata = null;
     ICoverageData cdata = null;
 
@@ -68,8 +172,7 @@
 
     // merge all data files:
 
-    for (int f = 0; f < emmaCoverageDataFiles.length; ++f) {
-      final File dataFile = emmaCoverageDataFiles[f];
+    for (final File dataFile : emmaCoverageDataFiles) {
       if (verbose)
         System.out.println("processing input file [" + dataFile.getAbsolutePath() + "] ...");
 
@@ -128,34 +231,81 @@
     final IReportDataModel model = IReportDataModel.Factory.create (mdata, cdata);
     m_view = model.getView (IReportDataView.HIER_SRC_VIEW);
 
-    if (verbose) {
-      if (mdata != null) {
-        System.out.println("  merged metadata contains " + mdata.size() + " entries");
-      }
+    if (verbose)
+    {
+      System.out.println("  merged metadata contains " + mdata.size() + " entries");
+      System.out.println("  merged coverage data contains " + cdata.size() + " entries");
 
-      if (cdata != null) {
-        System.out.println("  merged coverage data contains " + cdata.size() + " entries");
-      }
     }
 
     return m_view;
   }
 
-  private static BufferedReader getDiffOutputReader() throws IOException {
+  private BufferedReader getDiffOutputReader() throws IOException {
 
-    Process child = Runtime.getRuntime().exec("svn diff");
+    StringBuilder svnExecCommand = new StringBuilder();
+
+    if(svnPath != null && svnPath.isAbsolute() && svnPath.isFile())
+    {
+      svnExecCommand.append(svnPath.getAbsolutePath());
+    }
+    else
+    {
+      //Just hope its in the path
+      svnExecCommand.append("svn");
+    }
+
+    //First verify svn is in path
+    final Process checkChild = Runtime.getRuntime().exec(svnExecCommand + " --version");
+    
+    try
+    {
+      checkChild.waitFor();
+    }
+    catch(InterruptedException ie)
+    {
+      throw new IOException("svn --version process interrupted");
+    }
+
+    if(checkChild.exitValue() != 0)
+    {
+      throw new IOException("Error returned from SVN call");
+    }
+    checkChild.destroy();
+
+    svnExecCommand.append(" diff ");
+
+    if(diffPath != null)
+    {
+      svnExecCommand.append(diffPath);
+    }
+
+
+    final Process child = Runtime.getRuntime().exec(svnExecCommand.toString());
     InputStream diffOutputStream = child.getInputStream();
-    BufferedReader diffOutput = new BufferedReader(
-        new InputStreamReader(diffOutputStream));
-    return diffOutput;
-
+    return new BufferedReader(new InputStreamReader(diffOutputStream));
   }
 
-  private static void processDiffOutput(BufferedReader diffOutput,
+  private void processDiffOutput(BufferedReader diffOutput,
                                         IReportDataView emmaDataView)
       throws IOException {
 
-    String line = diffOutput.readLine();
+    File file = new File(outputPath, "index.html");
+    BufferedWriter writer =
+        new BufferedWriter (new OutputStreamWriter (
+            new FileOutputStream (file), ENCODING), IO_BUF_SIZE);
+    HTMLWriter out = new HTMLWriter(writer);
+
+    System.out.println("Writing report to [" + file.toString() + "]");
+
+    String title = "Coverage Diff Report (generated ";
+    title = title + new Date(System.currentTimeMillis ());
+    title = title + " )";
+
+    HTMLDocument page = new HTMLDocument (title, ENCODING);
+    page.addStyle (CSS);
+
+        String line = diffOutput.readLine();
     ArrayList<String> diffOutputFile = new ArrayList<String>();
 
     while(line != null)
@@ -163,7 +313,7 @@
       //Diffed file
       if(line.length() >6 && line.substring(0, 6).equals("Index:"))
       {
-        processDiffOutputFile(diffOutputFile, emmaDataView);
+        processDiffOutputFile(page, diffOutputFile, emmaDataView);
         diffOutputFile = new ArrayList<String>();
         diffOutputFile.add(line);
       }
@@ -174,10 +324,108 @@
 
       line = diffOutput.readLine();
     }
-    processDiffOutputFile(diffOutputFile, emmaDataView);
+    processDiffOutputFile(page, diffOutputFile, emmaDataView);
+
+    IElementList overallStats = new ElementList();
+
+    final IElement statTitle = IElement.Factory.create (Tag.Hs[1]);
+    statTitle.setText("OVERALL STATS SUMMARY", true);
+
+    overallStats.add(statTitle);
+
+    final HTMLTable statsTable = new HTMLTable (null, null, null, "0");
+    statsTable.setClass ("it");
+    {
+      HTMLTable.IRow row = statsTable.newRow ();
+      row.newCell ().setText ("base directory:", true);
+      row.newCell ().setText ("" + diffPath.toString(), true);
+
+      row = statsTable.newRow ();
+      row.newCell ().setText ("total files modified:", true);
+      row.newCell ().setText ("" + emmaSrcMap.keySet().size(), false);
+
+      Double[] overallModCoverage = new Double[4];
+      overallModCoverage[COVERED_MOD_EXE_LINES] = 0.0;
+      overallModCoverage[MOD_EXE_LINES] = 0.0;
+      overallModCoverage[MOD_LINES] = 0.0;
+      overallModCoverage[DEL_LINES] = 0.0;
+
+      Double[] modCoverage;
+      for (Double[] doubles : modCoverageMap.values()) {
+        modCoverage = doubles;
+
+        if (modCoverage != null) {
+          overallModCoverage[COVERED_MOD_EXE_LINES] += modCoverage[COVERED_MOD_EXE_LINES];
+          overallModCoverage[MOD_EXE_LINES] += modCoverage[MOD_EXE_LINES];
+          overallModCoverage[MOD_LINES] += modCoverage[MOD_LINES];
+          overallModCoverage[DEL_LINES] += modCoverage[DEL_LINES];
+        }
+      }
+      String modCoverageStr = "";
+      if(overallModCoverage[MOD_EXE_LINES] > 0)
+      {
+        modCoverageStr =
+            String.valueOf(overallModCoverage[COVERED_MOD_EXE_LINES]/overallModCoverage[MOD_EXE_LINES]*100) + "% ";
+      }
+      modCoverageStr = modCoverageStr + "(" +
+          overallModCoverage[COVERED_MOD_EXE_LINES] + "/" +
+          overallModCoverage[MOD_EXE_LINES] +")";
+      row = statsTable.newRow ();
+      row.newCell ().setText ("total lines modified:", true);
+      row.newCell ().setText ("" + overallModCoverage[MOD_LINES], true);
+      row = statsTable.newRow ();
+      row.newCell ().setText ("total lines removed:", true);
+      row.newCell ().setText ("" + overallModCoverage[DEL_LINES], true);
+      row = statsTable.newRow ();
+      row.newCell ().setText ("coverage for modified executable lines:", true);
+      row.newCell ().setText ("" + modCoverageStr, true);
+    }
+
+    overallStats.add(statsTable);
+
+    final IElement coverageTitle = IElement.Factory.create (Tag.Hs[1]);
+    statTitle.setText("OVERALL DIFF SUMMARY", true);
+
+    overallStats.add(coverageTitle);
+
+    HTMLTable summaryTable = new HTMLTable ("100%", null, null, "0");
+    if(emmaDataView != null)
+    {
+      addHeaderRow(emmaDataView.getRoot(), summaryTable, true);
+    }
+    else
+    {
+      addHeaderRow(null, summaryTable, true);
+    }
+
+    Set<Map.Entry<String, SrcFileItem>> items = emmaSrcMap.entrySet();
+    Map.Entry<String, SrcFileItem> item;
+    boolean odd = true;
+
+    for (Map.Entry<String, SrcFileItem> item1 : items) {
+      item = item1;
+
+      if (item != null) {
+        final String fileName = item.getKey();
+        final SrcFileItem srcFileItem = item.getValue();
+        final Double[] modCoverage = modCoverageMap.get(fileName);
+
+        addItemRow(fileName, srcFileItem, modCoverage, odd, summaryTable, createHREF(fileName), true, true);
+
+        odd = !odd;
+      }
+    }
+
+    overallStats.add(summaryTable);
+
+    page.setHeader(overallStats);
+
+    page.emit(out);
+    out.flush();
   }
 
-  private static void processDiffOutputFile(ArrayList<String> diffFile,
+  private void processDiffOutputFile(HTMLDocument html,
+                                            ArrayList<String> diffFile,
                                             IReportDataView emmaDataView)
       throws IOException
   {
@@ -185,126 +433,164 @@
     {
       return;
     }
-    
+
+    Double[] modCoverage = new Double[4];
+    modCoverage[COVERED_MOD_EXE_LINES] = 0.0;
+    modCoverage[MOD_EXE_LINES] = 0.0;
+    modCoverage[MOD_LINES] = 0.0;
+    modCoverage[DEL_LINES] = 0.0;
+
     String fileHeader = diffFile.get(0);
 
+    //Try to get the package information if its a Java file
     File srcFilePath = new File(fileHeader.substring(7));
-    FileInputStream srcFile = new FileInputStream(srcFilePath);
-    String srcFilePackage = parseJavaPackage(srcFile);
-    SrcFileItem emmaSourceItem = getEmmaSrcItem(emmaDataView.getRoot(),
-                  srcFilePackage, srcFilePath.getName());
-
-    if(emmaSourceItem == null)
+    SrcFileItem emmaSourceItem = null;
+    if(srcFilePath.isFile())
     {
-      System.out.println(fileHeader);
-      System.out.println("Coverage: Not Available");
-      for(int i = 1; i < diffFile.size(); i++)
+      FileInputStream srcFile = new FileInputStream(srcFilePath);
+      String srcFilePackage = parseJavaPackage(srcFile);
+      if(emmaDataView != null)
       {
-        System.out.println(diffFile.get(i));
+        emmaSourceItem = getEmmaSrcItem(emmaDataView.getRoot(),
+                  srcFilePackage, srcFilePath.getName());
       }
     }
+
+    //Figure out the flag for the working copy.
+    String workingCopyFlag = null;
+    String otherCopyFlag = null;
+
+    String firstFileLine = diffFile.get(2);
+    String secondFileLine = diffFile.get(3);
+    String revisionStr = "unknown";
+
+
+    HTMLTable srcTable = null;
+
+    if(firstFileLine.endsWith("(working copy)"))
+    {
+      workingCopyFlag = firstFileLine.substring(0, 1);
+    }
     else
     {
-      System.out.println(fileHeader);
+      otherCopyFlag = firstFileLine.substring(0, 1);
+      revisionStr = firstFileLine.substring(firstFileLine.lastIndexOf("("));
+    }
 
-      System.out.print("Coverage: ");
-      String name;
-      StringBuffer buf = new StringBuffer();
-      for(int i = 1; i <= 4; i++)
+    if(secondFileLine.endsWith("(working copy)"))
+    {
+      workingCopyFlag = secondFileLine.substring(0, 1);
+    }
+    else
+    {
+      otherCopyFlag = secondFileLine.substring(0, 1);
+      revisionStr = secondFileLine.substring(secondFileLine.lastIndexOf("("));
+    }
+
+    if(firstFileLine.endsWith("(revision 0)") &&
+        secondFileLine.endsWith("(revision 0)"))
+    {
+      workingCopyFlag = "+";
+      otherCopyFlag = "-";
+    }
+
+    if(workingCopyFlag == null || otherCopyFlag == null)
+    {
+      throw new IOException("Error occured while parsing diff output");
+    }
+    else
+    {
+      srcTable = new HTMLTable ("100%", null, null, "0");
+      srcTable.setClass("s");
+
+      ArrayList<String> diffOutputChunk = new ArrayList<String>();
+      Double[] chunkModCoverage;
+
+      for(int i = 4; i < diffFile.size(); i++)
       {
-        buf.setLength(0);
-        emmaSourceItem.getAttribute(i, 0).format(emmaSourceItem, buf);
-        name = emmaSourceItem.getAttribute(i, 0).getName();
-        System.out.print(name);
-        for(int j = 0; j < buf.length() - name.length() + 1; j++)
+        //Found a chunk indicator.
+        if(diffFile.get(i).startsWith("@@"))
         {
-          System.out.print(" ");
-        }
-      }
-      System.out.print("\n          ");
-      for(int i = 1; i <= 4; i++)
-      {
-        buf.setLength(0);
-        emmaSourceItem.getAttribute(i, 0).format(emmaSourceItem, buf);
-        System.out.print(buf + " ");
-      }
-      System.out.println("");
-
-      System.out.println(diffFile.get(1));
-
-      //Figure out the flag for the working copy.
-      String workingCopyFlag = null;
-      String otherCopyFlag = null;
-
-      String firstFileLine = diffFile.get(2);
-      String secondFileLine = diffFile.get(3);
-      System.out.println(firstFileLine);
-      System.out.println(secondFileLine);
-
-      if(firstFileLine.endsWith("(working copy)"))
-      {
-        workingCopyFlag = firstFileLine.substring(0, 1);
-      }
-      else
-      {
-        otherCopyFlag = firstFileLine.substring(0, 1);
-      }
-
-      if(secondFileLine.endsWith("(working copy)"))
-      {
-        workingCopyFlag = secondFileLine.substring(0, 1);
-      }
-      else
-      {
-        otherCopyFlag = secondFileLine.substring(0, 1);
-      }
-
-      if(firstFileLine.endsWith("(revision 0)") &&
-          secondFileLine.endsWith("(revision 0)"))
-      {
-        workingCopyFlag = "+";
-        otherCopyFlag = "-";
-      }
-
-      if(workingCopyFlag == null || otherCopyFlag == null ||
-          srcFilePackage == null)
-      {
-        for(int i = 4; i < diffFile.size(); i++)
-        {
-          System.out.println(diffFile.get(i));
-        }
-      }
-      else
-      {
-
-        ArrayList<String> diffOutputChunk = new ArrayList<String>();
-
-        for(int i = 4; i < diffFile.size(); i++)
-        {
-          //Found a chunk indicator.
-          if(diffFile.get(i).startsWith("@@"))
-          {
-            processDiffOutputFileChunk(diffOutputChunk, workingCopyFlag,
+          chunkModCoverage = processDiffOutputFileChunk(srcTable, diffOutputChunk, workingCopyFlag,
                 otherCopyFlag, emmaSourceItem);
-            diffOutputChunk = new ArrayList<String>();
-            diffOutputChunk.add(diffFile.get(i));
-          }
-          //Not any of the above so this line must be diffed text
-          else
-          {
-            diffOutputChunk.add(diffFile.get(i));
-          }
-        }
 
-        //Finishing process whatever we have queued up
-        processDiffOutputFileChunk(diffOutputChunk, workingCopyFlag,
-            otherCopyFlag, emmaSourceItem);
+          if(chunkModCoverage != null)
+          {
+            modCoverage[COVERED_MOD_EXE_LINES] += chunkModCoverage[COVERED_MOD_EXE_LINES];
+            modCoverage[MOD_EXE_LINES] += chunkModCoverage[MOD_EXE_LINES];
+            modCoverage[MOD_LINES] += chunkModCoverage[MOD_LINES];
+            modCoverage[DEL_LINES] += chunkModCoverage[DEL_LINES];
+          }
+
+          diffOutputChunk = new ArrayList<String>();
+          diffOutputChunk.add(diffFile.get(i));
+        }
+        //Not any of the above so this line must be diffed text
+        else
+        {
+          diffOutputChunk.add(diffFile.get(i));
+        }
+      }
+
+      //Finishing process whatever we have queued up
+      chunkModCoverage = processDiffOutputFileChunk(srcTable, diffOutputChunk, workingCopyFlag,
+          otherCopyFlag, emmaSourceItem);
+      if(chunkModCoverage != null)
+      {
+        modCoverage[COVERED_MOD_EXE_LINES] += chunkModCoverage[COVERED_MOD_EXE_LINES];
+        modCoverage[MOD_EXE_LINES] += chunkModCoverage[MOD_EXE_LINES];
+        modCoverage[MOD_LINES] += chunkModCoverage[MOD_LINES];
+        modCoverage[DEL_LINES] += chunkModCoverage[DEL_LINES];
       }
     }
 
+    final IElement a = IElement.Factory.create (Tag.A);
+    a.getAttributes ().set (Attribute.NAME, createHREF(srcFilePath.toString()));
+
+    html.add(a);
+
+    final IElement itemname = IElement.Factory.create (Tag.SPAN);
+    {
+      itemname.setText (toRelativePath(srcFilePath.toString()), true);
+      itemname.setClass ("in");
+    }
+
+    final IElementList title = new ElementList ();
+    {
+      title.add (new Text ("DIFF SUMMARY FOR SOURCE FILE [", true));
+      title.add (itemname);
+      title.add (new Text ("] against ", true));
+      title.add (new Text (revisionStr, true));
+    }
+
+    html.addH (1, title, null);
+
+    if(emmaSourceItem != null)
+    {
+      final HTMLTable coverageTable = new HTMLTable ("100%", null, null, "0");
+      addHeaderRow(emmaSourceItem, coverageTable, false);
+      addItemRow(srcFilePath.toString(), emmaSourceItem, modCoverage, false, coverageTable, null, false, false);
+
+      html.add(coverageTable);
+
+      html.addEmptyP();
+    }
+    else
+    {
+      html.addH(2, "Coverage Information Not Available", null);
+    }
+
+    if(srcTable != null)
+    {
+      html.add(srcTable);
+    }
+
+    emmaSrcMap.put(srcFilePath.toString(), emmaSourceItem);
+    modCoverageMap.put(srcFilePath.toString(), modCoverage);
   }
 
-  private static void processDiffOutputFileChunk(ArrayList<String> diffChunk,
+  private Double[] processDiffOutputFileChunk(HTMLTable table,
+                                                 ArrayList<String> diffChunk,
                                                  String workingCopyFlag,
                                                  String otherCopyFlag,
                                                  SrcFileItem emmaSrcItem)
@@ -312,13 +598,19 @@
 
     if(diffChunk.size() <= 0)
     {
-      return;
+      return null;
     }
 
     int workingCopyBegin;
     int workingCopyRange;
     int otherCopyBegin;
     int otherCopyRange;
+    
+    Double[] modCoverage = new Double[4];
+    modCoverage[COVERED_MOD_EXE_LINES] = 0.0;
+    modCoverage[MOD_EXE_LINES] = 0.0;
+    modCoverage[MOD_LINES] = 0.0;
+    modCoverage[DEL_LINES] = 0.0;
 
     IntObjectMap lineCoverageMap = null;
     if(emmaSrcItem != null)
@@ -327,7 +619,6 @@
     }
 
     String chunkHeader = diffChunk.get(0);
-    System.out.println(chunkHeader);
 
     int workingCopyBeginIdx = chunkHeader.indexOf(workingCopyFlag);
     int workingCopyCommaIdx = chunkHeader.indexOf(",", workingCopyBeginIdx);
@@ -346,52 +637,90 @@
 
     String chunkLine;
     SrcFileItem.LineCoverageData lCoverageData = null;
-    int workingCopyLineIncrement = 0;
-    int otherCopyLineIncrement = 0;
+    int workingCopyLine = workingCopyBegin;
+    int otherCopyLine = otherCopyBegin;
+
+    final HTMLTable.IRow chunkRow = table.newTitleRow();
+    final HTMLTable.ICell chunkCell = chunkRow.newCell();
+    chunkCell.setColspan(2);
+    chunkCell.setText("Lines " + workingCopyBegin + " - " +
+        String.valueOf(workingCopyLine + workingCopyRange), true);
+
     for(int i = 1; i < diffChunk.size(); i++)
     {
       chunkLine = diffChunk.get(i);
-      //System.out.print(workingCopyBegin + workingCopyLineIncrement + " ");
+
       if(lineCoverageMap != null)
       {
-        lCoverageData = (SrcFileItem.LineCoverageData) lineCoverageMap.get (workingCopyBegin + workingCopyLineIncrement);
+        lCoverageData = (SrcFileItem.LineCoverageData) lineCoverageMap.get (workingCopyLine);
       }
 
-      if(!chunkLine.startsWith(otherCopyFlag) && lCoverageData != null)
-      {
+      final HTMLTable.IRow srcRow = table.newRow();
+      final HTMLTable.ICell lineNumCell = srcRow.newCell();
+      final HTMLTable.ICell lineTxtCell = srcRow.newCell();
 
-        switch(lCoverageData.m_coverageStatus)
+      lineTxtCell.setText(chunkLine.substring(1), true);
+
+      //This line is either a modified line or a unchanged line
+      if(!chunkLine.startsWith(otherCopyFlag))
+      {
+        lineNumCell.setText(String.valueOf(workingCopyLine), true);
+
+        //Determine if this line is a modified line or a unchange line
+        if(chunkLine.startsWith(workingCopyFlag))
         {
-          case SrcFileItem.LineCoverageData.LINE_COVERAGE_ZERO:
-            System.out.println(chunkLine.charAt(0) + "N" + chunkLine.substring(1));
-            break;
-          case SrcFileItem.LineCoverageData.LINE_COVERAGE_PARTIAL:
-            System.out.println(chunkLine.charAt(0) + "P" + chunkLine.substring(1));
-            break;
-          case SrcFileItem.LineCoverageData.LINE_COVERAGE_COMPLETE:
-            System.out.println(chunkLine.charAt(0) + "C" + chunkLine.substring(1));
-            break;
-          default:
-            System.out.println(chunkLine.charAt(0) + "U" + chunkLine.substring(1));
+          lineNumCell.setClass("dm");
+          modCoverage[MOD_LINES] ++;
+        }
+        else
+        {
+          lineNumCell.setClass("ds");
+        }
+
+        if(lCoverageData != null)
+        {
+          modCoverage[MOD_EXE_LINES] ++;
+          switch(lCoverageData.m_coverageStatus)
+          {
+            case SrcFileItem.LineCoverageData.LINE_COVERAGE_ZERO:
+              lineTxtCell.setClass ("cz");
+              break;
+
+            case SrcFileItem.LineCoverageData.LINE_COVERAGE_PARTIAL:
+              lineTxtCell.setClass ("cp");
+              modCoverage[COVERED_MOD_EXE_LINES] += 0.5;
+              break;
+
+            case SrcFileItem.LineCoverageData.LINE_COVERAGE_COMPLETE:
+              lineTxtCell.setClass ("cc");
+              modCoverage[COVERED_MOD_EXE_LINES] ++;
+              break;
+            default:
+          }
         }
       }
       else
       {
-        System.out.println(chunkLine.charAt(0) + " " + chunkLine.substring(1));
+        lineNumCell.setClass("dd");
+        lineNumCell.setText(String.valueOf(otherCopyLine), true);
+        lineTxtCell.setClass("ddt");
+        modCoverage[DEL_LINES] ++;
       }
 
       if(!chunkLine.startsWith(otherCopyFlag))
       {
-        workingCopyLineIncrement++;
+        workingCopyLine++;
       }
       if(!chunkLine.startsWith(workingCopyFlag))
       {
-        otherCopyLineIncrement++;
+        otherCopyLine++;
       }
     }
+
+    return modCoverage;
   }
 
-  private static String parseJavaPackage(FileInputStream srcFile)
+  private String parseJavaPackage(FileInputStream srcFile)
       throws IOException {
 
     BufferedReader srcFileReader = new BufferedReader(
@@ -406,7 +735,7 @@
         int endIdx = line.indexOf(";", beginIdx);
         if(endIdx > -1)
         {
-          return  line.substring(beginIdx + 7, endIdx).trim();
+          return line.substring(beginIdx + 7, endIdx).trim();
         }
       }
       line = srcFileReader.readLine();
@@ -415,10 +744,15 @@
     return null;
   }
 
-  private static SrcFileItem getEmmaSrcItem(IItem rootItem,
+  private  SrcFileItem getEmmaSrcItem(IItem rootItem,
                                       String srcPackageName,
                                       String srcFileName)
   {
+    if(rootItem == null || srcPackageName == null || srcFileName == null)
+    {
+      return null;
+    }
+    
     for(Iterator packages = rootItem.getChildren(); packages.hasNext();)
     {
       IItem packageItem = (IItem)packages.next();
@@ -436,4 +770,151 @@
     }
     return null;
   }
+
+  private void addHeaderRow (final IItem item, final HTMLTable table, boolean includeName)
+  {
+
+    // header row:
+    final HTMLTable.IRow header = table.newTitleRow ();
+
+    if(includeName)
+    {
+      final HTMLTable.ICell nameCell = header.newCell();
+      nameCell.setText("File", true);
+    }
+
+    for (int c = 1; c <= 4; ++ c)
+    {
+      IItemAttribute attr = null;
+
+      if(item != null)
+      {
+        attr = item.getAttribute (c, 0);
+      }
+
+      if (attr != null)
+      {
+        final HTMLTable.ICell cell = header.newCell ();
+
+        cell.setText (attr.getName (), true);
+      }
+      else
+      {
+        final HTMLTable.ICell cell = header.newCell ();
+        cell.setText (" ", true);
+      }
+
+    }
+
+    if(item != null)
+    {
+      final HTMLTable.ICell cell = header.newCell();
+      cell.setText("mod lines, %", true);
+    }
+    else
+    {
+      final HTMLTable.ICell cell = header.newCell ();
+      cell.setText (" ", true);
+    }
+
+  }
+
+  /*
+     * No header row, just data rows.
+     */
+  private void addItemRow (final String fileName,
+                           final IItem item,
+                           final Double[] modCoverage,
+                           final boolean odd,
+                           final HTMLTable table,
+                           final String nameHREF,
+                           final boolean anchor,
+                           final boolean includeName)
+  {
+    final HTMLTable.IRow row = table.newRow ();
+    if (odd) row.setClass ("o");
+
+    if(includeName)
+    {
+      final HTMLTable.ICell nameCell = row.newCell();
+      if(nameHREF != null)
+      {
+        final String fullHREFName = anchor ? "#".concat (nameHREF) : nameHREF;
+        nameCell.add(new HyperRef(fullHREFName, toRelativePath(fileName), true));
+      }
+      else
+      {
+        nameCell.setText(fileName, true);
+      }
+    }
+
+    final StringBuffer buf = new StringBuffer (11);
+
+    for (int c = 1; c <=4; ++ c)
+    {
+      IItemAttribute attr = null;
+
+      if(item != null)
+      {
+        attr = item.getAttribute (c, 0);
+      }
+
+      if (attr != null)
+      {
+        final HTMLTable.ICell cell = row.newCell ();
+
+
+        //final boolean fail = (m_metrics [attrID] > 0) && ! attr.passes (item, m_metrics [attrID]);
+
+        buf.setLength (0);
+        attr.format (item, buf);
+
+        cell.setText (buf.toString (), true);
+        //if (fail) cell.setClass (CSS_DATA_HIGHLIGHT);
+
+      }
+      else
+      {
+
+        final HTMLTable.ICell cell = row.newCell ();
+        cell.setText (" ", true);
+      }
+    }
+
+    if(item != null && modCoverage != null)
+    {
+      String modCoverageStr = "";
+      if(modCoverage[1] > 0)
+      {
+        modCoverageStr = String.valueOf(modCoverage[0]/modCoverage[1]*100) + "% ";
+      }
+      modCoverageStr = modCoverageStr + "(" + modCoverage[0] + "/" + modCoverage[1] +")";
+
+      final HTMLTable.ICell cell = row.newCell();
+      cell.setText(modCoverageStr, true);
+    }
+    else
+    {
+      final HTMLTable.ICell cell = row.newCell ();
+      cell.setText (" ", true);
+    }
+  }
+
+  private String createHREF(String name)
+  {
+    if(name == null)
+    {
+      return null;
+    }
+
+    name = name.replaceAll("[/,\\,(,),.]", "_");
+
+    return name;
+
+  }
+
+  private String toRelativePath(String file)
+  {
+    return file.substring(diffPath.toString().length()+1);
+  }
 }

--
Gitblit v1.10.0