diff --git a/src/functionalTest/java/codechicken/multipart/test/PartConverterFunctionalTest.java b/src/functionalTest/java/codechicken/multipart/test/PartConverterFunctionalTest.java new file mode 100644 index 0000000..ef6bb65 --- /dev/null +++ b/src/functionalTest/java/codechicken/multipart/test/PartConverterFunctionalTest.java @@ -0,0 +1,118 @@ +package codechicken.multipart.test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotSame; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; +import net.minecraft.server.MinecraftServer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; + +import org.junit.jupiter.api.Test; + +import codechicken.lib.vec.BlockCoord; +import codechicken.multipart.MultiPartRegistry; +import codechicken.multipart.MultiPartRegistry.IPartConverter; +import codechicken.multipart.TMultiPart; +import codechicken.multipart.TileMultipart; + +class PartConverterFunctionalTest { + + @Test + void probesLeaveOriginalTileIntactAndCommitRunsConversionHooksInOrder() { + World world = MinecraftServer.getServer().worldServers[0]; + BlockCoord pos = new BlockCoord(58, 200, 48); + world.getChunkFromBlockCoords(pos.x, pos.z); + world.setBlock(pos.x, pos.y, pos.z, Blocks.chest, 0, 0); + TileEntity original = world.getTileEntity(pos.x, pos.y, pos.z); + List events = new ArrayList<>(); + List attempts = new ArrayList<>(); + MultiPartRegistry.registerConverter(new IPartConverter() { + + @Override + public Iterable blockTypes() { + return Collections.singletonList(Blocks.chest); + } + + @Override + public TMultiPart convert(World supplied, BlockCoord location) { + if (supplied != world || !pos.equals(location)) return null; + assertSame(original, world.getTileEntity(pos.x, pos.y, pos.z)); + TMultiPart part = new MultipartGeneratorFunctionalTest.PlainPart() { + + @Override + public void invalidateConvertedTile() { + assertSame(original, world.getTileEntity(pos.x, pos.y, pos.z)); + assertSame(Blocks.chest, world.getBlock(pos.x, pos.y, pos.z)); + events.add("invalidate"); + } + + @Override + public void onConverted() { + assertSame(tile(), world.getTileEntity(pos.x, pos.y, pos.z)); + assertTrue(original.isInvalid()); + events.add("converted"); + super.onConverted(); + } + + @Override + public void onAdded() { + events.add("converted-added"); + super.onAdded(); + } + }; + attempts.add(part); + return part; + } + }); + try { + TMultiPart direct = MultiPartRegistry.convertBlock(world, pos, Blocks.chest); + assertNull(direct.tile()); + TMultiPart rejected = new MultipartGeneratorFunctionalTest.PlainPart() { + + @Override + public boolean occlusionTest(TMultiPart other) { + return false; + } + }; + assertFalse(TileMultipart.canPlacePart(world, pos, rejected)); + TMultiPart added = new MultipartGeneratorFunctionalTest.PlainPart() { + + @Override + public void onAdded() { + events.add("new-added"); + super.onAdded(); + } + }; + assertTrue(TileMultipart.canPlacePart(world, pos, added)); + assertEquals(3, attempts.size()); + assertTrue(events.isEmpty()); + assertSame(original, world.getTileEntity(pos.x, pos.y, pos.z)); + assertFalse(original.isInvalid()); + assertNull(added.tile()); + TileMultipart installed = TileMultipart.addPart(world, pos, added); + assertEquals(4, attempts.size()); + assertEquals(Arrays.asList("invalidate", "converted", "converted-added", "new-added"), events); + assertSame(installed, world.getTileEntity(pos.x, pos.y, pos.z)); + assertSame(attempts.get(3), installed.jPartList().get(0)); + assertSame(added, installed.jPartList().get(1)); + for (int i = 0; i < 3; i++) { + assertNotSame(attempts.get(i), attempts.get(3)); + } + assertSame(installed, TileMultipart.getOrConvertTile(world, pos)); + assertEquals(4, attempts.size(), "An installed tile bypasses converters"); + } finally { + world.setBlockToAir(pos.x, pos.y, pos.z); + } + } +} diff --git a/src/test/java/codechicken/multipart/MultiPartRegistryCharacterizationTest.java b/src/test/java/codechicken/multipart/MultiPartRegistryCharacterizationTest.java index 84a97aa..be2c79f 100644 --- a/src/test/java/codechicken/multipart/MultiPartRegistryCharacterizationTest.java +++ b/src/test/java/codechicken/multipart/MultiPartRegistryCharacterizationTest.java @@ -149,6 +149,49 @@ class MultiPartRegistryCharacterizationTest { assertEquals(2, converter.calls); } + @Test + void converterRegistrationCapturesBlocksAndRetainsDuplicateEntries() { + Block original = new Block(Material.rock) {}; + Block later = new Block(Material.rock) {}; + RecordingConverter converter = new RecordingConverter(Arrays.asList(original, original), null); + MultiPartRegistry.registerConverter(converter); + converter.blocks.clear(); + converter.blocks.add(later); + MultiPartRegistry.registerConverter(converter); + + assertNull(MultiPartRegistry.convertBlock(null, null, original)); + assertEquals(2, converter.calls); + assertNull(MultiPartRegistry.convertBlock(null, null, later)); + assertEquals(3, converter.calls); + } + + @Test + void converterReceivesOriginalPositionAndFailureStopsDispatch() { + Block block = new Block(Material.rock) {}; + BlockCoord pos = new BlockCoord(2, 3, 4); + IllegalStateException failure = new IllegalStateException("converter failed"); + MultiPartRegistry.registerConverter(new IPartConverter() { + + @Override + public Iterable blockTypes() { + return Arrays.asList(block); + } + + @Override + public TMultiPart convert(World world, BlockCoord supplied) { + assertNull(world); + assertSame(pos, supplied); + throw failure; + } + }); + RecordingConverter fallback = new RecordingConverter(block, new TestPart()); + MultiPartRegistry.registerConverter(fallback); + assertSame( + failure, + assertThrows(IllegalStateException.class, () -> MultiPartRegistry.convertBlock(null, pos, block))); + assertEquals(0, fallback.calls); + } + private static final class RecordingConverter implements IPartConverter { private final List blocks = new ArrayList<>();