package org.opends.build.tools; import com.vladium.emma.*; import com.vladium.emma.report.*; import com.vladium.emma.data.*; import com.vladium.util.IntObjectMap; import java.io.*; import java.util.Iterator; import java.util.ArrayList; public class CoverageDiff { private static boolean verbose = false; public static void main(String[] args) { if(args.length < 1 || args[0] == null) { System.out.println("Please specify emma data location"); return; } IReportDataView emmaDataView = null; try { emmaDataView = loadEmmaData(new File(args[0].trim())); } catch(IOException ie) { System.out.println("An error occured while loading EMMA data: " + ie.toString()); } if(emmaDataView == null) { System.out.println(System.in); } else { try { processDiffOutput(new BufferedReader(new InputStreamReader(System.in)), emmaDataView); } catch(IOException ie) { System.out.println("An error occured while processing diff output: " + ie.toString()); } } } private static IReportDataView loadEmmaData(File emmaCoverageDataDir) throws IOException { File[] emmaCoverageDataFiles = emmaCoverageDataDir.listFiles(); int emmaCoverageDataFileCount = 0; IReportDataView m_view = null; IMetaData mdata = null; ICoverageData cdata = null; if(emmaCoverageDataFiles == null || emmaCoverageDataFiles.length <= 0) { throw new IOException("No EMMA data files found"); } if (verbose) System.out.println("processing input files ..."); final long start = verbose ? System.currentTimeMillis() : 0; // merge all data files: for (int f = 0; f < emmaCoverageDataFiles.length; ++f) { final File dataFile = emmaCoverageDataFiles[f]; if (verbose) System.out.println("processing input file [" + dataFile.getAbsolutePath() + "] ..."); final IMergeable[] fileData = DataFactory.load(dataFile); final IMetaData _mdata = (IMetaData) fileData[DataFactory.TYPE_METADATA]; if (_mdata != null) { if (verbose) System.out.println(" loaded " + _mdata.size() + " metadata entries"); if (mdata == null) mdata = _mdata; else mdata = (IMetaData) mdata.merge(_mdata); // note: later datapath entries override earlier ones } final ICoverageData _cdata = (ICoverageData) fileData[DataFactory.TYPE_COVERAGEDATA]; if (_cdata != null) { if (verbose) System.out.println(" loaded " + _cdata.size() + " coverage data entries"); if (cdata == null) cdata = _cdata; else cdata = (ICoverageData) cdata.merge(_cdata); // note: later datapath entries override earlier ones } ++emmaCoverageDataFileCount; } if (verbose) { final long end = System.currentTimeMillis(); System.out.println(emmaCoverageDataFileCount + " file(s) read and merged in " + (end - start) + " ms"); } if ((mdata == null) || mdata.isEmpty()) { System.out.println("nothing to do: no metadata found in any of the data files"); return null; } if (cdata == null) { System.out.println("nothing to do: no runtime coverage data found in any of the data files"); return null; } if (cdata.isEmpty()) { System.out.println("no collected coverage data found in any of the data files [Diff output will not include coverage data]"); return null; } if (!mdata.hasLineNumberData() || !mdata.hasSrcFileData()) { System.out.println("no collected line coverage data found in any of the data files [Diff output will not include coverage data]"); return null; } 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 (cdata != null) { System.out.println(" merged coverage data contains " + cdata.size() + " entries"); } } return m_view; } private static BufferedReader getDiffOutputReader() throws IOException { Process child = Runtime.getRuntime().exec("svn diff"); InputStream diffOutputStream = child.getInputStream(); BufferedReader diffOutput = new BufferedReader( new InputStreamReader(diffOutputStream)); return diffOutput; } private static void processDiffOutput(BufferedReader diffOutput, IReportDataView emmaDataView) throws IOException { String line = diffOutput.readLine(); ArrayList diffOutputFile = new ArrayList(); while(line != null) { //Diffed file if(line.length() >6 && line.substring(0, 6).equals("Index:")) { processDiffOutputFile(diffOutputFile, emmaDataView); diffOutputFile = new ArrayList(); diffOutputFile.add(line); } else { diffOutputFile.add(line); } line = diffOutput.readLine(); } processDiffOutputFile(diffOutputFile, emmaDataView); } private static void processDiffOutputFile(ArrayList diffFile, IReportDataView emmaDataView) throws IOException { if(diffFile.size() <= 0) { return; } String fileHeader = diffFile.get(0); 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) { 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; 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 diffOutputChunk = new ArrayList(); for(int i = 4; i < diffFile.size(); i++) { //Found a chunk indicator. if(diffFile.get(i).startsWith("@@")) { processDiffOutputFileChunk(diffOutputChunk, workingCopyFlag, otherCopyFlag, emmaSourceItem); diffOutputChunk = new ArrayList(); 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); } } } private static void processDiffOutputFileChunk(ArrayList diffChunk, String workingCopyFlag, String otherCopyFlag, SrcFileItem emmaSrcItem) { if(diffChunk.size() <= 0) { return; } int workingCopyBegin; int workingCopyRange; int otherCopyBegin; int otherCopyRange; IntObjectMap lineCoverageMap = null; if(emmaSrcItem != null) { lineCoverageMap = emmaSrcItem.getLineCoverage (); } String chunkHeader = diffChunk.get(0); System.out.println(chunkHeader); int workingCopyBeginIdx = chunkHeader.indexOf(workingCopyFlag); int workingCopyCommaIdx = chunkHeader.indexOf(",", workingCopyBeginIdx); int workingCopyEndIdx = chunkHeader.indexOf(" ", workingCopyCommaIdx); int otherCopyBeginIdx = chunkHeader.indexOf(otherCopyFlag); int otherCopyCommaIdx = chunkHeader.indexOf(",", otherCopyBeginIdx); int otherCopyEndIdx = chunkHeader.indexOf(" ", otherCopyCommaIdx); workingCopyBegin = Integer.parseInt( chunkHeader.substring(workingCopyBeginIdx + 1, workingCopyCommaIdx)); workingCopyRange = Integer.parseInt( chunkHeader.substring(workingCopyCommaIdx + 1, workingCopyEndIdx)); otherCopyBegin = Integer.parseInt( chunkHeader.substring(otherCopyBeginIdx + 1, otherCopyCommaIdx)); otherCopyRange = Integer.parseInt( chunkHeader.substring(otherCopyCommaIdx + 1, otherCopyEndIdx)); String chunkLine; SrcFileItem.LineCoverageData lCoverageData = null; int workingCopyLineIncrement = 0; int otherCopyLineIncrement = 0; 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); } if(!chunkLine.startsWith(otherCopyFlag) && lCoverageData != null) { switch(lCoverageData.m_coverageStatus) { 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)); } } else { System.out.println(chunkLine.charAt(0) + " " + chunkLine.substring(1)); } if(!chunkLine.startsWith(otherCopyFlag)) { workingCopyLineIncrement++; } if(!chunkLine.startsWith(workingCopyFlag)) { otherCopyLineIncrement++; } } } private static String parseJavaPackage(FileInputStream srcFile) throws IOException { BufferedReader srcFileReader = new BufferedReader( new InputStreamReader(srcFile)); String line = srcFileReader.readLine(); while(line != null) { int beginIdx = line.indexOf("package"); if(beginIdx > -1) { int endIdx = line.indexOf(";", beginIdx); if(endIdx > -1) { return line.substring(beginIdx + 7, endIdx).trim(); } } line = srcFileReader.readLine(); } return null; } private static SrcFileItem getEmmaSrcItem(IItem rootItem, String srcPackageName, String srcFileName) { for(Iterator packages = rootItem.getChildren(); packages.hasNext();) { IItem packageItem = (IItem)packages.next(); if(packageItem.getName().equals(srcPackageName)) { for(Iterator sources = packageItem.getChildren(); sources.hasNext();) { SrcFileItem sourceItem = (SrcFileItem)sources.next(); if(sourceItem.getName().equals(srcFileName)) { return sourceItem; } } } } return null; } }