From 39d4ba3910dbc68e37836711a7704031276d8feb Mon Sep 17 00:00:00 2001 From: Henry Coles Date: Mon, 3 Apr 2023 14:23:12 +0100 Subject: [PATCH] new extension points for manipulating environment --- .../org/pitest/coverage/CoverageData.java | 5 ----- .../coverage/execute/CoverageMinion.java | 10 +++++++++ .../config/ClientPluginServices.java | 10 +++++++++ .../mutationtest/config/MinionSettings.java | 10 +++++++++ .../engine/gregor/MethodMutationContext.java | 20 +++++++++++------- .../engine/gregor/MutationContext.java | 2 ++ .../environment/CompositeReset.java | 21 +++++++++++++++++++ .../environment/EnvironmentResetPlugin.java | 9 ++++++++ .../environment/ResetEnvironment.java | 7 +++++++ .../environment/TransformationPlugin.java | 11 ++++++++++ .../mutationtest/execute/MinionArguments.java | 2 +- .../execute/MutationTestMinion.java | 14 ++++++++++++- .../execute/MutationTestWorker.java | 13 +++++++++--- .../execute/MutationTestWorkerTest.java | 6 +++++- 14 files changed, 121 insertions(+), 19 deletions(-) create mode 100644 pitest/src/main/java/org/pitest/mutationtest/environment/CompositeReset.java create mode 100644 pitest/src/main/java/org/pitest/mutationtest/environment/EnvironmentResetPlugin.java create mode 100644 pitest/src/main/java/org/pitest/mutationtest/environment/ResetEnvironment.java create mode 100644 pitest/src/main/java/org/pitest/mutationtest/environment/TransformationPlugin.java diff --git a/pitest-entry/src/main/java/org/pitest/coverage/CoverageData.java b/pitest-entry/src/main/java/org/pitest/coverage/CoverageData.java index 5a8982ba4..fde7b4778 100644 --- a/pitest-entry/src/main/java/org/pitest/coverage/CoverageData.java +++ b/pitest-entry/src/main/java/org/pitest/coverage/CoverageData.java @@ -161,11 +161,6 @@ private void checkForFailedTest(final CoverageResult cr) { private TestInfo createTestInfo(final Description description, final int executionTime, final int linesCovered) { - - if (description.getFirstTestClass() == null) { - System.out.println(description); - } - final Optional testee = this.code.findTestee(description .getFirstTestClass()); return new TestInfo(description.getFirstTestClass(), diff --git a/pitest/src/main/java/org/pitest/coverage/execute/CoverageMinion.java b/pitest/src/main/java/org/pitest/coverage/execute/CoverageMinion.java index 43c242547..5f266ed04 100644 --- a/pitest/src/main/java/org/pitest/coverage/execute/CoverageMinion.java +++ b/pitest/src/main/java/org/pitest/coverage/execute/CoverageMinion.java @@ -22,6 +22,7 @@ import org.pitest.help.PitHelpError; import org.pitest.mutationtest.config.ClientPluginServices; import org.pitest.mutationtest.config.MinionSettings; +import org.pitest.mutationtest.environment.TransformationPlugin; import org.pitest.mutationtest.mocksupport.BendJavassistToMyWillTransformer; import org.pitest.mutationtest.mocksupport.JavassistInputStreamInterceptorAdapater; import org.pitest.testapi.Configuration; @@ -81,6 +82,8 @@ public static void main(final String[] args) { HotSwapAgent.addTransformer(new CoverageTransformer( convertToJVMClassFilter(paramsFromParent.getFilter()))); + enableTransformations(); + final List tus = getTestsFromParent(dis, paramsFromParent, invokeQueue); LOG.info(() -> tus.size() + " tests discovered"); @@ -123,6 +126,13 @@ public static void main(final String[] args) { } + private static void enableTransformations() { + ClientPluginServices plugins = ClientPluginServices.makeForContextLoader(); + for (TransformationPlugin each : plugins.findTransformations()) { + HotSwapAgent.addTransformer(each.makeTransformer()); + } + } + private static List removeTestsExecutedDuringDiscovery(List tus) { List toExecute = tus.stream() .filter(t -> !(t instanceof ExecutedInDiscovery)) diff --git a/pitest/src/main/java/org/pitest/mutationtest/config/ClientPluginServices.java b/pitest/src/main/java/org/pitest/mutationtest/config/ClientPluginServices.java index adab9639b..4524f4a79 100644 --- a/pitest/src/main/java/org/pitest/mutationtest/config/ClientPluginServices.java +++ b/pitest/src/main/java/org/pitest/mutationtest/config/ClientPluginServices.java @@ -2,7 +2,9 @@ import java.util.Collection; +import org.pitest.mutationtest.environment.EnvironmentResetPlugin; import org.pitest.mutationtest.MutationEngineFactory; +import org.pitest.mutationtest.environment.TransformationPlugin; import org.pitest.testapi.TestPluginFactory; import org.pitest.util.IsolationUtils; import org.pitest.util.ServiceLoader; @@ -26,4 +28,12 @@ Collection findMutationEngines() { return ServiceLoader.load(MutationEngineFactory.class, this.loader); } + Collection findResets() { + return ServiceLoader.load(EnvironmentResetPlugin.class, this.loader); + } + + public Collection findTransformations() { + return ServiceLoader.load(TransformationPlugin.class, this.loader); + } + } diff --git a/pitest/src/main/java/org/pitest/mutationtest/config/MinionSettings.java b/pitest/src/main/java/org/pitest/mutationtest/config/MinionSettings.java index e45b252b6..dac4dd3c4 100644 --- a/pitest/src/main/java/org/pitest/mutationtest/config/MinionSettings.java +++ b/pitest/src/main/java/org/pitest/mutationtest/config/MinionSettings.java @@ -3,7 +3,10 @@ import org.pitest.classinfo.ClassByteArraySource; import org.pitest.help.PitHelpError; import org.pitest.junit.NullConfiguration; +import org.pitest.mutationtest.environment.CompositeReset; +import org.pitest.mutationtest.environment.EnvironmentResetPlugin; import org.pitest.mutationtest.MutationEngineFactory; +import org.pitest.mutationtest.environment.ResetEnvironment; import org.pitest.testapi.Configuration; import org.pitest.util.PitError; @@ -20,6 +23,12 @@ public MinionSettings(final ClientPluginServices plugins) { this.plugins = plugins; } + public ResetEnvironment createReset() { + List resets = this.plugins.findResets().stream() + .map(EnvironmentResetPlugin::make).collect(Collectors.toList()); + return new CompositeReset(resets); + } + public MutationEngineFactory createEngine(String engine) { for (final MutationEngineFactory each : this.plugins.findMutationEngines()) { if (each.name().equals(engine)) { @@ -49,4 +58,5 @@ public Configuration getTestFrameworkPlugin(TestPluginArguments options, ClassBy } + } diff --git a/pitest/src/main/java/org/pitest/mutationtest/engine/gregor/MethodMutationContext.java b/pitest/src/main/java/org/pitest/mutationtest/engine/gregor/MethodMutationContext.java index 61313575a..9c9562026 100644 --- a/pitest/src/main/java/org/pitest/mutationtest/engine/gregor/MethodMutationContext.java +++ b/pitest/src/main/java/org/pitest/mutationtest/engine/gregor/MethodMutationContext.java @@ -22,17 +22,21 @@ class MethodMutationContext implements MutationContext, InstructionCounter { @Override public MutationIdentifier registerMutation( final MethodMutatorFactory factory, final String description) { - final MutationIdentifier newId = getNextMutationIdentifer(factory, - this.classContext.getJavaClassName()); - final MutationDetails details = new MutationDetails(newId, - this.classContext.getFileName(), description, this.lastLineNumber, - this.classContext.getCurrentBlock()); - registerMutation(details); + final MutationIdentifier newId = getNextMutationIdentifier(factory); + registerMutation(newId, description); return newId; } - private MutationIdentifier getNextMutationIdentifer( - final MethodMutatorFactory factory, final String className) { + @Override + public void registerMutation(MutationIdentifier id, String description) { + final MutationDetails details = new MutationDetails(id, + this.classContext.getFileName(), description, this.lastLineNumber, + this.classContext.getCurrentBlock()); + registerMutation(details); + } + + private MutationIdentifier getNextMutationIdentifier( + final MethodMutatorFactory factory) { return new MutationIdentifier(this.location, this.instructionIndex, factory.getGloballyUniqueId()); } diff --git a/pitest/src/main/java/org/pitest/mutationtest/engine/gregor/MutationContext.java b/pitest/src/main/java/org/pitest/mutationtest/engine/gregor/MutationContext.java index f4cef4908..84d31503d 100644 --- a/pitest/src/main/java/org/pitest/mutationtest/engine/gregor/MutationContext.java +++ b/pitest/src/main/java/org/pitest/mutationtest/engine/gregor/MutationContext.java @@ -12,6 +12,8 @@ public interface MutationContext extends BlockCounter { MutationIdentifier registerMutation(MethodMutatorFactory factory, String description); + void registerMutation(MutationIdentifier id, String description); + boolean shouldMutate(MutationIdentifier newId); } \ No newline at end of file diff --git a/pitest/src/main/java/org/pitest/mutationtest/environment/CompositeReset.java b/pitest/src/main/java/org/pitest/mutationtest/environment/CompositeReset.java new file mode 100644 index 000000000..fc1e24e86 --- /dev/null +++ b/pitest/src/main/java/org/pitest/mutationtest/environment/CompositeReset.java @@ -0,0 +1,21 @@ +package org.pitest.mutationtest.environment; + +import org.pitest.mutationtest.engine.Mutant; + +import java.util.Collections; +import java.util.List; + +public class CompositeReset implements ResetEnvironment { + private final List children; + + public CompositeReset(List children) { + this.children = Collections.unmodifiableList(children); + } + + @Override + public void resetFor(Mutant mutatedClass) { + for (ResetEnvironment each : children) { + each.resetFor(mutatedClass); + } + } +} diff --git a/pitest/src/main/java/org/pitest/mutationtest/environment/EnvironmentResetPlugin.java b/pitest/src/main/java/org/pitest/mutationtest/environment/EnvironmentResetPlugin.java new file mode 100644 index 000000000..29868986e --- /dev/null +++ b/pitest/src/main/java/org/pitest/mutationtest/environment/EnvironmentResetPlugin.java @@ -0,0 +1,9 @@ +package org.pitest.mutationtest.environment; + +import org.pitest.plugin.ClientClasspathPlugin; + +public interface EnvironmentResetPlugin extends ClientClasspathPlugin { + + ResetEnvironment make(); + +} diff --git a/pitest/src/main/java/org/pitest/mutationtest/environment/ResetEnvironment.java b/pitest/src/main/java/org/pitest/mutationtest/environment/ResetEnvironment.java new file mode 100644 index 000000000..b8b3c9914 --- /dev/null +++ b/pitest/src/main/java/org/pitest/mutationtest/environment/ResetEnvironment.java @@ -0,0 +1,7 @@ +package org.pitest.mutationtest.environment; + +import org.pitest.mutationtest.engine.Mutant; + +public interface ResetEnvironment { + void resetFor(Mutant mutatedClass); +} diff --git a/pitest/src/main/java/org/pitest/mutationtest/environment/TransformationPlugin.java b/pitest/src/main/java/org/pitest/mutationtest/environment/TransformationPlugin.java new file mode 100644 index 000000000..2dc9611a9 --- /dev/null +++ b/pitest/src/main/java/org/pitest/mutationtest/environment/TransformationPlugin.java @@ -0,0 +1,11 @@ +package org.pitest.mutationtest.environment; + +import org.pitest.plugin.ClientClasspathPlugin; + +import java.lang.instrument.ClassFileTransformer; + +public interface TransformationPlugin extends ClientClasspathPlugin { + + ClassFileTransformer makeTransformer(); + +} diff --git a/pitest/src/main/java/org/pitest/mutationtest/execute/MinionArguments.java b/pitest/src/main/java/org/pitest/mutationtest/execute/MinionArguments.java index 1a0c35ce7..1fd5854f1 100644 --- a/pitest/src/main/java/org/pitest/mutationtest/execute/MinionArguments.java +++ b/pitest/src/main/java/org/pitest/mutationtest/execute/MinionArguments.java @@ -38,7 +38,7 @@ public class MinionArguments implements Serializable { final TestPluginArguments pitConfig; public MinionArguments(final Collection mutations, - final Collection tests, final String engine, final EngineArguments engineArgs, + final Collection tests, final String engine, final EngineArguments engineArgs, final TimeoutLengthStrategy timeoutStrategy, final Verbosity verbosity, final boolean fullMutationMatrix, final TestPluginArguments pitConfig) { this.mutations = mutations; diff --git a/pitest/src/main/java/org/pitest/mutationtest/execute/MutationTestMinion.java b/pitest/src/main/java/org/pitest/mutationtest/execute/MutationTestMinion.java index 1789eee83..5322f181b 100644 --- a/pitest/src/main/java/org/pitest/mutationtest/execute/MutationTestMinion.java +++ b/pitest/src/main/java/org/pitest/mutationtest/execute/MutationTestMinion.java @@ -21,10 +21,12 @@ import org.pitest.classpath.ClassloaderByteArraySource; import org.pitest.functional.prelude.Prelude; import org.pitest.mutationtest.EngineArguments; +import org.pitest.mutationtest.environment.ResetEnvironment; import org.pitest.mutationtest.config.ClientPluginServices; import org.pitest.mutationtest.config.MinionSettings; import org.pitest.mutationtest.config.TestPluginArguments; import org.pitest.mutationtest.engine.MutationEngine; +import org.pitest.mutationtest.environment.TransformationPlugin; import org.pitest.mutationtest.mocksupport.BendJavassistToMyWillTransformer; import org.pitest.mutationtest.mocksupport.JavassistInputStreamInterceptorAdapater; import org.pitest.mutationtest.mocksupport.JavassistInterceptor; @@ -84,9 +86,10 @@ public void run() { final MutationEngine engine = createEngine(paramsFromParent.engine, paramsFromParent.engineArgs); + final ResetEnvironment reset = this.plugins.createReset(); final MutationTestWorker worker = new MutationTestWorker(hotswap, - engine.createMutator(byteSource), loader, paramsFromParent.fullMutationMatrix); + engine.createMutator(byteSource), loader, reset, paramsFromParent.fullMutationMatrix); final List tests = findTestsForTestClasses(loader, paramsFromParent.testClasses, createTestPlugin(paramsFromParent.pitConfig)); @@ -125,6 +128,8 @@ public static void main(final String[] args) { enablePowerMockSupport(); HotSwapAgent.addTransformer(new CatchNewClassLoadersTransformer()); + enableTransformations(); + final int port = Integer.parseInt(args[0]); Socket s = null; @@ -166,6 +171,13 @@ private static void enablePowerMockSupport() { .or(new Glob("javassist/*")), JavassistInputStreamInterceptorAdapater.inputStreamAdapterSupplier(JavassistInterceptor.class))); } + private static void enableTransformations() { + ClientPluginServices plugins = ClientPluginServices.makeForContextLoader(); + for (TransformationPlugin each : plugins.findTransformations()) { + HotSwapAgent.addTransformer(each.makeTransformer()); + } + } + private static void safelyCloseSocket(final Socket s) { if (s != null) { try { diff --git a/pitest/src/main/java/org/pitest/mutationtest/execute/MutationTestWorker.java b/pitest/src/main/java/org/pitest/mutationtest/execute/MutationTestWorker.java index a0e4e2569..fb909587d 100644 --- a/pitest/src/main/java/org/pitest/mutationtest/execute/MutationTestWorker.java +++ b/pitest/src/main/java/org/pitest/mutationtest/execute/MutationTestWorker.java @@ -16,6 +16,7 @@ import org.pitest.mutationtest.DetectionStatus; import org.pitest.mutationtest.MutationStatusTestPair; +import org.pitest.mutationtest.environment.ResetEnvironment; import org.pitest.mutationtest.engine.Mutant; import org.pitest.mutationtest.engine.Mutater; import org.pitest.mutationtest.engine.MutationDetails; @@ -57,10 +58,15 @@ public class MutationTestWorker { private final HotSwap hotswap; private final boolean fullMutationMatrix; - public MutationTestWorker( - final HotSwap hotswap, - final Mutater mutater, final ClassLoader loader, final boolean fullMutationMatrix) { + private final ResetEnvironment reset; + + public MutationTestWorker(HotSwap hotswap, + Mutater mutater, + ClassLoader loader, + ResetEnvironment reset, + boolean fullMutationMatrix) { this.loader = loader; + this.reset = reset; this.mutater = mutater; this.hotswap = hotswap; this.fullMutationMatrix = fullMutationMatrix; @@ -94,6 +100,7 @@ private void processMutation(final Reporter r, // mess with the internals of Javassist so our mutated class // bytes are returned JavassistInterceptor.setMutant(mutatedClass); + reset.resetFor(mutatedClass); if (DEBUG) { LOG.fine("mutating method " + mutatedClass.getDetails().getMethod()); diff --git a/pitest/src/test/java/org/pitest/mutationtest/execute/MutationTestWorkerTest.java b/pitest/src/test/java/org/pitest/mutationtest/execute/MutationTestWorkerTest.java index 95cb40e18..0c6066c53 100644 --- a/pitest/src/test/java/org/pitest/mutationtest/execute/MutationTestWorkerTest.java +++ b/pitest/src/test/java/org/pitest/mutationtest/execute/MutationTestWorkerTest.java @@ -21,6 +21,7 @@ import org.pitest.classinfo.ClassName; import org.pitest.mutationtest.DetectionStatus; import org.pitest.mutationtest.MutationStatusTestPair; +import org.pitest.mutationtest.environment.ResetEnvironment; import org.pitest.mutationtest.engine.Mutant; import org.pitest.mutationtest.engine.Mutater; import org.pitest.mutationtest.engine.MutationDetails; @@ -50,11 +51,14 @@ public class MutationTestWorkerTest { @Mock private Reporter reporter; + @Mock + private ResetEnvironment reset; + @Before public void setUp() { MockitoAnnotations.openMocks(this); this.testee = new MutationTestWorker(this.hotswapper, this.mutater, - this.loader, false); + this.loader, this.reset,false); } @Test