import java.nio.file.Path; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Element; /** Exact module-wide line gate; consumes JaCoCo XML without rounding percentages. */ public class Coverage { public static void main(String[] args) throws Exception { final var factory = DocumentBuilderFactory.newInstance(); factory.setFeature("http://xml.org/sax/features/external-general-entities", false); factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); final Element report = factory.newDocumentBuilder().parse(Path.of(args[0]).toFile()).getDocumentElement(); for (var child = report.getFirstChild(); child != null; child = child.getNextSibling()) { if (child instanceof Element counter && counter.getTagName().equals("counter") && counter.getAttribute("type").equals("LINE")) { final long covered = Long.parseLong(counter.getAttribute("covered")); final long missed = Long.parseLong(counter.getAttribute("missed")); final long total = covered + missed; System.out.println( "Backend line coverage: " + covered + "/" + total + " (" + 100.0 * covered / total + "%)"); if (total == 0 || 5 * covered < 4 * total) throw new IllegalStateException("Backend line coverage must reach 80%: " + args[0]); return; } } throw new IllegalStateException("Missing module LINE counter: " + args[0]); } }