All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.teamscale.report.testwise.jacoco.CachingExecutionDataReader Maven / Gradle / Ivy

There is a newer version: 34.2.0
Show newest version
package com.teamscale.report.testwise.jacoco;

import com.teamscale.report.EDuplicateClassFileBehavior;
import com.teamscale.report.jacoco.dump.Dump;
import com.teamscale.report.testwise.jacoco.cache.AnalyzerCache;
import com.teamscale.report.testwise.jacoco.cache.CoverageGenerationException;
import com.teamscale.report.testwise.jacoco.cache.ProbesCache;
import com.teamscale.report.testwise.model.builder.TestCoverageBuilder;
import com.teamscale.report.util.ClasspathWildcardIncludeFilter;
import com.teamscale.report.util.ILogger;
import org.jacoco.core.data.ExecutionData;
import org.jacoco.core.data.ExecutionDataStore;

import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * Helper class for analyzing class files, reading execution data and converting them to coverage data.
 */
class CachingExecutionDataReader {

	private final ILogger logger;
	private final Collection classesDirectories;
	private final ClasspathWildcardIncludeFilter locationIncludeFilter;
	private final EDuplicateClassFileBehavior duplicateClassFileBehavior;
	private ProbesCache probesCache;

	public CachingExecutionDataReader(ILogger logger, Collection classesDirectories,
									  ClasspathWildcardIncludeFilter locationIncludeFilter,
									  EDuplicateClassFileBehavior duplicateClassFileBehavior) {
		this.logger = logger;
		this.classesDirectories = classesDirectories;
		this.locationIncludeFilter = locationIncludeFilter;
		this.duplicateClassFileBehavior = duplicateClassFileBehavior;
	}

	/**
	 * Analyzes the class/jar/war/... files and creates a lookup of which probes belong to which method.
	 */
	public void analyzeClassDirs() {
		if (probesCache == null) {
			probesCache = new ProbesCache(logger, duplicateClassFileBehavior);
		}
		if (classesDirectories.isEmpty()) {
			logger.warn("No class directories found for caching.");
			return;
		}
		AnalyzerCache analyzer = new AnalyzerCache(probesCache, locationIncludeFilter, logger);
		int classCount = 0;
		for (File classDir : classesDirectories) {
			if (classDir.exists()) {
				try {
					classCount += analyzer.analyzeAll(classDir);
				} catch (IOException e) {
					logger.error("Failed to analyze class files in " + classDir + "! " +
							"Maybe the folder contains incompatible class files. " +
							"Coverage for class files in this folder will be ignored.", e);
				}
			}
		}
		if (classCount == 0) {
			String directoryList = classesDirectories.stream().map(File::getPath).collect(Collectors.joining(","));
			logger.error("No class files found in the given directories! " + directoryList);
		} else if (probesCache.isEmpty()) {
			String directoryList = classesDirectories.stream().map(File::getPath).collect(Collectors.joining(","));
			logger.error(
					"None of the " + classCount + " class files found in the given directories match the configured include/exclude patterns! " + directoryList);
		}
	}

	/**
	 * Converts the given store to coverage data. The coverage will only contain line range coverage information.
	 */
	public DumpConsumer buildCoverageConsumer(ClasspathWildcardIncludeFilter locationIncludeFilter,
											  Consumer nextConsumer) {
		return new DumpConsumer(logger, locationIncludeFilter, nextConsumer);
	}

	/**
	 * Consumer of {@link Dump} objects. Converts them to {@link TestCoverageBuilder} and passes them to the
	 * nextConsumer.
	 */
	public class DumpConsumer implements Consumer {

		/** The logger. */
		private final ILogger logger;

		/** The location include filter to be applied on the profiled classes. */
		private final ClasspathWildcardIncludeFilter locationIncludeFilter;

		/** Consumer that should be called with the newly built TestCoverageBuilder. */
		private final Consumer nextConsumer;

		private DumpConsumer(ILogger logger, ClasspathWildcardIncludeFilter locationIncludeFilter,
							 Consumer nextConsumer) {
			this.logger = logger;
			this.locationIncludeFilter = locationIncludeFilter;
			this.nextConsumer = nextConsumer;
		}

		@Override
		public void accept(Dump dump) {
			String testId = dump.info.getId();
			if (testId.isEmpty()) {
				// Ignore intermediate coverage that does not belong to any specific test
				logger.debug("Found a session with empty name! This could indicate that coverage is dumped also for " +
						"coverage in between tests or that the given test name was empty!");
				return;
			}
			try {
				TestCoverageBuilder testCoverage = buildCoverage(testId, dump.store, locationIncludeFilter);
				nextConsumer.accept(testCoverage);
			} catch (CoverageGenerationException e) {
				logger.error("Failed to generate coverage for test " + testId + "! Skipping to the next test.", e);
			}
		}

		/**
		 * Converts the given store to coverage data. The coverage will only contain line range coverage information.
		 */
		private TestCoverageBuilder buildCoverage(String testId, ExecutionDataStore executionDataStore,
												  ClasspathWildcardIncludeFilter locationIncludeFilter) throws CoverageGenerationException {
			TestCoverageBuilder testCoverage = new TestCoverageBuilder(testId);
			for (ExecutionData executionData : executionDataStore.getContents()) {
				testCoverage.add(probesCache.getCoverage(executionData, locationIncludeFilter));
			}
			probesCache.flushLogger();
			return testCoverage;
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy