• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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