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.core.test.validation; 13 14 import static org.junit.Assert.assertEquals; 15 import static org.junit.Assert.fail; 16 17 import java.io.IOException; 18 import java.lang.reflect.Method; 19 import java.util.Arrays; 20 21 import org.jacoco.core.analysis.Analyzer; 22 import org.jacoco.core.analysis.CoverageBuilder; 23 import org.jacoco.core.analysis.ICounter; 24 import org.jacoco.core.analysis.ILine; 25 import org.jacoco.core.analysis.ISourceFileCoverage; 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.targets.Stubs; 32 import org.junit.Before; 33 34 /** 35 * Base class for validation tests. It executes the given class under code 36 * coverage and provides the coverage results for validation. 37 */ 38 public abstract class ValidationTestBase { 39 40 protected static final boolean isJDKCompiler = Compiler.DETECT.isJDK(); 41 42 private static final String[] STATUS_NAME = new String[4]; 43 44 { 45 STATUS_NAME[ICounter.EMPTY] = "EMPTY"; 46 STATUS_NAME[ICounter.NOT_COVERED] = "NOT_COVERED"; 47 STATUS_NAME[ICounter.FULLY_COVERED] = "FULLY_COVERED"; 48 STATUS_NAME[ICounter.PARTLY_COVERED] = "PARTLY_COVERED"; 49 } 50 51 private final String srcFolder; 52 53 private final Class<?> target; 54 55 private ISourceFileCoverage sourceCoverage; 56 57 private Source source; 58 59 private InstrumentingLoader loader; 60 61 protected ValidationTestBase(final String srcFolder, final Class<?> target) { 62 this.srcFolder = srcFolder; 63 this.target = target; 64 } 65 66 protected ValidationTestBase(final Class<?> target) { 67 this("src", target); 68 } 69 70 @Before 71 public void setup() throws Exception { 72 final ExecutionDataStore store = execute(); 73 analyze(store); 74 source = Source.getSourceFor(srcFolder, target); 75 } 76 77 private ExecutionDataStore execute() throws Exception { 78 loader = new InstrumentingLoader(target); 79 run(loader.loadClass(target.getName())); 80 return loader.collect(); 81 } 82 83 protected void run(final Class<?> targetClass) throws Exception { 84 targetClass.getMethod("main", String[].class).invoke(null, 85 (Object) new String[0]); 86 } 87 88 private void analyze(final ExecutionDataStore store) throws IOException { 89 final CoverageBuilder builder = new CoverageBuilder(); 90 final Analyzer analyzer = new Analyzer(store, builder); 91 for (ExecutionData data : store.getContents()) { 92 analyze(analyzer, data); 93 } 94 95 String srcName = target.getName().replace('.', '/') + ".java"; 96 for (ISourceFileCoverage file : builder.getSourceFiles()) { 97 if (srcName.equals(file.getPackageName() + "/" + file.getName())) { 98 sourceCoverage = file; 99 return; 100 } 101 } 102 fail("No source node found for " + srcName); 103 } 104 105 private void analyze(final Analyzer analyzer, final ExecutionData data) 106 throws IOException { 107 final byte[] bytes = TargetLoader.getClassDataAsBytes( 108 target.getClassLoader(), data.getName()); 109 analyzer.analyzeClass(bytes, data.getName()); 110 } 111 112 protected void assertMethodCount(final int expectedTotal) { 113 assertEquals(expectedTotal, 114 sourceCoverage.getMethodCounter().getTotalCount()); 115 } 116 117 protected void assertLine(final String tag, final int status) { 118 final int nr = source.getLineNumber(tag); 119 final ILine line = sourceCoverage.getLine(nr); 120 final String msg = String.format("Status in line %s: %s", 121 Integer.valueOf(nr), source.getLine(nr)); 122 final int insnStatus = line.getInstructionCounter().getStatus(); 123 assertEquals(msg, STATUS_NAME[status], STATUS_NAME[insnStatus]); 124 } 125 126 protected void assertLine(final String tag, final int status, 127 final int missedBranches, final int coveredBranches) { 128 assertLine(tag, status); 129 final int nr = source.getLineNumber(tag); 130 final ILine line = sourceCoverage.getLine(nr); 131 final String msg = String.format("Branches in line %s: %s", 132 Integer.valueOf(nr), source.getLine(nr)); 133 assertEquals(msg + " branches", 134 CounterImpl.getInstance(missedBranches, coveredBranches), 135 line.getBranchCounter()); 136 } 137 138 protected void assertLogEvents(String... events) throws Exception { 139 final Method getter = Class.forName(Stubs.class.getName(), false, 140 loader).getMethod("getLogEvents"); 141 assertEquals("Log events", Arrays.asList(events), getter.invoke(null)); 142 } 143 144 } 145