1 /******************************************************************************* 2 * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors 3 * All rights reserved. This program and the accompanying materials 4 * are made available under the terms of the Eclipse Public License v1.0 5 * which accompanies this distribution, and is available at 6 * http://www.eclipse.org/legal/epl-v10.html 7 * 8 * Contributors: 9 * Marc R. Hoffmann - initial API and implementation 10 * 11 *******************************************************************************/ 12 package org.jacoco.examples; 13 14 import java.io.InputStream; 15 import java.io.PrintStream; 16 import java.util.HashMap; 17 import java.util.Map; 18 19 import org.jacoco.core.analysis.Analyzer; 20 import org.jacoco.core.analysis.CoverageBuilder; 21 import org.jacoco.core.analysis.IClassCoverage; 22 import org.jacoco.core.analysis.ICounter; 23 import org.jacoco.core.data.ExecutionDataStore; 24 import org.jacoco.core.data.SessionInfoStore; 25 import org.jacoco.core.instr.Instrumenter; 26 import org.jacoco.core.runtime.IRuntime; 27 import org.jacoco.core.runtime.LoggerRuntime; 28 import org.jacoco.core.runtime.RuntimeData; 29 30 /** 31 * Example usage of the JaCoCo core API. In this tutorial a single target class 32 * will be instrumented and executed. Finally the coverage information will be 33 * dumped. 34 */ 35 public final class CoreTutorial { 36 37 /** 38 * The test target we want to see code coverage for. 39 */ 40 public static class TestTarget implements Runnable { 41 run()42 public void run() { 43 isPrime(7); 44 } 45 isPrime(final int n)46 private boolean isPrime(final int n) { 47 for (int i = 2; i * i <= n; i++) { 48 if ((n ^ i) == 0) { 49 return false; 50 } 51 } 52 return true; 53 } 54 55 } 56 57 /** 58 * A class loader that loads classes from in-memory data. 59 */ 60 public static class MemoryClassLoader extends ClassLoader { 61 62 private final Map<String, byte[]> definitions = new HashMap<String, byte[]>(); 63 64 /** 65 * Add a in-memory representation of a class. 66 * 67 * @param name 68 * name of the class 69 * @param bytes 70 * class definition 71 */ addDefinition(final String name, final byte[] bytes)72 public void addDefinition(final String name, final byte[] bytes) { 73 definitions.put(name, bytes); 74 } 75 76 @Override loadClass(final String name, final boolean resolve)77 protected Class<?> loadClass(final String name, final boolean resolve) 78 throws ClassNotFoundException { 79 final byte[] bytes = definitions.get(name); 80 if (bytes != null) { 81 return defineClass(name, bytes, 0, bytes.length); 82 } 83 return super.loadClass(name, resolve); 84 } 85 86 } 87 88 private final PrintStream out; 89 90 /** 91 * Creates a new example instance printing to the given stream. 92 * 93 * @param out 94 * stream for outputs 95 */ CoreTutorial(final PrintStream out)96 public CoreTutorial(final PrintStream out) { 97 this.out = out; 98 } 99 100 /** 101 * Run this example. 102 * 103 * @throws Exception 104 * in case of errors 105 */ execute()106 public void execute() throws Exception { 107 final String targetName = TestTarget.class.getName(); 108 109 // For instrumentation and runtime we need a IRuntime instance 110 // to collect execution data: 111 final IRuntime runtime = new LoggerRuntime(); 112 113 // The Instrumenter creates a modified version of our test target class 114 // that contains additional probes for execution data recording: 115 final Instrumenter instr = new Instrumenter(runtime); 116 InputStream original = getTargetClass(targetName); 117 final byte[] instrumented = instr.instrument(original, targetName); 118 original.close(); 119 120 // Now we're ready to run our instrumented class and need to startup the 121 // runtime first: 122 final RuntimeData data = new RuntimeData(); 123 runtime.startup(data); 124 125 // In this tutorial we use a special class loader to directly load the 126 // instrumented class definition from a byte[] instances. 127 final MemoryClassLoader memoryClassLoader = new MemoryClassLoader(); 128 memoryClassLoader.addDefinition(targetName, instrumented); 129 final Class<?> targetClass = memoryClassLoader.loadClass(targetName); 130 131 // Here we execute our test target class through its Runnable interface: 132 final Runnable targetInstance = (Runnable) targetClass.newInstance(); 133 targetInstance.run(); 134 135 // At the end of test execution we collect execution data and shutdown 136 // the runtime: 137 final ExecutionDataStore executionData = new ExecutionDataStore(); 138 final SessionInfoStore sessionInfos = new SessionInfoStore(); 139 data.collect(executionData, sessionInfos, false); 140 runtime.shutdown(); 141 142 // Together with the original class definition we can calculate coverage 143 // information: 144 final CoverageBuilder coverageBuilder = new CoverageBuilder(); 145 final Analyzer analyzer = new Analyzer(executionData, coverageBuilder); 146 original = getTargetClass(targetName); 147 analyzer.analyzeClass(original, targetName); 148 original.close(); 149 150 // Let's dump some metrics and line coverage information: 151 for (final IClassCoverage cc : coverageBuilder.getClasses()) { 152 out.printf("Coverage of class %s%n", cc.getName()); 153 154 printCounter("instructions", cc.getInstructionCounter()); 155 printCounter("branches", cc.getBranchCounter()); 156 printCounter("lines", cc.getLineCounter()); 157 printCounter("methods", cc.getMethodCounter()); 158 printCounter("complexity", cc.getComplexityCounter()); 159 160 for (int i = cc.getFirstLine(); i <= cc.getLastLine(); i++) { 161 out.printf("Line %s: %s%n", Integer.valueOf(i), 162 getColor(cc.getLine(i).getStatus())); 163 } 164 } 165 } 166 getTargetClass(final String name)167 private InputStream getTargetClass(final String name) { 168 final String resource = '/' + name.replace('.', '/') + ".class"; 169 return getClass().getResourceAsStream(resource); 170 } 171 printCounter(final String unit, final ICounter counter)172 private void printCounter(final String unit, final ICounter counter) { 173 final Integer missed = Integer.valueOf(counter.getMissedCount()); 174 final Integer total = Integer.valueOf(counter.getTotalCount()); 175 out.printf("%s of %s %s missed%n", missed, total, unit); 176 } 177 getColor(final int status)178 private String getColor(final int status) { 179 switch (status) { 180 case ICounter.NOT_COVERED: 181 return "red"; 182 case ICounter.PARTLY_COVERED: 183 return "yellow"; 184 case ICounter.FULLY_COVERED: 185 return "green"; 186 } 187 return ""; 188 } 189 190 /** 191 * Entry point to run this examples as a Java application. 192 * 193 * @param args 194 * list of program arguments 195 * @throws Exception 196 * in case of errors 197 */ main(final String[] args)198 public static void main(final String[] args) throws Exception { 199 new CoreTutorial(System.out).execute(); 200 } 201 202 } 203