1 /*******************************************************************************
2  * Copyright (c) 2009, 2015 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