Add tests for consistent getItemDetails behaviour

Closes #2346.
This commit is contained in:
Jonathan Coates
2025-12-28 11:01:57 +00:00
parent b481aa95f2
commit 0005ee9657
6 changed files with 128 additions and 11 deletions
@@ -25,12 +25,17 @@ import java.util.ServiceLoader;
@ExtendWith(WithMinecraft.Setup.class)
public @interface WithMinecraft {
class Setup implements Extension, BeforeAllCallback {
private static boolean setup = false;
@Override
public void beforeAll(ExtensionContext context) {
bootstrap();
}
public static void bootstrap() {
public static synchronized void bootstrap() {
if (setup) return;
setup = true;
ServiceLoader.load(SetupHook.class, SetupHook.class.getClassLoader()).forEach(SetupHook::run);
SharedConstants.tryDetectVersion();
Bootstrap.bootStrap();
@@ -0,0 +1,54 @@
// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
//
// SPDX-License-Identifier: MPL-2.0
package dan200.computercraft.test.shared.peripheral.generic.methods;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.shared.peripheral.generic.methods.AbstractInventoryMethods;
import dan200.computercraft.test.shared.WithMinecraft;
import net.minecraft.world.Container;
import net.minecraft.world.SimpleContainer;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
/**
* Test Interface defining the behaviour of a {@link AbstractInventoryMethods} implementation.
*
* @param <T> The type for inventories.
*/
@WithMinecraft
public interface InventoryMethodsContract<T> {
/**
* Create our {@link AbstractInventoryMethods} implementation.
*
* @return The inventory methods.
*/
AbstractInventoryMethods<T> create();
/**
* Wrap a basic container into a mod-loader-specific inventory.
*
* @param container The container to wrap.
* @return The wrapped inventory.
*/
T wrap(Container container);
@Test
default void testGetItemLimit() throws LuaException {
var container = new SimpleContainer(3);
container.setItem(0, new ItemStack(Items.DIRT, 1));
container.setItem(1, new ItemStack(Items.WATER_BUCKET, 1));
assertEquals(64, create().getItemLimit(wrap(container), 1), "Dirt stacks to 64");
assertEquals(1, create().getItemLimit(wrap(container), 2), "Buckets stack to 1");
assertEquals(64, create().getItemLimit(wrap(container), 3), "Empty slots stack to 64 by default");
var err = assertThrows(LuaException.class, () -> create().getItemLimit(wrap(container), 0));
assertEquals("Slot out of range (between 1 and 3)", err.getMessage());
}
}
@@ -4,6 +4,7 @@
package dan200.computercraft.shared.peripheral.generic.methods;
import com.google.common.annotations.VisibleForTesting;
import dan200.computercraft.api.detail.VanillaDetailRegistries;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.LuaFunction;
@@ -18,6 +19,7 @@ import net.fabricmc.fabric.api.transfer.v1.storage.base.CombinedStorage;
import net.fabricmc.fabric.api.transfer.v1.storage.base.SingleSlotStorage;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.HolderLookup;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
@@ -38,10 +40,15 @@ import static dan200.computercraft.core.util.ArgumentHelpers.assertBetween;
* {@link StorageWrapper} box.
*/
public final class InventoryMethods extends AbstractInventoryMethods<InventoryMethods.StorageWrapper> {
private final MinecraftServer server;
private final HolderLookup.Provider registries;
public InventoryMethods(MinecraftServer server) {
this.server = server;
public InventoryMethods(MinecraftServer registries) {
this.registries = registries.registryAccess();
}
@VisibleForTesting
InventoryMethods(HolderLookup.Provider registries) {
this.registries = registries;
}
/**
@@ -95,7 +102,7 @@ public final class InventoryMethods extends AbstractInventoryMethods<InventoryMe
for (var i = 0; i < size; i++) {
var stack = toStack(slots.get(i));
if (!stack.isEmpty()) {
result.put(i + 1, VanillaDetailRegistries.ITEM_STACK.getBasicDetails(server.registryAccess(), stack));
result.put(i + 1, VanillaDetailRegistries.ITEM_STACK.getBasicDetails(registries, stack));
}
}
@@ -109,7 +116,7 @@ public final class InventoryMethods extends AbstractInventoryMethods<InventoryMe
assertBetween(slot, 1, inventory.storage().getSlotCount(), "Slot out of range (%s)");
var stack = toStack(inventory.storage().getSlot(slot - 1));
return stack.isEmpty() ? null : VanillaDetailRegistries.ITEM_STACK.getDetails(server.registryAccess(), stack);
return stack.isEmpty() ? null : VanillaDetailRegistries.ITEM_STACK.getDetails(registries, stack);
}
@Override
@@ -0,0 +1,22 @@
// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
//
// SPDX-License-Identifier: MPL-2.0
package dan200.computercraft.shared.peripheral.generic.methods;
import dan200.computercraft.test.shared.peripheral.generic.methods.InventoryMethodsContract;
import net.fabricmc.fabric.api.transfer.v1.item.InventoryStorage;
import net.minecraft.core.RegistryAccess;
import net.minecraft.world.Container;
public class InventoryMethodsTest implements InventoryMethodsContract<InventoryMethods.StorageWrapper> {
@Override
public AbstractInventoryMethods<InventoryMethods.StorageWrapper> create() {
return new InventoryMethods(RegistryAccess.EMPTY);
}
@Override
public InventoryMethods.StorageWrapper wrap(Container container) {
return new InventoryMethods.StorageWrapper(InventoryStorage.of(container, null));
}
}
@@ -4,6 +4,7 @@
package dan200.computercraft.shared.peripheral.generic.methods;
import com.google.common.annotations.VisibleForTesting;
import dan200.computercraft.api.detail.VanillaDetailRegistries;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.LuaFunction;
@@ -13,6 +14,7 @@ import dan200.computercraft.shared.platform.ForgeContainerTransfer;
import dan200.computercraft.shared.util.CapabilityUtil;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.HolderLookup;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.Container;
@@ -35,10 +37,15 @@ import static dan200.computercraft.core.util.ArgumentHelpers.assertBetween;
* Inventory methods for Forge's {@link ResourceHandler}.
*/
public final class InventoryMethods extends AbstractInventoryMethods<InventoryMethods.StorageWrapper> {
private final MinecraftServer server;
private final HolderLookup.Provider registries;
public InventoryMethods(MinecraftServer server) {
this.server = server;
public InventoryMethods(MinecraftServer registries) {
this.registries = registries.registryAccess();
}
@VisibleForTesting
InventoryMethods(HolderLookup.Provider registries) {
this.registries = registries;
}
public record StorageWrapper(ResourceHandler<ItemResource> storage) {
@@ -59,7 +66,7 @@ public final class InventoryMethods extends AbstractInventoryMethods<InventoryMe
for (var i = 0; i < size; i++) {
var stack = storage.getResource(i).toStack(storage.getAmountAsInt(i));
if (!stack.isEmpty()) {
result.put(i + 1, VanillaDetailRegistries.ITEM_STACK.getBasicDetails(server.registryAccess(), stack));
result.put(i + 1, VanillaDetailRegistries.ITEM_STACK.getBasicDetails(registries, stack));
}
}
@@ -74,7 +81,7 @@ public final class InventoryMethods extends AbstractInventoryMethods<InventoryMe
assertBetween(slot, 1, storage.size(), "Slot out of range (%s)");
var stack = storage.getResource(slot - 1).toStack(storage.getAmountAsInt(slot - 1));
return stack.isEmpty() ? null : VanillaDetailRegistries.ITEM_STACK.getDetails(server.registryAccess(), stack);
return stack.isEmpty() ? null : VanillaDetailRegistries.ITEM_STACK.getDetails(registries, stack);
}
@Override
@@ -0,0 +1,22 @@
// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
//
// SPDX-License-Identifier: MPL-2.0
package dan200.computercraft.shared.peripheral.generic.methods;
import dan200.computercraft.test.shared.peripheral.generic.methods.InventoryMethodsContract;
import net.minecraft.core.RegistryAccess;
import net.minecraft.world.Container;
import net.neoforged.neoforge.transfer.item.VanillaContainerWrapper;
public class InventoryMethodsTest implements InventoryMethodsContract<InventoryMethods.StorageWrapper> {
@Override
public AbstractInventoryMethods<InventoryMethods.StorageWrapper> create() {
return new InventoryMethods(RegistryAccess.EMPTY);
}
@Override
public InventoryMethods.StorageWrapper wrap(Container container) {
return new InventoryMethods.StorageWrapper(VanillaContainerWrapper.of(container));
}
}