mirror of
https://github.com/AuthMe/AuthMeReloaded.git
synced 2024-11-23 18:55:11 +01:00
#778 Delayed runner: add support for annotations, add validation
- Add support for dependencies identified by annotations - Add some more usage validation - Change a few test classes to use the DelayedInjectionRunner
This commit is contained in:
parent
4b3ab4b116
commit
e7ba579960
@ -7,7 +7,6 @@ import fr.xephi.authme.datasource.DataSource;
|
|||||||
import fr.xephi.authme.initialization.AuthMeServiceInitializer;
|
import fr.xephi.authme.initialization.AuthMeServiceInitializer;
|
||||||
import fr.xephi.authme.initialization.DataFolder;
|
import fr.xephi.authme.initialization.DataFolder;
|
||||||
import fr.xephi.authme.listener.AuthMeBlockListener;
|
import fr.xephi.authme.listener.AuthMeBlockListener;
|
||||||
import fr.xephi.authme.output.Messages;
|
|
||||||
import fr.xephi.authme.permission.PermissionsManager;
|
import fr.xephi.authme.permission.PermissionsManager;
|
||||||
import fr.xephi.authme.process.Management;
|
import fr.xephi.authme.process.Management;
|
||||||
import fr.xephi.authme.process.login.ProcessSyncPlayerLogin;
|
import fr.xephi.authme.process.login.ProcessSyncPlayerLogin;
|
||||||
@ -106,7 +105,6 @@ public class AuthMeInitializationTest {
|
|||||||
initializer.register(AuthMe.class, authMe);
|
initializer.register(AuthMe.class, authMe);
|
||||||
initializer.register(NewSetting.class, settings);
|
initializer.register(NewSetting.class, settings);
|
||||||
initializer.register(DataSource.class, mock(DataSource.class));
|
initializer.register(DataSource.class, mock(DataSource.class));
|
||||||
initializer.register(Messages.class, mock(Messages.class));
|
|
||||||
|
|
||||||
// when
|
// when
|
||||||
authMe.instantiateServices(initializer);
|
authMe.instantiateServices(initializer);
|
||||||
|
@ -7,14 +7,15 @@ import fr.xephi.authme.command.TestCommandsUtil.TestUnregisterCommand;
|
|||||||
import fr.xephi.authme.command.help.HelpProvider;
|
import fr.xephi.authme.command.help.HelpProvider;
|
||||||
import fr.xephi.authme.initialization.AuthMeServiceInitializer;
|
import fr.xephi.authme.initialization.AuthMeServiceInitializer;
|
||||||
import fr.xephi.authme.permission.PermissionsManager;
|
import fr.xephi.authme.permission.PermissionsManager;
|
||||||
|
import fr.xephi.authme.runner.BeforeInjecting;
|
||||||
|
import fr.xephi.authme.runner.DelayedInjectionRunner;
|
||||||
|
import fr.xephi.authme.runner.InjectDelayed;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.invocation.InvocationOnMock;
|
import org.mockito.invocation.InvocationOnMock;
|
||||||
import org.mockito.runners.MockitoJUnitRunner;
|
|
||||||
import org.mockito.stubbing.Answer;
|
import org.mockito.stubbing.Answer;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -48,9 +49,10 @@ import static org.mockito.Mockito.verify;
|
|||||||
// Justification: It's more readable to use asList() everywhere in the test when we often generated two lists where one
|
// Justification: It's more readable to use asList() everywhere in the test when we often generated two lists where one
|
||||||
// often consists of only one element, e.g. myMethod(asList("authme"), asList("my", "args"), ...)
|
// often consists of only one element, e.g. myMethod(asList("authme"), asList("my", "args"), ...)
|
||||||
@SuppressWarnings("ArraysAsListWithZeroOrOneArgument")
|
@SuppressWarnings("ArraysAsListWithZeroOrOneArgument")
|
||||||
@RunWith(MockitoJUnitRunner.class)
|
@RunWith(DelayedInjectionRunner.class)
|
||||||
public class CommandHandlerTest {
|
public class CommandHandlerTest {
|
||||||
|
|
||||||
|
@InjectDelayed
|
||||||
private CommandHandler handler;
|
private CommandHandler handler;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
@ -64,13 +66,12 @@ public class CommandHandlerTest {
|
|||||||
|
|
||||||
private Map<Class<? extends ExecutableCommand>, ExecutableCommand> mockedCommands = new HashMap<>();
|
private Map<Class<? extends ExecutableCommand>, ExecutableCommand> mockedCommands = new HashMap<>();
|
||||||
|
|
||||||
@Before
|
@BeforeInjecting
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void initializeCommandMapper() {
|
public void initializeCommandMapper() {
|
||||||
given(commandMapper.getCommandClasses()).willReturn(Sets.newHashSet(ExecutableCommand.class,
|
given(commandMapper.getCommandClasses()).willReturn(Sets.newHashSet(
|
||||||
TestLoginCommand.class, TestRegisterCommand.class, TestUnregisterCommand.class));
|
ExecutableCommand.class, TestLoginCommand.class, TestRegisterCommand.class, TestUnregisterCommand.class));
|
||||||
setInjectorToMockExecutableCommandClasses();
|
setInjectorToMockExecutableCommandClasses();
|
||||||
handler = new CommandHandler(initializer, commandMapper, permissionsManager, helpProvider);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3,16 +3,17 @@ package fr.xephi.authme.converter;
|
|||||||
import fr.xephi.authme.TestHelper;
|
import fr.xephi.authme.TestHelper;
|
||||||
import fr.xephi.authme.cache.auth.PlayerAuth;
|
import fr.xephi.authme.cache.auth.PlayerAuth;
|
||||||
import fr.xephi.authme.datasource.DataSource;
|
import fr.xephi.authme.datasource.DataSource;
|
||||||
|
import fr.xephi.authme.initialization.DataFolder;
|
||||||
|
import fr.xephi.authme.runner.DelayedInjectionRunner;
|
||||||
|
import fr.xephi.authme.runner.InjectDelayed;
|
||||||
import fr.xephi.authme.settings.NewSetting;
|
import fr.xephi.authme.settings.NewSetting;
|
||||||
import fr.xephi.authme.settings.properties.ConverterSettings;
|
import fr.xephi.authme.settings.properties.ConverterSettings;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.runners.MockitoJUnitRunner;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -31,9 +32,10 @@ import static org.mockito.Mockito.verifyZeroInteractions;
|
|||||||
/**
|
/**
|
||||||
* Test for {@link CrazyLoginConverter}.
|
* Test for {@link CrazyLoginConverter}.
|
||||||
*/
|
*/
|
||||||
@RunWith(MockitoJUnitRunner.class)
|
@RunWith(DelayedInjectionRunner.class)
|
||||||
public class CrazyLoginConverterTest {
|
public class CrazyLoginConverterTest {
|
||||||
|
|
||||||
|
@InjectDelayed
|
||||||
private CrazyLoginConverter crazyLoginConverter;
|
private CrazyLoginConverter crazyLoginConverter;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
@ -42,6 +44,7 @@ public class CrazyLoginConverterTest {
|
|||||||
@Mock
|
@Mock
|
||||||
private NewSetting settings;
|
private NewSetting settings;
|
||||||
|
|
||||||
|
@DataFolder
|
||||||
private File dataFolder = TestHelper.getJarFile("/converter/");
|
private File dataFolder = TestHelper.getJarFile("/converter/");
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
@ -49,11 +52,6 @@ public class CrazyLoginConverterTest {
|
|||||||
TestHelper.setupLogger();
|
TestHelper.setupLogger();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Before
|
|
||||||
public void instantiateConverter() {
|
|
||||||
crazyLoginConverter = new CrazyLoginConverter(dataFolder, dataSource, settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldImportUsers() {
|
public void shouldImportUsers() {
|
||||||
// given
|
// given
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package fr.xephi.authme.runner;
|
package fr.xephi.authme.runner;
|
||||||
|
|
||||||
import fr.xephi.authme.ReflectionTestUtils;
|
|
||||||
import fr.xephi.authme.initialization.Injection;
|
import fr.xephi.authme.initialization.Injection;
|
||||||
import fr.xephi.authme.initialization.InjectionHelper;
|
import fr.xephi.authme.initialization.InjectionHelper;
|
||||||
import org.junit.runner.notification.RunNotifier;
|
import org.junit.runner.notification.RunNotifier;
|
||||||
@ -11,13 +10,9 @@ import org.junit.runners.model.InitializationError;
|
|||||||
import org.junit.runners.model.Statement;
|
import org.junit.runners.model.Statement;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
import org.mockito.internal.runners.util.FrameworkUsageValidator;
|
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom JUnit runner which adds support for {@link InjectDelayed} and {@link BeforeInjecting}.
|
* Custom JUnit runner which adds support for {@link InjectDelayed} and {@link BeforeInjecting}.
|
||||||
@ -63,7 +58,7 @@ public class DelayedInjectionRunner extends BlockJUnit4ClassRunner {
|
|||||||
@Override
|
@Override
|
||||||
public void run(final RunNotifier notifier) {
|
public void run(final RunNotifier notifier) {
|
||||||
// add listener that validates framework usage at the end of each test
|
// add listener that validates framework usage at the end of each test
|
||||||
notifier.addListener(new FrameworkUsageValidator(notifier));
|
notifier.addListener(new DelayedInjectionRunnerValidator(notifier, getTestClass()));
|
||||||
super.run(notifier);
|
super.run(notifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,53 +82,23 @@ public class DelayedInjectionRunner extends BlockJUnit4ClassRunner {
|
|||||||
|
|
||||||
List<PendingInjection> pendingInjections = new ArrayList<>(delayedFields.size());
|
List<PendingInjection> pendingInjections = new ArrayList<>(delayedFields.size());
|
||||||
for (FrameworkField field : delayedFields) {
|
for (FrameworkField field : delayedFields) {
|
||||||
pendingInjections.add(createPendingInjection(target, field.getField()));
|
pendingInjections.add(new PendingInjection(field.getField(), getInjection(field)));
|
||||||
}
|
}
|
||||||
return new RunDelayedInjects(statement, pendingInjections, target);
|
InjectionResolver injectionResolver = new InjectionResolver(getTestClass(), target);
|
||||||
|
return new RunDelayedInjects(statement, pendingInjections, target, injectionResolver);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a {@link PendingInjection} for the given field's type, using the target's values.
|
* Gets the injection method for the given field's type and ensures an injection method has been found.
|
||||||
*
|
*
|
||||||
* @param target the target to get dependencies from
|
* @param field the field to get the injection for
|
||||||
* @param field the field to prepare an injection for
|
* @return the injection
|
||||||
* @return the resulting object
|
|
||||||
*/
|
*/
|
||||||
private PendingInjection createPendingInjection(Object target, Field field) {
|
private static Injection<?> getInjection(FrameworkField field) {
|
||||||
final Injection<?> injection = InjectionHelper.getInjection(field.getType());
|
final Injection<?> injection = InjectionHelper.getInjection(field.getType());
|
||||||
if (injection == null) {
|
if (injection == null) {
|
||||||
throw new IllegalStateException("No injection method available for field '" + field.getName() + "'");
|
throw new IllegalStateException("No injection method available for field '" + field.getName() + "'");
|
||||||
}
|
}
|
||||||
final Object[] dependencies = fulfillDependencies(target, injection.getDependencies());
|
return injection;
|
||||||
return new PendingInjection(field, injection, dependencies);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a list of all objects for the given list of dependencies, retrieved from the given
|
|
||||||
* target's {@link @Mock} fields.
|
|
||||||
*
|
|
||||||
* @param target the target to get the required dependencies from
|
|
||||||
* @param dependencies the required dependency types
|
|
||||||
* @return the resolved dependencies
|
|
||||||
*/
|
|
||||||
private Object[] fulfillDependencies(Object target, Class<?>[] dependencies) {
|
|
||||||
List<FrameworkField> availableMocks = getTestClass().getAnnotatedFields(Mock.class);
|
|
||||||
Map<Class<?>, Object> mocksByType = new HashMap<>();
|
|
||||||
for (FrameworkField frameworkField : availableMocks) {
|
|
||||||
Field field = frameworkField.getField();
|
|
||||||
Object fieldValue = ReflectionTestUtils.getFieldValue(field, target);
|
|
||||||
mocksByType.put(field.getType(), fieldValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
Object[] resolvedValues = new Object[dependencies.length];
|
|
||||||
for (int i = 0; i < dependencies.length; ++i) {
|
|
||||||
Object o = mocksByType.get(dependencies[i]);
|
|
||||||
if (o == null) {
|
|
||||||
throw new IllegalStateException("No mock found for '" + dependencies[i] + "'. "
|
|
||||||
+ "All dependencies of @InjectDelayed must be provided as @Mock fields");
|
|
||||||
}
|
|
||||||
resolvedValues[i] = o;
|
|
||||||
}
|
|
||||||
return resolvedValues;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,36 @@
|
|||||||
|
package fr.xephi.authme.runner;
|
||||||
|
|
||||||
|
import org.junit.runner.Description;
|
||||||
|
import org.junit.runner.notification.Failure;
|
||||||
|
import org.junit.runner.notification.RunListener;
|
||||||
|
import org.junit.runner.notification.RunNotifier;
|
||||||
|
import org.junit.runners.model.TestClass;
|
||||||
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates that {@link DelayedInjectionRunner} is used as intended.
|
||||||
|
*/
|
||||||
|
class DelayedInjectionRunnerValidator extends RunListener {
|
||||||
|
|
||||||
|
private final RunNotifier notifier;
|
||||||
|
private final TestClass testClass;
|
||||||
|
|
||||||
|
public DelayedInjectionRunnerValidator(RunNotifier notifier, TestClass testClass) {
|
||||||
|
this.notifier = notifier;
|
||||||
|
this.testClass = testClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void testFinished(Description description) throws Exception {
|
||||||
|
try {
|
||||||
|
Mockito.validateMockitoUsage();
|
||||||
|
if (!testClass.getAnnotatedFields(InjectMocks.class).isEmpty()) {
|
||||||
|
throw new IllegalStateException("Do not use @InjectMocks with the DelayedInjectionRunner:" +
|
||||||
|
" use @InjectDelayed or change runner");
|
||||||
|
}
|
||||||
|
} catch (Throwable t) {
|
||||||
|
notifier.fireTestFailure(new Failure(description, t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
104
src/test/java/fr/xephi/authme/runner/InjectionResolver.java
Normal file
104
src/test/java/fr/xephi/authme/runner/InjectionResolver.java
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
package fr.xephi.authme.runner;
|
||||||
|
|
||||||
|
import fr.xephi.authme.ReflectionTestUtils;
|
||||||
|
import fr.xephi.authme.initialization.Injection;
|
||||||
|
import fr.xephi.authme.initialization.InjectionHelper;
|
||||||
|
import org.junit.runners.model.FrameworkField;
|
||||||
|
import org.junit.runners.model.TestClass;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves the dependencies of an injection based on the provided {@link TestClass} and {@link #target target}.
|
||||||
|
*/
|
||||||
|
class InjectionResolver {
|
||||||
|
|
||||||
|
private final TestClass testClass;
|
||||||
|
private final Object target;
|
||||||
|
private final Map<Class<?>, Object> mocksByType;
|
||||||
|
|
||||||
|
public InjectionResolver(TestClass testClass, Object target) {
|
||||||
|
this.testClass = testClass;
|
||||||
|
this.target = target;
|
||||||
|
this.mocksByType = gatherAvailableMocks();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object instantiate(Injection<?> injection) {
|
||||||
|
Object[] dependencies = resolveDependencies(injection);
|
||||||
|
Object object = injection.instantiateWith(dependencies);
|
||||||
|
executePostConstructMethod(object);
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of all objects for the given list of dependencies, retrieved from the given
|
||||||
|
* target's {@link Mock} fields.
|
||||||
|
*
|
||||||
|
* @param injection the injection whose dependencies to gather
|
||||||
|
* @return the resolved dependencies
|
||||||
|
*/
|
||||||
|
private Object[] resolveDependencies(Injection<?> injection) {
|
||||||
|
final Class<?>[] dependencies = injection.getDependencies();
|
||||||
|
final Class<?>[] annotations = injection.getDependencyAnnotations();
|
||||||
|
Object[] resolvedValues = new Object[dependencies.length];
|
||||||
|
for (int i = 0; i < dependencies.length; ++i) {
|
||||||
|
Object dependency = (annotations[i] == null)
|
||||||
|
? resolveDependency(dependencies[i])
|
||||||
|
: resolveAnnotation(annotations[i]);
|
||||||
|
resolvedValues[i] = dependency;
|
||||||
|
}
|
||||||
|
return resolvedValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object resolveDependency(Class<?> clazz) {
|
||||||
|
Object o = mocksByType.get(clazz);
|
||||||
|
if (o == null) {
|
||||||
|
throw new IllegalStateException("No mock found for '" + clazz + "'. "
|
||||||
|
+ "All dependencies of @InjectDelayed must be provided as @Mock fields");
|
||||||
|
}
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object resolveAnnotation(Class<?> clazz) {
|
||||||
|
Class<? extends Annotation> annotation = (Class<? extends Annotation>) clazz;
|
||||||
|
List<FrameworkField> matches = testClass.getAnnotatedFields(annotation);
|
||||||
|
if (matches.isEmpty()) {
|
||||||
|
throw new IllegalStateException("No field found with @" + annotation.getSimpleName() + " in test class,"
|
||||||
|
+ "but a dependency in an @InjectDelayed field is using it");
|
||||||
|
} else if (matches.size() > 1) {
|
||||||
|
throw new IllegalStateException("You cannot have multiple fields with @" + annotation.getSimpleName());
|
||||||
|
}
|
||||||
|
return ReflectionTestUtils.getFieldValue(matches.get(0).getField(), target);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the class' PostConstruct method if available. Validates that all rules for
|
||||||
|
* {@link javax.annotation.PostConstruct} are met.
|
||||||
|
*
|
||||||
|
* @param object the object whose PostConstruct method should be run, if available
|
||||||
|
* @see InjectionHelper#getAndValidatePostConstructMethod
|
||||||
|
*/
|
||||||
|
private static void executePostConstructMethod(Object object) {
|
||||||
|
Method postConstructMethod = InjectionHelper.getAndValidatePostConstructMethod(object.getClass());
|
||||||
|
if (postConstructMethod != null) {
|
||||||
|
ReflectionTestUtils.invokeMethod(postConstructMethod, object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<Class<?>, Object> gatherAvailableMocks() {
|
||||||
|
List<FrameworkField> availableMocks = testClass.getAnnotatedFields(Mock.class);
|
||||||
|
Map<Class<?>, Object> mocksByType = new HashMap<>();
|
||||||
|
for (FrameworkField frameworkField : availableMocks) {
|
||||||
|
Field field = frameworkField.getField();
|
||||||
|
Object fieldValue = ReflectionTestUtils.getFieldValue(field, target);
|
||||||
|
mocksByType.put(field.getType(), fieldValue);
|
||||||
|
}
|
||||||
|
return mocksByType;
|
||||||
|
}
|
||||||
|
}
|
@ -1,36 +1,29 @@
|
|||||||
package fr.xephi.authme.runner;
|
package fr.xephi.authme.runner;
|
||||||
|
|
||||||
import fr.xephi.authme.ReflectionTestUtils;
|
|
||||||
import fr.xephi.authme.initialization.Injection;
|
import fr.xephi.authme.initialization.Injection;
|
||||||
import fr.xephi.authme.initialization.InjectionHelper;
|
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains all necessary information to initialize a {@link InjectDelayed} field.
|
* Contains an injection and the field it's for.
|
||||||
*/
|
*/
|
||||||
class PendingInjection {
|
class PendingInjection {
|
||||||
|
|
||||||
private Field field;
|
private final Field field;
|
||||||
private Object[] dependencies;
|
private final Injection<?> injection;
|
||||||
private Injection<?> injection;
|
|
||||||
|
|
||||||
public PendingInjection(Field field, Injection<?> injection, Object[] dependencies) {
|
public PendingInjection(Field field, Injection<?> injection) {
|
||||||
this.field = field;
|
this.field = field;
|
||||||
this.injection = injection;
|
this.injection = injection;
|
||||||
this.dependencies = dependencies;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs an object with the stored injection information.
|
* Returns the injection to perform.
|
||||||
*
|
*
|
||||||
* @return the constructed object
|
* @return the injection
|
||||||
*/
|
*/
|
||||||
public Object instantiate() {
|
public Injection<?> getInjection() {
|
||||||
Object object = injection.instantiateWith(dependencies);
|
return injection;
|
||||||
executePostConstructMethod(object);
|
|
||||||
return object;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -42,26 +35,4 @@ class PendingInjection {
|
|||||||
return field;
|
return field;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears all fields (avoids keeping a reference to all dependencies).
|
|
||||||
*/
|
|
||||||
public void clearFields() {
|
|
||||||
field = null;
|
|
||||||
dependencies = null;
|
|
||||||
injection = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes the class' PostConstruct method if available. Validates that all rules for
|
|
||||||
* {@link javax.annotation.PostConstruct} are met.
|
|
||||||
*
|
|
||||||
* @param object the object whose PostConstruct method should be run, if available
|
|
||||||
* @see InjectionHelper#getAndValidatePostConstructMethod
|
|
||||||
*/
|
|
||||||
private static void executePostConstructMethod(Object object) {
|
|
||||||
Method postConstructMethod = InjectionHelper.getAndValidatePostConstructMethod(object.getClass());
|
|
||||||
if (postConstructMethod != null) {
|
|
||||||
ReflectionTestUtils.invokeMethod(postConstructMethod, object);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -13,21 +13,28 @@ class RunDelayedInjects extends Statement {
|
|||||||
|
|
||||||
private final Statement next;
|
private final Statement next;
|
||||||
private final Object target;
|
private final Object target;
|
||||||
private final List<PendingInjection> pendingInjections;
|
private List<PendingInjection> pendingInjections;
|
||||||
|
private InjectionResolver injectionResolver;
|
||||||
|
|
||||||
public RunDelayedInjects(Statement next, List<PendingInjection> pendingInjections, Object target) {
|
public RunDelayedInjects(Statement next, List<PendingInjection> pendingInjections, Object target,
|
||||||
|
InjectionResolver injectionResolver) {
|
||||||
this.next = next;
|
this.next = next;
|
||||||
this.pendingInjections = pendingInjections;
|
this.pendingInjections = pendingInjections;
|
||||||
this.target = target;
|
this.target = target;
|
||||||
|
this.injectionResolver = injectionResolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void evaluate() throws Throwable {
|
public void evaluate() throws Throwable {
|
||||||
for (PendingInjection pendingInjection : pendingInjections) {
|
for (PendingInjection pendingInjection : pendingInjections) {
|
||||||
Object object = pendingInjection.instantiate();
|
if (ReflectionTestUtils.getFieldValue(pendingInjection.getField(), target) != null) {
|
||||||
|
throw new IllegalStateException("Field with @InjectDelayed must be null on startup");
|
||||||
|
}
|
||||||
|
Object object = injectionResolver.instantiate(pendingInjection.getInjection());
|
||||||
ReflectionTestUtils.setField(pendingInjection.getField(), target, object);
|
ReflectionTestUtils.setField(pendingInjection.getField(), target, object);
|
||||||
pendingInjection.clearFields();
|
|
||||||
}
|
}
|
||||||
|
this.pendingInjections = null;
|
||||||
|
this.injectionResolver = null;
|
||||||
next.evaluate();
|
next.evaluate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,14 +4,19 @@ import com.google.common.io.Files;
|
|||||||
import fr.xephi.authme.TestHelper;
|
import fr.xephi.authme.TestHelper;
|
||||||
import fr.xephi.authme.datasource.DataSource;
|
import fr.xephi.authme.datasource.DataSource;
|
||||||
import fr.xephi.authme.hooks.PluginHooks;
|
import fr.xephi.authme.hooks.PluginHooks;
|
||||||
|
import fr.xephi.authme.initialization.DataFolder;
|
||||||
|
import fr.xephi.authme.runner.BeforeInjecting;
|
||||||
|
import fr.xephi.authme.runner.DelayedInjectionRunner;
|
||||||
|
import fr.xephi.authme.runner.InjectDelayed;
|
||||||
import fr.xephi.authme.settings.properties.RestrictionSettings;
|
import fr.xephi.authme.settings.properties.RestrictionSettings;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.rules.TemporaryFolder;
|
import org.junit.rules.TemporaryFolder;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -24,15 +29,28 @@ import static org.mockito.Mockito.mock;
|
|||||||
/**
|
/**
|
||||||
* Test for {@link SpawnLoader}.
|
* Test for {@link SpawnLoader}.
|
||||||
*/
|
*/
|
||||||
|
@RunWith(DelayedInjectionRunner.class)
|
||||||
public class SpawnLoaderTest {
|
public class SpawnLoaderTest {
|
||||||
|
|
||||||
|
@InjectDelayed
|
||||||
|
private SpawnLoader spawnLoader;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private NewSetting settings;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private DataSource dataSource;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private PluginHooks pluginHooks;
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public TemporaryFolder temporaryFolder = new TemporaryFolder();
|
public TemporaryFolder temporaryFolder = new TemporaryFolder();
|
||||||
|
|
||||||
|
@DataFolder
|
||||||
private File testFolder;
|
private File testFolder;
|
||||||
private NewSetting settings;
|
|
||||||
|
|
||||||
@Before
|
@BeforeInjecting
|
||||||
public void setup() throws IOException {
|
public void setup() throws IOException {
|
||||||
// Copy test config into a new temporary folder
|
// Copy test config into a new temporary folder
|
||||||
testFolder = temporaryFolder.newFolder();
|
testFolder = temporaryFolder.newFolder();
|
||||||
@ -41,7 +59,6 @@ public class SpawnLoaderTest {
|
|||||||
Files.copy(source, destination);
|
Files.copy(source, destination);
|
||||||
|
|
||||||
// Create a settings mock with default values
|
// Create a settings mock with default values
|
||||||
settings = mock(NewSetting.class);
|
|
||||||
given(settings.getProperty(RestrictionSettings.SPAWN_PRIORITY))
|
given(settings.getProperty(RestrictionSettings.SPAWN_PRIORITY))
|
||||||
.willReturn("authme, essentials, multiverse, default");
|
.willReturn("authme, essentials, multiverse, default");
|
||||||
}
|
}
|
||||||
@ -49,8 +66,6 @@ public class SpawnLoaderTest {
|
|||||||
@Test
|
@Test
|
||||||
public void shouldSetSpawn() {
|
public void shouldSetSpawn() {
|
||||||
// given
|
// given
|
||||||
SpawnLoader spawnLoader =
|
|
||||||
new SpawnLoader(testFolder, settings, mock(PluginHooks.class), mock(DataSource.class));
|
|
||||||
World world = mock(World.class);
|
World world = mock(World.class);
|
||||||
given(world.getName()).willReturn("new_world");
|
given(world.getName()).willReturn("new_world");
|
||||||
Location newSpawn = new Location(world, 123, 45.0, -67.89);
|
Location newSpawn = new Location(world, 123, 45.0, -67.89);
|
||||||
|
Loading…
Reference in New Issue
Block a user