Added confirmation to IslandResetCommand

Added test class.
This commit is contained in:
Tastybento 2018-04-28 12:50:07 -07:00
parent 72306035f6
commit 0bdc146da3
7 changed files with 256 additions and 23 deletions

View File

@ -98,6 +98,9 @@ general:
acid-blocked-commands:
- home
# Time in seconds that players have to confirm sensitive commands, e.g. island reset
confimation-time: 20
### World Settings ###
world:
# Name of the world - if it does not exist then it will be generated.

View File

@ -34,6 +34,7 @@ general:
unknown-command: "&cUnknown command. Do &b/[label] help &cfor help."
warp-not-safe: "&cThat warp is not safe right now!"
wrong-world: "&cYou are not in the right world to do that!"
you-must-wait: "&cYou must wait [seconds]s before you can do that command again"
tips:
changing-obsidian-to-lava: "Changing obsidian back into lava. Be careful!"
@ -80,6 +81,9 @@ commands:
reset:
description: "restart your island and remove the old one"
must-remove-members: "You must remove all members from your island before you can restart it (/island kick <player>)."
none-left: "&cYou have no more resets left!"
resets-left: "&cYou have [number] resets left"
confirm: "&cType [label] reset confirm within [seconds]s to confirm reset"
sethome:
description: "set your teleport point for /island"
must-be-on-your-island: "You must be on your island to set home!"

View File

@ -14,6 +14,7 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffectType;
import us.tastybento.bskyblock.Constants.GameType;
import us.tastybento.bskyblock.api.configuration.ConfigComment;
import us.tastybento.bskyblock.api.configuration.ConfigEntry;
import us.tastybento.bskyblock.api.configuration.ISettings;
import us.tastybento.bskyblock.api.configuration.StoreAt;
@ -78,6 +79,10 @@ public class Settings implements ISettings<Settings> {
@ConfigEntry(path = "general.allow-obsidian-scooping")
private boolean allowObsidianScooping = true;
@ConfigComment("Time in seconds that players have to confirm sensitive commands, e.g. island reset")
@ConfigEntry(path = "general.confirmation-time")
private int confirmationTime = 20;
// ---------------------------------------------
@ -1242,6 +1247,18 @@ public class Settings implements ISettings<Settings> {
public void setFakePlayers(Set<String> fakePlayers) {
this.fakePlayers = fakePlayers;
}
/**
* @return the confirmationTime
*/
public int getConfirmationTime() {
return confirmationTime;
}
/**
* @param confirmationTime the confirmationTime to set
*/
public void setConfirmationTime(int confirmationTime) {
this.confirmationTime = confirmationTime;
}
}

View File

@ -127,7 +127,7 @@ public abstract class CompositeCommand extends Command implements PluginIdentifi
subCommandAliases = new LinkedHashMap<>();
// Add aliases to the parent for this command
for (String alias : aliases) {
parent.subCommandAliases.put(alias, this);
parent.getSubCommandAliases().put(alias, this);
}
setUsage("");
setup();
@ -434,4 +434,11 @@ public abstract class CompositeCommand extends Command implements PluginIdentifi
protected boolean showHelp(CompositeCommand command, User user) {
return command.getSubCommand("help").map(helpCommand -> helpCommand.execute(user, new ArrayList<>())).orElse(false);
}
/**
* @return the subCommandAliases
*/
public Map<String, CompositeCommand> getSubCommandAliases() {
return subCommandAliases;
}
}

View File

@ -1,8 +1,14 @@
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;
import org.bukkit.GameMode;
import org.bukkit.entity.Player;
@ -15,7 +21,8 @@ import us.tastybento.bskyblock.managers.island.NewIsland;
public class IslandResetCommand extends CompositeCommand {
private static final boolean DEBUG = false;
private Map<UUID, Long> cooldown;
private Set<UUID> confirm;
public IslandResetCommand(CompositeCommand islandCommand) {
super(islandCommand, "reset", "restart");
@ -23,6 +30,8 @@ public class IslandResetCommand extends CompositeCommand {
@Override
public void setup() {
cooldown = new HashMap<>();
confirm = new HashSet<>();
setPermission(Constants.PERMPREFIX + "island.create");
setOnlyPlayer(true);
setDescription("commands.island.reset.description");
@ -30,36 +39,71 @@ public class IslandResetCommand extends CompositeCommand {
@Override
public boolean execute(User user, List<String> args) {
// Check cooldown
if (getSettings().getResetWait() > 0 && onRestartWaitTime(user) > 0 && !user.isOp()) {
user.sendMessage("general.errors.you-must-wait", "[seconds]", String.valueOf(onRestartWaitTime(user)));
return false;
}
if (!getIslands().hasIsland(user.getUniqueId())) {
user.sendMessage("general.errors.no-island");
return true;
return false;
}
if (!getIslands().isOwner(user.getUniqueId())) {
user.sendMessage("general.errors.not-leader");
return false;
}
if (getPlugin().getPlayers().inTeam(user.getUniqueId())) {
if (getPlayers().inTeam(user.getUniqueId())) {
user.sendMessage("commands.island.reset.must-remove-members");
return false;
}
if (getSettings().getResetLimit() >= 0 ) {
if (getPlayers().getResetsLeft(user.getUniqueId()) == 0) {
user.sendMessage("commands.island.reset.none-left");
return false;
} else {
// Notify how many resets are left
user.sendMessage("commands.island.reset.resets-left", "[number]", String.valueOf(getPlayers().getResetsLeft(user.getUniqueId())));
}
}
// Check confirmation or reset immediately if no confirmation required
if (!getSettings().isResetConfirmation() || (confirm.contains(user.getUniqueId()) && args.size() == 1 && args.get(0).equalsIgnoreCase("confirm"))) {
// Reset the island
Player player = user.getPlayer();
player.setGameMode(GameMode.SPECTATOR);
// Get the player's old island
Island oldIsland = getIslands().getIsland(player.getUniqueId());
// Remove them from this island (it still exists and will be deleted later)
getIslands().removePlayer(player.getUniqueId());
// Create new island and then delete the old one
try {
NewIsland.builder()
.player(player)
.reason(Reason.RESET)
.oldIsland(oldIsland)
.build();
} catch (IOException e) {
getPlugin().logError("Could not create island for player. " + e.getMessage());
user.sendMessage("commands.island.create.unable-create-island");
}
setCooldown(user);
return true;
} else {
// Require confirmation
user.sendMessage("commands.island.reset.confirm", "[label]", Constants.ISLANDCOMMAND, "[seconds]", String.valueOf(getSettings().getConfirmationTime()));
confirm.add(user.getUniqueId());
Bukkit.getScheduler().runTaskLater(getPlugin(), () -> confirm.remove(user.getUniqueId()), getSettings().getConfirmationTime() * 20L);
return true;
}
Player player = user.getPlayer();
player.setGameMode(GameMode.SPECTATOR);
// Get the player's old island
Island oldIsland = getIslands().getIsland(player.getUniqueId());
// Remove them from this island (it still exists and will be deleted later)
getIslands().removePlayer(player.getUniqueId());
// Create new island and then delete the old one
try {
NewIsland.builder()
.player(player)
.reason(Reason.RESET)
.oldIsland(oldIsland)
.build();
} catch (IOException e) {
getPlugin().logError("Could not create island for player. " + e.getMessage());
user.sendMessage("commands.island.create.unable-create-island");
}
return true;
}
private int onRestartWaitTime(User user) {
if (!cooldown.containsKey(user.getUniqueId())) {
return 0;
}
return (int) ((System.currentTimeMillis() - cooldown.get(user.getUniqueId()) / 1000));
}
private void setCooldown(User user) {
cooldown.put(user.getUniqueId(), System.currentTimeMillis() + (getSettings().getResetLimit() * 1000L));
}
}

View File

@ -34,7 +34,7 @@ import us.tastybento.bskyblock.managers.IslandsManager;
import us.tastybento.bskyblock.managers.PlayersManager;
@RunWith(PowerMockRunner.class)
@PrepareForTest( { BSkyBlock.class })
@PrepareForTest(BSkyBlock.class)
public class IslandCommandTest {
@Mock

View File

@ -0,0 +1,158 @@
/**
*
*/
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.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.UUID;
import org.bukkit.entity.Player;
import org.junit.Before;
import org.junit.BeforeClass;
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;
import us.tastybento.bskyblock.managers.island.NewIsland;
/**
* @author tastybento
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({BSkyBlock.class, NewIsland.class })
public class IslandResetCommandTest {
private static BSkyBlock plugin;
/**
* @throws java.lang.Exception
*/
@BeforeClass
public static void setUpBeforeClass() throws Exception {
plugin = mock(BSkyBlock.class);
Whitebox.setInternalState(BSkyBlock.class, "instance", plugin);
/*
NewIsland.Builder builder = mock(NewIsland.Builder.class);
when(builder.player(Mockito.any())).thenReturn(builder);
when(builder.oldIsland(Mockito.any())).thenReturn(builder);
when(builder.reason(Mockito.any())).thenReturn(builder);
when(builder.build()).thenReturn(mock(Island.class));
PowerMockito.mockStatic(NewIsland.class);
when(NewIsland.builder()).thenReturn(builder);
*/
}
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
CommandsManager cm = mock(CommandsManager.class);
when(plugin.getCommandsManager()).thenReturn(cm);
}
/**
* Test method for {@link us.tastybento.bskyblock.commands.island.IslandResetCommand#execute(us.tastybento.bskyblock.api.user.User, java.util.List)}.
* @throws IOException
*/
@Test
public void testExecuteUserListOfString() throws IOException {
Settings s = mock(Settings.class);
when(s.getResetWait()).thenReturn(0L);
when(plugin.getSettings()).thenReturn(s);
Player p = mock(Player.class);
User user = mock(User.class, Mockito.withSettings().verboseLogging());
when(user.isOp()).thenReturn(false);
UUID uuid = UUID.randomUUID();
when(user.getUniqueId()).thenReturn(uuid);
when(user.getPlayer()).thenReturn(p);
IslandCommand ic = mock(IslandCommand.class);
when(ic.getSubCommandAliases()).thenReturn(new HashMap<>());
IslandResetCommand irc = new IslandResetCommand(ic);
// No island
IslandsManager 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
PlayersManager pm = mock(PlayersManager.class);
when(pm.inTeam(Mockito.eq(uuid))).thenReturn(true);
when(plugin.getPlayers()).thenReturn(pm);
// Test the reset command
// Does not have island
assertFalse(irc.execute(user, new ArrayList<>()));
Mockito.verify(user).sendMessage("general.errors.no-island");
// Now has island, but is not the leader
when(im.hasIsland(Mockito.eq(uuid))).thenReturn(true);
assertFalse(irc.execute(user, new ArrayList<>()));
Mockito.verify(user).sendMessage("general.errors.not-leader");
// Now is owner, but still has team
when(im.isOwner(Mockito.eq(uuid))).thenReturn(true);
assertFalse(irc.execute(user, new ArrayList<>()));
Mockito.verify(user).sendMessage("commands.island.reset.must-remove-members");
// Now has no team
when(pm.inTeam(Mockito.eq(uuid))).thenReturn(false);
// Block based on no resets left
when(s.getResetLimit()).thenReturn(1);
when(pm.getResetsLeft(Mockito.eq(uuid))).thenReturn(0);
assertFalse(irc.execute(user, new ArrayList<>()));
Mockito.verify(user).sendMessage("commands.island.reset.none-left");
// Give the user some resets
when(pm.getResetsLeft(Mockito.eq(uuid))).thenReturn(1);
// No confirmation required
when(s.isResetConfirmation()).thenReturn(false);
// Old island
Island oldIsland = mock(Island.class);
when(im.getIsland(Mockito.eq(uuid))).thenReturn(oldIsland);
// Mock up NewIsland
NewIsland.Builder builder = mock(NewIsland.Builder.class);
when(builder.player(Mockito.any())).thenReturn(builder);
when(builder.oldIsland(Mockito.any())).thenReturn(builder);
when(builder.reason(Mockito.any())).thenReturn(builder);
when(builder.build()).thenReturn(mock(Island.class));
PowerMockito.mockStatic(NewIsland.class);
when(NewIsland.builder()).thenReturn(builder);
// Reset
assertTrue(irc.execute(user, new ArrayList<>()));
Mockito.verify(builder).build();
Mockito.verify(user).sendMessage("commands.island.reset.resets-left", "[number]", "1");
}
}