diff --git a/locales/en-US.yml b/locales/en-US.yml index 55c590ecb..8d3ae390f 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -159,6 +159,10 @@ commands: ban: description: "ban a player from your island" parameters: "" + cannot-ban-yourself: "&cYou cannot ban yourself!" + cannot-ban: "&cThat player cannot be banned." + cannot-ban-member: "&cKick the team member first, then ban." + player-already-banned: "&cPlayer is already banned" unban: description: "unban a player from your island" parameters: "" diff --git a/src/main/java/us/tastybento/bskyblock/api/commands/CompositeCommand.java b/src/main/java/us/tastybento/bskyblock/api/commands/CompositeCommand.java index b8032daa3..1e918da33 100644 --- a/src/main/java/us/tastybento/bskyblock/api/commands/CompositeCommand.java +++ b/src/main/java/us/tastybento/bskyblock/api/commands/CompositeCommand.java @@ -294,7 +294,7 @@ public abstract class CompositeCommand extends Command implements PluginIdentifi /** * Convenience method to obtain the user's team leader * @param user - the User - * @return UUID of player's team leader + * @return UUID of player's team leader or null if user has no island */ protected UUID getTeamLeader(User user) { return plugin.getIslands().getTeamLeader(user.getUniqueId()); diff --git a/src/main/java/us/tastybento/bskyblock/commands/island/IslandBanCommand.java b/src/main/java/us/tastybento/bskyblock/commands/island/IslandBanCommand.java index a79fabf8d..0bf53951b 100644 --- a/src/main/java/us/tastybento/bskyblock/commands/island/IslandBanCommand.java +++ b/src/main/java/us/tastybento/bskyblock/commands/island/IslandBanCommand.java @@ -1,4 +1,90 @@ package us.tastybento.bskyblock.commands.island; -public class IslandBanCommand { +import java.util.List; +import java.util.UUID; + +import us.tastybento.bskyblock.Constants; +import us.tastybento.bskyblock.api.commands.CompositeCommand; +import us.tastybento.bskyblock.api.user.User; + +public class IslandBanCommand extends CompositeCommand { + + public IslandBanCommand(CompositeCommand islandCommand) { + super(islandCommand, "ban"); + } + + @Override + public void setup() { + setPermission(Constants.PERMPREFIX + "island.ban"); + setOnlyPlayer(true); + setParameters("command.island.ban.parameters"); + setDescription("commands.island.ban.description"); + } + + @Override + public boolean execute(User user, List args) { + if (args.size() != 1) { + showHelp(this, user); + return false; + } + UUID playerUUID = user.getUniqueId(); + // Player issuing the command must have an island + if (!getIslands().hasIsland(playerUUID)) { + user.sendMessage("general.errors.no-island"); + return false; + } + if (!getIslands().isOwner(playerUUID)) { + user.sendMessage("general.errors.not-leader"); + return false; + } + if (args.isEmpty() || args.size() > 1) { + // Show help + showHelp(this, user); + return false; + } else { + // Get target player + UUID targetUUID = getPlayers().getUUID(args.get(0)); + if (targetUUID == null) { + user.sendMessage("general.errors.unknown-player"); + return false; + } + // Player cannot ban themselves + if (playerUUID.equals(targetUUID)) { + user.sendMessage("commands.island.ban.cannot-ban-yourself"); + return false; + } + if (getIslands().getMembers(user.getUniqueId()).contains(targetUUID)) { + user.sendMessage("commands.island.ban.cannot-ban-member"); + return false; + } + if (getIslands().getIsland(playerUUID).isBanned(targetUUID)) { + user.sendMessage("commands.island.ban.player-already-banned"); + return false; + } + User target = User.getInstance(targetUUID); + // Cannot ban ops + if (!target.isPlayer() || target.isOp()) { + user.sendMessage("commands.island.ban.cannot-ban"); + return false; + } + + User targetUser = User.getInstance(targetUUID); + // Finished error checking - start the banning + if (getIslands().getIsland(playerUUID).addToBanList(targetUUID)) { + user.sendMessage("general.success"); + targetUser.sendMessage("commands.island.ban.you-are-banned", "[owner]", user.getName()); + if (target.isOnline()) { + // Remove from island + if (getPlayers().hasIsland(targetUUID)) { + getIslands().homeTeleport(target.getPlayer()); + } + // TODO else if there is a spawn, send them there + } + return true; + } + // Banning was blocked, maybe due to an event cancellation. Fail silently. + } + return false; + } + } diff --git a/src/main/java/us/tastybento/bskyblock/commands/island/IslandResetCommand.java b/src/main/java/us/tastybento/bskyblock/commands/island/IslandResetCommand.java index 1bcbda2ad..350029771 100644 --- a/src/main/java/us/tastybento/bskyblock/commands/island/IslandResetCommand.java +++ b/src/main/java/us/tastybento/bskyblock/commands/island/IslandResetCommand.java @@ -2,10 +2,8 @@ package us.tastybento.bskyblock.commands.island; import java.io.IOException; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.UUID; import org.bukkit.Bukkit; diff --git a/src/test/java/us/tastybento/bskyblock/api/addons/AddonTest.java b/src/test/java/us/tastybento/bskyblock/api/addons/AddonTest.java index ea927f77d..760af30f8 100644 --- a/src/test/java/us/tastybento/bskyblock/api/addons/AddonTest.java +++ b/src/test/java/us/tastybento/bskyblock/api/addons/AddonTest.java @@ -160,7 +160,7 @@ public class AddonTest { @Test public void testSaveConfig() { - TestClass test = new TestClass(); + //TestClass test = new TestClass(); // This will wipe out the config.yml of BSB so I am commenting it out //test.saveConfig(); } diff --git a/src/test/java/us/tastybento/bskyblock/commands/island/IslandBanCommandTest.java b/src/test/java/us/tastybento/bskyblock/commands/island/IslandBanCommandTest.java new file mode 100644 index 000000000..91d2d8e07 --- /dev/null +++ b/src/test/java/us/tastybento/bskyblock/commands/island/IslandBanCommandTest.java @@ -0,0 +1,282 @@ +/** + * + */ +package us.tastybento.bskyblock.commands.island; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitScheduler; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +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 us.tastybento.bskyblock.BSkyBlock; +import us.tastybento.bskyblock.Settings; +import us.tastybento.bskyblock.api.user.User; +import us.tastybento.bskyblock.commands.IslandCommand; +import us.tastybento.bskyblock.database.objects.Island; +import us.tastybento.bskyblock.managers.CommandsManager; +import us.tastybento.bskyblock.managers.IslandsManager; +import us.tastybento.bskyblock.managers.PlayersManager; + +/** + * @author tastybento + * + */ +@RunWith(PowerMockRunner.class) +@PrepareForTest({Bukkit.class, BSkyBlock.class, User.class }) +public class IslandBanCommandTest { + + private BSkyBlock plugin; + private IslandCommand ic; + private UUID uuid; + private User user; + private Settings s; + private IslandsManager im; + private PlayersManager pm; + private Island island; + + /** + * @throws java.lang.Exception + */ + @Before + public void setUp() throws Exception { + // Set up plugin + plugin = mock(BSkyBlock.class); + Whitebox.setInternalState(BSkyBlock.class, "instance", plugin); + + // Command manager + CommandsManager cm = mock(CommandsManager.class); + when(plugin.getCommandsManager()).thenReturn(cm); + + // Settings + s = mock(Settings.class); + when(s.getResetWait()).thenReturn(0L); + when(s.getResetLimit()).thenReturn(3); + when(plugin.getSettings()).thenReturn(s); + + // Player + Player p = mock(Player.class); + // Sometimes use Mockito.withSettings().verboseLogging() + user = mock(User.class); + when(user.isOp()).thenReturn(false); + uuid = UUID.randomUUID(); + when(user.getUniqueId()).thenReturn(uuid); + when(user.getPlayer()).thenReturn(p); + when(user.getName()).thenReturn("tastybento"); + + // Parent command has no aliases + ic = mock(IslandCommand.class); + when(ic.getSubCommandAliases()).thenReturn(new HashMap<>()); + + // No island for player to begin with (set it later in the tests) + im = mock(IslandsManager.class); + when(im.hasIsland(Mockito.eq(uuid))).thenReturn(false); + when(im.isOwner(Mockito.eq(uuid))).thenReturn(false); + when(plugin.getIslands()).thenReturn(im); + + // Has team + pm = mock(PlayersManager.class); + when(pm.inTeam(Mockito.eq(uuid))).thenReturn(true); + when(plugin.getPlayers()).thenReturn(pm); + + // Server & Scheduler + BukkitScheduler sch = mock(BukkitScheduler.class); + PowerMockito.mockStatic(Bukkit.class); + when(Bukkit.getScheduler()).thenReturn(sch); + + // Island Banned list initialization + island = mock(Island.class); + when(island.getBanned()).thenReturn(new HashSet<>()); + when(island.isBanned(Mockito.any())).thenReturn(false); + when(im.getIsland(Mockito.any(UUID.class))).thenReturn(island); + + } + + /** + * Test method for {@link us.tastybento.bskyblock.commands.island.IslandBanCommand#execute(us.tastybento.bskyblock.api.user.User, java.util.List)}. + */ + // Island ban command by itself + + // *** Error conditions *** + // Ban without an island + // Ban as not a team leader + // Ban unknown user + // Ban self + // Ban team mate + // Ban someone you have already banned + // Unban someone not banned + // Ban an Op + + // *** Working conditions *** + // Ban offline user + // Ban online user + // Unban offline user + // Unban online user + + @Test + public void testNoArgs() { + IslandBanCommand ibc = new IslandBanCommand(ic); + assertFalse(ibc.execute(user, new ArrayList<>())); + } + + @Test + public void testNoIsland() { + IslandBanCommand ibc = new IslandBanCommand(ic); + assertFalse(ibc.execute(user, Arrays.asList("bill"))); + Mockito.verify(user).sendMessage("general.errors.no-island"); + } + + @Test + public void testNotOwner() { + IslandBanCommand ibc = new IslandBanCommand(ic); + when(im.hasIsland(Mockito.eq(uuid))).thenReturn(true); + assertFalse(ibc.execute(user, Arrays.asList("bill"))); + Mockito.verify(user).sendMessage("general.errors.not-leader"); + } + + @Test + public void testUnknownUser() { + IslandBanCommand ibc = new IslandBanCommand(ic); + when(im.hasIsland(Mockito.eq(uuid))).thenReturn(true); + when(im.isOwner(Mockito.eq(uuid))).thenReturn(true); + when(pm.getUUID(Mockito.anyString())).thenReturn(null); + assertFalse(ibc.execute(user, Arrays.asList("bill"))); + Mockito.verify(user).sendMessage("general.errors.unknown-player"); + } + + @Test + public void testBanSelf() { + IslandBanCommand ibc = new IslandBanCommand(ic); + when(im.hasIsland(Mockito.eq(uuid))).thenReturn(true); + when(im.isOwner(Mockito.eq(uuid))).thenReturn(true); + when(pm.getUUID(Mockito.anyString())).thenReturn(uuid); + assertFalse(ibc.execute(user, Arrays.asList("bill"))); + Mockito.verify(user).sendMessage("commands.island.ban.cannot-ban-yourself"); + } + + @Test + public void testBanTeamMate() { + IslandBanCommand ibc = new IslandBanCommand(ic); + when(im.hasIsland(Mockito.eq(uuid))).thenReturn(true); + when(im.isOwner(Mockito.eq(uuid))).thenReturn(true); + UUID teamMate = UUID.randomUUID(); + when(pm.getUUID(Mockito.anyString())).thenReturn(teamMate); + Set members = new HashSet<>(); + members.add(uuid); + members.add(teamMate); + when(im.getMembers(Mockito.any())).thenReturn(members); + assertFalse(ibc.execute(user, Arrays.asList("bill"))); + Mockito.verify(user).sendMessage("commands.island.ban.cannot-ban-member"); + } + + @Test + public void testBanAlreadyBanned() { + IslandBanCommand ibc = new IslandBanCommand(ic); + when(im.hasIsland(Mockito.eq(uuid))).thenReturn(true); + when(im.isOwner(Mockito.eq(uuid))).thenReturn(true); + UUID bannedUser = UUID.randomUUID(); + when(pm.getUUID(Mockito.anyString())).thenReturn(bannedUser); + when(island.isBanned(Mockito.eq(bannedUser))).thenReturn(true); + assertFalse(ibc.execute(user, Arrays.asList("bill"))); + Mockito.verify(user).sendMessage("commands.island.ban.player-already-banned"); + } + + @Test + public void testBanOp() { + IslandBanCommand ibc = new IslandBanCommand(ic); + when(im.hasIsland(Mockito.eq(uuid))).thenReturn(true); + when(im.isOwner(Mockito.eq(uuid))).thenReturn(true); + UUID op = UUID.randomUUID(); + when(pm.getUUID(Mockito.anyString())).thenReturn(op); + PowerMockito.mockStatic(User.class); + User opUser = mock(User.class); + when(opUser.isOp()).thenReturn(true); + when(opUser.isPlayer()).thenReturn(true); + when(User.getInstance(Mockito.any(UUID.class))).thenReturn(opUser); + assertFalse(ibc.execute(user, Arrays.asList("bill"))); + Mockito.verify(user).sendMessage("commands.island.ban.cannot-ban"); + } + + @Test + public void testBanOfflineUser() { + IslandBanCommand ibc = new IslandBanCommand(ic); + when(im.hasIsland(Mockito.eq(uuid))).thenReturn(true); + when(im.isOwner(Mockito.eq(uuid))).thenReturn(true); + UUID targetUuid = UUID.randomUUID(); + when(pm.getUUID(Mockito.anyString())).thenReturn(targetUuid); + PowerMockito.mockStatic(User.class); + User targetUser = mock(User.class); + when(targetUser.isOp()).thenReturn(false); + when(targetUser.isPlayer()).thenReturn(true); + when(targetUser.isOnline()).thenReturn(false); + when(User.getInstance(Mockito.any(UUID.class))).thenReturn(targetUser); + + // Allow adding to ban list + when(island.addToBanList(Mockito.any())).thenReturn(true); + + assertTrue(ibc.execute(user, Arrays.asList("bill"))); + Mockito.verify(user).sendMessage("general.success"); + Mockito.verify(targetUser).sendMessage("commands.island.ban.you-are-banned", "[owner]", user.getName()); + } + + @Test + public void testBanOnlineUser() { + IslandBanCommand ibc = new IslandBanCommand(ic); + when(im.hasIsland(Mockito.eq(uuid))).thenReturn(true); + when(im.isOwner(Mockito.eq(uuid))).thenReturn(true); + UUID op = UUID.randomUUID(); + when(pm.getUUID(Mockito.anyString())).thenReturn(op); + PowerMockito.mockStatic(User.class); + User targetUser = mock(User.class); + when(targetUser.isOp()).thenReturn(false); + when(targetUser.isPlayer()).thenReturn(true); + when(targetUser.isOnline()).thenReturn(true); + when(User.getInstance(Mockito.any(UUID.class))).thenReturn(targetUser); + // Allow adding to ban list + when(island.addToBanList(Mockito.any())).thenReturn(true); + + assertTrue(ibc.execute(user, Arrays.asList("bill"))); + Mockito.verify(user).sendMessage("general.success"); + Mockito.verify(targetUser).sendMessage("commands.island.ban.you-are-banned", "[owner]", user.getName()); + } + + @Test + public void testCancelledBan() { + IslandBanCommand ibc = new IslandBanCommand(ic); + when(im.hasIsland(Mockito.eq(uuid))).thenReturn(true); + when(im.isOwner(Mockito.eq(uuid))).thenReturn(true); + UUID op = UUID.randomUUID(); + when(pm.getUUID(Mockito.anyString())).thenReturn(op); + PowerMockito.mockStatic(User.class); + User targetUser = mock(User.class); + when(targetUser.isOp()).thenReturn(false); + when(targetUser.isPlayer()).thenReturn(true); + when(targetUser.isOnline()).thenReturn(true); + when(User.getInstance(Mockito.any(UUID.class))).thenReturn(targetUser); + // Disallow adding to ban list - even cancelled + when(island.addToBanList(Mockito.any())).thenReturn(false); + + assertFalse(ibc.execute(user, Arrays.asList("bill"))); + Mockito.verify(user, Mockito.never()).sendMessage("general.success"); + Mockito.verify(targetUser, Mockito.never()).sendMessage("commands.island.ban.you-are-banned", "[owner]", user.getName()); + } + +}