Refactorer BlockInteractionListener and added test class

May fix:

https://github.com/BentoBoxWorld/BentoBox/issues/1023
This commit is contained in:
tastybento 2019-11-05 21:45:26 -08:00
parent 77a3797d3b
commit c56b9bec18
4 changed files with 924 additions and 294 deletions

View File

@ -1,5 +1,6 @@
package world.bentobox.bentobox.listeners.flags.protection;
import java.util.EnumMap;
import java.util.Map;
import java.util.Optional;
@ -29,306 +30,208 @@ import world.bentobox.bentobox.lists.Flags;
*/
public class BlockInteractionListener extends FlagListener {
/**
* These cover materials in another server version.
* This avoids run time errors due to unknown enum values, at the expense of a string comparison
*/
private final Map<String, String> stringFlags = ImmutableMap.<String, String>builder()
.build();
static final Map<Material, Flag> IN_HAND_ITEMS = new EnumMap<Material, Flag>(Material.class) {
private static final long serialVersionUID = 1L;
{
put(Material.ENDER_PEARL, Flags.ENDER_PEARL);
put(Material.BONE_MEAL, Flags.PLACE_BLOCKS);
}};
/**
* Handle interaction with blocks
* @param e - event
*/
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onPlayerInteract(final PlayerInteractEvent e) {
// For some items, we need to do a specific check for RIGHT_CLICK_BLOCK
if (e.getAction().equals(Action.RIGHT_CLICK_BLOCK)
&& e.getClickedBlock().getType().equals(Material.ITEM_FRAME)) {
checkIsland(e, e.getPlayer(), e.getClickedBlock().getLocation(), Flags.ITEM_FRAME);
return;
}
static final Map<Material, Flag> CLICKED_BLOCKS = new EnumMap<Material, Flag>(Material.class) {
private static final long serialVersionUID = 1L;
{
put(Material.ANVIL, Flags.ANVIL);
put(Material.CHIPPED_ANVIL, Flags.ANVIL);
put(Material.DAMAGED_ANVIL, Flags.ANVIL);
put(Material.BEACON, Flags.BEACON);
put(Material.BLACK_BED, Flags.BED);
put(Material.BLUE_BED, Flags.BED);
put(Material.BROWN_BED, Flags.BED);
put(Material.CYAN_BED, Flags.BED);
put(Material.GRAY_BED, Flags.BED);
put(Material.GREEN_BED, Flags.BED);
put(Material.LIGHT_BLUE_BED, Flags.BED);
put(Material.LIGHT_GRAY_BED, Flags.BED);
put(Material.LIME_BED, Flags.BED);
put(Material.MAGENTA_BED, Flags.BED);
put(Material.ORANGE_BED, Flags.BED);
put(Material.PINK_BED, Flags.BED);
put(Material.PURPLE_BED, Flags.BED);
put(Material.RED_BED, Flags.BED);
put(Material.WHITE_BED, Flags.BED);
put(Material.YELLOW_BED, Flags.BED);
put(Material.BREWING_STAND, Flags.BREWING);
put(Material.CAULDRON, Flags.BREWING);
put(Material.BARREL, Flags.CONTAINER);
put(Material.CHEST, Flags.CONTAINER);
put(Material.CHEST_MINECART, Flags.CONTAINER);
put(Material.TRAPPED_CHEST, Flags.CONTAINER);
put(Material.BLACK_SHULKER_BOX, Flags.CONTAINER);
put(Material.BLUE_SHULKER_BOX, Flags.CONTAINER);
put(Material.BROWN_SHULKER_BOX, Flags.CONTAINER);
put(Material.CYAN_SHULKER_BOX, Flags.CONTAINER);
put(Material.GRAY_SHULKER_BOX, Flags.CONTAINER);
put(Material.GREEN_SHULKER_BOX, Flags.CONTAINER);
put(Material.LIGHT_BLUE_SHULKER_BOX, Flags.CONTAINER);
put(Material.LIME_SHULKER_BOX, Flags.CONTAINER);
put(Material.PINK_SHULKER_BOX, Flags.CONTAINER);
put(Material.MAGENTA_SHULKER_BOX, Flags.CONTAINER);
put(Material.ORANGE_SHULKER_BOX, Flags.CONTAINER);
put(Material.PURPLE_SHULKER_BOX, Flags.CONTAINER);
put(Material.RED_SHULKER_BOX, Flags.CONTAINER);
put(Material.LIGHT_GRAY_SHULKER_BOX, Flags.CONTAINER);
put(Material.WHITE_SHULKER_BOX, Flags.CONTAINER);
put(Material.YELLOW_SHULKER_BOX, Flags.CONTAINER);
put(Material.SHULKER_BOX, Flags.CONTAINER);
put(Material.FLOWER_POT, Flags.CONTAINER);
put(Material.COMPOSTER, Flags.CONTAINER);
put(Material.DISPENSER, Flags.DISPENSER);
put(Material.DROPPER, Flags.DROPPER);
put(Material.HOPPER, Flags.HOPPER);
put(Material.HOPPER_MINECART, Flags.HOPPER);
put(Material.ACACIA_DOOR, Flags.DOOR);
put(Material.BIRCH_DOOR, Flags.DOOR);
put(Material.DARK_OAK_DOOR, Flags.DOOR);
put(Material.IRON_DOOR, Flags.DOOR);
put(Material.JUNGLE_DOOR, Flags.DOOR);
put(Material.SPRUCE_DOOR, Flags.DOOR);
put(Material.OAK_DOOR, Flags.DOOR);
put(Material.ACACIA_TRAPDOOR, Flags.TRAPDOOR);
put(Material.BIRCH_TRAPDOOR, Flags.TRAPDOOR);
put(Material.DARK_OAK_TRAPDOOR, Flags.TRAPDOOR);
put(Material.OAK_TRAPDOOR, Flags.TRAPDOOR);
put(Material.JUNGLE_TRAPDOOR, Flags.TRAPDOOR);
put(Material.SPRUCE_TRAPDOOR, Flags.TRAPDOOR);
put(Material.IRON_TRAPDOOR, Flags.TRAPDOOR);
put(Material.ACACIA_FENCE_GATE, Flags.GATE);
put(Material.BIRCH_FENCE_GATE, Flags.GATE);
put(Material.DARK_OAK_FENCE_GATE, Flags.GATE);
put(Material.OAK_FENCE_GATE, Flags.GATE);
put(Material.JUNGLE_FENCE_GATE, Flags.GATE);
put(Material.SPRUCE_FENCE_GATE, Flags.GATE);
put(Material.BLAST_FURNACE, Flags.FURNACE);
put(Material.CAMPFIRE, Flags.FURNACE);
put(Material.FURNACE_MINECART, Flags.FURNACE);
put(Material.FURNACE, Flags.FURNACE);
put(Material.SMOKER, Flags.FURNACE);
put(Material.ENCHANTING_TABLE, Flags.ENCHANTING);
put(Material.ENDER_CHEST, Flags.ENDER_CHEST);
put(Material.JUKEBOX, Flags.JUKEBOX);
put(Material.NOTE_BLOCK, Flags.NOTE_BLOCK);
put(Material.CRAFTING_TABLE, Flags.CRAFTING);
put(Material.CARTOGRAPHY_TABLE, Flags.CRAFTING);
put(Material.GRINDSTONE, Flags.CRAFTING);
put(Material.STONECUTTER, Flags.CRAFTING);
put(Material.LOOM, Flags.CRAFTING);
put(Material.STONE_BUTTON, Flags.BUTTON);
put(Material.ACACIA_BUTTON, Flags.BUTTON);
put(Material.BIRCH_BUTTON, Flags.BUTTON);
put(Material.DARK_OAK_BUTTON, Flags.BUTTON);
put(Material.JUNGLE_BUTTON, Flags.BUTTON);
put(Material.OAK_BUTTON, Flags.BUTTON);
put(Material.SPRUCE_BUTTON, Flags.BUTTON);
put(Material.LEVER, Flags.LEVER);
put(Material.REPEATER, Flags.REDSTONE);
put(Material.COMPARATOR, Flags.REDSTONE);
put(Material.DAYLIGHT_DETECTOR, Flags.REDSTONE);
put(Material.DRAGON_EGG, Flags.DRAGON_EGG);
put(Material.END_PORTAL_FRAME, Flags.PLACE_BLOCKS);
put(Material.ITEM_FRAME, Flags.ITEM_FRAME);
put(Material.LECTERN, Flags.BREAK_BLOCKS);
put(Material.SWEET_BERRY_BUSH, Flags.BREAK_BLOCKS);
put(Material.CAKE, Flags.CAKE);
}};
// We only care about the RIGHT_CLICK_BLOCK action.
if (!e.getAction().equals(Action.RIGHT_CLICK_BLOCK)) {
return;
}
// Check clicked block
checkClickedBlock(e, e.getPlayer(), e.getClickedBlock().getLocation(), e.getClickedBlock().getType());
/**
* These cover materials in another server version.
* This avoids run time errors due to unknown enum values, at the expense of a string comparison
*/
private final Map<String, String> stringFlags = ImmutableMap.<String, String>builder()
.build();
// Now check for in-hand items
if (e.getItem() != null) {
if (e.getItem().getType().name().contains("BOAT")) {
checkIsland(e, e.getPlayer(), e.getClickedBlock().getLocation(), Flags.PLACE_BLOCKS);
return;
/**
* Handle interaction with blocks
* @param e - event
*/
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onPlayerInteract(final PlayerInteractEvent e) {
// We only care about the RIGHT_CLICK_BLOCK action.
if (!e.getAction().equals(Action.RIGHT_CLICK_BLOCK)) {
return;
}
// Check clicked block
checkClickedBlock(e, e.getPlayer(), e.getClickedBlock().getLocation(), e.getClickedBlock().getType());
// Now check for in-hand items
if (e.getItem() != null && !e.getItem().getType().equals(Material.AIR)) {
// Boats
if (e.getItem().getType().name().endsWith("_BOAT")) {
checkIsland(e, e.getPlayer(), e.getClickedBlock().getLocation(), Flags.PLACE_BLOCKS);
return;
}
// Spawn eggs
else if (e.getItem().getType().name().endsWith("_SPAWN_EGG")) {
checkIsland(e, e.getPlayer(), e.getClickedBlock().getLocation(), Flags.SPAWN_EGGS);
return;
}
// Other items
else if (IN_HAND_ITEMS.containsKey(e.getItem().getType())) {
checkIsland(e, e.getPlayer(), e.getClickedBlock().getLocation(), IN_HAND_ITEMS.get(e.getItem().getType()));
}
}
}
switch (e.getItem().getType()) {
case ENDER_PEARL:
checkIsland(e, e.getPlayer(), e.getClickedBlock().getLocation(), Flags.ENDER_PEARL);
break;
case BONE_MEAL:
checkIsland(e, e.getPlayer(), e.getClickedBlock().getLocation(), Flags.PLACE_BLOCKS);
break;
case BAT_SPAWN_EGG:
case BLAZE_SPAWN_EGG:
case CAVE_SPIDER_SPAWN_EGG:
case CHICKEN_SPAWN_EGG:
case COD_SPAWN_EGG:
case COW_SPAWN_EGG:
case CREEPER_SPAWN_EGG:
case DOLPHIN_SPAWN_EGG:
case DONKEY_SPAWN_EGG:
case DROWNED_SPAWN_EGG:
case ELDER_GUARDIAN_SPAWN_EGG:
case ENDERMAN_SPAWN_EGG:
case ENDERMITE_SPAWN_EGG:
case EVOKER_SPAWN_EGG:
case GHAST_SPAWN_EGG:
case GUARDIAN_SPAWN_EGG:
case HORSE_SPAWN_EGG:
case HUSK_SPAWN_EGG:
case LLAMA_SPAWN_EGG:
case MAGMA_CUBE_SPAWN_EGG:
case MOOSHROOM_SPAWN_EGG:
case MULE_SPAWN_EGG:
case OCELOT_SPAWN_EGG:
case PARROT_SPAWN_EGG:
case PHANTOM_SPAWN_EGG:
case PIG_SPAWN_EGG:
case POLAR_BEAR_SPAWN_EGG:
case PUFFERFISH_SPAWN_EGG:
case RABBIT_SPAWN_EGG:
case SALMON_SPAWN_EGG:
case SHEEP_SPAWN_EGG:
case SHULKER_SPAWN_EGG:
case SILVERFISH_SPAWN_EGG:
case SKELETON_HORSE_SPAWN_EGG:
case SKELETON_SPAWN_EGG:
case SLIME_SPAWN_EGG:
case SPIDER_SPAWN_EGG:
case SQUID_SPAWN_EGG:
case STRAY_SPAWN_EGG:
case TROPICAL_FISH_SPAWN_EGG:
case TURTLE_SPAWN_EGG:
case VEX_SPAWN_EGG:
case VILLAGER_SPAWN_EGG:
case VINDICATOR_SPAWN_EGG:
case WITCH_SPAWN_EGG:
case WITHER_SKELETON_SPAWN_EGG:
case WOLF_SPAWN_EGG:
case ZOMBIE_HORSE_SPAWN_EGG:
case ZOMBIE_PIGMAN_SPAWN_EGG:
case ZOMBIE_SPAWN_EGG:
case ZOMBIE_VILLAGER_SPAWN_EGG:
checkIsland(e, e.getPlayer(), e.getClickedBlock().getLocation(), Flags.SPAWN_EGGS);
break;
default:
break;
/**
* Check if an action can occur on a clicked block
* @param e - event called
* @param player - player
* @param loc - location of clicked block
* @param type - material type of clicked block
*/
private void checkClickedBlock(Event e, Player player, Location loc, Material type) {
// Handle pots
if (type.name().startsWith("POTTED")) {
checkIsland(e, player, loc, Flags.CONTAINER);
return;
}
if (CLICKED_BLOCKS.containsKey(type)) {
checkIsland(e, player, loc, CLICKED_BLOCKS.get(type));
}
if (stringFlags.containsKey(type.name())) {
Optional<Flag> f = BentoBox.getInstance().getFlagsManager().getFlag(stringFlags.get(type.name()));
f.ifPresent(flag -> checkIsland(e, player, loc, flag));
}
}
}
}
/**
* Check if an action can occur on a clicked block
* @param e - event called
* @param player - player
* @param loc - location of clicked block
* @param type - material type of clicked block
*/
private void checkClickedBlock(Event e, Player player, Location loc, Material type) {
// Handle pots
if (type.name().startsWith("POTTED")) {
checkIsland(e, player, loc, Flags.CONTAINER);
return;
}
switch (type) {
case ANVIL:
case CHIPPED_ANVIL:
case DAMAGED_ANVIL:
checkIsland(e, player, loc, Flags.ANVIL);
break;
case BEACON:
checkIsland(e, player, loc, Flags.BEACON);
break;
case BLACK_BED:
case BLUE_BED:
case BROWN_BED:
case CYAN_BED:
case GRAY_BED:
case GREEN_BED:
case LIGHT_BLUE_BED:
case LIGHT_GRAY_BED:
case LIME_BED:
case MAGENTA_BED:
case ORANGE_BED:
case PINK_BED:
case PURPLE_BED:
case RED_BED:
case WHITE_BED:
case YELLOW_BED:
checkIsland(e, player, loc, Flags.BED);
break;
case BREWING_STAND:
case CAULDRON:
checkIsland(e, player, loc, Flags.BREWING);
break;
case BARREL:
case CHEST:
case CHEST_MINECART:
case TRAPPED_CHEST:
case BLACK_SHULKER_BOX:
case BLUE_SHULKER_BOX:
case BROWN_SHULKER_BOX:
case CYAN_SHULKER_BOX:
case GRAY_SHULKER_BOX:
case GREEN_SHULKER_BOX:
case LIGHT_BLUE_SHULKER_BOX:
case LIME_SHULKER_BOX:
case PINK_SHULKER_BOX:
case MAGENTA_SHULKER_BOX:
case ORANGE_SHULKER_BOX:
case PURPLE_SHULKER_BOX:
case RED_SHULKER_BOX:
case LIGHT_GRAY_SHULKER_BOX:
case WHITE_SHULKER_BOX:
case YELLOW_SHULKER_BOX:
case SHULKER_BOX:
case FLOWER_POT:
case COMPOSTER:
checkIsland(e, player, loc, Flags.CONTAINER);
break;
case DISPENSER:
checkIsland(e, player, loc, Flags.DISPENSER);
break;
case DROPPER:
checkIsland(e, player, loc, Flags.DROPPER);
break;
case HOPPER:
case HOPPER_MINECART:
checkIsland(e, player, loc, Flags.HOPPER);
break;
case ACACIA_DOOR:
case BIRCH_DOOR:
case DARK_OAK_DOOR:
case IRON_DOOR:
case JUNGLE_DOOR:
case SPRUCE_DOOR:
case OAK_DOOR:
checkIsland(e, player, loc, Flags.DOOR);
break;
case ACACIA_TRAPDOOR:
case BIRCH_TRAPDOOR:
case DARK_OAK_TRAPDOOR:
case OAK_TRAPDOOR:
case JUNGLE_TRAPDOOR:
case SPRUCE_TRAPDOOR:
case IRON_TRAPDOOR:
checkIsland(e, player, loc, Flags.TRAPDOOR);
break;
case ACACIA_FENCE_GATE:
case BIRCH_FENCE_GATE:
case DARK_OAK_FENCE_GATE:
case OAK_FENCE_GATE:
case JUNGLE_FENCE_GATE:
case SPRUCE_FENCE_GATE:
checkIsland(e, player, loc, Flags.GATE);
break;
case BLAST_FURNACE:
case CAMPFIRE:
case FURNACE_MINECART:
case FURNACE:
case SMOKER:
checkIsland(e, player, loc, Flags.FURNACE);
break;
case ENCHANTING_TABLE:
checkIsland(e, player, loc, Flags.ENCHANTING);
break;
case ENDER_CHEST:
checkIsland(e, player, loc, Flags.ENDER_CHEST);
break;
case JUKEBOX:
checkIsland(e, player, loc, Flags.JUKEBOX);
break;
case NOTE_BLOCK:
checkIsland(e, player, loc, Flags.NOTE_BLOCK);
break;
case CRAFTING_TABLE:
case CARTOGRAPHY_TABLE:
case GRINDSTONE:
case STONECUTTER:
case LOOM:
checkIsland(e, player, loc, Flags.CRAFTING);
break;
case STONE_BUTTON:
case ACACIA_BUTTON:
case BIRCH_BUTTON:
case DARK_OAK_BUTTON:
case JUNGLE_BUTTON:
case OAK_BUTTON:
case SPRUCE_BUTTON:
checkIsland(e, player, loc, Flags.BUTTON);
break;
case LEVER:
checkIsland(e, player, loc, Flags.LEVER);
break;
case REPEATER:
case COMPARATOR:
case DAYLIGHT_DETECTOR:
checkIsland(e, player, loc, Flags.REDSTONE);
break;
case DRAGON_EGG:
checkIsland(e, player, loc, Flags.DRAGON_EGG);
break;
case END_PORTAL_FRAME:
checkIsland(e, player, loc, Flags.PLACE_BLOCKS);
break;
case ITEM_FRAME:
checkIsland(e, player, loc, Flags.ITEM_FRAME);
break;
case LECTERN:
case SWEET_BERRY_BUSH:
checkIsland(e, player, loc, Flags.BREAK_BLOCKS);
break;
case CAKE:
checkIsland(e, player, loc, Flags.CAKE);
break;
default:
if (stringFlags.containsKey(type.name())) {
Optional<Flag> f = BentoBox.getInstance().getFlagsManager().getFlag(stringFlags.get(type.name()));
f.ifPresent(flag -> checkIsland(e, player, loc, flag));
/**
* When breaking blocks is allowed, this protects
* specific blocks from being broken, which would bypass the protection.
* For example, player enables break blocks, but chests are still protected
* Fires after the BreakBlocks check.
*
* @param e - event
*/
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onBlockBreak(final BlockBreakEvent e) {
checkClickedBlock(e, e.getPlayer(), e.getBlock().getLocation(), e.getBlock().getType());
}
}
}
/**
* When breaking blocks is allowed, this protects
* specific blocks from being broken, which would bypass the protection.
* For example, player enables break blocks, but chests are still protected
* Fires after the BreakBlocks check.
*
* @param e - event
*/
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onBlockBreak(final BlockBreakEvent e) {
checkClickedBlock(e, e.getPlayer(), e.getBlock().getLocation(), e.getBlock().getType());
}
/**
* Prevents dragon eggs from flying out of an island's protected space
* @param e - event
*/
@EventHandler(priority = EventPriority.LOWEST)
public void onDragonEggTeleport(BlockFromToEvent e) {
Block block = e.getBlock();
if (!block.getType().equals(Material.DRAGON_EGG) || !getIWM().inWorld(block.getLocation())) {
return;
}
// If egg starts in a protected island...
// Cancel if toIsland is not fromIsland or if there is no protected island there
// This protects against eggs dropping into adjacent islands, e.g. island distance and protection range are equal
Optional<Island> fromIsland = getIslands().getProtectedIslandAt(block.getLocation());
Optional<Island> toIsland = getIslands().getProtectedIslandAt(e.getToBlock().getLocation());
fromIsland.ifPresent(from -> e.setCancelled(toIsland.map(to -> to != from).orElse(true)));
}
/**
* Prevents dragon eggs from flying out of an island's protected space
* @param e - event
*/
@EventHandler(priority = EventPriority.LOWEST)
public void onDragonEggTeleport(BlockFromToEvent e) {
Block block = e.getBlock();
if (!block.getType().equals(Material.DRAGON_EGG) || !getIWM().inWorld(block.getLocation())) {
return;
}
// If egg starts in a protected island...
// Cancel if toIsland is not fromIsland or if there is no protected island there
// This protects against eggs dropping into adjacent islands, e.g. island distance and protection range are equal
Optional<Island> fromIsland = getIslands().getProtectedIslandAt(block.getLocation());
Optional<Island> toIsland = getIslands().getProtectedIslandAt(e.getToBlock().getLocation());
fromIsland.ifPresent(from -> e.setCancelled(toIsland.map(to -> to != from).orElse(true)));
}
}

View File

@ -0,0 +1,329 @@
package world.bentobox.bentobox.listeners.flags.protection;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.Arrays;
import java.util.Collections;
import java.util.Optional;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Player;
import org.bukkit.event.Event;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemFactory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.metadata.FixedMetadataValue;
import org.bukkit.metadata.MetadataValue;
import org.bukkit.plugin.PluginManager;
import org.eclipse.jdt.annotation.Nullable;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.configuration.WorldSettings;
import world.bentobox.bentobox.api.flags.Flag.Type;
import world.bentobox.bentobox.api.user.Notifier;
import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.bentobox.lists.Flags;
import world.bentobox.bentobox.managers.IslandWorldManager;
import world.bentobox.bentobox.managers.IslandsManager;
import world.bentobox.bentobox.managers.LocalesManager;
import world.bentobox.bentobox.managers.PlaceholdersManager;
/**
* @author tastybento
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({Bukkit.class, BentoBox.class})
public class BlockInteractionListenerTest {
@Mock
private Player player;
@Mock
private PluginManager pim;
@Mock
private ItemFactory itemFactory;
@Mock
private Location location;
@Mock
private World world;
private UUID uuid = UUID.randomUUID();
@Mock
private IslandWorldManager iwm;
@Mock
private IslandsManager im;
@Mock
private Island island;
@Mock
private BentoBox plugin;
@Mock
private PlayerInventory inv;
@Mock
private Notifier notifier;
private EquipmentSlot hand;
private BlockInteractionListener bil;
@Mock
private ItemStack item;
@Mock
private Block clickedBlock;
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
// Set up plugin
Whitebox.setInternalState(BentoBox.class, "instance", plugin);
// Bukkit
PowerMockito.mockStatic(Bukkit.class);
when(Bukkit.getPluginManager()).thenReturn(pim);
when(Bukkit.getItemFactory()).thenReturn(itemFactory);
// Location
when(location.getWorld()).thenReturn(world);
when(location.getBlockX()).thenReturn(0);
when(location.getBlockY()).thenReturn(0);
when(location.getBlockZ()).thenReturn(0);
// Clicked block
when(clickedBlock.getLocation()).thenReturn(location);
when(clickedBlock.getType()).thenReturn(Material.ITEM_FRAME);
// Player
when(player.getUniqueId()).thenReturn(uuid);
when(player.getLocation()).thenReturn(location);
when(player.getWorld()).thenReturn(world);
User.setPlugin(plugin);
User.getInstance(player);
// IWM
when(plugin.getIWM()).thenReturn(iwm);
when(iwm.inWorld(any(Location.class))).thenReturn(true);
when(iwm.inWorld(any(World.class))).thenReturn(true);
@Nullable
WorldSettings worldSet = new TestWorldSettings();
when(iwm.getWorldSettings(any())).thenReturn(worldSet);
// Island Manager
when(plugin.getIslands()).thenReturn(im);
Optional<Island> optionalIsland = Optional.of(island);
when(im.getProtectedIslandAt(any())).thenReturn(optionalIsland);
// Island - nothing is allowed by default
when(island.isAllowed(any())).thenReturn(false);
when(island.isAllowed(any(), any())).thenReturn(false);
// Inventory
hand = EquipmentSlot.HAND;
// Nothing in hand right now
when(item.getType()).thenReturn(Material.AIR);
when(player.getInventory()).thenReturn(inv);
// Enable reporting from Flags class
MetadataValue mdv = new FixedMetadataValue(plugin, "_why_debug");
when(player.getMetadata(anyString())).thenReturn(Collections.singletonList(mdv));
// Locales & Placeholders
LocalesManager lm = mock(LocalesManager.class);
when(lm.get(any(), any())).thenAnswer((Answer<String>) invocation -> invocation.getArgument(1, String.class));
PlaceholdersManager phm = mock(PlaceholdersManager.class);
when(plugin.getPlaceholdersManager()).thenReturn(phm);
when(phm.replacePlaceholders(any(), any())).thenAnswer((Answer<String>) invocation -> invocation.getArgument(1, String.class));
when(plugin.getLocalesManager()).thenReturn(lm);
// Notifier
when(plugin.getNotifier()).thenReturn(notifier);
// Class under test
bil = new BlockInteractionListener();
}
/**
* @throws java.lang.Exception
*/
@After
public void tearDown() throws Exception {
User.clearUsers();
}
/**
* Test method for {@link world.bentobox.bentobox.listeners.flags.protection.BlockInteractionListener#onPlayerInteract(org.bukkit.event.player.PlayerInteractEvent)}.
*/
@Test
public void testOnPlayerInteractItemFrameNotAllowed() {
when(clickedBlock.getType()).thenReturn(Material.ITEM_FRAME);
PlayerInteractEvent e = new PlayerInteractEvent(player, Action.RIGHT_CLICK_BLOCK, item, clickedBlock, BlockFace.EAST, hand);
bil.onPlayerInteract(e);
assertTrue(e.useInteractedBlock().equals(Event.Result.DENY));
verify(notifier).notify(any(), eq("protection.protected"));
}
/**
* Test method for {@link world.bentobox.bentobox.listeners.flags.protection.BlockInteractionListener#onPlayerInteract(org.bukkit.event.player.PlayerInteractEvent)}.
*/
@Test
public void testOnPlayerInteractItemFrameNotAllowedOtherFlagsOkay() {
when(island.isAllowed(any(), eq(Flags.BREAK_BLOCKS))).thenReturn(true);
when(island.isAllowed(any(), eq(Flags.PLACE_BLOCKS))).thenReturn(true);
when(clickedBlock.getType()).thenReturn(Material.ITEM_FRAME);
PlayerInteractEvent e = new PlayerInteractEvent(player, Action.RIGHT_CLICK_BLOCK, item, clickedBlock, BlockFace.EAST, hand);
bil.onPlayerInteract(e);
assertTrue(e.useInteractedBlock().equals(Event.Result.DENY));
verify(notifier).notify(any(), eq("protection.protected"));
}
/**
* Test method for {@link world.bentobox.bentobox.listeners.flags.protection.BlockInteractionListener#onPlayerInteract(org.bukkit.event.player.PlayerInteractEvent)}.
*/
@Test
public void testOnPlayerInteractNothingInHandPotsNotAllowed() {
Arrays.stream(Material.values()).filter(m -> m.name().startsWith("POTTED")).forEach(bm -> {
when(clickedBlock.getType()).thenReturn(bm);
PlayerInteractEvent e = new PlayerInteractEvent(player, Action.RIGHT_CLICK_BLOCK, item, clickedBlock, BlockFace.EAST, hand);
bil.onPlayerInteract(e);
assertTrue("Failure " + bm, e.useInteractedBlock().equals(Event.Result.DENY));
});
verify(notifier, times((int)Arrays.stream(Material.values()).filter(m -> m.name().startsWith("POTTED")).count())).notify(any(), eq("protection.protected"));
}
/**
* Test method for {@link world.bentobox.bentobox.listeners.flags.protection.BlockInteractionListener#onPlayerInteract(org.bukkit.event.player.PlayerInteractEvent)}.
*/
@Test
public void testOnPlayerInteractNothingInHandNotAllowed() {
int count = 0;
int worldSettingCount = 0;
for (Material bm : BlockInteractionListener.CLICKED_BLOCKS.keySet()) {
when(clickedBlock.getType()).thenReturn(bm);
PlayerInteractEvent e = new PlayerInteractEvent(player, Action.RIGHT_CLICK_BLOCK, item, clickedBlock, BlockFace.EAST, hand);
bil.onPlayerInteract(e);
assertTrue("Failure " + bm, e.useInteractedBlock().equals(Event.Result.DENY));
if (BlockInteractionListener.CLICKED_BLOCKS.get(bm).getType().equals(Type.PROTECTION)) {
count++;
} else if (BlockInteractionListener.CLICKED_BLOCKS.get(bm).getType().equals(Type.WORLD_SETTING)) {
worldSettingCount++;
}
verify(notifier, times(count)).notify(any(), eq("protection.protected"));
verify(notifier, times(worldSettingCount)).notify(any(), eq("protection.world-protected"));
}
}
/**
* Test method for {@link world.bentobox.bentobox.listeners.flags.protection.BlockInteractionListener#onPlayerInteract(org.bukkit.event.player.PlayerInteractEvent)}.
*/
@Test
public void testOnPlayerInteractNothingInHandAllowed() {
when(island.isAllowed(any(), any())).thenReturn(true);
for (Material bm : BlockInteractionListener.CLICKED_BLOCKS.keySet()) {
// Allow flags
if (BlockInteractionListener.CLICKED_BLOCKS.get(bm).getType().equals(Type.PROTECTION)) {
when(island.isAllowed(any(), eq(BlockInteractionListener.CLICKED_BLOCKS.get(bm)))).thenReturn(true);
} else if (BlockInteractionListener.CLICKED_BLOCKS.get(bm).getType().equals(Type.WORLD_SETTING)) {
BlockInteractionListener.CLICKED_BLOCKS.get(bm).setSetting(world, true);
}
when(clickedBlock.getType()).thenReturn(bm);
PlayerInteractEvent e = new PlayerInteractEvent(player, Action.RIGHT_CLICK_BLOCK, item, clickedBlock, BlockFace.EAST, hand);
bil.onPlayerInteract(e);
assertFalse("Failure " + bm, e.useInteractedBlock().equals(Event.Result.DENY));
verify(notifier, never()).notify(any(), eq("protection.protected"));
verify(notifier, never()).notify(any(), eq("protection.world-protected"));
}
}
/**
* Test method for {@link world.bentobox.bentobox.listeners.flags.protection.BlockInteractionListener#onPlayerInteract(org.bukkit.event.player.PlayerInteractEvent)}.
*/
@Test
public void testOnPlayerInteractSpawnEggInHandNotAllowed() {
when(clickedBlock.getType()).thenReturn(Material.SPAWNER);
when(item.getType()).thenReturn(Material.BLAZE_SPAWN_EGG);
PlayerInteractEvent e = new PlayerInteractEvent(player, Action.RIGHT_CLICK_BLOCK, item, clickedBlock, BlockFace.EAST, hand);
bil.onPlayerInteract(e);
assertTrue(e.useInteractedBlock().equals(Event.Result.DENY));
assertTrue(e.useItemInHand().equals(Event.Result.DENY));
verify(notifier).notify(any(), eq("protection.protected"));
}
/**
* Test method for {@link world.bentobox.bentobox.listeners.flags.protection.BlockInteractionListener#onPlayerInteract(org.bukkit.event.player.PlayerInteractEvent)}.
*/
@Test
public void testOnPlayerInteractSpawnEggInHandAllowed() {
when(island.isAllowed(any(), any())).thenReturn(true);
when(clickedBlock.getType()).thenReturn(Material.SPAWNER);
when(item.getType()).thenReturn(Material.BLAZE_SPAWN_EGG);
PlayerInteractEvent e = new PlayerInteractEvent(player, Action.RIGHT_CLICK_BLOCK, item, clickedBlock, BlockFace.EAST, hand);
bil.onPlayerInteract(e);
assertFalse(e.useInteractedBlock().equals(Event.Result.DENY));
assertFalse(e.useItemInHand().equals(Event.Result.DENY));
verify(notifier, never()).notify(any(), eq("protection.protected"));
}
/**
* Test method for {@link world.bentobox.bentobox.listeners.flags.protection.BlockInteractionListener#onPlayerInteract(org.bukkit.event.player.PlayerInteractEvent)}.
*/
@Test
public void testOnPlayerInteractSpawnEggInHandOnItemFrameNotAllowed() {
when(island.isAllowed(any(), eq(Flags.BREAK_BLOCKS))).thenReturn(true);
when(island.isAllowed(any(), eq(Flags.PLACE_BLOCKS))).thenReturn(true);
when(clickedBlock.getType()).thenReturn(Material.ITEM_FRAME);
when(item.getType()).thenReturn(Material.BLAZE_SPAWN_EGG);
PlayerInteractEvent e = new PlayerInteractEvent(player, Action.RIGHT_CLICK_BLOCK, item, clickedBlock, BlockFace.EAST, hand);
bil.onPlayerInteract(e);
assertTrue(e.useInteractedBlock().equals(Event.Result.DENY));
assertTrue(e.useItemInHand().equals(Event.Result.DENY));
verify(notifier, times(2)).notify(any(), eq("protection.protected"));
}
/**
* Test method for {@link world.bentobox.bentobox.listeners.flags.protection.BlockInteractionListener#onBlockBreak(org.bukkit.event.block.BlockBreakEvent)}.
*/
@Ignore("TODO")
@Test
public void testOnBlockBreak() {
fail("Not yet implemented"); // TODO
}
/**
* Test method for {@link world.bentobox.bentobox.listeners.flags.protection.BlockInteractionListener#onDragonEggTeleport(org.bukkit.event.block.BlockFromToEvent)}.
*/
@Ignore("TODO")
@Test
public void testOnDragonEggTeleport() {
fail("Not yet implemented"); // TODO
}
}

View File

@ -107,7 +107,6 @@ public class EntityInteractListenerTest {
when(location.getBlockX()).thenReturn(0);
when(location.getBlockY()).thenReturn(0);
when(location.getBlockZ()).thenReturn(0);
when(clickedEntity.getLocation()).thenReturn(location);
// Clicked block
when(clickedEntity.getLocation()).thenReturn(location);

View File

@ -0,0 +1,399 @@
package world.bentobox.bentobox.listeners.flags.protection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.bukkit.Difficulty;
import org.bukkit.GameMode;
import org.bukkit.entity.EntityType;
import org.eclipse.jdt.annotation.NonNull;
import world.bentobox.bentobox.api.configuration.WorldSettings;
import world.bentobox.bentobox.api.flags.Flag;
public class TestWorldSettings implements WorldSettings {
private Map<String, Boolean> map = new HashMap<>();
@Override
public GameMode getDefaultGameMode() {
return null;
}
@Override
public Map<Flag, Integer> getDefaultIslandFlags() {
return null;
}
@Override
public Map<Flag, Integer> getDefaultIslandSettings() {
return null;
}
@Override
public Difficulty getDifficulty() {
return null;
}
@Override
public void setDifficulty(Difficulty difficulty) {
}
@Override
public String getFriendlyName() {
return null;
}
@Override
public int getIslandDistance() {
return 0;
}
@Override
public int getIslandHeight() {
return 0;
}
@Override
public int getIslandProtectionRange() {
return 0;
}
@Override
public int getIslandStartX() {
return 0;
}
@Override
public int getIslandStartZ() {
return 0;
}
@Override
public int getIslandXOffset() {
return 0;
}
@Override
public int getIslandZOffset() {
return 0;
}
@Override
public List<String> getIvSettings() {
return null;
}
@Override
public int getMaxHomes() {
return 0;
}
@Override
public int getMaxIslands() {
return 0;
}
@Override
public int getMaxTeamSize() {
return 0;
}
@Override
public int getNetherSpawnRadius() {
return 0;
}
@Override
public String getPermissionPrefix() {
return null;
}
@Override
public Set<EntityType> getRemoveMobsWhitelist() {
return null;
}
@Override
public int getSeaHeight() {
return 0;
}
@Override
public List<String> getHiddenFlags() {
return null;
}
@Override
public List<String> getVisitorBannedCommands() {
return null;
}
@Override
public Map<String, Boolean> getWorldFlags() {
return map ;
}
/**
* @return the map
*/
public Map<String, Boolean> getMap() {
return map;
}
/**
* @param map the map to set
*/
public void setMap(Map<String, Boolean> map) {
this.map = map;
}
@Override
public String getWorldName() {
return null;
}
@Override
public boolean isDragonSpawn() {
return false;
}
@Override
public boolean isEndGenerate() {
return false;
}
@Override
public boolean isEndIslands() {
return false;
}
@Override
public boolean isNetherGenerate() {
return false;
}
@Override
public boolean isNetherIslands() {
return false;
}
@Override
public boolean isOnJoinResetEnderChest() {
return false;
}
@Override
public boolean isOnJoinResetInventory() {
return false;
}
@Override
public boolean isOnJoinResetMoney() {
return false;
}
@Override
public boolean isOnJoinResetHealth() {
return false;
}
@Override
public boolean isOnJoinResetHunger() {
return false;
}
@Override
public boolean isOnJoinResetXP() {
return false;
}
@Override
public @NonNull List<String> getOnJoinCommands() {
return null;
}
@Override
public boolean isOnLeaveResetEnderChest() {
return false;
}
@Override
public boolean isOnLeaveResetInventory() {
return false;
}
@Override
public boolean isOnLeaveResetMoney() {
return false;
}
@Override
public boolean isOnLeaveResetHealth() {
return false;
}
@Override
public boolean isOnLeaveResetHunger() {
return false;
}
@Override
public boolean isOnLeaveResetXP() {
return false;
}
@Override
public @NonNull List<String> getOnLeaveCommands() {
return null;
}
@Override
public boolean isUseOwnGenerator() {
return false;
}
@Override
public boolean isWaterUnsafe() {
return false;
}
@Override
public List<String> getGeoLimitSettings() {
return null;
}
@Override
public int getResetLimit() {
return 0;
}
@Override
public long getResetEpoch() {
return 0;
}
@Override
public void setResetEpoch(long timestamp) {
}
@Override
public boolean isTeamJoinDeathReset() {
return false;
}
@Override
public int getDeathsMax() {
return 0;
}
@Override
public boolean isDeathsCounted() {
return false;
}
@Override
public boolean isDeathsResetOnNewIsland() {
return false;
}
@Override
public boolean isAllowSetHomeInNether() {
return false;
}
@Override
public boolean isAllowSetHomeInTheEnd() {
return false;
}
@Override
public boolean isRequireConfirmationToSetHomeInNether() {
return false;
}
@Override
public boolean isRequireConfirmationToSetHomeInTheEnd() {
return false;
}
@Override
public int getBanLimit() {
return 0;
}
@Override
public boolean isLeaversLoseReset() {
return false;
}
@Override
public boolean isKickedKeepInventory() {
return false;
}
}