diff --git a/build.gradle.kts b/build.gradle.kts index faed50c617..22dca7fb3f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -38,6 +38,8 @@ subprojects { exceptionFormat = TestExceptionFormat.FULL events(TestLogEvent.STANDARD_OUT) } + minHeapSize = "2g" + maxHeapSize = "2g" } repositories { diff --git a/patches/api/Add-Material-Tags.patch b/patches/api/Add-Material-Tags.patch index 5045aa6216..0d8e06e287 100644 --- a/patches/api/Add-Material-Tags.patch +++ b/patches/api/Add-Material-Tags.patch @@ -1146,8 +1146,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + +import io.papermc.paper.tag.BaseTag; +import io.papermc.paper.tag.EntityTags; ++import io.papermc.paper.testing.TestServer; +import org.bukkit.Bukkit; -+import org.bukkit.TestServer; +import org.junit.Before; +import org.junit.Test; + @@ -1163,7 +1163,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + + @Before + public void before() { -+ TestServer.getInstance(); ++ TestServer.setup(); + } + + @Test @@ -1211,20 +1211,18 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ +package io.papermc.paper; + -+import com.destroystokyo.paper.MaterialTags; +import io.papermc.paper.tag.EntityTags; -+import org.bukkit.Bukkit; -+import org.bukkit.TestServer; -+import org.junit.Test; -+ ++import io.papermc.paper.testing.TestServer; +import java.util.logging.Level; ++import org.bukkit.Bukkit; ++import org.junit.Test; + +public class EntityTagsTest { + + @Test + public void testInitialize() { + try { -+ TestServer.getInstance(); ++ TestServer.setup(); + EntityTags.HORSES.getValues(); + assert true; + } catch (Throwable e) { @@ -1233,24 +1231,3 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + } +} -diff --git a/src/test/java/org/bukkit/TestServer.java b/src/test/java/org/bukkit/TestServer.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/test/java/org/bukkit/TestServer.java -+++ b/src/test/java/org/bukkit/TestServer.java -@@ -0,0 +0,0 @@ public final class TestServer implements InvocationHandler { - } - } - ); -+ // Paper start -+ methodMap.put( -+ Server.class.getMethod("getTag", String.class, NamespacedKey.class, Class.class), -+ new MethodHandler() { -+ public Object handle(TestServer server, Object[] args) { -+ return new com.destroystokyo.paper.MaterialSetTag(); -+ } -+ } -+ ); -+ // Paper end - methodMap.put( - Server.class.getMethod("getPluginManager"), - new MethodHandler() { diff --git a/patches/api/Annotation-Test-changes.patch b/patches/api/Annotation-Test-changes.patch deleted file mode 100644 index c063fdab0d..0000000000 --- a/patches/api/Annotation-Test-changes.patch +++ /dev/null @@ -1,114 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shane Freeder <theboyetronic@gmail.com> -Date: Sun, 17 Mar 2019 23:04:30 +0000 -Subject: [PATCH] Annotation Test changes - -- Allow use of TYPE_USE annotations -- Ignore package-private methods for nullability annotations -- Add excludes for classes which don't pass - -diff --git a/src/test/java/org/bukkit/AnnotationTest.java b/src/test/java/org/bukkit/AnnotationTest.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/test/java/org/bukkit/AnnotationTest.java -+++ b/src/test/java/org/bukkit/AnnotationTest.java -@@ -0,0 +0,0 @@ public class AnnotationTest { - "org/bukkit/util/io/Wrapper", - "org/bukkit/plugin/java/PluginClassLoader", - // Generic functional interface -- "org/bukkit/util/Consumer" -+ "org/bukkit/util/Consumer", -+ // Paper start -+ // Timings history is broken in terms of nullability due to guavas Function defining that the param is NonNull -+ "co/aikar/timings/TimingHistory$2", -+ "co/aikar/timings/TimingHistory$2$1", -+ "co/aikar/timings/TimingHistory$2$1$1", -+ "co/aikar/timings/TimingHistory$2$1$2", -+ "co/aikar/timings/TimingHistory$3", -+ "co/aikar/timings/TimingHistory$4", -+ "co/aikar/timings/TimingHistoryEntry$1" -+ // Paper end - }; - - @Test -@@ -0,0 +0,0 @@ public class AnnotationTest { - } - - if (mustBeAnnotated(Type.getReturnType(method.desc)) && !isWellAnnotated(method.invisibleAnnotations)) { -+ // Paper start - Allow use of TYPE_USE annotations -+ boolean warn = true; -+ if (isWellAnnotated(method.visibleTypeAnnotations)) { -+ warn = false; -+ } else if (method.invisibleTypeAnnotations != null) { -+ dance: for (final org.objectweb.asm.tree.TypeAnnotationNode invisibleTypeAnnotation : method.invisibleTypeAnnotations) { -+ final org.objectweb.asm.TypeReference ref = new org.objectweb.asm.TypeReference(invisibleTypeAnnotation.typeRef); -+ if (ref.getSort() == org.objectweb.asm.TypeReference.METHOD_RETURN && java.util.Arrays.binarySearch(ACCEPTED_ANNOTATIONS, invisibleTypeAnnotation.desc) >= 0) { -+ warn = false; -+ break dance; // cha cha real smooth -+ } -+ } -+ } -+ if (warn) -+ // Paper end - warn(errors, clazz, method, "return value"); - } - - Type[] paramTypes = Type.getArgumentTypes(method.desc); - List<ParameterNode> parameters = method.parameters; - -+ dancing: // Paper - for (int i = 0; i < paramTypes.length; i++) { - if (mustBeAnnotated(paramTypes[i]) ^ isWellAnnotated(method.invisibleParameterAnnotations == null ? null : method.invisibleParameterAnnotations[i])) { -+ // Paper start -+ if (method.invisibleTypeAnnotations != null) { -+ for (final org.objectweb.asm.tree.TypeAnnotationNode invisibleTypeAnnotation : method.invisibleTypeAnnotations) { -+ final org.objectweb.asm.TypeReference ref = new org.objectweb.asm.TypeReference(invisibleTypeAnnotation.typeRef); -+ if (ref.getSort() == org.objectweb.asm.TypeReference.METHOD_FORMAL_PARAMETER && ref.getTypeParameterIndex() == i && java.util.Arrays.binarySearch(ACCEPTED_ANNOTATIONS, invisibleTypeAnnotation.desc) >= 0) { -+ continue dancing; -+ } -+ } -+ } -+ // Paper end - Allow use of TYPE_USE annotations - ParameterNode paramNode = parameters == null ? null : parameters.get(i); - String paramName = paramNode == null ? null : paramNode.name; - -@@ -0,0 +0,0 @@ public class AnnotationTest { - - Collections.sort(errors); - -- System.out.println(errors.size() + " missing annotation(s):"); -+ StringBuilder builder = new StringBuilder() -+ .append("There ") -+ .append(errors.size() != 1 ? "are " : "is ") -+ .append(errors.size()) -+ .append(" missing annotation") -+ .append(errors.size() != 1 ? "s:\n" : ":\n"); -+ - for (String message : errors) { -- System.out.print("\t"); -- System.out.println(message); -+ builder.append("\t").append(message).append("\n"); - } - -- Assert.fail("There " + errors.size() + " are missing annotation(s)"); -+ Assert.fail(builder.toString()); - } - - private static void collectClasses(@NotNull File from, @NotNull Map<String, ClassNode> to) throws IOException { -@@ -0,0 +0,0 @@ public class AnnotationTest { - - private static boolean isMethodIncluded(@NotNull ClassNode clazz, @NotNull MethodNode method, @NotNull Map<String, ClassNode> allClasses) { - // Exclude private, synthetic and deprecated methods -- if ((method.access & (Opcodes.ACC_PRIVATE | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_DEPRECATED)) != 0) { -+ if ((method.access & (Opcodes.ACC_PRIVATE | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_DEPRECATED)) != 0 || (method.access & (Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED | Opcodes.ACC_PUBLIC)) == 0) { // Paper - ignore package-private - return false; - } - -@@ -0,0 +0,0 @@ public class AnnotationTest { - return true; - } - -- private static boolean isWellAnnotated(@Nullable List<AnnotationNode> annotations) { -+ private static boolean isWellAnnotated(@Nullable List<? extends AnnotationNode> annotations) { // Paper - if (annotations == null) { - return false; - } diff --git a/patches/api/Remove-deadlock-risk-in-firing-async-events.patch b/patches/api/Remove-deadlock-risk-in-firing-async-events.patch index 5577144752..b41013e8f4 100644 --- a/patches/api/Remove-deadlock-risk-in-firing-async-events.patch +++ b/patches/api/Remove-deadlock-risk-in-firing-async-events.patch @@ -88,7 +88,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/test/java/org/bukkit/plugin/PluginManagerTest.java +++ b/src/test/java/org/bukkit/plugin/PluginManagerTest.java @@ -0,0 +0,0 @@ public class PluginManagerTest { - private static final PluginManager pm = TestServer.getInstance().getPluginManager(); + private static final PluginManager pm = org.bukkit.Bukkit.getServer().getPluginManager(); // Paper private final MutableObject store = new MutableObject(); - diff --git a/patches/api/Test-changes.patch b/patches/api/Test-changes.patch new file mode 100644 index 0000000000..b7039e17b4 --- /dev/null +++ b/patches/api/Test-changes.patch @@ -0,0 +1,478 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Shane Freeder <theboyetronic@gmail.com> +Date: Sun, 17 Mar 2019 23:04:30 +0000 +Subject: [PATCH] Test changes + +- convert to mockito for mocking of types +- Allow use of TYPE_USE annotations +- Ignore package-private methods for nullability annotations +- Add excludes for classes which don't pass + +Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com> + +diff --git a/build.gradle.kts b/build.gradle.kts +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/build.gradle.kts ++++ b/build.gradle.kts +@@ -0,0 +0,0 @@ dependencies { + compileOnlyApi(checkerQual) + testCompileOnly(checkerQual) + // Paper end ++ testImplementation("org.mockito:mockito-core:4.9.0") // Paper - add mockito + + testImplementation("org.apache.commons:commons-lang3:3.12.0") + testImplementation("junit:junit:4.13.2") +diff --git a/src/test/java/io/papermc/paper/testing/EmptyRegistry.java b/src/test/java/io/papermc/paper/testing/EmptyRegistry.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/test/java/io/papermc/paper/testing/EmptyRegistry.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.testing; ++ ++import java.util.Collections; ++import java.util.Iterator; ++import org.bukkit.Keyed; ++import org.bukkit.NamespacedKey; ++import org.bukkit.Registry; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++public record EmptyRegistry() implements Registry<Keyed> { ++ ++ @NotNull ++ @Override ++ public Iterator<Keyed> iterator() { ++ return Collections.emptyIterator(); ++ } ++ ++ @Override ++ public @Nullable Keyed get(@NotNull final NamespacedKey key) { ++ return null; ++ } ++} +diff --git a/src/test/java/io/papermc/paper/testing/EmptyTag.java b/src/test/java/io/papermc/paper/testing/EmptyTag.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/test/java/io/papermc/paper/testing/EmptyTag.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.testing; ++ ++import java.util.Collections; ++import java.util.Set; ++import org.bukkit.Keyed; ++import org.bukkit.NamespacedKey; ++import org.bukkit.Tag; ++import org.jetbrains.annotations.NotNull; ++ ++public record EmptyTag(NamespacedKey key) implements Tag<Keyed> { ++ ++ @SuppressWarnings("deprecation") ++ public EmptyTag() { ++ this(NamespacedKey.randomKey()); ++ } ++ ++ @Override ++ public @NotNull NamespacedKey getKey() { ++ return this.key; ++ } ++ ++ @Override ++ public boolean isTagged(@NotNull final Keyed item) { ++ return false; ++ } ++ ++ @Override ++ public @NotNull Set<Keyed> getValues() { ++ return Collections.emptySet(); ++ } ++} +diff --git a/src/test/java/io/papermc/paper/testing/TestServer.java b/src/test/java/io/papermc/paper/testing/TestServer.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/test/java/io/papermc/paper/testing/TestServer.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.testing; ++ ++import java.util.logging.Logger; ++import org.bukkit.Bukkit; ++import org.bukkit.NamespacedKey; ++import org.bukkit.Server; ++import org.bukkit.command.SimpleCommandMap; ++import org.bukkit.plugin.PluginManager; ++import org.bukkit.plugin.SimplePluginManager; ++ ++import static org.mockito.ArgumentMatchers.anyString; ++import static org.mockito.Mockito.any; ++import static org.mockito.Mockito.mock; ++import static org.mockito.Mockito.when; ++ ++public final class TestServer { ++ ++ @SuppressWarnings("removal") ++ public static void setup() { ++ //noinspection ConstantValue ++ if (Bukkit.getServer() != null) { ++ return; ++ } ++ ++ final Server dummyServer = mock(Server.class); ++ ++ final Logger logger = Logger.getLogger(TestServer.class.getCanonicalName()); ++ when(dummyServer.getLogger()).thenReturn(logger); ++ when(dummyServer.getName()).thenReturn(TestServer.class.getSimpleName()); ++ when(dummyServer.getVersion()).thenReturn("Version_" + TestServer.class.getPackage().getImplementationVersion()); ++ when(dummyServer.getBukkitVersion()).thenReturn("BukkitVersion_" + TestServer.class.getPackage().getImplementationVersion()); ++ ++ ++ final Thread currentThread = Thread.currentThread(); ++ when(dummyServer.isPrimaryThread()).thenAnswer(ignored -> Thread.currentThread().equals(currentThread)); ++ ++ when(dummyServer.getTag(anyString(), any(NamespacedKey.class), any())).thenAnswer(ignored -> new EmptyTag()); ++ ++ final PluginManager pluginManager = new SimplePluginManager(dummyServer, new SimpleCommandMap(dummyServer)); ++ when(dummyServer.getPluginManager()).thenReturn(pluginManager); ++ ++ when(dummyServer.getRegistry(any())).thenAnswer(ignored -> new EmptyRegistry()); ++ when(dummyServer.getScoreboardCriteria(anyString())).thenReturn(null); ++ ++ Bukkit.setServer(dummyServer); ++ } ++ ++} +diff --git a/src/test/java/org/bukkit/AnnotationTest.java b/src/test/java/org/bukkit/AnnotationTest.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/test/java/org/bukkit/AnnotationTest.java ++++ b/src/test/java/org/bukkit/AnnotationTest.java +@@ -0,0 +0,0 @@ public class AnnotationTest { + "org/bukkit/util/io/Wrapper", + "org/bukkit/plugin/java/PluginClassLoader", + // Generic functional interface +- "org/bukkit/util/Consumer" ++ "org/bukkit/util/Consumer", ++ // Paper start ++ // Timings history is broken in terms of nullability due to guavas Function defining that the param is NonNull ++ "co/aikar/timings/TimingHistory$2", ++ "co/aikar/timings/TimingHistory$2$1", ++ "co/aikar/timings/TimingHistory$2$1$1", ++ "co/aikar/timings/TimingHistory$2$1$2", ++ "co/aikar/timings/TimingHistory$3", ++ "co/aikar/timings/TimingHistory$4", ++ "co/aikar/timings/TimingHistoryEntry$1" ++ // Paper end + }; + + @Test +@@ -0,0 +0,0 @@ public class AnnotationTest { + } + + if (mustBeAnnotated(Type.getReturnType(method.desc)) && !isWellAnnotated(method.invisibleAnnotations)) { ++ // Paper start - Allow use of TYPE_USE annotations ++ boolean warn = true; ++ if (isWellAnnotated(method.visibleTypeAnnotations)) { ++ warn = false; ++ } else if (method.invisibleTypeAnnotations != null) { ++ dance: for (final org.objectweb.asm.tree.TypeAnnotationNode invisibleTypeAnnotation : method.invisibleTypeAnnotations) { ++ final org.objectweb.asm.TypeReference ref = new org.objectweb.asm.TypeReference(invisibleTypeAnnotation.typeRef); ++ if (ref.getSort() == org.objectweb.asm.TypeReference.METHOD_RETURN && java.util.Arrays.binarySearch(ACCEPTED_ANNOTATIONS, invisibleTypeAnnotation.desc) >= 0) { ++ warn = false; ++ break dance; // cha cha real smooth ++ } ++ } ++ } ++ if (warn) ++ // Paper end + warn(errors, clazz, method, "return value"); + } + + Type[] paramTypes = Type.getArgumentTypes(method.desc); + List<ParameterNode> parameters = method.parameters; + ++ dancing: // Paper + for (int i = 0; i < paramTypes.length; i++) { + if (mustBeAnnotated(paramTypes[i]) ^ isWellAnnotated(method.invisibleParameterAnnotations == null ? null : method.invisibleParameterAnnotations[i])) { ++ // Paper start ++ if (method.invisibleTypeAnnotations != null) { ++ for (final org.objectweb.asm.tree.TypeAnnotationNode invisibleTypeAnnotation : method.invisibleTypeAnnotations) { ++ final org.objectweb.asm.TypeReference ref = new org.objectweb.asm.TypeReference(invisibleTypeAnnotation.typeRef); ++ if (ref.getSort() == org.objectweb.asm.TypeReference.METHOD_FORMAL_PARAMETER && ref.getTypeParameterIndex() == i && java.util.Arrays.binarySearch(ACCEPTED_ANNOTATIONS, invisibleTypeAnnotation.desc) >= 0) { ++ continue dancing; ++ } ++ } ++ } ++ // Paper end - Allow use of TYPE_USE annotations + ParameterNode paramNode = parameters == null ? null : parameters.get(i); + String paramName = paramNode == null ? null : paramNode.name; + +@@ -0,0 +0,0 @@ public class AnnotationTest { + + Collections.sort(errors); + +- System.out.println(errors.size() + " missing annotation(s):"); ++ StringBuilder builder = new StringBuilder() ++ .append("There ") ++ .append(errors.size() != 1 ? "are " : "is ") ++ .append(errors.size()) ++ .append(" missing annotation") ++ .append(errors.size() != 1 ? "s:\n" : ":\n"); ++ + for (String message : errors) { +- System.out.print("\t"); +- System.out.println(message); ++ builder.append("\t").append(message).append("\n"); + } + +- Assert.fail("There " + errors.size() + " are missing annotation(s)"); ++ Assert.fail(builder.toString()); + } + + private static void collectClasses(@NotNull File from, @NotNull Map<String, ClassNode> to) throws IOException { +@@ -0,0 +0,0 @@ public class AnnotationTest { + + private static boolean isMethodIncluded(@NotNull ClassNode clazz, @NotNull MethodNode method, @NotNull Map<String, ClassNode> allClasses) { + // Exclude private, synthetic and deprecated methods +- if ((method.access & (Opcodes.ACC_PRIVATE | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_DEPRECATED)) != 0) { ++ if ((method.access & (Opcodes.ACC_PRIVATE | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_DEPRECATED)) != 0 || (method.access & (Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED | Opcodes.ACC_PUBLIC)) == 0) { // Paper - ignore package-private + return false; + } + +@@ -0,0 +0,0 @@ public class AnnotationTest { + return true; + } + +- private static boolean isWellAnnotated(@Nullable List<AnnotationNode> annotations) { ++ private static boolean isWellAnnotated(@Nullable List<? extends AnnotationNode> annotations) { // Paper + if (annotations == null) { + return false; + } +diff --git a/src/test/java/org/bukkit/TestServer.java b/src/test/java/org/bukkit/TestServer.java +deleted file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- a/src/test/java/org/bukkit/TestServer.java ++++ /dev/null +@@ -0,0 +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 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() { +- return null; +- } +- +- @Nullable +- @Override +- public Keyed get(@NotNull NamespacedKey key) { +- return null; +- } +- }; +- } +- } +- ); +- 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)); +- } +-} +diff --git a/src/test/java/org/bukkit/TestWorld.java b/src/test/java/org/bukkit/TestWorld.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/test/java/org/bukkit/TestWorld.java ++++ b/src/test/java/org/bukkit/TestWorld.java +@@ -0,0 +0,0 @@ public final class TestWorld implements InvocationHandler { + + static { + try { +- TestServer.getInstance(); ++ io.papermc.paper.testing.TestServer.setup(); // Paper + + ImmutableMap.Builder<Method, MethodHandler> methodMap = ImmutableMap.builder(); + methodMap.put( +diff --git a/src/test/java/org/bukkit/event/SyntheticEventTest.java b/src/test/java/org/bukkit/event/SyntheticEventTest.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/test/java/org/bukkit/event/SyntheticEventTest.java ++++ b/src/test/java/org/bukkit/event/SyntheticEventTest.java +@@ -0,0 +0,0 @@ + package org.bukkit.event; + +-import org.bukkit.TestServer; + import org.bukkit.plugin.PluginLoader; + import org.bukkit.plugin.SimplePluginManager; + import org.bukkit.plugin.TestPlugin; +@@ -0,0 +0,0 @@ public class SyntheticEventTest { + @SuppressWarnings("deprecation") + @Test + public void test() { +- final JavaPluginLoader loader = new JavaPluginLoader(TestServer.getInstance()); ++ io.papermc.paper.testing.TestServer.setup(); // Paper ++ final JavaPluginLoader loader = new JavaPluginLoader(org.bukkit.Bukkit.getServer()); // Paper + TestPlugin plugin = new TestPlugin(getClass().getName()) { + @Override + public PluginLoader getPluginLoader() { + return loader; + } + }; +- SimplePluginManager pluginManager = new SimplePluginManager(TestServer.getInstance(), null); ++ SimplePluginManager pluginManager = new SimplePluginManager(org.bukkit.Bukkit.getServer(), null); // Paper + + TestEvent event = new TestEvent(false); + Impl impl = new Impl(); +diff --git a/src/test/java/org/bukkit/plugin/PluginManagerTest.java b/src/test/java/org/bukkit/plugin/PluginManagerTest.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/test/java/org/bukkit/plugin/PluginManagerTest.java ++++ b/src/test/java/org/bukkit/plugin/PluginManagerTest.java +@@ -0,0 +0,0 @@ package org.bukkit.plugin; + + import static org.hamcrest.Matchers.*; + import static org.junit.Assert.*; +-import org.bukkit.TestServer; + import org.bukkit.event.Event; + import org.bukkit.event.TestEvent; + import org.bukkit.permissions.Permission; +@@ -0,0 +0,0 @@ public class PluginManagerTest { + volatile Object value = null; + } + +- private static final PluginManager pm = TestServer.getInstance().getPluginManager(); ++ private static final PluginManager pm = org.bukkit.Bukkit.getServer().getPluginManager(); // Paper + + private final MutableObject store = new MutableObject(); + +diff --git a/src/test/java/org/bukkit/scoreboard/CriteriaTest.java b/src/test/java/org/bukkit/scoreboard/CriteriaTest.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/test/java/org/bukkit/scoreboard/CriteriaTest.java ++++ b/src/test/java/org/bukkit/scoreboard/CriteriaTest.java +@@ -0,0 +0,0 @@ package org.bukkit.scoreboard; + + import org.bukkit.Material; + import org.bukkit.Statistic; +-import org.bukkit.TestServer; + import org.bukkit.entity.EntityType; + import org.junit.Assert; + import org.junit.Test; +@@ -0,0 +0,0 @@ public class CriteriaTest { + + @Test + public void testStatistic() { +- TestServer.getInstance(); ++ io.papermc.paper.testing.TestServer.setup(); // Paper + + 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 diff --git a/patches/server/Added-missing-default-perms-for-commands.patch b/patches/server/Added-missing-default-perms-for-commands.patch index d8cb1b19d9..f76c09264e 100644 --- a/patches/server/Added-missing-default-perms-for-commands.patch +++ b/patches/server/Added-missing-default-perms-for-commands.patch @@ -170,38 +170,3 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 + } + } +} -diff --git a/src/test/java/org/bukkit/support/DummyServer.java b/src/test/java/org/bukkit/support/DummyServer.java -index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 ---- a/src/test/java/org/bukkit/support/DummyServer.java -+++ b/src/test/java/org/bukkit/support/DummyServer.java -@@ -0,0 +0,0 @@ public final class DummyServer implements InvocationHandler { - } - } - ); -- Bukkit.setServer(Proxy.getProxyClass(Server.class.getClassLoader(), Server.class).asSubclass(Server.class).getConstructor(InvocationHandler.class).newInstance(new DummyServer())); -+ // Paper start - modeled off of TestServer in the API tests module -+ methods.put( -+ Server.class.getMethod("getPluginManager"), -+ new MethodHandler() { -+ @Override -+ public Object handle(DummyServer server, Object[] args) { -+ return server.pluginManager; -+ } -+ } -+ ); -+ DummyServer server = new DummyServer(); -+ Server instance = Proxy.getProxyClass(Server.class.getClassLoader(), Server.class).asSubclass(Server.class).getConstructor(InvocationHandler.class).newInstance(server); -+ Bukkit.setServer(instance); -+ server.pluginManager = new org.bukkit.plugin.SimplePluginManager(instance, new org.bukkit.command.SimpleCommandMap(instance)); -+ // Paper end - } catch (Throwable t) { - throw new Error(t); - } -@@ -0,0 +0,0 @@ public final class DummyServer implements InvocationHandler { - - private DummyServer() {}; - -+ private org.bukkit.plugin.PluginManager pluginManager; // Paper - @Override - public Object invoke(Object proxy, Method method, Object[] args) { - MethodHandler handler = DummyServer.methods.get(method); diff --git a/patches/server/Deobfuscate-stacktraces-in-log-messages-crash-report.patch b/patches/server/Deobfuscate-stacktraces-in-log-messages-crash-report.patch index cf0447c3f1..9e56a8c403 100644 --- a/patches/server/Deobfuscate-stacktraces-in-log-messages-crash-report.patch +++ b/patches/server/Deobfuscate-stacktraces-in-log-messages-crash-report.patch @@ -17,7 +17,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 // Paper end implementation("org.apache.logging.log4j:log4j-iostreams:2.19.0") // Paper - remove exclusion implementation("org.ow2.asm:asm:9.3") - implementation("org.ow2.asm:asm-commons:9.3") // Paper - ASM event executor generation +@@ -0,0 +0,0 @@ dependencies { + testImplementation("org.mockito:mockito-core:4.9.0") // Paper - switch to mockito implementation("org.spongepowered:configurate-yaml:4.1.2") // Paper - config files implementation("commons-lang:commons-lang:2.6") + implementation("net.fabricmc:mapping-io:0.3.0") // Paper - needed to read mappings for stacktrace deobfuscation diff --git a/patches/server/Paper-config-files.patch b/patches/server/Paper-config-files.patch index 95b2204dba..30d2cec6f7 100644 --- a/patches/server/Paper-config-files.patch +++ b/patches/server/Paper-config-files.patch @@ -18,9 +18,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -0,0 +0,0 @@ dependencies { - implementation("org.apache.logging.log4j:log4j-iostreams:2.19.0") // Paper - remove exclusion implementation("org.ow2.asm:asm:9.3") implementation("org.ow2.asm:asm-commons:9.3") // Paper - ASM event executor generation + testImplementation("org.mockito:mockito-core:4.9.0") // Paper - switch to mockito + implementation("org.spongepowered:configurate-yaml:4.1.2") // Paper - config files implementation("commons-lang:commons-lang:2.6") runtimeOnly("org.xerial:sqlite-jdbc:3.36.0.3") @@ -4664,8 +4664,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 --- a/src/test/java/org/bukkit/support/AbstractTestingBase.java +++ b/src/test/java/org/bukkit/support/AbstractTestingBase.java @@ -0,0 +0,0 @@ public abstract class AbstractTestingBase { + BIOMES = REGISTRY_CUSTOM.registryOrThrow(Registries.BIOME); - DummyServer.setup(); DummyEnchantments.setup(); + io.papermc.paper.configuration.GlobalConfigTestingBase.setupGlobalConfigForTest(); // Paper diff --git a/patches/server/Test-changes.patch b/patches/server/Test-changes.patch new file mode 100644 index 0000000000..9c8c50be8e --- /dev/null +++ b/patches/server/Test-changes.patch @@ -0,0 +1,280 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic <jake.m.potrebic@gmail.com> +Date: Mon, 13 Feb 2023 14:14:56 -0800 +Subject: [PATCH] Test changes + + +diff --git a/build.gradle.kts b/build.gradle.kts +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/build.gradle.kts ++++ b/build.gradle.kts +@@ -0,0 +0,0 @@ dependencies { + implementation("org.apache.logging.log4j:log4j-iostreams:2.19.0") // Paper - remove exclusion + implementation("org.ow2.asm:asm:9.3") + implementation("org.ow2.asm:asm-commons:9.3") // Paper - ASM event executor generation ++ testImplementation("org.mockito:mockito-core:4.9.0") // Paper - switch to mockito + implementation("commons-lang:commons-lang:2.6") + runtimeOnly("org.xerial:sqlite-jdbc:3.36.0.3") + runtimeOnly("mysql:mysql-connector-java:8.0.29") +diff --git a/src/test/java/io/papermc/paper/testing/DummyServer.java b/src/test/java/io/papermc/paper/testing/DummyServer.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/test/java/io/papermc/paper/testing/DummyServer.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.testing; ++ ++import java.util.logging.Logger; ++import org.bukkit.Bukkit; ++import org.bukkit.Material; ++import org.bukkit.NamespacedKey; ++import org.bukkit.Server; ++import org.bukkit.command.SimpleCommandMap; ++import org.bukkit.craftbukkit.CraftRegistry; ++import org.bukkit.craftbukkit.block.data.CraftBlockData; ++import org.bukkit.craftbukkit.inventory.CraftItemFactory; ++import org.bukkit.craftbukkit.util.CraftMagicNumbers; ++import org.bukkit.craftbukkit.util.CraftNamespacedKey; ++import org.bukkit.plugin.PluginManager; ++import org.bukkit.plugin.SimplePluginManager; ++import org.bukkit.support.AbstractTestingBase; ++ ++import static org.mockito.Mockito.any; ++import static org.mockito.Mockito.mock; ++import static org.mockito.Mockito.when; ++ ++public final class DummyServer { ++ ++ @SuppressWarnings({"deprecation", "removal"}) ++ public static void setup() { ++ //noinspection ConstantValue ++ if (Bukkit.getServer() != null) { ++ return; ++ } ++ ++ final Server dummyServer = mock(Server.class); ++ ++ final Logger logger = Logger.getLogger(DummyServer.class.getCanonicalName()); ++ when(dummyServer.getLogger()).thenReturn(logger); ++ when(dummyServer.getName()).thenReturn(DummyServer.class.getSimpleName()); ++ when(dummyServer.getVersion()).thenReturn("Version_" + DummyServer.class.getPackage().getImplementationVersion()); ++ when(dummyServer.getBukkitVersion()).thenReturn("BukkitVersion_" + DummyServer.class.getPackage().getImplementationVersion()); ++ ++ final Thread currentThread = Thread.currentThread(); ++ when(dummyServer.isPrimaryThread()).thenAnswer(ignored -> Thread.currentThread().equals(currentThread)); ++ ++ when(dummyServer.getItemFactory()).thenReturn(CraftItemFactory.instance()); ++ ++ when(dummyServer.getUnsafe()).thenAnswer(ignored -> CraftMagicNumbers.INSTANCE); // lambda for lazy load ++ ++ when(dummyServer.createBlockData(any(Material.class))).thenAnswer(invocation -> { ++ return CraftBlockData.newData(invocation.getArgument(0, Material.class), null); ++ }); ++ ++ when(dummyServer.getLootTable(any(NamespacedKey.class))).thenAnswer(invocation -> { ++ final NamespacedKey key = invocation.getArgument(0, NamespacedKey.class); ++ return new org.bukkit.craftbukkit.CraftLootTable(key, AbstractTestingBase.DATA_PACK.getLootTables().get(CraftNamespacedKey.toMinecraft(key))); ++ }); ++ ++ when(dummyServer.getRegistry(any())).thenAnswer(invocation -> { ++ // LazyRegistry because the vanilla data hasn't been bootstrapped yet. ++ return new LazyRegistry(() -> CraftRegistry.createRegistry(invocation.getArgument(0, Class.class), AbstractTestingBase.REGISTRY_CUSTOM)); ++ }); ++ ++ final PluginManager pluginManager = new SimplePluginManager(dummyServer, new SimpleCommandMap(dummyServer)); ++ when(dummyServer.getPluginManager()).thenReturn(pluginManager); ++ ++ Bukkit.setServer(dummyServer); ++ ++ } ++} +diff --git a/src/test/java/io/papermc/paper/testing/LazyRegistry.java b/src/test/java/io/papermc/paper/testing/LazyRegistry.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- /dev/null ++++ b/src/test/java/io/papermc/paper/testing/LazyRegistry.java +@@ -0,0 +0,0 @@ ++package io.papermc.paper.testing; ++ ++import java.util.Iterator; ++import java.util.function.Supplier; ++import org.bukkit.Keyed; ++import org.bukkit.NamespacedKey; ++import org.bukkit.Registry; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++public record LazyRegistry(Supplier<Registry<Keyed>> supplier) implements Registry<Keyed> { ++ ++ @NotNull ++ @Override ++ public Iterator<Keyed> iterator() { ++ return this.supplier().get().iterator(); ++ } ++ ++ @Override ++ public @Nullable Keyed get(@NotNull final NamespacedKey key) { ++ return this.supplier().get().get(key); ++ } ++} +diff --git a/src/test/java/org/bukkit/support/AbstractTestingBase.java b/src/test/java/org/bukkit/support/AbstractTestingBase.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/test/java/org/bukkit/support/AbstractTestingBase.java ++++ b/src/test/java/org/bukkit/support/AbstractTestingBase.java +@@ -0,0 +0,0 @@ package org.bukkit.support; + + import com.google.common.collect.ImmutableList; + import com.google.common.util.concurrent.MoreExecutors; +-import java.util.Collections; + import java.util.List; + import net.minecraft.SharedConstants; + import net.minecraft.commands.Commands; +@@ -0,0 +0,0 @@ public abstract class AbstractTestingBase { + public static final Registry<Biome> BIOMES; + + static { ++ io.papermc.paper.testing.DummyServer.setup(); // Paper + SharedConstants.tryDetectVersion(); + Bootstrap.bootStrap(); + // Set up resource manager +@@ -0,0 +0,0 @@ public abstract class AbstractTestingBase { + // Biome shortcut + BIOMES = REGISTRY_CUSTOM.registryOrThrow(Registries.BIOME); + +- DummyServer.setup(); + DummyEnchantments.setup(); + + ImmutableList.Builder<Material> builder = ImmutableList.builder(); +diff --git a/src/test/java/org/bukkit/support/DummyServer.java b/src/test/java/org/bukkit/support/DummyServer.java +deleted file mode 100644 +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 +--- a/src/test/java/org/bukkit/support/DummyServer.java ++++ /dev/null +@@ -0,0 +0,0 @@ +-package org.bukkit.support; +- +-import java.lang.reflect.InvocationHandler; +-import java.lang.reflect.Method; +-import java.lang.reflect.Proxy; +-import java.util.HashMap; +-import java.util.logging.Logger; +-import org.bukkit.Bukkit; +-import org.bukkit.Material; +-import org.bukkit.NamespacedKey; +-import org.bukkit.Server; +-import org.bukkit.craftbukkit.CraftLootTable; +-import org.bukkit.craftbukkit.CraftRegistry; +-import org.bukkit.craftbukkit.block.data.CraftBlockData; +-import org.bukkit.craftbukkit.inventory.CraftItemFactory; +-import org.bukkit.craftbukkit.util.CraftMagicNumbers; +-import org.bukkit.craftbukkit.util.CraftNamespacedKey; +-import org.bukkit.craftbukkit.util.Versioning; +- +-public final class DummyServer implements InvocationHandler { +- private static interface MethodHandler { +- Object handle(DummyServer server, Object[] args); +- } +- private static final HashMap<Method, MethodHandler> methods = new HashMap<Method, MethodHandler>(); +- static { +- try { +- methods.put( +- Server.class.getMethod("getItemFactory"), +- new MethodHandler() { +- @Override +- public Object handle(DummyServer server, Object[] args) { +- return CraftItemFactory.instance(); +- } +- } +- ); +- methods.put( +- Server.class.getMethod("getName"), +- new MethodHandler() { +- @Override +- public Object handle(DummyServer server, Object[] args) { +- return DummyServer.class.getName(); +- } +- } +- ); +- methods.put( +- Server.class.getMethod("getVersion"), +- new MethodHandler() { +- @Override +- public Object handle(DummyServer server, Object[] args) { +- return DummyServer.class.getPackage().getImplementationVersion(); +- } +- } +- ); +- methods.put( +- Server.class.getMethod("getBukkitVersion"), +- new MethodHandler() { +- @Override +- public Object handle(DummyServer server, Object[] args) { +- return Versioning.getBukkitVersion(); +- } +- } +- ); +- methods.put( +- Server.class.getMethod("getLogger"), +- new MethodHandler() { +- final Logger logger = Logger.getLogger(DummyServer.class.getCanonicalName()); +- @Override +- public Object handle(DummyServer server, Object[] args) { +- return logger; +- } +- } +- ); +- methods.put( +- Server.class.getMethod("getUnsafe"), +- new MethodHandler() { +- @Override +- public Object handle(DummyServer server, Object[] args) { +- return CraftMagicNumbers.INSTANCE; +- } +- } +- ); +- methods.put( +- Server.class.getMethod("createBlockData", Material.class), +- new MethodHandler() { +- final Logger logger = Logger.getLogger(DummyServer.class.getCanonicalName()); +- @Override +- public Object handle(DummyServer server, Object[] args) { +- return CraftBlockData.newData((Material) args[0], null); +- } +- } +- ); +- methods.put(Server.class.getMethod("getLootTable", NamespacedKey.class), +- new MethodHandler() { +- @Override +- public Object handle(DummyServer server, Object[] args) { +- NamespacedKey key = (NamespacedKey) args[0]; +- return new CraftLootTable(key, AbstractTestingBase.DATA_PACK.getLootTables().get(CraftNamespacedKey.toMinecraft(key))); +- } +- } +- ); +- methods.put(Server.class.getMethod("getRegistry", Class.class), +- new MethodHandler() { +- @Override +- public Object handle(DummyServer server, Object[] args) { +- return CraftRegistry.createRegistry((Class) args[0], AbstractTestingBase.REGISTRY_CUSTOM); +- } +- } +- ); +- Bukkit.setServer(Proxy.getProxyClass(Server.class.getClassLoader(), Server.class).asSubclass(Server.class).getConstructor(InvocationHandler.class).newInstance(new DummyServer())); +- } catch (Throwable t) { +- throw new Error(t); +- } +- } +- +- public static void setup() {} +- +- private DummyServer() {}; +- +- @Override +- public Object invoke(Object proxy, Method method, Object[] args) { +- MethodHandler handler = DummyServer.methods.get(method); +- if (handler != null) { +- return handler.handle(this, args); +- } +- throw new UnsupportedOperationException(String.valueOf(method)); +- } +-}