package org.jvnet.hudson.plugins.fit; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import org.apache.commons.lang.StringUtils; import org.ccil.cowan.tagsoup.Parser; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; import org.xml.sax.InputSource; import org.xml.sax.Locator; import org.xml.sax.SAXException; public final class HtmlContentHandler implements ContentHandler { public static final class FitResult { private int expectationsNumber; private int errorsNumber; void addExpectation() { expectationsNumber++; } public int getExpectationsNumber() { return expectationsNumber; } void addError() { errorsNumber++; } public int getErrorsNumber() { return errorsNumber; } } private class TdAttributes { boolean yellowBackground = false; boolean containsHorizontalLine = false; boolean containsExpected = false; boolean italicsDetected = false; } private TdAttributes tdAttributes; private FitResult fitResult = new FitResult(); // private boolean italicsDetected = false; private boolean inTable = false; private boolean inItalics = false; public void characters(char[] ch, int start, int length) throws SAXException { String content = new String(ch, start, length); if (tdAttributes != null && tdAttributes.italicsDetected) { if (!tdAttributes.containsExpected) { tdAttributes.containsExpected = containsExpected(content); } if (tdAttributes.containsExpected && containsActual(content) && inItalics) { fitResult.addExpectation(); } } } private boolean containsExpected(String content) { return content.startsWith("expected"); } private boolean containsActual(String content) { return content.startsWith("actual"); } public void endDocument() throws SAXException { } public void endPrefixMapping(String prefix) throws SAXException { } public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException { } public void processingInstruction(String target, String data) throws SAXException { } public void setDocumentLocator(Locator locator) { } public void skippedEntity(String name) throws SAXException { } public void startDocument() throws SAXException { } public void startElement(String uri, String localName, String name, Attributes atts) throws SAXException { if (isElementItalics(localName)) { inItalics = true; } if (isElementTable(localName)) { inTable = true; } else if (isElementTd(localName) && inTable) { tdAttributes = new TdAttributes(); tdAttributes.yellowBackground = isBackgroundColorYellow(atts); } else if (tdAttributes != null) { if (isElementItalics(localName)) { tdAttributes.italicsDetected = true; } if (tdAttributes.yellowBackground && !tdAttributes.containsHorizontalLine) { tdAttributes.containsHorizontalLine = isElementHr(localName); if (tdAttributes.containsHorizontalLine) { fitResult.addError(); } } } } public void endElement(String uri, String localName, String name) throws SAXException { if (isElementItalics(localName)) { inItalics = false; } if (isElementTable(localName)) { inTable = false; tdAttributes = null; } else if (isElementTd(localName)) { tdAttributes = null; } } private boolean isElementHr(String localName) { return StringUtils.equalsIgnoreCase(localName, "hr"); } private boolean isBackgroundColorYellow(Attributes atts) { // the pink background For fit results is #ffcfcf return StringUtils .equalsIgnoreCase("#ffffcf", atts.getValue("bgcolor")); } private boolean isElementTd(String localName) { return StringUtils.equalsIgnoreCase(localName, "td"); } private boolean isElementItalics(String localName) { return StringUtils.equalsIgnoreCase(localName, "i"); } private boolean isElementTable(String localName) { return StringUtils.equalsIgnoreCase(localName, "table"); } public void startPrefixMapping(String prefix, String uri) throws SAXException { } protected static HtmlContentHandler.FitResult parse(String filename) throws IOException { return new HtmlContentHandler().parse(filename, null); } protected static HtmlContentHandler.FitResult parse(InputSource input) throws IOException { return new HtmlContentHandler().parse(null, input); } protected static HtmlContentHandler.FitResult parse(File file) throws IOException { FileInputStream fileInputStream = new FileInputStream(file); return parse(new InputSource(fileInputStream)); } private HtmlContentHandler.FitResult parse(String filename, InputSource inputSource) throws IOException { try { Parser parser = new Parser(); parser.setContentHandler(this); if (filename != null) { parser.parse(filename); } else { parser.parse(inputSource); } } catch (SAXException e) { throw new RuntimeException(e); } return fitResult; } }