package org.python.pydev.debug.codecoverage; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.util.TreeSet; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.python.pydev.core.log.Log; import org.python.pydev.shared_core.io.FileUtils; import org.python.pydev.shared_core.string.FastStringBuffer; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; public class CoverageXmlInfo { public static final SAXParserFactory parserFactory = SAXParserFactory.newInstance(); public static SAXParser getSAXParser() { SAXParser parser = null; try { synchronized (parserFactory) { parser = parserFactory.newSAXParser(); } } catch (Exception e) { throw new RuntimeException(e); } return parser; } public static class FillCacheFromXmlHandler extends DefaultHandler { private CoverageCache cache; private File file; private int stmts = 0; private int miss = 0; private TreeSet<Integer> missedLines = new TreeSet<>(); public FillCacheFromXmlHandler(CoverageCache cache) { this.cache = cache; } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if (qName.equals("class")) { String filename = attributes.getValue("filename"); file = new File(filename); stmts = 0; miss = 0; missedLines.clear(); } else if (qName.equals("line")) { try { int lineNum = Integer.parseInt(attributes.getValue("number")); stmts += 1; String hits = attributes.getValue("hits"); if ("0".equals(hits)) { miss += 1; missedLines.add(lineNum); } } catch (Exception e) { Log.log(e); return; } } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { if (qName.equals("class")) { cache.addFile(file, file.getParentFile(), stmts, miss, calculateMissingBuf(missedLines)); file = null; stmts = 0; miss = 0; missedLines.clear(); } } public static String calculateMissingBuf(TreeSet<Integer> missedLines) { int last = -1; int gapStart = -1; FastStringBuffer missingBuf = new FastStringBuffer(); for (Integer missedLine : missedLines) { if (last == -1) { last = gapStart = missedLine; } else { if (missedLine == last + 1) { last = missedLine; } else { if (missingBuf.length() > 0) { missingBuf.append(", "); } if (gapStart == last) { missingBuf.append(last); } else { missingBuf.append(gapStart); missingBuf.append('-'); missingBuf.append(last); } last = gapStart = missedLine; } } } if (last != -1) { if (missingBuf.length() > 0) { missingBuf.append(", "); } if (gapStart == last) { missingBuf.append(last); } else { missingBuf.append(gapStart); missingBuf.append('-'); missingBuf.append(last); } } return missingBuf.toString(); } } public static void analyze(CoverageCache cache, File coverageXmlLocation) throws SAXException, IOException { String fileContents = FileUtils.getFileContents(coverageXmlLocation); SAXParser parser = getSAXParser(); parser.parse(new ByteArrayInputStream(fileContents.getBytes()), new FillCacheFromXmlHandler(cache)); } }