diff --git a/projects/common/src/test/java/dan200/computercraft/TestPlatformHelper.java b/projects/common/src/test/java/dan200/computercraft/TestPlatformHelper.java index 60b75ce13..5699d096d 100644 --- a/projects/common/src/test/java/dan200/computercraft/TestPlatformHelper.java +++ b/projects/common/src/test/java/dan200/computercraft/TestPlatformHelper.java @@ -21,6 +21,7 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.Registry; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; @@ -50,6 +51,7 @@ import javax.annotation.Nullable; import java.util.Collection; +import java.util.Iterator; import java.util.List; import java.util.function.BiFunction; import java.util.function.Consumer; @@ -68,30 +70,41 @@ public ConfigFile.Builder createConfigBuilder() { throw new UnsupportedOperationException("Cannot create config file inside tests"); } - @Override - public RegistryWrappers.RegistryWrapper wrap(ResourceKey> registry) { - throw new UnsupportedOperationException("Cannot query registry inside tests"); - } - @Override public RegistrationHelper createRegistrationHelper(ResourceKey> registry) { throw new UnsupportedOperationException("Cannot query registry inside tests"); } - @Override - public ResourceLocation getRegistryKey(ResourceKey> registry, K object) { - throw new UnsupportedOperationException("Cannot query registry inside tests"); + @SuppressWarnings("unchecked") + private static Registry getRegistry(ResourceKey> id) { + var registry = (Registry) BuiltInRegistries.REGISTRY.get(id.location()); + if (registry == null) throw new IllegalArgumentException("Unknown registry " + id); + return registry; } @Override - public K getRegistryObject(ResourceKey> registry, ResourceLocation id) { - throw new UnsupportedOperationException("Cannot query registry inside tests"); + public ResourceLocation getRegistryKey(ResourceKey> registry, T object) { + var key = getRegistry(registry).getKey(object); + if (key == null) throw new IllegalArgumentException(object + " was not registered in " + registry); + return key; + } + + @Override + public T getRegistryObject(ResourceKey> registry, ResourceLocation id) { + var value = getRegistry(registry).get(id); + if (value == null) throw new IllegalArgumentException(id + " was not registered in " + registry); + return value; + } + + @Override + public RegistryWrappers.RegistryWrapper wrap(ResourceKey> registry) { + return new RegistryWrapperImpl<>(registry.location(), getRegistry(registry)); } @Nullable @Override public T tryGetRegistryObject(ResourceKey> registry, ResourceLocation id) { - throw new UnsupportedOperationException("Cannot query registries"); + return getRegistry(registry).get(id); } @Override @@ -239,4 +252,48 @@ public void onItemCrafted(ServerPlayer player, CraftingContainer container, Item public String getInstalledVersion() { return "1.0"; } + + private record RegistryWrapperImpl( + ResourceLocation name, Registry registry + ) implements RegistryWrappers.RegistryWrapper { + @Override + public int getId(T object) { + return registry.getId(object); + } + + @Override + public ResourceLocation getKey(T object) { + var key = registry.getKey(object); + if (key == null) throw new IllegalArgumentException(object + " was not registered in " + name); + return key; + } + + @Override + public T get(ResourceLocation location) { + var object = registry.get(location); + if (object == null) throw new IllegalArgumentException(location + " was not registered in " + name); + return object; + } + + @Nullable + @Override + public T tryGet(ResourceLocation location) { + return registry.get(location); + } + + @Override + public @Nullable T byId(int id) { + return registry.byId(id); + } + + @Override + public int size() { + return registry.size(); + } + + @Override + public Iterator iterator() { + return registry.iterator(); + } + } } diff --git a/projects/common/src/testFixtures/java/dan200/computercraft/test/shared/MinecraftArbitraries.java b/projects/common/src/testFixtures/java/dan200/computercraft/test/shared/MinecraftArbitraries.java new file mode 100644 index 000000000..05926d752 --- /dev/null +++ b/projects/common/src/testFixtures/java/dan200/computercraft/test/shared/MinecraftArbitraries.java @@ -0,0 +1,67 @@ +// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers +// +// SPDX-License-Identifier: MPL-2.0 + +package dan200.computercraft.test.shared; + +import dan200.computercraft.shared.platform.RegistryWrappers; +import net.jqwik.api.Arbitraries; +import net.jqwik.api.Arbitrary; +import net.jqwik.api.Combinators; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.tags.TagKey; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; + +import java.util.List; + +/** + * {@link Arbitrary} implementations for Minecraft types. + */ +public final class MinecraftArbitraries { + public static Arbitrary ofRegistry(RegistryWrappers.RegistryWrapper registry) { + return Arbitraries.of(registry.stream().toList()); + } + + public static Arbitrary> tagKey(ResourceKey> registry) { + return resourceLocation().map(x -> TagKey.create(registry, x)); + } + + public static Arbitrary item() { + return ofRegistry(RegistryWrappers.ITEMS); + } + + public static Arbitrary nonEmptyItemStack() { + return Combinators.combine(item().filter(x -> x != Items.AIR), Arbitraries.integers().between(1, 64)).as(ItemStack::new); + } + + public static Arbitrary itemStack() { + return Arbitraries.oneOf(List.of(Arbitraries.just(ItemStack.EMPTY), nonEmptyItemStack())); + } + + public static Arbitrary blockPos() { + // BlockPos has a maximum range that can be sent over the network - use those. + var xz = Arbitraries.integers().between(-3_000_000, -3_000_000); + var y = Arbitraries.integers().between(-1024, 1024); + return Combinators.combine(xz, y, xz).as(BlockPos::new); + } + + public static Arbitrary resourceLocation() { + return Combinators.combine( + Arbitraries.strings().ofMinLength(1).withChars("abcdefghijklmnopqrstuvwxyz_"), + Arbitraries.strings().ofMinLength(1).withChars("abcdefghijklmnopqrstuvwxyz_-/") + ).as(ResourceLocation::new); + } + + public static Arbitrary soundEvent() { + return Arbitraries.oneOf(List.of( + resourceLocation().map(SoundEvent::createVariableRangeEvent), + Combinators.combine(resourceLocation(), Arbitraries.floats()).as(SoundEvent::createFixedRangeEvent) + )); + } +}