Browse Source

Improve class generation for testing

pull/515/head
Decebal Suiu 1 year ago
parent
commit
aebfa790b6

+ 41
- 71
pf4j/src/test/java/org/pf4j/AbstractExtensionFinderTest.java View File

@@ -15,34 +15,26 @@
*/
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);
}

}

+ 22
- 2
pf4j/src/test/java/org/pf4j/DefaultExtensionFactoryTest.java View File

@@ -15,12 +15,16 @@
*/
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));
}

}

+ 49
- 10
pf4j/src/test/java/org/pf4j/DefaultPluginFactoryTest.java View File

@@ -15,14 +15,18 @@
*/
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();


+ 39
- 54
pf4j/src/test/java/org/pf4j/ExtensionAnnotationProcessorTest.java View File

@@ -16,12 +16,16 @@
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);
}

}

+ 1
- 2
pf4j/src/test/java/org/pf4j/SingletonExtensionFactoryTest.java View 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);

+ 0
- 32
pf4j/src/test/java/org/pf4j/test/AnotherFailTestPlugin.java View File

@@ -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);
}

}

+ 0
- 34
pf4j/src/test/java/org/pf4j/test/AnotherTestPlugin.java View File

@@ -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();
}

}

+ 5
- 15
pf4j/src/test/java/org/pf4j/test/DefaultClassDataProvider.java View File

@@ -15,10 +15,10 @@
*/
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);
}
}


+ 0
- 37
pf4j/src/test/java/org/pf4j/test/FailTestExtension.java View File

@@ -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";
}

}

+ 0
- 26
pf4j/src/test/java/org/pf4j/test/FailTestPlugin.java View File

@@ -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 {

}

+ 73
- 0
pf4j/src/test/java/org/pf4j/test/JavaFileObjectClassLoader.java View File

@@ -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;
}

}

+ 62
- 0
pf4j/src/test/java/org/pf4j/test/JavaFileObjectDataProvider.java View File

@@ -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));
}

}

+ 52
- 0
pf4j/src/test/java/org/pf4j/test/JavaFileObjectUtils.java View File

@@ -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);
}
}

}

+ 64
- 0
pf4j/src/test/java/org/pf4j/test/JavaSources.java View File

@@ -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);
}

}

+ 1
- 2
pf4j/src/test/java/org/pf4j/test/TestPlugin.java View 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
*/

Loading…
Cancel
Save