1 /******************************************************************************* 2 * Copyright (c) 2009, 2017 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 final byte[] instrumented = instr.instrument( 117 getTargetClass(targetName), targetName); 118 119 // Now we're ready to run our instrumented class and need to startup the 120 // runtime first: 121 final RuntimeData data = new RuntimeData(); 122 runtime.startup(data); 123 124 // In this tutorial we use a special class loader to directly load the 125 // instrumented class definition from a byte[] instances. 126 final MemoryClassLoader memoryClassLoader = new MemoryClassLoader(); 127 memoryClassLoader.addDefinition(targetName, instrumented); 128 final Class<?> targetClass = memoryClassLoader.loadClass(targetName); 129 130 // Here we execute our test target class through its Runnable interface: 131 final Runnable targetInstance = (Runnable) targetClass.newInstance(); 132 targetInstance.run(); 133 134 // At the end of test execution we collect execution data and shutdown 135 // the runtime: 136 final ExecutionDataStore executionData = new ExecutionDataStore(); 137 final SessionInfoStore sessionInfos = new SessionInfoStore(); 138 data.collect(executionData, sessionInfos, false); 139 runtime.shutdown(); 140 141 // Together with the original class definition we can calculate coverage 142 // information: 143 final CoverageBuilder coverageBuilder = new CoverageBuilder(); 144 final Analyzer analyzer = new Analyzer(executionData, coverageBuilder); 145 analyzer.analyzeClass(getTargetClass(targetName), targetName); 146 147 // Let's dump some metrics and line coverage information: 148 for (final IClassCoverage cc : coverageBuilder.getClasses()) { 149 out.printf("Coverage of class %s%n", cc.getName()); 150 151 printCounter("instructions", cc.getInstructionCounter()); 152 printCounter("branches", cc.getBranchCounter()); 153 printCounter("lines", cc.getLineCounter()); 154 printCounter("methods", cc.getMethodCounter()); 155 printCounter("complexity", cc.getComplexityCounter()); 156 157 for (int i = cc.getFirstLine(); i <= cc.getLastLine(); i++) { 158 out.printf("Line %s: %s%n", Integer.valueOf(i), getColor(cc 159 .getLine(i).getStatus())); 160 } 161 } 162 } 163 getTargetClass(final String name)164 private InputStream getTargetClass(final String name) { 165 final String resource = '/' + name.replace('.', '/') + ".class"; 166 return getClass().getResourceAsStream(resource); 167 } 168 printCounter(final String unit, final ICounter counter)169 private void printCounter(final String unit, final ICounter counter) { 170 final Integer missed = Integer.valueOf(counter.getMissedCount()); 171 final Integer total = Integer.valueOf(counter.getTotalCount()); 172 out.printf("%s of %s %s missed%n", missed, total, unit); 173 } 174 getColor(final int status)175 private String getColor(final int status) { 176 switch (status) { 177 case ICounter.NOT_COVERED: 178 return "red"; 179 case ICounter.PARTLY_COVERED: 180 return "yellow"; 181 case ICounter.FULLY_COVERED: 182 return "green"; 183 } 184 return ""; 185 } 186 187 /** 188 * Entry point to run this examples as a Java application. 189 * 190 * @param args 191 * list of program arguments 192 * @throws Exception 193 * in case of errors 194 */ main(final String[] args)195 public static void main(final String[] args) throws Exception { 196 new CoreTutorial(System.out).execute(); 197 } 198 199 } 200