]> source.dussan.org Git - pf4j.git/commitdiff
Improve class generation for testing (#515)
authorDecebal Suiu <decebal.suiu@gmail.com>
Thu, 2 Feb 2023 18:05:51 +0000 (20:05 +0200)
committerGitHub <noreply@github.com>
Thu, 2 Feb 2023 18:05:51 +0000 (20:05 +0200)
15 files changed:
pf4j/src/test/java/org/pf4j/AbstractExtensionFinderTest.java
pf4j/src/test/java/org/pf4j/DefaultExtensionFactoryTest.java
pf4j/src/test/java/org/pf4j/DefaultPluginFactoryTest.java
pf4j/src/test/java/org/pf4j/ExtensionAnnotationProcessorTest.java
pf4j/src/test/java/org/pf4j/SingletonExtensionFactoryTest.java
pf4j/src/test/java/org/pf4j/test/AnotherFailTestPlugin.java [deleted file]
pf4j/src/test/java/org/pf4j/test/AnotherTestPlugin.java [deleted file]
pf4j/src/test/java/org/pf4j/test/DefaultClassDataProvider.java
pf4j/src/test/java/org/pf4j/test/FailTestExtension.java [deleted file]
pf4j/src/test/java/org/pf4j/test/FailTestPlugin.java [deleted file]
pf4j/src/test/java/org/pf4j/test/JavaFileObjectClassLoader.java [new file with mode: 0644]
pf4j/src/test/java/org/pf4j/test/JavaFileObjectDataProvider.java [new file with mode: 0644]
pf4j/src/test/java/org/pf4j/test/JavaFileObjectUtils.java [new file with mode: 0644]
pf4j/src/test/java/org/pf4j/test/JavaSources.java [new file with mode: 0644]
pf4j/src/test/java/org/pf4j/test/TestPlugin.java

index eff6ebef2ca7f3492ea3912b84d628af6bcb8891..1e4b5ebb0e1927a0b45a590884c4e51cef4cffd8 100644 (file)
  */
 package org.pf4j;
 
-import com.google.common.collect.ImmutableList;
-import com.google.common.io.ByteStreams;
-import com.google.testing.compile.Compilation;
-import java.util.Comparator;
-import java.util.UUID;
 import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
-import org.pf4j.test.FailTestPlugin;
+import org.pf4j.test.JavaFileObjectClassLoader;
+import org.pf4j.test.JavaFileObjectUtils;
+import org.pf4j.test.JavaSources;
+import org.pf4j.test.TestExtension;
 import org.pf4j.test.TestExtensionPoint;
 
 import javax.tools.JavaFileObject;
-import java.io.IOException;
-import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.UUID;
 
-import static com.google.testing.compile.CompilationSubject.assertThat;
-import static com.google.testing.compile.Compiler.javac;
-import static org.junit.Assert.assertNull;
 import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
@@ -64,9 +56,9 @@ public class AbstractExtensionFinderTest {
         when(pluginStopped.getPluginState()).thenReturn(PluginState.STOPPED);
 
         pluginManager = mock(PluginManager.class);
-        when(pluginManager.getPlugin(eq("plugin1"))).thenReturn(pluginStarted);
-        when(pluginManager.getPlugin(eq("plugin2"))).thenReturn(pluginStopped);
-        when(pluginManager.getPluginClassLoader(eq("plugin1"))).thenReturn(getClass().getClassLoader());
+        when(pluginManager.getPlugin("plugin1")).thenReturn(pluginStarted);
+        when(pluginManager.getPlugin("plugin2")).thenReturn(pluginStopped);
+        when(pluginManager.getPluginClassLoader("plugin1")).thenReturn(getClass().getClassLoader());
         when(pluginManager.getExtensionFactory()).thenReturn(new DefaultExtensionFactory());
     }
 
@@ -93,7 +85,7 @@ public class AbstractExtensionFinderTest {
             }
 
         };
-        List<ExtensionWrapper<FailTestPlugin>> list = instance.find(FailTestPlugin.class);
+        List<ExtensionWrapper<TestExtension>> list = instance.find(TestExtension.class);
         assertEquals(0, list.size());
     }
 
@@ -115,7 +107,6 @@ public class AbstractExtensionFinderTest {
 
                 Set<String> bucket = new HashSet<>();
                 bucket.add("org.pf4j.test.TestExtension");
-                bucket.add("org.pf4j.test.FailTestExtension");
                 entries.put(null, bucket);
 
                 return entries;
@@ -124,7 +115,7 @@ public class AbstractExtensionFinderTest {
         };
 
         List<ExtensionWrapper<TestExtensionPoint>> list = instance.find(TestExtensionPoint.class);
-        assertEquals(2, list.size());
+        assertEquals(1, list.size());
     }
 
     /**
@@ -140,7 +131,6 @@ public class AbstractExtensionFinderTest {
 
                 Set<String> bucket = new HashSet<>();
                 bucket.add("org.pf4j.test.TestExtension");
-                bucket.add("org.pf4j.test.FailTestExtension");
                 entries.put("plugin1", bucket);
                 bucket = new HashSet<>();
                 bucket.add("org.pf4j.test.TestExtension");
@@ -157,12 +147,13 @@ public class AbstractExtensionFinderTest {
         };
 
         List<ExtensionWrapper<TestExtensionPoint>> list = instance.find(TestExtensionPoint.class);
-        assertEquals(2, list.size());
+        assertEquals(1, list.size());
 
         list = instance.find(TestExtensionPoint.class, "plugin1");
-        assertEquals(2, list.size());
+        assertEquals(1, list.size());
 
         list = instance.find(TestExtensionPoint.class, "plugin2");
+        // "0" because the status of "plugin2" is STOPPED => no extensions
         assertEquals(0, list.size());
     }
 
@@ -210,6 +201,16 @@ public class AbstractExtensionFinderTest {
      */
     @Test
     public void testFindExtensionWrappersFromPluginId() {
+        // complicate the test to show hot to deal with dynamic Java classes (generated at runtime from sources)
+        PluginWrapper plugin3 = mock(PluginWrapper.class);
+        JavaFileObject object = JavaSources.compile(DefaultExtensionFactoryTest.FailTestExtension);
+        JavaFileObjectClassLoader classLoader = new JavaFileObjectClassLoader();
+        classLoader.load(object);
+        when(plugin3.getPluginClassLoader()).thenReturn(classLoader);
+        when(plugin3.getPluginState()).thenReturn(PluginState.STARTED);
+        when(pluginManager.getPluginClassLoader("plugin3")).thenReturn(classLoader);
+        when(pluginManager.getPlugin("plugin3")).thenReturn(plugin3);
+
         ExtensionFinder instance = new AbstractExtensionFinder(pluginManager) {
 
             @Override
@@ -218,11 +219,13 @@ public class AbstractExtensionFinderTest {
 
                 Set<String> bucket = new HashSet<>();
                 bucket.add("org.pf4j.test.TestExtension");
-                bucket.add("org.pf4j.test.FailTestExtension");
                 entries.put("plugin1", bucket);
                 bucket = new HashSet<>();
                 bucket.add("org.pf4j.test.TestExtension");
                 entries.put("plugin2", bucket);
+                bucket = new HashSet<>();
+                bucket.add(JavaFileObjectUtils.getClassName(object));
+                entries.put("plugin3", bucket);
 
                 return entries;
             }
@@ -235,73 +238,40 @@ public class AbstractExtensionFinderTest {
         };
 
         List<ExtensionWrapper> plugin1Result = instance.find("plugin1");
-        assertEquals(2, plugin1Result.size());
+        assertEquals(1, plugin1Result.size());
 
         List<ExtensionWrapper> plugin2Result = instance.find("plugin2");
         assertEquals(0, plugin2Result.size());
 
-        List<ExtensionWrapper> plugin3Result = instance.find(UUID.randomUUID().toString());
-        assertEquals(0, plugin3Result.size());
+        List<ExtensionWrapper> plugin3Result = instance.find("plugin3");
+        assertEquals(1, plugin3Result.size());
+
+        List<ExtensionWrapper> plugin4Result = instance.find(UUID.randomUUID().toString());
+        assertEquals(0, plugin4Result.size());
     }
 
     @Test
-    public void findExtensionAnnotation() throws Exception {
-        Compilation compilation = javac().compile(ExtensionAnnotationProcessorTest.Greeting,
-            ExtensionAnnotationProcessorTest.WhazzupGreeting);
-        assertThat(compilation).succeededWithoutWarnings();
-        ImmutableList<JavaFileObject> generatedFiles = compilation.generatedFiles();
+    public void findExtensionAnnotation() {
+        List<JavaFileObject> generatedFiles = JavaSources.compileAll(JavaSources.Greeting, JavaSources.WhazzupGreeting);
         assertEquals(2, generatedFiles.size());
 
-        JavaFileObjectClassLoader classLoader = new JavaFileObjectClassLoader();
-        Map<String, Class<?>> loadedClasses = classLoader.loadClasses(new ArrayList<>(generatedFiles));
+        Map<String, Class<?>> loadedClasses = new JavaFileObjectClassLoader().load(generatedFiles);
         Class<?> clazz = loadedClasses.get("test.WhazzupGreeting");
         Extension extension = AbstractExtensionFinder.findExtensionAnnotation(clazz);
-        assertNotNull(extension);
+        Assertions.assertNotNull(extension);
     }
 
     @Test
-    public void findExtensionAnnotationThatMissing() throws Exception {
-        Compilation compilation = javac().compile(ExtensionAnnotationProcessorTest.Greeting,
+    public void findExtensionAnnotationThatMissing() {
+        List<JavaFileObject> generatedFiles = JavaSources.compileAll(JavaSources.Greeting,
             ExtensionAnnotationProcessorTest.SpinnakerExtension_NoExtension,
             ExtensionAnnotationProcessorTest.WhazzupGreeting_SpinnakerExtension);
-        assertThat(compilation).succeededWithoutWarnings();
-        ImmutableList<JavaFileObject> generatedFiles = compilation.generatedFiles();
         assertEquals(3, generatedFiles.size());
 
-        JavaFileObjectClassLoader classLoader = new JavaFileObjectClassLoader();
-        Map<String, Class<?>> loadedClasses = classLoader.loadClasses(new ArrayList<>(generatedFiles));
+        Map<String, Class<?>> loadedClasses = new JavaFileObjectClassLoader().load(generatedFiles);
         Class<?> clazz = loadedClasses.get("test.WhazzupGreeting");
         Extension extension = AbstractExtensionFinder.findExtensionAnnotation(clazz);
-        assertNull(extension);
-    }
-
-   static class JavaFileObjectClassLoader extends ClassLoader {
-
-        public Map<String, Class<?>> loadClasses(List<JavaFileObject> classes) throws IOException {
-            // Sort generated ".class" by lastModified field
-            classes.sort(Comparator.comparingLong(JavaFileObject::getLastModified));
-
-            // Load classes
-            Map<String, Class<?>> loadedClasses = new HashMap<>(classes.size());
-            for (JavaFileObject clazz : classes) {
-                String className = getClassName(clazz);
-                byte[] data = ByteStreams.toByteArray(clazz.openInputStream());
-                Class<?> loadedClass = defineClass(className, data,0, data.length);
-                loadedClasses.put(className, loadedClass);
-            }
-
-            return loadedClasses;
-        }
-
-        private static String getClassName(JavaFileObject object) {
-            String name = object.getName();
-            // Remove "/CLASS_OUT/" from head and ".class" from tail
-            name = name.substring(14, name.length() - 6);
-            name = name.replace('/', '.');
-
-            return name;
-        }
-
+        Assertions.assertNull(extension);
     }
 
 }
index 9d73b5e42ce1bc71ea9ab1bf728d7791d4a9fb77..47eb2d302fb1d7cd68e1c618459a30f6c861ba54 100644 (file)
  */
 package org.pf4j;
 
+import com.google.testing.compile.JavaFileObjects;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
-import org.pf4j.test.FailTestExtension;
+import org.pf4j.test.JavaFileObjectClassLoader;
+import org.pf4j.test.JavaSources;
 import org.pf4j.test.TestExtension;
 
+import javax.tools.JavaFileObject;
+
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 
@@ -29,6 +33,19 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
  */
 public class DefaultExtensionFactoryTest {
 
+    public static final JavaFileObject FailTestExtension = JavaFileObjects.forSourceLines("FailTestExtension",
+        "package test;",
+        "import org.pf4j.test.TestExtensionPoint;",
+        "import org.pf4j.Extension;",
+        "",
+        "@Extension",
+        "public class FailTestExtension implements TestExtensionPoint {",
+        "    public FailTestExtension(String name) {}",
+        "",
+        "    @Override",
+        "    public String saySomething() { return \"I am a fail test extension\";}",
+        "}");
+
     private ExtensionFactory extensionFactory;
 
     @BeforeEach
@@ -54,7 +71,10 @@ public class DefaultExtensionFactoryTest {
      */
     @Test
     public void testCreateFailConstructor() {
-        assertThrows(PluginRuntimeException.class, () -> extensionFactory.create(FailTestExtension.class));
+        JavaFileObject object = JavaSources.compile(FailTestExtension);
+        JavaFileObjectClassLoader classLoader = new JavaFileObjectClassLoader();
+        Class<?> extensionClass = (Class<?>) classLoader.load(object).values().toArray()[0];
+        assertThrows(PluginRuntimeException.class, () -> extensionFactory.create(extensionClass));
     }
 
 }
index c453e38e841dfe17f248a5df3ac75fb942cc81a6..24ed40c5047adba590132d73873764557bd568bd 100644 (file)
  */
 package org.pf4j;
 
+import com.google.testing.compile.JavaFileObjects;
 import org.junit.jupiter.api.Test;
-import org.pf4j.test.AnotherFailTestPlugin;
-import org.pf4j.test.AnotherTestPlugin;
-import org.pf4j.test.FailTestPlugin;
+import org.pf4j.test.JavaFileObjectClassLoader;
+import org.pf4j.test.JavaFileObjectUtils;
+import org.pf4j.test.JavaSources;
 import org.pf4j.test.TestPlugin;
 
+import javax.tools.JavaFileObject;
+
 import static org.hamcrest.CoreMatchers.instanceOf;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.mockito.Mockito.mock;
@@ -33,6 +37,29 @@ import static org.mockito.Mockito.when;
  */
 public class DefaultPluginFactoryTest {
 
+    public static final JavaFileObject FailTestPlugin = JavaFileObjects.forSourceLines("FailTestPlugin",
+        "package test;",
+        "import org.pf4j.Plugin;",
+        "",
+        "public class FailTestPlugin {",
+        "}");
+
+    public static final JavaFileObject AnotherFailTestPlugin = JavaFileObjects.forSourceLines("AnotherFailTestPlugin",
+        "package test;",
+        "import org.pf4j.Plugin;",
+        "",
+        "public class AnotherFailTestPlugin extends Plugin {",
+        "     public AnotherFailTestPlugin() { super(null); }",
+        "}");
+
+    public static final JavaFileObject AnotherTestPlugin = JavaFileObjects.forSourceLines("AnotherTestPlugin",
+        "package test;",
+        "import org.pf4j.Plugin;",
+        "",
+        "public class AnotherTestPlugin extends Plugin {",
+        "     public AnotherTestPlugin() { super(); }",
+        "}");
+
     @Test
     public void testCreate() {
         PluginDescriptor pluginDescriptor = mock(PluginDescriptor.class);
@@ -52,27 +79,35 @@ public class DefaultPluginFactoryTest {
     @Test
     public void pluginConstructorNoParameters() {
         PluginDescriptor pluginDescriptor = mock(PluginDescriptor.class);
-        when(pluginDescriptor.getPluginClass()).thenReturn(AnotherTestPlugin.class.getName());
+        JavaFileObject object = JavaSources.compile(AnotherTestPlugin);
+        String pluginClassName = JavaFileObjectUtils.getClassName(object);
+        when(pluginDescriptor.getPluginClass()).thenReturn(pluginClassName);
 
         PluginWrapper pluginWrapper = mock(PluginWrapper.class);
         when(pluginWrapper.getDescriptor()).thenReturn(pluginDescriptor);
-        when(pluginWrapper.getPluginClassLoader()).thenReturn(getClass().getClassLoader());
+        JavaFileObjectClassLoader classLoader = new JavaFileObjectClassLoader();
+        classLoader.load(AnotherTestPlugin);
+        when(pluginWrapper.getPluginClassLoader()).thenReturn(classLoader);
 
         PluginFactory pluginFactory = new DefaultPluginFactory();
 
         Plugin result = pluginFactory.create(pluginWrapper);
         assertNotNull(result);
-        assertThat(result, instanceOf(AnotherTestPlugin.class));
+        assertEquals(pluginClassName, result.getClass().getName());
     }
 
     @Test
     public void testCreateFail() {
         PluginDescriptor pluginDescriptor = mock(PluginDescriptor.class);
-        when(pluginDescriptor.getPluginClass()).thenReturn(FailTestPlugin.class.getName());
+        JavaFileObject object = JavaSources.compile(FailTestPlugin);
+        String pluginClassName = JavaFileObjectUtils.getClassName(object);
+        when(pluginDescriptor.getPluginClass()).thenReturn(pluginClassName);
 
         PluginWrapper pluginWrapper = mock(PluginWrapper.class);
         when(pluginWrapper.getDescriptor()).thenReturn(pluginDescriptor);
-        when(pluginWrapper.getPluginClassLoader()).thenReturn(getClass().getClassLoader());
+        JavaFileObjectClassLoader classLoader = new JavaFileObjectClassLoader();
+        classLoader.load(FailTestPlugin);
+        when(pluginWrapper.getPluginClassLoader()).thenReturn(classLoader);
 
         PluginFactory pluginFactory = new DefaultPluginFactory();
 
@@ -98,11 +133,15 @@ public class DefaultPluginFactoryTest {
     @Test
     public void testCreateFailConstructor() {
         PluginDescriptor pluginDescriptor = mock(PluginDescriptor.class);
-        when(pluginDescriptor.getPluginClass()).thenReturn(AnotherFailTestPlugin.class.getName());
+        JavaFileObject object = JavaSources.compile(AnotherFailTestPlugin);
+        String pluginClassName = JavaFileObjectUtils.getClassName(object);
+        when(pluginDescriptor.getPluginClass()).thenReturn(pluginClassName);
 
         PluginWrapper pluginWrapper = mock(PluginWrapper.class);
         when(pluginWrapper.getDescriptor()).thenReturn(pluginDescriptor);
-        when(pluginWrapper.getPluginClassLoader()).thenReturn(getClass().getClassLoader());
+        JavaFileObjectClassLoader classLoader = new JavaFileObjectClassLoader();
+        classLoader.load(AnotherFailTestPlugin);
+        when(pluginWrapper.getPluginClassLoader()).thenReturn(classLoader);
 
         PluginFactory pluginFactory = new DefaultPluginFactory();
 
index f966523fa4f782137bdd213759c2c2f09c07f9af..2b3241d361cdcef41e6366cfb7f21e0e22cd3053 100644 (file)
 package org.pf4j;
 
 import com.google.testing.compile.Compilation;
+import com.google.testing.compile.Compiler;
 import com.google.testing.compile.JavaFileObjects;
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.pf4j.processor.ExtensionAnnotationProcessor;
 import org.pf4j.processor.LegacyExtensionStorage;
+import org.pf4j.test.JavaSources;
 
 import javax.tools.JavaFileObject;
+import java.io.IOException;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -38,30 +42,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
  */
 public class ExtensionAnnotationProcessorTest {
 
-    public static final JavaFileObject Greeting = JavaFileObjects.forSourceLines(
-        "Greeting",
-        "package test;",
-        "import org.pf4j.ExtensionPoint;",
-        "",
-        "public interface Greeting extends ExtensionPoint {",
-        "   String getGreeting();",
-        "}");
-
-    public static final JavaFileObject WhazzupGreeting = JavaFileObjects.forSourceLines(
-        "WhazzupGreeting",
-        "package test;",
-        "import org.pf4j.Extension;",
-        "",
-        "@Extension",
-        "public class WhazzupGreeting implements Greeting {",
-        "   @Override",
-        "    public String getGreeting() {",
-        "       return \"Whazzup\";",
-        "    }",
-        "}");
-
-    public static final JavaFileObject WhazzupGreeting_NoExtensionPoint = JavaFileObjects.forSourceLines(
-        "WhazzupGreeting",
+    public static final JavaFileObject WhazzupGreeting_NoExtensionPoint = JavaFileObjects.forSourceLines("WhazzupGreeting",
         "package test;",
         "import org.pf4j.Extension;",
         "",
@@ -73,8 +54,7 @@ public class ExtensionAnnotationProcessorTest {
         "    }",
         "}");
 
-    public static final JavaFileObject SpinnakerExtension = JavaFileObjects.forSourceLines(
-        "SpinnakerExtension",
+    public static final JavaFileObject SpinnakerExtension = JavaFileObjects.forSourceLines("SpinnakerExtension",
         "package test;",
         "",
         "import org.pf4j.Extension;",
@@ -91,8 +71,7 @@ public class ExtensionAnnotationProcessorTest {
         "public @interface SpinnakerExtension {",
         "}");
 
-    public static final JavaFileObject WhazzupGreeting_SpinnakerExtension = JavaFileObjects.forSourceLines(
-        "WhazzupGreeting",
+    public static final JavaFileObject WhazzupGreeting_SpinnakerExtension = JavaFileObjects.forSourceLines("WhazzupGreeting",
         "package test;",
         "",
         "@SpinnakerExtension",
@@ -104,10 +83,9 @@ public class ExtensionAnnotationProcessorTest {
         "}");
 
     /**
-     * The same like {@link #SpinnakerExtension} but without {@code Extension} annotation.
+     * The same as {@link #SpinnakerExtension} but without {@code Extension} annotation.
      */
-    public static final JavaFileObject SpinnakerExtension_NoExtension = JavaFileObjects.forSourceLines(
-        "SpinnakerExtension",
+    public static final JavaFileObject SpinnakerExtension_NoExtension = JavaFileObjects.forSourceLines("SpinnakerExtension",
         "package test;",
         "",
         "import org.pf4j.Extension;",
@@ -124,52 +102,53 @@ public class ExtensionAnnotationProcessorTest {
         "public @interface SpinnakerExtension {",
         "}");
 
+    private ExtensionAnnotationProcessor annotationProcessor;
+
+    @BeforeEach
+    public void setUp() throws IOException {
+        annotationProcessor = new ExtensionAnnotationProcessor();
+    }
+
     @Test
     public void getSupportedAnnotationTypes() {
-        ExtensionAnnotationProcessor instance = new ExtensionAnnotationProcessor();
-        Set<String> result = instance.getSupportedAnnotationTypes();
+        Set<String> result = annotationProcessor.getSupportedAnnotationTypes();
         assertEquals(1, result.size());
         assertEquals("*", result.iterator().next());
     }
 
     @Test
     public void getSupportedOptions() {
-        ExtensionAnnotationProcessor instance = new ExtensionAnnotationProcessor();
-        Set<String> result = instance.getSupportedOptions();
+        Set<String> result = annotationProcessor.getSupportedOptions();
         assertEquals(2, result.size());
     }
 
     @Test
     public void options() {
-        ExtensionAnnotationProcessor processor = new ExtensionAnnotationProcessor();
-        Compilation compilation = javac().withProcessors(processor).withOptions("-Ab=2", "-Ac=3")
-            .compile(Greeting, WhazzupGreeting);
-        assertEquals(compilation.status(), Compilation.Status.SUCCESS);
+        Compilation compilation = compiler().withOptions("-Ab=2", "-Ac=3")
+            .compile(JavaSources.Greeting, JavaSources.WhazzupGreeting);
+        assertEquals(Compilation.Status.SUCCESS, compilation.status());
         Map<String, String> options = new HashMap<>();
         options.put("b", "2");
         options.put("c", "3");
-        assertEquals(options, processor.getProcessingEnvironment().getOptions());
+        assertEquals(options, annotationProcessor.getProcessingEnvironment().getOptions());
     }
 
     @Test
     public void storage() {
-        ExtensionAnnotationProcessor processor = new ExtensionAnnotationProcessor();
-        Compilation compilation = javac().withProcessors(processor).compile(Greeting, WhazzupGreeting);
-        assertEquals(compilation.status(), Compilation.Status.SUCCESS);
-        assertEquals(processor.getStorage().getClass(), LegacyExtensionStorage.class);
+        Compilation compilation = compile(JavaSources.Greeting, JavaSources.WhazzupGreeting);
+        assertEquals(Compilation.Status.SUCCESS, compilation.status());
+        assertEquals(annotationProcessor.getStorage().getClass(), LegacyExtensionStorage.class);
     }
 
     @Test
     public void compileWithoutError() {
-        ExtensionAnnotationProcessor processor = new ExtensionAnnotationProcessor();
-         Compilation compilation = javac().withProcessors(processor).compile(Greeting, WhazzupGreeting);
+         Compilation compilation = compile(JavaSources.Greeting, JavaSources.WhazzupGreeting);
          assertThat(compilation).succeededWithoutWarnings();
     }
 
     @Test
     public void compileWithError() {
-        ExtensionAnnotationProcessor processor = new ExtensionAnnotationProcessor();
-        Compilation compilation = javac().withProcessors(processor).compile(Greeting, WhazzupGreeting_NoExtensionPoint);
+        Compilation compilation = compile(JavaSources.Greeting, WhazzupGreeting_NoExtensionPoint);
         assertThat(compilation).failed();
         assertThat(compilation).hadErrorContaining("it doesn't implement ExtensionPoint")
             .inFile(WhazzupGreeting_NoExtensionPoint)
@@ -179,22 +158,28 @@ public class ExtensionAnnotationProcessorTest {
 
     @Test
     public void getExtensions() {
-        ExtensionAnnotationProcessor processor = new ExtensionAnnotationProcessor();
-        Compilation compilation = javac().withProcessors(processor).compile(Greeting, WhazzupGreeting);
+        Compilation compilation = compile(JavaSources.Greeting, JavaSources.WhazzupGreeting);
         assertThat(compilation).succeededWithoutWarnings();
         Map<String, Set<String>> extensions = new HashMap<>();
         extensions.put("test.Greeting", new HashSet<>(Collections.singletonList("test.WhazzupGreeting")));
-        assertEquals(extensions, processor.getExtensions());
+        assertEquals(extensions, annotationProcessor.getExtensions());
     }
 
     @Test
     public void compileNestedExtensionAnnotation() {
-        ExtensionAnnotationProcessor processor = new ExtensionAnnotationProcessor();
-        Compilation compilation = javac().withProcessors(processor).compile(Greeting, SpinnakerExtension, WhazzupGreeting_SpinnakerExtension);
+        Compilation compilation = compile(JavaSources.Greeting, SpinnakerExtension, WhazzupGreeting_SpinnakerExtension);
         assertThat(compilation).succeededWithoutWarnings();
         Map<String, Set<String>> extensions = new HashMap<>();
         extensions.put("test.Greeting", new HashSet<>(Collections.singletonList("test.WhazzupGreeting")));
-        assertEquals(extensions, processor.getExtensions());
+        assertEquals(extensions, annotationProcessor.getExtensions());
+    }
+
+    private Compiler compiler() {
+        return javac().withProcessors(annotationProcessor);
+    }
+
+    private Compilation compile(JavaFileObject... sources) {
+        return compiler().compile(sources);
     }
 
 }
index ddfd2a48a200d5f9ae7031b8a6bd6694710dac66..ff3d65a49ba8c8df5cd8c6c3b2b3758faa12bace 100644 (file)
@@ -18,7 +18,6 @@ package org.pf4j;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
-import org.pf4j.test.FailTestExtension;
 import org.pf4j.test.TestExtension;
 
 import java.io.File;
@@ -57,7 +56,7 @@ public class SingletonExtensionFactoryTest {
 
     @Test
     public void createNewEachTime() {
-        ExtensionFactory extensionFactory = new SingletonExtensionFactory(pluginManager, FailTestExtension.class.getName());
+        ExtensionFactory extensionFactory = new SingletonExtensionFactory(pluginManager, "FailTestExtension.class");
         Object extensionOne = extensionFactory.create(TestExtension.class);
         Object extensionTwo = extensionFactory.create(TestExtension.class);
         assertNotSame(extensionOne, extensionTwo);
diff --git a/pf4j/src/test/java/org/pf4j/test/AnotherFailTestPlugin.java b/pf4j/src/test/java/org/pf4j/test/AnotherFailTestPlugin.java
deleted file mode 100644 (file)
index 79aa41b..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2012-present the original author or authors.
- *
- * 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.pf4j.test;
-
-import org.pf4j.Plugin;
-
-/**
- * A wrong {@link org.pf4j.Plugin}.
- * It's wrong because it calls super constructor with {@code null} for ({@link org.pf4j.PluginWrapper} parameter).
- *
- * @author Mario Franco
- */
-public class AnotherFailTestPlugin extends Plugin {
-
-    public AnotherFailTestPlugin() {
-        super(null);
-    }
-
-}
diff --git a/pf4j/src/test/java/org/pf4j/test/AnotherTestPlugin.java b/pf4j/src/test/java/org/pf4j/test/AnotherTestPlugin.java
deleted file mode 100644 (file)
index f2e10c1..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2012-present the original author or authors.
- *
- * 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.pf4j.test;
-
-import org.pf4j.Plugin;
-
-/**
- * A simple {@link Plugin}.
- *
- * In real applications you don't need to create a plugin like this if you are not interested in lifecycle events.
- * {@code PF4J} will automatically create a plugin similar to this (empty / dummy) if no class plugin is specified.
- *
- * @author Decebal Suiu
- */
-public class AnotherTestPlugin extends Plugin {
-
-    public AnotherTestPlugin() {
-        super();
-    }
-
-}
index 6a203aa0ce883d0b2118ec92138661c8649570c2..473f948b77b0d088f1fc3376f9cc667444c3f4ac 100644 (file)
  */
 package org.pf4j.test;
 
-import java.io.ByteArrayOutputStream;
+import com.google.common.io.ByteStreams;
+
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.OutputStream;
 
 /**
  * Get class data from the class path.
@@ -35,20 +35,10 @@ public class DefaultClassDataProvider implements ClassDataProvider {
             throw new RuntimeException("Cannot find class data");
         }
 
-        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
-            copyStream(classDataStream, outputStream);
-            return outputStream.toByteArray();
+        try {
+            return ByteStreams.toByteArray(classDataStream);
         } catch (IOException e) {
-            throw new RuntimeException(e.getMessage(), e);
-        }
-    }
-
-    private void copyStream(InputStream in, OutputStream out) throws IOException {
-        byte[] buffer = new byte[1024];
-
-        int bytesRead;
-        while ((bytesRead = in.read(buffer)) != -1) {
-            out.write(buffer, 0, bytesRead);
+            throw new IllegalStateException(e);
         }
     }
 
diff --git a/pf4j/src/test/java/org/pf4j/test/FailTestExtension.java b/pf4j/src/test/java/org/pf4j/test/FailTestExtension.java
deleted file mode 100644 (file)
index 1ce2aa8..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2012-present the original author or authors.
- *
- * 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.pf4j.test;
-
-import org.pf4j.Extension;
-
-/**
- * A wrong {@link org.pf4j.Extension}.
- * It's wrong because it doesn't contain a constructor with empty parameters (or only the default constructor).
- *
- * @author Mario Franco
- */
-@Extension
-public class FailTestExtension implements TestExtensionPoint {
-
-    public FailTestExtension(String name) {
-    }
-
-    @Override
-    public String saySomething() {
-        return "I am a fail test extension";
-    }
-
-}
diff --git a/pf4j/src/test/java/org/pf4j/test/FailTestPlugin.java b/pf4j/src/test/java/org/pf4j/test/FailTestPlugin.java
deleted file mode 100644 (file)
index 3a1824f..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2012-present the original author or authors.
- *
- * 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.pf4j.test;
-
-/**
- * A wrong {@link org.pf4j.Plugin}.
- * It's wrong because it doesn't extends {@link org.pf4j.Plugin}.
- *
- * @author Mario Franco
- */
-public class FailTestPlugin {
-
-}
diff --git a/pf4j/src/test/java/org/pf4j/test/JavaFileObjectClassLoader.java b/pf4j/src/test/java/org/pf4j/test/JavaFileObjectClassLoader.java
new file mode 100644 (file)
index 0000000..2afe0d2
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2012-present the original author or authors.
+ *
+ * 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.pf4j.test;
+
+import javax.tools.JavaFileObject;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * {@link ClassLoader} that loads {@link JavaFileObject.Kind#CLASS}s.
+ * If {@code JavaFileObject} type is {@link JavaFileObject.Kind#SOURCE} them the source is compiled.
+ *
+ * @author Decebal Suiu
+ */
+public class JavaFileObjectClassLoader extends ClassLoader {
+
+    public Map<String, Class<?>> load(JavaFileObject... objects) {
+        return load(Arrays.asList(objects));
+    }
+
+    public Map<String, Class<?>> load(List<JavaFileObject> objects) {
+        Objects.requireNonNull(objects);
+
+        List<JavaFileObject> mutableObjects = new ArrayList<>(objects);
+
+        // Sort generated ".class" by lastModified field
+        mutableObjects.sort(Comparator.comparingLong(JavaFileObject::getLastModified));
+
+        // Compile Java sources (if exists)
+        for (int i = 0; i < mutableObjects.size(); i++) {
+            JavaFileObject object = mutableObjects.get(i);
+            if (object.getKind() == JavaFileObject.Kind.CLASS) {
+                continue;
+            }
+
+            if (object.getKind() == JavaFileObject.Kind.SOURCE) {
+                mutableObjects.set(i, JavaSources.compile(object));
+            } else {
+                throw new IllegalStateException("Type " + object.getKind() + " is not supported");
+            }
+        }
+
+        // Load objects
+        Map<String, Class<?>> loadedClasses = new HashMap<>();
+        for (JavaFileObject object : mutableObjects) {
+            String className = JavaFileObjectUtils.getClassName(object);
+            byte[] data = JavaFileObjectUtils.getAllBytes(object);
+            Class<?> loadedClass = defineClass(className, data, 0, data.length);
+            loadedClasses.put(className, loadedClass);
+        }
+
+        return loadedClasses;
+    }
+
+}
diff --git a/pf4j/src/test/java/org/pf4j/test/JavaFileObjectDataProvider.java b/pf4j/src/test/java/org/pf4j/test/JavaFileObjectDataProvider.java
new file mode 100644 (file)
index 0000000..d729721
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2012-present the original author or authors.
+ *
+ * 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.pf4j.test;
+
+import javax.tools.FileObject;
+import javax.tools.JavaFileObject;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * Get class data from {@link JavaFileObject}.
+ * If {@code JavaFileObject} type is {@link JavaFileObject.Kind#SOURCE} them the source is compiled.
+ *
+ * @author Decebal Suiu
+ */
+public class JavaFileObjectDataProvider implements ClassDataProvider {
+
+    private final Map<String, JavaFileObject> classes;
+
+    public JavaFileObjectDataProvider(Map<String, JavaFileObject> classes) {
+        this.classes = classes;
+    }
+
+    public static JavaFileObjectDataProvider of(List<JavaFileObject> objects) {
+        List<JavaFileObject> tmp = new ArrayList<>(objects.size());
+        for (JavaFileObject object : objects) {
+            if (object.getKind() == JavaFileObject.Kind.CLASS) {
+                tmp.add(object);
+            } else if (object.getKind() == JavaFileObject.Kind.SOURCE) {
+                tmp.add(JavaSources.compile(object));
+            } else {
+                throw new IllegalStateException("Type " + object.getKind() + " is not supported");
+            }
+        }
+
+        // TODO JavaFileObjectUtils.getClassName() ?!
+        Map<String, JavaFileObject> classes = tmp.stream().collect(Collectors.toMap(FileObject::getName, c -> c));
+
+        return new JavaFileObjectDataProvider(classes);
+    }
+
+    @Override
+    public byte[] getClassData(String className) {
+        return JavaFileObjectUtils.getAllBytes(classes.get(className));
+    }
+
+}
diff --git a/pf4j/src/test/java/org/pf4j/test/JavaFileObjectUtils.java b/pf4j/src/test/java/org/pf4j/test/JavaFileObjectUtils.java
new file mode 100644 (file)
index 0000000..4e7c32c
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2012-present the original author or authors.
+ *
+ * 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.pf4j.test;
+
+import com.google.common.io.ByteStreams;
+
+import javax.tools.JavaFileObject;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * @author Decebal Suiu
+ */
+public class JavaFileObjectUtils {
+
+    private JavaFileObjectUtils() {}
+
+    public static String getClassName(JavaFileObject object) {
+        if (object.getKind() != JavaFileObject.Kind.CLASS) {
+            throw new IllegalStateException("Only Kind.CLASS is supported");
+        }
+
+        String name = object.getName();
+        // Remove "/CLASS_OUT/" from head and ".class" from tail
+        name = name.substring(14, name.length() - 6);
+        name = name.replace('/', '.');
+
+        return name;
+    }
+
+    public static byte[] getAllBytes(JavaFileObject object) {
+        try (InputStream in = object.openInputStream()) {
+            return ByteStreams.toByteArray(in);
+        } catch (IOException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+}
diff --git a/pf4j/src/test/java/org/pf4j/test/JavaSources.java b/pf4j/src/test/java/org/pf4j/test/JavaSources.java
new file mode 100644 (file)
index 0000000..2031edc
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2012-present the original author or authors.
+ *
+ * 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.pf4j.test;
+
+import com.google.testing.compile.JavaFileObjects;
+
+import javax.tools.JavaFileObject;
+import java.util.List;
+
+import static com.google.testing.compile.Compiler.javac;
+
+/**
+ * Keep common Java sources (useful in many tests).
+ * For Java 13+ is recommended to use Text Block feature (it's more clear).
+ *
+ * @author Decebal Suiu
+ */
+public class JavaSources {
+
+    public static final JavaFileObject Greeting = JavaFileObjects.forSourceLines("Greeting",
+        "package test;",
+        "import org.pf4j.ExtensionPoint;",
+        "",
+        "public interface Greeting extends ExtensionPoint {",
+        "   String getGreeting();",
+        "}");
+
+    public static final JavaFileObject WhazzupGreeting = JavaFileObjects.forSourceLines("WhazzupGreeting",
+        "package test;",
+        "import org.pf4j.Extension;",
+        "",
+        "@Extension",
+        "public class WhazzupGreeting implements Greeting {",
+        "   @Override",
+        "    public String getGreeting() {",
+        "       return \"Whazzup\";",
+        "    }",
+        "}");
+
+    /**
+     * Compile a list of sources using javac compiler.
+     */
+    public static List<JavaFileObject> compileAll(JavaFileObject... sources) {
+        return javac().compile(sources).generatedFiles();
+    }
+
+    public static JavaFileObject compile(JavaFileObject source) {
+        return compileAll(source).get(0);
+    }
+
+}
index bab85b39fe6046565a8a7b7ff3632e5e0c852df3..59b818d8f0f278caa4c9abbf08fd086342040c38 100644 (file)
@@ -20,9 +20,8 @@ import org.pf4j.PluginWrapper;
 
 /**
  * A simple {@link Plugin}.
- *
  * In real applications you don't need to create a plugin like this if you are not interested in lifecycle events.
- * {@codes PF4J} will automatically create a plugin similar to this (empty / dummy) if no class plugin is specified.
+ * {@code PF4J} will automatically create a plugin similar to this (empty / dummy) if no class plugin is specified.
  *
  * @author Mario Franco
  */