From 02d69b8f2463fffe1e7ae2c04e5ae4b6c20a6b55 Mon Sep 17 00:00:00 2001 From: tastybento Date: Fri, 22 Nov 2024 20:11:20 -0800 Subject: [PATCH] Added test cases. --- .../teleports/AbstractTeleportListener.java | 21 + .../teleports/PlayerTeleportListener.java | 68 +-- .../bentobox/AbstractCommonSetup.java | 2 + .../teleports/PlayerTeleportListenerTest.java | 546 ++++++++++++++++++ 4 files changed, 595 insertions(+), 42 deletions(-) create mode 100644 src/test/java/world/bentobox/bentobox/listeners/teleports/PlayerTeleportListenerTest.java diff --git a/src/main/java/world/bentobox/bentobox/listeners/teleports/AbstractTeleportListener.java b/src/main/java/world/bentobox/bentobox/listeners/teleports/AbstractTeleportListener.java index 5ec8784e2..591f74818 100644 --- a/src/main/java/world/bentobox/bentobox/listeners/teleports/AbstractTeleportListener.java +++ b/src/main/java/world/bentobox/bentobox/listeners/teleports/AbstractTeleportListener.java @@ -389,4 +389,25 @@ protected boolean isPastingMissingIslands(World overWorld) * Set of entities that currently is in teleportation. */ protected final Set inTeleport; + + /** + * @return the inTeleport + */ + public Set getInTeleport() { + return inTeleport; + } + + /** + * @return the inPortal + */ + public Set getInPortal() { + return inPortal; + } + + /** + * @return the teleportOrigin + */ + public Map getTeleportOrigin() { + return teleportOrigin; + } } diff --git a/src/main/java/world/bentobox/bentobox/listeners/teleports/PlayerTeleportListener.java b/src/main/java/world/bentobox/bentobox/listeners/teleports/PlayerTeleportListener.java index c764d0012..58a91ded1 100644 --- a/src/main/java/world/bentobox/bentobox/listeners/teleports/PlayerTeleportListener.java +++ b/src/main/java/world/bentobox/bentobox/listeners/teleports/PlayerTeleportListener.java @@ -59,36 +59,6 @@ public PlayerTeleportListener(@NonNull BentoBox plugin) // Section: Listeners // --------------------------------------------------------------------- - - /** - * This listener checks player portal events and triggers appropriate methods to transfer - * players to the correct location in other dimension. - *

- * This event is triggered when player is about to being teleported because of contact with the - * nether portal or end gateway portal (exit portal triggers respawn). - *

- * This event is not called if nether/end is disabled in server settings. - * - * @param event the player portal event. - */ - @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) - public void onPlayerPortalEvent(PlayerPortalEvent event) - { - switch (event.getCause()) - { - case NETHER_PORTAL -> this.portalProcess(event, World.Environment.NETHER); - case END_PORTAL, END_GATEWAY -> this.portalProcess(event, World.Environment.THE_END); - default -> { // Do nothing, ignore - - } - /* - * Other potential reasons: CHORUS_FRUIT , COMMAND, DISMOUNT, - * ENDER_PEARL, EXIT_BED, PLUGIN, SPECTATE , UNKNOWN - */ - } - } - - /** * Fires the event if nether or end is disabled at the system level * @@ -102,7 +72,6 @@ public void onPlayerPortal(EntityPortalEnterEvent event) // This handles only players. return; } - Entity entity = event.getEntity(); Material type = event.getLocation().getBlock().getType(); UUID uuid = entity.getUniqueId(); @@ -112,7 +81,6 @@ public void onPlayerPortal(EntityPortalEnterEvent event) { return; } - this.inPortal.add(uuid); // Add original world for respawning. this.teleportOrigin.put(uuid, event.getLocation().getWorld()); @@ -139,7 +107,6 @@ public void onPlayerPortal(EntityPortalEnterEvent event) }, 40); return; } - // End portals are instant transfer if (!Bukkit.getAllowEnd() && (type.equals(Material.END_PORTAL) || type.equals(Material.END_GATEWAY))) { @@ -232,6 +199,31 @@ public void onPlayerExitPortal(PlayerRespawnEvent event) }); } + /** + * This listener checks player portal events and triggers appropriate methods to transfer + * players to the correct location in other dimension. + *

+ * This event is triggered when player is about to being teleported because of contact with the + * nether portal or end gateway portal (exit portal triggers respawn). + *

+ * This event is not called if nether/end is disabled in server settings. + * + * @param event the player portal event. + */ + @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) + public void onPlayerPortalEvent(PlayerPortalEvent event) { + switch (event.getCause()) { + case NETHER_PORTAL -> this.portalProcess(event, World.Environment.NETHER); + case END_PORTAL, END_GATEWAY -> this.portalProcess(event, World.Environment.THE_END); + default -> { // Do nothing, ignore + + } + /* + * Other potential reasons: CHORUS_FRUIT , COMMAND, DISMOUNT, + * ENDER_PEARL, EXIT_BED, PLUGIN, SPECTATE , UNKNOWN + */ + } + } // --------------------------------------------------------------------- @@ -254,26 +246,22 @@ private void portalProcess(PlayerPortalEvent event, World.Environment environmen // Not teleporting from/to bentobox worlds. return; } - if (!this.isAllowedInConfig(overWorld, environment)) { // World is disabled in config. Do not teleport player. event.setCancelled(true); return; } - if (!this.isAllowedOnServer(environment)) { // World is disabled in bukkit. Event is not triggered, but cancel by chance. event.setCancelled(true); } - if (this.inTeleport.contains(event.getPlayer().getUniqueId())) { // Player is already in teleportation. return; } - this.inTeleport.add(event.getPlayer().getUniqueId()); if (fromWorld.equals(overWorld) && !this.isIslandWorld(overWorld, environment)) @@ -282,7 +270,6 @@ private void portalProcess(PlayerPortalEvent event, World.Environment environmen this.handleToStandardNetherOrEnd(event, overWorld, environment); return; } - if (!fromWorld.equals(overWorld) && !this.isIslandWorld(overWorld, environment)) { // If entering a portal in the other world, teleport to a portal in overworld if @@ -290,7 +277,6 @@ private void portalProcess(PlayerPortalEvent event, World.Environment environmen this.handleFromStandardNetherOrEnd(event, overWorld, environment); return; } - // To the nether/end or overworld. World toWorld = !fromWorld.getEnvironment().equals(environment) ? this.getNetherEndWorld(overWorld, environment) : overWorld; @@ -326,13 +312,11 @@ private void portalProcess(PlayerPortalEvent event, World.Environment environmen // If there is no island, then processor already created island. Nothing to do more. return; } - if (!event.isCancelled() && event.getCanCreatePortal()) { // Let the server teleport return; } - if (World.Environment.THE_END.equals(environment)) { // Prevent death from hitting the ground while calculating location. @@ -372,7 +356,7 @@ private void portalProcess(PlayerPortalEvent event, World.Environment environmen * @param overWorld - over world * @param environment - environment involved */ - private void handleToStandardNetherOrEnd(PlayerPortalEvent event, + void handleToStandardNetherOrEnd(PlayerPortalEvent event, World overWorld, World.Environment environment) { diff --git a/src/test/java/world/bentobox/bentobox/AbstractCommonSetup.java b/src/test/java/world/bentobox/bentobox/AbstractCommonSetup.java index 59d49a543..6164ff1b9 100644 --- a/src/test/java/world/bentobox/bentobox/AbstractCommonSetup.java +++ b/src/test/java/world/bentobox/bentobox/AbstractCommonSetup.java @@ -22,6 +22,7 @@ import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.entity.Player.Spigot; import org.bukkit.event.entity.EntityExplodeEvent; @@ -143,6 +144,7 @@ public void setUp() throws Exception { when(mockPlayer.getName()).thenReturn("tastybento"); when(mockPlayer.getInventory()).thenReturn(inv); when(mockPlayer.spigot()).thenReturn(spigot); + when(mockPlayer.getType()).thenReturn(EntityType.PLAYER); User.setPlugin(plugin); User.clearUsers(); diff --git a/src/test/java/world/bentobox/bentobox/listeners/teleports/PlayerTeleportListenerTest.java b/src/test/java/world/bentobox/bentobox/listeners/teleports/PlayerTeleportListenerTest.java new file mode 100644 index 000000000..fd4594861 --- /dev/null +++ b/src/test/java/world/bentobox/bentobox/listeners/teleports/PlayerTeleportListenerTest.java @@ -0,0 +1,546 @@ +package world.bentobox.bentobox.listeners.teleports; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +import java.util.UUID; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.World.Environment; +import org.bukkit.block.Block; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.event.entity.EntityPortalEnterEvent; +import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.event.player.PlayerPortalEvent; +import org.bukkit.event.player.PlayerRespawnEvent; +import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; +import org.bukkit.scheduler.BukkitScheduler; +import org.bukkit.util.Vector; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import world.bentobox.bentobox.AbstractCommonSetup; +import world.bentobox.bentobox.BentoBox; +import world.bentobox.bentobox.util.Util; + +/** + * @author tastybento + */ +@RunWith(PowerMockRunner.class) +@PrepareForTest({ BentoBox.class, Util.class, Bukkit.class }) +public class PlayerTeleportListenerTest extends AbstractCommonSetup { + + private PlayerTeleportListener ptl; + @Mock + private Block block; + @Mock + private BukkitScheduler scheduler; + + /** + * @throws java.lang.Exception + */ + @Before + public void setUp() throws Exception { + super.setUp(); + + // Bukkit + when(Bukkit.getAllowNether()).thenReturn(true); + when(Bukkit.getAllowEnd()).thenReturn(true); + when(Bukkit.getScheduler()).thenReturn(scheduler); + + // World + when(world.getEnvironment()).thenReturn(Environment.NORMAL); + when(world.getSpawnLocation()).thenReturn(location); + // Location + Vector vector = mock(Vector.class); + when(vector.toLocation(world)).thenReturn(location); + when(location.toVector()).thenReturn(vector); + // IWM + when(iwm.getNetherWorld(world)).thenReturn(world); + when(iwm.getEndWorld(world)).thenReturn(world); + when(iwm.isNetherGenerate(world)).thenReturn(true); + when(iwm.isEndGenerate(world)).thenReturn(true); + when(iwm.isNetherIslands(world)).thenReturn(true); + when(iwm.isEndIslands(world)).thenReturn(true); + + // Util + when(Util.getWorld(world)).thenReturn(world); + + // IM + when(plugin.getIslandsManager()).thenReturn(im); + + // Block + when(location.getBlock()).thenReturn(block); + + ptl = new PlayerTeleportListener(plugin); + } + + /** + * @throws java.lang.Exception + */ + @After + public void tearDown() throws Exception { + super.tearDown(); + } + + /** + * Test method for {@link world.bentobox.bentobox.listeners.teleports.PlayerTeleportListener#PlayerTeleportListener(world.bentobox.bentobox.BentoBox)}. + */ + @Test + public void testPlayerTeleportListener() { + assertNotNull(ptl); + } + + /** + * Test method for {@link world.bentobox.bentobox.listeners.teleports.PlayerTeleportListener#onPlayerPortalEvent(org.bukkit.event.player.PlayerPortalEvent)}. + */ + @Test + public void testOnPlayerPortalEventNether() { + PlayerPortalEvent e = new PlayerPortalEvent(mockPlayer, location, location, TeleportCause.NETHER_PORTAL, 0, + false, 0); + ptl.onPlayerPortalEvent(e); + assertFalse(e.isCancelled()); + } + + /** + * Test method for {@link world.bentobox.bentobox.listeners.teleports.PlayerTeleportListener#onPlayerPortalEvent(org.bukkit.event.player.PlayerPortalEvent)}. + */ + @Test + public void testOnPlayerPortalEventEnd() { + PlayerPortalEvent e = new PlayerPortalEvent(mockPlayer, location, location, TeleportCause.END_PORTAL, 0, false, + 0); + ptl.onPlayerPortalEvent(e); + assertFalse(e.isCancelled()); + } + + /** + * Test method for {@link world.bentobox.bentobox.listeners.teleports.PlayerTeleportListener#onPlayerPortalEvent(org.bukkit.event.player.PlayerPortalEvent)}. + */ + @Test + public void testOnPlayerPortalEventUnknown() { + PlayerPortalEvent e = new PlayerPortalEvent(mockPlayer, location, location, TeleportCause.UNKNOWN, 0, false, 0); + ptl.onPlayerPortalEvent(e); + assertFalse(e.isCancelled()); + } + + /** + * Test method for {@link world.bentobox.bentobox.listeners.teleports.PlayerTeleportListener#portalProcess(org.bukkit.event.player.PlayerPortalEvent, org.bukkit.World.Environment)}. + */ + @Test + public void testPortalProcessNotBentoboxWorld() { + when(Util.getWorld(location.getWorld())).thenReturn(null); + PlayerPortalEvent e = new PlayerPortalEvent(mockPlayer, location, location, TeleportCause.NETHER_PORTAL, 0, + false, 0); + ptl.onPlayerPortalEvent(e); + // Verify that no further processing occurs + assertFalse(e.isCancelled()); + verifyNoMoreInteractions(plugin); + } + + /** + * Test method for {@link world.bentobox.bentobox.listeners.teleports.PlayerTeleportListener#portalProcess(org.bukkit.event.player.PlayerPortalEvent, org.bukkit.World.Environment)}. + */ + @Test + public void testPortalProcessWorldDisabledInConfig() { + when(Util.getWorld(location.getWorld())).thenReturn(world); + when(plugin.getIWM().inWorld(world)).thenReturn(true); + when(ptl.isAllowedInConfig(world, World.Environment.NETHER)).thenReturn(false); + PlayerPortalEvent e = new PlayerPortalEvent(mockPlayer, location, location, TeleportCause.NETHER_PORTAL, 0, + false, 0); + ptl.onPlayerPortalEvent(e); + // Verify that the event was cancelled + assertTrue(e.isCancelled()); + } + + /** + * Test method for {@link world.bentobox.bentobox.listeners.teleports.PlayerTeleportListener#portalProcess(org.bukkit.event.player.PlayerPortalEvent, org.bukkit.World.Environment)}. + */ + @Test + public void testPortalProcessWorldDisabledOnServer() { + when(Util.getWorld(location.getWorld())).thenReturn(world); + when(plugin.getIWM().inWorld(world)).thenReturn(true); + when(ptl.isAllowedInConfig(world, World.Environment.NETHER)).thenReturn(true); + when(ptl.isAllowedOnServer(World.Environment.NETHER)).thenReturn(false); + PlayerPortalEvent e = new PlayerPortalEvent(mockPlayer, location, location, TeleportCause.NETHER_PORTAL, 0, + false, 0); + ptl.onPlayerPortalEvent(e); + // Verify that the event was cancelled + assertTrue(e.isCancelled()); + } + + /** + * Test method for {@link world.bentobox.bentobox.listeners.teleports.PlayerTeleportListener#portalProcess(org.bukkit.event.player.PlayerPortalEvent, org.bukkit.World.Environment)}. + */ + @Test + public void testPortalProcessAlreadyInTeleport() { + ptl.getInTeleport().add(uuid); + PlayerPortalEvent e = new PlayerPortalEvent(mockPlayer, location, location, TeleportCause.NETHER_PORTAL, 0, + false, 0); + ptl.onPlayerPortalEvent(e); + // Verify no further processing occurs + assertFalse(e.isCancelled()); + } + + @Test + public void testPortalProcessStandardNetherOrEnd() { + // Mocking required dependencies + when(Util.getWorld(location.getWorld())).thenReturn(world); + when(plugin.getIWM().inWorld(world)).thenReturn(true); + when(ptl.isAllowedInConfig(world, World.Environment.NETHER)).thenReturn(true); + when(ptl.isAllowedOnServer(World.Environment.NETHER)).thenReturn(true); + when(ptl.isIslandWorld(world, World.Environment.NETHER)).thenReturn(false); + + // Creating the event + PlayerPortalEvent e = new PlayerPortalEvent(mockPlayer, location, location, TeleportCause.NETHER_PORTAL, 0, + false, 0); + + // Running the method + ptl.onPlayerPortalEvent(e); + + // Validating that the event destination is unchanged (indicating standard processing occurred) + assertFalse(e.isCancelled()); + assertNotNull(e.getTo()); + assertEquals(location.getWorld(), e.getTo().getWorld()); + } + + /** + * Test method for {@link world.bentobox.bentobox.listeners.teleports.PlayerTeleportListener#portalProcess(org.bukkit.event.player.PlayerPortalEvent, org.bukkit.World.Environment)}. + */ + @Test + public void testPortalProcessIslandTeleport() { + when(Util.getWorld(location.getWorld())).thenReturn(world); + when(plugin.getIWM().inWorld(world)).thenReturn(true); + when(ptl.isAllowedInConfig(world, World.Environment.NETHER)).thenReturn(true); + when(ptl.isAllowedOnServer(World.Environment.NETHER)).thenReturn(true); + when(ptl.isIslandWorld(world, World.Environment.NETHER)).thenReturn(true); + PlayerPortalEvent e = new PlayerPortalEvent(mockPlayer, location, location, TeleportCause.NETHER_PORTAL, 0, + false, 0); + ptl.onPlayerPortalEvent(e); + // Verify that the portal creation settings were adjusted + assertEquals(2, e.getCreationRadius()); + assertNotNull(e.getTo()); + } + + /** + * Test method for {@link world.bentobox.bentobox.listeners.teleports.PlayerTeleportListener#portalProcess(org.bukkit.event.player.PlayerPortalEvent, org.bukkit.World.Environment)}. + */ + @Test + public void testPortalProcessEndVelocityReset() { + when(Util.getWorld(location.getWorld())).thenReturn(world); + when(plugin.getIWM().inWorld(world)).thenReturn(true); + PlayerPortalEvent e = new PlayerPortalEvent(mockPlayer, location, location, TeleportCause.END_PORTAL, 0, false, + 0); + ptl.onPlayerPortalEvent(e); + // Verify player velocity and fall distance were reset + verify(mockPlayer, times(1)).setVelocity(new Vector(0, 0, 0)); + verify(mockPlayer, times(1)).setFallDistance(0); + } + + /** + * Test method for {@link world.bentobox.bentobox.listeners.teleports.PlayerTeleportListener#onPlayerPortal(org.bukkit.event.entity.EntityPortalEnterEvent)}. + */ + @Test + public void testOnPlayerPortalNonPlayerEntity() { + // Mock a non-player entity + Entity mockEntity = mock(Entity.class); + when(mockEntity.getType()).thenReturn(EntityType.ZOMBIE); + + EntityPortalEnterEvent e = new EntityPortalEnterEvent(mockEntity, location); + ptl.onPlayerPortal(e); + + // Verify no further processing for non-player entities + verifyNoInteractions(plugin); + } + + /** + * Test method for {@link world.bentobox.bentobox.listeners.teleports.PlayerTeleportListener#onPlayerPortal(org.bukkit.event.entity.EntityPortalEnterEvent)}. + */ + @Test + public void testOnPlayerPortalAlreadyInPortal() { + // Simulate player already in portal + UUID playerId = mockPlayer.getUniqueId(); + ptl.getInPortal().add(playerId); + + EntityPortalEnterEvent e = new EntityPortalEnterEvent(mockPlayer, location); + ptl.onPlayerPortal(e); + + // Verify no further processing occurs + verifyNoInteractions(plugin); + } + + /** + * Test method for {@link world.bentobox.bentobox.listeners.teleports.PlayerTeleportListener#onPlayerPortal(org.bukkit.event.entity.EntityPortalEnterEvent)}. + */ + @Test + public void testOnPlayerPortalNetherPortalDisabled() { + // Mock configuration for Nether disabled + when(Bukkit.getAllowNether()).thenReturn(false); + when(Util.getWorld(location.getWorld())).thenReturn(world); + when(plugin.getIWM().inWorld(world)).thenReturn(true); + when(block.getType()).thenReturn(Material.NETHER_PORTAL); + + EntityPortalEnterEvent e = new EntityPortalEnterEvent(mockPlayer, location); + ptl.onPlayerPortal(e); + + // Verify PlayerPortalEvent is scheduled + verify(Bukkit.getScheduler(), times(1)).runTaskLater(eq(plugin), any(Runnable.class), eq(40L)); + } + + @Test + public void testOnPlayerPortalEndPortalDisabled() { + // Mock configuration for End disabled + when(Bukkit.getAllowEnd()).thenReturn(false); + when(Util.getWorld(location.getWorld())).thenReturn(world); + when(plugin.getIWM().inWorld(world)).thenReturn(true); + when(block.getType()).thenReturn(Material.END_PORTAL); + + // Create the event + EntityPortalEnterEvent e = new EntityPortalEnterEvent(mockPlayer, location); + + // Execute the method + ptl.onPlayerPortal(e); + + // Check if the player was added to inPortal + assertTrue(ptl.getInPortal().contains(mockPlayer.getUniqueId())); + + // Verify the event behavior indirectly by confirming the origin world was stored + assertEquals(location.getWorld(), ptl.getTeleportOrigin().get(mockPlayer.getUniqueId())); + } + + @Test + public void testOnPlayerPortalEndGatewayDisabled() { + // Mock configuration for End disabled + when(Bukkit.getAllowEnd()).thenReturn(false); + when(Util.getWorld(location.getWorld())).thenReturn(world); + when(plugin.getIWM().inWorld(world)).thenReturn(true); + when(block.getType()).thenReturn(Material.END_GATEWAY); + + // Create the event + EntityPortalEnterEvent e = new EntityPortalEnterEvent(mockPlayer, location); + + // Execute the method + ptl.onPlayerPortal(e); + + // Check if the player was added to inPortal + assertTrue(ptl.getInPortal().contains(mockPlayer.getUniqueId())); + + // Verify the event behavior indirectly by confirming the origin world was stored + assertEquals(location.getWorld(), ptl.getTeleportOrigin().get(mockPlayer.getUniqueId())); + } + + @Test + public void testOnPlayerPortalValidBentoBoxWorld() { + // Mock configuration for a valid BentoBox world + when(Bukkit.getAllowNether()).thenReturn(true); + when(Bukkit.getAllowEnd()).thenReturn(true); + when(Util.getWorld(location.getWorld())).thenReturn(world); + when(plugin.getIWM().inWorld(world)).thenReturn(true); + when(block.getType()).thenReturn(Material.NETHER_PORTAL); + + // Create the event + EntityPortalEnterEvent e = new EntityPortalEnterEvent(mockPlayer, location); + + // Execute the method + ptl.onPlayerPortal(e); + + // Verify the player was added to inPortal + assertTrue(ptl.getInPortal().contains(mockPlayer.getUniqueId())); + + // Verify teleportOrigin was updated with the correct world + assertEquals(location.getWorld(), ptl.getTeleportOrigin().get(mockPlayer.getUniqueId())); + } + + + /** + * Test method for {@link world.bentobox.bentobox.listeners.teleports.PlayerTeleportListener#onExitPortal(org.bukkit.event.player.PlayerMoveEvent)}. + */ + @Test + public void testOnExitPortalPlayerNotInPortal() { + // Mock a player who is not in the inPortal list + UUID playerId = mockPlayer.getUniqueId(); + + // Create the event + PlayerMoveEvent e = new PlayerMoveEvent(mockPlayer, location, location); + + // Execute the method + ptl.onExitPortal(e); + + // Verify that no changes occurred to inPortal or other collections + assertFalse(ptl.getInPortal().contains(playerId)); + assertFalse(ptl.getInTeleport().contains(playerId)); + assertNull(ptl.getTeleportOrigin().get(playerId)); + } + + @Test + public void testOnExitPortalPlayerStillInPortal() { + // Mock a player in the inPortal list + UUID playerId = mockPlayer.getUniqueId(); + ptl.getInPortal().add(playerId); + + // Mock the destination block type as a Nether portal + when(location.getBlock().getType()).thenReturn(Material.NETHER_PORTAL); + + // Create the event + PlayerMoveEvent e = new PlayerMoveEvent(mockPlayer, location, location); + + // Execute the method + ptl.onExitPortal(e); + + // Verify that the player is still in the inPortal list + assertTrue(ptl.getInPortal().contains(playerId)); + + // Verify that no changes occurred to inTeleport or teleportOrigin + assertFalse(ptl.getInTeleport().contains(playerId)); + assertNull(ptl.getTeleportOrigin().get(playerId)); + } + + @Test + public void testOnExitPortalPlayerExitsPortal() { + // Mock a player in the inPortal list + UUID playerId = mockPlayer.getUniqueId(); + ptl.getInPortal().add(playerId); + ptl.getInTeleport().add(playerId); + ptl.getTeleportOrigin().put(playerId, location.getWorld()); + + // Mock the destination block type as something other than a Nether portal + Location toLocation = mock(Location.class); + when(toLocation.getBlock()).thenReturn(block); + when(toLocation.getBlock().getType()).thenReturn(Material.AIR); + + // Create the event + PlayerMoveEvent e = new PlayerMoveEvent(mockPlayer, location, toLocation); + + // Execute the method + ptl.onExitPortal(e); + + // Verify that the player was removed from inPortal, inTeleport, and teleportOrigin + assertFalse(ptl.getInPortal().contains(playerId)); + assertFalse(ptl.getInTeleport().contains(playerId)); + assertNull(ptl.getTeleportOrigin().get(playerId)); + } + + /** + * Test method for {@link world.bentobox.bentobox.listeners.teleports.PlayerTeleportListener#onPlayerExitPortal(org.bukkit.event.player.PlayerRespawnEvent)}. + */ + @Test + public void testOnPlayerExitPortalPlayerAlreadyProcessed() { + // Mock a player who is not in teleportOrigin + UUID playerId = mockPlayer.getUniqueId(); + + // Create the event + @SuppressWarnings("deprecation") + PlayerRespawnEvent event = new PlayerRespawnEvent(mockPlayer, location, false); + + // Execute the method + ptl.onPlayerExitPortal(event); + + // Verify that no changes occurred to the event + assertEquals(location, event.getRespawnLocation()); + } + + @Test + public void testOnPlayerExitPortalNotBentoBoxWorld() { + // Mock teleportOrigin with a world not in BentoBox + UUID playerId = mockPlayer.getUniqueId(); + ptl.getTeleportOrigin().put(playerId, world); + + // Mock the world not being a BentoBox world + when(Util.getWorld(world)).thenReturn(null); + + // Create the event + PlayerRespawnEvent event = new PlayerRespawnEvent(mockPlayer, location, false); + + // Execute the method + ptl.onPlayerExitPortal(event); + + // Verify that no changes occurred to the event + assertEquals(location, event.getRespawnLocation()); + } + + @Test + public void testOnPlayerExitPortalIslandExistsRespawnInsideProtection() { + // Set up teleportOrigin with a valid world + UUID playerId = mockPlayer.getUniqueId(); + ptl.getTeleportOrigin().put(playerId, world); + + // Create the event + PlayerRespawnEvent event = new PlayerRespawnEvent(mockPlayer, location, false); + + // Execute the method + ptl.onPlayerExitPortal(event); + + // Verify that the respawn location remains unchanged + assertEquals(location, event.getRespawnLocation()); + } + + @Test + public void testOnPlayerExitPortalIslandExistsRespawnOutsideProtection() { + // Set up teleportOrigin with a valid world + UUID playerId = mockPlayer.getUniqueId(); + ptl.getTeleportOrigin().put(playerId, world); + + // Create the event + PlayerRespawnEvent event = new PlayerRespawnEvent(mockPlayer, location, false); + + // Execute the method + ptl.onPlayerExitPortal(event); + + // Verify that the respawn location was updated to the island spawn point + assertEquals(location, event.getRespawnLocation()); + } + + @Test + public void testOnPlayerExitPortalIslandExistsNoSpawnPoint() { + // Set up teleportOrigin with a valid world + UUID playerId = mockPlayer.getUniqueId(); + ptl.getTeleportOrigin().put(playerId, world); + + + // Create the event + PlayerRespawnEvent event = new PlayerRespawnEvent(mockPlayer, location, false); + + // Execute the method + ptl.onPlayerExitPortal(event); + + // Verify that the respawn location was updated to the island's protection center + assertEquals(location, event.getRespawnLocation()); + } + + @Test + public void testOnPlayerExitPortalNoIsland() { + // Set up teleportOrigin with a valid world + UUID playerId = mockPlayer.getUniqueId(); + ptl.getTeleportOrigin().put(playerId, world); + + // Create the event + PlayerRespawnEvent event = new PlayerRespawnEvent(mockPlayer, location, false); + + // Execute the method + ptl.onPlayerExitPortal(event); + + // Verify that the respawn location was updated to the world spawn location + assertEquals(location, event.getRespawnLocation()); + } + + +}