/*
* 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.commandline;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.when;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.pitest.functional.predicate.Predicate;
import org.pitest.functional.prelude.Prelude;
import org.pitest.mutationtest.config.ConfigOption;
import org.pitest.mutationtest.config.PluginServices;
import org.pitest.mutationtest.config.ReportOptions;
import org.pitest.mutationtest.engine.gregor.GregorMutationEngine;
import org.pitest.mutationtest.engine.gregor.mutators.ConditionalsBoundaryMutator;
import org.pitest.mutationtest.engine.gregor.mutators.MathMutator;
public class OptionsParserTest {
private static final String JAVA_PATH_SEPARATOR = "/";
private static final String JAVA_CLASS_PATH_PROPERTY = "java.class.path";
private OptionsParser testee;
@Mock
private Predicate<String> filter;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
when(this.filter.apply(any(String.class))).thenReturn(true);
this.testee = new OptionsParser(this.filter);
}
@Test
public void shouldParseReportDir() {
final String value = "foo";
final ReportOptions actual = parseAddingRequiredArgs("--reportDir", value);
assertEquals(value, actual.getReportDir());
}
@Test
public void shouldCreatePredicateFromCommaSeparatedListOfTargetClassGlobs() {
final ReportOptions actual = parseAddingRequiredArgs("--targetClasses",
"foo*,bar*");
final Predicate<String> actualPredicate = actual.getTargetClassesFilter();
assertTrue(actualPredicate.apply("foo_anything"));
assertTrue(actualPredicate.apply("bar_anything"));
assertFalse(actualPredicate.apply("notfoobar"));
}
@Test
public void shouldParseCommaSeparatedListOfSourceDirectories() {
final ReportOptions actual = parseAddingRequiredArgs("--sourceDirs",
"foo/bar,bar/far");
assertEquals(Arrays.asList(new File("foo/bar"), new File("bar/far")), actual.getSourceDirs());
}
@Test
public void shouldParseMaxDepenencyDistance() {
final ReportOptions actual = parseAddingRequiredArgs(
"--dependencyDistance", "42");
assertEquals(42, actual.getDependencyAnalysisMaxDistance());
}
@Test
public void shouldParseCommaSeparatedListOfJVMArgs() {
final ReportOptions actual = parseAddingRequiredArgs("--jvmArgs", "foo,bar");
assertEquals(Arrays.asList("foo", "bar"), actual.getJvmArgs());
}
@Test
public void shouldParseCommaSeparatedListOfMutationOperators() {
final ReportOptions actual = parseAddingRequiredArgs("--mutators",
ConditionalsBoundaryMutator.CONDITIONALS_BOUNDARY_MUTATOR.name() + ","
+ MathMutator.MATH_MUTATOR.name());
assertEquals(Arrays.asList(
ConditionalsBoundaryMutator.CONDITIONALS_BOUNDARY_MUTATOR.name(),
MathMutator.MATH_MUTATOR.name()), actual.getMutators());
}
@Test
public void shouldDetermineIfMutateStaticInitializersFlagIsSet() {
final ReportOptions actual = parseAddingRequiredArgs("--mutateStaticInits");
assertTrue(actual.isMutateStaticInitializers());
}
@Test
public void shouldDetermineIfMutateStaticInitializersFlagIsSetWhenTrueSupplied() {
final ReportOptions actual = parseAddingRequiredArgs("--mutateStaticInits",
"true");
assertTrue(actual.isMutateStaticInitializers());
}
@Test
public void shouldDetermineIfMutateStaticInitializersFlagIsSetWhenFalseSupplied() {
final ReportOptions actual = parseAddingRequiredArgs("--mutateStaticInits=false");
assertFalse(actual.isMutateStaticInitializers());
}
@Test
public void shouldNotCreateMutationsInStaticInitializerByDefault() {
final ReportOptions actual = parseAddingRequiredArgs("");
assertFalse(actual.isMutateStaticInitializers());
}
@Test
public void shouldNotDetectInlinedCodeByDefault() {
final ReportOptions actual = parseAddingRequiredArgs("");
assertFalse(actual.isDetectInlinedCode());
}
@Test
public void shouldDetermineIfInlinedCodeFlagIsSet() {
final ReportOptions actual = parseAddingRequiredArgs("--detectInlinedCode");
assertTrue(actual.isDetectInlinedCode());
}
@Test
public void shouldDetermineIfInlinedCodeFlagIsSetWhenFalseSupplied() {
final ReportOptions actual = parseAddingRequiredArgs("--detectInlinedCode=false");
assertFalse(actual.isDetectInlinedCode());
}
@Test
public void shouldCreateTimestampedReportsByDefault() {
final ReportOptions actual = parseAddingRequiredArgs();
assertTrue(actual.shouldCreateTimeStampedReports());
}
@Test
public void shouldDetermineIfSuppressTimestampedReportsFlagIsSet() {
final ReportOptions actual = parseAddingRequiredArgs("--timestampedReports");
assertTrue(actual.shouldCreateTimeStampedReports());
}
@Test
public void shouldDetermineIfSuppressTimestampedReportsFlagIsSetWhenFalseSupplied() {
final ReportOptions actual = parseAddingRequiredArgs("--timestampedReports=false");
assertFalse(actual.shouldCreateTimeStampedReports());
}
@Test
public void shouldParseNumberOfThreads() {
final ReportOptions actual = parseAddingRequiredArgs("--threads", "42");
assertEquals(42, actual.getNumberOfThreads());
}
@Test
public void shouldParseTimeOutFactor() {
final ReportOptions actual = parseAddingRequiredArgs("--timeoutFactor",
"1.32");
assertEquals(1.32f, actual.getTimeoutFactor(), 0.1);
}
@Test
public void shouldParseTimeOutConstant() {
final ReportOptions actual = parseAddingRequiredArgs("--timeoutConst", "42");
assertEquals(42, actual.getTimeoutConstant());
}
@Test
public void shouldParseCommaSeparatedListOfTargetTestClassGlobs() {
final ReportOptions actual = parseAddingRequiredArgs("--targetTest",
"foo*,bar*");
final Predicate<String> actualPredicate = actual.getTargetTestsFilter();
assertTrue(actualPredicate.apply("foo_anything"));
assertTrue(actualPredicate.apply("bar_anything"));
assertFalse(actualPredicate.apply("notfoobar"));
}
@Test
public void shouldParseCommaSeparatedListOfTargetTestClassGlobAsRegex() {
ReportOptions actual = parseAddingRequiredArgs("--targetTest",
"~foo\\w*,~bar.*");
Predicate<String> actualPredicate = actual.getTargetTestsFilter();
assertTrue(actualPredicate.apply("foo_anything"));
assertTrue(actualPredicate.apply("bar_anything"));
assertFalse(actualPredicate.apply("notfoobar"));
actual = parseAddingRequiredArgs("--targetTest",
"~.*?foo\\w*,~bar.*");
actualPredicate = actual.getTargetTestsFilter();
assertTrue(actualPredicate.apply("notfoobar"));
}
@Test
public void shouldUseTargetClassesFilterForTestsWhenNoTargetTestsFilterSupplied() {
final ReportOptions actual = parseAddingRequiredArgs("--targetClasses",
"foo*,bar*");
final Predicate<String> actualPredicate = actual.getTargetTestsFilter();
assertTrue(actualPredicate.apply("foo_anything"));
assertTrue(actualPredicate.apply("bar_anything"));
assertFalse(actualPredicate.apply("notfoobar"));
}
@Test
public void shouldParseCommaSeparatedListOfExcludedClassGlobsAndApplyTheseToTests() {
final ReportOptions actual = parseAddingRequiredArgs("--excludedClasses",
"foo*", "--targetTests", "foo*,bar*", "--targetClasses", "foo*,bar*");
final Predicate<String> testPredicate = actual.getTargetTestsFilter();
assertFalse(testPredicate.apply("foo_anything"));
assertTrue(testPredicate.apply("bar_anything"));
}
@Test
public void shouldParseCommaSeparatedListOfExcludedClassGlobsAndApplyTheseToTargets() {
final ReportOptions actual = parseAddingRequiredArgs("--excludedClasses",
"foo*", "--targetTests", "foo*,bar*", "--targetClasses", "foo*,bar*");
final Predicate<String> targetPredicate = actual.getTargetClassesFilter();
assertFalse(targetPredicate.apply("foo_anything"));
assertTrue(targetPredicate.apply("bar_anything"));
}
@Test
public void shouldDefaultLoggingPackagesToDefaultsDefinedByDefaultMutationConfigFactory() {
final ReportOptions actual = parseAddingRequiredArgs();
assertEquals(ReportOptions.LOGGING_CLASSES, actual.getLoggingClasses());
}
@Test
public void shouldParseCommaSeparatedListOfClassesToAvoidCallTo() {
final ReportOptions actual = parseAddingRequiredArgs("--avoidCallsTo",
"foo,bar,foo.bar");
assertEquals(Arrays.asList("foo", "bar", "foo.bar"),
actual.getLoggingClasses());
}
@Test
public void shouldParseCommaSeparatedListOfExcludedMethods() {
final ReportOptions actual = parseAddingRequiredArgs("--excludedMethods",
"foo*,bar*,car");
final Predicate<String> actualPredicate = Prelude.or(actual
.getExcludedMethods());
assertTrue(actualPredicate.apply("foox"));
assertTrue(actualPredicate.apply("barx"));
assertTrue(actualPredicate.apply("car"));
assertFalse(actualPredicate.apply("carx"));
}
@Test
public void shouldParseVerboseFlag() {
final ReportOptions actual = parseAddingRequiredArgs("--verbose");
assertTrue(actual.isVerbose());
}
@Test
public void shouldDefaultToHtmlReportWhenNoOutputFormatsSpecified() {
final ReportOptions actual = parseAddingRequiredArgs();
assertEquals(new HashSet<String>(Arrays.asList("HTML")),
actual.getOutputFormats());
}
@Test
public void shouldParseCommaSeparatedListOfOutputFormatsWhenSupplied() {
final ReportOptions actual = parseAddingRequiredArgs("--outputFormats",
"HTML,CSV");
assertEquals(new HashSet<String>(Arrays.asList("HTML", "CSV")),
actual.getOutputFormats());
}
@Test
public void shouldAcceptCommaSeparatedListOfAdditionalClassPathElements() {
final ReportOptions ro = parseAddingRequiredArgs("--classPath",
"/foo/bar,./boo");
final Collection<String> actual = ro.getClassPathElements();
assertTrue(actual.contains("/foo/bar"));
assertTrue(actual.contains("./boo"));
}
@Test
public void shouldAcceptFileWithListOfAdditionalClassPathElements() {
ClassLoader classLoader = getClass().getClassLoader();
File classPathFile = new File(classLoader.getResource("testClassPathFile.txt").getFile());
final ReportOptions ro = parseAddingRequiredArgs("--classPathFile",
classPathFile.getAbsolutePath());
final Collection<String> actual = ro.getClassPathElements();
assertTrue(actual.contains("C:/foo"));
assertTrue(actual.contains("/etc/bar"));
}
@Test
public void shouldDetermineIfFailWhenNoMutationsFlagIsSet() {
assertTrue(parseAddingRequiredArgs("--failWhenNoMutations", "true")
.shouldFailWhenNoMutations());
assertFalse(parseAddingRequiredArgs("--failWhenNoMutations", "false")
.shouldFailWhenNoMutations());
}
@Test
public void shouldFailWhenNoMutationsSetByDefault() {
assertTrue(parseAddingRequiredArgs("").shouldFailWhenNoMutations());
}
@Test
public void shouldParseCommaSeparatedListOfMutableCodePaths() {
final ReportOptions actual = parseAddingRequiredArgs("--mutableCodePaths",
"foo,bar");
assertEquals(Arrays.asList("foo", "bar"), actual.getCodePaths());
}
@Test
public void shouldParseCommaSeparatedListOfExcludedTestGroups() {
final ReportOptions actual = parseAddingRequiredArgs("--excludedGroups",
"foo,bar");
assertEquals(Arrays.asList("foo", "bar"), actual.getGroupConfig()
.getExcludedGroups());
}
@Test
public void shouldParseCommaSeparatedListOfIncludedTestGroups() {
final ReportOptions actual = parseAddingRequiredArgs("--includedGroups",
"foo,bar");
assertEquals(Arrays.asList("foo", "bar"), actual.getGroupConfig()
.getIncludedGroups());
}
@Test
public void shouldParseMutationUnitSize() {
final ReportOptions actual = parseAddingRequiredArgs("--mutationUnitSize",
"50");
assertEquals(50, actual.getMutationUnitSize());
}
@Test
public void shouldDefaultMutationUnitSizeToCorrectValue() {
final ReportOptions actual = parseAddingRequiredArgs("");
assertEquals(
(int) ConfigOption.MUTATION_UNIT_SIZE.getDefault(Integer.class),
actual.getMutationUnitSize());
}
@Test
public void shouldDefaultToNoHistory() {
final ReportOptions actual = parseAddingRequiredArgs("");
assertNull(actual.getHistoryInputLocation());
assertNull(actual.getHistoryOutputLocation());
}
@Test
public void shouldParseHistoryInputLocation() {
final ReportOptions actual = parseAddingRequiredArgs(
"--historyInputLocation", "foo");
assertEquals(new File("foo"), actual.getHistoryInputLocation());
}
@Test
public void shouldParseHistoryOutputLocation() {
final ReportOptions actual = parseAddingRequiredArgs(
"--historyOutputLocation", "foo");
assertEquals(new File("foo"), actual.getHistoryOutputLocation());
}
@Test
public void shouldParseMutationThreshold() {
final ReportOptions actual = parseAddingRequiredArgs("--mutationThreshold",
"42");
assertEquals(42, actual.getMutationThreshold());
}
@Test
public void shouldParseMaximumAllowedSurvivingMutants() {
final ReportOptions actual = parseAddingRequiredArgs("--maxSurviving",
"42");
assertEquals(42, actual.getMaximumAllowedSurvivors());
}
@Test
public void shouldParseCoverageThreshold() {
final ReportOptions actual = parseAddingRequiredArgs("--coverageThreshold",
"42");
assertEquals(42, actual.getCoverageThreshold());
}
@Test
public void shouldDefaultToGregorEngineWhenNoOptionSupplied() {
final ReportOptions actual = parseAddingRequiredArgs();
assertEquals("gregor", actual.getMutationEngine());
}
@Test
public void shouldParseMutationEnigne() {
final ReportOptions actual = parseAddingRequiredArgs("--mutationEngine",
"foo");
assertEquals("foo", actual.getMutationEngine());
}
@Test
public void shouldDefaultJVMToNull() {
final ReportOptions actual = parseAddingRequiredArgs();
assertEquals(null, actual.getJavaExecutable());
}
@Test
public void shouldParseJVM() {
final ReportOptions actual = parseAddingRequiredArgs("--jvmPath", "foo");
assertEquals("foo", actual.getJavaExecutable());
}
@Test
public void shouldParseExportLineCoverageFlag() {
final ReportOptions actual = parseAddingRequiredArgs("--exportLineCoverage");
assertTrue(actual.shouldExportLineCoverage());
}
@Test
public void shouldNotExportLineCoverageWhenFlagNotSet() {
final ReportOptions actual = parseAddingRequiredArgs("");
assertFalse(actual.shouldExportLineCoverage());
}
@Test
public void shouldIncludeLaunchClasspathByDefault() {
final ReportOptions actual = parseAddingRequiredArgs("");
assertTrue(actual.isIncludeLaunchClasspath());
}
@Test
public void shouldNotIncludeLaunchClasspathWhenFlagUnset() {
final ReportOptions actual = parseAddingRequiredArgs("--includeLaunchClasspath=false");
assertFalse(actual.isIncludeLaunchClasspath());
}
@Test
public void shouldIncludeLaunchClasspathWhenFlag() {
final ReportOptions actual = parseAddingRequiredArgs("--includeLaunchClasspath=true");
assertTrue(actual.isIncludeLaunchClasspath());
}
@Test
public void shouldHandleNotCanonicalLaunchClasspathElements() {
final String oldClasspath = System.getProperty(JAVA_CLASS_PATH_PROPERTY);
try {
// given
final PluginServices plugins = PluginServices.makeForContextLoader();
this.testee = new OptionsParser(new PluginFilter(plugins));
// and
System.setProperty(JAVA_CLASS_PATH_PROPERTY,
getNonCanonicalGregorEngineClassPath());
// when
final ReportOptions actual = parseAddingRequiredArgs("--includeLaunchClasspath=false");
// then
assertThat(actual.getClassPath().findClasses(gregorClass())).hasSize(1);
} finally {
System.setProperty(JAVA_CLASS_PATH_PROPERTY, oldClasspath);
}
}
@Test
public void shouldCreateEmptyPluginPropertiesWhenNoneSupplied() {
final ReportOptions actual = parseAddingRequiredArgs("");
assertNotNull(actual.getFreeFormProperties());
}
@Test
public void shouldIncludePluginPropertyValuesWhenSingleKey() {
final ReportOptions actual = parseAddingRequiredArgs("-pluginConfiguration=foo=1");
assertEquals("1", actual.getFreeFormProperties().getProperty("foo"));
}
@Test
public void shouldIncludePluginPropertyValuesWhenMultipleKeys() {
final ReportOptions actual = parseAddingRequiredArgs(
"-pluginConfiguration=foo=1", "-pluginConfiguration=bar=2");
assertEquals("1", actual.getFreeFormProperties().getProperty("foo"));
assertEquals("2", actual.getFreeFormProperties().getProperty("bar"));
}
private String getNonCanonicalGregorEngineClassPath() {
final String gregorEngineClassPath = GregorMutationEngine.class
.getProtectionDomain().getCodeSource().getLocation().getFile();
final int lastOccurrenceOfFileSeparator = gregorEngineClassPath
.lastIndexOf(JAVA_PATH_SEPARATOR);
return new StringBuilder(gregorEngineClassPath).replace(
lastOccurrenceOfFileSeparator, lastOccurrenceOfFileSeparator + 1,
JAVA_PATH_SEPARATOR + "." + JAVA_PATH_SEPARATOR).toString();
}
private Predicate<String> gregorClass() {
return new Predicate<String>() {
@Override
public Boolean apply(String s) {
return GregorMutationEngine.class.getName().equals(s);
}
};
}
private ReportOptions parseAddingRequiredArgs(final String... args) {
final List<String> a = new ArrayList<String>();
a.addAll(Arrays.asList(args));
addIfNotPresent(a, "--targetClasses");
addIfNotPresent(a, "--reportDir");
addIfNotPresent(a, "--sourceDirs");
return parse(a.toArray(new String[a.size()]));
}
private void addIfNotPresent(final List<String> uniqueArgs, final String value) {
if (!uniqueArgs.contains(value)) {
uniqueArgs.add(value);
uniqueArgs.add("ignore");
}
}
private ReportOptions parse(final String... args) {
return this.testee.parse(args).getOptions();
}
}