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