From 655fbf479915d61da0a8b6a5505f9e145b5b31a8 Mon Sep 17 00:00:00 2001 From: "Kristian S. Stangeland" Date: Tue, 25 Dec 2012 15:44:14 +0100 Subject: [PATCH] Added StructureModifier tests for different packet types. --- ProtocolLib/pom.xml | 18 + .../protocol/events/PacketContainerTest.java | 340 ++++++++++++++++++ 2 files changed, 358 insertions(+) create mode 100644 ProtocolLib/src/test/java/com/comphenix/protocol/events/PacketContainerTest.java diff --git a/ProtocolLib/pom.xml b/ProtocolLib/pom.xml index 1c8bec49..4fa87e38 100644 --- a/ProtocolLib/pom.xml +++ b/ProtocolLib/pom.xml @@ -8,6 +8,7 @@ cp1252 + 1.5 @@ -211,5 +212,22 @@ 4.10 test + + org.mockito + mockito-all + 1.8.4 + + + org.powermock + powermock-module-junit4 + ${powermock.version} + test + + + org.powermock + powermock-api-mockito + ${powermock.version} + test + \ No newline at end of file diff --git a/ProtocolLib/src/test/java/com/comphenix/protocol/events/PacketContainerTest.java b/ProtocolLib/src/test/java/com/comphenix/protocol/events/PacketContainerTest.java new file mode 100644 index 00000000..ce907afe --- /dev/null +++ b/ProtocolLib/src/test/java/com/comphenix/protocol/events/PacketContainerTest.java @@ -0,0 +1,340 @@ +package com.comphenix.protocol.events; + +import static org.junit.Assert.*; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.List; + +// Will have to be updated for every version though +import org.bukkit.craftbukkit.v1_4_6.inventory.CraftItemFactory; + +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.Server; +import org.bukkit.WorldType; +import org.bukkit.inventory.ItemFactory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PrepareForTest; + +import com.comphenix.protocol.Packets; +import com.comphenix.protocol.reflect.FieldUtils; +import com.comphenix.protocol.reflect.StructureModifier; +import com.comphenix.protocol.utility.MinecraftReflection; +import com.comphenix.protocol.wrappers.ChunkPosition; +import com.comphenix.protocol.wrappers.WrappedDataWatcher; +import com.comphenix.protocol.wrappers.WrappedWatchableObject; +import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; + +// Ensure that the CraftItemFactory is mockable +@RunWith(org.powermock.modules.junit4.PowerMockRunner.class) +@PrepareForTest(CraftItemFactory.class) +public class PacketContainerTest { + + @BeforeClass + public static void initializeBukkit() throws IllegalAccessException { + // Initialize reflection + MinecraftReflection.setMinecraftPackage("net.minecraft.server.v1_4_6", "org.bukkit.craftbukkit.v1_4_6"); + + // Mock the server object + Server mockedServer = mock(Server.class); + ItemFactory mockedFactory = mock(CraftItemFactory.class); + ItemMeta mockedMeta = mock(ItemMeta.class); + + when(mockedServer.getItemFactory()).thenReturn(mockedFactory); + when(mockedFactory.getItemMeta(any(Material.class))).thenReturn(mockedMeta); + + // Inject this fake server + FieldUtils.writeStaticField(Bukkit.class, "server", mockedServer, true); + + // And the fake item factory + FieldUtils.writeStaticField(CraftItemFactory.class, "instance", mockedFactory, true); + } + + private void testPrimitive(StructureModifier modifier, int index, T initialValue, T testValue) { + // Check initial value + assertEquals(initialValue, modifier.read(index)); + + // Test assignment + modifier.write(index, testValue); + assertEquals(testValue, modifier.read(0)); + } + + private void testObjectArray(StructureModifier modifier, int index, T[] initialValue, T[] testValue) { + // Check initial value + assertNull(modifier.read(index)); + modifier.writeDefaults(); + + // Test initial + assertArrayEquals(initialValue, modifier.read(index)); + + // Test assignment + modifier.write(index, testValue); + assertArrayEquals(testValue, modifier.read(0)); + } + + @Test + public void testGetByteArrays() { + // Contains a byte array we will test + PacketContainer customPayload = new PacketContainer(Packets.Server.CUSTOM_PAYLOAD); + StructureModifier bytes = customPayload.getByteArrays(); + byte[] testArray = new byte[] { 1, 2, 3 }; + + // It's NULL at first + assertArrayEquals(null, (byte[]) bytes.read(0)); + customPayload.getModifier().writeDefaults(); + + // Then it should create an empty array + assertArrayEquals(new byte[0], (byte[]) bytes.read(0)); + + // Check and see if we can write to it + bytes.write(0, testArray); + assertArrayEquals(testArray, (byte[]) bytes.read(0)); + } + + @Test + public void testGetBytes() { + PacketContainer spawnMob = new PacketContainer(Packets.Server.MOB_SPAWN); + testPrimitive(spawnMob.getBytes(), 0, (byte)0, (byte)1); + } + + @Test + public void testGetShorts() { + PacketContainer itemData = new PacketContainer(Packets.Server.ITEM_DATA); + testPrimitive(itemData.getShorts(), 0, (short)0, (short)1); + } + + @Test + public void testGetIntegers() { + PacketContainer updateSign = new PacketContainer(Packets.Server.UPDATE_SIGN); + testPrimitive(updateSign.getIntegers(), 0, (int)0, (int)1); + } + + @Test + public void testGetLongs() { + PacketContainer updateTime = new PacketContainer(Packets.Server.UPDATE_TIME); + testPrimitive(updateTime.getLongs(), 0, (long)0, (long)1); + } + + @Test + public void testGetFloat() { + PacketContainer explosion = new PacketContainer(Packets.Server.EXPLOSION); + testPrimitive(explosion.getFloat(), 0, (float)0, (float)0.8); + } + + @Test + public void testGetDoubles() { + PacketContainer explosion = new PacketContainer(Packets.Server.EXPLOSION); + testPrimitive(explosion.getDoubles(), 0, (double)0, (double)0.8); + } + + @Test + public void testGetStrings() { + PacketContainer explosion = new PacketContainer(Packets.Server.CHAT); + testPrimitive(explosion.getStrings(), 0, null, "hello"); + } + + @Test + public void testGetStringArrays() { + PacketContainer explosion = new PacketContainer(Packets.Server.UPDATE_SIGN); + testObjectArray(explosion.getStringArrays(), 0, new String[0], new String[] { "hello", "world" }); + } + + @Test + public void testGetIntegerArrays() { + // Contains a byte array we will test + PacketContainer mapChunkBulk = new PacketContainer(Packets.Server.MAP_CHUNK_BULK); + StructureModifier integers = mapChunkBulk.getIntegerArrays(); + int[] testArray = new int[] { 1, 2, 3 }; + + // Pre and post conditions + assertArrayEquals(null, (int[]) integers.read(0)); + mapChunkBulk.getModifier().writeDefaults(); + assertArrayEquals(new int[0], (int[]) integers.read(0)); + + integers.write(0, testArray); + assertArrayEquals(testArray, (int[]) integers.read(0)); + } + + @Test + public void testGetItemModifier() { + PacketContainer windowClick = new PacketContainer(Packets.Client.WINDOW_CLICK); + + StructureModifier items = windowClick.getItemModifier(); + ItemStack goldAxe = new ItemStack(Material.GOLD_AXE); + + assertNull(items.read(0)); + + // Insert the goldaxe and check if it's there + items.write(0, goldAxe); + assertTrue(equivalentItem(goldAxe, items.read(0))); + } + + @Test + public void testGetItemArrayModifier() { + PacketContainer windowItems = new PacketContainer(Packets.Server.WINDOW_ITEMS); + StructureModifier itemAccess = windowItems.getItemArrayModifier(); + + ItemStack[] itemArray = new ItemStack[] { + new ItemStack(Material.GOLD_AXE), + new ItemStack(Material.DIAMOND_AXE) + }; + + assertNull(itemAccess.read(0)); + + // Insert and check that it was succesful + itemAccess.write(0, itemArray); + + // Read back array + ItemStack[] comparision = itemAccess.read(0); + assertEquals(itemArray.length, comparision.length); + + // Check that it is equivalent + for (int i = 0; i < itemArray.length; i++) { + assertTrue(String.format("Array element %s is not the same: %s != %s", + i, itemArray[i], comparision[i]), equivalentItem(itemArray[i], comparision[i])); + } + } + + private boolean equivalentItem(ItemStack first, ItemStack second) { + if (first == null) + return second == null; + else if (second == null) + return false; + else + return first.getType().equals(second.getType()); + } + + private boolean equivalentPacket(PacketContainer first, PacketContainer second) { + if (first == null) + return second == null; + else if (second == null) + return false; + else + return first.getModifier().getValues().equals(second.getModifier().getValues()); + } + + @Test + public void testGetWorldTypeModifier() { + PacketContainer loginPacket = new PacketContainer(Packets.Server.LOGIN); + StructureModifier worldAccess = loginPacket.getWorldTypeModifier(); + + WorldType testValue = WorldType.LARGE_BIOMES; + + assertNull(worldAccess.read(0)); + + // Insert and read back + worldAccess.write(0, testValue); + assertEquals(testValue, worldAccess.read(0)); + } + + @Test + public void testGetDataWatcherModifier() { + PacketContainer mobSpawnPacket = new PacketContainer(Packets.Server.MOB_SPAWN); + StructureModifier watcherAccessor = mobSpawnPacket.getDataWatcherModifier(); + + WrappedDataWatcher dataWatcher = new WrappedDataWatcher(); + dataWatcher.setObject(1, 100); + dataWatcher.setObject(2, 125); + + assertNull(watcherAccessor.read(0)); + + // Insert and read back + watcherAccessor.write(0, dataWatcher); + assertEquals(dataWatcher, watcherAccessor.read(0)); + } + + // Unfortunately, it might be too difficult to mock this one + // + // @Test + // public void testGetEntityModifier() { } + + // No packet expose this type directly. + // + // @Test + // public void testGetPositionModifier() { } + + @Test + public void testGetPositionCollectionModifier() { + PacketContainer explosionPacket = new PacketContainer(Packets.Server.EXPLOSION); + StructureModifier> positionAccessor = explosionPacket.getPositionCollectionModifier(); + + assertNull(positionAccessor.read(0)); + + List positions = Lists.newArrayList(); + positions.add(new ChunkPosition(1, 2, 3)); + positions.add(new ChunkPosition(3, 4, 5)); + + // Insert and read back + positionAccessor.write(0, positions); + assertEquals(positions, positionAccessor.read(0)); + } + + @Test + public void testGetWatchableCollectionModifier() { + PacketContainer entityMetadata = new PacketContainer(Packets.Server.ENTITY_METADATA); + StructureModifier> watchableAccessor = + entityMetadata.getWatchableCollectionModifier(); + + assertNull(watchableAccessor.read(0)); + + WrappedDataWatcher watcher = new WrappedDataWatcher(); + watcher.setObject(1, 10); + watcher.setObject(8, 10); + + List list = watcher.getWatchableObjects(); + + // Insert and read back + watchableAccessor.write(0, list); + assertEquals(list, watchableAccessor.read(0)); + } + + @Test + public void testDeepClone() { + // Try constructing all the packets + for (Integer id : Iterables.concat( + Packets.getClientRegistry().values(), + Packets.getServerRegistry().values() )) { + + // Whether or not this packet has been registered + boolean registered = Packets.Server.isSupported(id) || + Packets.Client.isSupported(id); + + try { + PacketContainer constructed = new PacketContainer(id); + + if (!registered) { + fail("Expected IllegalArgumentException(Packet " + id + " not registered"); + } + + // Make sure these packets contains fields as well + assertTrue("Constructed packet with no known fields (" + id + ")", + constructed.getModifier().size() > 0); + + // Initialize default values + constructed.getModifier().writeDefaults(); + + // Clone the packet + PacketContainer cloned = constructed.deepClone(); + + // Make sure they're equivalent + assertTrue("Packet " + id + " could not be cloned.", equivalentPacket(constructed, cloned)); + + } catch (IllegalArgumentException e) { + if (!registered) { + // Check the same + assertEquals(e.getMessage(), "The packet ID " + id + " is not registered."); + } else { + // Something is very wrong + throw e; + } + } + } + } +}