• 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.core.test.validation;
14 
15 import static org.junit.Assert.assertEquals;
16 import static org.junit.Assert.assertTrue;
17 
18 import java.io.IOException;
19 import java.lang.reflect.Method;
20 import java.util.Arrays;
21 
22 import org.jacoco.core.analysis.Analyzer;
23 import org.jacoco.core.analysis.CoverageBuilder;
24 import org.jacoco.core.analysis.ICounter;
25 import org.jacoco.core.analysis.ILine;
26 import org.jacoco.core.data.ExecutionData;
27 import org.jacoco.core.data.ExecutionDataStore;
28 import org.jacoco.core.internal.analysis.CounterImpl;
29 import org.jacoco.core.test.InstrumentingLoader;
30 import org.jacoco.core.test.TargetLoader;
31 import org.jacoco.core.test.validation.Source.Line;
32 import org.jacoco.core.test.validation.targets.Stubs;
33 import org.junit.Before;
34 import org.junit.Test;
35 
36 /**
37  * Base class for validation tests. It executes the given class under code
38  * coverage and provides the coverage results for validation.
39  */
40 public abstract class ValidationTestBase {
41 
42 	protected static final boolean isJDKCompiler = Compiler.DETECT.isJDK();
43 
44 	protected static final JavaVersion JAVA_VERSION = new JavaVersion(
45 			System.getProperty("java.version"));
46 
47 	private static final String[] STATUS_NAME = new String[4];
48 
49 	{
50 		STATUS_NAME[ICounter.EMPTY] = "EMPTY";
51 		STATUS_NAME[ICounter.NOT_COVERED] = "NOT_COVERED";
52 		STATUS_NAME[ICounter.FULLY_COVERED] = "FULLY_COVERED";
53 		STATUS_NAME[ICounter.PARTLY_COVERED] = "PARTLY_COVERED";
54 	}
55 
56 	private final Class<?> target;
57 
58 	private Source source;
59 
60 	private InstrumentingLoader loader;
61 
ValidationTestBase(final Class<?> target)62 	protected ValidationTestBase(final Class<?> target) {
63 		this.target = target;
64 	}
65 
66 	@Before
setup()67 	public void setup() throws Exception {
68 		final ExecutionDataStore store = execute();
69 		analyze(store);
70 	}
71 
execute()72 	private ExecutionDataStore execute() throws Exception {
73 		loader = new InstrumentingLoader(target);
74 		run(loader.loadClass(target.getName()));
75 		return loader.collect();
76 	}
77 
run(final Class<?> targetClass)78 	protected void run(final Class<?> targetClass) throws Exception {
79 		targetClass.getMethod("main", String[].class).invoke(null,
80 				(Object) new String[0]);
81 	}
82 
analyze(final ExecutionDataStore store)83 	private void analyze(final ExecutionDataStore store) throws IOException {
84 		final CoverageBuilder builder = new CoverageBuilder();
85 		final Analyzer analyzer = new Analyzer(store, builder);
86 		for (ExecutionData data : store.getContents()) {
87 			analyze(analyzer, data);
88 		}
89 		source = Source.load(target, builder.getBundle("Test"));
90 	}
91 
analyze(final Analyzer analyzer, final ExecutionData data)92 	private void analyze(final Analyzer analyzer, final ExecutionData data)
93 			throws IOException {
94 		final byte[] bytes = TargetLoader
95 				.getClassDataAsBytes(target.getClassLoader(), data.getName());
96 		analyzer.analyzeClass(bytes, data.getName());
97 	}
98 
99 	/**
100 	 * All single line comments are interpreted as statements in the following
101 	 * format:
102 	 *
103 	 * <pre>
104 	 * // statement1() statement2()
105 	 * </pre>
106 	 */
107 	@Test
execute_assertions_in_comments()108 	public void execute_assertions_in_comments() throws IOException {
109 		for (Line line : source.getLines()) {
110 			String exec = line.getComment();
111 			if (exec != null) {
112 				StatementParser.parse(exec, new StatementExecutor(this, line),
113 						line.toString());
114 			}
115 		}
116 	}
117 
118 	@Test
last_line_in_coverage_data_should_be_less_or_equal_to_number_of_lines_in_source_file()119 	public void last_line_in_coverage_data_should_be_less_or_equal_to_number_of_lines_in_source_file() {
120 		assertTrue(String.format(
121 				"Last line in coverage data (%d) should be less or equal to number of lines in source file (%d)",
122 				Integer.valueOf(source.getCoverage().getLastLine()),
123 				Integer.valueOf(source.getLines().size())),
124 				source.getCoverage().getLastLine() <= source.getLines().size());
125 	}
126 
127 	@Test
all_missed_instructions_should_have_line_number()128 	public void all_missed_instructions_should_have_line_number() {
129 		CounterImpl c = CounterImpl.COUNTER_0_0;
130 		for (Line line : source.getLines()) {
131 			c = c.increment(line.getCoverage().getInstructionCounter());
132 		}
133 		assertEquals(
134 				"sum of missed instructions of all lines should be equal to missed instructions of file",
135 				source.getCoverage().getInstructionCounter().getMissedCount(),
136 				c.getMissedCount());
137 	}
138 
139 	@Test
all_branches_should_have_line_number()140 	public void all_branches_should_have_line_number() {
141 		CounterImpl c = CounterImpl.COUNTER_0_0;
142 		for (Line line : source.getLines()) {
143 			c = c.increment(line.getCoverage().getBranchCounter());
144 		}
145 		assertEquals(
146 				"sum of branch counters of all lines should be equal to branch counter of file",
147 				source.getCoverage().getBranchCounter(), c);
148 	}
149 
150 	/*
151 	 * Predefined assertion methods:
152 	 */
153 
assertCoverage(final Line line, final int insnStatus, final int missedBranches, final int coveredBranches)154 	private void assertCoverage(final Line line, final int insnStatus,
155 			final int missedBranches, final int coveredBranches) {
156 		final ILine coverage = line.getCoverage();
157 
158 		String msg = String.format("Instructions (%s)", line);
159 		final int actualStatus = coverage.getInstructionCounter().getStatus();
160 		assertEquals(msg, STATUS_NAME[insnStatus], STATUS_NAME[actualStatus]);
161 
162 		msg = String.format("Branches (%s)", line);
163 		assertEquals(msg,
164 				CounterImpl.getInstance(missedBranches, coveredBranches),
165 				coverage.getBranchCounter());
166 	}
167 
assertFullyCovered(final Line line, final int missedBranches, final int coveredBranches)168 	public void assertFullyCovered(final Line line, final int missedBranches,
169 			final int coveredBranches) {
170 		assertCoverage(line, ICounter.FULLY_COVERED, missedBranches,
171 				coveredBranches);
172 	}
173 
assertFullyCovered(final Line line)174 	public void assertFullyCovered(final Line line) {
175 		assertFullyCovered(line, 0, 0);
176 	}
177 
assertPartlyCovered(final Line line, final int missedBranches, final int coveredBranches)178 	public void assertPartlyCovered(final Line line, final int missedBranches,
179 			final int coveredBranches) {
180 		assertCoverage(line, ICounter.PARTLY_COVERED, missedBranches,
181 				coveredBranches);
182 	}
183 
assertPartlyCovered(final Line line)184 	public void assertPartlyCovered(final Line line) {
185 		assertPartlyCovered(line, 0, 0);
186 	}
187 
assertNotCovered(final Line line, final int missedBranches, final int coveredBranches)188 	public void assertNotCovered(final Line line, final int missedBranches,
189 			final int coveredBranches) {
190 		assertCoverage(line, ICounter.NOT_COVERED, missedBranches,
191 				coveredBranches);
192 	}
193 
assertNotCovered(final Line line)194 	public void assertNotCovered(final Line line) {
195 		assertNotCovered(line, 0, 0);
196 	}
197 
assertEmpty(final Line line)198 	public void assertEmpty(final Line line) {
199 		assertCoverage(line, ICounter.EMPTY, 0, 0);
200 	}
201 
assertLogEvents(String... events)202 	protected void assertLogEvents(String... events) throws Exception {
203 		final Method getter = Class
204 				.forName(Stubs.class.getName(), false, loader)
205 				.getMethod("getLogEvents");
206 		assertEquals("Log events", Arrays.asList(events), getter.invoke(null));
207 	}
208 
assertMethodCount(final int expectedTotal)209 	protected void assertMethodCount(final int expectedTotal) {
210 		assertEquals(expectedTotal,
211 				source.getCoverage().getMethodCounter().getTotalCount());
212 	}
213 
214 }
215