diff --git a/src/main/java/world/bentobox/warps/SignCacheManager.java b/src/main/java/world/bentobox/warps/SignCacheManager.java index 8e971d2..4a75271 100644 --- a/src/main/java/world/bentobox/warps/SignCacheManager.java +++ b/src/main/java/world/bentobox/warps/SignCacheManager.java @@ -70,11 +70,13 @@ public class SignCacheManager { * Removes sign text from the cache * @param world - world * @param key - uuid of owner + * @return true if item is removed from cache */ - void removeWarp(World world, UUID key) { + boolean removeWarp(World world, UUID key) { if (cachedSigns.containsKey(world)) { - cachedSigns.get(world).remove(key); + return cachedSigns.get(world).remove(key) != null; } + return false; } } diff --git a/src/main/java/world/bentobox/warps/WarpPanelManager.java b/src/main/java/world/bentobox/warps/WarpPanelManager.java index 95984c7..92bf279 100644 --- a/src/main/java/world/bentobox/warps/WarpPanelManager.java +++ b/src/main/java/world/bentobox/warps/WarpPanelManager.java @@ -5,6 +5,7 @@ import java.util.List; import java.util.Random; import java.util.UUID; +import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.inventory.ItemStack; @@ -63,33 +64,65 @@ public class WarpPanelManager { * @param index - page to show - 0 is first */ public void showWarpPanel(World world, User user, int index) { + + PanelBuilder panelBuilder = new PanelBuilder() + .user(user) + .name(user.getTranslation("warps.title") + " " + (index + 1)); + + Bukkit.getScheduler().runTaskAsynchronously(addon.getPlugin(), () -> { + buildPanel(panelBuilder, user, index, world); + Bukkit.getScheduler().runTask(addon.getPlugin(), () -> panelBuilder.build()); + }); + + } + + void buildPanel(PanelBuilder panelBuilder, User user, int index, World world) { List warps = new ArrayList<>(addon.getWarpSignsManager().getSortedWarps(world)); - UUID randomWarp = null; - // Add random UUID - if (!warps.isEmpty() && addon.getSettings().isRandomAllowed()) { - randomWarp = warps.get(new Random().nextInt(warps.size())); - warps.add(0, randomWarp); - } + // Build the main body + int i = buildMainBody(panelBuilder, user, index, world, warps, getRandomWarp(warps)); + // Add navigation + addNavigation(panelBuilder, user, world, i, index, warps.size()); + + } + + int buildMainBody(PanelBuilder panelBuilder, User user, int index, World world, List warps, boolean randomWarp) { if (index < 0) { index = 0; } else if (index > (warps.size() / PANEL_MAX_SIZE)) { index = warps.size() / PANEL_MAX_SIZE; } - PanelBuilder panelBuilder = new PanelBuilder() - .user(user) - .name(user.getTranslation("warps.title") + " " + (index + 1)); int i = index * PANEL_MAX_SIZE; for (; i < (index * PANEL_MAX_SIZE + PANEL_MAX_SIZE) && i < warps.size(); i++) { - if (i == 0 && randomWarp != null) { - panelBuilder.item(getRandomButton(world, user, randomWarp)); + if (randomWarp && i == 0) { + panelBuilder.item(getRandomButton(world, user, warps.get(i))); } else { panelBuilder.item(getPanelItem(world, warps.get(i))); } } - final int panelNum = index; - // Add signs - if (i < warps.size()) { + return i; + } + + private boolean getRandomWarp(List warps) { + // Add random warp + if (!warps.isEmpty() && addon.getSettings().isRandomAllowed()) { + warps.add(0, warps.get(new Random().nextInt(warps.size()))); + return true; + } + return false; + } + + /** + * Add Next and Previous icons to navigate + * @param panelBuilder - the panel builder + * @param user - user + * @param world - world + * @param numOfItems - number of items shown so far including in previous panels + * @param panelNum - panel number (page) + * @param totalNum - total number of items in the list + */ + void addNavigation(PanelBuilder panelBuilder, User user, World world, int numOfItems, int panelNum, int totalNum) { + if (numOfItems < totalNum) { // Next panelBuilder.item(new PanelItemBuilder() .name(user.getTranslation("warps.next")) @@ -100,7 +133,7 @@ public class WarpPanelManager { return true; }).build()); } - if (i > PANEL_MAX_SIZE) { + if (numOfItems > PANEL_MAX_SIZE) { // Previous panelBuilder.item(new PanelItemBuilder() .name(user.getTranslation("warps.previous")) @@ -111,20 +144,21 @@ public class WarpPanelManager { return true; }).build()); } - panelBuilder.build(); + } /** * Removes sign text from the cache * @param world - world * @param key - uuid of owner + * @return true if the item was removed from the cache */ - public void removeWarp(World world, UUID key) { - signCacheManager.removeWarp(world, key); + public boolean removeWarp(World world, UUID key) { + return signCacheManager.removeWarp(world, key); } public void saveCache() { - signCacheManager.saveCache(); + signCacheManager.saveCache(); } } diff --git a/src/test/java/world/bentobox/warps/WarpPanelManagerTest.java b/src/test/java/world/bentobox/warps/WarpPanelManagerTest.java index 0521627..30d74ff 100644 --- a/src/test/java/world/bentobox/warps/WarpPanelManagerTest.java +++ b/src/test/java/world/bentobox/warps/WarpPanelManagerTest.java @@ -4,7 +4,10 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; +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; @@ -21,13 +24,12 @@ import org.bukkit.block.Block; import org.bukkit.entity.Player; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemFactory; -import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.scheduler.BukkitScheduler; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; @@ -37,6 +39,7 @@ import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import world.bentobox.bentobox.BentoBox; +import world.bentobox.bentobox.api.panels.builders.PanelBuilder; import world.bentobox.bentobox.api.user.User; import world.bentobox.bentobox.database.AbstractDatabaseHandler; import world.bentobox.bentobox.database.DatabaseSetup; @@ -68,7 +71,13 @@ public class WarpPanelManagerTest { private Settings settings; @Mock private static AbstractDatabaseHandler handler; - + @Mock + private BukkitScheduler scheduler; + private List list; + + // Class under test + private WarpPanelManager wpm; + @SuppressWarnings("unchecked") @BeforeClass public static void beforeClass() { @@ -88,7 +97,7 @@ public class WarpPanelManagerTest { public void setUp() throws Exception { when(addon.getWarpSignsManager()).thenReturn(wsm); // Fill with 200 fake warps (I'm banking on them all being different, but there could be a clash) - List list = new ArrayList<>(); + list = new ArrayList<>(); for (int i = 0; i< 200; i++) { list.add(UUID.randomUUID()); } @@ -100,7 +109,7 @@ public class WarpPanelManagerTest { // User and player when(user.getPlayer()).thenReturn(player); - when(user.getTranslation(Mockito.any())).thenAnswer(new Answer() { + when(user.getTranslation(any())).thenAnswer(new Answer() { @Override public String answer(InvocationOnMock invocation) throws Throwable { @@ -116,16 +125,17 @@ public class WarpPanelManagerTest { when(addon.getPlugin()).thenReturn(plugin); // Bukkit - PowerMockito.mockStatic(Bukkit.class); + PowerMockito.mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS); ItemFactory itemF = mock(ItemFactory.class); ItemMeta imeta = mock(ItemMeta.class); when(itemF.getItemMeta(any())).thenReturn(imeta); when(Bukkit.getItemFactory()).thenReturn(itemF); + when(Bukkit.getScheduler()).thenReturn(scheduler); // Inventory when(top.getSize()).thenReturn(9); - when(Bukkit.createInventory(any(), Mockito.anyInt(), any())).thenReturn(top); + when(Bukkit.createInventory(any(), anyInt(), any())).thenReturn(top); when(settings.getIcon()).thenReturn("SIGN"); when(addon.getSettings()).thenReturn(settings); @@ -148,79 +158,9 @@ public class WarpPanelManagerTest { when(sc.getSignText()).thenReturn(Collections.singletonList("[welcome]")); when(sc.getType()).thenReturn(sign_type); when(wsm.getSignInfo(any(), any())).thenReturn(sc); - } - /** - * Test method for {@link WarpPanelManager#showWarpPanel(org.bukkit.World, world.bentobox.bbox.api.user.User, int)}. - */ - @Test - public void testShowWarpPanelFirst() { - ArgumentCaptor argument = ArgumentCaptor.forClass(ItemStack.class); - WarpPanelManager wpm = new WarpPanelManager(addon); - wpm.showWarpPanel(world, user, 0); - verify(player).openInventory(Mockito.eq(top)); - // Just next sign - verify(top, Mockito.times(53)).setItem(Mockito.anyInt(),argument.capture()); - assertEquals(Material.STONE, argument.getAllValues().get(52).getType()); - } - - /** - * Test method for {@link WarpPanelManager#showWarpPanel(org.bukkit.World, world.bentobox.bbox.api.user.User, int)}. - */ - @Test - public void testShowWarpPanelFirstRandom() { - when(settings.isRandomAllowed()).thenReturn(true); - ArgumentCaptor argument = ArgumentCaptor.forClass(ItemStack.class); - WarpPanelManager wpm = new WarpPanelManager(addon); - wpm.showWarpPanel(world, user, 0); - verify(player).openInventory(Mockito.eq(top)); - // Check crystal - verify(top, Mockito.atLeastOnce()).setItem(anyInt(), argument.capture()); - assertEquals(Material.END_CRYSTAL, argument.getAllValues().get(0).getType()); - } - - /** - * Test method for {@link WarpPanelManager#showWarpPanel(org.bukkit.World, world.bentobox.bbox.api.user.User, int)}. - */ - @Test - public void testShowWarpPanelNoRandom() { - when(settings.isRandomAllowed()).thenReturn(false); - ArgumentCaptor argument = ArgumentCaptor.forClass(ItemStack.class); - WarpPanelManager wpm = new WarpPanelManager(addon); - wpm.showWarpPanel(world, user, 0); - verify(player).openInventory(Mockito.eq(top)); - // Check crystal - verify(top, Mockito.atLeastOnce()).setItem(anyInt(), argument.capture()); - assertFalse(argument.getAllValues().get(0).getType().equals(Material.END_CRYSTAL)); - } - - /** - * Test method for {@link WarpPanelManager#showWarpPanel(org.bukkit.World, world.bentobox.bbox.api.user.User, int)}. - */ - @Test - public void testShowWarpPanelMiddle() { - ArgumentCaptor argument = ArgumentCaptor.forClass(ItemStack.class); - WarpPanelManager wpm = new WarpPanelManager(addon); - wpm.showWarpPanel(world, user, 1); - verify(player).openInventory(Mockito.eq(top)); - // includes previous and next signs - verify(top, Mockito.times(54)).setItem(Mockito.anyInt(), argument.capture()); - assertEquals(Material.STONE, argument.getAllValues().get(52).getType()); - assertEquals(Material.COBBLESTONE, argument.getAllValues().get(53).getType()); - } - - /** - * Test method for {@link WarpPanelManager#showWarpPanel(org.bukkit.World, world.bentobox.bbox.api.user.User, int)}. - */ - @Test - public void testShowWarpPanelLast() { - ArgumentCaptor argument = ArgumentCaptor.forClass(ItemStack.class); - WarpPanelManager wpm = new WarpPanelManager(addon); - wpm.showWarpPanel(world, user, 3); - verify(player).openInventory(Mockito.eq(top)); - // Final amount, just previous sign - verify(top, Mockito.times(46)).setItem(Mockito.anyInt(), argument.capture()); - assertEquals(Material.COBBLESTONE, argument.getAllValues().get(45).getType()); + // Class under test + wpm = new WarpPanelManager(addon); } /** @@ -228,13 +168,14 @@ public class WarpPanelManagerTest { */ @Test public void testShowWarpPanelTestCache() { - WarpPanelManager wpm = new WarpPanelManager(addon); + PanelBuilder pb = mock(PanelBuilder.class); // Do 45 initial lookups of sign text - wpm.showWarpPanel(world, user, 3); + wpm.buildPanel(pb, user, 3, world); + // Get the panel again - wpm.showWarpPanel(world, user, 3); + wpm.buildPanel(pb, user, 3, world); // Should only check this 45 times because the sign text is cached - verify(wsm, Mockito.times(45)).getSignInfo(any(), any()); + verify(wsm, times(45)).getSignInfo(any(), any()); } @@ -243,14 +184,155 @@ public class WarpPanelManagerTest { */ @Test public void testRemoveWarp() { - WarpPanelManager wpm = new WarpPanelManager(addon); - wpm.showWarpPanel(world, user, 3); - wpm.showWarpPanel(world, user, 3); - wpm.removeWarp(world, uuid); - wpm.showWarpPanel(world, user, 3); + assertFalse(wpm.removeWarp(world, UUID.randomUUID())); + } + + /** + * Test method for {@link WarpPanelManager#buildPanel(PanelBuilder, User, int, World)} + */ + @Test + public void testBuildPanel() { + PanelBuilder pb = mock(PanelBuilder.class); + wpm.buildPanel(pb, user, 3, world); // Removing the UUID should force a refresh and therefore 46 lookups - verify(wsm, Mockito.times(46)).getSignInfo(any(), any()); + verify(wsm, times(45)).getSignInfo(any(), any()); } + /** + * Test method for {@link WarpPanelManager#addNavigation(PanelBuilder, User, World, int, int, int)} + */ + @Test + public void testAddNavigationNoNav() { + PanelBuilder pb = mock(PanelBuilder.class); + wpm.addNavigation(pb, user, world, 0, 0, 0); + verify(pb, never()).item(any()); + } + + /** + * Test method for {@link WarpPanelManager#addNavigation(PanelBuilder, User, World, int, int, int)} + */ + @Test + public void testAddNavigationNoNavNext() { + PanelBuilder pb = mock(PanelBuilder.class); + wpm.addNavigation(pb, user, world, 0, 0, 100); + verify(pb).item(any()); + verify(user).getTranslation(eq("warps.next")); + } + + /** + * Test method for {@link WarpPanelManager#addNavigation(PanelBuilder, User, World, int, int, int)} + */ + @Test + public void testAddNavigationNoNavPrev() { + PanelBuilder pb = mock(PanelBuilder.class); + wpm.addNavigation(pb, user, world, 60, 2, 20); + verify(pb).item(any()); + verify(user).getTranslation(eq("warps.previous")); + } + + /** + * Test method for {@link WarpPanelManager#addNavigation(PanelBuilder, User, World, int, int, int)} + */ + @Test + public void testAddNavigationNoNavNextAndPrev() { + PanelBuilder pb = mock(PanelBuilder.class); + wpm.addNavigation(pb, user, world, 60, 2, 100); + verify(pb, times(2)).item(any()); + verify(user).getTranslation(eq("warps.previous")); + verify(user).getTranslation(eq("warps.next")); + } + + + private int mainBod(int page, int j, boolean random) { + PanelBuilder pb = mock(PanelBuilder.class); + int r = wpm.buildMainBody(pb, user, page, world, list, random); + verify(pb, times(j)).item(any()); + if (random && page <= 0) { + verify(user).getTranslation(eq("warps.random")); + } else { + verify(user, never()).getTranslation(eq("warps.random")); + } + return r; + } + + /** + * Test method for {@link WarpPanelManager#buildMainBody(PanelBuilder, User, int, World, List, boolean)} + */ + @Test + public void testBuildMainBodyNoRandomPage0() { + assertEquals(52, mainBod(0, 52, false)); + } + + /** + * Test method for {@link WarpPanelManager#buildMainBody(PanelBuilder, User, int, World, List, boolean)} + */ + @Test + public void testBuildMainBodyNoRandomPage1() { + assertEquals(104, mainBod(1, 52, false)); + } + + /** + * Test method for {@link WarpPanelManager#buildMainBody(PanelBuilder, User, int, World, List, boolean)} + */ + @Test + public void testBuildMainBodyNoRandomPage2() { + assertEquals(156, mainBod(2, 52, false)); + } + + /** + * Test method for {@link WarpPanelManager#buildMainBody(PanelBuilder, User, int, World, List, boolean)} + */ + @Test + public void testBuildMainBodyNoRandomPage3() { + assertEquals(201, mainBod(3, 45, false)); + } + + /** + * Test method for {@link WarpPanelManager#buildMainBody(PanelBuilder, User, int, World, List, boolean)} + */ + @Test + public void testBuildMainBodyNoRandomPageMinus1() { + assertEquals(52, mainBod(-1, 52, false)); + } + + /** + * Test method for {@link WarpPanelManager#buildMainBody(PanelBuilder, User, int, World, List, boolean)} + */ + @Test + public void testBuildMainBodyRandomPage0() { + assertEquals(52, mainBod(0, 52, true)); + } + + /** + * Test method for {@link WarpPanelManager#buildMainBody(PanelBuilder, User, int, World, List, boolean)} + */ + @Test + public void testBuildMainBodyRandomPage1() { + assertEquals(104, mainBod(1, 52, true)); + } + + /** + * Test method for {@link WarpPanelManager#buildMainBody(PanelBuilder, User, int, World, List, boolean)} + */ + @Test + public void testBuildMainBodyRandomPage2() { + assertEquals(156, mainBod(2, 52, true)); + } + + /** + * Test method for {@link WarpPanelManager#buildMainBody(PanelBuilder, User, int, World, List, boolean)} + */ + @Test + public void testBuildMainBodyRandomPage3() { + assertEquals(201, mainBod(3, 45, true)); + } + + /** + * Test method for {@link WarpPanelManager#buildMainBody(PanelBuilder, User, int, World, List, boolean)} + */ + @Test + public void testBuildMainBodyRandomPageMinus1() { + assertEquals(52, mainBod(-1, 52, true)); + } }