13
0
geforkt von Mirrors/Paper

#990: Use Mockito instead of InvocationHandler for test mocking

By: DerFrZocker <derrieple@gmail.com>
Dieser Commit ist enthalten in:
Bukkit/Spigot 2023-09-11 18:20:41 +10:00
Ursprung 085e8f6d9f
Commit e589401ea7
13 geänderte Dateien mit 113 neuen und 280 gelöschten Zeilen

Datei anzeigen

@ -97,6 +97,12 @@
<version>1.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.5.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-tree</artifactId>

Datei anzeigen

@ -1,6 +1,6 @@
package org.bukkit;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.*;
import java.util.Arrays;
import java.util.Collection;
import org.junit.Test;

Datei anzeigen

@ -2,6 +2,7 @@ package org.bukkit;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import com.google.common.collect.ImmutableList;
import java.util.List;
import java.util.Random;
@ -189,8 +190,10 @@ public class LocationTest {
return new Vector(x, y, z);
}
private static final World TEST_WORLD = mock();
private static Location getEmptyLocation() {
return new Location(TestWorld.INSTANCE, 0, 0, 0);
return new Location(TEST_WORLD, 0, 0, 0);
}
private Location getLocation() {

Datei anzeigen

@ -1,146 +0,0 @@
package org.bukkit;
import com.google.common.collect.ImmutableMap;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Iterator;
import java.util.Map;
import java.util.logging.Logger;
import java.util.stream.Stream;
import org.bukkit.command.SimpleCommandMap;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.SimplePluginManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public final class TestServer implements InvocationHandler {
private static interface MethodHandler {
Object handle(TestServer server, Object[] args);
}
private static final Map<Method, MethodHandler> methods;
static {
try {
ImmutableMap.Builder<Method, MethodHandler> methodMap = ImmutableMap.builder();
methodMap.put(
Server.class.getMethod("isPrimaryThread"),
new MethodHandler() {
@Override
public Object handle(TestServer server, Object[] args) {
return Thread.currentThread().equals(server.creatingThread);
}
}
);
methodMap.put(
Server.class.getMethod("getPluginManager"),
new MethodHandler() {
@Override
public Object handle(TestServer server, Object[] args) {
return server.pluginManager;
}
}
);
methodMap.put(
Server.class.getMethod("getLogger"),
new MethodHandler() {
final Logger logger = Logger.getLogger(TestServer.class.getCanonicalName());
@Override
public Object handle(TestServer server, Object[] args) {
return logger;
}
}
);
methodMap.put(
Server.class.getMethod("getName"),
new MethodHandler() {
@Override
public Object handle(TestServer server, Object[] args) {
return TestServer.class.getSimpleName();
}
}
);
methodMap.put(
Server.class.getMethod("getVersion"),
new MethodHandler() {
@Override
public Object handle(TestServer server, Object[] args) {
return "Version_" + TestServer.class.getPackage().getImplementationVersion();
}
}
);
methodMap.put(
Server.class.getMethod("getBukkitVersion"),
new MethodHandler() {
@Override
public Object handle(TestServer server, Object[] args) {
return "BukkitVersion_" + TestServer.class.getPackage().getImplementationVersion();
}
}
);
methodMap.put(
Server.class.getMethod("getRegistry", Class.class),
new MethodHandler() {
@Override
public Object handle(TestServer server, Object[] args) {
return new Registry() {
@NotNull
@Override
public Iterator iterator() {
throw new UnsupportedOperationException();
}
@Nullable
@Override
public Keyed get(@NotNull NamespacedKey key) {
return null;
}
@NotNull
@Override
public Stream stream() {
throw new UnsupportedOperationException();
}
};
}
}
);
methodMap.put(
Server.class.getMethod("getScoreboardCriteria", String.class),
new MethodHandler() {
@Override
public Object handle(TestServer server, Object[] args) {
// Does not need to return anything. Exists solely to test CriteriaTest which has static init fields
return null;
}
}
);
methods = methodMap.build();
TestServer server = new TestServer();
Server instance = Proxy.getProxyClass(Server.class.getClassLoader(), Server.class).asSubclass(Server.class).getConstructor(InvocationHandler.class).newInstance(server);
Bukkit.setServer(instance);
server.pluginManager = new SimplePluginManager(instance, new SimpleCommandMap(instance));
} catch (Throwable t) {
throw new Error(t);
}
}
private Thread creatingThread = Thread.currentThread();
private PluginManager pluginManager;
private TestServer() {};
public static Server getInstance() {
return Bukkit.getServer();
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) {
MethodHandler handler = methods.get(method);
if (handler != null) {
return handler.handle(this, args);
}
throw new UnsupportedOperationException(String.valueOf(method));
}
}

Datei anzeigen

@ -1,66 +0,0 @@
package org.bukkit;
import com.google.common.collect.ImmutableMap;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map;
public final class TestWorld implements InvocationHandler {
private static interface MethodHandler {
Object handle(TestWorld server, Object[] args);
}
private static final Map<Method, MethodHandler> methods;
public static final World INSTANCE;
static {
try {
TestServer.getInstance();
ImmutableMap.Builder<Method, MethodHandler> methodMap = ImmutableMap.builder();
methodMap.put(
Object.class.getMethod("equals", Object.class),
new MethodHandler() {
@Override
public Object handle(TestWorld server, Object[] args) {
return this == args[0];
}
}
);
methodMap.put(
Object.class.getMethod("hashCode"),
new MethodHandler() {
@Override
public Object handle(TestWorld server, Object[] args) {
return this.hashCode();
}
}
);
methods = methodMap.build();
TestWorld world = new TestWorld();
INSTANCE = Proxy.getProxyClass(World.class.getClassLoader(), World.class).asSubclass(World.class).getConstructor(InvocationHandler.class).newInstance(world);
} catch (Throwable t) {
throw new Error(t);
}
}
private TestWorld() {
}
public static Server getInstance() {
return Bukkit.getServer();
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) {
MethodHandler handler = methods.get(method);
if (handler != null) {
return handler.handle(this, args);
}
throw new UnsupportedOperationException(String.valueOf(method));
}
}

Datei anzeigen

@ -2,9 +2,9 @@ package org.bukkit.event;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import com.google.common.collect.ImmutableList;
import org.bukkit.event.player.PlayerChatTabCompleteEvent;
import org.bukkit.plugin.messaging.TestPlayer;
import org.junit.Test;
public class PlayerChatTabCompleteEventTest {
@ -21,6 +21,6 @@ public class PlayerChatTabCompleteEventTest {
}
private String getToken(String message) {
return new PlayerChatTabCompleteEvent(TestPlayer.getInstance(), message, ImmutableList.<String>of()).getLastToken();
return new PlayerChatTabCompleteEvent(mock(), message, ImmutableList.<String>of()).getLastToken();
}
}

Datei anzeigen

@ -1,25 +1,26 @@
package org.bukkit.event;
import org.bukkit.TestServer;
import org.bukkit.Bukkit;
import org.bukkit.plugin.PluginLoader;
import org.bukkit.plugin.SimplePluginManager;
import org.bukkit.plugin.TestPlugin;
import org.bukkit.plugin.java.JavaPluginLoader;
import org.bukkit.support.AbstractTestingBase;
import org.junit.Assert;
import org.junit.Test;
public class SyntheticEventTest {
public class SyntheticEventTest extends AbstractTestingBase {
@SuppressWarnings("deprecation")
@Test
public void test() {
final JavaPluginLoader loader = new JavaPluginLoader(TestServer.getInstance());
final JavaPluginLoader loader = new JavaPluginLoader(Bukkit.getServer());
TestPlugin plugin = new TestPlugin(getClass().getName()) {
@Override
public PluginLoader getPluginLoader() {
return loader;
}
};
SimplePluginManager pluginManager = new SimplePluginManager(TestServer.getInstance(), null);
SimplePluginManager pluginManager = new SimplePluginManager(Bukkit.getServer(), null);
TestEvent event = new TestEvent(false);
Impl impl = new Impl();

Datei anzeigen

@ -2,19 +2,20 @@ package org.bukkit.plugin;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import org.bukkit.TestServer;
import org.bukkit.Bukkit;
import org.bukkit.event.Event;
import org.bukkit.event.TestEvent;
import org.bukkit.permissions.Permission;
import org.bukkit.support.AbstractTestingBase;
import org.junit.After;
import org.junit.Test;
public class PluginManagerTest {
public class PluginManagerTest extends AbstractTestingBase {
private class MutableObject {
volatile Object value = null;
}
private static final PluginManager pm = TestServer.getInstance().getPluginManager();
private static final PluginManager pm = Bukkit.getServer().getPluginManager();
private final MutableObject store = new MutableObject();

Datei anzeigen

@ -2,6 +2,7 @@ package org.bukkit.plugin.messaging;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import java.util.Collection;
import org.bukkit.entity.Player;
import org.bukkit.plugin.TestPlugin;
@ -73,7 +74,7 @@ public class StandardMessengerTest {
Messenger messenger = getMessenger();
TestPlugin plugin = getPlugin();
TestMessageListener listener = new TestMessageListener("test:foo", "test:bar".getBytes());
Player player = TestPlayer.getInstance();
Player player = mock();
PluginMessageListenerRegistration registration = messenger.registerIncomingPluginChannel(plugin, "test:foo", listener);
assertTrue(registration.isValid());
@ -114,7 +115,7 @@ public class StandardMessengerTest {
TestPlugin plugin = getPlugin();
TestMessageListener listener1 = new TestMessageListener("test:foo", "test:bar".getBytes());
TestMessageListener listener2 = new TestMessageListener("test:baz", "test:qux".getBytes());
Player player = TestPlayer.getInstance();
Player player = mock();
PluginMessageListenerRegistration registration1 = messenger.registerIncomingPluginChannel(plugin, "test:foo", listener1);
PluginMessageListenerRegistration registration2 = messenger.registerIncomingPluginChannel(plugin, "test:baz", listener2);
@ -143,7 +144,7 @@ public class StandardMessengerTest {
TestPlugin plugin = getPlugin();
TestMessageListener listener1 = new TestMessageListener("test:foo", "test:bar".getBytes());
TestMessageListener listener2 = new TestMessageListener("test:baz", "test:qux".getBytes());
Player player = TestPlayer.getInstance();
Player player = mock();
PluginMessageListenerRegistration registration1 = messenger.registerIncomingPluginChannel(plugin, "test:foo", listener1);
PluginMessageListenerRegistration registration2 = messenger.registerIncomingPluginChannel(plugin, "test:baz", listener2);

Datei anzeigen

@ -1,50 +0,0 @@
package org.bukkit.plugin.messaging;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import org.bukkit.entity.Player;
public final class TestPlayer implements InvocationHandler {
private static interface MethodHandler {
Object handle(TestPlayer server, Object[] args);
}
private static final Constructor<? extends Player> constructor;
private static final HashMap<Method, MethodHandler> methods = new HashMap<Method, MethodHandler>();
static {
try {
/*
methods.put(Player.class.getMethod("methodName"),
new MethodHandler() {
public Object handle(TestPlayer server, Object[] args) {
}
});
*/
constructor = Proxy.getProxyClass(Player.class.getClassLoader(), Player.class).asSubclass(Player.class).getConstructor(InvocationHandler.class);
} catch (Throwable t) {
throw new Error(t);
}
}
private TestPlayer() {};
public static Player getInstance() {
try {
return constructor.newInstance(new TestPlayer());
} catch (Throwable t) {
throw new RuntimeException(t);
}
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) {
MethodHandler handler = methods.get(method);
if (handler != null) {
return handler.handle(this, args);
}
throw new UnsupportedOperationException(String.valueOf(method));
}
}

Datei anzeigen

@ -2,17 +2,15 @@ package org.bukkit.scoreboard;
import org.bukkit.Material;
import org.bukkit.Statistic;
import org.bukkit.TestServer;
import org.bukkit.entity.EntityType;
import org.bukkit.support.AbstractTestingBase;
import org.junit.Assert;
import org.junit.Test;
public class CriteriaTest {
public class CriteriaTest extends AbstractTestingBase {
@Test
public void testStatistic() {
TestServer.getInstance();
Assert.assertThrows(IllegalArgumentException.class, () -> Criteria.statistic(Statistic.AVIATE_ONE_CM, Material.STONE)); // Generic statistic with block
Assert.assertThrows(IllegalArgumentException.class, () -> Criteria.statistic(Statistic.AVIATE_ONE_CM, EntityType.CREEPER)); // Generic statistic with entity type

Datei anzeigen

@ -0,0 +1,13 @@
package org.bukkit.support;
/**
* If you are getting: java.lang.ExceptionInInitializerError
*
* extend this class to solve it.
*/
public abstract class AbstractTestingBase {
static {
TestServer.setup();
}
}

Datei anzeigen

@ -0,0 +1,72 @@
package org.bukkit.support;
import static org.mockito.Mockito.*;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.logging.Logger;
import java.util.stream.Stream;
import org.bukkit.Bukkit;
import org.bukkit.Keyed;
import org.bukkit.NamespacedKey;
import org.bukkit.Registry;
import org.bukkit.Server;
import org.bukkit.UnsafeValues;
import org.bukkit.command.SimpleCommandMap;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.SimplePluginManager;
import org.jetbrains.annotations.NotNull;
public final class TestServer {
static {
Server instance = mock(withSettings().stubOnly());
Thread creatingThread = Thread.currentThread();
when(instance.isPrimaryThread()).then(mock -> Thread.currentThread().equals(creatingThread));
PluginManager pluginManager = new SimplePluginManager(instance, new SimpleCommandMap(instance));
when(instance.getPluginManager()).thenReturn(pluginManager);
Logger logger = Logger.getLogger(TestServer.class.getCanonicalName());
when(instance.getLogger()).thenReturn(logger);
when(instance.getName()).thenReturn(TestServer.class.getSimpleName());
when(instance.getVersion()).thenReturn("Version_" + TestServer.class.getPackage().getImplementationVersion());
when(instance.getBukkitVersion()).thenReturn("BukkitVersion_" + TestServer.class.getPackage().getImplementationVersion());
Map<Class<? extends Keyed>, Registry<?>> registers = new HashMap<>();
when(instance.getRegistry(any())).then(invocationOnMock -> registers.computeIfAbsent(invocationOnMock.getArgument(0), aClass -> new Registry<Keyed>() {
private final Map<NamespacedKey, Keyed> cache = new HashMap<>();
@Override
public Keyed get(NamespacedKey key) {
return cache.computeIfAbsent(key, key2 -> mock(aClass, withSettings().stubOnly()));
}
@NotNull
@Override
public Stream<Keyed> stream() {
throw new UnsupportedOperationException("Not supported");
}
@Override
public Iterator<Keyed> iterator() {
throw new UnsupportedOperationException("Not supported");
}
}));
UnsafeValues unsafeValues = mock(withSettings().stubOnly());
when(instance.getUnsafe()).thenReturn(unsafeValues);
Bukkit.setServer(instance);
}
private TestServer() {
}
public static void setup() {
}
}