13
0
geforkt von Mirrors/Paper

#1340: Centralize the conversion from and to Minecraft / Bukkit registry items even more and add a test case for them

By: DerFrZocker <derrieple@gmail.com>
Dieser Commit ist enthalten in:
CraftBukkit/Spigot 2024-01-22 20:36:36 +11:00
Ursprung e6b4a5f109
Commit d7095f8578
20 geänderte Dateien mit 623 neuen und 110 gelöschten Zeilen

Datei anzeigen

@ -1,31 +1,20 @@
package org.bukkit.craftbukkit; package org.bukkit.craftbukkit;
import com.google.common.base.Preconditions;
import net.minecraft.core.IRegistry;
import net.minecraft.core.registries.Registries; import net.minecraft.core.registries.Registries;
import org.bukkit.GameEvent; import org.bukkit.GameEvent;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.Registry; import org.bukkit.Registry;
import org.bukkit.craftbukkit.util.CraftNamespacedKey; import org.bukkit.craftbukkit.util.Handleable;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
public class CraftGameEvent extends GameEvent { public class CraftGameEvent extends GameEvent implements Handleable<net.minecraft.world.level.gameevent.GameEvent> {
public static GameEvent minecraftToBukkit(net.minecraft.world.level.gameevent.GameEvent minecraft) { public static GameEvent minecraftToBukkit(net.minecraft.world.level.gameevent.GameEvent minecraft) {
Preconditions.checkArgument(minecraft != null); return CraftRegistry.minecraftToBukkit(minecraft, Registries.GAME_EVENT, Registry.GAME_EVENT);
IRegistry<net.minecraft.world.level.gameevent.GameEvent> registry = CraftRegistry.getMinecraftRegistry(Registries.GAME_EVENT);
GameEvent bukkit = Registry.GAME_EVENT.get(CraftNamespacedKey.fromMinecraft(registry.getKey(minecraft)));
Preconditions.checkArgument(bukkit != null);
return bukkit;
} }
public static net.minecraft.world.level.gameevent.GameEvent bukkitToMinecraft(GameEvent bukkit) { public static net.minecraft.world.level.gameevent.GameEvent bukkitToMinecraft(GameEvent bukkit) {
Preconditions.checkArgument(bukkit != null); return CraftRegistry.bukkitToMinecraft(bukkit);
return ((CraftGameEvent) bukkit).getHandle();
} }
private final NamespacedKey key; private final NamespacedKey key;
@ -36,6 +25,7 @@ public class CraftGameEvent extends GameEvent {
this.handle = handle; this.handle = handle;
} }
@Override
public net.minecraft.world.level.gameevent.GameEvent getHandle() { public net.minecraft.world.level.gameevent.GameEvent getHandle() {
return handle; return handle;
} }

Datei anzeigen

@ -1,32 +1,21 @@
package org.bukkit.craftbukkit; package org.bukkit.craftbukkit;
import com.google.common.base.Preconditions;
import net.minecraft.core.IRegistry;
import net.minecraft.core.registries.Registries; import net.minecraft.core.registries.Registries;
import net.minecraft.world.item.Instrument; import net.minecraft.world.item.Instrument;
import org.bukkit.MusicInstrument; import org.bukkit.MusicInstrument;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.Registry; import org.bukkit.Registry;
import org.bukkit.craftbukkit.util.CraftNamespacedKey; import org.bukkit.craftbukkit.util.Handleable;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
public class CraftMusicInstrument extends MusicInstrument { public class CraftMusicInstrument extends MusicInstrument implements Handleable<Instrument> {
public static MusicInstrument minecraftToBukkit(Instrument minecraft) { public static MusicInstrument minecraftToBukkit(Instrument minecraft) {
Preconditions.checkArgument(minecraft != null); return CraftRegistry.minecraftToBukkit(minecraft, Registries.INSTRUMENT, Registry.INSTRUMENT);
IRegistry<Instrument> registry = CraftRegistry.getMinecraftRegistry(Registries.INSTRUMENT);
MusicInstrument bukkit = Registry.INSTRUMENT.get(CraftNamespacedKey.fromMinecraft(registry.getKey(minecraft)));
Preconditions.checkArgument(bukkit != null);
return bukkit;
} }
public static Instrument bukkitToMinecraft(MusicInstrument bukkit) { public static Instrument bukkitToMinecraft(MusicInstrument bukkit) {
Preconditions.checkArgument(bukkit != null); return CraftRegistry.bukkitToMinecraft(bukkit);
return ((CraftMusicInstrument) bukkit).getHandle();
} }
private final NamespacedKey key; private final NamespacedKey key;
@ -37,6 +26,7 @@ public class CraftMusicInstrument extends MusicInstrument {
this.handle = handle; this.handle = handle;
} }
@Override
public Instrument getHandle() { public Instrument getHandle() {
return handle; return handle;
} }

Datei anzeigen

@ -23,6 +23,7 @@ import org.bukkit.craftbukkit.inventory.trim.CraftTrimMaterial;
import org.bukkit.craftbukkit.inventory.trim.CraftTrimPattern; import org.bukkit.craftbukkit.inventory.trim.CraftTrimPattern;
import org.bukkit.craftbukkit.potion.CraftPotionEffectType; import org.bukkit.craftbukkit.potion.CraftPotionEffectType;
import org.bukkit.craftbukkit.util.CraftNamespacedKey; import org.bukkit.craftbukkit.util.CraftNamespacedKey;
import org.bukkit.craftbukkit.util.Handleable;
import org.bukkit.enchantments.Enchantment; import org.bukkit.enchantments.Enchantment;
import org.bukkit.generator.structure.Structure; import org.bukkit.generator.structure.Structure;
import org.bukkit.generator.structure.StructureType; import org.bukkit.generator.structure.StructureType;
@ -48,6 +49,47 @@ public class CraftRegistry<B extends Keyed, M> implements Registry<B> {
return getMinecraftRegistry().registryOrThrow(key); return getMinecraftRegistry().registryOrThrow(key);
} }
/**
* Usage note: Only use this method to delegate the conversion methods from the individual Craft classes to here.
* Do not use it in other parts of CraftBukkit, use the methods in the respective Craft classes instead.
*
* @param minecraft the minecraft representation
* @param registryKey the registry key of the minecraft registry to use
* @param bukkitRegistry the bukkit registry to use
* @return the bukkit representation of the minecraft value
*/
public static <B extends Keyed, M> B minecraftToBukkit(M minecraft, ResourceKey<IRegistry<M>> registryKey, Registry<B> bukkitRegistry) {
Preconditions.checkArgument(minecraft != null);
IRegistry<M> registry = CraftRegistry.getMinecraftRegistry(registryKey);
B bukkit = bukkitRegistry.get(CraftNamespacedKey.fromMinecraft(registry.getResourceKey(minecraft)
.orElseThrow(() -> new IllegalStateException(String.format("Cannot convert '%s' to bukkit representation, since it is not registered.", minecraft))).location()));
Preconditions.checkArgument(bukkit != null);
return bukkit;
}
/**
* Usage note: Only use this method to delegate the conversion methods from the individual Craft classes to here.
* Do not use it in other parts of CraftBukkit, use the methods in the respective Craft classes instead.
*
* @param bukkit the bukkit representation
* @return the minecraft representation of the bukkit value
*/
public static <B extends Keyed, M> M bukkitToMinecraft(B bukkit) {
Preconditions.checkArgument(bukkit != null);
return ((Handleable<M>) bukkit).getHandle();
}
/**
* Note: Newly added registries should also be added to RegistriesArgumentProvider in the test package
*
* @param bukkitClass the bukkit class of the registry
* @param registryHolder the minecraft registry holder
* @return the bukkit registry of the provided class
*/
public static <B extends Keyed> Registry<?> createRegistry(Class<B> bukkitClass, IRegistryCustom registryHolder) { public static <B extends Keyed> Registry<?> createRegistry(Class<B> bukkitClass, IRegistryCustom registryHolder) {
if (bukkitClass == Enchantment.class) { if (bukkitClass == Enchantment.class) {
return new CraftRegistry<>(Enchantment.class, registryHolder.registryOrThrow(Registries.ENCHANTMENT), CraftEnchantment::new); return new CraftRegistry<>(Enchantment.class, registryHolder.registryOrThrow(Registries.ENCHANTMENT), CraftEnchantment::new);

Datei anzeigen

@ -1,7 +1,5 @@
package org.bukkit.craftbukkit.enchantments; package org.bukkit.craftbukkit.enchantments;
import com.google.common.base.Preconditions;
import net.minecraft.core.IRegistry;
import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.registries.Registries; import net.minecraft.core.registries.Registries;
import net.minecraft.world.item.enchantment.EnchantmentBinding; import net.minecraft.world.item.enchantment.EnchantmentBinding;
@ -10,29 +8,20 @@ import org.bukkit.NamespacedKey;
import org.bukkit.Registry; import org.bukkit.Registry;
import org.bukkit.craftbukkit.CraftRegistry; import org.bukkit.craftbukkit.CraftRegistry;
import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.inventory.CraftItemStack;
import org.bukkit.craftbukkit.util.CraftNamespacedKey; import org.bukkit.craftbukkit.util.Handleable;
import org.bukkit.enchantments.Enchantment; import org.bukkit.enchantments.Enchantment;
import org.bukkit.enchantments.EnchantmentTarget; import org.bukkit.enchantments.EnchantmentTarget;
import org.bukkit.enchantments.EnchantmentWrapper; import org.bukkit.enchantments.EnchantmentWrapper;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
public class CraftEnchantment extends Enchantment { public class CraftEnchantment extends Enchantment implements Handleable<net.minecraft.world.item.enchantment.Enchantment> {
public static Enchantment minecraftToBukkit(net.minecraft.world.item.enchantment.Enchantment minecraft) { public static Enchantment minecraftToBukkit(net.minecraft.world.item.enchantment.Enchantment minecraft) {
Preconditions.checkArgument(minecraft != null); return CraftRegistry.minecraftToBukkit(minecraft, Registries.ENCHANTMENT, Registry.ENCHANTMENT);
IRegistry<net.minecraft.world.item.enchantment.Enchantment> registry = CraftRegistry.getMinecraftRegistry(Registries.ENCHANTMENT);
Enchantment bukkit = Registry.ENCHANTMENT.get(CraftNamespacedKey.fromMinecraft(registry.getResourceKey(minecraft).orElseThrow().location()));
Preconditions.checkArgument(bukkit != null);
return bukkit;
} }
public static net.minecraft.world.item.enchantment.Enchantment bukkitToMinecraft(Enchantment bukkit) { public static net.minecraft.world.item.enchantment.Enchantment bukkitToMinecraft(Enchantment bukkit) {
Preconditions.checkArgument(bukkit != null); return CraftRegistry.bukkitToMinecraft(bukkit);
return ((CraftEnchantment) bukkit).getHandle();
} }
private final NamespacedKey key; private final NamespacedKey key;
@ -45,6 +34,7 @@ public class CraftEnchantment extends Enchantment {
this.id = BuiltInRegistries.ENCHANTMENT.getId(handle); this.id = BuiltInRegistries.ENCHANTMENT.getId(handle);
} }
@Override
public net.minecraft.world.item.enchantment.Enchantment getHandle() { public net.minecraft.world.item.enchantment.Enchantment getHandle() {
return handle; return handle;
} }

Datei anzeigen

@ -1,32 +1,21 @@
package org.bukkit.craftbukkit.generator.structure; package org.bukkit.craftbukkit.generator.structure;
import com.google.common.base.Preconditions;
import net.minecraft.core.IRegistry;
import net.minecraft.core.registries.Registries; import net.minecraft.core.registries.Registries;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.Registry; import org.bukkit.Registry;
import org.bukkit.craftbukkit.CraftRegistry; import org.bukkit.craftbukkit.CraftRegistry;
import org.bukkit.craftbukkit.util.CraftNamespacedKey; import org.bukkit.craftbukkit.util.Handleable;
import org.bukkit.generator.structure.Structure; import org.bukkit.generator.structure.Structure;
import org.bukkit.generator.structure.StructureType; import org.bukkit.generator.structure.StructureType;
public class CraftStructure extends Structure { public class CraftStructure extends Structure implements Handleable<net.minecraft.world.level.levelgen.structure.Structure> {
public static Structure minecraftToBukkit(net.minecraft.world.level.levelgen.structure.Structure minecraft) { public static Structure minecraftToBukkit(net.minecraft.world.level.levelgen.structure.Structure minecraft) {
Preconditions.checkArgument(minecraft != null); return CraftRegistry.minecraftToBukkit(minecraft, Registries.STRUCTURE, Registry.STRUCTURE);
IRegistry<net.minecraft.world.level.levelgen.structure.Structure> registry = CraftRegistry.getMinecraftRegistry(Registries.STRUCTURE);
Structure bukkit = Registry.STRUCTURE.get(CraftNamespacedKey.fromMinecraft(registry.getResourceKey(minecraft).orElseThrow().location()));
Preconditions.checkArgument(bukkit != null);
return bukkit;
} }
public static net.minecraft.world.level.levelgen.structure.Structure bukkitToMinecraft(Structure bukkit) { public static net.minecraft.world.level.levelgen.structure.Structure bukkitToMinecraft(Structure bukkit) {
Preconditions.checkArgument(bukkit != null); return CraftRegistry.bukkitToMinecraft(bukkit);
return ((CraftStructure) bukkit).getHandle();
} }
private final NamespacedKey key; private final NamespacedKey key;
@ -39,6 +28,7 @@ public class CraftStructure extends Structure {
this.structureType = CraftStructureType.minecraftToBukkit(structure.type()); this.structureType = CraftStructureType.minecraftToBukkit(structure.type());
} }
@Override
public net.minecraft.world.level.levelgen.structure.Structure getHandle() { public net.minecraft.world.level.levelgen.structure.Structure getHandle() {
return structure; return structure;
} }

Datei anzeigen

@ -1,31 +1,20 @@
package org.bukkit.craftbukkit.generator.structure; package org.bukkit.craftbukkit.generator.structure;
import com.google.common.base.Preconditions;
import net.minecraft.core.IRegistry;
import net.minecraft.core.registries.Registries; import net.minecraft.core.registries.Registries;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.Registry; import org.bukkit.Registry;
import org.bukkit.craftbukkit.CraftRegistry; import org.bukkit.craftbukkit.CraftRegistry;
import org.bukkit.craftbukkit.util.CraftNamespacedKey; import org.bukkit.craftbukkit.util.Handleable;
import org.bukkit.generator.structure.StructureType; import org.bukkit.generator.structure.StructureType;
public class CraftStructureType extends StructureType { public class CraftStructureType extends StructureType implements Handleable<net.minecraft.world.level.levelgen.structure.StructureType<?>> {
public static StructureType minecraftToBukkit(net.minecraft.world.level.levelgen.structure.StructureType<?> minecraft) { public static StructureType minecraftToBukkit(net.minecraft.world.level.levelgen.structure.StructureType<?> minecraft) {
Preconditions.checkArgument(minecraft != null); return CraftRegistry.minecraftToBukkit(minecraft, Registries.STRUCTURE_TYPE, Registry.STRUCTURE_TYPE);
IRegistry<net.minecraft.world.level.levelgen.structure.StructureType<?>> registry = CraftRegistry.getMinecraftRegistry(Registries.STRUCTURE_TYPE);
StructureType bukkit = Registry.STRUCTURE_TYPE.get(CraftNamespacedKey.fromMinecraft(registry.getResourceKey(minecraft).orElseThrow().location()));
Preconditions.checkArgument(bukkit != null);
return bukkit;
} }
public static net.minecraft.world.level.levelgen.structure.StructureType<?> bukkitToMinecraft(StructureType bukkit) { public static net.minecraft.world.level.levelgen.structure.StructureType<?> bukkitToMinecraft(StructureType bukkit) {
Preconditions.checkArgument(bukkit != null); return CraftRegistry.bukkitToMinecraft(bukkit);
return ((CraftStructureType) bukkit).getHandle();
} }
private final NamespacedKey key; private final NamespacedKey key;
@ -36,6 +25,7 @@ public class CraftStructureType extends StructureType {
this.structureType = structureType; this.structureType = structureType;
} }
@Override
public net.minecraft.world.level.levelgen.structure.StructureType<?> getHandle() { public net.minecraft.world.level.levelgen.structure.StructureType<?> getHandle() {
return structureType; return structureType;
} }

Datei anzeigen

@ -1,10 +1,22 @@
package org.bukkit.craftbukkit.inventory.trim; package org.bukkit.craftbukkit.inventory.trim;
import net.minecraft.core.registries.Registries;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.Registry;
import org.bukkit.craftbukkit.CraftRegistry;
import org.bukkit.craftbukkit.util.Handleable;
import org.bukkit.inventory.meta.trim.TrimMaterial; import org.bukkit.inventory.meta.trim.TrimMaterial;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
public class CraftTrimMaterial implements TrimMaterial { public class CraftTrimMaterial implements TrimMaterial, Handleable<net.minecraft.world.item.armortrim.TrimMaterial> {
public static TrimMaterial minecraftToBukkit(net.minecraft.world.item.armortrim.TrimMaterial minecraft) {
return CraftRegistry.minecraftToBukkit(minecraft, Registries.TRIM_MATERIAL, Registry.TRIM_MATERIAL);
}
public static net.minecraft.world.item.armortrim.TrimMaterial bukkitToMinecraft(TrimMaterial bukkit) {
return CraftRegistry.bukkitToMinecraft(bukkit);
}
private final NamespacedKey key; private final NamespacedKey key;
private final net.minecraft.world.item.armortrim.TrimMaterial handle; private final net.minecraft.world.item.armortrim.TrimMaterial handle;
@ -14,13 +26,14 @@ public class CraftTrimMaterial implements TrimMaterial {
this.handle = handle; this.handle = handle;
} }
@Override
public net.minecraft.world.item.armortrim.TrimMaterial getHandle() {
return handle;
}
@Override @Override
@NotNull @NotNull
public NamespacedKey getKey() { public NamespacedKey getKey() {
return key; return key;
} }
public net.minecraft.world.item.armortrim.TrimMaterial getHandle() {
return handle;
}
} }

Datei anzeigen

@ -1,10 +1,22 @@
package org.bukkit.craftbukkit.inventory.trim; package org.bukkit.craftbukkit.inventory.trim;
import net.minecraft.core.registries.Registries;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.Registry;
import org.bukkit.craftbukkit.CraftRegistry;
import org.bukkit.craftbukkit.util.Handleable;
import org.bukkit.inventory.meta.trim.TrimPattern; import org.bukkit.inventory.meta.trim.TrimPattern;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
public class CraftTrimPattern implements TrimPattern { public class CraftTrimPattern implements TrimPattern, Handleable<net.minecraft.world.item.armortrim.TrimPattern> {
public static TrimPattern minecraftToBukkit(net.minecraft.world.item.armortrim.TrimPattern minecraft) {
return CraftRegistry.minecraftToBukkit(minecraft, Registries.TRIM_PATTERN, Registry.TRIM_PATTERN);
}
public static net.minecraft.world.item.armortrim.TrimPattern bukkitToMinecraft(TrimPattern bukkit) {
return CraftRegistry.bukkitToMinecraft(bukkit);
}
private final NamespacedKey key; private final NamespacedKey key;
private final net.minecraft.world.item.armortrim.TrimPattern handle; private final net.minecraft.world.item.armortrim.TrimPattern handle;
@ -14,13 +26,14 @@ public class CraftTrimPattern implements TrimPattern {
this.handle = handle; this.handle = handle;
} }
@Override
public net.minecraft.world.item.armortrim.TrimPattern getHandle() {
return handle;
}
@Override @Override
@NotNull @NotNull
public NamespacedKey getKey() { public NamespacedKey getKey() {
return key; return key;
} }
public net.minecraft.world.item.armortrim.TrimPattern getHandle() {
return handle;
}
} }

Datei anzeigen

@ -1,19 +1,25 @@
package org.bukkit.craftbukkit.potion; package org.bukkit.craftbukkit.potion;
import com.google.common.base.Preconditions;
import net.minecraft.core.IRegistry;
import net.minecraft.core.registries.Registries; import net.minecraft.core.registries.Registries;
import net.minecraft.world.effect.MobEffectList; import net.minecraft.world.effect.MobEffectList;
import org.bukkit.Color; import org.bukkit.Color;
import org.bukkit.NamespacedKey; import org.bukkit.NamespacedKey;
import org.bukkit.Registry; import org.bukkit.Registry;
import org.bukkit.craftbukkit.CraftRegistry; import org.bukkit.craftbukkit.CraftRegistry;
import org.bukkit.craftbukkit.util.CraftNamespacedKey; import org.bukkit.craftbukkit.util.Handleable;
import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType; import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
public class CraftPotionEffectType extends PotionEffectType { public class CraftPotionEffectType extends PotionEffectType implements Handleable<MobEffectList> {
public static PotionEffectType minecraftToBukkit(MobEffectList minecraft) {
return CraftRegistry.minecraftToBukkit(minecraft, Registries.MOB_EFFECT, Registry.EFFECT);
}
public static MobEffectList bukkitToMinecraft(PotionEffectType bukkit) {
return CraftRegistry.bukkitToMinecraft(bukkit);
}
private final NamespacedKey key; private final NamespacedKey key;
private final MobEffectList handle; private final MobEffectList handle;
@ -25,6 +31,7 @@ public class CraftPotionEffectType extends PotionEffectType {
this.id = CraftRegistry.getMinecraftRegistry(Registries.MOB_EFFECT).getId(handle) + 1; this.id = CraftRegistry.getMinecraftRegistry(Registries.MOB_EFFECT).getId(handle) + 1;
} }
@Override
public MobEffectList getHandle() { public MobEffectList getHandle() {
return handle; return handle;
} }
@ -123,21 +130,4 @@ public class CraftPotionEffectType extends PotionEffectType {
public String toString() { public String toString() {
return "CraftPotionEffectType[" + getKey() + "]"; return "CraftPotionEffectType[" + getKey() + "]";
} }
public static PotionEffectType minecraftToBukkit(MobEffectList minecraft) {
Preconditions.checkArgument(minecraft != null);
IRegistry<MobEffectList> registry = CraftRegistry.getMinecraftRegistry(Registries.MOB_EFFECT);
PotionEffectType bukkit = Registry.EFFECT.get(CraftNamespacedKey.fromMinecraft(registry.getResourceKey(minecraft).orElseThrow().location()));
Preconditions.checkArgument(bukkit != null);
return bukkit;
}
public static MobEffectList bukkitToMinecraft(PotionEffectType bukkit) {
Preconditions.checkArgument(bukkit != null);
return ((CraftPotionEffectType) bukkit).getHandle();
}
} }

Datei anzeigen

@ -0,0 +1,6 @@
package org.bukkit.craftbukkit.util;
public interface Handleable<M> {
M getHandle();
}

Datei anzeigen

@ -1,4 +1,4 @@
package org.bukkit; package org.bukkit.registry;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
@ -6,6 +6,9 @@ import java.lang.reflect.Field;
import java.util.List; import java.util.List;
import java.util.Random; import java.util.Random;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.bukkit.Keyed;
import org.bukkit.NamespacedKey;
import org.bukkit.Registry;
import org.bukkit.craftbukkit.CraftRegistry; import org.bukkit.craftbukkit.CraftRegistry;
import org.bukkit.support.AbstractTestingBase; import org.bukkit.support.AbstractTestingBase;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;

Datei anzeigen

@ -0,0 +1,50 @@
package org.bukkit.registry;
import static org.junit.jupiter.api.Assertions.*;
import com.google.common.base.Joiner;
import java.util.HashSet;
import java.util.Set;
import org.bukkit.Registry;
import org.bukkit.support.AbstractTestingBase;
import org.bukkit.support.DummyServer;
import org.bukkit.support.provider.RegistriesArgumentProvider;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.provider.Arguments;
/**
* This class tests, if all default registries present in {@link Registry} are added to {@link RegistriesArgumentProvider}
*/
public class RegistryArgumentAddedTest extends AbstractTestingBase {
@Test
public void testPresent() throws ClassNotFoundException {
// Make sure every registry is created
Class.forName(Registry.class.getName());
Set<Class<?>> loadedRegistries = new HashSet<>(DummyServer.registers.keySet());
Set<Class<?>> notFound = new HashSet<>();
RegistriesArgumentProvider
.getData()
.map(Arguments::get)
.map(array -> array[0])
.map(clazz -> (Class<?>) clazz)
.forEach(clazz -> {
if (!loadedRegistries.remove(clazz)) {
notFound.add(clazz);
}
});
assertTrue(loadedRegistries.isEmpty(), String.format("""
There are registries present, which are not registered in RegistriesArgumentProvider.
Add the following registries to the RegistriesArgumentProvider class, so that they can be tested.
%s""", Joiner.on('\n').join(loadedRegistries)));
assertTrue(notFound.isEmpty(), String.format("""
There are more registries present in RegistriesArgumentProvider then loaded by Registry class.
Remove the following registries from the RegistriesArgumentProvider class.
%s""", Joiner.on('\n').join(notFound)));
}
}

Datei anzeigen

@ -1,4 +1,4 @@
package org.bukkit; package org.bukkit.registry;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
import java.lang.reflect.Field; import java.lang.reflect.Field;
@ -9,6 +9,9 @@ import net.minecraft.core.IRegistry;
import net.minecraft.core.registries.Registries; import net.minecraft.core.registries.Registries;
import net.minecraft.resources.MinecraftKey; import net.minecraft.resources.MinecraftKey;
import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceKey;
import org.bukkit.Keyed;
import org.bukkit.NamespacedKey;
import org.bukkit.Registry;
import org.bukkit.craftbukkit.util.CraftNamespacedKey; import org.bukkit.craftbukkit.util.CraftNamespacedKey;
import org.bukkit.inventory.meta.trim.TrimMaterial; import org.bukkit.inventory.meta.trim.TrimMaterial;
import org.bukkit.inventory.meta.trim.TrimPattern; import org.bukkit.inventory.meta.trim.TrimPattern;

Datei anzeigen

@ -0,0 +1,306 @@
package org.bukkit.registry;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assumptions.*;
import static org.mockito.Mockito.*;
import com.google.common.base.Joiner;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import net.minecraft.core.IRegistry;
import net.minecraft.resources.ResourceKey;
import org.bukkit.Bukkit;
import org.bukkit.Keyed;
import org.bukkit.Registry;
import org.bukkit.craftbukkit.util.Handleable;
import org.bukkit.support.AbstractTestingBase;
import org.bukkit.support.provider.RegistryArgumentProvider;
import org.bukkit.support.test.RegistriesTest;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.params.provider.Arguments;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class RegistryConversionTest extends AbstractTestingBase {
private static final String MINECRAFT_TO_BUKKIT = "minecraftToBukkit";
private static final String BUKKIT_TO_MINECRAFT = "bukkitToMinecraft";
private static final Map<Class<? extends Keyed>, Method> MINECRAFT_TO_BUKKIT_METHODS = new HashMap<>();
private static final Map<Class<? extends Keyed>, Method> BUKKIT_TO_MINECRAFT_METHODS = new HashMap<>();
private static final Set<Class<? extends Keyed>> IMPLEMENT_HANDLE_ABLE = new HashSet<>();
@Order(1)
@RegistriesTest
public void testHandleableImplementation(Class<? extends Keyed> clazz) {
Set<Class<? extends Keyed>> notImplemented = new HashSet<>();
Registry<? extends Keyed> registry = Bukkit.getRegistry(clazz);
for (Keyed item : registry) {
if (!(item instanceof Handleable<?>)) {
notImplemented.add(item.getClass());
}
}
assertTrue(notImplemented.isEmpty(), String.format("""
Not all implementations of the registry from the class %s have the Handleable interface implemented.
Every Implementation should implement the Handleable interface.
The following implementation do not implement Handleable:
%s""", clazz.getName(), Joiner.on('\n').join(notImplemented)));
IMPLEMENT_HANDLE_ABLE.add(clazz);
}
@Order(2)
@RegistriesTest
public void testMinecraftToBukkitPresent(Class<? extends Keyed> clazz, ResourceKey<IRegistry<?>> registryKey,
Class<? extends Keyed> craftClazz, Class<?> minecraftClazz) {
Method method = null;
try {
method = craftClazz.getDeclaredMethod(MINECRAFT_TO_BUKKIT, minecraftClazz);
} catch (NoSuchMethodException e) {
fail(String.format("""
The class %s does not have a public static method to convert a minecraft value to a bukkit value.
Following method should be add which, returns the bukkit value based on the minecraft value.
%s
""", craftClazz, buildMinecraftToBukkitMethod(clazz, minecraftClazz)));
}
assertTrue(Modifier.isPublic(method.getModifiers()), String.format("""
The method %s in class %s is not public.
The method should be made public, method structure:
%s
""", MINECRAFT_TO_BUKKIT, craftClazz, buildMinecraftToBukkitMethod(clazz, minecraftClazz)));
assertTrue(Modifier.isStatic(method.getModifiers()), String.format("""
The method %s in class %s is not static.
The method should be made static, method structure:
%s
""", MINECRAFT_TO_BUKKIT, craftClazz, buildMinecraftToBukkitMethod(clazz, minecraftClazz)));
assertSame(clazz, method.getReturnType(), String.format("""
The method %s in class %s has the wrong return value.
The method should have the correct return value, method structure:
%s
""", MINECRAFT_TO_BUKKIT, craftClazz, buildMinecraftToBukkitMethod(clazz, minecraftClazz)));
MINECRAFT_TO_BUKKIT_METHODS.put(clazz, method);
}
private String buildMinecraftToBukkitMethod(Class<? extends Keyed> clazz, Class<?> minecraftClazz) {
return String.format("""
public static %s minecraftToBukkit(%s minecraft) {
[...]
}
""", clazz.getSimpleName(), minecraftClazz.getName());
}
@Order(2)
@RegistriesTest
public void testBukkitToMinecraftPresent(Class<? extends Keyed> clazz, ResourceKey<IRegistry<?>> registryKey,
Class<? extends Keyed> craftClazz, Class<?> minecraftClazz) {
Method method = null;
try {
method = craftClazz.getDeclaredMethod(BUKKIT_TO_MINECRAFT, clazz);
} catch (NoSuchMethodException e) {
fail(String.format("""
The class %s does not have a public static method to convert a bukkit value to a minecraft value.
Following method should be add which, returns the minecraft value based on the bukkit value.
%s
""", craftClazz, buildBukkitToMinecraftMethod(clazz, minecraftClazz)));
}
assertTrue(Modifier.isPublic(method.getModifiers()), String.format("""
The method %s in class %s is not public.
The method should be made public, method structure:
%s
""", BUKKIT_TO_MINECRAFT, craftClazz, buildBukkitToMinecraftMethod(clazz, minecraftClazz)));
assertTrue(Modifier.isStatic(method.getModifiers()), String.format("""
The method %s in class %s is not static.
The method should be made static, method structure:
%s
""", BUKKIT_TO_MINECRAFT, craftClazz, buildBukkitToMinecraftMethod(clazz, minecraftClazz)));
assertSame(minecraftClazz, method.getReturnType(), String.format("""
The method %s in class %s has the wrong return value.
The method should have the correct return value, method structure:
%s
""", BUKKIT_TO_MINECRAFT, craftClazz, buildBukkitToMinecraftMethod(clazz, minecraftClazz)));
BUKKIT_TO_MINECRAFT_METHODS.put(clazz, method);
}
private String buildBukkitToMinecraftMethod(Class<? extends Keyed> clazz, Class<?> minecraftClazz) {
return String.format("""
public static %s bukkitToMinecraft(%s bukkit) {
[...]
}
""", minecraftClazz.getName(), clazz.getSimpleName());
}
@Order(2)
@RegistriesTest
public void testMinecraftToBukkitNullValue(Class<? extends Keyed> clazz) throws IllegalAccessException {
checkValidMinecraftToBukkit(clazz);
try {
Object result = MINECRAFT_TO_BUKKIT_METHODS.get(clazz).invoke(null, (Object) null);
fail(String.format("""
Method %s in class %s should not accept null values and should throw a IllegalArgumentException.
Got '%s' as return object.
""", MINECRAFT_TO_BUKKIT, clazz.getName(), result));
} catch (InvocationTargetException e) {
// #invoke wraps the error in a InvocationTargetException, so we need to check it this way
assertSame(IllegalArgumentException.class, e.getCause().getClass(), String.format("""
Method %s in class %s should not accept null values and should throw a IllegalArgumentException.
""", MINECRAFT_TO_BUKKIT, clazz.getName()));
}
}
@Order(3)
@RegistriesTest
public void testBukkitToMinecraftNullValue(Class<? extends Keyed> clazz) throws IllegalAccessException {
checkValidBukkitToMinecraft(clazz);
try {
Object result = BUKKIT_TO_MINECRAFT_METHODS.get(clazz).invoke(null, (Object) null);
fail(String.format("""
Method %s in class %s should not accept null values and should throw a IllegalArgumentException.
Got '%s' as return object.
""", BUKKIT_TO_MINECRAFT, clazz.getName(), result));
} catch (InvocationTargetException e) {
// #invoke wraps the error in a InvocationTargetException, so we need to check it this way
assertSame(IllegalArgumentException.class, e.getCause().getClass(), String.format("""
Method %s in class %s should not accept null values and should throw a IllegalArgumentException.
""", BUKKIT_TO_MINECRAFT, clazz.getName()));
}
}
@Order(3)
@RegistriesTest
public void testMinecraftToBukkit(Class<? extends Keyed> clazz) {
checkValidMinecraftToBukkit(clazz);
checkValidHandle(clazz);
Map<Object, Object> notMatching = new HashMap<>();
Method method = MINECRAFT_TO_BUKKIT_METHODS.get(clazz);
RegistryArgumentProvider.getValues(clazz).map(Arguments::get).forEach(arguments -> {
Keyed bukkit = (Keyed) arguments[0];
Object minecraft = arguments[1];
try {
Object otherBukkit = method.invoke(null, minecraft);
if (bukkit != otherBukkit) {
notMatching.put(bukkit, otherBukkit);
}
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
});
assertTrue(notMatching.isEmpty(), String.format("""
The method %s in class %s does not match all registry items correctly.
Following registry items where match not correctly:
%s""", MINECRAFT_TO_BUKKIT, clazz.getName(),
Joiner.on('\n').withKeyValueSeparator(" got: ").join(notMatching)));
}
@Order(3)
@RegistriesTest
public void testBukkitToMinecraft(Class<? extends Keyed> clazz) {
checkValidBukkitToMinecraft(clazz);
checkValidHandle(clazz);
Map<Object, Object> notMatching = new HashMap<>();
Method method = BUKKIT_TO_MINECRAFT_METHODS.get(clazz);
RegistryArgumentProvider.getValues(clazz).map(Arguments::get).forEach(arguments -> {
Keyed bukkit = (Keyed) arguments[0];
Object minecraft = arguments[1];
try {
Object otherMinecraft = method.invoke(null, bukkit);
if (minecraft != otherMinecraft) {
notMatching.put(minecraft, otherMinecraft);
}
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
});
assertTrue(notMatching.isEmpty(), String.format("""
The method %s in class %s does not match all registry items correctly.
Following registry items where match not correctly:
%s""", BUKKIT_TO_MINECRAFT, clazz.getName(),
Joiner.on('\n').withKeyValueSeparator(" got: ").join(notMatching)));
}
/**
* Minecraft registry can return a default key / value
* when the passed minecraft value is not registry in this case, we want it to throw an error.
*/
@Order(3)
@RegistriesTest
public void testMinecraftToBukkitNoValidMinecraft(Class<? extends Keyed> clazz, ResourceKey<IRegistry<?>> registryKey,
Class<? extends Keyed> craftClazz, Class<?> minecraftClazz) throws IllegalAccessException {
checkValidMinecraftToBukkit(clazz);
try {
Object minecraft = mock(minecraftClazz);
Object result = MINECRAFT_TO_BUKKIT_METHODS.get(clazz).invoke(null, minecraft);
fail(String.format("""
Method %s in class %s should not accept a none registered value and should throw a IllegalStateException.
Got '%s' as return object.
""", MINECRAFT_TO_BUKKIT, clazz.getName(), result));
} catch (InvocationTargetException e) {
// #invoke wraps the error in a InvocationTargetException, so we need to check it this way
assertSame(IllegalStateException.class, e.getCause().getClass(), String.format("""
Method %s in class %s should not accept a none registered value and should throw a IllegalStateException.
""", MINECRAFT_TO_BUKKIT, clazz.getName()));
}
}
private void checkValidBukkitToMinecraft(Class<? extends Keyed> clazz) {
assumeTrue(BUKKIT_TO_MINECRAFT_METHODS.containsKey(clazz), String.format("""
Cannot test class %s, because it does not have a valid %s method.
Check test results of testBukkitToMinecraftPresent for more information.
""", clazz.getName(), BUKKIT_TO_MINECRAFT));
}
private void checkValidMinecraftToBukkit(Class<? extends Keyed> clazz) {
assumeTrue(MINECRAFT_TO_BUKKIT_METHODS.containsKey(clazz), String.format("""
Cannot test class %s, because it does not have a valid %s method.
Check test results of testMinecraftToBukkitPresent for more information.
""", clazz.getName(), MINECRAFT_TO_BUKKIT));
}
private void checkValidHandle(Class<? extends Keyed> clazz) {
assumeTrue(IMPLEMENT_HANDLE_ABLE.contains(clazz), String.format("""
Cannot test class %s, because it does not implement Handleable.
Check test results of testHandleableImplementation for more information.
""", clazz.getName()));
}
}

Datei anzeigen

@ -1,4 +1,4 @@
package org.bukkit; package org.bukkit.registry;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
import com.mojang.serialization.Lifecycle; import com.mojang.serialization.Lifecycle;
@ -9,6 +9,9 @@ import net.minecraft.core.IRegistry;
import net.minecraft.core.RegistryMaterials; import net.minecraft.core.RegistryMaterials;
import net.minecraft.resources.MinecraftKey; import net.minecraft.resources.MinecraftKey;
import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceKey;
import org.bukkit.Keyed;
import org.bukkit.NamespacedKey;
import org.bukkit.Registry;
import org.bukkit.craftbukkit.CraftRegistry; import org.bukkit.craftbukkit.CraftRegistry;
import org.bukkit.support.AbstractTestingBase; import org.bukkit.support.AbstractTestingBase;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;

Datei anzeigen

@ -1,9 +1,13 @@
package org.bukkit.support; package org.bukkit.support;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Keyed;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.Registry;
import org.bukkit.Server; import org.bukkit.Server;
import org.bukkit.craftbukkit.CraftLootTable; import org.bukkit.craftbukkit.CraftLootTable;
import org.bukkit.craftbukkit.CraftRegistry; import org.bukkit.craftbukkit.CraftRegistry;
@ -12,9 +16,12 @@ import org.bukkit.craftbukkit.inventory.CraftItemFactory;
import org.bukkit.craftbukkit.util.CraftMagicNumbers; import org.bukkit.craftbukkit.util.CraftMagicNumbers;
import org.bukkit.craftbukkit.util.CraftNamespacedKey; import org.bukkit.craftbukkit.util.CraftNamespacedKey;
import org.bukkit.craftbukkit.util.Versioning; import org.bukkit.craftbukkit.util.Versioning;
import org.mockito.stubbing.Answer;
public final class DummyServer { public final class DummyServer {
public static final Map<Class<?>, Registry<?>> registers = new HashMap<>();
static { static {
try { try {
Server instance = mock(withSettings().stubOnly()); Server instance = mock(withSettings().stubOnly());
@ -36,7 +43,10 @@ public final class DummyServer {
when(instance.getLootTable(any())).then(mock -> new CraftLootTable(mock.getArgument(0), when(instance.getLootTable(any())).then(mock -> new CraftLootTable(mock.getArgument(0),
AbstractTestingBase.DATA_PACK.getLootData().getLootTable(CraftNamespacedKey.toMinecraft(mock.getArgument(0))))); AbstractTestingBase.DATA_PACK.getLootData().getLootTable(CraftNamespacedKey.toMinecraft(mock.getArgument(0)))));
when(instance.getRegistry(any())).then(mock -> CraftRegistry.createRegistry(mock.getArgument(0), AbstractTestingBase.REGISTRY_CUSTOM)); when(instance.getRegistry(any())).then((Answer<Registry<?>>) mock -> {
Class<? extends Keyed> aClass = mock.getArgument(0);
return registers.computeIfAbsent(aClass, key -> CraftRegistry.createRegistry(aClass, AbstractTestingBase.REGISTRY_CUSTOM));
});
Bukkit.setServer(instance); Bukkit.setServer(instance);
} catch (Throwable t) { } catch (Throwable t) {

Datei anzeigen

@ -0,0 +1,53 @@
package org.bukkit.support.provider;
import com.google.common.collect.Lists;
import java.util.List;
import java.util.stream.Stream;
import net.minecraft.core.registries.Registries;
import net.minecraft.world.effect.MobEffectList;
import net.minecraft.world.item.Instrument;
import org.bukkit.GameEvent;
import org.bukkit.MusicInstrument;
import org.bukkit.craftbukkit.CraftGameEvent;
import org.bukkit.craftbukkit.CraftMusicInstrument;
import org.bukkit.craftbukkit.enchantments.CraftEnchantment;
import org.bukkit.craftbukkit.generator.structure.CraftStructure;
import org.bukkit.craftbukkit.generator.structure.CraftStructureType;
import org.bukkit.craftbukkit.inventory.trim.CraftTrimMaterial;
import org.bukkit.craftbukkit.inventory.trim.CraftTrimPattern;
import org.bukkit.craftbukkit.potion.CraftPotionEffectType;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.generator.structure.Structure;
import org.bukkit.generator.structure.StructureType;
import org.bukkit.inventory.meta.trim.TrimMaterial;
import org.bukkit.inventory.meta.trim.TrimPattern;
import org.bukkit.potion.PotionEffectType;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.ArgumentsProvider;
public class RegistriesArgumentProvider implements ArgumentsProvider {
private static final List<Arguments> DATA = Lists.newArrayList();
static {
// Order: Bukkit class, Minecraft Registry key, CraftBukkit class, Minecraft class
DATA.add(Arguments.of(Enchantment.class, Registries.ENCHANTMENT, CraftEnchantment.class, net.minecraft.world.item.enchantment.Enchantment.class));
DATA.add(Arguments.of(GameEvent.class, Registries.GAME_EVENT, CraftGameEvent.class, net.minecraft.world.level.gameevent.GameEvent.class));
DATA.add(Arguments.of(MusicInstrument.class, Registries.INSTRUMENT, CraftMusicInstrument.class, Instrument.class));
DATA.add(Arguments.of(PotionEffectType.class, Registries.MOB_EFFECT, CraftPotionEffectType.class, MobEffectList.class));
DATA.add(Arguments.of(Structure.class, Registries.STRUCTURE, CraftStructure.class, net.minecraft.world.level.levelgen.structure.Structure.class));
DATA.add(Arguments.of(StructureType.class, Registries.STRUCTURE_TYPE, CraftStructureType.class, net.minecraft.world.level.levelgen.structure.StructureType.class));
DATA.add(Arguments.of(TrimMaterial.class, Registries.TRIM_MATERIAL, CraftTrimMaterial.class, net.minecraft.world.item.armortrim.TrimMaterial.class));
DATA.add(Arguments.of(TrimPattern.class, Registries.TRIM_PATTERN, CraftTrimPattern.class, net.minecraft.world.item.armortrim.TrimPattern.class));
}
@Override
public Stream<? extends Arguments> provideArguments(ExtensionContext extensionContext) throws Exception {
return getData();
}
public static Stream<? extends Arguments> getData() {
return DATA.stream();
}
}

Datei anzeigen

@ -0,0 +1,33 @@
package org.bukkit.support.provider;
import java.util.stream.Stream;
import org.bukkit.Bukkit;
import org.bukkit.Keyed;
import org.bukkit.Registry;
import org.bukkit.craftbukkit.util.Handleable;
import org.bukkit.support.test.RegistryTest;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.ArgumentsProvider;
import org.junit.jupiter.params.support.AnnotationConsumer;
public class RegistryArgumentProvider implements ArgumentsProvider, AnnotationConsumer<RegistryTest> {
private Class<? extends Keyed> registryType;
@Override
public void accept(RegistryTest registryTest) {
registryType = registryTest.value();
}
@Override
public Stream<? extends Arguments> provideArguments(ExtensionContext extensionContext) throws Exception {
return getValues(registryType);
}
public static Stream<? extends Arguments> getValues(Class<? extends Keyed> registryType) {
Registry<?> registry = Bukkit.getRegistry(registryType);
return registry.stream().map(keyed -> (Handleable<?>) keyed)
.map(handleAble -> Arguments.of(handleAble, handleAble.getHandle()));
}
}

Datei anzeigen

@ -0,0 +1,19 @@
package org.bukkit.support.test;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.bukkit.support.provider.RegistriesArgumentProvider;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ArgumentsSource;
/**
* Order: Bukkit class, Minecraft Registry key, CraftBukkit class, Minecraft class
*/
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@ArgumentsSource(RegistriesArgumentProvider.class)
@ParameterizedTest
public @interface RegistriesTest {
}

Datei anzeigen

@ -0,0 +1,19 @@
package org.bukkit.support.test;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.bukkit.Keyed;
import org.bukkit.support.provider.RegistryArgumentProvider;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ArgumentsSource;
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@ArgumentsSource(RegistryArgumentProvider.class)
@ParameterizedTest
public @interface RegistryTest {
Class<? extends Keyed> value();
}