mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

boli
09.19.2007 2465da4eae0df8251b578e47411ed2f6981ea9d6
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.

Fix for issue 1125
1 files deleted
2 files modified
861 ■■■■ changed files
opendj-sdk/opends/build-tools/bin/coveragediff 61 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/build-tools/src/org/opends/build/tools/CoverageDiff.java 693 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/build.xml 107 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/build-tools/bin/coveragediff
File was deleted
opendj-sdk/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)
    {
      System.out.println("Please specify emma data location");
    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)
    {
      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)
    {
      System.out.println(System.in);
    }
    else
    {
      try
      {
        processDiffOutput(new BufferedReader(new InputStreamReader(System.in)), emmaDataView);
      processDiffOutput(getDiffOutputReader(), 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,33 +231,80 @@
    final IReportDataModel model = IReportDataModel.Factory.create (mdata, cdata);
    m_view = model.getView (IReportDataView.HIER_SRC_VIEW);
    if (verbose) {
      if (mdata != null) {
    if (verbose)
    {
        System.out.println("  merged metadata contains " + mdata.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");
    InputStream diffOutputStream = child.getInputStream();
    BufferedReader diffOutput = new BufferedReader(
        new InputStreamReader(diffOutputStream));
    return diffOutput;
    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");
  }
  private static void processDiffOutput(BufferedReader diffOutput,
    //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();
    return new BufferedReader(new InputStreamReader(diffOutputStream));
  }
  private void processDiffOutput(BufferedReader diffOutput,
                                        IReportDataView emmaDataView)
      throws IOException {
    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>();
@@ -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);
  }
  private static void processDiffOutputFile(ArrayList<String> diffFile,
    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 void processDiffOutputFile(HTMLDocument html,
                                            ArrayList<String> diffFile,
                                            IReportDataView emmaDataView)
      throws IOException
  {
@@ -186,51 +434,27 @@
      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));
    SrcFileItem emmaSourceItem = null;
    if(srcFilePath.isFile())
    {
    FileInputStream srcFile = new FileInputStream(srcFilePath);
    String srcFilePackage = parseJavaPackage(srcFile);
    SrcFileItem emmaSourceItem = getEmmaSrcItem(emmaDataView.getRoot(),
      if(emmaDataView != null)
      {
        emmaSourceItem = getEmmaSrcItem(emmaDataView.getRoot(),
                  srcFilePackage, srcFilePath.getName());
    if(emmaSourceItem == null)
    {
      System.out.println(fileHeader);
      System.out.println("Coverage: Not Available");
      for(int i = 1; i < diffFile.size(); i++)
      {
        System.out.println(diffFile.get(i));
      }
    }
    else
    {
      System.out.println(fileHeader);
      System.out.print("Coverage: ");
      String name;
      StringBuffer buf = new StringBuffer();
      for(int i = 1; i <= 4; 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++)
        {
          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;
@@ -238,8 +462,10 @@
      String firstFileLine = diffFile.get(2);
      String secondFileLine = diffFile.get(3);
      System.out.println(firstFileLine);
      System.out.println(secondFileLine);
    String revisionStr = "unknown";
    HTMLTable srcTable = null;
      if(firstFileLine.endsWith("(working copy)"))
      {
@@ -248,6 +474,7 @@
      else
      {
        otherCopyFlag = firstFileLine.substring(0, 1);
      revisionStr = firstFileLine.substring(firstFileLine.lastIndexOf("("));
      }
      if(secondFileLine.endsWith("(working copy)"))
@@ -257,6 +484,7 @@
      else
      {
        otherCopyFlag = secondFileLine.substring(0, 1);
      revisionStr = secondFileLine.substring(secondFileLine.lastIndexOf("("));
      }
      if(firstFileLine.endsWith("(revision 0)") &&
@@ -266,26 +494,34 @@
        otherCopyFlag = "-";
      }
      if(workingCopyFlag == null || otherCopyFlag == null ||
          srcFilePackage == null)
    if(workingCopyFlag == null || otherCopyFlag == null)
      {
        for(int i = 4; i < diffFile.size(); i++)
        {
          System.out.println(diffFile.get(i));
        }
      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++)
        {
          //Found a chunk indicator.
          if(diffFile.get(i).startsWith("@@"))
          {
            processDiffOutputFileChunk(diffOutputChunk, workingCopyFlag,
          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];
          }
            diffOutputChunk = new ArrayList<String>();
            diffOutputChunk.add(diffFile.get(i));
          }
@@ -297,14 +533,64 @@
        }
        //Finishing process whatever we have queued up
        processDiffOutputFileChunk(diffOutputChunk, workingCopyFlag,
      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");
  }
  private static void processDiffOutputFileChunk(ArrayList<String> diffChunk,
    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 Double[] processDiffOutputFileChunk(HTMLTable table,
                                                 ArrayList<String> diffChunk,
                                                 String workingCopyFlag,
                                                 String otherCopyFlag,
                                                 SrcFileItem emmaSrcItem)
@@ -312,7 +598,7 @@
    if(diffChunk.size() <= 0)
    {
      return;
      return null;
    }
    int workingCopyBegin;
@@ -320,6 +606,12 @@
    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();
      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))
        {
          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:
            System.out.println(chunkLine.charAt(0) + "N" + chunkLine.substring(1));
              lineTxtCell.setClass ("cz");
            break;
          case SrcFileItem.LineCoverageData.LINE_COVERAGE_PARTIAL:
            System.out.println(chunkLine.charAt(0) + "P" + chunkLine.substring(1));
              lineTxtCell.setClass ("cp");
              modCoverage[COVERED_MOD_EXE_LINES] += 0.5;
            break;
          case SrcFileItem.LineCoverageData.LINE_COVERAGE_COMPLETE:
            System.out.println(chunkLine.charAt(0) + "C" + chunkLine.substring(1));
              lineTxtCell.setClass ("cc");
              modCoverage[COVERED_MOD_EXE_LINES] ++;
            break;
          default:
            System.out.println(chunkLine.charAt(0) + "U" + chunkLine.substring(1));
          }
        }
      }
      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++;
    }
  }
  private static String parseJavaPackage(FileInputStream srcFile)
    return modCoverage;
  }
  private String parseJavaPackage(FileInputStream srcFile)
      throws IOException {
    BufferedReader srcFileReader = new BufferedReader(
@@ -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);
  }
}
opendj-sdk/opends/build.xml
@@ -86,6 +86,11 @@
      <property name="statuspanel.classes.dir"
                location="${build.dir}/statuspanel/classes"                />
  <!-- Properties for coverage diff reports                        -->
  <property name="cvgdiff.dir" location="build/diff"                />
  <property name="cvgdiff.report.dir"
            location="${cvgdiff.dir}/report"                        />
  <!-- Properties for code coverage testing.                            -->
  <property name="coverage.dir"         location="build/coverage"            />
  <property name="coverage.report.dir"  
@@ -727,6 +732,45 @@
    </javac>
 
    <!-- Prep the TestNG XML file -->
    <condition property="test.groups" value="exclude=slow">
      <not>
        <or>
          <isset property="test.groups" />
          <isset property="test.packages" />
          <isset property="test.classes" />
          <isset property="test.methods" />
        </or>
      </not>
    </condition>
    <condition property="test.packages" value="org.opends.server.*">
      <not>
        <or>
          <isset property="test.packages" />
          <isset property="test.classes" />
          <isset property="test.methods" />
        </or>
      </not>
    </condition>
    <condition property="test.classes" value="">
      <not>
        <or>
          <isset property="test.classes" />
          <isset property="test.methods" />
        </or>
      </not>
    </condition>
    <condition property="test.methods" value="">
      <not>
        <or>
          <isset property="test.methods" />
        </or>
      </not>
    </condition>
    <mkdir dir="${unittest.resource.dir}" />
    <typedef name="preptestng" classname="org.opends.build.tools.PrepTestNG"
        classpath="${build.dir}/build-tools/build-tools.jar" />
@@ -743,7 +787,49 @@
  </target>
  <!-- Generate coverage diff report -->
  <target name="coveragediff">
    <condition property="test.diff.srcpath" value="">
      <not>
        <isset property="test.diff.srcpath" />
      </not>
    </condition>
    <condition property="test.diff.svnpath" value="">
      <not>
        <isset property="test.diff.svnpath" />
      </not>
    </condition>
    <condition property="test.diff.enabled" value="true">
      <not>
        <isset property="test.diff.disable" />
      </not>
    </condition>
    <condition property="test.diff.enabled" value="false">
      <isset property="test.diff.disable" />
    </condition>
    <mkdir dir="${cvgdiff.report.dir}" />
    <taskdef name="coveragediff" classname="org.opends.build.tools.CoverageDiff">
      <classpath>
        <fileset dir="${build.dir}/build-tools">
          <include name="*.jar" />
        </fileset>
        <fileset dir="${emma.dir}">
          <include name="*.jar" />
        </fileset>
      </classpath>
    </taskdef>
    <coveragediff emmadatapath="${coverage.data.dir}"
                  outputpath="${cvgdiff.report.dir}"
                  diffpath="${basedir}/${test.diff.srcpath}"
                  svnpath="${test.diff.svnpath}"
                  enabled="${test.diff.enabled}" />
  </target>
  <!-- Execute the Directory Server TestNG unit tests in text mode. -->
  <target name="enableTestNGAssertions">
@@ -752,8 +838,8 @@
  <!-- Execute Directory Server TestNG unit tests specified from CLI -->
  <target name="testcustom"
          depends="testinit,runtests"
          description="Execute the Directory Server TestNG unit tests specified from CLI.">
    <echo message="This target is deprecated. Please use the test target as it now supports the test.* properties." />
  </target>
  <!-- Execute all of the Directory Server TestNG unit tests in text mode. -->
@@ -765,26 +851,26 @@
  <!-- Execute the Directory Server TestNG unit tests in text mode. -->
  <target name="test"
          depends="prepdefaulttest,testinit,runtests"
          depends="testinit,runtests"
          description="Execute the Directory Server TestNG unit tests in text mode.">
  </target>
  <!-- Execute the Directory Server TestNG unit tests in text mode with a coverage report. -->
  <target name="testwithcoverage"
          depends="coverage,test"
          depends="coverage,test,coveragediff"
          description="Execute the Directory Server TestNG unit tests in text mode with a coverage report.">
  </target>
  <!-- Execute the Directory Server TestNG unit tests in text mode with a coverage report and slow tests. -->
  <target name="testallwithcoverage"
          depends="coverage,testall"
          depends="coverage,testall,coveragediff"
          description="Execute the Directory Server TestNG unit tests in text mode with a coverage report.">
  </target>
  <!-- Execute the Directory Server TestNG unit tests specified from CLI in text mode with a coverage report. -->
  <target name="testcustomwithcoverage"
          depends="coverage,testcustom"
          description="Execute the Directory Server TestNG unit tests specified from CLI in text mode with a coverage report.">
    <echo message="This target is deprecated. Please use the testwithcoverage target as it now supports the test.* properties." />
  </target>
  <!-- Internal target to execute the Directory Server TestNG unit tests in text mode after everything has been initialized. -->
@@ -857,19 +943,8 @@
  </target>
  <!-- Internal target used to set the properties for the preptestng task -->
  <target name="prepdefaulttest">
    <property name="test.groups" value="exclude=slow" />
    <property name="test.packages" value="org.opends.server.*" />
    <property name="test.classes" value="" />
    <property name="test.methods" value="" />
  </target>
  <target name="prepdefaultalltest">
    <property name="test.groups" value="" />
    <property name="test.packages" value="org.opends.server.*" />
    <property name="test.classes" value="" />
    <property name="test.methods" value="" />
  </target>
  <target name="testreport"