/******************************************************************************* * Copyright (c) 2009, 2017 Mountainminds GmbH & Co. KG and Contributors * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Marc R. Hoffmann - initial API and implementation * *******************************************************************************/ package org.jacoco.examples; import java.io.InputStream; import java.io.PrintStream; import java.util.HashMap; import java.util.Map; import org.jacoco.core.analysis.Analyzer; import org.jacoco.core.analysis.CoverageBuilder; import org.jacoco.core.analysis.IClassCoverage; import org.jacoco.core.analysis.ICounter; import org.jacoco.core.data.ExecutionDataStore; import org.jacoco.core.data.SessionInfoStore; import org.jacoco.core.instr.Instrumenter; import org.jacoco.core.runtime.IRuntime; import org.jacoco.core.runtime.LoggerRuntime; import org.jacoco.core.runtime.RuntimeData; /** * Example usage of the JaCoCo core API. In this tutorial a single target class * will be instrumented and executed. Finally the coverage information will be * dumped. */ public final class CoreTutorial { /** * The test target we want to see code coverage for. */ public static class TestTarget implements Runnable { public void run() { isPrime(7); } private boolean isPrime(final int n) { for (int i = 2; i * i <= n; i++) { if ((n ^ i) == 0) { return false; } } return true; } } /** * A class loader that loads classes from in-memory data. */ public static class MemoryClassLoader extends ClassLoader { private final Map<String, byte[]> definitions = new HashMap<String, byte[]>(); /** * Add a in-memory representation of a class. * * @param name * name of the class * @param bytes * class definition */ public void addDefinition(final String name, final byte[] bytes) { definitions.put(name, bytes); } @Override protected Class<?> loadClass(final String name, final boolean resolve) throws ClassNotFoundException { final byte[] bytes = definitions.get(name); if (bytes != null) { return defineClass(name, bytes, 0, bytes.length); } return super.loadClass(name, resolve); } } private final PrintStream out; /** * Creates a new example instance printing to the given stream. * * @param out * stream for outputs */ public CoreTutorial(final PrintStream out) { this.out = out; } /** * Run this example. * * @throws Exception * in case of errors */ public void execute() throws Exception { final String targetName = TestTarget.class.getName(); // For instrumentation and runtime we need a IRuntime instance // to collect execution data: final IRuntime runtime = new LoggerRuntime(); // The Instrumenter creates a modified version of our test target class // that contains additional probes for execution data recording: final Instrumenter instr = new Instrumenter(runtime); final byte[] instrumented = instr.instrument( getTargetClass(targetName), targetName); // Now we're ready to run our instrumented class and need to startup the // runtime first: final RuntimeData data = new RuntimeData(); runtime.startup(data); // In this tutorial we use a special class loader to directly load the // instrumented class definition from a byte[] instances. final MemoryClassLoader memoryClassLoader = new MemoryClassLoader(); memoryClassLoader.addDefinition(targetName, instrumented); final Class<?> targetClass = memoryClassLoader.loadClass(targetName); // Here we execute our test target class through its Runnable interface: final Runnable targetInstance = (Runnable) targetClass.newInstance(); targetInstance.run(); // At the end of test execution we collect execution data and shutdown // the runtime: final ExecutionDataStore executionData = new ExecutionDataStore(); final SessionInfoStore sessionInfos = new SessionInfoStore(); data.collect(executionData, sessionInfos, false); runtime.shutdown(); // Together with the original class definition we can calculate coverage // information: final CoverageBuilder coverageBuilder = new CoverageBuilder(); final Analyzer analyzer = new Analyzer(executionData, coverageBuilder); analyzer.analyzeClass(getTargetClass(targetName), targetName); // Let's dump some metrics and line coverage information: for (final IClassCoverage cc : coverageBuilder.getClasses()) { out.printf("Coverage of class %s%n", cc.getName()); printCounter("instructions", cc.getInstructionCounter()); printCounter("branches", cc.getBranchCounter()); printCounter("lines", cc.getLineCounter()); printCounter("methods", cc.getMethodCounter()); printCounter("complexity", cc.getComplexityCounter()); for (int i = cc.getFirstLine(); i <= cc.getLastLine(); i++) { out.printf("Line %s: %s%n", Integer.valueOf(i), getColor(cc .getLine(i).getStatus())); } } } private InputStream getTargetClass(final String name) { final String resource = '/' + name.replace('.', '/') + ".class"; return getClass().getResourceAsStream(resource); } private void printCounter(final String unit, final ICounter counter) { final Integer missed = Integer.valueOf(counter.getMissedCount()); final Integer total = Integer.valueOf(counter.getTotalCount()); out.printf("%s of %s %s missed%n", missed, total, unit); } private String getColor(final int status) { switch (status) { case ICounter.NOT_COVERED: return "red"; case ICounter.PARTLY_COVERED: return "yellow"; case ICounter.FULLY_COVERED: return "green"; } return ""; } /** * Entry point to run this examples as a Java application. * * @param args * list of program arguments * @throws Exception * in case of errors */ public static void main(final String[] args) throws Exception { new CoreTutorial(System.out).execute(); } }