TSK-1941: test-api injects enclosing class instance for non-static member classes
this allows SPIs to use instance fields from their enclosing class
This commit is contained in:
parent
41ecfa2245
commit
830723800e
|
@ -44,4 +44,18 @@ public class ReflectionUtil {
|
|||
public static <T> Class<T> wrap(Class<T> c) {
|
||||
return c.isPrimitive() ? (Class<T>) PRIMITIVES_TO_WRAPPERS.get(c) : c;
|
||||
}
|
||||
|
||||
public static Object getEnclosingInstance(Object instance) {
|
||||
return Arrays.stream(instance.getClass().getDeclaredFields())
|
||||
.filter(Field::isSynthetic)
|
||||
.filter(f -> f.getName().startsWith("this"))
|
||||
.findFirst()
|
||||
.map(
|
||||
CheckedFunction.wrap(
|
||||
field -> {
|
||||
field.setAccessible(true);
|
||||
return field.get(instance);
|
||||
}))
|
||||
.orElse(null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,9 @@ import java.lang.reflect.Field;
|
|||
import java.util.List;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import pro.taskana.common.internal.util.TopLevelTestClass.FirstNestedClass;
|
||||
import pro.taskana.common.internal.util.TopLevelTestClass.FirstNestedClass.SecondNestedClass;
|
||||
|
||||
class ReflectionUtilTest {
|
||||
|
||||
@Test
|
||||
|
@ -31,6 +34,36 @@ class ReflectionUtilTest {
|
|||
assertThat(wrap).isEqualTo(TestClass.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_ReturnNull_For_TopLevelClass() {
|
||||
TopLevelTestClass topLevelTestClass = new TopLevelTestClass();
|
||||
|
||||
Object enclosingInstance = ReflectionUtil.getEnclosingInstance(topLevelTestClass);
|
||||
|
||||
assertThat(enclosingInstance).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_ReturnTopLevelInstance_For_NestedInstance() {
|
||||
TopLevelTestClass topLevelTestClass = new TopLevelTestClass();
|
||||
FirstNestedClass firstNestedClass = topLevelTestClass.new FirstNestedClass();
|
||||
|
||||
Object enclosingInstance = ReflectionUtil.getEnclosingInstance(firstNestedClass);
|
||||
|
||||
assertThat(enclosingInstance).isSameAs(topLevelTestClass);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_ReturnNestedInstance_For_NestedNestedInstance() {
|
||||
TopLevelTestClass topLevelTestClass = new TopLevelTestClass();
|
||||
FirstNestedClass firstNestedClass = topLevelTestClass.new FirstNestedClass();
|
||||
SecondNestedClass secondNestedClass = firstNestedClass.new SecondNestedClass();
|
||||
|
||||
Object enclosingInstance = ReflectionUtil.getEnclosingInstance(secondNestedClass);
|
||||
|
||||
assertThat(enclosingInstance).isSameAs(firstNestedClass);
|
||||
}
|
||||
|
||||
static class TestClass {
|
||||
@SuppressWarnings("unused")
|
||||
String fieldA;
|
||||
|
@ -46,3 +79,16 @@ class ReflectionUtilTest {
|
|||
String fieldC;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"checkstyle:OneTopLevelClass", "InnerClassMayBeStatic", "unused"})
|
||||
class TopLevelTestClass {
|
||||
String someField;
|
||||
|
||||
class FirstNestedClass {
|
||||
String someField;
|
||||
|
||||
class SecondNestedClass {
|
||||
String someField;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,8 +55,6 @@ class TaskRoutingAccTest {
|
|||
.permission(WorkbasketPermission.READ)
|
||||
.permission(WorkbasketPermission.APPEND)
|
||||
.buildAndStore(workbasketService);
|
||||
|
||||
TaskRoutingProviderForDomainA.domainAWorkbasketId = domainAWorkbasket.getId();
|
||||
}
|
||||
|
||||
@WithAccessId(user = "user-1-1")
|
||||
|
@ -83,9 +81,7 @@ class TaskRoutingAccTest {
|
|||
assertThat(createdTask.getWorkbasketSummary()).isEqualTo(domainAWorkbasket);
|
||||
}
|
||||
|
||||
public static class TaskRoutingProviderForDomainA implements TaskRoutingProvider {
|
||||
|
||||
static String domainAWorkbasketId;
|
||||
class TaskRoutingProviderForDomainA implements TaskRoutingProvider {
|
||||
|
||||
@Override
|
||||
public void initialize(TaskanaEngine taskanaEngine) {}
|
||||
|
@ -93,7 +89,7 @@ class TaskRoutingAccTest {
|
|||
@Override
|
||||
public String determineWorkbasketId(Task task) {
|
||||
if ("DOMAIN_A".equals(task.getDomain())) {
|
||||
return domainAWorkbasketId;
|
||||
return domainAWorkbasket.getId();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import static org.junit.platform.commons.support.AnnotationSupport.isAnnotated;
|
|||
import static pro.taskana.testapi.util.ExtensionCommunicator.getClassLevelStore;
|
||||
import static pro.taskana.testapi.util.ExtensionCommunicator.isTopLevelClass;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.sql.DataSource;
|
||||
import org.apache.ibatis.session.SqlSession;
|
||||
|
@ -29,6 +30,7 @@ import pro.taskana.common.internal.InternalTaskanaEngine;
|
|||
import pro.taskana.common.internal.JobServiceImpl;
|
||||
import pro.taskana.common.internal.TaskanaEngineImpl;
|
||||
import pro.taskana.common.internal.security.CurrentUserContextImpl;
|
||||
import pro.taskana.common.internal.util.ReflectionUtil;
|
||||
import pro.taskana.common.internal.util.SpiLoader;
|
||||
import pro.taskana.monitor.api.MonitorService;
|
||||
import pro.taskana.monitor.internal.MonitorServiceImpl;
|
||||
|
@ -68,7 +70,8 @@ public class TaskanaInitializationExtension implements TestInstancePostProcessor
|
|||
|
||||
TaskanaEngine taskanaEngine;
|
||||
try (MockedStatic<SpiLoader> staticMock = Mockito.mockStatic(SpiLoader.class)) {
|
||||
ServiceProviderExtractor.extractServiceProviders(testClass)
|
||||
ServiceProviderExtractor.extractServiceProviders(
|
||||
testClass, extractEnclosingTestInstances(testInstance))
|
||||
.forEach(
|
||||
(spi, serviceProviders) ->
|
||||
staticMock.when(() -> SpiLoader.load(spi)).thenReturn(serviceProviders));
|
||||
|
@ -80,6 +83,15 @@ public class TaskanaInitializationExtension implements TestInstancePostProcessor
|
|||
}
|
||||
}
|
||||
|
||||
private static Map<Class<?>, Object> extractEnclosingTestInstances(Object instance) {
|
||||
HashMap<Class<?>, Object> instanceByClass = new HashMap<>();
|
||||
while (instance != null) {
|
||||
instanceByClass.put(instance.getClass(), instance);
|
||||
instance = ReflectionUtil.getEnclosingInstance(instance);
|
||||
}
|
||||
return instanceByClass;
|
||||
}
|
||||
|
||||
private static TaskanaEngineConfiguration createDefaultTaskanaEngineConfiguration(Store store) {
|
||||
String schemaName = store.get(TestContainerExtension.STORE_SCHEMA_NAME, String.class);
|
||||
if (schemaName == null) {
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
package pro.taskana.testapi.util;
|
||||
|
||||
import static org.junit.platform.commons.support.AnnotationSupport.findRepeatableAnnotations;
|
||||
import static pro.taskana.common.internal.util.CheckedFunction.wrap;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
@ -12,6 +10,7 @@ import java.util.Map.Entry;
|
|||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import org.junit.platform.commons.JUnitException;
|
||||
import org.junit.platform.commons.support.ReflectionSupport;
|
||||
|
||||
import pro.taskana.spi.history.api.TaskanaHistory;
|
||||
import pro.taskana.spi.priority.api.PriorityServiceProvider;
|
||||
|
@ -36,7 +35,8 @@ public class ServiceProviderExtractor {
|
|||
throw new IllegalStateException("utility class");
|
||||
}
|
||||
|
||||
public static Map<Class<?>, List<Object>> extractServiceProviders(Class<?> testClass) {
|
||||
public static Map<Class<?>, List<Object>> extractServiceProviders(
|
||||
Class<?> testClass, Map<Class<?>, Object> enclosingTestInstancesByClass) {
|
||||
List<WithServiceProvider> withServiceProviders =
|
||||
findRepeatableAnnotations(testClass, WithServiceProvider.class);
|
||||
|
||||
|
@ -44,7 +44,9 @@ public class ServiceProviderExtractor {
|
|||
.peek(entry -> validateServiceProviders(entry.getKey(), entry.getValue()))
|
||||
.collect(
|
||||
Collectors.toMap(
|
||||
Entry::getKey, entry -> instantiateServiceProviders(entry.getValue())));
|
||||
Entry::getKey,
|
||||
entry ->
|
||||
instantiateServiceProviders(entry.getValue(), enclosingTestInstancesByClass)));
|
||||
}
|
||||
|
||||
private static void validateServiceProviders(Class<?> spi, List<Class<?>> serviceProviders) {
|
||||
|
@ -69,24 +71,33 @@ public class ServiceProviderExtractor {
|
|||
Collectors.toList())));
|
||||
}
|
||||
|
||||
private static List<Object> instantiateServiceProviders(List<Class<?>> serviceProviders) {
|
||||
private static List<Object> instantiateServiceProviders(
|
||||
List<Class<?>> serviceProviders, Map<Class<?>, Object> enclosingTestInstancesByClass) {
|
||||
return serviceProviders.stream()
|
||||
.map(wrap(ServiceProviderExtractor::instantiateClass))
|
||||
.map(clz -> instantiateClass(clz, enclosingTestInstancesByClass))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static Object instantiateClass(Class<?> clz) throws Exception {
|
||||
private static Object instantiateClass(
|
||||
Class<?> clz, Map<Class<?>, Object> enclosingTestInstancesByClass) {
|
||||
// we don't have to consider anonymous classes since they can't be passed as an argument to
|
||||
// the WithServiceProvider annotation.
|
||||
if (clz.isLocalClass() || (clz.isMemberClass() && !Modifier.isStatic(clz.getModifiers()))) {
|
||||
Class<?> motherClass = clz.getEnclosingClass();
|
||||
Object motherInstance = instantiateClass(motherClass);
|
||||
Constructor<?> constructor = clz.getDeclaredConstructor(motherClass);
|
||||
constructor.setAccessible(true);
|
||||
return constructor.newInstance(motherInstance);
|
||||
try {
|
||||
Class<?> motherClass = clz.getEnclosingClass();
|
||||
Object motherInstance =
|
||||
enclosingTestInstancesByClass.getOrDefault(
|
||||
motherClass, instantiateClass(motherClass, enclosingTestInstancesByClass));
|
||||
return ReflectionSupport.newInstance(clz, motherInstance);
|
||||
} catch (Exception e) {
|
||||
//noinspection ConstantConditions
|
||||
if (NoSuchMethodException.class == e.getClass()) {
|
||||
throw new JUnitException(
|
||||
"test-api does not support local class which accesses method variables");
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
Constructor<?> constructor = clz.getDeclaredConstructor();
|
||||
constructor.setAccessible(true);
|
||||
return constructor.newInstance();
|
||||
return ReflectionSupport.newInstance(clz);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package pro.taskana.testapi.util;
|
||||
|
||||
import static java.util.Map.entry;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static pro.taskana.testapi.util.ServiceProviderExtractor.extractServiceProviders;
|
||||
|
@ -14,6 +15,7 @@ import org.junit.jupiter.api.TestInstance;
|
|||
import org.junit.jupiter.api.TestInstance.Lifecycle;
|
||||
import org.junit.platform.commons.JUnitException;
|
||||
|
||||
import pro.taskana.common.internal.util.ReflectionUtil;
|
||||
import pro.taskana.spi.priority.api.PriorityServiceProvider;
|
||||
import pro.taskana.spi.task.api.CreateTaskPreprocessor;
|
||||
import pro.taskana.task.api.models.Task;
|
||||
|
@ -66,16 +68,30 @@ class ServiceProviderExtractorTest {
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("InnerClassMayBeStatic")
|
||||
class NonStaticCreateTaskPreprocessorOutsideOfTestClass implements CreateTaskPreprocessor {
|
||||
@Override
|
||||
public void processTaskBeforeCreation(Task taskToProcess) {
|
||||
// implementation not important for the tests
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestInstance(Lifecycle.PER_CLASS)
|
||||
class ServiceProviderInstantiation {
|
||||
|
||||
private final Map<Class<?>, Object> enclosingTestInstancesByClass =
|
||||
Map.ofEntries(
|
||||
entry(ServiceProviderInstantiation.class, this),
|
||||
entry(ServiceProviderExtractorTest.class, ServiceProviderExtractorTest.this));
|
||||
|
||||
@Test
|
||||
void should_ReturnEmptyMap_When_NoServiceProviderIsDefined() {
|
||||
class ExampleClazzWithNoServiceProviders {}
|
||||
class ExampleTestClassWithNoServiceProviders {}
|
||||
|
||||
Map<Class<?>, List<Object>> extractServiceProviders =
|
||||
extractServiceProviders(ExampleClazzWithNoServiceProviders.class);
|
||||
extractServiceProviders(
|
||||
ExampleTestClassWithNoServiceProviders.class, enclosingTestInstancesByClass);
|
||||
|
||||
assertThat(extractServiceProviders).isEmpty();
|
||||
}
|
||||
|
@ -85,16 +101,17 @@ class ServiceProviderExtractorTest {
|
|||
@WithServiceProvider(
|
||||
serviceProviderInterface = CreateTaskPreprocessor.class,
|
||||
serviceProviders = TopLevelCreateTaskPreprocessor.class)
|
||||
class ExampleClassWithServiceProviders {}
|
||||
class ExampleTestClassWithServiceProviders {}
|
||||
|
||||
Map<Class<?>, List<Object>> extractServiceProviders =
|
||||
extractServiceProviders(ExampleClassWithServiceProviders.class);
|
||||
extractServiceProviders(
|
||||
ExampleTestClassWithServiceProviders.class, enclosingTestInstancesByClass);
|
||||
|
||||
assertThat(extractServiceProviders).containsOnlyKeys(CreateTaskPreprocessor.class);
|
||||
assertThat(extractServiceProviders.get(CreateTaskPreprocessor.class))
|
||||
.extracting(Object::getClass)
|
||||
.asList()
|
||||
.containsExactly(TopLevelCreateTaskPreprocessor.class);
|
||||
.hasExactlyElementsOfTypes(TopLevelCreateTaskPreprocessor.class)
|
||||
.extracting(ReflectionUtil::getEnclosingInstance)
|
||||
.containsOnlyNulls();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -102,16 +119,17 @@ class ServiceProviderExtractorTest {
|
|||
@WithServiceProvider(
|
||||
serviceProviderInterface = CreateTaskPreprocessor.class,
|
||||
serviceProviders = StaticCreateTaskPreprocessor.class)
|
||||
class ExampleClassWithServiceProviders {}
|
||||
class ExampleTestClassWithServiceProviders {}
|
||||
|
||||
Map<Class<?>, List<Object>> extractServiceProviders =
|
||||
extractServiceProviders(ExampleClassWithServiceProviders.class);
|
||||
extractServiceProviders(
|
||||
ExampleTestClassWithServiceProviders.class, enclosingTestInstancesByClass);
|
||||
|
||||
assertThat(extractServiceProviders).containsOnlyKeys(CreateTaskPreprocessor.class);
|
||||
assertThat(extractServiceProviders.get(CreateTaskPreprocessor.class))
|
||||
.extracting(Object::getClass)
|
||||
.asList()
|
||||
.containsExactly(StaticCreateTaskPreprocessor.class);
|
||||
.hasExactlyElementsOfTypes(StaticCreateTaskPreprocessor.class)
|
||||
.extracting(ReflectionUtil::getEnclosingInstance)
|
||||
.containsOnlyNulls();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -119,16 +137,17 @@ class ServiceProviderExtractorTest {
|
|||
@WithServiceProvider(
|
||||
serviceProviderInterface = CreateTaskPreprocessor.class,
|
||||
serviceProviders = PrivateStaticCreateTaskPreprocessor.class)
|
||||
class ExampleClassWithServiceProviders {}
|
||||
class ExampleTestClassWithServiceProviders {}
|
||||
|
||||
Map<Class<?>, List<Object>> extractServiceProviders =
|
||||
extractServiceProviders(ExampleClassWithServiceProviders.class);
|
||||
extractServiceProviders(
|
||||
ExampleTestClassWithServiceProviders.class, enclosingTestInstancesByClass);
|
||||
|
||||
assertThat(extractServiceProviders).containsOnlyKeys(CreateTaskPreprocessor.class);
|
||||
assertThat(extractServiceProviders.get(CreateTaskPreprocessor.class))
|
||||
.extracting(Object::getClass)
|
||||
.asList()
|
||||
.containsExactly(PrivateStaticCreateTaskPreprocessor.class);
|
||||
.hasExactlyElementsOfTypes(PrivateStaticCreateTaskPreprocessor.class)
|
||||
.extracting(ReflectionUtil::getEnclosingInstance)
|
||||
.containsOnlyNulls();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -143,33 +162,35 @@ class ServiceProviderExtractorTest {
|
|||
@WithServiceProvider(
|
||||
serviceProviderInterface = CreateTaskPreprocessor.class,
|
||||
serviceProviders = LocalCreateTaskPreprocessor.class)
|
||||
class ExampleClassWithServiceProviders {}
|
||||
class ExampleTestClassWithServiceProviders {}
|
||||
|
||||
Map<Class<?>, List<Object>> extractServiceProviders =
|
||||
extractServiceProviders(ExampleClassWithServiceProviders.class);
|
||||
extractServiceProviders(
|
||||
ExampleTestClassWithServiceProviders.class, enclosingTestInstancesByClass);
|
||||
|
||||
assertThat(extractServiceProviders).containsOnlyKeys(CreateTaskPreprocessor.class);
|
||||
assertThat(extractServiceProviders.get(CreateTaskPreprocessor.class))
|
||||
.extracting(Object::getClass)
|
||||
.asList()
|
||||
.containsExactly(LocalCreateTaskPreprocessor.class);
|
||||
.hasExactlyElementsOfTypes(LocalCreateTaskPreprocessor.class)
|
||||
.extracting(ReflectionUtil::getEnclosingInstance)
|
||||
.containsExactly(this);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_InstantiateServiceProvider_When_ServiceProviderIsNonStaticMemberClass() {
|
||||
@WithServiceProvider(
|
||||
serviceProviderInterface = CreateTaskPreprocessor.class,
|
||||
serviceProviders = NonStaticCreateTaskPreprocessor.class)
|
||||
class ExampleClassWithServiceProviders {}
|
||||
serviceProviders = NonStaticCreateTaskPreprocessorInsideOfTestClass.class)
|
||||
class ExampleTestClassWithServiceProviders {}
|
||||
|
||||
Map<Class<?>, List<Object>> extractServiceProviders =
|
||||
extractServiceProviders(ExampleClassWithServiceProviders.class);
|
||||
extractServiceProviders(
|
||||
ExampleTestClassWithServiceProviders.class, enclosingTestInstancesByClass);
|
||||
|
||||
assertThat(extractServiceProviders).containsOnlyKeys(CreateTaskPreprocessor.class);
|
||||
assertThat(extractServiceProviders.get(CreateTaskPreprocessor.class))
|
||||
.extracting(Object::getClass)
|
||||
.asList()
|
||||
.containsExactly(NonStaticCreateTaskPreprocessor.class);
|
||||
.hasExactlyElementsOfTypes(NonStaticCreateTaskPreprocessorInsideOfTestClass.class)
|
||||
.extracting(ReflectionUtil::getEnclosingInstance)
|
||||
.containsExactly(this);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -177,20 +198,38 @@ class ServiceProviderExtractorTest {
|
|||
@WithServiceProvider(
|
||||
serviceProviderInterface = CreateTaskPreprocessor.class,
|
||||
serviceProviders = PrivateNonStaticCreateTaskPreprocessor.class)
|
||||
class ExampleClassWithServiceProviders {}
|
||||
class ExampleTestClassWithServiceProviders {}
|
||||
|
||||
Map<Class<?>, List<Object>> extractServiceProviders =
|
||||
extractServiceProviders(ExampleClassWithServiceProviders.class);
|
||||
extractServiceProviders(
|
||||
ExampleTestClassWithServiceProviders.class, enclosingTestInstancesByClass);
|
||||
|
||||
assertThat(extractServiceProviders).containsOnlyKeys(CreateTaskPreprocessor.class);
|
||||
assertThat(extractServiceProviders.get(CreateTaskPreprocessor.class))
|
||||
.extracting(Object::getClass)
|
||||
.asList()
|
||||
.containsExactly(PrivateNonStaticCreateTaskPreprocessor.class);
|
||||
.hasExactlyElementsOfTypes(PrivateNonStaticCreateTaskPreprocessor.class)
|
||||
.extracting(ReflectionUtil::getEnclosingInstance)
|
||||
.containsExactly(this);
|
||||
}
|
||||
|
||||
class NonStaticCreateTaskPreprocessor implements CreateTaskPreprocessor {
|
||||
@Test
|
||||
void should_InstantiateServiceProvider_When_ItIsNonStaticMemberClassOutsideOfTestClass() {
|
||||
@WithServiceProvider(
|
||||
serviceProviderInterface = CreateTaskPreprocessor.class,
|
||||
serviceProviders = NonStaticCreateTaskPreprocessorOutsideOfTestClass.class)
|
||||
class ExampleTestClassWithServiceProviders {}
|
||||
|
||||
Map<Class<?>, List<Object>> extractServiceProviders =
|
||||
extractServiceProviders(
|
||||
ExampleTestClassWithServiceProviders.class, enclosingTestInstancesByClass);
|
||||
|
||||
assertThat(extractServiceProviders).containsOnlyKeys(CreateTaskPreprocessor.class);
|
||||
assertThat(extractServiceProviders.get(CreateTaskPreprocessor.class))
|
||||
.hasExactlyElementsOfTypes(NonStaticCreateTaskPreprocessorOutsideOfTestClass.class)
|
||||
.extracting(ReflectionUtil::getEnclosingInstance)
|
||||
.containsExactly(ServiceProviderExtractorTest.this);
|
||||
}
|
||||
|
||||
class NonStaticCreateTaskPreprocessorInsideOfTestClass implements CreateTaskPreprocessor {
|
||||
@Override
|
||||
public void processTaskBeforeCreation(Task taskToProcess) {
|
||||
// implementation not important for the tests
|
||||
|
@ -210,21 +249,26 @@ class ServiceProviderExtractorTest {
|
|||
@TestInstance(Lifecycle.PER_CLASS)
|
||||
class ExtractServiceProvidersFromSingleServiceProviderInterface {
|
||||
|
||||
private final Map<Class<?>, Object> enclosingTestInstancesByClass =
|
||||
Map.ofEntries(
|
||||
entry(ExtractServiceProvidersFromSingleServiceProviderInterface.class, this),
|
||||
entry(ServiceProviderExtractorTest.class, ServiceProviderExtractorTest.this));
|
||||
|
||||
@Test
|
||||
void should_ExtractServiceProvider() {
|
||||
@WithServiceProvider(
|
||||
serviceProviderInterface = CreateTaskPreprocessor.class,
|
||||
serviceProviders = DummyTaskPreprocessor1.class)
|
||||
class ExampleClassWithServiceProviders {}
|
||||
class ExampleTestClassWithServiceProviders {}
|
||||
|
||||
Map<Class<?>, List<Object>> extractServiceProviders =
|
||||
extractServiceProviders(ExampleClassWithServiceProviders.class);
|
||||
extractServiceProviders(
|
||||
ExampleTestClassWithServiceProviders.class, enclosingTestInstancesByClass);
|
||||
|
||||
assertThat(extractServiceProviders).containsOnlyKeys(CreateTaskPreprocessor.class);
|
||||
assertThat(extractServiceProviders.get(CreateTaskPreprocessor.class))
|
||||
.extracting(Object::getClass)
|
||||
.asList()
|
||||
.containsExactly(DummyTaskPreprocessor1.class);
|
||||
.hasExactlyElementsOfTypes(DummyTaskPreprocessor1.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -232,16 +276,16 @@ class ServiceProviderExtractorTest {
|
|||
@WithServiceProvider(
|
||||
serviceProviderInterface = CreateTaskPreprocessor.class,
|
||||
serviceProviders = {DummyTaskPreprocessor1.class, DummyTaskPreprocessor2.class})
|
||||
class ExampleClassWithServiceProviders {}
|
||||
class ExampleTestClassWithServiceProviders {}
|
||||
|
||||
Map<Class<?>, List<Object>> extractServiceProviders =
|
||||
extractServiceProviders(ExampleClassWithServiceProviders.class);
|
||||
extractServiceProviders(
|
||||
ExampleTestClassWithServiceProviders.class, enclosingTestInstancesByClass);
|
||||
|
||||
assertThat(extractServiceProviders).containsOnlyKeys(CreateTaskPreprocessor.class);
|
||||
assertThat(extractServiceProviders.get(CreateTaskPreprocessor.class))
|
||||
.extracting(Object::getClass)
|
||||
.asList()
|
||||
.containsExactly(DummyTaskPreprocessor1.class, DummyTaskPreprocessor2.class);
|
||||
.hasExactlyElementsOfTypes(DummyTaskPreprocessor1.class, DummyTaskPreprocessor2.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -252,16 +296,15 @@ class ServiceProviderExtractorTest {
|
|||
@WithServiceProvider(
|
||||
serviceProviderInterface = CreateTaskPreprocessor.class,
|
||||
serviceProviders = DummyTaskPreprocessor2.class)
|
||||
class ExampleClassWithServiceProviders {}
|
||||
class ExampleTestClassWithServiceProviders {}
|
||||
|
||||
Map<Class<?>, List<Object>> extractServiceProviders =
|
||||
extractServiceProviders(ExampleClassWithServiceProviders.class);
|
||||
extractServiceProviders(
|
||||
ExampleTestClassWithServiceProviders.class, enclosingTestInstancesByClass);
|
||||
|
||||
assertThat(extractServiceProviders).containsOnlyKeys(CreateTaskPreprocessor.class);
|
||||
assertThat(extractServiceProviders.get(CreateTaskPreprocessor.class))
|
||||
.extracting(Object::getClass)
|
||||
.asList()
|
||||
.containsExactly(DummyTaskPreprocessor1.class, DummyTaskPreprocessor2.class);
|
||||
.hasExactlyElementsOfTypes(DummyTaskPreprocessor1.class, DummyTaskPreprocessor2.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -269,16 +312,15 @@ class ServiceProviderExtractorTest {
|
|||
@WithServiceProvider(
|
||||
serviceProviderInterface = CreateTaskPreprocessor.class,
|
||||
serviceProviders = {DummyTaskPreprocessor1.class, DummyTaskPreprocessor1.class})
|
||||
class ExampleClassWithServiceProviders {}
|
||||
class ExampleTestClassWithServiceProviders {}
|
||||
|
||||
Map<Class<?>, List<Object>> extractServiceProviders =
|
||||
extractServiceProviders(ExampleClassWithServiceProviders.class);
|
||||
extractServiceProviders(
|
||||
ExampleTestClassWithServiceProviders.class, enclosingTestInstancesByClass);
|
||||
|
||||
assertThat(extractServiceProviders).containsOnlyKeys(CreateTaskPreprocessor.class);
|
||||
assertThat(extractServiceProviders.get(CreateTaskPreprocessor.class))
|
||||
.extracting(Object::getClass)
|
||||
.asList()
|
||||
.containsExactly(DummyTaskPreprocessor1.class, DummyTaskPreprocessor1.class);
|
||||
.hasExactlyElementsOfTypes(DummyTaskPreprocessor1.class, DummyTaskPreprocessor1.class);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -286,6 +328,11 @@ class ServiceProviderExtractorTest {
|
|||
@TestInstance(Lifecycle.PER_CLASS)
|
||||
class ExtractMultipleServiceProvidersFromMultipleServiceProviderInterfaces {
|
||||
|
||||
private final Map<Class<?>, Object> enclosingTestInstancesByClass =
|
||||
Map.ofEntries(
|
||||
entry(ExtractMultipleServiceProvidersFromMultipleServiceProviderInterfaces.class, this),
|
||||
entry(ServiceProviderExtractorTest.class, ServiceProviderExtractorTest.this));
|
||||
|
||||
@Test
|
||||
void should_ExtractServiceProviders() {
|
||||
@WithServiceProvider(
|
||||
|
@ -294,21 +341,18 @@ class ServiceProviderExtractorTest {
|
|||
@WithServiceProvider(
|
||||
serviceProviderInterface = PriorityServiceProvider.class,
|
||||
serviceProviders = DummyPriorityServiceProvider1.class)
|
||||
class ExampleClassWithServiceProviders {}
|
||||
class ExampleTestClassWithServiceProviders {}
|
||||
|
||||
Map<Class<?>, List<Object>> extractServiceProviders =
|
||||
extractServiceProviders(ExampleClassWithServiceProviders.class);
|
||||
extractServiceProviders(
|
||||
ExampleTestClassWithServiceProviders.class, enclosingTestInstancesByClass);
|
||||
|
||||
assertThat(extractServiceProviders)
|
||||
.containsOnlyKeys(CreateTaskPreprocessor.class, PriorityServiceProvider.class);
|
||||
assertThat(extractServiceProviders.get(CreateTaskPreprocessor.class))
|
||||
.extracting(Object::getClass)
|
||||
.asList()
|
||||
.containsExactly(DummyTaskPreprocessor1.class);
|
||||
.hasExactlyElementsOfTypes(DummyTaskPreprocessor1.class);
|
||||
assertThat(extractServiceProviders.get(PriorityServiceProvider.class))
|
||||
.extracting(Object::getClass)
|
||||
.asList()
|
||||
.containsExactly(DummyPriorityServiceProvider1.class);
|
||||
.hasExactlyElementsOfTypes(DummyPriorityServiceProvider1.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -322,21 +366,18 @@ class ServiceProviderExtractorTest {
|
|||
DummyPriorityServiceProvider1.class,
|
||||
DummyPriorityServiceProvider2.class
|
||||
})
|
||||
class ExampleClassWithServiceProviders {}
|
||||
class ExampleTestClassWithServiceProviders {}
|
||||
|
||||
Map<Class<?>, List<Object>> extractServiceProviders =
|
||||
extractServiceProviders(ExampleClassWithServiceProviders.class);
|
||||
extractServiceProviders(
|
||||
ExampleTestClassWithServiceProviders.class, enclosingTestInstancesByClass);
|
||||
|
||||
assertThat(extractServiceProviders)
|
||||
.containsOnlyKeys(CreateTaskPreprocessor.class, PriorityServiceProvider.class);
|
||||
assertThat(extractServiceProviders.get(CreateTaskPreprocessor.class))
|
||||
.extracting(Object::getClass)
|
||||
.asList()
|
||||
.containsExactly(DummyTaskPreprocessor1.class, DummyTaskPreprocessor2.class);
|
||||
.hasExactlyElementsOfTypes(DummyTaskPreprocessor1.class, DummyTaskPreprocessor2.class);
|
||||
assertThat(extractServiceProviders.get(PriorityServiceProvider.class))
|
||||
.extracting(Object::getClass)
|
||||
.asList()
|
||||
.containsExactly(
|
||||
.hasExactlyElementsOfTypes(
|
||||
DummyPriorityServiceProvider1.class, DummyPriorityServiceProvider2.class);
|
||||
}
|
||||
}
|
||||
|
@ -350,9 +391,10 @@ class ServiceProviderExtractorTest {
|
|||
@WithServiceProvider(
|
||||
serviceProviderInterface = ErrorHandling.class,
|
||||
serviceProviders = DummyTaskPreprocessor1.class)
|
||||
class ExampleClassWithServiceProviders {}
|
||||
class ExampleTestClassWithServiceProviders {}
|
||||
|
||||
ThrowingCallable call = () -> extractServiceProviders(ExampleClassWithServiceProviders.class);
|
||||
ThrowingCallable call =
|
||||
() -> extractServiceProviders(ExampleTestClassWithServiceProviders.class, Map.of());
|
||||
|
||||
assertThatThrownBy(call)
|
||||
.isInstanceOf(JUnitException.class)
|
||||
|
@ -364,9 +406,10 @@ class ServiceProviderExtractorTest {
|
|||
@WithServiceProvider(
|
||||
serviceProviderInterface = CreateTaskPreprocessor.class,
|
||||
serviceProviders = DummyPriorityServiceProvider1.class)
|
||||
class ExampleClassWithServiceProviders {}
|
||||
class ExampleTestClassWithServiceProviders {}
|
||||
|
||||
ThrowingCallable call = () -> extractServiceProviders(ExampleClassWithServiceProviders.class);
|
||||
ThrowingCallable call =
|
||||
() -> extractServiceProviders(ExampleTestClassWithServiceProviders.class, Map.of());
|
||||
|
||||
assertThatThrownBy(call)
|
||||
.isInstanceOf(JUnitException.class)
|
||||
|
@ -380,9 +423,10 @@ class ServiceProviderExtractorTest {
|
|||
@WithServiceProvider(
|
||||
serviceProviderInterface = CreateTaskPreprocessor.class,
|
||||
serviceProviders = {DummyTaskPreprocessor1.class, DummyPriorityServiceProvider1.class})
|
||||
class ExampleClassWithServiceProviders {}
|
||||
class ExampleTestClassWithServiceProviders {}
|
||||
|
||||
ThrowingCallable call = () -> extractServiceProviders(ExampleClassWithServiceProviders.class);
|
||||
ThrowingCallable call =
|
||||
() -> extractServiceProviders(ExampleTestClassWithServiceProviders.class, Map.of());
|
||||
|
||||
assertThatThrownBy(call)
|
||||
.isInstanceOf(JUnitException.class)
|
||||
|
@ -390,5 +434,29 @@ class ServiceProviderExtractorTest {
|
|||
"At least one ServiceProvider does not implement the requested SPI '%s'",
|
||||
CreateTaskPreprocessor.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void should_ThrowException_When_LocalServiceProviderUsesAMethodVariable() {
|
||||
String methodVariable = "foobar";
|
||||
class LocalCreateTaskPreprocessor implements CreateTaskPreprocessor {
|
||||
@Override
|
||||
public void processTaskBeforeCreation(Task taskToProcess) {
|
||||
// implementation not important for the tests
|
||||
taskToProcess.setOwner(methodVariable);
|
||||
}
|
||||
}
|
||||
|
||||
@WithServiceProvider(
|
||||
serviceProviderInterface = CreateTaskPreprocessor.class,
|
||||
serviceProviders = LocalCreateTaskPreprocessor.class)
|
||||
class ExampleTestClassWithServiceProviders {}
|
||||
|
||||
ThrowingCallable call =
|
||||
() -> extractServiceProviders(ExampleTestClassWithServiceProviders.class, Map.of());
|
||||
|
||||
assertThatThrownBy(call)
|
||||
.isInstanceOf(JUnitException.class)
|
||||
.hasMessage("test-api does not support local class which accesses method variables");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue