Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend transformation extension point #1348

Merged
merged 1 commit into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,16 @@
import org.pitest.classinfo.ClassName;
import org.pitest.classpath.ClassloaderByteArraySource;
import org.pitest.coverage.CoverageTransformer;
import org.pitest.functional.prelude.Prelude;
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;
import org.pitest.testapi.ExecutedInDiscovery;
import org.pitest.testapi.TestUnit;
import org.pitest.testapi.TestUnitExecutionListener;
import org.pitest.testapi.execute.FindTestUnits;
import org.pitest.util.ExitCode;
import org.pitest.util.Glob;
import org.pitest.util.Log;
import org.pitest.util.SafeDataInputStream;
import sun.pitest.CodeCoverageStore;
Expand All @@ -55,7 +51,7 @@ public class CoverageMinion {

public static void main(final String[] args) {

enablePowerMockSupport();
enableTransformations();

ExitCode exitCode = ExitCode.OK;
Socket s = null;
Expand All @@ -82,8 +78,6 @@ public static void main(final String[] args) {
HotSwapAgent.addTransformer(new CoverageTransformer(
convertToJVMClassFilter(paramsFromParent.getFilter())));

enableTransformations();

final List<TestUnit> tus = getTestsFromParent(dis, paramsFromParent, invokeQueue);

LOG.info(() -> tus.size() + " tests discovered");
Expand Down Expand Up @@ -129,7 +123,7 @@ public static void main(final String[] args) {
private static void enableTransformations() {
ClientPluginServices plugins = ClientPluginServices.makeForContextLoader();
for (TransformationPlugin each : plugins.findTransformations()) {
HotSwapAgent.addTransformer(each.makeTransformer());
HotSwapAgent.addTransformer(each.makeCoverageTransformer());
}
}

Expand All @@ -140,13 +134,6 @@ private static List<TestUnit> removeTestsExecutedDuringDiscovery(List<TestUnit>
return toExecute;
}

private static void enablePowerMockSupport() {
// Bwahahahahahahaha
HotSwapAgent.addTransformer(new BendJavassistToMyWillTransformer(Prelude
.or(new Glob("javassist/*")),
JavassistInputStreamInterceptorAdapater.inputStreamAdapterSupplier(JavassistCoverageInterceptor.class)));
}

private static Predicate<String> convertToJVMClassFilter(
final Predicate<String> child) {
return a -> child.test(a.replace("/", "."));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import java.lang.instrument.ClassFileTransformer;

public interface TransformationPlugin extends ClientClasspathPlugin {

ClassFileTransformer makeTransformer();
ClassFileTransformer makeCoverageTransformer();
ClassFileTransformer makeMutationTransformer();

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,17 @@
import org.pitest.classinfo.ClassByteArraySource;
import org.pitest.classinfo.ClassName;
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;
import org.pitest.testapi.Configuration;
import org.pitest.testapi.TestUnit;
import org.pitest.testapi.execute.FindTestUnits;
import org.pitest.util.ExitCode;
import org.pitest.util.Glob;
import org.pitest.util.IsolationUtils;
import org.pitest.util.Log;
import org.pitest.util.SafeDataInputStream;
Expand Down Expand Up @@ -130,10 +125,8 @@ private Configuration createTestPlugin(TestPluginArguments pitConfig) {
public static void main(final String[] args) {
LOG.fine(() -> "minion started");

enablePowerMockSupport();
HotSwapAgent.addTransformer(new CatchNewClassLoadersTransformer());

enableTransformations();
HotSwapAgent.addTransformer(new CatchNewClassLoadersTransformer());

final int port = Integer.parseInt(args[0]);

Expand Down Expand Up @@ -165,21 +158,18 @@ public static void main(final String[] args) {
private static List<TestUnit> findTestsForTestClasses(
final ClassLoader loader, final Collection<ClassName> testClasses,
final Configuration pitConfig) {
final Collection<Class<?>> tcs = testClasses.stream().flatMap(ClassName.nameToClass(loader)).collect(Collectors.toList());

final Collection<Class<?>> tcs = testClasses.stream()
.flatMap(ClassName.nameToClass(loader))
.collect(Collectors.toList());
final FindTestUnits finder = new FindTestUnits(pitConfig);
return finder.findTestUnitsForAllSuppliedClasses(tcs);
}

private static void enablePowerMockSupport() {
// Bwahahahahahahaha
HotSwapAgent.addTransformer(new BendJavassistToMyWillTransformer(Prelude
.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());
HotSwapAgent.addTransformer(each.makeMutationTransformer());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import org.pitest.mutationtest.engine.Mutater;
import org.pitest.mutationtest.engine.MutationDetails;
import org.pitest.mutationtest.engine.MutationIdentifier;
import org.pitest.mutationtest.mocksupport.JavassistInterceptor;
import org.pitest.testapi.Description;
import org.pitest.testapi.TestResult;
import org.pitest.testapi.TestUnit;
Expand Down Expand Up @@ -62,6 +61,7 @@ public class MutationTestWorker {

private final ResetEnvironment reset;


public MutationTestWorker(HotSwap hotswap,
Mutater mutater,
ClassLoader loader,
Expand Down Expand Up @@ -91,17 +91,13 @@ protected void run(final Collection<MutationDetails> range, final Reporter r,

}

private void processMutation(final Reporter r,
final TimeOutDecoratedTestSource testSource,
final MutationDetails mutationDetails) {
private void processMutation(Reporter r,
TimeOutDecoratedTestSource testSource,
MutationDetails mutationDetails) {

final MutationIdentifier mutationId = mutationDetails.getId();
final Mutant mutatedClass = this.mutater.getMutation(mutationId);

// For the benefit of mocking frameworks such as PowerMock
// mess with the internals of Javassist so our mutated class
// bytes are returned
JavassistInterceptor.setMutant(mutatedClass);
reset.resetFor(mutatedClass);

if (DEBUG) {
Expand All @@ -126,8 +122,8 @@ private MutationStatusTestPair handleMutation(
final List<TestUnit> relevantTests) {
final MutationStatusTestPair mutationDetected;
if ((relevantTests == null) || relevantTests.isEmpty()) {
LOG.info(() -> "No test coverage for mutation " + mutationId + " in "
+ mutatedClass.getDetails().getMethod());
LOG.log(Level.WARNING, "No test coverage for mutation " + mutationId + " in " + mutatedClass.getDetails().getMethod()
+ ". This should have been detected in the outer process so treating as an error");
mutationDetected = MutationStatusTestPair.notAnalysed(0, DetectionStatus.RUN_ERROR, Collections.emptyList());
} else {
mutationDetected = handleCoveredMutation(mutationId, mutatedClass,
Expand All @@ -142,7 +138,7 @@ private MutationStatusTestPair handleCoveredMutation(
final List<TestUnit> relevantTests) {
final MutationStatusTestPair mutationDetected;
if (DEBUG) {
LOG.fine("" + relevantTests.size() + " relevant test for "
LOG.fine(relevantTests.size() + " relevant test for "
+ mutatedClass.getDetails().getMethod());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,17 @@
import org.objectweb.asm.Opcodes;
import org.pitest.bytecode.ASMVersion;

public class JavassistInputStreamInterceptorAdapater extends ClassVisitor {
public class JavassistInputStreamInterceptorAdapter extends ClassVisitor {

private final String interceptorClass;

public JavassistInputStreamInterceptorAdapater(final ClassVisitor arg0, Class<?> interceptor) {
public JavassistInputStreamInterceptorAdapter(final ClassVisitor arg0, Class<?> interceptor) {
super(ASMVersion.ASM_VERSION, arg0);
this.interceptorClass = classToName(interceptor);
}

public static Function<ClassWriter, ClassVisitor> inputStreamAdapterSupplier(final Class<?> interceptor) {
return a -> new JavassistInputStreamInterceptorAdapater(a, interceptor);
return a -> new JavassistInputStreamInterceptorAdapter(a, interceptor);
}


Expand All @@ -59,8 +59,8 @@ class JavassistInputStreamInterceptorMethodVisitor extends MethodVisitor {
}

@Override
public void visitMethodInsn(final int opcode, final String owner,
final String name, final String desc, boolean itf) {
public void visitMethodInsn(int opcode, String owner,
String name, String desc, boolean itf) {
if ((opcode == Opcodes.INVOKEINTERFACE)
&& owner.equals("javassist/ClassPath") && name.equals("openClassfile")) {
this.mv.visitMethodInsn(Opcodes.INVOKESTATIC, this.interceptorClass, name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public static InputStream openClassfile(final Object classPath, // NO_UCD
final String name) {

if (isMutatedClass(name)) {
return new ByteArrayInputStream(
return new ByteArrayInputStream(
mutant.getBytes());
} else {
return returnNormalBytes(classPath, name);
Expand All @@ -58,7 +58,7 @@ private static boolean isMutatedClass(final String name) {
.equals(ClassName.fromString(name));
}

public static void setMutant(final Mutant newMutant) {
static void setMutant(final Mutant newMutant) {
mutant = newMutant;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.pitest.mutationtest.mocksupport;

import org.pitest.coverage.execute.JavassistCoverageInterceptor;
import org.pitest.functional.prelude.Prelude;
import org.pitest.mutationtest.environment.TransformationPlugin;
import org.pitest.util.Glob;

import java.lang.instrument.ClassFileTransformer;

public class JavassistTransformation implements TransformationPlugin {

@Override
public ClassFileTransformer makeCoverageTransformer() {
return new BendJavassistToMyWillTransformer(Prelude
.or(new Glob("javassist/*")),
JavassistInputStreamInterceptorAdapter.inputStreamAdapterSupplier(JavassistCoverageInterceptor.class));
}

@Override
public ClassFileTransformer makeMutationTransformer() {
return new BendJavassistToMyWillTransformer(Prelude
.or(new Glob("javassist/*")),
JavassistInputStreamInterceptorAdapter.inputStreamAdapterSupplier(JavassistInterceptor.class));
}

@Override
public String description() {
return "Support for mocking frameworks using javassist";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.pitest.mutationtest.mocksupport;

import org.pitest.mutationtest.environment.EnvironmentResetPlugin;
import org.pitest.mutationtest.environment.ResetEnvironment;

public class ResetJavassistEnvironment implements EnvironmentResetPlugin {
@Override
public ResetEnvironment make() {
return JavassistInterceptor::setMutant;
}

@Override
public String description() {
return "Reset environment for javassist";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
org.pitest.mutationtest.mocksupport.ResetJavassistEnvironment
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
org.pitest.mutationtest.mocksupport.JavassistTransformation
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public class BendJavassistToMyWillTransformerTest {
@Before
public void setUp() {
MockitoAnnotations.openMocks(this);
this.testee = new BendJavassistToMyWillTransformer(this.filter, JavassistInputStreamInterceptorAdapater.inputStreamAdapterSupplier(JavassistInterceptor.class));
this.testee = new BendJavassistToMyWillTransformer(this.filter, JavassistInputStreamInterceptorAdapter.inputStreamAdapterSupplier(JavassistInterceptor.class));
final ClassloaderByteArraySource source = new ClassloaderByteArraySource(
IsolationUtils.getContextClassLoader());
this.bytes = source.getBytes("java.lang.String").get();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

public class JavassistInputStreamInterceptorAdapaterTest {
public class JavassistInputStreamInterceptorAdapterTest {

private JavassistInputStreamInterceptorMethodVisitor testee;

Expand Down
Loading