/*
* 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.engine.gregor.config;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.pitest.functional.F;
import org.pitest.functional.FCollection;
import org.pitest.functional.prelude.Prelude;
import org.pitest.help.Help;
import org.pitest.help.PitHelpError;
import org.pitest.mutationtest.engine.gregor.MethodMutatorFactory;
import org.pitest.mutationtest.engine.gregor.mutators.ArgumentPropagationMutator;
import org.pitest.mutationtest.engine.gregor.mutators.ConditionalsBoundaryMutator;
import org.pitest.mutationtest.engine.gregor.mutators.ConstructorCallMutator;
import org.pitest.mutationtest.engine.gregor.mutators.IncrementsMutator;
import org.pitest.mutationtest.engine.gregor.mutators.InlineConstantMutator;
import org.pitest.mutationtest.engine.gregor.mutators.InvertNegsMutator;
import org.pitest.mutationtest.engine.gregor.mutators.MathMutator;
import org.pitest.mutationtest.engine.gregor.mutators.NegateConditionalsMutator;
import org.pitest.mutationtest.engine.gregor.mutators.NonVoidMethodCallMutator;
import org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator;
import org.pitest.mutationtest.engine.gregor.mutators.RemoveConditionalMutator.Choice;
import org.pitest.mutationtest.engine.gregor.mutators.ReturnValsMutator;
import org.pitest.mutationtest.engine.gregor.mutators.VoidMethodCallMutator;
import org.pitest.mutationtest.engine.gregor.mutators.experimental.RemoveIncrementsMutator;
import org.pitest.mutationtest.engine.gregor.mutators.experimental.RemoveSwitchMutator;
import org.pitest.mutationtest.engine.gregor.mutators.experimental.SwitchMutator;
public final class Mutator {
private static final Map<String, Iterable<MethodMutatorFactory>> MUTATORS = new LinkedHashMap<String, Iterable<MethodMutatorFactory>>();
static {
/**
* Default mutator that inverts the negation of integer and floating point
* numbers.
*/
add("INVERT_NEGS", InvertNegsMutator.INVERT_NEGS_MUTATOR);
/**
* Default mutator that mutates the return values of methods.
*/
add("RETURN_VALS", ReturnValsMutator.RETURN_VALS_MUTATOR);
/**
* Optional mutator that mutates integer and floating point inline
* constants.
*/
add("INLINE_CONSTS", new InlineConstantMutator());
/**
* Default mutator that mutates binary arithmetic operations.
*/
add("MATH", MathMutator.MATH_MUTATOR);
/**
* Default mutator that removes method calls to void methods.
*
*/
add("VOID_METHOD_CALLS", VoidMethodCallMutator.VOID_METHOD_CALL_MUTATOR);
/**
* Default mutator that negates conditionals.
*/
add("NEGATE_CONDITIONALS",
NegateConditionalsMutator.NEGATE_CONDITIONALS_MUTATOR);
/**
* Default mutator that replaces the relational operators with their
* boundary counterpart.
*/
add("CONDITIONALS_BOUNDARY",
ConditionalsBoundaryMutator.CONDITIONALS_BOUNDARY_MUTATOR);
/**
* Default mutator that mutates increments, decrements and assignment
* increments and decrements of local variables.
*/
add("INCREMENTS", IncrementsMutator.INCREMENTS_MUTATOR);
/**
* Optional mutator that removes local variable increments.
*/
add("REMOVE_INCREMENTS", RemoveIncrementsMutator.REMOVE_INCREMENTS_MUTATOR);
/**
* Optional mutator that removes method calls to non void methods.
*/
add("NON_VOID_METHOD_CALLS",
NonVoidMethodCallMutator.NON_VOID_METHOD_CALL_MUTATOR);
/**
* Optional mutator that replaces constructor calls with null values.
*/
add("CONSTRUCTOR_CALLS", ConstructorCallMutator.CONSTRUCTOR_CALL_MUTATOR);
/**
* Removes conditional statements so that guarded statements always execute
* The EQUAL version ignores LT,LE,GT,GE, which is the default behavior,
* ORDER version mutates only those.
*/
add("REMOVE_CONDITIONALS_EQ_IF", new RemoveConditionalMutator(Choice.EQUAL,
true));
add("REMOVE_CONDITIONALS_EQ_ELSE", new RemoveConditionalMutator(
Choice.EQUAL, false));
add("REMOVE_CONDITIONALS_ORD_IF", new RemoveConditionalMutator(
Choice.ORDER, true));
add("REMOVE_CONDITIONALS_ORD_ELSE", new RemoveConditionalMutator(
Choice.ORDER, false));
addGroup("REMOVE_CONDITIONALS", RemoveConditionalMutator.makeMutators());
/**
* Experimental mutator that removed assignments to member variables.
*/
add("EXPERIMENTAL_MEMBER_VARIABLE",
new org.pitest.mutationtest.engine.gregor.mutators.experimental.MemberVariableMutator());
/**
* Experimental mutator that swaps labels in switch statements
*/
add("EXPERIMENTAL_SWITCH",
new org.pitest.mutationtest.engine.gregor.mutators.experimental.SwitchMutator());
/**
* Experimental mutator that replaces method call with one of its parameters
* of matching type
*/
add("EXPERIMENTAL_ARGUMENT_PROPAGATION",
ArgumentPropagationMutator.ARGUMENT_PROPAGATION_MUTATOR);
addGroup("REMOVE_SWITCH", RemoveSwitchMutator.makeMutators());
addGroup("DEFAULTS", defaults());
addGroup("STRONGER", stronger());
addGroup("ALL", all());
}
public static Collection<MethodMutatorFactory> all() {
return fromStrings(MUTATORS.keySet());
}
private static Collection<MethodMutatorFactory> stronger() {
return combine(
defaults(),
group(new RemoveConditionalMutator(Choice.EQUAL, false),
new SwitchMutator()));
}
private static Collection<MethodMutatorFactory> combine(
Collection<MethodMutatorFactory> a, Collection<MethodMutatorFactory> b) {
List<MethodMutatorFactory> l = new ArrayList<MethodMutatorFactory>(a);
l.addAll(b);
return l;
}
/**
* Default set of mutators - designed to provide balance between strength and
* performance
*/
public static Collection<MethodMutatorFactory> defaults() {
return group(InvertNegsMutator.INVERT_NEGS_MUTATOR,
ReturnValsMutator.RETURN_VALS_MUTATOR, MathMutator.MATH_MUTATOR,
VoidMethodCallMutator.VOID_METHOD_CALL_MUTATOR,
NegateConditionalsMutator.NEGATE_CONDITIONALS_MUTATOR,
ConditionalsBoundaryMutator.CONDITIONALS_BOUNDARY_MUTATOR,
IncrementsMutator.INCREMENTS_MUTATOR);
}
private static Collection<MethodMutatorFactory> group(
final MethodMutatorFactory... ms) {
return Arrays.asList(ms);
}
public static Collection<MethodMutatorFactory> byName(final String name) {
return FCollection.map(MUTATORS.get(name),
Prelude.id(MethodMutatorFactory.class));
}
private static void add(final String key, final MethodMutatorFactory value) {
MUTATORS.put(key, Collections.singleton(value));
}
private static void addGroup(final String key,
final Iterable<MethodMutatorFactory> value) {
MUTATORS.put(key, value);
}
public static Collection<MethodMutatorFactory> fromStrings(
final Collection<String> names) {
final Set<MethodMutatorFactory> unique = new TreeSet<MethodMutatorFactory>(
compareId());
FCollection.flatMapTo(names, fromString(), unique);
return unique;
}
private static Comparator<? super MethodMutatorFactory> compareId() {
return new Comparator<MethodMutatorFactory>() {
@Override
public int compare(final MethodMutatorFactory o1,
final MethodMutatorFactory o2) {
return o1.getGloballyUniqueId().compareTo(o2.getGloballyUniqueId());
}
};
}
private static F<String, Iterable<MethodMutatorFactory>> fromString() {
return new F<String, Iterable<MethodMutatorFactory>>() {
@Override
public Iterable<MethodMutatorFactory> apply(final String a) {
Iterable<MethodMutatorFactory> i = MUTATORS.get(a);
if (i == null) {
throw new PitHelpError(Help.UNKNOWN_MUTATOR, a);
}
return i;
}
};
}
}