From 281d422340128602daf0baf714bd9fad2c410d10 Mon Sep 17 00:00:00 2001 From: tastybento Date: Sun, 15 Oct 2023 19:00:28 -0700 Subject: [PATCH] Enables permissions to set how many islands a play can create. Multiple Island Permissions #2199 --- .../commands/island/IslandCreateCommand.java | 12 ++-- .../team/IslandTeamSetownerCommand.java | 5 +- .../island/IslandCreateCommandTest.java | 59 +++++++++++---- .../team/IslandTeamSetownerCommandTest.java | 72 +++++++++++++++---- 4 files changed, 113 insertions(+), 35 deletions(-) diff --git a/src/main/java/world/bentobox/bentobox/api/commands/island/IslandCreateCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/island/IslandCreateCommand.java index 186f28685..854b42b74 100644 --- a/src/main/java/world/bentobox/bentobox/api/commands/island/IslandCreateCommand.java +++ b/src/main/java/world/bentobox/bentobox/api/commands/island/IslandCreateCommand.java @@ -5,6 +5,7 @@ import org.eclipse.jdt.annotation.Nullable; +import world.bentobox.bentobox.api.addons.GameModeAddon; import world.bentobox.bentobox.api.commands.CompositeCommand; import world.bentobox.bentobox.api.events.island.IslandEvent.Reason; import world.bentobox.bentobox.api.user.User; @@ -48,12 +49,11 @@ public boolean canExecute(User user, String label, List args) { if (island.isReserved()) { return true; } - // Get how many islands this player has - int num = this.getIslands().getNumberOfConcurrentIslands(user.getUniqueId(), getWorld()); - int max = this.getIWM().getWorldSettings(getWorld()).getConcurrentIslands(); - if (num < max) { - return true; - } + } + // Get how many islands this player has + int num = this.getIslands().getNumberOfConcurrentIslands(user.getUniqueId(), getWorld()); + int max = user.getPermissionValue(this.getIWM().getAddon(getWorld()).map(GameModeAddon::getPermissionPrefix).orElse("") + "island.number", this.getIWM().getWorldSettings(getWorld()).getConcurrentIslands()); + if (num >= max) { // You cannot make an island user.sendMessage("general.errors.you-cannot-make"); return false; diff --git a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamSetownerCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamSetownerCommand.java index c4b38d279..981dc9af5 100644 --- a/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamSetownerCommand.java +++ b/src/main/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamSetownerCommand.java @@ -6,6 +6,7 @@ import org.eclipse.jdt.annotation.Nullable; +import world.bentobox.bentobox.api.addons.GameModeAddon; import world.bentobox.bentobox.api.commands.CompositeCommand; import world.bentobox.bentobox.api.events.IslandBaseEvent; import world.bentobox.bentobox.api.events.island.IslandEvent; @@ -64,7 +65,9 @@ public boolean canExecute(User user, String label, List args) { return false; } // Check how many islands target has - if (getIslands().getNumberOfConcurrentIslands(targetUUID, getWorld()) >= this.getIWM().getWorldSettings(getWorld()).getConcurrentIslands()) { + int num = getIslands().getNumberOfConcurrentIslands(targetUUID, getWorld()); + int max = user.getPermissionValue(this.getIWM().getAddon(getWorld()).map(GameModeAddon::getPermissionPrefix).orElse("") + "island.number", this.getIWM().getWorldSettings(getWorld()).getConcurrentIslands()); + if (num >= max) { // Too many user.sendMessage("commands.island.team.setowner.errors.at-max"); return false; diff --git a/src/test/java/world/bentobox/bentobox/api/commands/island/IslandCreateCommandTest.java b/src/test/java/world/bentobox/bentobox/api/commands/island/IslandCreateCommandTest.java index 9c5572668..0dad8587f 100644 --- a/src/test/java/world/bentobox/bentobox/api/commands/island/IslandCreateCommandTest.java +++ b/src/test/java/world/bentobox/bentobox/api/commands/island/IslandCreateCommandTest.java @@ -4,6 +4,8 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -13,6 +15,7 @@ import java.io.IOException; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.UUID; @@ -106,15 +109,17 @@ public void setUp() throws Exception { UUID uuid = UUID.randomUUID(); when(user.getUniqueId()).thenReturn(uuid); when(user.getPlayer()).thenReturn(player); - when(user.hasPermission(Mockito.anyString())).thenReturn(true); - when(user.getTranslation(Mockito.any())).thenAnswer((Answer) invocation -> invocation.getArgument(0, String.class)); + when(user.hasPermission(anyString())).thenReturn(true); + when(user.getTranslation(any())).thenAnswer((Answer) invocation -> invocation.getArgument(0, String.class)); + // Return the default value for perm questions by default + when(user.getPermissionValue(anyString(), anyInt())).thenAnswer((Answer) inv -> inv.getArgument(1, Integer.class)); User.setPlugin(plugin); // Set up user already User.getInstance(player); // Addon GameModeAddon addon = mock(GameModeAddon.class); - + when(addon.getPermissionPrefix()).thenReturn("bskyblock."); // Parent command has no aliases when(ic.getSubCommandAliases()).thenReturn(new HashMap<>()); @@ -144,10 +149,11 @@ public void setUp() throws Exception { PowerMockito.mockStatic(Bukkit.class); when(Bukkit.getScheduler()).thenReturn(sch); - // IWM friendly name + // IWM when(iwm.getFriendlyName(any())).thenReturn("BSkyBlock"); when(ws.getConcurrentIslands()).thenReturn(1); // One island allowed when(iwm.getWorldSettings(world)).thenReturn(ws); + when(iwm.getAddon(world)).thenReturn(Optional.of(addon)); when(plugin.getIWM()).thenReturn(iwm); // NewIsland @@ -209,6 +215,30 @@ public void testCanExecuteUserStringListOfStringHasIsland() { verify(user).sendMessage("general.errors.you-cannot-make"); } + /** + * Test method for {@link world.bentobox.bentobox.api.commands.island.IslandCreateCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. + */ + @Test + public void testCanExecuteUserStringListOfStringZeroAllowed() { + when(ws.getConcurrentIslands()).thenReturn(0); // No islands allowed + assertFalse(cc.canExecute(user, "", Collections.emptyList())); + verify(user).sendMessage("general.errors.you-cannot-make"); + + } + + /** + * Test method for {@link world.bentobox.bentobox.api.commands.island.IslandCreateCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. + */ + @Test + public void testCanExecuteUserStringListOfStringHasPerm() { + // Currently user has two islands + when(im.getNumberOfConcurrentIslands(user.getUniqueId(), world)).thenReturn(19); + // Perm + when(user.getPermissionValue(anyString(), anyInt())).thenReturn(20); // 20 allowed! + assertTrue(cc.canExecute(user, "", Collections.emptyList())); + verify(user, never()).sendMessage(anyString()); + } + /** * Test method for {@link world.bentobox.bentobox.api.commands.island.IslandCreateCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. */ @@ -216,20 +246,22 @@ public void testCanExecuteUserStringListOfStringHasIsland() { public void testCanExecuteUserStringListOfStringHasIslandReserved() { @Nullable Island island = mock(Island.class); - when(im.getIsland(any(), Mockito.any(User.class))).thenReturn(island); + when(im.getIsland(any(), any(User.class))).thenReturn(island); when(island.isReserved()).thenReturn(true); assertTrue(cc.canExecute(user, "", Collections.emptyList())); verify(user, never()).sendMessage("general.errors.already-have-island"); } + + /** * Test method for {@link world.bentobox.bentobox.api.commands.island.IslandCreateCommand#canExecute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. */ @Test public void testCanExecuteUserStringListOfStringTooManyIslands() { - when(im.getPrimaryIsland(any(), Mockito.any(UUID.class))).thenReturn(null); - when(im.inTeam(any(), Mockito.any(UUID.class))).thenReturn(false); + when(im.getPrimaryIsland(any(), any(UUID.class))).thenReturn(null); + when(im.inTeam(any(), any(UUID.class))).thenReturn(false); when(iwm.getMaxIslands(any())).thenReturn(100); when(im.getIslandCount(any())).thenReturn(100L); assertFalse(cc.canExecute(user, "", Collections.emptyList())); @@ -247,7 +279,7 @@ public void testExecuteUserStringListOfStringSuccess() throws Exception { // Has permission when(bpm.checkPerm(any(), any(), any())).thenReturn(true); - assertTrue(cc.execute(user, "", Collections.singletonList("custom"))); + assertTrue(cc.execute(user, "", List.of("custom"))); verify(builder).player(eq(user)); verify(builder).addon(any()); verify(builder).reason(eq(Reason.CREATE)); @@ -267,7 +299,7 @@ public void testExecuteUserStringListOfStringThrowException() throws Exception { when(bpm.checkPerm(any(), any(), any())).thenReturn(true); when(builder.build()).thenThrow(new IOException("commands.island.create.unable-create-island")); - assertFalse(cc.execute(user, "", Collections.singletonList("custom"))); + assertFalse(cc.execute(user, "", List.of("custom"))); verify(user).sendMessage("commands.island.create.creating-island"); verify(user).sendMessage("commands.island.create.unable-create-island"); verify(plugin).logError("Could not create island for player. commands.island.create.unable-create-island"); @@ -291,7 +323,7 @@ public void testExecuteUserStringListOfStringBundleNoPermission() { */ @Test public void testExecuteUserStringListOfStringUnknownBundle() { - assertFalse(cc.execute(user, "", Collections.singletonList("custom"))); + assertFalse(cc.execute(user, "", List.of("custom"))); verify(user).sendMessage(eq("commands.island.create.unknown-blueprint")); verify(user, never()).sendMessage("commands.island.create.creating-island"); } @@ -347,10 +379,9 @@ public void testExecuteUserStringListOfStringNoCooldown() { */ @Test public void testExecuteUserStringListOfStringShowPanel() { - Map map = new HashMap<>(); - map.put("bundle1", new BlueprintBundle()); - map.put("bundle2", new BlueprintBundle()); - map.put("bundle3", new BlueprintBundle()); + Map map = Map.of("bundle1", new BlueprintBundle(), + "bundle2", new BlueprintBundle(), + "bundle3", new BlueprintBundle()); when(bpm.getBlueprintBundles(any())).thenReturn(map); assertTrue(cc.execute(user, "", Collections.emptyList())); // Panel is shown, not the creation message diff --git a/src/test/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamSetownerCommandTest.java b/src/test/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamSetownerCommandTest.java index d0c6ed4d4..b67c9067e 100644 --- a/src/test/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamSetownerCommandTest.java +++ b/src/test/java/world/bentobox/bentobox/api/commands/island/team/IslandTeamSetownerCommandTest.java @@ -4,6 +4,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; @@ -14,6 +15,7 @@ import java.util.HashMap; import java.util.List; import java.util.Optional; +import java.util.Set; import java.util.UUID; import org.bukkit.Bukkit; @@ -29,6 +31,7 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.Mockito; +import org.mockito.stubbing.Answer; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; @@ -98,6 +101,8 @@ public void setUp() throws Exception { when(user.getUniqueId()).thenReturn(uuid); when(user.getPlayer()).thenReturn(player); when(user.getName()).thenReturn("tastybento"); + // Return the default value for perm questions by default + when(user.getPermissionValue(anyString(), anyInt())).thenAnswer((Answer) inv -> inv.getArgument(1, Integer.class)); // Parent command has no aliases ic = mock(CompositeCommand.class); @@ -196,7 +201,7 @@ public void testCanExecuteUserStringListOfStringNotOwner() { public void testCanExecuteUserStringListOfStringShowHelp() { when(im.inTeam(any(), any())).thenReturn(true); when(im.getOwner(any(), any())).thenReturn(uuid); - assertFalse(its.canExecute(user, "", Collections.emptyList())); + assertFalse(its.canExecute(user, "", List.of())); verify(user).sendMessage("commands.help.header","[label]", null); } @@ -208,7 +213,7 @@ public void testCanExecuteUserStringListOfStringUnknownPlayer() { when(im.inTeam(any(), any())).thenReturn(true); when(im.getOwner(any(), any())).thenReturn(uuid); when(pm.getUUID(anyString())).thenReturn(null); - assertFalse(its.canExecute(user, "", Collections.singletonList("tastybento"))); + assertFalse(its.canExecute(user, "", List.of("tastybento"))); verify(user).sendMessage("general.errors.unknown-player", TextVariables.NAME, "tastybento"); } @@ -220,7 +225,7 @@ public void testCanExecuteUserStringListOfStringSamePlayer() { when(im.inTeam(any(), any())).thenReturn(true); when(im.getOwner(any(), any())).thenReturn(uuid); when(pm.getUUID(anyString())).thenReturn(uuid); - assertFalse(its.canExecute(user, "", Collections.singletonList("tastybento"))); + assertFalse(its.canExecute(user, "", List.of("tastybento"))); verify(user).sendMessage("commands.island.team.setowner.errors.cant-transfer-to-yourself"); } @@ -233,14 +238,14 @@ public void testCanExecuteUserStringListOfStringTargetAtMaxIslands() { when(im.getOwner(any(), any())).thenReturn(uuid); UUID target = UUID.randomUUID(); when(pm.getUUID(anyString())).thenReturn(target); - when(im.getMembers(any(), any())).thenReturn(Collections.singleton(target)); + when(im.getMembers(any(), any())).thenReturn(Set.of(target)); @Nullable Island island = mock(Island.class); when(im.getIsland(any(), any(User.class))).thenReturn(island); when(im.getNumberOfConcurrentIslands(target, world)).thenReturn(3); - assertFalse(its.canExecute(user, "", Collections.singletonList("tastybento"))); + assertFalse(its.canExecute(user, "", List.of("tastybento"))); verify(user).sendMessage("commands.island.team.setowner.errors.at-max"); } @@ -252,11 +257,50 @@ public void testCanExecuteUserStringListOfStringTargetNotInTeam() { when(im.inTeam(any(), any())).thenReturn(true); when(im.getOwner(any(), any())).thenReturn(uuid); when(pm.getUUID(anyString())).thenReturn(UUID.randomUUID()); - when(im.getMembers(any(), any())).thenReturn(Collections.singleton(uuid)); - assertFalse(its.canExecute(user, "", Collections.singletonList("tastybento"))); + when(im.getMembers(any(), any())).thenReturn(Set.of(uuid)); + assertFalse(its.canExecute(user, "", List.of("tastybento"))); verify(user).sendMessage("commands.island.team.setowner.errors.target-is-not-member"); } + /** + * Test method for {@link world.bentobox.bentobox.api.commands.island.team.IslandTeamSetownerCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. + */ + @Test + public void testExecuteUserStringListOfStringTooManyConcurrent() { + when(im.getNumberOfConcurrentIslands(any(), eq(world))).thenReturn(20); + when(im.inTeam(any(), any())).thenReturn(true); + when(im.getOwner(any(), any())).thenReturn(uuid); + UUID target = UUID.randomUUID(); + when(pm.getUUID(anyString())).thenReturn(target); + when(im.getMembers(any(), any())).thenReturn(Set.of(target)); + @Nullable + Island island = mock(Island.class); + when(im.getIsland(any(), any(User.class))).thenReturn(island); + assertFalse(its.canExecute(user, "", List.of("tastybento"))); + verify(user).sendMessage("commands.island.team.setowner.errors.at-max"); + } + + /** + * Test method for {@link world.bentobox.bentobox.api.commands.island.team.IslandTeamSetownerCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. + */ + @Test + public void testExecuteUserStringListOfStringHasManyConcurrentAndPerm() { + when(user.getPermissionValue(anyString(), anyInt())).thenReturn(40); + when(im.getNumberOfConcurrentIslands(any(), eq(world))).thenReturn(20); + when(im.inTeam(any(), any())).thenReturn(true); + when(im.getOwner(any(), any())).thenReturn(uuid); + UUID target = UUID.randomUUID(); + when(pm.getUUID(anyString())).thenReturn(target); + when(im.getMembers(any(), any())).thenReturn(Set.of(target)); + @Nullable + Island island = mock(Island.class); + when(im.getIsland(any(), any(User.class))).thenReturn(island); + assertTrue(its.canExecute(user, "", List.of("tastybento"))); + assertTrue(its.execute(user, "", List.of("tastybento"))); + verify(im).setOwner(any(), eq(user), eq(target)); + verify(im).save(island); + } + /** * Test method for {@link world.bentobox.bentobox.api.commands.island.team.IslandTeamSetownerCommand#execute(world.bentobox.bentobox.api.user.User, java.lang.String, java.util.List)}. */ @@ -266,12 +310,12 @@ public void testExecuteUserStringListOfStringSuccess() { when(im.getOwner(any(), any())).thenReturn(uuid); UUID target = UUID.randomUUID(); when(pm.getUUID(anyString())).thenReturn(target); - when(im.getMembers(any(), any())).thenReturn(Collections.singleton(target)); + when(im.getMembers(any(), any())).thenReturn(Set.of(target)); @Nullable Island island = mock(Island.class); when(im.getIsland(any(), any(User.class))).thenReturn(island); - assertTrue(its.canExecute(user, "", Collections.singletonList("tastybento"))); - assertTrue(its.execute(user, "", Collections.singletonList("tastybento"))); + assertTrue(its.canExecute(user, "", List.of("tastybento"))); + assertTrue(its.execute(user, "", List.of("tastybento"))); verify(im).setOwner(any(), eq(user), eq(target)); verify(im).save(island); } @@ -281,7 +325,7 @@ public void testExecuteUserStringListOfStringSuccess() { */ @Test public void testTabCompleteUserStringListOfString() { - assertTrue(its.tabComplete(user, "", Collections.emptyList()).get().isEmpty()); + assertTrue(its.tabComplete(user, "", List.of()).get().isEmpty()); } /** @@ -289,7 +333,7 @@ public void testTabCompleteUserStringListOfString() { */ @Test public void testTabCompleteUserStringListOfStringUnknown() { - assertTrue(its.tabComplete(user, "ta", Collections.emptyList()).get().isEmpty()); + assertTrue(its.tabComplete(user, "ta", List.of()).get().isEmpty()); } /** @@ -299,8 +343,8 @@ public void testTabCompleteUserStringListOfStringUnknown() { public void testTabCompleteUserStringListOfStringMember() { UUID target = UUID.randomUUID(); when(pm.getName(any())).thenReturn("tastybento"); - when(im.getMembers(any(), any())).thenReturn(Collections.singleton(target)); - assertEquals("tastybento", its.tabComplete(user, "", Collections.emptyList()).get().get(0)); + when(im.getMembers(any(), any())).thenReturn(Set.of(target)); + assertEquals("tastybento", its.tabComplete(user, "", List.of()).get().get(0)); } }