/* * Copyright 2010 Henry Coles * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and limitations under the License. */ package org.pitest.mutationtest.config; import static org.pitest.functional.prelude.Prelude.not; import static org.pitest.functional.prelude.Prelude.or; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; import java.util.Properties; import org.pitest.classpath.ClassFilter; import org.pitest.classpath.ClassPath; import org.pitest.classpath.ClassPathRoot; import org.pitest.classpath.PathFilter; import org.pitest.classpath.ProjectClassPaths; import org.pitest.functional.F; import org.pitest.functional.FCollection; import org.pitest.functional.Option; import org.pitest.functional.predicate.Predicate; import org.pitest.functional.prelude.Prelude; import org.pitest.help.Help; import org.pitest.help.PitHelpError; import org.pitest.mutationtest.build.PercentAndConstantTimeoutStrategy; import org.pitest.mutationtest.incremental.FileWriterFactory; import org.pitest.mutationtest.incremental.NullWriterFactory; import org.pitest.mutationtest.incremental.WriterFactory; import org.pitest.testapi.TestGroupConfig; import org.pitest.testapi.execute.Pitest; import org.pitest.util.Glob; import org.pitest.util.ResultOutputStrategy; import org.pitest.util.Unchecked; // FIXME move all logic to SettingsFactory and turn into simple bean /** * Big ball of user supplied options to configure various aspects of mutation * testing. * */ public class ReportOptions { public static final Collection<String> LOGGING_CLASSES = Arrays .asList( "java.util.logging", "org.apache.log4j", "org.apache.logging.log4j", "org.slf4j", "org.apache.commons.logging"); private Collection<Predicate<String>> targetClasses; private Collection<Predicate<String>> excludedMethods = Collections .emptyList(); private Collection<Predicate<String>> excludedClasses = Collections .emptyList(); private Collection<String> codePaths; private String reportDir; private File historyInputLocation; private File historyOutputLocation; private Collection<File> sourceDirs; private Collection<String> classPathElements; private Collection<String> mutators; private int dependencyAnalysisMaxDistance; private boolean mutateStaticInitializers = false; private final List<String> jvmArgs = new ArrayList<String>(); private int numberOfThreads = 0; private float timeoutFactor = PercentAndConstantTimeoutStrategy.DEFAULT_FACTOR; private long timeoutConstant = PercentAndConstantTimeoutStrategy.DEFAULT_CONSTANT; private Collection<Predicate<String>> targetTests; private Collection<String> loggingClasses = new ArrayList<String>(); private int maxMutationsPerClass; private boolean verbose = false; private boolean failWhenNoMutations = false; private final Collection<String> outputs = new LinkedHashSet<String>(); private TestGroupConfig groupConfig; private int mutationUnitSize; private boolean shouldCreateTimestampedReports = true; private boolean detectInlinedCode = false; private boolean exportLineCoverage = false; private int mutationThreshold; private int coverageThreshold; private String mutationEngine = "gregor"; private String javaExecutable; private boolean includeLaunchClasspath = true; private Properties properties; private int maxSurvivors; private Collection<String> excludedRunners = new ArrayList<String>(); public boolean isVerbose() { return this.verbose; } /** * @return the reportDir */ public String getReportDir() { return this.reportDir; } /** * @param reportDir * the reportDir to set */ public void setReportDir(final String reportDir) { this.reportDir = reportDir; } /** * @return the sourceDirs */ public Collection<File> getSourceDirs() { return this.sourceDirs; } public Collection<String> getClassPathElements() { return this.classPathElements; } public void setClassPathElements(final Collection<String> classPathElements) { this.classPathElements = classPathElements; } /** * @param sourceDirs * the sourceDirs to set */ public void setSourceDirs(final Collection<File> sourceDirs) { this.sourceDirs = sourceDirs; } /** * @return the mutators */ public Collection<String> getMutators() { return this.mutators; } /** * @param mutators * the mutators to set */ public void setMutators(final Collection<String> mutators) { this.mutators = mutators; } /** * @return the dependencyAnalysisMaxDistance */ public int getDependencyAnalysisMaxDistance() { return this.dependencyAnalysisMaxDistance; } /** * @param dependencyAnalysisMaxDistance * the dependencyAnalysisMaxDistance to set */ public void setDependencyAnalysisMaxDistance( final int dependencyAnalysisMaxDistance) { this.dependencyAnalysisMaxDistance = dependencyAnalysisMaxDistance; } public List<String> getJvmArgs() { return this.jvmArgs; } public void addChildJVMArgs(final List<String> args) { this.jvmArgs.addAll(args); } public ClassPath getClassPath() { if (this.classPathElements != null) { return createClassPathFromElements(); } else { return new ClassPath(); } } private ClassPath createClassPathFromElements() { return new ClassPath( FCollection.map(this.classPathElements, stringToFile())); } private static F<String, File> stringToFile() { return new F<String, File>() { @Override public File apply(final String a) { return new File(a); } }; } public Collection<Predicate<String>> getTargetClasses() { return this.targetClasses; } @SuppressWarnings("unchecked") public Predicate<String> getTargetClassesFilter() { final Predicate<String> filter = Prelude.and(or(this.targetClasses), not(isBlackListed(ReportOptions.this.excludedClasses))); checkNotTryingToMutateSelf(filter); return filter; } private void checkNotTryingToMutateSelf(final Predicate<String> filter) { if (filter.apply(Pitest.class.getName())) { throw new PitHelpError(Help.BAD_FILTER); } } public void setTargetClasses(final Collection<Predicate<String>> targetClasses) { this.targetClasses = targetClasses; } public void setTargetTests( final Collection<Predicate<String>> targetTestsPredicates) { this.targetTests = targetTestsPredicates; } public boolean isMutateStaticInitializers() { return this.mutateStaticInitializers; } public void setMutateStaticInitializers(final boolean mutateStaticInitializers) { this.mutateStaticInitializers = mutateStaticInitializers; } public int getNumberOfThreads() { return this.numberOfThreads; } public void setNumberOfThreads(final int numberOfThreads) { this.numberOfThreads = numberOfThreads; } public float getTimeoutFactor() { return this.timeoutFactor; } public long getTimeoutConstant() { return this.timeoutConstant; } public void setTimeoutConstant(final long timeoutConstant) { this.timeoutConstant = timeoutConstant; } public void setTimeoutFactor(final float timeoutFactor) { this.timeoutFactor = timeoutFactor; } public Collection<Predicate<String>> getTargetTests() { return this.targetTests; } @SuppressWarnings("unchecked") public Predicate<String> getTargetTestsFilter() { if ((this.targetTests == null) || this.targetTests.isEmpty()) { return this.getTargetClassesFilter(); // if no tests specified assume the // target classes filter covers both } else { return Prelude.and(or(this.targetTests), not(isBlackListed(ReportOptions.this.excludedClasses))); } } private static Predicate<String> isBlackListed( final Collection<Predicate<String>> excludedClasses) { return or(excludedClasses); } public Collection<String> getLoggingClasses() { if (this.loggingClasses.isEmpty()) { return LOGGING_CLASSES; } else { return this.loggingClasses; } } public void setLoggingClasses(final Collection<String> loggingClasses) { this.loggingClasses = loggingClasses; } public Collection<Predicate<String>> getExcludedMethods() { return this.excludedMethods; } public void setExcludedMethods( final Collection<Predicate<String>> excludedMethods) { this.excludedMethods = excludedMethods; } public int getMaxMutationsPerClass() { return this.maxMutationsPerClass; } public void setMaxMutationsPerClass(final int maxMutationsPerClass) { this.maxMutationsPerClass = maxMutationsPerClass; } public void setVerbose(final boolean verbose) { this.verbose = verbose; } public void setExcludedClasses( final Collection<Predicate<String>> excludedClasses) { this.excludedClasses = excludedClasses; } public void addOutputFormats(final Collection<String> formats) { this.outputs.addAll(formats); } public Collection<String> getOutputFormats() { return this.outputs; } public Collection<Predicate<String>> getExcludedClasses() { return this.excludedClasses; } public boolean shouldFailWhenNoMutations() { return this.failWhenNoMutations; } public void setFailWhenNoMutations(final boolean failWhenNoMutations) { this.failWhenNoMutations = failWhenNoMutations; } public ProjectClassPaths getMutationClassPaths() { return new ProjectClassPaths(this.getClassPath(), createClassesFilter(), createPathFilter()); } public ClassFilter createClassesFilter() { return new ClassFilter(this.getTargetTestsFilter(), this.getTargetClassesFilter()); } private PathFilter createPathFilter() { return new PathFilter(createCodePathFilter(), not(new DefaultDependencyPathPredicate())); } private Predicate<ClassPathRoot> createCodePathFilter() { if ((this.codePaths != null) && !this.codePaths.isEmpty()) { return new PathNamePredicate(Prelude.or(Glob .toGlobPredicates(this.codePaths))); } else { return new DefaultCodePathPredicate(); } } public Collection<String> getCodePaths() { return this.codePaths; } public void setCodePaths(final Collection<String> codePaths) { this.codePaths = codePaths; } public void setGroupConfig(final TestGroupConfig groupConfig) { this.groupConfig = groupConfig; } public TestGroupConfig getGroupConfig() { return this.groupConfig; } public int getMutationUnitSize() { return this.mutationUnitSize; } public void setMutationUnitSize(final int size) { this.mutationUnitSize = size; } public ResultOutputStrategy getReportDirectoryStrategy() { return new DirectoryResultOutputStrategy(getReportDir(), pickDirectoryStrategy()); } public void setShouldCreateTimestampedReports( final boolean shouldCreateTimestampedReports) { this.shouldCreateTimestampedReports = shouldCreateTimestampedReports; } private ReportDirCreationStrategy pickDirectoryStrategy() { if (this.shouldCreateTimestampedReports) { return new DatedDirectoryReportDirCreationStrategy(); } else { return new UndatedReportDirCreationStrategy(); } } public boolean shouldCreateTimeStampedReports() { return this.shouldCreateTimestampedReports; } public boolean isDetectInlinedCode() { return this.detectInlinedCode; } public void setDetectInlinedCode(final boolean b) { this.detectInlinedCode = b; } public WriterFactory createHistoryWriter() { if (this.historyOutputLocation == null) { return new NullWriterFactory(); } return new FileWriterFactory(this.historyOutputLocation); } public Option<Reader> createHistoryReader() { if (this.historyInputLocation == null) { return Option.none(); } try { if (this.historyInputLocation.exists() && (this.historyInputLocation.length() > 0)) { return Option.<Reader> some(new InputStreamReader(new FileInputStream( this.historyInputLocation), "UTF-8")); } return Option.none(); } catch (final IOException ex) { throw Unchecked.translateCheckedException(ex); } } public void setHistoryInputLocation(final File historyInputLocation) { this.historyInputLocation = historyInputLocation; } public void setHistoryOutputLocation(final File historyOutputLocation) { this.historyOutputLocation = historyOutputLocation; } public File getHistoryInputLocation() { return this.historyInputLocation; } public File getHistoryOutputLocation() { return this.historyOutputLocation; } public void setExportLineCoverage(final boolean value) { this.exportLineCoverage = value; } public boolean shouldExportLineCoverage() { return this.exportLineCoverage; } public int getMutationThreshold() { return this.mutationThreshold; } public void setMutationThreshold(final int value) { this.mutationThreshold = value; } public String getMutationEngine() { return this.mutationEngine; } public void setMutationEngine(final String mutationEngine) { this.mutationEngine = mutationEngine; } public int getCoverageThreshold() { return this.coverageThreshold; } public void setCoverageThreshold(final int coverageThreshold) { this.coverageThreshold = coverageThreshold; } public String getJavaExecutable() { return this.javaExecutable; } public void setJavaExecutable(final String javaExecutable) { this.javaExecutable = javaExecutable; } public void setIncludeLaunchClasspath(final boolean b) { this.includeLaunchClasspath = b; } public boolean isIncludeLaunchClasspath() { return this.includeLaunchClasspath; } public Properties getFreeFormProperties() { return this.properties; } public void setFreeFormProperties(Properties props) { this.properties = props; } public int getMaximumAllowedSurvivors() { return maxSurvivors; } public void setMaximumAllowedSurvivors(int maxSurvivors) { this.maxSurvivors = maxSurvivors; } public Collection<String> getExcludedRunners() { return excludedRunners; } public void setExcludedRunners(Collection<String> excludedRunners) { this.excludedRunners = excludedRunners; } @Override public String toString() { return "ReportOptions [targetClasses=" + targetClasses + ", excludedMethods=" + excludedMethods + ", excludedClasses=" + excludedClasses + ", codePaths=" + codePaths + ", reportDir=" + reportDir + ", historyInputLocation=" + historyInputLocation + ", historyOutputLocation=" + historyOutputLocation + ", sourceDirs=" + sourceDirs + ", classPathElements=" + classPathElements + ", mutators=" + mutators + ", dependencyAnalysisMaxDistance=" + dependencyAnalysisMaxDistance + ", mutateStaticInitializers=" + mutateStaticInitializers + ", jvmArgs=" + jvmArgs + ", numberOfThreads=" + numberOfThreads + ", timeoutFactor=" + timeoutFactor + ", timeoutConstant=" + timeoutConstant + ", targetTests=" + targetTests + ", loggingClasses=" + loggingClasses + ", maxMutationsPerClass=" + maxMutationsPerClass + ", verbose=" + verbose + ", failWhenNoMutations=" + failWhenNoMutations + ", outputs=" + outputs + ", groupConfig=" + groupConfig + ", mutationUnitSize=" + mutationUnitSize + ", shouldCreateTimestampedReports=" + shouldCreateTimestampedReports + ", detectInlinedCode=" + detectInlinedCode + ", exportLineCoverage=" + exportLineCoverage + ", mutationThreshold=" + mutationThreshold + ", coverageThreshold=" + coverageThreshold + ", mutationEngine=" + mutationEngine + ", javaExecutable=" + javaExecutable + ", includeLaunchClasspath=" + includeLaunchClasspath + ", properties=" + properties + ", maxSurvivors=" + maxSurvivors + ", excludedRunners=" + excludedRunners + "]"; } }