Home | History | Annotate | Download | only in validation
      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