diff --git a/bundles/org.pitest.pitclipse.core/src/org/pitest/pitclipse/core/Mutators.java b/bundles/org.pitest.pitclipse.core/src/org/pitest/pitclipse/core/Mutators.java new file mode 100644 index 00000000..b87a6278 --- /dev/null +++ b/bundles/org.pitest.pitclipse.core/src/org/pitest/pitclipse/core/Mutators.java @@ -0,0 +1,148 @@ +/******************************************************************************* + * Copyright 2012-2021 Phil Glover and contributors + * + * 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.pitclipse.core; + +import java.util.ArrayList; +import java.util.List; + +import org.pitest.mutationtest.engine.gregor.config.Mutator; + +/** + * Enum which holds information about the mutators of pit.
+ * The name of new values must be the exact String, which is used by PIT + * in the class {@link Mutator}. + */ +public enum Mutators { + CUSTOM("Custom mutator data", "This is used for the custom settings of mutators and should not be seen by the user."), + OLD_DEFAULTS("Old defaults", "&Old default Mutators"), + DEFAULTS("Defaults", "&Default Mutators"), + STRONGER("Stronger defaults", "&Stronger Mutators"), + ALL("All", "&All Mutators"), + CONDITIONALS_BOUNDARY("Conditionals Boundary", "Replaces the relational operators <, <=, >, >=", true), + INCREMENTS("Increments", "Mutates increments, decrements and assignment increments and decrements of local variables (stack variables). Replaces increments with decrements and vice versa", true), + INVERT_NEGS("Invert Negatives", "Inverts negation of integer and floating point numbers", true), + MATH("Math", "Replaces binary arithmetic operations for either integer or floating-point arithmetic with another operation", true), + NEGATE_CONDITIONALS("Negate Conditionals", "Mutates all conditionals found", true), + RETURN_VALS("Return Values", "Mutates the return values of method calls. Depending on the return type of the method another mutation is used"), + VOID_METHOD_CALLS("Void Method Call", "Removes method calls to void methods", true), + CONSTRUCTOR_CALLS("Constructor Call", "Replaces constructor calls with null values"), + RETURNS("All Returns", "Group which includes all return mutators"), + EMPTY_RETURNS("Empty Returns", "Replaces return values with an 'empty' value", true), + FALSE_RETURNS("False Returns", "Replaces primitive and boxed boolean return values with false", true), + TRUE_RETURNS("True Returns", "Replaces primitive and boxed boolean return values with true", true), + INLINE_CONSTS("Inline Constant", "Mutates inline constants. An inline constant is a literal value assigned to a non-final variable"), + NULL_RETURNS("Null Returns", "Replaces return values with null. Method that can be mutated by the EMPTY_RETURNS mutator or that are directly annotated with NotNull are not mutated", true), + NON_VOID_METHOD_CALLS("Non Void Method Call", "Removes method calls to non void methods. Their return value is replaced by the Java Default Value for that specific type"), + PRIMITIVE_RETURNS("Primite Returns", "Replaces int, short, long, char, float and double return values with 0", true), + REMOVE_CONDITIONALS("Remove Conditionals", "Removes all conditionals statements such that the guarded statements always execute"), + REMOVE_CONDITIONALS_EQ_IF("Remove Equal Conditionals If", "Remove equal conditions and replace with true, execute if part"), + REMOVE_CONDITIONALS_EQ_ELSE("Remove Equal Conditionals Else", "Remove equal conditions and replace with false, execute else part"), + REMOVE_CONDITIONALS_ORD_IF("Remove Order Checks If", "Remove order conditions and replace with true, execute if part"), + REMOVE_CONDITIONALS_ORD_ELSE("Remove Order Checks Else", "Remove order conditions and replace with false, execute else part"), + REMOVE_INCREMENTS("Remove Increments", "Removes local variable increments"), + EXPERIMENTAL_ARGUMENT_PROPAGATION("Experimentation Argument Propagation", "Replaces method call with one of its parameters of matching type"), + EXPERIMENTAL_BIG_INTEGER("Experimental Big Integer", "Swaps big integer methods"), + EXPERIMENTAL_NAKED_RECEIVER("Experimental Naked Receiver", "Replaces method call with a naked receiver"), + EXPERIMENTAL_MEMBER_VARIABLE("Experimental Member Variable", "Removes assignments to member variables. Can even remove assignments to final members. The members will be initialized with their Java Default Value"), + EXPERIMENTAL_SWITCH("Experimental Switch", "Finds the first label within a switch statement that differs from the default label. Mutates the switch statement by replacing the default label (wherever it is used) with this label. All the other labels are replaced by the default one"), + ABS("Negation", "Replaces any use of a numeric variable (local variable, field, array cell) with its negation"), + AOR("Arithmetic Operator Replacement", "Like the Math mutator, replaces binary arithmetic operations for either integer or floating-point arithmetic with another operation"), + AOR_1("Arithmetic Operator Replacement 1", "+ -> -, - -> +, * -> /, / -> *, % -> *"), + AOR_2("Arithmetic Operator Replacement 2", "+ -> *, - -> *, * -> %, / -> %, % -> /"), + AOR_3("Arithmetic Operator Replacement 3", "+ -> /, - -> /, * -> +, / -> +, % -> +"), + AOR_4("Arithmetic Operator Replacement 4", "+ -> %, - -> %, * -> -, / -> -, % -> -"), + AOD("Arithmetic Operator Deletion", "Replaces an arithmetic operation with one of its members"), + AOD1("Arithmetic Operator Deletion 1", "int a = b + c; -> int a = b;"), + AOD2("Arithmetic Operator Deletion 2", "int a = b + c; -> int a = c;"), + CRCR("Constant Replacement", "Like the Inline Constant mutator, mutates inline constant"), + CRCR1("Constant Replacement 1", "Replaces the inline constant c with 1"), + CRCR2("Constant Replacement 2", "Replaces the inline constant c with 0"), + CRCR3("Constant Replacement 3", "Replaces the inline constant c with -1"), + CRCR4("Constant Replacement 4", "Replaces the inline constant c with -c"), + CRCR5("Constant Replacement 5", "Replaces the inline constant c with c+1"), + CRCR6("Constant Replacement 6", "Replaces the inline constant c with c-1"), + OBBN("Bitwise Operator", "Mutates bitwise and (&) and or (|)"), + OBBN1("Bitwise Operator 1", "a & b; -> a | b;"), + OBBN2("Bitwise Operator 2", "a & b; -> a;"), + OBBN3("Bitwise Operator 3", "a & b; -> b;"), + ROR("Relational Operator Replacement", "Replaces a relational operator with another one"), + ROR1("Relational Operator Replacement 1", "< -> <=, <= -> <, > -> <, >= -> <, == -> <, != -> <"), + ROR2("Relational Operator Replacement 2", "< -> >, <= -> >, > -> <=, >= -> <=, == -> <=, != -> <="), + ROR3("Relational Operator Replacement 3", "< -> >=, <= -> >=, > -> >=, >= -> >, == -> >, != -> >"), + ROR4("Relational Operator Replacement 4", "< -> ==, <= -> ==, > -> ==, >= -> ==, == -> >=, != -> >="), + ROR5("Relational Operator Replacement 5", "< -> !=, <= -> !=, > -> !=, >= -> !=, == -> !=, != -> =="), + // XXX REMOVE_SWITCH("",""), no data on the page of pitest + UOI1("Unary Operator Insertion 1", "Inserts a unary operator to a variable call from the variable a to a++"), + UOI2("Unary Operator Insertion 2", "Inserts a unary operator to a variable call from the variable a to a--"), + UOI3("Unary Operator Insertion 3", "Inserts a unary operator to a variable call from the variable a to ++a"), + UOI4("Unary Operator Insertion 4", "Inserts a unary operator to a variable call from the variable a to --a"), + UOI("Unary Operator Insertion", "Inserts a unary operator (increment or decrement) to a variable call. Affects local variables, array variables, fields and parameters"); + + /** + * Descriptor which is used to display the name of this mutator in a table + */ + private final String descriptor; + /** + * Description of this mutator + */ + private final String description; + /** + * true, if this mutator is contained in the DEFAULTS group of PIT + */ + private final boolean activeByDefault; + + private Mutators(String descriptor, String description) { + this(descriptor, description, false); + } + + private Mutators(String descriptor, String description, boolean activeByDefault) { + this.descriptor = descriptor; + this.description = description; + this.activeByDefault = activeByDefault; + } + + public String getDescriptor() { + return descriptor; + } + + public String getDescription() { + return description; + } + + public boolean isActiveByDefault() { + return activeByDefault; + } + + public static List getMainGroup() { + final ArrayList mainGroup = new ArrayList<>(); + mainGroup.add(DEFAULTS); + mainGroup.add(STRONGER); + mainGroup.add(ALL); + mainGroup.add(OLD_DEFAULTS); + return mainGroup; + } + + public static List getDefaultMutators() { + ArrayList defaultMutators = new ArrayList<>(); + for (Mutators m : values()) { + if (m.isActiveByDefault()) { + defaultMutators.add(m.name()); + } + } + return defaultMutators; + } +} diff --git a/bundles/org.pitest.pitclipse.core/src/org/pitest/pitclipse/core/PitCoreActivator.java b/bundles/org.pitest.pitclipse.core/src/org/pitest/pitclipse/core/PitCoreActivator.java index 418a0fef..62a7b3a4 100644 --- a/bundles/org.pitest.pitclipse.core/src/org/pitest/pitclipse/core/PitCoreActivator.java +++ b/bundles/org.pitest.pitclipse.core/src/org/pitest/pitclipse/core/PitCoreActivator.java @@ -20,9 +20,10 @@ import static org.pitest.pitclipse.core.preferences.PitPreferences.AVOID_CALLS_TO; import static org.pitest.pitclipse.core.preferences.PitPreferences.EXCLUDED_CLASSES; import static org.pitest.pitclipse.core.preferences.PitPreferences.EXCLUDED_METHODS; +import static org.pitest.pitclipse.core.preferences.PitPreferences.EXECUTION_MODE; import static org.pitest.pitclipse.core.preferences.PitPreferences.INCREMENTAL_ANALYSIS; -import static org.pitest.pitclipse.core.preferences.PitPreferences.PIT_EXECUTION_MODE; -import static org.pitest.pitclipse.core.preferences.PitPreferences.PIT_MUTATORS; +import static org.pitest.pitclipse.core.preferences.PitPreferences.INDIVIDUAL_MUTATORS; +import static org.pitest.pitclipse.core.preferences.PitPreferences.MUTATOR_GROUP; import static org.pitest.pitclipse.core.preferences.PitPreferences.RUN_IN_PARALLEL; import static org.pitest.pitclipse.core.preferences.PitPreferences.TIMEOUT; import static org.pitest.pitclipse.core.preferences.PitPreferences.TIMEOUT_FACTOR; @@ -267,8 +268,9 @@ public File getHistoryFile() { public PitConfiguration getConfiguration() { IPreferenceStore preferenceStore = getPreferenceStore(); - String executionMode = preferenceStore.getString(PIT_EXECUTION_MODE); - String mutators = preferenceStore.getString(PIT_MUTATORS); + String executionMode = preferenceStore.getString(EXECUTION_MODE); + String mutatorGroup = preferenceStore.getString(MUTATOR_GROUP); + String mutators = preferenceStore.getString(INDIVIDUAL_MUTATORS); boolean parallelRun = preferenceStore.getBoolean(RUN_IN_PARALLEL); boolean incrementalAnalysis = preferenceStore.getBoolean(INCREMENTAL_ANALYSIS); String excludedClasses = preferenceStore.getString(EXCLUDED_CLASSES); @@ -292,20 +294,25 @@ public PitConfiguration getConfiguration() { break; } } - for (PitMutators mutatorMode : PitMutators.values()) { - if (mutatorMode.getId().equals(mutators)) { - builder.withMutators(mutatorMode.toString()); - break; - } + + if (mutatorGroup.equals(Mutators.CUSTOM.name())) { + builder.withMutators(mutators); + } else { + builder.withMutators(mutatorGroup); } + return builder.build(); } public void setExecutionMode(PitExecutionMode pitExecutionMode) { - getPreferenceStore().setValue(PIT_EXECUTION_MODE, pitExecutionMode.getId()); + getPreferenceStore().setValue(EXECUTION_MODE, pitExecutionMode.getId()); + } + + public void setDefaultMutatorGroup(Mutators mutators) { + getPreferenceStore().setValue(MUTATOR_GROUP, mutators.name()); } - public void setMutators(PitMutators mutators) { - getPreferenceStore().setValue(PIT_MUTATORS, mutators.getId()); + public String getDefaultMutatorGroup() { + return getPreferenceStore().getString(MUTATOR_GROUP); } } diff --git a/bundles/org.pitest.pitclipse.core/src/org/pitest/pitclipse/core/preferences/PitPreferences.java b/bundles/org.pitest.pitclipse.core/src/org/pitest/pitclipse/core/preferences/PitPreferences.java index 355856a8..6c2a2d9c 100644 --- a/bundles/org.pitest.pitclipse.core/src/org/pitest/pitclipse/core/preferences/PitPreferences.java +++ b/bundles/org.pitest.pitclipse.core/src/org/pitest/pitclipse/core/preferences/PitPreferences.java @@ -1,12 +1,12 @@ /******************************************************************************* - * Copyright 2012-2019 Phil Glover and contributors - * + * Copyright 2012-2021 Phil Glover and contributors + * * 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 @@ -20,25 +20,39 @@ * Constants used to deal with Pitclipse's preferences. */ public final class PitPreferences { + public static final String MUTATORS_LABEL = "Mutators"; + public static final String MUTATOR_GROUP = "pitMutators"; - public static final String PIT_MUTATORS = "pitMutators"; + public static final String INDIVIDUAL_MUTATORS = "pitIndividualMutators"; - public static final String USE_INCREMENTAL_ANALYSIS = "Use &incremental analysis"; - public static final String EXCLUDE_CLASSES_FROM_PIT = "E&xcluded classes (e.g.*IntTest)"; - public static final String MUTATION_TESTS_RUN_IN_PARALLEL = "Mutation tests run in para&llel"; - public static final String EXCLUDE_METHODS_FROM_PIT = "Excluded &methods (e.g.*toString*)"; - public static final String AVOID_CALLS_FROM_PIT = "&Avoid calls to"; - public static final String PIT_TIMEOUT = "Pit Ti&meout"; - public static final String PIT_TIMEOUT_FACTOR = "Timeout &Factor"; - public static final String EXCLUDED_METHODS = "excludedMethods"; - public static final String AVOID_CALLS_TO = "avoidCallsTo"; - public static final String EXCLUDED_CLASSES = "excludedClasses"; + public static final String INCREMENTAL_ANALYSIS_LABEL = "Use &incremental analysis"; public static final String INCREMENTAL_ANALYSIS = "incrementalAnalysis"; - public static final String PIT_EXECUTION_MODE = "pitExecutionMode"; + + public static final String EXCLUDED_CLASSES_LABEL = "E&xcluded classes (e.g.*IntTest)"; + public static final String EXCLUDED_CLASSES = "excludedClasses"; + + public static final String RUN_IN_PARALLEL_LABEL = "Mutation tests run in para&llel"; public static final String RUN_IN_PARALLEL = "runInParallel"; + + public static final String EXCLUDED_METHODS_LABEL = "Excluded &methods (e.g.*toString*)"; + public static final String EXCLUDED_METHODS = "excludedMethods"; + + public static final String AVOID_CALLS_TO_LABEL = "&Avoid calls to"; + public static final String AVOID_CALLS_TO = "avoidCallsTo"; + + public static final String TIMEOUT_LABEL = "Pit Ti&meout"; public static final String TIMEOUT = "pitTimeout"; + + public static final String TIMEOUT_FACTOR_LABEL = "Timeout &Factor"; public static final String TIMEOUT_FACTOR = "pitTimeoutFactor"; - + + + public static final String EXECUTION_MODE_LABEL = "Pit execution scope"; + public static final String EXECUTION_MODE = "pitExecutionMode"; + + public static final String PREFERENCE_DESCRIPTION_LABEL = "Pitclipse Preferences"; + public static final String MUTATORS_DESCRIPTION_LABEL = "Mutator Preferences"; + private PitPreferences() { // utility class should not be instantiated } diff --git a/bundles/org.pitest.pitclipse.core/src/org/pitest/pitclipse/core/preferences/PreferenceInitializer.java b/bundles/org.pitest.pitclipse.core/src/org/pitest/pitclipse/core/preferences/PreferenceInitializer.java index 8681404d..4d04f0e9 100644 --- a/bundles/org.pitest.pitclipse.core/src/org/pitest/pitclipse/core/preferences/PreferenceInitializer.java +++ b/bundles/org.pitest.pitclipse.core/src/org/pitest/pitclipse/core/preferences/PreferenceInitializer.java @@ -24,7 +24,7 @@ import static org.pitest.pitclipse.core.preferences.PitPreferences.AVOID_CALLS_TO; import static org.pitest.pitclipse.core.preferences.PitPreferences.EXCLUDED_CLASSES; import static org.pitest.pitclipse.core.preferences.PitPreferences.INCREMENTAL_ANALYSIS; -import static org.pitest.pitclipse.core.preferences.PitPreferences.PIT_EXECUTION_MODE; +import static org.pitest.pitclipse.core.preferences.PitPreferences.EXECUTION_MODE; import static org.pitest.pitclipse.core.preferences.PitPreferences.RUN_IN_PARALLEL; import static org.pitest.pitclipse.core.preferences.PitPreferences.TIMEOUT; import static org.pitest.pitclipse.core.preferences.PitPreferences.TIMEOUT_FACTOR; @@ -47,7 +47,7 @@ public class PreferenceInitializer extends AbstractPreferenceInitializer { @Override public void initializeDefaultPreferences() { IPreferenceStore store = PitCoreActivator.getDefault().getPreferenceStore(); - store.setDefault(PIT_EXECUTION_MODE, "containingProject"); + store.setDefault(EXECUTION_MODE, "containingProject"); store.setDefault(RUN_IN_PARALLEL, true); store.setDefault(INCREMENTAL_ANALYSIS, false); store.setDefault(AVOID_CALLS_TO, DEFAULT_AVOID_CALLS_TO_LIST); diff --git a/bundles/org.pitest.pitclipse.launch.ui/META-INF/MANIFEST.MF b/bundles/org.pitest.pitclipse.launch.ui/META-INF/MANIFEST.MF index 38e7c3e2..45817b85 100644 --- a/bundles/org.pitest.pitclipse.launch.ui/META-INF/MANIFEST.MF +++ b/bundles/org.pitest.pitclipse.launch.ui/META-INF/MANIFEST.MF @@ -16,6 +16,8 @@ Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.11.1,4.0.0)", org.pitest.pitclipse.launch, org.eclipse.jface;bundle-version="[3.11.1,4.0.0)", org.eclipse.ui.workbench;bundle-version="[3.107.1,4.0.0)", - org.eclipse.jdt.debug.ui;bundle-version="[3.7.101,4.0.0)" -Import-Package: com.google.common.collect;version="21.0.0" + org.eclipse.jdt.debug.ui;bundle-version="[3.7.101,4.0.0)", + org.pitest.pitclipse.ui;bundle-version="2.1.2" +Import-Package: com.google.common.collect;version="21.0.0", + org.pitest.mutationtest.engine.gregor.config Export-Package: org.pitest.pitclipse.launch.ui diff --git a/bundles/org.pitest.pitclipse.launch.ui/src/org/pitest/pitclipse/launch/ui/PitArgumentsTab.java b/bundles/org.pitest.pitclipse.launch.ui/src/org/pitest/pitclipse/launch/ui/PitArgumentsTab.java index 91d40d2a..7114b0d3 100644 --- a/bundles/org.pitest.pitclipse.launch.ui/src/org/pitest/pitclipse/launch/ui/PitArgumentsTab.java +++ b/bundles/org.pitest.pitclipse.launch.ui/src/org/pitest/pitclipse/launch/ui/PitArgumentsTab.java @@ -1,12 +1,12 @@ /******************************************************************************* - * Copyright 2012-2019 Phil Glover and contributors - * + * Copyright 2012-2021 Phil Glover and contributors + * * 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 @@ -16,6 +16,21 @@ package org.pitest.pitclipse.launch.ui; +import static org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME; +import static org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME; +import static org.eclipse.swt.layout.GridData.FILL_HORIZONTAL; +import static org.pitest.pitclipse.core.preferences.PitPreferences.AVOID_CALLS_TO_LABEL; +import static org.pitest.pitclipse.core.preferences.PitPreferences.EXCLUDED_CLASSES_LABEL; +import static org.pitest.pitclipse.core.preferences.PitPreferences.EXCLUDED_METHODS_LABEL; +import static org.pitest.pitclipse.core.preferences.PitPreferences.INCREMENTAL_ANALYSIS_LABEL; +import static org.pitest.pitclipse.core.preferences.PitPreferences.RUN_IN_PARALLEL_LABEL; +import static org.pitest.pitclipse.launch.PitLaunchArgumentsConstants.ATTR_TEST_CONTAINER; +import static org.pitest.pitclipse.launch.config.LaunchConfigurationWrapper.ATTR_AVOID_CALLS_TO; +import static org.pitest.pitclipse.launch.config.LaunchConfigurationWrapper.ATTR_EXCLUDE_CLASSES; +import static org.pitest.pitclipse.launch.config.LaunchConfigurationWrapper.ATTR_EXCLUDE_METHODS; +import static org.pitest.pitclipse.launch.config.LaunchConfigurationWrapper.ATTR_TEST_INCREMENTALLY; +import static org.pitest.pitclipse.launch.config.LaunchConfigurationWrapper.ATTR_TEST_IN_PARALLEL; + import org.eclipse.core.runtime.CoreException; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; @@ -29,35 +44,31 @@ import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; import org.pitest.pitclipse.core.PitCoreActivator; import org.pitest.pitclipse.runner.config.PitConfiguration; - -import static org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME; -import static org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME; -import static org.eclipse.swt.layout.GridData.FILL_HORIZONTAL; -import static org.pitest.pitclipse.core.preferences.PitPreferences.AVOID_CALLS_FROM_PIT; -import static org.pitest.pitclipse.core.preferences.PitPreferences.EXCLUDE_CLASSES_FROM_PIT; -import static org.pitest.pitclipse.core.preferences.PitPreferences.EXCLUDE_METHODS_FROM_PIT; -import static org.pitest.pitclipse.core.preferences.PitPreferences.MUTATION_TESTS_RUN_IN_PARALLEL; -import static org.pitest.pitclipse.core.preferences.PitPreferences.USE_INCREMENTAL_ANALYSIS; -import static org.pitest.pitclipse.launch.config.LaunchConfigurationWrapper.ATTR_AVOID_CALLS_TO; -import static org.pitest.pitclipse.launch.config.LaunchConfigurationWrapper.ATTR_EXCLUDE_CLASSES; -import static org.pitest.pitclipse.launch.config.LaunchConfigurationWrapper.ATTR_EXCLUDE_METHODS; -import static org.pitest.pitclipse.launch.config.LaunchConfigurationWrapper.ATTR_TEST_INCREMENTALLY; -import static org.pitest.pitclipse.launch.config.LaunchConfigurationWrapper.ATTR_TEST_IN_PARALLEL; -import static org.pitest.pitclipse.launch.PitLaunchArgumentsConstants.ATTR_TEST_CONTAINER; +import org.pitest.pitclipse.ui.core.PitUiActivator; /** - * Tab allowing to configure a PIT analyze. + * Tab allowing to configure a PIT analyze. */ public final class PitArgumentsTab extends AbstractLaunchConfigurationTab { + public static final String NAME = "PIT"; private static final int NUMBER_OF_COLUMNS = 3; + public static final String TEST_CLASS_RADIO_TEXT = "Run mutations from a unit test"; + public static final String TEST_CLASS_TEXT = "Test Class:"; + public static final String TEST_DIR_RADIO_TEXT = "Run mutations against a package or directory"; + public static final String TEST_DIR_TEXT = "Directory:"; + public static final String FILTERS_GROUP_TEXT = " Filters "; + public static final String SCOPE_GROUP_TEXT = " Mutation Scope "; + public static final String PROJECT_TEXT = "Project to mutate: "; private Text testClassText; private Text projectText; @@ -71,6 +82,11 @@ public final class PitArgumentsTab extends AbstractLaunchConfigurationTab { private Text excludedMethodsText; private Text avoidCallsTo; + @Override + public Image getImage() { + return PitUiActivator.getDefault().getPitIcon(); + } + @Override public void initializeFrom(ILaunchConfiguration config) { projectText.setText(getAttributeFromConfig(config, ATTR_PROJECT_NAME, "")); @@ -127,43 +143,61 @@ public void createControl(Composite parent) { createSpacer(comp); createProjectWidgets(font, comp); createSpacer(comp); - createTestClassWidgets(font, comp); + createMutationScopeWidgets(font, comp); createSpacer(comp); - createTestDirWidgets(font, comp); + createFilters(font, comp); createSpacer(comp); createPreferences(font, comp); } + private void createMutationScopeWidgets(Font font, Composite comp) { + Group group = new Group(comp, SWT.NONE); + group.setText(SCOPE_GROUP_TEXT); + group.setFont(font); + GridData groupGrid = new GridData(FILL_HORIZONTAL); + groupGrid.horizontalSpan = NUMBER_OF_COLUMNS; + group.setLayoutData(groupGrid); + GridLayout groupLayout = new GridLayout(2, false); + group.setLayout(groupLayout); + + createTestClassWidgets(font, group, groupLayout.numColumns); + createSpacer(group); + createTestDirWidgets(font, group, groupLayout.numColumns); + } + private void createProjectWidgets(Font font, Composite comp) { Label projectLabel = new Label(comp, SWT.NONE); - projectLabel.setText("Project to mutate:"); - GridData gd = new GridData(FILL_HORIZONTAL); + projectLabel.setText(PROJECT_TEXT); + GridData gd = new GridData(); gd.horizontalSpan = 1; projectLabel.setLayoutData(gd); projectLabel.setFont(font); gd = new GridData(FILL_HORIZONTAL); - gd.horizontalSpan = NUMBER_OF_COLUMNS; + // 1 column less to fit label in front of the text field + gd.horizontalSpan = NUMBER_OF_COLUMNS - 1; projectText = new Text(comp, SWT.SINGLE | SWT.BORDER); projectText.setLayoutData(gd); projectText.addModifyListener(new UpdateOnModifyListener()); } - private void createTestClassWidgets(Font font, Composite comp) { - testClassRadioButton = createTestRadioButton(comp, - "Run mutations from a unit test"); + private void createTestClassWidgets(Font font, Composite comp, int columnsInParent) { + testClassRadioButton = createTestRadioButton(comp, TEST_CLASS_RADIO_TEXT); + GridData testClassGrid = new GridData(FILL_HORIZONTAL); + testClassGrid.horizontalSpan = columnsInParent; + testClassRadioButton.setLayoutData(testClassGrid); Label testClassLabel = new Label(comp, SWT.NONE); - testClassLabel.setText("Test Class:"); - GridData labelGrid = new GridData(FILL_HORIZONTAL); + testClassLabel.setText(TEST_CLASS_TEXT); + GridData labelGrid = new GridData(); labelGrid.horizontalIndent = 25; - labelGrid.horizontalSpan = NUMBER_OF_COLUMNS; + labelGrid.horizontalSpan = 1; testClassLabel.setLayoutData(labelGrid); testClassLabel.setFont(font); GridData textGrid = new GridData(FILL_HORIZONTAL); - textGrid.horizontalSpan = NUMBER_OF_COLUMNS; - textGrid.horizontalIndent = 25; + textGrid.horizontalSpan = columnsInParent - 1; + textGrid.grabExcessHorizontalSpace = true; testClassText = new Text(comp, SWT.SINGLE | SWT.BORDER); testClassText.setLayoutData(textGrid); testClassText.addModifyListener(new UpdateOnModifyListener()); @@ -176,61 +210,82 @@ private Button createTestRadioButton(Composite comp, String label) { return button; } - private void createTestDirWidgets(Font font, Composite comp) { - testDirectoryRadioButton = createTestRadioButton(comp, - "Run mutations against a package or directory"); + private void createTestDirWidgets(Font font, Composite comp, int columnsInParent) { + testDirectoryRadioButton = createTestRadioButton(comp, TEST_DIR_RADIO_TEXT); + GridData testDirGrid = new GridData(FILL_HORIZONTAL); + testDirGrid.horizontalSpan = columnsInParent; + testDirectoryRadioButton.setLayoutData(testDirGrid); - GridData labelGrid = new GridData(FILL_HORIZONTAL); + GridData labelGrid = new GridData(); labelGrid.horizontalIndent = 25; - labelGrid.horizontalSpan = NUMBER_OF_COLUMNS; + labelGrid.horizontalSpan = 1; Label testDirectoryLabel = new Label(comp, SWT.NONE); - testDirectoryLabel.setText("Directory:"); + testDirectoryLabel.setText(TEST_DIR_TEXT); testDirectoryLabel.setLayoutData(labelGrid); testDirectoryLabel.setFont(font); GridData textGrid = new GridData(FILL_HORIZONTAL); - textGrid.horizontalSpan = NUMBER_OF_COLUMNS; - textGrid.horizontalIndent = 25; + textGrid.horizontalSpan = columnsInParent - 1; testDirText = new Text(comp, SWT.SINGLE | SWT.BORDER); testDirText.setLayoutData(textGrid); testDirText.addModifyListener(new UpdateOnModifyListener()); } + private void createFilters(Font font, Composite comp) { + Group group = new Group(comp, SWT.NONE); + group.setText(FILTERS_GROUP_TEXT); + group.setFont(font); + GridData groupGrid = new GridData(FILL_HORIZONTAL); + groupGrid.horizontalSpan = NUMBER_OF_COLUMNS; + group.setLayoutData(groupGrid); + GridLayout groupLayout = new GridLayout(1, false); + group.setLayout(groupLayout); + + runInParallel = createNewCheckBox(font, group, groupLayout.numColumns, + RUN_IN_PARALLEL_LABEL); + incrementalAnalysis = createNewCheckBox(font, group, groupLayout.numColumns, + INCREMENTAL_ANALYSIS_LABEL); + } + private void createPreferences(Font font, Composite comp) { - runInParallel = createNewCheckBox(font, comp, - MUTATION_TESTS_RUN_IN_PARALLEL); - incrementalAnalysis = createNewCheckBox(font, comp, - USE_INCREMENTAL_ANALYSIS); - excludedClassesText = createTextPreference(font, comp, - EXCLUDE_CLASSES_FROM_PIT); - excludedMethodsText = createTextPreference(font, comp, - EXCLUDE_METHODS_FROM_PIT); - avoidCallsTo = createTextPreference(font, comp, AVOID_CALLS_FROM_PIT); + Group misc = new Group(comp, SWT.NONE); + misc.setText(" Preferences "); + misc.setFont(font); + GridData miscGrid = new GridData(FILL_HORIZONTAL); + miscGrid.horizontalSpan = NUMBER_OF_COLUMNS; + misc.setLayoutData(miscGrid); + GridLayout miscLayout = new GridLayout(2, false); + misc.setLayout(miscLayout); + + excludedClassesText = createTextPreference(font, misc, miscLayout.numColumns, + EXCLUDED_CLASSES_LABEL); + excludedMethodsText = createTextPreference(font, misc, miscLayout.numColumns, + EXCLUDED_METHODS_LABEL); + avoidCallsTo = createTextPreference(font, misc, miscLayout.numColumns, + AVOID_CALLS_TO_LABEL); } - private Text createTextPreference(Font font, Composite comp, String label) { - GridData labelGrid = new GridData(FILL_HORIZONTAL); - labelGrid.horizontalIndent = 25; - labelGrid.horizontalSpan = NUMBER_OF_COLUMNS; + private Text createTextPreference(Font font, Composite comp, int columnsInParent, String label) { + GridData labelGrid = new GridData(); + labelGrid.horizontalSpan = 1; Label testDirectoryLabel = new Label(comp, SWT.NONE); testDirectoryLabel.setText(label); testDirectoryLabel.setLayoutData(labelGrid); testDirectoryLabel.setFont(font); GridData textGrid = new GridData(FILL_HORIZONTAL); - textGrid.horizontalSpan = NUMBER_OF_COLUMNS; - textGrid.horizontalIndent = 25; + textGrid.horizontalSpan = columnsInParent - 1; Text textBox = new Text(comp, SWT.SINGLE | SWT.BORDER); textBox.setLayoutData(textGrid); textBox.addModifyListener(new UpdateOnModifyListener()); return textBox; } - private Button createNewCheckBox(Font font, Composite comp, String label) { + private Button createNewCheckBox(Font font, Composite comp, int columnsInParent, String label) { Button checkBox = new Button(comp, SWT.CHECK); checkBox.setText(label); GridData labelGrid = new GridData(FILL_HORIZONTAL); - labelGrid.horizontalSpan = NUMBER_OF_COLUMNS; + labelGrid.horizontalSpan = columnsInParent - 1; checkBox.setLayoutData(labelGrid); checkBox.setFont(font); return checkBox; @@ -238,7 +293,7 @@ private Button createNewCheckBox(Font font, Composite comp, String label) { @Override public String getName() { - return "PIT"; + return NAME; } @Override @@ -278,7 +333,7 @@ public void setDefaults(ILaunchConfigurationWorkingCopy workingCopy) { */ } - public String getAttributeFromConfig(ILaunchConfiguration config, + public static String getAttributeFromConfig(ILaunchConfiguration config, String attribute, String defaultValue) { String result = defaultValue; try { @@ -289,7 +344,7 @@ public String getAttributeFromConfig(ILaunchConfiguration config, return result; } - public boolean getBooleanAttributeFromConfig(ILaunchConfiguration config, + public static boolean getBooleanAttributeFromConfig(ILaunchConfiguration config, String attribute, boolean defaultValue) { boolean result = defaultValue; try { diff --git a/bundles/org.pitest.pitclipse.launch.ui/src/org/pitest/pitclipse/launch/ui/PitLaunchConfigurationTabGroup.java b/bundles/org.pitest.pitclipse.launch.ui/src/org/pitest/pitclipse/launch/ui/PitLaunchConfigurationTabGroup.java index 2310f0ea..ed99ae22 100644 --- a/bundles/org.pitest.pitclipse.launch.ui/src/org/pitest/pitclipse/launch/ui/PitLaunchConfigurationTabGroup.java +++ b/bundles/org.pitest.pitclipse.launch.ui/src/org/pitest/pitclipse/launch/ui/PitLaunchConfigurationTabGroup.java @@ -32,6 +32,7 @@ public class PitLaunchConfigurationTabGroup extends AbstractLaunchConfigurationT public void createTabs(ILaunchConfigurationDialog dialog, String mode) { final ILaunchConfigurationTab[] tabs = new ILaunchConfigurationTab[] { new PitArgumentsTab(), + new PitMutatorsTab(), new JavaArgumentsTab(), new JavaJRETab(), new JavaClasspathTab(), diff --git a/bundles/org.pitest.pitclipse.launch.ui/src/org/pitest/pitclipse/launch/ui/PitLaunchUiActivator.java b/bundles/org.pitest.pitclipse.launch.ui/src/org/pitest/pitclipse/launch/ui/PitLaunchUiActivator.java index 433890bf..4620694c 100644 --- a/bundles/org.pitest.pitclipse.launch.ui/src/org/pitest/pitclipse/launch/ui/PitLaunchUiActivator.java +++ b/bundles/org.pitest.pitclipse.launch.ui/src/org/pitest/pitclipse/launch/ui/PitLaunchUiActivator.java @@ -25,6 +25,8 @@ public class PitLaunchUiActivator extends AbstractUIPlugin { + public static String PLUGIN_ID = "org.pitest.pitclipse.launch.ui"; + private static PitLaunchUiActivator plugin; @Override @@ -32,6 +34,10 @@ public void start(BundleContext context) throws Exception { super.start(context); plugin = this; } + + public static PitLaunchUiActivator getInstance() { + return plugin; + } public static Shell getActiveWorkbenchShell() { IWorkbenchWindow workBenchWindow = getActiveWorkbenchWindow(); diff --git a/bundles/org.pitest.pitclipse.launch.ui/src/org/pitest/pitclipse/launch/ui/PitMutatorsTab.java b/bundles/org.pitest.pitclipse.launch.ui/src/org/pitest/pitclipse/launch/ui/PitMutatorsTab.java new file mode 100644 index 00000000..0ce58d01 --- /dev/null +++ b/bundles/org.pitest.pitclipse.launch.ui/src/org/pitest/pitclipse/launch/ui/PitMutatorsTab.java @@ -0,0 +1,363 @@ +/******************************************************************************* + * Copyright 2021 Jonas Kutscha and contributors + * + * 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.pitclipse.launch.ui; + +import static org.pitest.pitclipse.core.preferences.PitPreferences.INDIVIDUAL_MUTATORS; +import static org.pitest.pitclipse.core.preferences.PitPreferences.MUTATOR_GROUP; + +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; +import org.eclipse.debug.ui.AbstractLaunchConfigurationTab; +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.layout.GridLayoutFactory; +import org.eclipse.jface.viewers.ArrayContentProvider; +import org.eclipse.jface.viewers.CellLabelProvider; +import org.eclipse.jface.viewers.CheckboxTableViewer; +import org.eclipse.jface.viewers.TableViewerColumn; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerCell; +import org.eclipse.jface.viewers.ViewerFilter; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Link; +import org.pitest.mutationtest.engine.gregor.config.Mutator; +import org.pitest.pitclipse.core.Mutators; +import org.pitest.pitclipse.core.PitCoreActivator; +import org.pitest.pitclipse.runner.config.PitConfiguration; +import org.pitest.pitclipse.ui.core.PitUiActivator; +import org.pitest.pitclipse.ui.utils.LinkSelectionAdapter; +import org.pitest.pitclipse.ui.utils.PitclipseUiUtils; + +/** + * Tab allowing to configure a PIT analyze. + * @author Jonas Kutscha + */ +public final class PitMutatorsTab extends AbstractLaunchConfigurationTab { + public static final String NAME = "Mutators"; + + private static final int NUMBER_OF_COLUMNS = Mutators.getMainGroup().size() + 2; + private static final String DESCRIPTION_TEXT = "Select the mutators used to alter the code."; + private static final String MUTATOR_LINK_TEXT = "See the documentation on Pitest.org"; + private static final String MUTATOR_LINK = "https://pitest.org/quickstart/mutators/"; + public static final String CUSTOM_MUTATOR_RADIO_TEXT = "Mutators selected below"; + private static final String COLUMN_DESCRIPTION = "Description"; + private static final String COLUMN_NAME = "Name"; + private static final String NO_DESCRIPTION_TEXT = "No description found yet."; + private static final String ERROR_MESSAGE = "At least one mutator or mutator group needs to be selected!"; + private String currentMutatorGroup; + private CheckboxTableViewer mutatorsTable; + private Button customMutatorsButton; + private Button[] groupButtons; + private Composite mainComp; + + @Override + public String getName() { + return NAME; + } + + @Override + public Image getImage() { + return PitUiActivator.getDefault().getPitIcon(); + } + + @Override + public void dispose() { + PitclipseUiUtils.disposeSafely(mainComp); + // always call super.dispose() last, if dispose() is overridden. + super.dispose(); + } + + @Override + public void initializeFrom(ILaunchConfiguration config) { + PitConfiguration preferences = PitCoreActivator.getDefault().getConfiguration(); + currentMutatorGroup = PitArgumentsTab.getAttributeFromConfig(config, MUTATOR_GROUP, preferences.getMutators()); + if (!updateSelectionOfGroup(currentMutatorGroup)) { + // no selection was made, because no match of data + // select custom mutators button + customMutatorsButton.setSelection(true); + } + // restore checked mutators + intializeMutatorsTable(config); + disableTableIfUnused(); + + } + + private void intializeMutatorsTable(ILaunchConfiguration config) { + final String individualMutators = PitArgumentsTab.getAttributeFromConfig(config, INDIVIDUAL_MUTATORS, ""); + if (individualMutators.isEmpty()) { + // no mutators where set, use defaults + for (String mutator : Mutators.getDefaultMutators()) { + mutatorsTable.setChecked(mutator, true); + } + } else { + for (String mutator : individualMutators.split(",")) { + mutatorsTable.setChecked(mutator, true); + } + } + } + + @Override + public void createControl(Composite parent) { + mainComp = new Composite(parent, SWT.NONE); + setControl(mainComp); + GridLayoutFactory.swtDefaults().numColumns(2).applyTo(mainComp); + Font font = parent.getFont(); + mainComp.setFont(font); + + createDescription(mainComp); + addSeparator(mainComp); + createSpacer(mainComp); + createMutatorGroupsWidgets(font, mainComp); + createSpacer(mainComp); + createMutatorsTable(mainComp); + + disableTableIfUnused(); + setDirty(false); + mainComp.pack(); + } + + /** + * Creates an description what mutants are and prvides a link to the + * documentation of pitest.org + * @param parent where to add the description + */ + private void createDescription(Composite parent) { + final Label descriptionLabel = new Label(parent, SWT.NONE); + descriptionLabel.setText(DESCRIPTION_TEXT); + GridDataFactory.swtDefaults().indent(5, 0).applyTo(descriptionLabel); + Link link = new Link(parent, SWT.NONE); + link.setText("" + MUTATOR_LINK_TEXT + ""); + link.addSelectionListener(new LinkSelectionAdapter(MUTATOR_LINK)); + GridDataFactory.swtDefaults().applyTo(link); + } + + /** + * Creates an radio Button for each group present in MutatorGroups and adds one + * for custom selection of mutants + * @param font which is used for text + * @param parent where to add the widget + */ + private void createMutatorGroupsWidgets(Font font, Composite parent) { + // add own composite to group options closer together + final Composite grouopComposite = new Composite(parent, SWT.NONE); + GridDataFactory.swtDefaults().span(NUMBER_OF_COLUMNS, 1).applyTo(grouopComposite); + GridLayoutFactory.swtDefaults().numColumns(NUMBER_OF_COLUMNS).applyTo(grouopComposite); + final Label mutateWithLabel = new Label(grouopComposite, SWT.NONE); + mutateWithLabel.setFont(font); + mutateWithLabel.setText("Mutate with: "); + GridDataFactory.swtDefaults().applyTo(mutateWithLabel); + + groupButtons = new Button[Mutators.getMainGroup().size()]; + int i = 0; + for (Mutators mutatorGroup : Mutators.getMainGroup()) { + Button button = new Button(grouopComposite, SWT.RADIO); + button.setText(mutatorGroup.getDescriptor()); + button.setData(mutatorGroup.name()); + button.setFont(font); + button.addSelectionListener(new UpdateDialogOnCurrentMutatorGroupChanged()); + groupButtons[i++] = button; + GridDataFactory.swtDefaults().applyTo(button); + } + customMutatorsButton = new Button(grouopComposite, SWT.RADIO); + customMutatorsButton.setText(CUSTOM_MUTATOR_RADIO_TEXT); + // set data of button to name of the mutator custom + customMutatorsButton.setData(Mutators.CUSTOM.name()); + customMutatorsButton.setFont(font); + customMutatorsButton.addSelectionListener(new UpdateDialogOnCurrentMutatorGroupChanged()); + GridDataFactory.swtDefaults().applyTo(customMutatorsButton); + } + + /** + * Called each time a mutator group is selected. If this mutator group was not + * previously selected, the launch configuration dialog is updated and the table + * may be disabled if unused. + */ + private class UpdateDialogOnCurrentMutatorGroupChanged extends SelectionAdapter { + @Override + public void widgetSelected(SelectionEvent event) { + final String old = currentMutatorGroup; + currentMutatorGroup = (String) event.widget.getData(); + if (((Button) event.widget).getSelection() && !old.equals(currentMutatorGroup)) { + updateLaunchConfigurationDialog(); + disableTableIfUnused(); + } + } + } + + /** + * Creates a group containing a table showing available Execution Hooks. + * Execution Hooks are found from extension points. Each execution hook provide + * a check box that can be used to activate / deactivate the hook. + */ + private void createMutatorsTable(Composite parent) { + mutatorsTable = CheckboxTableViewer.newCheckList(parent, SWT.MULTI | SWT.BORDER); + mutatorsTable.getTable().setHeaderVisible(true); + mutatorsTable.setContentProvider(new ArrayContentProvider()); + // filter out groups which are present in the main group + mutatorsTable.setFilters(new ViewerFilter() { + @Override + public boolean select(Viewer viewer, Object parentElement, Object element) { + try { + return !Mutators.getMainGroup().contains(Mutators.valueOf((String) element)); + } catch (IllegalArgumentException e) { + // not in predefined mutators, is okay + return true; + } + } + }); + GridDataFactory.swtDefaults().grab(false, false).span(NUMBER_OF_COLUMNS, 1).applyTo(mutatorsTable.getTable()); + + TableViewerColumn colName = new TableViewerColumn(mutatorsTable, SWT.FILL); + colName.getColumn().setText(COLUMN_NAME); + colName.setLabelProvider(new CellLabelProvider() { + @Override + public void update(ViewerCell cell) { + final String name = (String) cell.getElement(); + try { + final Mutators info = Mutators.valueOf(name); + cell.setText(info.getDescriptor()); + } catch (IllegalArgumentException e) { + // if no info in our enum is present use default + cell.setText(name); + } + } + }); + + TableViewerColumn colDescription = new TableViewerColumn(mutatorsTable, SWT.FILL); + colDescription.getColumn().setText(COLUMN_DESCRIPTION); + colDescription.setLabelProvider(new CellLabelProvider() { + @Override + public void update(ViewerCell cell) { + final String name = (String) cell.getElement(); + try { + final Mutators info = Mutators.valueOf(name); + cell.setText(info.getDescription()); + } catch (IllegalArgumentException e) { + // if no info in our enum is present use default + cell.setText(NO_DESCRIPTION_TEXT); + } + } + }); + mutatorsTable.setInput(Mutator.allMutatorIds()); + colName.getColumn().pack(); + colDescription.getColumn().pack(); + mutatorsTable.getTable().setEnabled(true); + // Update the tab when a hook is activated / deactivated + mutatorsTable.addCheckStateListener(event -> updateLaunchConfigurationDialog()); + } + + private void disableTableIfUnused() { + mutatorsTable.getTable().setEnabled(customMutatorsButton.getSelection()); + } + + protected static void addSeparator(Composite parent) { + Label separator = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL); + GridDataFactory.fillDefaults().span(NUMBER_OF_COLUMNS, 1).applyTo(separator); + } + + @Override + public void performApply(ILaunchConfigurationWorkingCopy config) { + config.setAttribute(INDIVIDUAL_MUTATORS, getIndividualMutators()); + config.setAttribute(MUTATOR_GROUP, currentMutatorGroup); + try { + PitMigrationDelegate.mapResources(config); + } catch (CoreException ce) { + setErrorMessage(ce.getStatus().getMessage()); + } + } + + private String getIndividualMutators() { + return Stream.of(mutatorsTable.getCheckedElements()) + .map(Object::toString) + .collect(Collectors.joining(",")); + } + + @Override + public void setDefaults(ILaunchConfigurationWorkingCopy workingCopy) { + // Intentionally left empty + } + + private void createSpacer(Composite comp) { + Label label = new Label(comp, SWT.NONE); + GridData gd = new GridData(); + gd.horizontalSpan = NUMBER_OF_COLUMNS; + label.setLayoutData(gd); + } + + /** + * Selects the button that conforms to the given value. + * @param selectedValue the selected value + * @param buttons array of buttons to select one + * @return true, if a button was selected + */ + private boolean updateSelectionOfGroup(String value) { + boolean found = false; + for (Button button : groupButtons) { + boolean selection = false; + if (button.getData().equals(value)) { + selection = true; + found = true; + } + button.setSelection(selection); + } + + return found; + } + + /** + * @return true, if one of the groups from PIT is selected.
+ * false, if individual mutators are selected. + */ + private boolean isBasicMutatorGroup() { + return !customMutatorsButton.getSelection(); + } + + /** + * Only allow save, if one of the main mutator groups is selected or at least + * one mutator is selected inside the mutatorTable + */ + @Override + public boolean canSave() { + return isBasicMutatorGroup() || mutatorsTable.getCheckedElements().length > 0; + } + + @Override + public boolean isValid(ILaunchConfiguration launchConfig) { + return canSave(); + } + + @Override + protected void updateLaunchConfigurationDialog() { + if (canSave()) { + setErrorMessage(null); + } else { + setErrorMessage(ERROR_MESSAGE); + } + super.updateLaunchConfigurationDialog(); + } +} diff --git a/bundles/org.pitest.pitclipse.launch/src/org/pitest/pitclipse/launch/config/LaunchConfigurationWrapper.java b/bundles/org.pitest.pitclipse.launch/src/org/pitest/pitclipse/launch/config/LaunchConfigurationWrapper.java index 4dcf9ffd..a22335ae 100644 --- a/bundles/org.pitest.pitclipse.launch/src/org/pitest/pitclipse/launch/config/LaunchConfigurationWrapper.java +++ b/bundles/org.pitest.pitclipse.launch/src/org/pitest/pitclipse/launch/config/LaunchConfigurationWrapper.java @@ -16,8 +16,15 @@ package org.pitest.pitclipse.launch.config; -import com.google.common.base.Splitter; -import com.google.common.collect.ImmutableList; +import static org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME; +import static org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME; +import static org.pitest.pitclipse.core.PitCoreActivator.getDefault; +import static org.pitest.pitclipse.core.preferences.PitPreferences.INDIVIDUAL_MUTATORS; +import static org.pitest.pitclipse.core.preferences.PitPreferences.MUTATOR_GROUP; + +import java.io.File; +import java.math.BigDecimal; +import java.util.List; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; @@ -28,6 +35,7 @@ import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaCore; +import org.pitest.pitclipse.core.Mutators; import org.pitest.pitclipse.core.launch.ProjectClosedException; import org.pitest.pitclipse.core.launch.ProjectNotFoundException; import org.pitest.pitclipse.core.launch.TestClassNotFoundException; @@ -35,13 +43,8 @@ import org.pitest.pitclipse.runner.PitOptions.PitOptionsBuilder; import org.pitest.pitclipse.runner.config.PitConfiguration; -import java.io.File; -import java.math.BigDecimal; -import java.util.List; - -import static org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME; -import static org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME; -import static org.pitest.pitclipse.core.PitCoreActivator.getDefault; +import com.google.common.base.Splitter; +import com.google.common.collect.ImmutableList; public class LaunchConfigurationWrapper { @@ -113,7 +116,7 @@ public boolean isTestLaunch() throws CoreException { public PitOptions getPitOptions() throws CoreException { return getPitOptionsBuilder().build(); } - + public PitOptions.PitOptionsBuilder getPitOptionsBuilder() throws CoreException { List classPath = getClassesFromProject(); List sourceDirs = getSourceDirsForProject(); @@ -122,7 +125,7 @@ public PitOptions.PitOptionsBuilder getPitOptionsBuilder() throws CoreException List excludedClasses = getExcludedClasses(); List excludedMethods = getExcludedMethods(); List avoidCallsTo = getAvoidCallsTo(); - List mutators = getMutators(); + String mutators = getMutators(); int timeout = pitConfiguration.getTimeout(); BigDecimal timeoutFactor = pitConfiguration.getTimeoutFactor(); @@ -260,7 +263,19 @@ public List getMutatedProjects() throws CoreException { return projectFinder.getProjects(this); } - private List getMutators() { - return ImmutableList.of(pitConfiguration.getMutators()); + private String getMutators() throws CoreException { + final String mutators; + if (launchConfig.hasAttribute(MUTATOR_GROUP)) { + if (launchConfig.getAttribute(MUTATOR_GROUP, "").equals(Mutators.CUSTOM.name())) { + // if we have custom mutators set, get them + mutators = launchConfig.getAttribute(INDIVIDUAL_MUTATORS, ""); + } else { + // use group + mutators = launchConfig.getAttribute(MUTATOR_GROUP, ""); + } + } else { + mutators = pitConfiguration.getMutators(); + } + return mutators; } } diff --git a/bundles/org.pitest.pitclipse.preferences.ui/src/org/pitest/pitclipse/preferences/ui/PitMutatorsPreferencePage.java b/bundles/org.pitest.pitclipse.preferences.ui/src/org/pitest/pitclipse/preferences/ui/PitMutatorsPreferencePage.java index 6dd684e8..25538ee2 100644 --- a/bundles/org.pitest.pitclipse.preferences.ui/src/org/pitest/pitclipse/preferences/ui/PitMutatorsPreferencePage.java +++ b/bundles/org.pitest.pitclipse.preferences.ui/src/org/pitest/pitclipse/preferences/ui/PitMutatorsPreferencePage.java @@ -16,21 +16,25 @@ package org.pitest.pitclipse.preferences.ui; +import static org.pitest.pitclipse.core.preferences.PitPreferences.MUTATOR_GROUP; +import static org.pitest.pitclipse.core.preferences.PitPreferences.MUTATORS_DESCRIPTION_LABEL; +import static org.pitest.pitclipse.core.preferences.PitPreferences.MUTATORS_LABEL; + +import java.util.List; + import org.eclipse.jface.preference.FieldEditorPreferencePage; import org.eclipse.jface.preference.RadioGroupFieldEditor; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchPreferencePage; +import org.pitest.pitclipse.core.Mutators; import org.pitest.pitclipse.core.PitCoreActivator; -import org.pitest.pitclipse.core.PitMutators; - -import static org.pitest.pitclipse.core.preferences.PitPreferences.PIT_MUTATORS; public class PitMutatorsPreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage { public PitMutatorsPreferencePage() { super(GRID); setPreferenceStore(PitCoreActivator.getDefault().getPreferenceStore()); - setDescription("Mutator Preferences"); + setDescription(MUTATORS_DESCRIPTION_LABEL); } @Override @@ -39,14 +43,17 @@ public void createFieldEditors() { } private void createExecutionModeRadioButtons() { - PitMutators[] values = PitMutators.values(); - String[][] mutatorValues = new String[values.length][2]; - for (int i = 0; i < values.length; i++) { - mutatorValues[i] = new String[] { values[i].getLabel(), values[i].getId() }; + List values = Mutators.getMainGroup(); + String[][] mutatorValues = new String[values.size()][2]; + int i = 0; + for (Mutators mutator : values) { + mutatorValues[i++] = new String[] { mutator.getDescriptor(), mutator.name() }; } - addField(new RadioGroupFieldEditor(PIT_MUTATORS, "Mutators", 1, mutatorValues, getFieldEditorParent())); + addField(new RadioGroupFieldEditor(MUTATOR_GROUP, MUTATORS_LABEL, 1, mutatorValues, getFieldEditorParent())); } @Override - public void init(IWorkbench workbench) { /* Intentionally Empty */ } + public void init(IWorkbench workbench) { + // Intentionally Empty + } } diff --git a/bundles/org.pitest.pitclipse.preferences.ui/src/org/pitest/pitclipse/preferences/ui/PitPreferencePage.java b/bundles/org.pitest.pitclipse.preferences.ui/src/org/pitest/pitclipse/preferences/ui/PitPreferencePage.java index 28ea1f09..35fb1d9a 100644 --- a/bundles/org.pitest.pitclipse.preferences.ui/src/org/pitest/pitclipse/preferences/ui/PitPreferencePage.java +++ b/bundles/org.pitest.pitclipse.preferences.ui/src/org/pitest/pitclipse/preferences/ui/PitPreferencePage.java @@ -25,21 +25,7 @@ import org.pitest.pitclipse.core.PitCoreActivator; import org.pitest.pitclipse.runner.config.PitExecutionMode; -import static org.pitest.pitclipse.core.preferences.PitPreferences.AVOID_CALLS_FROM_PIT; -import static org.pitest.pitclipse.core.preferences.PitPreferences.AVOID_CALLS_TO; -import static org.pitest.pitclipse.core.preferences.PitPreferences.EXCLUDED_CLASSES; -import static org.pitest.pitclipse.core.preferences.PitPreferences.EXCLUDED_METHODS; -import static org.pitest.pitclipse.core.preferences.PitPreferences.EXCLUDE_CLASSES_FROM_PIT; -import static org.pitest.pitclipse.core.preferences.PitPreferences.EXCLUDE_METHODS_FROM_PIT; -import static org.pitest.pitclipse.core.preferences.PitPreferences.INCREMENTAL_ANALYSIS; -import static org.pitest.pitclipse.core.preferences.PitPreferences.MUTATION_TESTS_RUN_IN_PARALLEL; -import static org.pitest.pitclipse.core.preferences.PitPreferences.PIT_EXECUTION_MODE; -import static org.pitest.pitclipse.core.preferences.PitPreferences.PIT_TIMEOUT; -import static org.pitest.pitclipse.core.preferences.PitPreferences.PIT_TIMEOUT_FACTOR; -import static org.pitest.pitclipse.core.preferences.PitPreferences.RUN_IN_PARALLEL; -import static org.pitest.pitclipse.core.preferences.PitPreferences.TIMEOUT; -import static org.pitest.pitclipse.core.preferences.PitPreferences.TIMEOUT_FACTOR; -import static org.pitest.pitclipse.core.preferences.PitPreferences.USE_INCREMENTAL_ANALYSIS; +import static org.pitest.pitclipse.core.preferences.PitPreferences.*; import static org.pitest.pitclipse.runner.config.PitExecutionMode.values; /** @@ -58,7 +44,7 @@ public class PitPreferencePage extends FieldEditorPreferencePage implements IWor public PitPreferencePage() { super(GRID); setPreferenceStore(PitCoreActivator.getDefault().getPreferenceStore()); - setDescription("Pitclipse Preferences"); + setDescription(PREFERENCE_DESCRIPTION_LABEL); } /** @@ -79,31 +65,31 @@ public void createFieldEditors() { } private void createAvoidCallsToField() { - addField(new StringFieldEditor(AVOID_CALLS_TO, AVOID_CALLS_FROM_PIT, getFieldEditorParent())); + addField(new StringFieldEditor(AVOID_CALLS_TO, AVOID_CALLS_TO_LABEL, getFieldEditorParent())); } private void createExcludeClassesField() { - addField(new StringFieldEditor(EXCLUDED_CLASSES, EXCLUDE_CLASSES_FROM_PIT, getFieldEditorParent())); + addField(new StringFieldEditor(EXCLUDED_CLASSES, EXCLUDED_CLASSES_LABEL, getFieldEditorParent())); } private void createExcludeMethodsField() { - addField(new StringFieldEditor(EXCLUDED_METHODS, EXCLUDE_METHODS_FROM_PIT, getFieldEditorParent())); + addField(new StringFieldEditor(EXCLUDED_METHODS, EXCLUDED_METHODS_LABEL, getFieldEditorParent())); } private void createUseIncrementalAnalysisOption() { - addField(new BooleanFieldEditor(INCREMENTAL_ANALYSIS, USE_INCREMENTAL_ANALYSIS, getFieldEditorParent())); + addField(new BooleanFieldEditor(INCREMENTAL_ANALYSIS, INCREMENTAL_ANALYSIS_LABEL, getFieldEditorParent())); } private void createRunInParallelOption() { - addField(new BooleanFieldEditor(RUN_IN_PARALLEL, MUTATION_TESTS_RUN_IN_PARALLEL, getFieldEditorParent())); + addField(new BooleanFieldEditor(RUN_IN_PARALLEL, RUN_IN_PARALLEL_LABEL, getFieldEditorParent())); } private void createPitTimeoutField() { - addField(new StringFieldEditor(TIMEOUT, PIT_TIMEOUT, getFieldEditorParent())); + addField(new StringFieldEditor(TIMEOUT, TIMEOUT_LABEL, getFieldEditorParent())); } private void createPitTimeoutFactorField() { - addField(new StringFieldEditor(TIMEOUT_FACTOR, PIT_TIMEOUT_FACTOR, getFieldEditorParent())); + addField(new StringFieldEditor(TIMEOUT_FACTOR, TIMEOUT_FACTOR_LABEL, getFieldEditorParent())); } private void createExecutionModeRadioButtons() { @@ -112,7 +98,7 @@ private void createExecutionModeRadioButtons() { for (int i = 0; i < values.length; i++) { executionModeValues[i] = new String[] { values[i].getLabel(), values[i].getId() }; } - addField(new RadioGroupFieldEditor(PIT_EXECUTION_MODE, "Pit execution scope", 1, executionModeValues, getFieldEditorParent())); + addField(new RadioGroupFieldEditor(EXECUTION_MODE, EXECUTION_MODE_LABEL, 1, executionModeValues, getFieldEditorParent())); } /* diff --git a/bundles/org.pitest.pitclipse.runner/src/org/pitest/pitclipse/runner/PitCliArguments.java b/bundles/org.pitest.pitclipse.runner/src/org/pitest/pitclipse/runner/PitCliArguments.java index d501aa39..ef3f9694 100644 --- a/bundles/org.pitest.pitclipse.runner/src/org/pitest/pitclipse/runner/PitCliArguments.java +++ b/bundles/org.pitest.pitclipse.runner/src/org/pitest/pitclipse/runner/PitCliArguments.java @@ -16,16 +16,16 @@ package org.pitest.pitclipse.runner; +import java.io.File; +import java.util.List; + import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList.Builder; import com.google.common.collect.Lists; -import java.io.File; -import java.util.List; - /** * Turns {@link PitOptions} instances into CLI arguments - * that can be understand by PIT. + * that can be understand by PIT. */ public class PitCliArguments { @@ -98,10 +98,10 @@ private List avoidedCallsFrom(PitOptions options) { private List mutatorsFrom(PitOptions options) { Builder builder = ImmutableList.builder(); - List mutators = options.getMutators(); - if (!mutators.isEmpty()) { + String mutators = options.getMutators(); + if (!mutators.trim().isEmpty()) { builder.add("--mutators"); - builder.add(concat(commaSeparate(mutators))); + builder.add(mutators); } return builder.build(); } diff --git a/bundles/org.pitest.pitclipse.runner/src/org/pitest/pitclipse/runner/PitOptions.java b/bundles/org.pitest.pitclipse.runner/src/org/pitest/pitclipse/runner/PitOptions.java index 75eea793..275d9fa0 100644 --- a/bundles/org.pitest.pitclipse.runner/src/org/pitest/pitclipse/runner/PitOptions.java +++ b/bundles/org.pitest.pitclipse.runner/src/org/pitest/pitclipse/runner/PitOptions.java @@ -51,7 +51,7 @@ public final class PitOptions implements Serializable { private final ImmutableList excludedClasses; private final ImmutableList excludedMethods; private final ImmutableList avoidCallsTo; - private final ImmutableList mutators; + private final String mutators; private final int timeout; private final BigDecimal timeoutFactor; private final boolean useJUnit5; @@ -59,7 +59,8 @@ public final class PitOptions implements Serializable { private PitOptions(String classUnderTest, ImmutableList classesToMutate, ImmutableList sourceDirs, // NOSONAR this is used by our builder File reportDir, ImmutableList packages, ImmutableList classPath, int threads, File historyLocation, ImmutableList excludedClasses, ImmutableList excludedMethods, - ImmutableList avoidCallsTo, ImmutableList mutators, int timeout, BigDecimal timeoutFactor, boolean useJUnit5) { + ImmutableList avoidCallsTo, String mutators, int timeout, BigDecimal timeoutFactor, + boolean useJUnit5) { this.classUnderTest = classUnderTest; this.threads = threads; this.historyLocation = historyLocation; @@ -102,7 +103,7 @@ public static final class PitOptionsBuilder { private ImmutableList excludedClasses = ImmutableList.of(); private ImmutableList excludedMethods = ImmutableList.of(); private ImmutableList avoidCallsTo = copyOf(split(DEFAULT_AVOID_CALLS_TO_LIST)); - private ImmutableList mutators = copyOf(split(DEFAULT_MUTATORS)); + private String mutators = DEFAULT_MUTATORS; private int timeout = 3000; private BigDecimal timeoutFactor = BigDecimal.valueOf(1.25); private boolean useJUnit5 = false; @@ -208,7 +209,7 @@ public PitOptionsBuilder withPackagesToTest(List packages) { this.packages = copyOf(packages); return this; } - + public PitOptionsBuilder withClassPath(List classPath) { this.classPath = copyOf(classPath); return this; @@ -239,8 +240,8 @@ public PitOptionsBuilder withAvoidCallsTo(List avoidCallsTo) { return this; } - public PitOptionsBuilder withMutators(List mutators) { - this.mutators = copyOf(mutators); + public PitOptionsBuilder withMutators(String mutators) { + this.mutators = mutators; return this; } @@ -297,7 +298,7 @@ public List getClassesToMutate() { public List getPackages() { return packages; } - + public List getClassPath() { return classPath; } @@ -306,7 +307,7 @@ public List getAvoidCallsTo() { return avoidCallsTo; } - public List getMutators() { + public String getMutators() { return mutators; } @@ -317,7 +318,7 @@ public int getTimeout() { public BigDecimal getTimeoutFactor() { return timeoutFactor; } - + public boolean getUseJUnit5() { return useJUnit5; } diff --git a/bundles/org.pitest.pitclipse.runner/src/org/pitest/pitclipse/runner/config/PitConfiguration.java b/bundles/org.pitest.pitclipse.runner/src/org/pitest/pitclipse/runner/config/PitConfiguration.java index 57da7c4d..af6ed970 100644 --- a/bundles/org.pitest.pitclipse.runner/src/org/pitest/pitclipse/runner/config/PitConfiguration.java +++ b/bundles/org.pitest.pitclipse.runner/src/org/pitest/pitclipse/runner/config/PitConfiguration.java @@ -16,10 +16,10 @@ package org.pitest.pitclipse.runner.config; -import java.math.BigDecimal; - import static org.pitest.pitclipse.runner.config.PitExecutionMode.PROJECT_ISOLATION; +import java.math.BigDecimal; + public class PitConfiguration { public static final String DEFAULT_AVOID_CALLS_TO_LIST = "java.util.logging, org.apache.log4j, org.slf4j, org.apache.commons.logging, org.apache.logging.log4j"; public static final String DEFAULT_MUTATORS = "DEFAULTS"; diff --git a/bundles/org.pitest.pitclipse.ui/META-INF/MANIFEST.MF b/bundles/org.pitest.pitclipse.ui/META-INF/MANIFEST.MF index 151968f6..25217aab 100644 --- a/bundles/org.pitest.pitclipse.ui/META-INF/MANIFEST.MF +++ b/bundles/org.pitest.pitclipse.ui/META-INF/MANIFEST.MF @@ -3,6 +3,7 @@ Bundle-ManifestVersion: 2 Bundle-Name: Pitclipse UI Bundle-SymbolicName: org.pitest.pitclipse.ui;singleton:=true Bundle-Version: 2.1.2.qualifier +Bundle-Activator: org.pitest.pitclipse.ui.core.PitUiActivator Require-Bundle: org.eclipse.ui;bundle-version="[3.107.0,4.0.0)", org.eclipse.core.runtime;bundle-version="[3.11.1,4.0.0)", org.eclipse.core.resources;bundle-version="[3.10.1,4.0.0)", @@ -18,5 +19,7 @@ Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Bundle-Vendor: Pitest.org Bundle-ClassPath: . -Export-Package: org.pitest.pitclipse.ui.extension.point +Export-Package: org.pitest.pitclipse.ui.core, + org.pitest.pitclipse.ui.extension.point, + org.pitest.pitclipse.ui.utils Automatic-Module-Name: org.pitest.pitclipse.ui diff --git a/bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/core/PitUiActivator.java b/bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/core/PitUiActivator.java new file mode 100644 index 00000000..ef7e44d6 --- /dev/null +++ b/bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/core/PitUiActivator.java @@ -0,0 +1,82 @@ +/******************************************************************************* + * Copyright 2021 Jonas Kutscha and contributors + * + * 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.pitclipse.ui.core; + +import java.net.URL; + +import org.eclipse.core.runtime.FileLocator; +import org.eclipse.core.runtime.Path; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.resource.ImageRegistry; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Display; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.FrameworkUtil; + +/** + * The ui activator class which initializes the icons of the plug in + */ +public class PitUiActivator extends AbstractUIPlugin { + /** + * Image registry for this plug in + */ + private ImageRegistry imageRegistry; + /** + * Key under which the pit icon is put in the registry + */ + private static final String PIT_ICON = "org.pitest.pitclipse.pitIcon"; + + /** + * The shared instance + */ + private static PitUiActivator plugin; + + @Override + public void start(BundleContext context) throws Exception { + plugin = this; // NOSONAR typical in Eclipse + initIcons(context); + super.start(context); + } + + /** + * Init of the icons of the plug in + */ + private void initIcons(BundleContext context) { + Display.getDefault().syncExec(() -> { + imageRegistry = new ImageRegistry(); + Bundle bundle = FrameworkUtil.getBundle(getClass()); + URL url = FileLocator.find(bundle, new Path("icons/pit.gif"), null); + imageRegistry.put(PIT_ICON, ImageDescriptor.createFromURL(url).createImage()); + }); + } + + /** + * @return Returns the pit icon. + */ + public Image getPitIcon() { + return imageRegistry.get(PIT_ICON); + } + + /** + * @return the shared instance + */ + public static PitUiActivator getDefault() { + return plugin; + } +} diff --git a/bundles/org.pitest.pitclipse.core/src/org/pitest/pitclipse/core/PitMutators.java b/bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/utils/LinkSelectionAdapter.java similarity index 55% rename from bundles/org.pitest.pitclipse.core/src/org/pitest/pitclipse/core/PitMutators.java rename to bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/utils/LinkSelectionAdapter.java index cceb0d1b..dbf8cf12 100644 --- a/bundles/org.pitest.pitclipse.core/src/org/pitest/pitclipse/core/PitMutators.java +++ b/bundles/org.pitest.pitclipse.ui/src/org/pitest/pitclipse/ui/utils/LinkSelectionAdapter.java @@ -1,12 +1,12 @@ /******************************************************************************* - * Copyright 2012-2019 Phil Glover and contributors - * + * Copyright 2021 Jonas Kutscha and contributors + * * 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 @@ -14,27 +14,25 @@ * the License. ******************************************************************************/ -package org.pitest.pitclipse.core; +package org.pitest.pitclipse.ui.utils; -public enum PitMutators { - - DEFAULTS("defaultMutators", "&Default Mutators"), - STRONGER("strongerMutators", "&Stronger Mutators"), - ALL("allMutators", "&All Mutators"); +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.program.Program; - private final String label; - private final String id; +/** + * Selection adapter which launches a browser with the link. + * @author jkutscha + */ +public class LinkSelectionAdapter extends SelectionAdapter { + private final String link; - private PitMutators(String id, String label) { - this.id = id; - this.label = label; + public LinkSelectionAdapter(final String link) { + this.link = link; } - public String getLabel() { - return label; - } - - public String getId() { - return id; + @Override + public void widgetSelected(SelectionEvent e) { + Program.launch(link); } } diff --git a/checkstyle.xml b/checkstyle.xml index ecdf0687..37d79034 100644 --- a/checkstyle.xml +++ b/checkstyle.xml @@ -141,4 +141,8 @@ + + + + diff --git a/tests/org.pitest.pitclipse.runner.tests/META-INF/MANIFEST.MF b/tests/org.pitest.pitclipse.runner.tests/META-INF/MANIFEST.MF index ac11b564..d7f8b8e7 100644 --- a/tests/org.pitest.pitclipse.runner.tests/META-INF/MANIFEST.MF +++ b/tests/org.pitest.pitclipse.runner.tests/META-INF/MANIFEST.MF @@ -13,4 +13,5 @@ Require-Bundle: org.apache.commons.lang3;bundle-version="3.1.0", org.objenesis;bundle-version="1.0.0", org.junit;bundle-version="4.12.0", org.eclipse.core.runtime;bundle-version="[3.11.1,4.0.0)", - com.google.guava + com.google.guava, + org.pitest.pitclipse.core diff --git a/tests/org.pitest.pitclipse.runner.tests/src/org/pitest/pitclipse/runner/MutatorApiOfPitTest.java b/tests/org.pitest.pitclipse.runner.tests/src/org/pitest/pitclipse/runner/MutatorApiOfPitTest.java new file mode 100644 index 00000000..10c1426f --- /dev/null +++ b/tests/org.pitest.pitclipse.runner.tests/src/org/pitest/pitclipse/runner/MutatorApiOfPitTest.java @@ -0,0 +1,108 @@ +/******************************************************************************* + * Copyright 2021 Jonas Kutscha and contributors + * + * 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.pitclipse.runner; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.pitest.mutationtest.engine.gregor.config.Mutator; +import org.pitest.pitclipse.core.Mutators; + +/** + * This test case is in place to detect whether the supplied mutators from pit + * changed and we need to change {@link Mutators}. + */ +public class MutatorApiOfPitTest { + @Test + public void testTheMutatorApiOfPit() { + assertEquals(getExpectedMutatorsAsString(), getPitMutatorsAsString()); + } + + private String getPitMutatorsAsString() { + StringBuilder sb = new StringBuilder(); + for (String mutator : Mutator.allMutatorIds()) { + sb.append(mutator).append('\n'); + } + return sb.toString(); + } + + private String getExpectedMutatorsAsString() { + return "INVERT_NEGS\n" + + "RETURN_VALS\n" + + "INLINE_CONSTS\n" + + "MATH\n" + + "VOID_METHOD_CALLS\n" + + "NEGATE_CONDITIONALS\n" + + "CONDITIONALS_BOUNDARY\n" + + "INCREMENTS\n" + + "REMOVE_INCREMENTS\n" + + "NON_VOID_METHOD_CALLS\n" + + "CONSTRUCTOR_CALLS\n" + + "REMOVE_CONDITIONALS_EQ_IF\n" + + "REMOVE_CONDITIONALS_EQ_ELSE\n" + + "REMOVE_CONDITIONALS_ORD_IF\n" + + "REMOVE_CONDITIONALS_ORD_ELSE\n" + + "REMOVE_CONDITIONALS\n" + + "TRUE_RETURNS\n" + + "FALSE_RETURNS\n" + + "PRIMITIVE_RETURNS\n" + + "EMPTY_RETURNS\n" + + "NULL_RETURNS\n" + + "RETURNS\n" + + "EXPERIMENTAL_MEMBER_VARIABLE\n" + + "EXPERIMENTAL_SWITCH\n" + + "EXPERIMENTAL_ARGUMENT_PROPAGATION\n" + + "EXPERIMENTAL_NAKED_RECEIVER\n" + + "EXPERIMENTAL_BIG_INTEGER\n" + + "AOR_1\n" + + "AOR_2\n" + + "AOR_3\n" + + "AOR_4\n" + + "ABS\n" + + "AOD1\n" + + "AOD2\n" + + "CRCR1\n" + + "CRCR2\n" + + "CRCR3\n" + + "CRCR4\n" + + "CRCR5\n" + + "CRCR6\n" + + "OBBN1\n" + + "OBBN2\n" + + "OBBN3\n" + + "ROR1\n" + + "ROR2\n" + + "ROR3\n" + + "ROR4\n" + + "ROR5\n" + + "UOI1\n" + + "UOI2\n" + + "UOI3\n" + + "UOI4\n" + + "REMOVE_SWITCH\n" + + "OLD_DEFAULTS\n" + + "STRONGER\n" + + "ALL\n" + + "DEFAULTS\n" + + "AOR\n" + + "AOD\n" + + "CRCR\n" + + "OBBN\n" + + "ROR\n" + + "UOI\n"; + } +} diff --git a/tests/org.pitest.pitclipse.runner.tests/src/org/pitest/pitclipse/runner/PitCliArgumentsTest.java b/tests/org.pitest.pitclipse.runner.tests/src/org/pitest/pitclipse/runner/PitCliArgumentsTest.java index b7c93e43..d101f271 100644 --- a/tests/org.pitest.pitclipse.runner.tests/src/org/pitest/pitclipse/runner/PitCliArgumentsTest.java +++ b/tests/org.pitest.pitclipse.runner.tests/src/org/pitest/pitclipse/runner/PitCliArgumentsTest.java @@ -16,26 +16,26 @@ package org.pitest.pitclipse.runner; -import com.google.common.base.Function; -import com.google.common.base.Splitter; -import com.google.common.collect.Collections2; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableList.Builder; - -import org.junit.Before; -import org.junit.Test; -import org.pitest.pitclipse.example.ExampleTest; - -import java.io.File; -import java.math.BigDecimal; -import java.util.List; - import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertTrue; import static org.pitest.pitclipse.runner.config.PitConfiguration.DEFAULT_AVOID_CALLS_TO_LIST; +import java.io.File; +import java.math.BigDecimal; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; +import org.pitest.pitclipse.example.ExampleTest; + +import com.google.common.base.Function; +import com.google.common.base.Splitter; +import com.google.common.collect.Collections2; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableList.Builder; + public class PitCliArgumentsTest { private static final String TEST_CLASS1 = PitOptionsTest.class.getCanonicalName(); @@ -50,7 +50,7 @@ public class PitCliArgumentsTest { private static final List EXCLUDED_METHODS = ImmutableList.of("*toString*", "leaveMeAlone*"); private static final File NO_HISTORY_FILE = null; private static final int DEFAULT_NUMBER_OF_THREADS = 1; - private static final List MUTATORS = ImmutableList.of("FOO", "BAR"); + private static final String MUTATORS = "FOO,BAR"; private static final List DEFAULT_AVOID_LIST = ImmutableList.copyOf(Splitter.on(',').trimResults() .omitEmptyStrings().split(DEFAULT_AVOID_CALLS_TO_LIST)); @@ -172,12 +172,13 @@ private void whenArgumentsAreMadeFrom(PitOptions options) { private void thenTheArgumentsAreMadeUpOf(File reportDir, List testSrcDirs, int threadCount, String testClass, List classesToMutate, File historyFile, List excludedClasses, List excludedMethods, - List avoidCallsTo, List mutators, int timeout, BigDecimal timeoutFactor) { + List avoidCallsTo, String mutators, int timeout, BigDecimal timeoutFactor) { Object[] expectedCliArgs = new ExpectedArgsBuilder().withThreadCount(threadCount).withReportDir(reportDir) .withClassUnderTest(testClass).withTargetClasses(classesToMutate) .withSourceDirectories(filesAsStrings(testSrcDirs)).withHistoryLocation(historyFile) .withExcludedClasses(excludedClasses).withExcludedMethods(excludedMethods).withMutators(MUTATORS) - .withAvoidCallsTo(avoidCallsTo).withMutators(mutators).withTimeout(timeout).withTimeoutFactor(timeoutFactor) + .withAvoidCallsTo(avoidCallsTo).withMutators(mutators).withTimeout(timeout) + .withTimeoutFactor(timeoutFactor) .build(); assertThat(actualCliArgs, is(equalTo(expectedCliArgs))); } @@ -204,7 +205,7 @@ private static final class ExpectedArgsBuilder { private List excludedClasses = NO_EXCLUDED_CLASSES; private List excludedMethods = NO_EXCLUDED_METHODS; private List avoidCallsTo = DEFAULT_AVOID_LIST; - private List mutators = MUTATORS; + private String mutators = MUTATORS; private int timeout = DEFAULT_TIMEOUT; private BigDecimal timeoutFactor = DEFAULT_TIMEOUT_FACTOR; @@ -227,8 +228,8 @@ public String[] build() { return asStrings(resultBuilder.build()); } - public ExpectedArgsBuilder withMutators(List mutators) { - this.mutators = ImmutableList.copyOf(mutators); + public ExpectedArgsBuilder withMutators(String mutators) { + this.mutators = mutators; return this; } diff --git a/tests/org.pitest.pitclipse.runner.tests/src/org/pitest/pitclipse/runner/PitRunnerTest.java b/tests/org.pitest.pitclipse.runner.tests/src/org/pitest/pitclipse/runner/PitRunnerTest.java index bdcbceab..dde6dd28 100644 --- a/tests/org.pitest.pitclipse.runner.tests/src/org/pitest/pitclipse/runner/PitRunnerTest.java +++ b/tests/org.pitest.pitclipse.runner.tests/src/org/pitest/pitclipse/runner/PitRunnerTest.java @@ -16,17 +16,16 @@ package org.pitest.pitclipse.runner; -import org.eclipse.core.runtime.Platform; -import org.hamcrest.Description; -import org.hamcrest.Matcher; -import org.hamcrest.TypeSafeMatcher; -import org.junit.Before; -import org.junit.Test; -import org.pitest.mutationtest.MutationResultListenerFactory; -import org.pitest.pitclipse.example.empty.EmptyClass; -import org.pitest.pitclipse.runner.results.ObjectFactory; -import org.pitest.pitclipse.runner.results.mutations.RecordingMutationsDispatcher; -import org.pitest.util.ServiceLoader; +import static java.util.Arrays.asList; +import static java.util.stream.Collectors.toSet; +import static org.eclipse.core.runtime.FileLocator.getBundleFile; +import static org.hamcrest.CoreMatchers.hasItems; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.nullValue; +import static org.hamcrest.collection.IsEmptyCollection.empty; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -38,16 +37,17 @@ import java.util.List; import java.util.Set; -import static java.util.Arrays.asList; -import static java.util.stream.Collectors.toSet; -import static org.eclipse.core.runtime.FileLocator.getBundleFile; -import static org.hamcrest.CoreMatchers.hasItems; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.not; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.nullValue; -import static org.hamcrest.collection.IsEmptyCollection.empty; +import org.eclipse.core.runtime.Platform; +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeMatcher; +import org.junit.Before; +import org.junit.Test; +import org.pitest.mutationtest.MutationResultListenerFactory; +import org.pitest.pitclipse.example.empty.EmptyClass; +import org.pitest.pitclipse.runner.results.ObjectFactory; +import org.pitest.pitclipse.runner.results.mutations.RecordingMutationsDispatcher; +import org.pitest.util.ServiceLoader; /** * Tests the behavior of a {@link PitRunner}'s functions. @@ -177,5 +177,4 @@ private static List classPathWithPitestAndJUnit() throws IOException { new File("lib/junit.jar").getAbsolutePath() ); } - } diff --git a/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/behaviours/pageobjects/PackageExplorer.java b/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/behaviours/pageobjects/PackageExplorer.java index 3585c4eb..ab7bfd9b 100644 --- a/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/behaviours/pageobjects/PackageExplorer.java +++ b/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/behaviours/pageobjects/PackageExplorer.java @@ -1,12 +1,12 @@ /******************************************************************************* - * Copyright 2012-2019 Phil Glover and contributors - * + * Copyright 2012-2021 Phil Glover and contributors + * * 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 @@ -16,20 +16,20 @@ package org.pitest.pitclipse.ui.behaviours.pageobjects; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableList.Builder; - -import org.eclipse.swtbot.eclipse.finder.SWTWorkbenchBot; -import org.eclipse.swtbot.swt.finder.widgets.SWTBotTreeItem; - -import java.util.List; -import java.util.NoSuchElementException; - import static com.google.common.base.Strings.isNullOrEmpty; import static org.junit.Assert.fail; import static org.pitest.pitclipse.ui.behaviours.pageobjects.SwtBotTreeHelper.selectAndExpand; import static org.pitest.pitclipse.ui.util.VerifyUtil.isNotNull; +import java.util.List; +import java.util.NoSuchElementException; + +import org.eclipse.swtbot.eclipse.finder.SWTWorkbenchBot; +import org.eclipse.swtbot.swt.finder.widgets.SWTBotTreeItem; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableList.Builder; + public class PackageExplorer { private static final String PACKAGE_EXPLORER = "Package Explorer"; @@ -57,6 +57,9 @@ private void openProject(SWTBotTreeItem project) { } private SWTBotTreeItem getProject(String projectName) { + // You need to have the focus on the explorer, otherwise the project doesn't get + // selected properly + bot.viewByTitle(PACKAGE_EXPLORER).show(); SWTBotTreeItem[] treeItems = bot.viewByTitle(PACKAGE_EXPLORER).bot().tree().getAllItems(); for (SWTBotTreeItem treeItem : treeItems) { if (projectName.equals(treeItem.getText())) { diff --git a/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/behaviours/pageobjects/PitPreferenceSelector.java b/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/behaviours/pageobjects/PitPreferenceSelector.java index 923fee48..6c1be584 100644 --- a/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/behaviours/pageobjects/PitPreferenceSelector.java +++ b/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/behaviours/pageobjects/PitPreferenceSelector.java @@ -21,26 +21,26 @@ import org.eclipse.swtbot.eclipse.finder.SWTWorkbenchBot; import org.eclipse.swtbot.swt.finder.widgets.SWTBotShell; import org.eclipse.swtbot.swt.finder.widgets.SWTBotTreeItem; -import org.pitest.pitclipse.core.PitMutators; +import org.pitest.pitclipse.core.Mutators; import org.pitest.pitclipse.runner.config.PitExecutionMode; import java.io.Closeable; import java.math.BigDecimal; import static java.math.BigDecimal.ZERO; +import static org.pitest.pitclipse.core.preferences.PitPreferences.AVOID_CALLS_TO_LABEL; +import static org.pitest.pitclipse.core.preferences.PitPreferences.EXCLUDED_CLASSES_LABEL; +import static org.pitest.pitclipse.core.preferences.PitPreferences.EXCLUDED_METHODS_LABEL; +import static org.pitest.pitclipse.core.preferences.PitPreferences.EXECUTION_MODE_LABEL; +import static org.pitest.pitclipse.core.preferences.PitPreferences.RUN_IN_PARALLEL_LABEL; +import static org.pitest.pitclipse.core.preferences.PitPreferences.TIMEOUT_LABEL; +import static org.pitest.pitclipse.core.preferences.PitPreferences.TIMEOUT_FACTOR_LABEL; +import static org.pitest.pitclipse.core.preferences.PitPreferences.INCREMENTAL_ANALYSIS_LABEL; import static org.pitest.pitclipse.ui.behaviours.pageobjects.SwtBotTreeHelper.selectAndExpand; public class PitPreferenceSelector implements Closeable { - private static final String USE_INCREMENTAL_ANALYSIS_LABEL = "Use incremental analysis"; - private static final String MUTATION_TESTS_RUN_IN_PARALLEL_LABEL = "Mutation tests run in parallel"; - private static final String EXCLUDED_CLASSES_LABEL = "Excluded classes (e.g.*IntTest)"; - private static final String EXCLUDED_METHODS_LABEL = "Excluded methods (e.g.*toString*)"; - private static final String AVOID_CALLS_TO_LABEL = "Avoid calls to"; private static final String MUTATORS_LABEL = "Mutators"; - private static final String EXECUTION_MODE_LABEL = "Pit Execution Scope"; - private static final String PIT_TIMEOUT_LABEL = "Pit Timeout"; - private static final String PIT_TIMEOUT_FACTOR_LABEL = "Timeout Factor"; private final SWTWorkbenchBot bot; public PitPreferenceSelector(SWTWorkbenchBot bot) { @@ -85,19 +85,19 @@ private PitExecutionMode getActiveExecutionMode() { } public boolean isPitRunInParallel() { - return getBoolean().from(MUTATION_TESTS_RUN_IN_PARALLEL_LABEL); + return getBoolean().from(RUN_IN_PARALLEL_LABEL); } public boolean isIncrementalAnalysisEnabled() { - return getBoolean().from(USE_INCREMENTAL_ANALYSIS_LABEL); + return getBoolean().from(INCREMENTAL_ANALYSIS_LABEL); } public void setPitRunInParallel(boolean inParallel) { - setSelectionFor(MUTATION_TESTS_RUN_IN_PARALLEL_LABEL).to(inParallel); + setSelectionFor(RUN_IN_PARALLEL_LABEL).to(inParallel); } public void setPitIncrementalAnalysisEnabled(boolean incremental) { - setSelectionFor(USE_INCREMENTAL_ANALYSIS_LABEL).to(incremental); + setSelectionFor(INCREMENTAL_ANALYSIS_LABEL).to(incremental); } public String getExcludedClasses() { @@ -124,7 +124,7 @@ public void setAvoidCallsTo(String avoidCallsTo) { setTextFor(AVOID_CALLS_TO_LABEL).to(avoidCallsTo); } - public PitMutators getMutators() { + public Mutators getMutators() { return getSelectedMutators().from(MUTATORS_LABEL); } @@ -139,11 +139,11 @@ private Optional expandPitMutatorPreferences() { } public void setPitTimeoutConst(int timeout) { - setTextFor(PIT_TIMEOUT_LABEL).to(timeout); + setTextFor(TIMEOUT_LABEL).to(timeout); } public void setPitTimeoutFactor(int factor) { - setTextFor(PIT_TIMEOUT_FACTOR_LABEL).to(factor); + setTextFor(TIMEOUT_FACTOR_LABEL).to(factor); } private static interface PreferenceGetter { @@ -263,17 +263,17 @@ public Boolean getPreference(String label) { }); } - private PreferenceGetterBuilder getSelectedMutators() { - return new PreferenceGetterBuilder(new PreferenceGetter() { + private PreferenceGetterBuilder getSelectedMutators() { + return new PreferenceGetterBuilder(new PreferenceGetter() { @Override - public PitMutators getPreference(String label) { + public Mutators getPreference(String label) { expandPitMutatorPreferences(); - for (PitMutators mutator : PitMutators.values()) { - if (bot.radio(mutator.getLabel()).isSelected()) { + for (Mutators mutator : Mutators.getMainGroup()) { + if (bot.radio(mutator.getDescriptor()).isSelected()) { return mutator; } } - return PitMutators.DEFAULTS; + return Mutators.DEFAULTS; } }); } @@ -288,10 +288,10 @@ public PitExecutionMode getPreference(String label) { } public int getTimeout() { - return getInteger().from(PIT_TIMEOUT_LABEL); + return getInteger().from(TIMEOUT_LABEL); } public BigDecimal getPitTimeoutFactor() { - return getBigDecimal().from(PIT_TIMEOUT_FACTOR_LABEL); + return getBigDecimal().from(TIMEOUT_FACTOR_LABEL); } } diff --git a/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/behaviours/pageobjects/PitRunConfiguration.java b/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/behaviours/pageobjects/PitRunConfiguration.java index 23f8747d..c7d3a7e4 100644 --- a/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/behaviours/pageobjects/PitRunConfiguration.java +++ b/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/behaviours/pageobjects/PitRunConfiguration.java @@ -1,12 +1,12 @@ /******************************************************************************* - * Copyright 2012-2019 Phil Glover and contributors - * + * Copyright 2012-2021 Phil Glover and contributors + * * 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 @@ -16,32 +16,67 @@ package org.pitest.pitclipse.ui.behaviours.pageobjects; -import com.google.common.collect.ImmutableList; +import static com.google.common.collect.ImmutableList.copyOf; +import static org.pitest.pitclipse.runner.config.PitConfiguration.DEFAULT_AVOID_CALLS_TO_LIST; import java.util.List; -import static com.google.common.collect.ImmutableList.copyOf; -import static org.pitest.pitclipse.runner.config.PitConfiguration.DEFAULT_AVOID_CALLS_TO_LIST; +import com.google.common.collect.ImmutableList; public class PitRunConfiguration { - + /** + * Name of the configuration + */ private final String name; + /** + * List of the projects which are in the scope of mutation + */ private final List projects; + /** + * Name of the test object. Can be the name of a class or directory. + */ + private final String testObject; + /** + * True, if the test object is a class + */ + private final boolean testClass; + /** + * True, if the tests should be run in pararllel + */ private final boolean runInParallel; + /** + * True, if incremental analysis should be used + */ private final boolean incrementalAnalysis; + /** + * List of globs to match against class names. Matching classes will be excluded + * from mutation. + */ private final String excludedClasses; + /** + * List of globs to match against method names. Methods matching the globs will + * be excluded from mutation. + */ private final String excludedMethods; + /** + * List of packages and classes which are to be considered outside the scope of + * mutation. Any lines of code containing calls to these classes will not be + * mutated. + */ private final String avoidCallsTo; - private PitRunConfiguration(String name, List projects, boolean runInParallel, boolean incrementalAnalysis, - String excludedClasses, String excludedMethods, String avoidCallsTo) { + private PitRunConfiguration(String name, List projects, String testObject, boolean testClass, + boolean runInParallel, boolean incrementalAnalysis, String excludedClasses, String excludedMethods, + String avoidCallsTo) { this.name = name; this.projects = projects; + this.testObject = testObject; this.runInParallel = runInParallel; this.incrementalAnalysis = incrementalAnalysis; this.excludedClasses = excludedClasses; this.excludedMethods = excludedMethods; this.avoidCallsTo = avoidCallsTo; + this.testClass = testClass; } public String getName() { @@ -52,18 +87,40 @@ public List getProjects() { return projects; } + public String getTestObject() { + return testObject; + } + public static class Builder { private String name; + private String testObject = null; private List projects = ImmutableList.of(); private boolean runInParallel = false; private boolean incrementalAnalysis = false; - private String excludedClasses = ""; + private boolean testClass = true; + private String excludedClasses = "*Test"; private String excludedMethods = ""; private String avoidCallsTo = DEFAULT_AVOID_CALLS_TO_LIST; + public Builder(PitRunConfiguration configuration) { + this.name = configuration.getName(); + this.testObject = configuration.getTestObject(); + this.projects = copyOf(configuration.getProjects()); + this.runInParallel = configuration.isRunInParallel(); + this.incrementalAnalysis = configuration.isIncrementalAnalysis(); + this.testClass = configuration.isTestClass(); + this.excludedClasses = configuration.getExcludedClasses(); + this.excludedMethods = configuration.getExcludedMethods(); + this.avoidCallsTo = configuration.getAvoidCallsTo(); + } + + public Builder() { + // intentionally empty + } + public PitRunConfiguration build() { - return new PitRunConfiguration(name, projects, runInParallel, incrementalAnalysis, excludedClasses, - excludedMethods, avoidCallsTo); + return new PitRunConfiguration(name, projects, testObject, testClass, runInParallel, incrementalAnalysis, + excludedClasses, excludedMethods, avoidCallsTo); } public Builder withName(String name) { @@ -76,6 +133,26 @@ public Builder withProjects(String... projects) { return this; } + public Builder withTestObject(String testObject) { + this.testObject = testObject; + return this; + } + + public Builder withTestDir(String testDir) { + this.testClass = false; + return withTestObject(testDir); + } + + public Builder withTestClassOrDir(boolean isTestClass) { + this.testClass = isTestClass; + return this; + } + + public Builder withTestClass(String testClass) { + this.testClass = true; + return withTestObject(testClass); + } + public Builder withRunInParallel(boolean runInParallel) { this.runInParallel = runInParallel; return this; @@ -121,4 +198,8 @@ public String getExcludedMethods() { public String getAvoidCallsTo() { return avoidCallsTo; } + + public boolean isTestClass() { + return testClass; + } } diff --git a/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/behaviours/pageobjects/RunConfigurationSelector.java b/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/behaviours/pageobjects/RunConfigurationSelector.java index 030674e2..47c5630d 100644 --- a/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/behaviours/pageobjects/RunConfigurationSelector.java +++ b/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/behaviours/pageobjects/RunConfigurationSelector.java @@ -16,37 +16,52 @@ package org.pitest.pitclipse.ui.behaviours.pageobjects; -import com.google.common.collect.ImmutableList; +import static com.google.common.collect.ImmutableList.builder; +import static org.eclipse.swtbot.swt.finder.waits.Conditions.shellIsActive; +import static org.junit.Assert.fail; +import java.util.List; +import java.util.stream.Collectors; + +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.TableItem; import org.eclipse.swtbot.eclipse.finder.SWTWorkbenchBot; +import org.eclipse.swtbot.swt.finder.widgets.SWTBotButton; +import org.eclipse.swtbot.swt.finder.widgets.SWTBotRadio; import org.eclipse.swtbot.swt.finder.widgets.SWTBotShell; +import org.eclipse.swtbot.swt.finder.widgets.SWTBotTable; import org.eclipse.swtbot.swt.finder.widgets.SWTBotTreeItem; +import org.pitest.pitclipse.core.Mutators; +import org.pitest.pitclipse.core.preferences.PitPreferences; +import org.pitest.pitclipse.launch.ui.PitArgumentsTab; +import org.pitest.pitclipse.launch.ui.PitMutatorsTab; import org.pitest.pitclipse.ui.behaviours.pageobjects.PitRunConfiguration.Builder; +import org.pitest.pitclipse.ui.swtbot.PitResultNotifier.PitSummary; +import org.pitest.pitclipse.ui.swtbot.SWTBotMenuHelper; -import java.util.List; - -import static com.google.common.collect.ImmutableList.builder; -import static org.pitest.pitclipse.ui.behaviours.pageobjects.SwtBotTreeHelper.selectAndExpand; +import com.google.common.collect.ImmutableList; public class RunConfigurationSelector { + private static final String RUN = "Run"; + private static final String RUN_CONFIGURATIONS = "Run Configurations"; private final SWTWorkbenchBot bot; + private final static String DELETE_SHELL_TITLE = "Confirm Launch Configuration Deletion"; public RunConfigurationSelector(SWTWorkbenchBot bot) { this.bot = bot; } public PitRunConfiguration getConfiguration(String configName) { - activateShell(); + activateConfiguration(configName); Builder builder = new PitRunConfiguration.Builder(); return builder.build(); } public List getConfigurations() { - activateShell(); try { ImmutableList.Builder builder = builder(); - SWTBotTreeItem[] configurations = activateShell().getItems(); + SWTBotTreeItem[] configurations = getPitConfigurationItem().getItems(); for (SWTBotTreeItem treeItem : configurations) { treeItem.select(); builder.add(getPitConfiguration(treeItem)); @@ -59,25 +74,240 @@ public List getConfigurations() { private PitRunConfiguration getPitConfiguration(SWTBotTreeItem treeItem) { String name = treeItem.getText(); - String project = bot.textWithLabel("Project to mutate:").getText(); - boolean runInParallel = bot.checkBox("Mutation tests run in parallel").isChecked(); - boolean incrementalAnalysis = bot.checkBox("Use incremental analysis").isChecked(); - String excludedClasses = bot.textWithLabel("Excluded classes (e.g.*IntTest)").getText(); - String excludedMethods = bot.textWithLabel("Excluded methods (e.g.*toString*)").getText(); - String avoidCallsTo = bot.textWithLabel("Avoid calls to").getText(); + String project = bot.textWithLabel(PitArgumentsTab.PROJECT_TEXT).getText(); + boolean isTestClass = bot.radio(PitArgumentsTab.TEST_CLASS_RADIO_TEXT).isSelected(); + String testObject; + if (isTestClass) { + testObject = bot.textWithLabel(PitArgumentsTab.TEST_CLASS_TEXT).getText(); + } else { + testObject = bot.textWithLabel(PitArgumentsTab.TEST_DIR_TEXT).getText(); + } + boolean runInParallel = bot.checkBox(PitPreferences.RUN_IN_PARALLEL_LABEL).isChecked(); + boolean incrementalAnalysis = bot.checkBox(PitPreferences.INCREMENTAL_ANALYSIS_LABEL).isChecked(); + String excludedClasses = bot.textWithLabel(PitPreferences.EXCLUDED_CLASSES_LABEL).getText(); + String excludedMethods = bot.textWithLabel(PitPreferences.EXCLUDED_METHODS_LABEL).getText(); + String avoidCallsTo = bot.textWithLabel(PitPreferences.AVOID_CALLS_TO_LABEL).getText(); return new Builder().withName(name).withProjects(project).withRunInParallel(runInParallel) .withIncrementalAnalysis(incrementalAnalysis).withExcludedClasses(excludedClasses) - .withExcludedMethods(excludedMethods).withAvoidCallsTo(avoidCallsTo).build(); + .withExcludedMethods(excludedMethods).withAvoidCallsTo(avoidCallsTo).withTestObject(testObject) + .withTestClassOrDir(isTestClass).build(); } - private SWTBotTreeItem activateShell() { - SWTBotShell shell = bot.shell("Run Configurations"); + private SWTBotShell activateShell() { + // look if shell is already open + for (SWTBotShell shell : bot.shells()) { + if (shell.getText().equals(RUN_CONFIGURATIONS)) { + shell.activate(); + return shell; + } + } + // make sure we don't have pending shells + bot.closeAllShells(); + // shell was not open, open and activate it + SWTBotMenuHelper menuHelper = new SWTBotMenuHelper(); + menuHelper.findMenu(bot.menu(RUN), RUN_CONFIGURATIONS + "...").click(); + SWTBotShell shell = bot.shell(RUN_CONFIGURATIONS); shell.activate(); + // make sure the dialog is active + bot.waitUntil(shellIsActive(RUN_CONFIGURATIONS)); + return shell; + } + + private SWTBotTreeItem getPitConfigurationItem() { + activateShell(); + final String itemName = "PIT Mutation Test"; for (SWTBotTreeItem treeItem : bot.tree().getAllItems()) { - if ("PIT Mutation Test".equals(treeItem.getText())) { - return selectAndExpand(treeItem); + if (itemName.equals(treeItem.getText())) { + return treeItem.select().expand(); + } + } + fail("Could not find '" + itemName + "' in the configurations tab."); + return null; // never reached + } + + private void activateConfiguration(String configurationName) { + for (SWTBotTreeItem i : getPitConfigurationItem().getItems()) { + if (i.getText().equals(configurationName)) { + i.click(); + return; + } + } + fail("Could not find '" + configurationName + "' in the configurations of PIT."); + } + + public void activateMutatorsTab(String configurationName) { + activateConfigurationTab(configurationName, PitMutatorsTab.NAME); + } + + public void activatePitTab(String configurationName) { + activateConfigurationTab(configurationName, PitArgumentsTab.NAME); + } + + private void activateConfigurationTab(String configurationName, String name) { + activateShell(); + activateConfiguration(configurationName); + bot.cTabItem(PitMutatorsTab.NAME).activate(); + } + + public void createRunConfiguration(String configurationName, String projectName, String className) { + getPitConfigurationItem().contextMenu("New Configuration").click(); + bot.textWithLabel("Name:").setText(configurationName); + activateShell().bot().button("Apply").click(); + PitRunConfiguration config = new Builder().withName(configurationName).withProjects(projectName) + .withTestClass(className).build(); + setConfiguration(config); + } + + public void setProjectForConfiguration(String configurationName, String project) { + setConfiguration(new Builder(getConfiguration(configurationName)).withProjects(project).build()); + } + + public void setTestClassForConfiguration(String configurationName, String testClass) { + setConfiguration(new Builder(getConfiguration(configurationName)).withTestClass(testClass).build()); + } + + public void setTestDirForConfiguration(String configurationName, String testDir) { + setConfiguration(new Builder(getConfiguration(configurationName)).withTestDir(testDir).build()); + } + + private void setConfiguration(PitRunConfiguration config) { + activateConfiguration(config.getName()); + bot.textWithLabel(PitArgumentsTab.PROJECT_TEXT).setText(getProjectsAsString(config)); + if (config.isTestClass()) { + bot.radio(PitArgumentsTab.TEST_CLASS_RADIO_TEXT).click(); + bot.textWithLabel(PitArgumentsTab.TEST_CLASS_TEXT).setText(config.getTestObject()); + } else { + bot.radio(PitArgumentsTab.TEST_DIR_RADIO_TEXT).click(); + bot.textWithLabel(PitArgumentsTab.TEST_DIR_TEXT).setText(config.getTestObject()); + + } + if (config.isRunInParallel()) { + bot.checkBox(PitPreferences.RUN_IN_PARALLEL_LABEL).select(); + } else { + bot.checkBox(PitPreferences.RUN_IN_PARALLEL_LABEL).deselect(); + } + if (config.isIncrementalAnalysis()) { + bot.checkBox(PitPreferences.INCREMENTAL_ANALYSIS_LABEL).select(); + } else { + bot.checkBox(PitPreferences.INCREMENTAL_ANALYSIS_LABEL).deselect(); + } + bot.textWithLabel(PitPreferences.EXCLUDED_CLASSES_LABEL).setText(config.getExcludedClasses()); + bot.textWithLabel(PitPreferences.EXCLUDED_METHODS_LABEL).setText(config.getExcludedMethods()); + bot.textWithLabel(PitPreferences.AVOID_CALLS_TO_LABEL).setText(config.getAvoidCallsTo()); + // close shell and save + closeConfigurationShell(); + } + + /** + * @param config where the projects are listed + * @return String which lists all projects of the configuration separated with + * commas + */ + private String getProjectsAsString(PitRunConfiguration config) { + return config.getProjects().stream() + .map(Object::toString) + .collect(Collectors.joining(",")); + } + + public void setMutatorGroup(String configurationName, Mutators mutatorGroup) { + activateMutatorsTab(configurationName); + bot.radio(mutatorGroup.getDescriptor()).click(); + closeConfigurationShell(); + } + + public void toggleCustomMutator(String configurationName, Mutators mutator) { + activateMutatorsTab(configurationName); + SWTBotRadio radioButton = bot.radio(PitMutatorsTab.CUSTOM_MUTATOR_RADIO_TEXT); + radioButton.click(); + SWTBotTable table = bot.table(); + toggleMutator(table, mutator); + closeConfigurationShell(); + } + + public void setOneCustomMutator(String configurationName, Mutators mutator) { + activateMutatorsTab(configurationName); + bot.radio(PitMutatorsTab.CUSTOM_MUTATOR_RADIO_TEXT).click(); + uncheckAllMutators(); + SWTBotTable table = bot.table(); + toggleMutator(table, mutator); + closeConfigurationShell(); + } + + public void checkAllMutators(String configurationName) { + activateMutatorsTab(configurationName); + bot.radio(PitMutatorsTab.CUSTOM_MUTATOR_RADIO_TEXT).click(); + SWTBotTable table = bot.table(); + Display.getDefault().syncExec(() -> { + final int itemCount = table.widget.getItems().length; + for (int i = 0; i < itemCount; i++) { + table.getTableItem(i).check(); + } + }); + closeConfigurationShell(); + } + + /** + * Assumes the Mutator tab is active and custom mutator mode is selected. + */ + private void uncheckAllMutators() { + SWTBotTable table = bot.table(); + Display.getDefault().syncExec(() -> { + for (TableItem item : table.widget.getItems()) { + item.setChecked(false); + } + }); + // don't close, because you cannot apply empty mutators + } + + /** + * Assumes the Mutator tab is active and custom mutator mode is selected. + * @param table where to check the mutator + * @param mutator which is set to active + */ + private void toggleMutator(SWTBotTable table, Mutators mutator) { + table.getTableItem(mutator.getDescriptor()).toggleCheck(); + } + + /** + * Closes the configuration shell and applies, if possible. + */ + private void closeConfigurationShell() { + SWTBotShell shell = bot.shell(RUN_CONFIGURATIONS); + SWTBotButton apply = shell.bot().button("Apply"); + if (apply.isEnabled()) { + apply.click(); + } + shell.bot().button("Close").click(); + } + + /** + * Runs the configuration specified by the given name and waits for it to be + * finished. + * @param configurationName + */ + public void runWithConfigurationAndWaitForIt(String configurationName) { + // reset Summary result + PitSummary.INSTANCE.resetSummary(); + activateConfiguration(configurationName); + SWTBotShell shell = bot.shell(RUN_CONFIGURATIONS); + shell.bot().button(RUN).click(); + // wait for pit + PitSummary.INSTANCE.waitForPitToFinish(); + } + + /** + * Deletes the pit run configuration, which matches the given name + * @param configurationName which should be deleted + */ + public void removeConfig(String configurationName) { + for (SWTBotTreeItem i : getPitConfigurationItem().getItems()) { + if (i.getText().equals(configurationName)) { + i.contextMenu("Delete").click(); + bot.waitUntil(shellIsActive(DELETE_SHELL_TITLE)); + bot.shell(DELETE_SHELL_TITLE).bot().button("Delete").click(); + return; } } - return null; + fail("Could not find '" + configurationName + "' in the configurations of PIT."); } } diff --git a/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/behaviours/pageobjects/RunMenu.java b/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/behaviours/pageobjects/RunMenu.java index b226f7f0..0a4e12da 100644 --- a/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/behaviours/pageobjects/RunMenu.java +++ b/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/behaviours/pageobjects/RunMenu.java @@ -22,6 +22,7 @@ import org.eclipse.swtbot.swt.finder.exceptions.WidgetNotFoundException; import org.eclipse.swtbot.swt.finder.widgets.SWTBotMenu; import org.eclipse.swtbot.swt.finder.widgets.SWTBotShell; +import org.pitest.pitclipse.core.Mutators; import org.pitest.pitclipse.runner.PitOptions; import org.pitest.pitclipse.ui.swtbot.PitOptionsNotifier; import org.pitest.pitclipse.ui.swtbot.SWTBotMenuHelper; @@ -32,7 +33,6 @@ public class RunMenu { private static final String RUN_AS = "Run As"; private static final String PIT_MUTATION_TEST = "PIT Mutation Test"; private static final String JUNIT_TEST = "JUnit Test"; - private static final String RUN_CONFIGURATIONS = "Run Configurations"; private final SWTWorkbenchBot bot; private final RunConfigurationSelector runConfigurationSelector; @@ -58,6 +58,10 @@ public void runPit() { ensureSelectTestConfigurationDialogIsClosed(); } + public void runPitWithConfiguration(String configurationName) { + runConfigurationSelector.runWithConfigurationAndWaitForIt(configurationName); + } + /** * The 'Select a Test Configuration' dialog only appears when Pit has been * launched at least once. If it is not found then PIT has been launched @@ -80,13 +84,67 @@ private void ensureSelectTestConfigurationDialogIsClosed() { } public List runConfigurations() { - SWTBotMenuHelper menuHelper = new SWTBotMenuHelper(); - menuHelper.findMenu(bot.menu(RUN), RUN_CONFIGURATIONS).click(); return runConfigurationSelector.getConfigurations(); } + public void createRunConfiguration(String configurationName, String projectName, String className) { + runConfigurationSelector.createRunConfiguration(configurationName, projectName, className); + } + + public void setProjectForConfiguration(String configurationName, String project) { + runConfigurationSelector.setProjectForConfiguration(configurationName, project); + } + + public void setTestClassForConfiguration(String configurationName, String testClass) { + runConfigurationSelector.setTestClassForConfiguration(configurationName, testClass); + } + public PitOptions getLastUsedPitOptions() { return PitOptionsNotifier.INSTANCE.getLastUsedOptions(); } + /** + * Selects the given group in the mutator launch configuration tab. + * @param configurationName where to select the group + * @param mutatorGroup which group to select + */ + public void setMutatorGroup(String configurationName, Mutators mutatorGroup) { + runConfigurationSelector.setMutatorGroup(configurationName, mutatorGroup); + } + + /** + * Checks all custom mutators for the given configuration + * @param configurationName of the configuration, where to select all mutators + */ + public void checkAllMutators(String configurationName) { + runConfigurationSelector.checkAllMutators(configurationName); + } + + /** + * Toggle the given mutator in the table of mutators + * @param configurationName which the mutator should be toggled + * @param mutator which should be toggled + */ + public void toggleCustomMutator(String configurationName, Mutators mutator) { + runConfigurationSelector.toggleCustomMutator(configurationName, mutator); + } + + /** + * Unchecks all custom mutators and selects the given mutator for the + * configuration specified by the given name + * @param configurationName where to select the one mutator + * @param mutator which to select in the configuration + */ + public void setOneCustomMutator(String configurationName, Mutators mutator) { + runConfigurationSelector.setOneCustomMutator(configurationName, mutator); + } + + /** + * Removes the pit run configuration, which matches the given name. + * @param configurationName which should be removed + */ + public void removeConfig(String configurationName) { + runConfigurationSelector.removeConfig(configurationName); + } + } diff --git a/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/behaviours/pageobjects/WindowsMenu.java b/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/behaviours/pageobjects/WindowsMenu.java index 4a9024e2..546504d1 100644 --- a/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/behaviours/pageobjects/WindowsMenu.java +++ b/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/behaviours/pageobjects/WindowsMenu.java @@ -25,7 +25,7 @@ import org.eclipse.swtbot.swt.finder.waits.Conditions; import org.eclipse.ui.dialogs.PreferencesUtil; import org.pitest.pitclipse.core.PitCoreActivator; -import org.pitest.pitclipse.core.PitMutators; +import org.pitest.pitclipse.core.Mutators; import org.pitest.pitclipse.runner.config.PitExecutionMode; public class WindowsMenu { @@ -155,12 +155,12 @@ public void openPitMutationsView() { viewSelector.selectView("PIT", "PIT Mutations"); } - public PitMutators getMutators() { + public Mutators getMutators() { return openPreferences().andThen().getMutators(); } - public void setMutators(PitMutators mutators) { - PitCoreActivator.getDefault().setMutators(mutators); + public void setMutatorGroup(Mutators mutators) { + PitCoreActivator.getDefault().setDefaultMutatorGroup(mutators); } public void setTimeoutConstant(int timeout) { diff --git a/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/behaviours/steps/PreferencesSteps.java b/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/behaviours/steps/PreferencesSteps.java index 46a97e5f..fccc4e67 100644 --- a/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/behaviours/steps/PreferencesSteps.java +++ b/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/behaviours/steps/PreferencesSteps.java @@ -21,7 +21,7 @@ import cucumber.api.java.en.When; import org.hamcrest.Description; import org.hamcrest.TypeSafeMatcher; -import org.pitest.pitclipse.core.PitMutators; +import org.pitest.pitclipse.core.Mutators; import org.pitest.pitclipse.runner.config.PitExecutionMode; import java.math.BigDecimal; @@ -33,8 +33,6 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; -import static org.pitest.pitclipse.core.PitMutators.ALL; -import static org.pitest.pitclipse.core.PitMutators.STRONGER; import static org.pitest.pitclipse.runner.config.PitConfiguration.DEFAULT_AVOID_CALLS_TO_LIST; import static org.pitest.pitclipse.runner.config.PitConfiguration.DEFAULT_MUTATORS; import static org.pitest.pitclipse.runner.config.PitExecutionMode.PROJECT_ISOLATION; @@ -149,18 +147,18 @@ public void setAvoidCalls(String avoidCallsTo) { @Then("the default mutators preference is selected") public void defaultMutators() { - PitMutators selectedMutators = PAGES.getWindowsMenu().getMutators(); + Mutators selectedMutators = PAGES.getWindowsMenu().getMutators(); assertThat(selectedMutators.toString(), is(equalTo(DEFAULT_MUTATORS))); } @Given("the stronger mutator preference is selected") public void useStrongerMutators() { - PAGES.getWindowsMenu().setMutators(STRONGER); + PAGES.getWindowsMenu().setMutatorGroup(Mutators.STRONGER); } @Given("the all mutators preference is selected") public void useAllMutators() { - PAGES.getWindowsMenu().setMutators(ALL); + PAGES.getWindowsMenu().setMutatorGroup(Mutators.ALL); } @Given("the timeout constant is {int}") diff --git a/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/swtbot/PitResultNotifier.java b/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/swtbot/PitResultNotifier.java index 596c9a8b..a0c5ebf8 100644 --- a/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/swtbot/PitResultNotifier.java +++ b/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/swtbot/PitResultNotifier.java @@ -124,7 +124,8 @@ public void waitForPitToFinish() { } /** - * Waits for PIT to finish. + * Waits for PIT to finish.
+ * Mandatory to call {@link #resetSummary()} before. * @param timeOut after the wait stops, if not set use SWTBotPreferences.TIMEOUT */ public void waitForPitToFinish(long timeOut) { diff --git a/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/tests/AbstractPitclipseSWTBotTest.java b/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/tests/AbstractPitclipseSWTBotTest.java index 255f0dcd..0bda2e3e 100644 --- a/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/tests/AbstractPitclipseSWTBotTest.java +++ b/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/tests/AbstractPitclipseSWTBotTest.java @@ -18,6 +18,7 @@ import static java.lang.Integer.parseInt; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.greaterThanOrEqualTo; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -25,6 +26,8 @@ import java.io.File; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -54,6 +57,7 @@ import org.junit.rules.TestWatcher; import org.junit.runner.Description; import org.junit.runner.RunWith; +import org.pitest.pitclipse.core.Mutators; import org.pitest.pitclipse.core.PitCoreActivator; import org.pitest.pitclipse.launch.ui.PitLaunchShortcut; import org.pitest.pitclipse.runner.results.DetectionStatus; @@ -328,6 +332,24 @@ protected static void runProjectTest(final String projectName) throws CoreExcept new PitclipseSteps().runProjectTest(projectName); } + /** + * Asserts that the only active mutator was the given mutator. + * @param mutators which should be the only active mutator + */ + protected static void mutatorIs(Mutators mutator) { + mutatorsAre(Arrays.asList(new Mutators[] { mutator })); + } + + /** + * Asserts that the only active mutators are the given mutators. + * @param mutators which should be the only active mutators + */ + protected static void mutatorsAre(Collection mutators) { + final String consoleText = PAGES.getConsole().getText(); + assertThat(consoleText, containsString(String.format("mutators=[%s]", + mutators.stream().map(Object::toString).collect(Collectors.joining(","))))); + } + /** * The expectedMutationsTable String argument represents the expected * mutations table, this is an example of String: diff --git a/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/tests/PitclipseMultipleProjectsTest.java b/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/tests/PitclipseMultipleProjectsTest.java index 7d76d46a..b09aa6df 100644 --- a/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/tests/PitclipseMultipleProjectsTest.java +++ b/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/tests/PitclipseMultipleProjectsTest.java @@ -81,7 +81,7 @@ public void testExecutionMode() throws CoreException { } finally { // reset default values IPreferenceStore preferenceStore = PitCoreActivator.getDefault().getPreferenceStore(); - preferenceStore.setValue(PitPreferences.PIT_EXECUTION_MODE, PROJECT_ISOLATION.toString()); + preferenceStore.setValue(PitPreferences.EXECUTION_MODE, PROJECT_ISOLATION.toString()); PitPreferenceSelector selector = PAGES.getWindowsMenu().openPreferences().andThen(); assertEquals(PROJECT_ISOLATION, selector.getPitExecutionMode()); selector.close(); diff --git a/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/tests/PitclipseOptionsTest.java b/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/tests/PitclipseOptionsTest.java index 5814f0e8..3da792da 100644 --- a/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/tests/PitclipseOptionsTest.java +++ b/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/tests/PitclipseOptionsTest.java @@ -5,7 +5,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static org.pitest.pitclipse.core.PitMutators.STRONGER; import static org.pitest.pitclipse.runner.config.PitConfiguration.DEFAULT_AVOID_CALLS_TO_LIST; import static org.pitest.pitclipse.runner.config.PitConfiguration.DEFAULT_MUTATORS; import static org.pitest.pitclipse.runner.config.PitExecutionMode.PROJECT_ISOLATION; @@ -18,8 +17,8 @@ import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; +import org.pitest.pitclipse.core.Mutators; import org.pitest.pitclipse.core.PitCoreActivator; -import org.pitest.pitclipse.core.PitMutators; import org.pitest.pitclipse.core.preferences.PitPreferences; import org.pitest.pitclipse.runner.config.PitConfiguration; import org.pitest.pitclipse.ui.behaviours.pageobjects.PitPreferenceSelector; @@ -68,6 +67,27 @@ public void defaultOptions() { selector.close(); } + @Test + public void useOldDefaultsMutators() throws CoreException { + // set OLD_DEFAULTS mutators + PAGES.getWindowsMenu().setMutatorGroup(Mutators.OLD_DEFAULTS); + try { + runPackageTest(FOO_BAR_PACKAGE, TEST_PROJECT); + coverageReportGenerated(2, 80, 0, 8, 0); + mutationsAre( "SURVIVED | " + TEST_PROJECT + " | foo.bar | foo.bar.Bar | 7 | negated conditional\n" + + "SURVIVED | " + TEST_PROJECT + " | foo.bar | foo.bar.Bar | 10 | replaced return of integer sized value with (x == 0 ? 1 : 0)\n" + + "SURVIVED | " + TEST_PROJECT + " | foo.bar | foo.bar.Foo | 7 | negated conditional\n" + + "SURVIVED | " + TEST_PROJECT + " | foo.bar | foo.bar.Foo | 10 | replaced return of integer sized value with (x == 0 ? 1 : 0)\n" + + "NO_COVERAGE | " + TEST_PROJECT + " | foo.bar | foo.bar.Bar | 8 | Replaced integer addition with subtraction\n" + + "NO_COVERAGE | " + TEST_PROJECT + " | foo.bar | foo.bar.Bar | 8 | replaced return of integer sized value with (x == 0 ? 1 : 0)\n" + + "NO_COVERAGE | " + TEST_PROJECT + " | foo.bar | foo.bar.Foo | 8 | Replaced integer addition with subtraction\n" + + "NO_COVERAGE | " + TEST_PROJECT + " | foo.bar | foo.bar.Foo | 8 | replaced return of integer sized value with (x == 0 ? 1 : 0)"); + } finally { + // it's crucial to reset it to the default or we break other tests + PAGES.getWindowsMenu().setMutatorGroup(Mutators.DEFAULTS); + } + } + @Test public void useDefaultMutators() throws CoreException { runPackageTest(FOO_BAR_PACKAGE, TEST_PROJECT); @@ -84,7 +104,7 @@ public void useDefaultMutators() throws CoreException { @Test public void useStrongerMutators() throws CoreException { // now set STRONGER mutators - PAGES.getWindowsMenu().setMutators(STRONGER); + PAGES.getWindowsMenu().setMutatorGroup(Mutators.STRONGER); try { runPackageTest(FOO_BAR_PACKAGE, TEST_PROJECT); coverageReportGenerated(2, 80, 0, 8, 0); @@ -99,7 +119,7 @@ public void useStrongerMutators() throws CoreException { "NO_COVERAGE | " + TEST_PROJECT + " | foo.bar | foo.bar.Foo | 8 | replaced int return with 0 for foo/bar/Foo::f"); } finally { // it's crucial to reset it to the default or we break other tests - PAGES.getWindowsMenu().setMutators(PitMutators.DEFAULTS); + PAGES.getWindowsMenu().setMutatorGroup(Mutators.DEFAULTS); } } diff --git a/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/tests/PitclipseRunConfigurationMutationTabTest.java b/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/tests/PitclipseRunConfigurationMutationTabTest.java new file mode 100644 index 00000000..06d373db --- /dev/null +++ b/tests/org.pitest.pitclipse.ui.tests/src/org/pitest/pitclipse/ui/tests/PitclipseRunConfigurationMutationTabTest.java @@ -0,0 +1,255 @@ +/******************************************************************************* + * Copyright 2021 Jonas Kutscha and contributors + * + * 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.pitclipse.ui.tests; + +import static org.pitest.pitclipse.ui.behaviours.pageobjects.PageObjects.PAGES; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.swtbot.swt.finder.junit.SWTBotJunit4ClassRunner; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.pitest.pitclipse.core.Mutators; + +/** + * @author Jonas Kutscha + * + */ +@RunWith(SWTBotJunit4ClassRunner.class) +public class PitclipseRunConfigurationMutationTabTest extends AbstractPitclipseSWTBotTest { + private static final String TEST_PROJECT = "org.pitest.pitclipse.testprojects.twoclasses"; + private static final String TEST_CONFIG_NAME = "Testing Config"; + private static final String FOO_BAR_PACKAGE = "foo.bar"; + private static final String FOO_TEST_CLASS = "FooTest"; + + private static final int COVERAGE = 40; + private static final int TESTED_CLASSES = 2; + + @BeforeClass + public static void initialSetup() throws CoreException { + importTestProject(TEST_PROJECT); + PAGES.getRunMenu().createRunConfiguration(TEST_CONFIG_NAME, + TEST_PROJECT, + FOO_BAR_PACKAGE + '.' + FOO_TEST_CLASS); + } + + @AfterClass + public static void removeConfig() { + PAGES.getRunMenu().removeConfig(TEST_CONFIG_NAME); + } + + @After + public void clearConsole() { + PAGES.getConsole().clear(); + } + + @Test + public void pressMutatorGroupButtons() { // NOSONAR + PAGES.getRunMenu().setMutatorGroup(TEST_CONFIG_NAME, Mutators.OLD_DEFAULTS); + PAGES.getRunMenu().setMutatorGroup(TEST_CONFIG_NAME, Mutators.DEFAULTS); + PAGES.getRunMenu().setMutatorGroup(TEST_CONFIG_NAME, Mutators.STRONGER); + PAGES.getRunMenu().setMutatorGroup(TEST_CONFIG_NAME, Mutators.ALL); + PAGES.getRunMenu().setMutatorGroup(TEST_CONFIG_NAME, Mutators.DEFAULTS); + } + + @Test + public void selectNoMutator() { // NOSONAR + PAGES.getRunMenu().setOneCustomMutator(TEST_CONFIG_NAME, Mutators.NEGATE_CONDITIONALS); + PAGES.getRunMenu().toggleCustomMutator(TEST_CONFIG_NAME, Mutators.NEGATE_CONDITIONALS); + // should switch back to previous selected mutator + PAGES.getRunMenu().runPitWithConfiguration(TEST_CONFIG_NAME); + coverageReportGenerated(TESTED_CLASSES, COVERAGE, 0, 2, 0); + // check that mutator was selected as only mutator + mutatorIs(Mutators.NEGATE_CONDITIONALS); + mutationsAre( "SURVIVED | " + TEST_PROJECT + " | foo.bar | foo.bar.Foo | 7 | negated conditional\n" + + "NO_COVERAGE | " + TEST_PROJECT + " | foo.bar | foo.bar.Bar | 7 | negated conditional"); + } + + @Test + public void useOldDefaultsMutatorsGroup() { // NOSONAR + // set OLD_DEFAULTS mutators + PAGES.getRunMenu().setMutatorGroup(TEST_CONFIG_NAME, Mutators.OLD_DEFAULTS); + // run test and confirm result is as expected + PAGES.getRunMenu().runPitWithConfiguration(TEST_CONFIG_NAME); + coverageReportGenerated(TESTED_CLASSES, COVERAGE, 0, 8, 0); + mutationsAre( "SURVIVED | " + TEST_PROJECT + " | foo.bar | foo.bar.Foo | 7 | negated conditional\n" + + "SURVIVED | " + TEST_PROJECT + " | foo.bar | foo.bar.Foo | 10 | replaced return of integer sized value with (x == 0 ? 1 : 0)\n" + + "NO_COVERAGE | " + TEST_PROJECT + " | foo.bar | foo.bar.Bar | 7 | negated conditional\n" + + "NO_COVERAGE | " + TEST_PROJECT + " | foo.bar | foo.bar.Bar | 8 | Replaced integer addition with subtraction\n" + + "NO_COVERAGE | " + TEST_PROJECT + " | foo.bar | foo.bar.Bar | 8 | replaced return of integer sized value with (x == 0 ? 1 : 0)\n" + + "NO_COVERAGE | " + TEST_PROJECT + " | foo.bar | foo.bar.Bar | 10 | replaced return of integer sized value with (x == 0 ? 1 : 0)\n" + + "NO_COVERAGE | " + TEST_PROJECT + " | foo.bar | foo.bar.Foo | 8 | Replaced integer addition with subtraction\n" + + "NO_COVERAGE | " + TEST_PROJECT + " | foo.bar | foo.bar.Foo | 8 | replaced return of integer sized value with (x == 0 ? 1 : 0)"); + } + + @Test + public void useDefaultMutatorsGroup() { // NOSONAR + // set DEFAULTS mutators + PAGES.getRunMenu().setMutatorGroup(TEST_CONFIG_NAME, Mutators.DEFAULTS); + // run test and confirm result is as expected + PAGES.getRunMenu().runPitWithConfiguration(TEST_CONFIG_NAME); + coverageReportGenerated(TESTED_CLASSES, COVERAGE, 0, 6, 0); + mutationsAre( "SURVIVED | " + TEST_PROJECT + " | foo.bar | foo.bar.Foo | 7 | negated conditional\n" + + "NO_COVERAGE | " + TEST_PROJECT + " | foo.bar | foo.bar.Bar | 7 | negated conditional\n" + + "NO_COVERAGE | " + TEST_PROJECT + " | foo.bar | foo.bar.Bar | 8 | Replaced integer addition with subtraction\n" + + "NO_COVERAGE | " + TEST_PROJECT + " | foo.bar | foo.bar.Bar | 8 | replaced int return with 0 for foo/bar/Bar::f\n" + + "NO_COVERAGE | " + TEST_PROJECT + " | foo.bar | foo.bar.Foo | 8 | Replaced integer addition with subtraction\n" + + "NO_COVERAGE | " + TEST_PROJECT + " | foo.bar | foo.bar.Foo | 8 | replaced int return with 0 for foo/bar/Foo::f"); + } + + @Test + public void useStrongerMutatorsGroup() { // NOSONAR + // now set STRONGER mutators + PAGES.getRunMenu().setMutatorGroup(TEST_CONFIG_NAME, Mutators.STRONGER); + // run test and confirm result is as expected + PAGES.getRunMenu().runPitWithConfiguration(TEST_CONFIG_NAME); + coverageReportGenerated(TESTED_CLASSES, COVERAGE, 0, 8, 0); + mutationsAre( "SURVIVED | " + TEST_PROJECT + " | foo.bar | foo.bar.Foo | 7 | negated conditional\n" + + "SURVIVED | " + TEST_PROJECT + " | foo.bar | foo.bar.Foo | 7 | removed conditional - replaced equality check with false\n" + + "NO_COVERAGE | " + TEST_PROJECT + " | foo.bar | foo.bar.Bar | 7 | negated conditional\n" + + "NO_COVERAGE | " + TEST_PROJECT + " | foo.bar | foo.bar.Bar | 7 | removed conditional - replaced equality check with false\n" + + "NO_COVERAGE | " + TEST_PROJECT + " | foo.bar | foo.bar.Bar | 8 | Replaced integer addition with subtraction\n" + + "NO_COVERAGE | " + TEST_PROJECT + " | foo.bar | foo.bar.Bar | 8 | replaced int return with 0 for foo/bar/Bar::f\n" + + "NO_COVERAGE | " + TEST_PROJECT + " | foo.bar | foo.bar.Foo | 8 | Replaced integer addition with subtraction\n" + + "NO_COVERAGE | " + TEST_PROJECT + " | foo.bar | foo.bar.Foo | 8 | replaced int return with 0 for foo/bar/Foo::f"); + } + + @Test + public void checkOneMutant() { // NOSONAR + PAGES.getRunMenu().setOneCustomMutator(TEST_CONFIG_NAME, Mutators.NEGATE_CONDITIONALS); + // run test and confirm result is as expected + PAGES.getRunMenu().runPitWithConfiguration(TEST_CONFIG_NAME); + coverageReportGenerated(TESTED_CLASSES, COVERAGE, 0, 2, 0); + // check that mutator was selected as only mutator + mutatorIs(Mutators.NEGATE_CONDITIONALS); + mutationsAre( "SURVIVED | " + TEST_PROJECT + " | foo.bar | foo.bar.Foo | 7 | negated conditional\n" + + "NO_COVERAGE | " + TEST_PROJECT + " | foo.bar | foo.bar.Bar | 7 | negated conditional"); + } + + /** + * This test will probably fail, if mutators of pit get changed + */ + @Test + public void useAllMutatorsGroup() { // NOSONAR + // now set ALL mutators group + PAGES.getRunMenu().setMutatorGroup(TEST_CONFIG_NAME, Mutators.ALL); + // run test and confirm result is as expected + PAGES.getRunMenu().runPitWithConfiguration(TEST_CONFIG_NAME); + coverageReportGenerated(TESTED_CLASSES, COVERAGE, 1, 84, 1); + mutationsAre(getAllMutantsResult()); + } + + /** + * This test will probably fail, if mutators of pit get changed + */ + @Test + public void checkAllMutants() { // NOSONAR + PAGES.getRunMenu().checkAllMutators(TEST_CONFIG_NAME); + // run test and confirm result is as expected + PAGES.getRunMenu().runPitWithConfiguration(TEST_CONFIG_NAME); + coverageReportGenerated(TESTED_CLASSES, COVERAGE, 1, 84, 1); + mutationsAre(getAllMutantsResult()); + } + + private String getAllMutantsResult(){ + return "SURVIVED | " + TEST_PROJECT + " |foo.bar | foo.bar.Foo | 7 | Substituted 1 with -1\n" + + "SURVIVED | " + TEST_PROJECT + " |foo.bar | foo.bar.Foo | 7 | Substituted 1 with -1\n" + + "SURVIVED | " + TEST_PROJECT + " |foo.bar | foo.bar.Foo | 7 | Substituted 1 with 0\n" + + "SURVIVED | " + TEST_PROJECT + " |foo.bar | foo.bar.Foo | 7 | Substituted 1 with 0\n" + + "SURVIVED | " + TEST_PROJECT + " |foo.bar | foo.bar.Foo | 7 | Substituted 1 with 0\n" + + "SURVIVED | " + TEST_PROJECT + " |foo.bar | foo.bar.Foo | 7 | Substituted 1 with 2\n" + + "SURVIVED | " + TEST_PROJECT + " |foo.bar | foo.bar.Foo | 7 | negated conditional\n" + + "SURVIVED | " + TEST_PROJECT + " |foo.bar | foo.bar.Foo | 7 | not equal to equal\n" + + "SURVIVED | " + TEST_PROJECT + " |foo.bar | foo.bar.Foo | 7 | not equal to greater or equal\n" + + "SURVIVED | " + TEST_PROJECT + " |foo.bar | foo.bar.Foo | 7 | not equal to greater than\n" + + "SURVIVED | " + TEST_PROJECT + " |foo.bar | foo.bar.Foo | 7 | not equal to less or equal\n" + + "SURVIVED | " + TEST_PROJECT + " |foo.bar | foo.bar.Foo | 7 | not equal to less than\n" + + "SURVIVED | " + TEST_PROJECT + " |foo.bar | foo.bar.Foo | 7 | removed call to java/util/ArrayList::size\n" + + "SURVIVED | " + TEST_PROJECT + " |foo.bar | foo.bar.Foo | 7 | removed conditional - replaced equality check with false\n" + + "SURVIVED | " + TEST_PROJECT + " |foo.bar | foo.bar.Foo | 7 | removed conditional - replaced equality check with true\n" + + "SURVIVED | " + TEST_PROJECT + " |foo.bar | foo.bar.Foo | 10 | Substituted 0 with -1\n" + + "SURVIVED | " + TEST_PROJECT + " |foo.bar | foo.bar.Foo | 10 | Substituted 0 with -1\n" + + "SURVIVED | " + TEST_PROJECT + " |foo.bar | foo.bar.Foo | 10 | Substituted 0 with 1\n" + + "SURVIVED | " + TEST_PROJECT + " |foo.bar | foo.bar.Foo | 10 | Substituted 0 with 1\n" + + "SURVIVED | " + TEST_PROJECT + " |foo.bar | foo.bar.Foo | 10 | Substituted 0 with 1\n" + + "SURVIVED | " + TEST_PROJECT + " |foo.bar | foo.bar.Foo | 10 | replaced return of integer sized value with (x == 0 ? 1 : 0)\n" + + "KILLED | " + TEST_PROJECT + " |foo.bar | foo.bar.Foo | 6 | removed call to java/util/ArrayList::\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Bar | 6 | removed call to java/util/ArrayList::\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Bar | 7 | Substituted 1 with -1\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Bar | 7 | Substituted 1 with -1\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Bar | 7 | Substituted 1 with 0\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Bar | 7 | Substituted 1 with 0\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Bar | 7 | Substituted 1 with 0\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Bar | 7 | Substituted 1 with 2\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Bar | 7 | negated conditional\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Bar | 7 | not equal to equal\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Bar | 7 | not equal to greater or equal\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Bar | 7 | not equal to greater than\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Bar | 7 | not equal to less or equal\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Bar | 7 | not equal to less than\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Bar | 7 | removed call to java/util/ArrayList::size\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Bar | 7 | removed conditional - replaced equality check with false\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Bar | 7 | removed conditional - replaced equality check with true\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Bar | 8 | Decremented (--a) integer local variable number 1\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Bar | 8 | Decremented (a--) integer local variable number 1\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Bar | 8 | Incremented (++a) integer local variable number 1\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Bar | 8 | Incremented (a++) integer local variable number 1\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Bar | 8 | Negated integer local variable number 1\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Bar | 8 | Replaced integer addition with division\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Bar | 8 | Replaced integer addition with modulus\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Bar | 8 | Replaced integer addition with multiplication\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Bar | 8 | Replaced integer addition with subtraction\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Bar | 8 | Replaced integer addition with subtraction\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Bar | 8 | Replaced integer operation by second member\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Bar | 8 | Replaced integer operation with first member\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Bar | 8 | Substituted 1 with -1\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Bar | 8 | Substituted 1 with -1\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Bar | 8 | Substituted 1 with 0\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Bar | 8 | Substituted 1 with 0\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Bar | 8 | Substituted 1 with 0\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Bar | 8 | Substituted 1 with 2\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Bar | 8 | replaced int return with 0 for foo/bar/Bar::f\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Bar | 8 | replaced return of integer sized value with (x == 0 ? 1 : 0)\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Bar | 10 | Substituted 0 with -1\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Bar | 10 | Substituted 0 with -1\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Bar | 10 | Substituted 0 with 1\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Bar | 10 | Substituted 0 with 1\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Bar | 10 | Substituted 0 with 1\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Bar | 10 | replaced return of integer sized value with (x == 0 ? 1 : 0)\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Foo | 8 | Decremented (--a) integer local variable number 1\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Foo | 8 | Decremented (a--) integer local variable number 1\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Foo | 8 | Incremented (++a) integer local variable number 1\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Foo | 8 | Incremented (a++) integer local variable number 1\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Foo | 8 | Negated integer local variable number 1\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Foo | 8 | Replaced integer addition with division\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Foo | 8 | Replaced integer addition with modulus\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Foo | 8 | Replaced integer addition with multiplication\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Foo | 8 | Replaced integer addition with subtraction\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Foo | 8 | Replaced integer addition with subtraction\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Foo | 8 | Replaced integer operation by second member\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Foo | 8 | Replaced integer operation with first member\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Foo | 8 | Substituted 1 with -1\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Foo | 8 | Substituted 1 with -1\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Foo | 8 | Substituted 1 with 0\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Foo | 8 | Substituted 1 with 0\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Foo | 8 | Substituted 1 with 0\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Foo | 8 | Substituted 1 with 2\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Foo | 8 | replaced int return with 0 for foo/bar/Foo::f\n" + + "NO_COVERAGE | " + TEST_PROJECT + " |foo.bar | foo.bar.Foo | 8 | replaced return of integer sized value with (x == 0 ? 1 : 0)"; + } +}