pitest / pitclipse

Mutation testing for Java in Eclipse IDE. Based on PIT (Pitest).
https://pitest.org
Apache License 2.0
59 stars 17 forks source link

Consume PIT Maven artifacts through TP #195

Open LorenzoBettini opened 2 years ago

LorenzoBettini commented 2 years ago

Now that PDE (and Tycho) support specifying Maven artifacts directly in the .target file

LorenzoBettini commented 2 years ago

I'm experiencing class loading problems in tests, e.g.,

java.lang.NoClassDefFoundError: org/pitest/mutationtest/config/PluginServices
    at org.pitest.mutationtest.commandline.MutationCoverageReport.main(MutationCoverageReport.java:35)
    at org.pitest.pitclipse.runner.PitRunner.apply(PitRunner.java:36)
    at org.pitest.pitclipse.runner.PitRunnerTest.shouldRunPitest(PitRunnerTest.java:84)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
    at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
    at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
    at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
    at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:93)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:40)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:529)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:756)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:452)
    at org.eclipse.pde.internal.junit.runtime.RemotePluginTestRunner.main(RemotePluginTestRunner.java:74)
    at org.eclipse.pde.internal.junit.runtime.CoreTestApplication.start(CoreTestApplication.java:28)
    at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:203)
    at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:136)
    at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:104)
    at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:402)
    at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:255)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:659)
    at org.eclipse.equinox.launcher.Main.basicRun(Main.java:596)
    at org.eclipse.equinox.launcher.Main.run(Main.java:1467)
    at org.eclipse.equinox.launcher.Main.main(Main.java:1440)
Caused by: java.lang.ClassNotFoundException: org.pitest.mutationtest.config.PluginServices cannot be found by wrapped.org.pitest.pitest-command-line_1.6.8
    at org.eclipse.osgi.internal.loader.BundleLoader.generateException(BundleLoader.java:541)
    at org.eclipse.osgi.internal.loader.BundleLoader.findClass0(BundleLoader.java:487)
    at org.eclipse.osgi.internal.loader.BundleLoader.findClass(BundleLoader.java:416)
    at org.eclipse.osgi.internal.loader.ModuleClassLoader.loadClass(ModuleClassLoader.java:168)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
    ... 44 more

Maybe due to

public class MutationCoverageReport {

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

    final PluginServices plugins = PluginServices.makeForContextLoader();

and

  public static PluginServices makeForContextLoader() {
    return new PluginServices(IsolationUtils.getContextClassLoader());
  }
LorenzoBettini commented 2 years ago

In PitRunnerTests I changed the way we load jars

    private static List<String> classPathWithPitestAndJUnit() throws IOException {
        final String jarDir = "lib";
        EquinoxBundle pitestBundle = (EquinoxBundle) Platform.getBundle("org.pitest.bundles");
        Bundle[] bundles = Platform.getBundle("org.eclipse.core.runtime").getBundleContext().getBundles();
        System.out.println("symbolic name: " + pitestBundle.getSymbolicName());
        List<EquinoxBundle> pitestWrappedBundles = Stream.of(bundles)
            .filter(b -> b instanceof EquinoxBundle)
            .map(b -> (EquinoxBundle) b)
            .filter(b -> b.getSymbolicName().startsWith("wrapped.org.pitest"))
            .collect(Collectors.toList());
        List<String> locations = pitestWrappedBundles.stream()
            .map(b -> b.getLocation())
            .collect(Collectors.toList());
        // hack, exclude JUnit 5?
        locations.remove(locations.size() - 1);

        List<String> classPath = new ArrayList<>();

        classPath.add(getBundleFile(pitestBundle).getCanonicalPath());

        classPath.add(getBundleFile(Platform.getBundle("org.pitest.pitclipse.runner")).getCanonicalPath());
        classPath.add(getBundleFile(Platform.getBundle("org.pitest.pitclipse.runner")).getCanonicalPath() + File.separator + BUILD_OUTPUT_DIR);

        for (Bundle bundle : pitestWrappedBundles) {
            classPath.add(getBundleFile(bundle).getCanonicalPath());
        }

        // Guava is needed
        classPath.add(getBundleFile(Platform.getBundle("com.google.guava")).getCanonicalPath());

        // Add .class files to mutate
        classPath.add(new File(BUILD_OUTPUT_DIR).getAbsolutePath());

        // Add JUnit dependency
        classPath.add(new File("lib/junit.jar").getAbsolutePath());

        return classPath;
    }

but again that does not work

LorenzoBettini commented 2 years ago

Another symptom that something is wrong with classloading is this test

    @Test 
    public void shouldFindAllAvailableMutationResultListeners() {
        ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
        Collection<MutationResultListenerFactory> factories = ServiceLoader.load(MutationResultListenerFactory.class, contextClassLoader);
        Set<String> factoriesName = factories.stream().map(f -> f.name()).collect(toSet());

        String[] expectedFactoriesName = new String[] {"HTML", "CSV", "XML", "PITCLIPSE_MUTATIONS", "PITCLIPSE_SUMMARY"};
        assertThat(factoriesName, hasItems(expectedFactoriesName));
    }

which retrieves an empty set...

LorenzoBettini commented 2 years ago

For the moment, I'm stopping working on that; maybe in the future, I'll get back to that.