mirror of
https://github.com/BentoBoxWorld/Limits.git
synced 2024-11-16 15:45:20 +01:00
commit
deda533db1
24
pom.xml
24
pom.xml
@ -39,13 +39,9 @@
|
||||
</issueManagement>
|
||||
|
||||
<distributionManagement>
|
||||
<snapshotRepository>
|
||||
<id>codemc-snapshots</id>
|
||||
<url>https://repo.codemc.org/repository/maven-snapshots</url>
|
||||
</snapshotRepository>
|
||||
<repository>
|
||||
<id>codemc-releases</id>
|
||||
<url>https://repo.codemc.org/repository/maven-releases</url>
|
||||
<id>bentoboxworld</id>
|
||||
<url>https://repo.codemc.org/repository/bentoboxworld/</url>
|
||||
</repository>
|
||||
</distributionManagement>
|
||||
|
||||
@ -57,14 +53,14 @@
|
||||
<!-- Non-minecraft related dependencies -->
|
||||
<powermock.version>2.0.9</powermock.version>
|
||||
<!-- More visible way how to change dependency versions -->
|
||||
<spigot.version>1.20.5-R0.1-SNAPSHOT</spigot.version>
|
||||
<bentobox.version>2.4.1-SNAPSHOT</bentobox.version>
|
||||
<spigot.version>1.21.3-R0.1-SNAPSHOT</spigot.version>
|
||||
<bentobox.version>2.7.1-SNAPSHOT</bentobox.version>
|
||||
<!-- Revision variable removes warning about dynamic version -->
|
||||
<revision>${build.version}-SNAPSHOT</revision>
|
||||
<!-- Do not change unless you want different name for local builds. -->
|
||||
<build.number>-LOCAL</build.number>
|
||||
<!-- This allows to change between versions. -->
|
||||
<build.version>1.25.1</build.version>
|
||||
<build.version>1.26.0</build.version>
|
||||
<sonar.projectKey>BentoBoxWorld_Limits</sonar.projectKey>
|
||||
<sonar.organization>bentobox-world</sonar.organization>
|
||||
<sonar.host.url>https://sonarcloud.io</sonar.host.url>
|
||||
@ -118,13 +114,13 @@
|
||||
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>codemc</id>
|
||||
<url>https://repo.codemc.org/repository/maven-snapshots/</url>
|
||||
<id>bentoboxworld</id>
|
||||
<url>https://repo.codemc.org/repository/bentoboxworld/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>codemc-repo</id>
|
||||
<url>https://repo.codemc.org/repository/maven-public/</url>
|
||||
</repository>
|
||||
<id>codemc</id>
|
||||
<url>https://repo.codemc.org/repository/maven-snapshots/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
|
@ -48,7 +48,7 @@ public class LimitTab implements Tab {
|
||||
.put(EntityType.IRON_GOLEM, Material.IRON_BLOCK)
|
||||
.put(EntityType.ILLUSIONER, Material.VILLAGER_SPAWN_EGG)
|
||||
.put(EntityType.WITHER, Material.WITHER_SKELETON_SKULL)
|
||||
.put(EntityType.BOAT, Material.OAK_BOAT)
|
||||
//.put(EntityType.BOAT, Material.OAK_BOAT)
|
||||
.put(EntityType.ARMOR_STAND, Material.ARMOR_STAND)
|
||||
.put(EntityType.ITEM_FRAME, Material.ITEM_FRAME)
|
||||
.put(EntityType.PAINTING, Material.PAINTING)
|
||||
@ -58,7 +58,7 @@ public class LimitTab implements Tab {
|
||||
.put(EntityType.FURNACE_MINECART, Material.FURNACE_MINECART)
|
||||
.put(EntityType.HOPPER_MINECART, Material.HOPPER_MINECART)
|
||||
.put(EntityType.SPAWNER_MINECART, Material.MINECART)
|
||||
.put(EntityType.CHEST_BOAT, Material.OAK_CHEST_BOAT)
|
||||
//.put(EntityType.CHEST_BOAT, Material.OAK_CHEST_BOAT)
|
||||
.build();
|
||||
// This is a map of blocks to Items
|
||||
private static final Map<Material, Material> B2M;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package bentobox.addon.limits.listeners;
|
||||
package world.bentobox.limits;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
@ -26,6 +26,7 @@ import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.permissions.PermissionAttachmentInfo;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.eclipse.jdt.annotation.Nullable;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@ -41,11 +42,9 @@ import world.bentobox.bentobox.api.events.island.IslandEvent;
|
||||
import world.bentobox.bentobox.api.events.team.TeamSetownerEvent;
|
||||
import world.bentobox.bentobox.database.objects.Island;
|
||||
import world.bentobox.bentobox.managers.IslandsManager;
|
||||
import world.bentobox.limits.EntityGroup;
|
||||
import world.bentobox.limits.Limits;
|
||||
import world.bentobox.limits.Settings;
|
||||
import world.bentobox.limits.listeners.BlockLimitsListener;
|
||||
import world.bentobox.limits.listeners.JoinListener;
|
||||
import world.bentobox.limits.mocks.ServerMocks;
|
||||
import world.bentobox.limits.objects.IslandBlockCount;
|
||||
|
||||
/**
|
||||
@ -82,55 +81,61 @@ public class JoinListenerTest {
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
jl = new JoinListener(addon);
|
||||
// Setup addon
|
||||
when(addon.getGameModes()).thenReturn(Collections.singletonList(bskyblock));
|
||||
when(addon.getGameModeName(any())).thenReturn("bskyblock");
|
||||
when(addon.getGameModePermPrefix(any())).thenReturn("bskyblock.");
|
||||
when(addon.getSettings()).thenReturn(settings);
|
||||
// Settings
|
||||
when(settings.getGroupLimitDefinitions())
|
||||
.thenReturn(new ArrayList<>(List.of(new EntityGroup("friendly", new HashSet<>(), -1, null))));
|
||||
// Island Manager
|
||||
when(island.getUniqueId()).thenReturn("unique_id");
|
||||
when(island.getOwner()).thenReturn(uuid);
|
||||
when(im.getIsland(any(), any(UUID.class))).thenReturn(island);
|
||||
when(im.getIslands(any(), any(UUID.class))).thenReturn(List.of(island));
|
||||
// Default is that player has island
|
||||
when(addon.getIslands()).thenReturn(im);
|
||||
// Player
|
||||
when(player.getUniqueId()).thenReturn(uuid);
|
||||
when(player.getName()).thenReturn("tastybento");
|
||||
// No permissions by default
|
||||
when(player.getEffectivePermissions()).thenReturn(Collections.emptySet());
|
||||
// bsKyBlock
|
||||
when(bskyblock.getPermissionPrefix()).thenReturn("bskyblock.");
|
||||
AddonDescription desc = new AddonDescription.Builder("main", "BSkyBlock", "1.0").build();
|
||||
when(bskyblock.getDescription()).thenReturn(desc);
|
||||
ServerMocks.newServer();
|
||||
jl = new JoinListener(addon);
|
||||
// Setup addon
|
||||
when(addon.getGameModes()).thenReturn(Collections.singletonList(bskyblock));
|
||||
when(addon.getGameModeName(any())).thenReturn("bskyblock");
|
||||
when(addon.getGameModePermPrefix(any())).thenReturn("bskyblock.");
|
||||
when(addon.getSettings()).thenReturn(settings);
|
||||
// Settings
|
||||
when(settings.getGroupLimitDefinitions())
|
||||
.thenReturn(new ArrayList<>(List.of(new EntityGroup("friendly", new HashSet<>(), -1, null))));
|
||||
// Island Manager
|
||||
when(island.getUniqueId()).thenReturn("unique_id");
|
||||
when(island.getOwner()).thenReturn(uuid);
|
||||
when(im.getIsland(any(), any(UUID.class))).thenReturn(island);
|
||||
when(im.getIslands(any(), any(UUID.class))).thenReturn(List.of(island));
|
||||
// Default is that player has island
|
||||
when(addon.getIslands()).thenReturn(im);
|
||||
// Player
|
||||
when(player.getUniqueId()).thenReturn(uuid);
|
||||
when(player.getName()).thenReturn("tastybento");
|
||||
// No permissions by default
|
||||
when(player.getEffectivePermissions()).thenReturn(Collections.emptySet());
|
||||
// bsKyBlock
|
||||
when(bskyblock.getPermissionPrefix()).thenReturn("bskyblock.");
|
||||
AddonDescription desc = new AddonDescription.Builder("main", "BSkyBlock", "1.0").build();
|
||||
when(bskyblock.getDescription()).thenReturn(desc);
|
||||
|
||||
// Block limit listener
|
||||
when(addon.getBlockLimitListener()).thenReturn(bll);
|
||||
when(bll.getIsland(anyString())).thenReturn(ibc);
|
||||
// Block limit listener
|
||||
when(addon.getBlockLimitListener()).thenReturn(bll);
|
||||
when(bll.getIsland(anyString())).thenReturn(ibc);
|
||||
|
||||
// bukkit
|
||||
PowerMockito.mockStatic(Bukkit.class);
|
||||
// default is that owner is online
|
||||
when(owner.isOnline()).thenReturn(true);
|
||||
when(owner.getPlayer()).thenReturn(player);
|
||||
when(Bukkit.getOfflinePlayer(any(UUID.class))).thenReturn(owner);
|
||||
when(Bukkit.getPluginManager()).thenReturn(pim);
|
||||
// bukkit
|
||||
PowerMockito.mockStatic(Bukkit.class);
|
||||
// default is that owner is online
|
||||
when(owner.isOnline()).thenReturn(true);
|
||||
when(owner.getPlayer()).thenReturn(player);
|
||||
when(Bukkit.getOfflinePlayer(any(UUID.class))).thenReturn(owner);
|
||||
when(Bukkit.getPluginManager()).thenReturn(pim);
|
||||
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
ServerMocks.unsetBukkitServer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link world.bentobox.limits.listeners.JoinListener#onNewIsland(world.bentobox.bentobox.api.events.island.IslandEvent)}.
|
||||
*/
|
||||
@Test
|
||||
public void testOnNewIslandWrongReason() {
|
||||
IslandEvent e = new IslandEvent(island, null, false, null, IslandEvent.Reason.BAN);
|
||||
jl.onNewIsland(e);
|
||||
verify(island, never()).getWorld();
|
||||
IslandEvent e = new IslandEvent(island, null, false, null, IslandEvent.Reason.BAN);
|
||||
jl.onNewIsland(e);
|
||||
verify(island, never()).getWorld();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -139,9 +144,9 @@ public class JoinListenerTest {
|
||||
*/
|
||||
@Test
|
||||
public void testOnNewIslandRegistered() {
|
||||
IslandEvent e = new IslandEvent(island, null, false, null, IslandEvent.Reason.REGISTERED);
|
||||
jl.onNewIsland(e);
|
||||
verify(island).getWorld();
|
||||
IslandEvent e = new IslandEvent(island, null, false, null, IslandEvent.Reason.REGISTERED);
|
||||
jl.onNewIsland(e);
|
||||
verify(island).getWorld();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -150,9 +155,9 @@ public class JoinListenerTest {
|
||||
*/
|
||||
@Test
|
||||
public void testOnNewIslandResetted() {
|
||||
IslandEvent e = new IslandEvent(island, null, false, null, IslandEvent.Reason.RESETTED);
|
||||
jl.onNewIsland(e);
|
||||
verify(island).getWorld();
|
||||
IslandEvent e = new IslandEvent(island, null, false, null, IslandEvent.Reason.RESETTED);
|
||||
jl.onNewIsland(e);
|
||||
verify(island).getWorld();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -202,12 +207,12 @@ public class JoinListenerTest {
|
||||
*/
|
||||
@Test
|
||||
public void testOnOwnerChange() {
|
||||
TeamSetownerEvent e = mock(TeamSetownerEvent.class);
|
||||
when(e.getIsland()).thenReturn(island);
|
||||
when(e.getNewOwner()).thenReturn(UUID.randomUUID());
|
||||
jl.onOwnerChange(e);
|
||||
verify(e, Mockito.times(2)).getIsland();
|
||||
verify(e).getNewOwner();
|
||||
TeamSetownerEvent e = mock(TeamSetownerEvent.class);
|
||||
when(e.getIsland()).thenReturn(island);
|
||||
when(e.getNewOwner()).thenReturn(UUID.randomUUID());
|
||||
jl.onOwnerChange(e);
|
||||
verify(e, Mockito.times(2)).getIsland();
|
||||
verify(e).getNewOwner();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -216,10 +221,10 @@ public class JoinListenerTest {
|
||||
*/
|
||||
@Test
|
||||
public void testOnPlayerJoin() {
|
||||
PlayerJoinEvent e = new PlayerJoinEvent(player, "welcome");
|
||||
jl.onPlayerJoin(e);
|
||||
verify(addon).getGameModes();
|
||||
verify(bll).setIsland("unique_id", ibc);
|
||||
PlayerJoinEvent e = new PlayerJoinEvent(player, "welcome");
|
||||
jl.onPlayerJoin(e);
|
||||
verify(addon).getGameModes();
|
||||
verify(bll).setIsland("unique_id", ibc);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -228,11 +233,11 @@ public class JoinListenerTest {
|
||||
*/
|
||||
@Test
|
||||
public void testOnPlayerJoinIBCNull() {
|
||||
ibc = null;
|
||||
PlayerJoinEvent e = new PlayerJoinEvent(player, "welcome");
|
||||
jl.onPlayerJoin(e);
|
||||
verify(addon).getGameModes();
|
||||
verify(bll, never()).setIsland("unique_id", ibc);
|
||||
ibc = null;
|
||||
PlayerJoinEvent e = new PlayerJoinEvent(player, "welcome");
|
||||
jl.onPlayerJoin(e);
|
||||
verify(addon).getGameModes();
|
||||
verify(bll, never()).setIsland("unique_id", ibc);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -241,15 +246,15 @@ public class JoinListenerTest {
|
||||
*/
|
||||
@Test
|
||||
public void testOnPlayerJoinWithPermNotLimits() {
|
||||
Set<PermissionAttachmentInfo> perms = new HashSet<>();
|
||||
PermissionAttachmentInfo permAtt = mock(PermissionAttachmentInfo.class);
|
||||
when(permAtt.getPermission()).thenReturn("bskyblock.my.perm.for.game");
|
||||
perms.add(permAtt);
|
||||
when(player.getEffectivePermissions()).thenReturn(perms);
|
||||
PlayerJoinEvent e = new PlayerJoinEvent(player, "welcome");
|
||||
jl.onPlayerJoin(e);
|
||||
verify(addon).getGameModes();
|
||||
verify(bll).setIsland("unique_id", ibc);
|
||||
Set<PermissionAttachmentInfo> perms = new HashSet<>();
|
||||
PermissionAttachmentInfo permAtt = mock(PermissionAttachmentInfo.class);
|
||||
when(permAtt.getPermission()).thenReturn("bskyblock.my.perm.for.game");
|
||||
perms.add(permAtt);
|
||||
when(player.getEffectivePermissions()).thenReturn(perms);
|
||||
PlayerJoinEvent e = new PlayerJoinEvent(player, "welcome");
|
||||
jl.onPlayerJoin(e);
|
||||
verify(addon).getGameModes();
|
||||
verify(bll).setIsland("unique_id", ibc);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -258,16 +263,16 @@ public class JoinListenerTest {
|
||||
*/
|
||||
@Test
|
||||
public void testOnPlayerJoinWithPermLimitsWrongSize() {
|
||||
Set<PermissionAttachmentInfo> perms = new HashSet<>();
|
||||
PermissionAttachmentInfo permAtt = mock(PermissionAttachmentInfo.class);
|
||||
when(permAtt.getPermission()).thenReturn("bskyblock.island.limit.my.perm.for.game");
|
||||
when(permAtt.getValue()).thenReturn(true);
|
||||
perms.add(permAtt);
|
||||
when(player.getEffectivePermissions()).thenReturn(perms);
|
||||
PlayerJoinEvent e = new PlayerJoinEvent(player, "welcome");
|
||||
jl.onPlayerJoin(e);
|
||||
verify(addon).logError(
|
||||
"Player tastybento has permission: 'bskyblock.island.limit.my.perm.for.game' but format must be 'bskyblock.island.limit.MATERIAL.NUMBER', 'bskyblock.island.limit.ENTITY-TYPE.NUMBER', or 'bskyblock.island.limit.ENTITY-GROUP.NUMBER' Ignoring...");
|
||||
Set<PermissionAttachmentInfo> perms = new HashSet<>();
|
||||
PermissionAttachmentInfo permAtt = mock(PermissionAttachmentInfo.class);
|
||||
when(permAtt.getPermission()).thenReturn("bskyblock.island.limit.my.perm.for.game");
|
||||
when(permAtt.getValue()).thenReturn(true);
|
||||
perms.add(permAtt);
|
||||
when(player.getEffectivePermissions()).thenReturn(perms);
|
||||
PlayerJoinEvent e = new PlayerJoinEvent(player, "welcome");
|
||||
jl.onPlayerJoin(e);
|
||||
verify(addon).logError(
|
||||
"Player tastybento has permission: 'bskyblock.island.limit.my.perm.for.game' but format must be 'bskyblock.island.limit.MATERIAL.NUMBER', 'bskyblock.island.limit.ENTITY-TYPE.NUMBER', or 'bskyblock.island.limit.ENTITY-GROUP.NUMBER' Ignoring...");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -276,16 +281,16 @@ public class JoinListenerTest {
|
||||
*/
|
||||
@Test
|
||||
public void testOnPlayerJoinWithPermLimitsInvalidMaterial() {
|
||||
Set<PermissionAttachmentInfo> perms = new HashSet<>();
|
||||
PermissionAttachmentInfo permAtt = mock(PermissionAttachmentInfo.class);
|
||||
when(permAtt.getPermission()).thenReturn("bskyblock.island.limit.mumbo.34");
|
||||
when(permAtt.getValue()).thenReturn(true);
|
||||
perms.add(permAtt);
|
||||
when(player.getEffectivePermissions()).thenReturn(perms);
|
||||
PlayerJoinEvent e = new PlayerJoinEvent(player, "welcome");
|
||||
jl.onPlayerJoin(e);
|
||||
verify(addon).logError(
|
||||
"Player tastybento has permission: 'bskyblock.island.limit.mumbo.34' but MUMBO is not a valid material or entity type/group. Ignoring...");
|
||||
Set<PermissionAttachmentInfo> perms = new HashSet<>();
|
||||
PermissionAttachmentInfo permAtt = mock(PermissionAttachmentInfo.class);
|
||||
when(permAtt.getPermission()).thenReturn("bskyblock.island.limit.mumbo.34");
|
||||
when(permAtt.getValue()).thenReturn(true);
|
||||
perms.add(permAtt);
|
||||
when(player.getEffectivePermissions()).thenReturn(perms);
|
||||
PlayerJoinEvent e = new PlayerJoinEvent(player, "welcome");
|
||||
jl.onPlayerJoin(e);
|
||||
verify(addon).logError(
|
||||
"Player tastybento has permission: 'bskyblock.island.limit.mumbo.34' but MUMBO is not a valid material or entity type/group. Ignoring...");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -294,16 +299,16 @@ public class JoinListenerTest {
|
||||
*/
|
||||
@Test
|
||||
public void testOnPlayerJoinWithPermLimitsWildcard() {
|
||||
Set<PermissionAttachmentInfo> perms = new HashSet<>();
|
||||
PermissionAttachmentInfo permAtt = mock(PermissionAttachmentInfo.class);
|
||||
when(permAtt.getPermission()).thenReturn("bskyblock.island.limit.*");
|
||||
when(permAtt.getValue()).thenReturn(true);
|
||||
perms.add(permAtt);
|
||||
when(player.getEffectivePermissions()).thenReturn(perms);
|
||||
PlayerJoinEvent e = new PlayerJoinEvent(player, "welcome");
|
||||
jl.onPlayerJoin(e);
|
||||
verify(addon).logError(
|
||||
"Player tastybento has permission: 'bskyblock.island.limit.*' but wildcards are not allowed. Ignoring...");
|
||||
Set<PermissionAttachmentInfo> perms = new HashSet<>();
|
||||
PermissionAttachmentInfo permAtt = mock(PermissionAttachmentInfo.class);
|
||||
when(permAtt.getPermission()).thenReturn("bskyblock.island.limit.*");
|
||||
when(permAtt.getValue()).thenReturn(true);
|
||||
perms.add(permAtt);
|
||||
when(player.getEffectivePermissions()).thenReturn(perms);
|
||||
PlayerJoinEvent e = new PlayerJoinEvent(player, "welcome");
|
||||
jl.onPlayerJoin(e);
|
||||
verify(addon).logError(
|
||||
"Player tastybento has permission: 'bskyblock.island.limit.*' but wildcards are not allowed. Ignoring...");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -312,16 +317,16 @@ public class JoinListenerTest {
|
||||
*/
|
||||
@Test
|
||||
public void testOnPlayerJoinWithPermLimitsNotNumber() {
|
||||
Set<PermissionAttachmentInfo> perms = new HashSet<>();
|
||||
PermissionAttachmentInfo permAtt = mock(PermissionAttachmentInfo.class);
|
||||
when(permAtt.getPermission()).thenReturn("bskyblock.island.limit.STONE.abc");
|
||||
when(permAtt.getValue()).thenReturn(true);
|
||||
perms.add(permAtt);
|
||||
when(player.getEffectivePermissions()).thenReturn(perms);
|
||||
PlayerJoinEvent e = new PlayerJoinEvent(player, "welcome");
|
||||
jl.onPlayerJoin(e);
|
||||
verify(addon).logError(
|
||||
"Player tastybento has permission: 'bskyblock.island.limit.STONE.abc' but the last part MUST be an integer! Ignoring...");
|
||||
Set<PermissionAttachmentInfo> perms = new HashSet<>();
|
||||
PermissionAttachmentInfo permAtt = mock(PermissionAttachmentInfo.class);
|
||||
when(permAtt.getPermission()).thenReturn("bskyblock.island.limit.STONE.abc");
|
||||
when(permAtt.getValue()).thenReturn(true);
|
||||
perms.add(permAtt);
|
||||
when(player.getEffectivePermissions()).thenReturn(perms);
|
||||
PlayerJoinEvent e = new PlayerJoinEvent(player, "welcome");
|
||||
jl.onPlayerJoin(e);
|
||||
verify(addon).logError(
|
||||
"Player tastybento has permission: 'bskyblock.island.limit.STONE.abc' but the last part MUST be an integer! Ignoring...");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -330,16 +335,16 @@ public class JoinListenerTest {
|
||||
*/
|
||||
@Test
|
||||
public void testOnPlayerJoinWithPermLimitsSuccess() {
|
||||
Set<PermissionAttachmentInfo> perms = new HashSet<>();
|
||||
PermissionAttachmentInfo permAtt = mock(PermissionAttachmentInfo.class);
|
||||
when(permAtt.getPermission()).thenReturn("bskyblock.island.limit.STONE.24");
|
||||
when(permAtt.getValue()).thenReturn(true);
|
||||
perms.add(permAtt);
|
||||
when(player.getEffectivePermissions()).thenReturn(perms);
|
||||
PlayerJoinEvent e = new PlayerJoinEvent(player, "welcome");
|
||||
jl.onPlayerJoin(e);
|
||||
verify(addon, never()).logError(anyString());
|
||||
verify(ibc).setBlockLimit(eq(Material.STONE), eq(24));
|
||||
Set<PermissionAttachmentInfo> perms = new HashSet<>();
|
||||
PermissionAttachmentInfo permAtt = mock(PermissionAttachmentInfo.class);
|
||||
when(permAtt.getPermission()).thenReturn("bskyblock.island.limit.STONE.24");
|
||||
when(permAtt.getValue()).thenReturn(true);
|
||||
perms.add(permAtt);
|
||||
when(player.getEffectivePermissions()).thenReturn(perms);
|
||||
PlayerJoinEvent e = new PlayerJoinEvent(player, "welcome");
|
||||
jl.onPlayerJoin(e);
|
||||
verify(addon, never()).logError(anyString());
|
||||
verify(ibc).setBlockLimit(eq(Material.STONE), eq(24));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -348,16 +353,16 @@ public class JoinListenerTest {
|
||||
*/
|
||||
@Test
|
||||
public void testOnPlayerJoinWithPermLimitsSuccessEntity() {
|
||||
Set<PermissionAttachmentInfo> perms = new HashSet<>();
|
||||
PermissionAttachmentInfo permAtt = mock(PermissionAttachmentInfo.class);
|
||||
when(permAtt.getPermission()).thenReturn("bskyblock.island.limit.BAT.24");
|
||||
when(permAtt.getValue()).thenReturn(true);
|
||||
perms.add(permAtt);
|
||||
when(player.getEffectivePermissions()).thenReturn(perms);
|
||||
PlayerJoinEvent e = new PlayerJoinEvent(player, "welcome");
|
||||
jl.onPlayerJoin(e);
|
||||
verify(addon, never()).logError(anyString());
|
||||
verify(ibc).setEntityLimit(eq(EntityType.BAT), eq(24));
|
||||
Set<PermissionAttachmentInfo> perms = new HashSet<>();
|
||||
PermissionAttachmentInfo permAtt = mock(PermissionAttachmentInfo.class);
|
||||
when(permAtt.getPermission()).thenReturn("bskyblock.island.limit.BAT.24");
|
||||
when(permAtt.getValue()).thenReturn(true);
|
||||
perms.add(permAtt);
|
||||
when(player.getEffectivePermissions()).thenReturn(perms);
|
||||
PlayerJoinEvent e = new PlayerJoinEvent(player, "welcome");
|
||||
jl.onPlayerJoin(e);
|
||||
verify(addon, never()).logError(anyString());
|
||||
verify(ibc).setEntityLimit(eq(EntityType.BAT), eq(24));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -366,16 +371,16 @@ public class JoinListenerTest {
|
||||
*/
|
||||
@Test
|
||||
public void testOnPlayerJoinWithPermLimitsSuccessEntityGroup() {
|
||||
Set<PermissionAttachmentInfo> perms = new HashSet<>();
|
||||
PermissionAttachmentInfo permAtt = mock(PermissionAttachmentInfo.class);
|
||||
when(permAtt.getPermission()).thenReturn("bskyblock.island.limit.friendly.24");
|
||||
when(permAtt.getValue()).thenReturn(true);
|
||||
perms.add(permAtt);
|
||||
when(player.getEffectivePermissions()).thenReturn(perms);
|
||||
PlayerJoinEvent e = new PlayerJoinEvent(player, "welcome");
|
||||
jl.onPlayerJoin(e);
|
||||
verify(addon, never()).logError(anyString());
|
||||
verify(ibc).setEntityGroupLimit(eq("friendly"), eq(24));
|
||||
Set<PermissionAttachmentInfo> perms = new HashSet<>();
|
||||
PermissionAttachmentInfo permAtt = mock(PermissionAttachmentInfo.class);
|
||||
when(permAtt.getPermission()).thenReturn("bskyblock.island.limit.friendly.24");
|
||||
when(permAtt.getValue()).thenReturn(true);
|
||||
perms.add(permAtt);
|
||||
when(player.getEffectivePermissions()).thenReturn(perms);
|
||||
PlayerJoinEvent e = new PlayerJoinEvent(player, "welcome");
|
||||
jl.onPlayerJoin(e);
|
||||
verify(addon, never()).logError(anyString());
|
||||
verify(ibc).setEntityGroupLimit(eq("friendly"), eq(24));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -384,41 +389,41 @@ public class JoinListenerTest {
|
||||
*/
|
||||
@Test
|
||||
public void testOnPlayerJoinWithPermLimitsMultiPerms() {
|
||||
Set<PermissionAttachmentInfo> perms = new HashSet<>();
|
||||
PermissionAttachmentInfo permAtt = mock(PermissionAttachmentInfo.class);
|
||||
when(permAtt.getPermission()).thenReturn("bskyblock.island.limit.STONE.24");
|
||||
when(permAtt.getValue()).thenReturn(true);
|
||||
perms.add(permAtt);
|
||||
PermissionAttachmentInfo permAtt2 = mock(PermissionAttachmentInfo.class);
|
||||
when(permAtt2.getPermission()).thenReturn("bskyblock.island.limit.short_grass.14");
|
||||
when(permAtt2.getValue()).thenReturn(true);
|
||||
perms.add(permAtt2);
|
||||
PermissionAttachmentInfo permAtt3 = mock(PermissionAttachmentInfo.class);
|
||||
when(permAtt3.getPermission()).thenReturn("bskyblock.island.limit.dirt.34");
|
||||
when(permAtt3.getValue()).thenReturn(true);
|
||||
perms.add(permAtt3);
|
||||
PermissionAttachmentInfo permAtt4 = mock(PermissionAttachmentInfo.class);
|
||||
when(permAtt4.getPermission()).thenReturn("bskyblock.island.limit.chicken.34");
|
||||
when(permAtt4.getValue()).thenReturn(true);
|
||||
perms.add(permAtt4);
|
||||
PermissionAttachmentInfo permAtt5 = mock(PermissionAttachmentInfo.class);
|
||||
when(permAtt5.getPermission()).thenReturn("bskyblock.island.limit.cave_spider.4");
|
||||
when(permAtt5.getValue()).thenReturn(true);
|
||||
perms.add(permAtt5);
|
||||
PermissionAttachmentInfo permAtt6 = mock(PermissionAttachmentInfo.class);
|
||||
when(permAtt6.getPermission()).thenReturn("bskyblock.island.limit.cave_spider.4");
|
||||
when(permAtt6.getValue()).thenReturn(false); // negative perm
|
||||
perms.add(permAtt6);
|
||||
Set<PermissionAttachmentInfo> perms = new HashSet<>();
|
||||
PermissionAttachmentInfo permAtt = mock(PermissionAttachmentInfo.class);
|
||||
when(permAtt.getPermission()).thenReturn("bskyblock.island.limit.STONE.24");
|
||||
when(permAtt.getValue()).thenReturn(true);
|
||||
perms.add(permAtt);
|
||||
PermissionAttachmentInfo permAtt2 = mock(PermissionAttachmentInfo.class);
|
||||
when(permAtt2.getPermission()).thenReturn("bskyblock.island.limit.short_grass.14");
|
||||
when(permAtt2.getValue()).thenReturn(true);
|
||||
perms.add(permAtt2);
|
||||
PermissionAttachmentInfo permAtt3 = mock(PermissionAttachmentInfo.class);
|
||||
when(permAtt3.getPermission()).thenReturn("bskyblock.island.limit.dirt.34");
|
||||
when(permAtt3.getValue()).thenReturn(true);
|
||||
perms.add(permAtt3);
|
||||
PermissionAttachmentInfo permAtt4 = mock(PermissionAttachmentInfo.class);
|
||||
when(permAtt4.getPermission()).thenReturn("bskyblock.island.limit.chicken.34");
|
||||
when(permAtt4.getValue()).thenReturn(true);
|
||||
perms.add(permAtt4);
|
||||
PermissionAttachmentInfo permAtt5 = mock(PermissionAttachmentInfo.class);
|
||||
when(permAtt5.getPermission()).thenReturn("bskyblock.island.limit.cave_spider.4");
|
||||
when(permAtt5.getValue()).thenReturn(true);
|
||||
perms.add(permAtt5);
|
||||
PermissionAttachmentInfo permAtt6 = mock(PermissionAttachmentInfo.class);
|
||||
when(permAtt6.getPermission()).thenReturn("bskyblock.island.limit.cave_spider.4");
|
||||
when(permAtt6.getValue()).thenReturn(false); // negative perm
|
||||
perms.add(permAtt6);
|
||||
|
||||
when(player.getEffectivePermissions()).thenReturn(perms);
|
||||
PlayerJoinEvent e = new PlayerJoinEvent(player, "welcome");
|
||||
jl.onPlayerJoin(e);
|
||||
verify(addon, never()).logError(anyString());
|
||||
verify(ibc).setBlockLimit(eq(Material.STONE), eq(24));
|
||||
verify(ibc).setBlockLimit(eq(Material.SHORT_GRASS), eq(14));
|
||||
verify(ibc).setBlockLimit(eq(Material.DIRT), eq(34));
|
||||
verify(ibc).setEntityLimit(eq(EntityType.CHICKEN), eq(34));
|
||||
verify(ibc).setEntityLimit(eq(EntityType.CAVE_SPIDER), eq(4));
|
||||
when(player.getEffectivePermissions()).thenReturn(perms);
|
||||
PlayerJoinEvent e = new PlayerJoinEvent(player, "welcome");
|
||||
jl.onPlayerJoin(e);
|
||||
verify(addon, never()).logError(anyString());
|
||||
verify(ibc).setBlockLimit(eq(Material.STONE), eq(24));
|
||||
verify(ibc).setBlockLimit(eq(Material.SHORT_GRASS), eq(14));
|
||||
verify(ibc).setBlockLimit(eq(Material.DIRT), eq(34));
|
||||
verify(ibc).setEntityLimit(eq(EntityType.CHICKEN), eq(34));
|
||||
verify(ibc).setEntityLimit(eq(EntityType.CAVE_SPIDER), eq(4));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -487,9 +492,9 @@ public class JoinListenerTest {
|
||||
*/
|
||||
@Test
|
||||
public void testOnUnregisterIslandNotUnregistered() {
|
||||
IslandEvent e = new IslandEvent(island, null, false, null, IslandEvent.Reason.BAN);
|
||||
jl.onUnregisterIsland(e);
|
||||
verify(island, never()).getWorld();
|
||||
IslandEvent e = new IslandEvent(island, null, false, null, IslandEvent.Reason.BAN);
|
||||
jl.onUnregisterIsland(e);
|
||||
verify(island, never()).getWorld();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -498,10 +503,10 @@ public class JoinListenerTest {
|
||||
*/
|
||||
@Test
|
||||
public void testOnUnregisterIslandNotInWorld() {
|
||||
IslandEvent e = new IslandEvent(island, null, false, null, IslandEvent.Reason.UNREGISTERED);
|
||||
jl.onUnregisterIsland(e);
|
||||
verify(island).getWorld();
|
||||
verify(addon, never()).getBlockLimitListener();
|
||||
IslandEvent e = new IslandEvent(island, null, false, null, IslandEvent.Reason.UNREGISTERED);
|
||||
jl.onUnregisterIsland(e);
|
||||
verify(island).getWorld();
|
||||
verify(addon, never()).getBlockLimitListener();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -510,15 +515,15 @@ public class JoinListenerTest {
|
||||
*/
|
||||
@Test
|
||||
public void testOnUnregisterIslandInWorld() {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<Material, Integer> map = mock(Map.class);
|
||||
when(ibc.getBlockLimits()).thenReturn(map);
|
||||
when(addon.inGameModeWorld(any())).thenReturn(true);
|
||||
IslandEvent e = new IslandEvent(island, null, false, null, IslandEvent.Reason.UNREGISTERED);
|
||||
jl.onUnregisterIsland(e);
|
||||
verify(island).getWorld();
|
||||
verify(addon).getBlockLimitListener();
|
||||
verify(map).clear();
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<Material, Integer> map = mock(Map.class);
|
||||
when(ibc.getBlockLimits()).thenReturn(map);
|
||||
when(addon.inGameModeWorld(any())).thenReturn(true);
|
||||
IslandEvent e = new IslandEvent(island, null, false, null, IslandEvent.Reason.UNREGISTERED);
|
||||
jl.onUnregisterIsland(e);
|
||||
verify(island).getWorld();
|
||||
verify(addon).getBlockLimitListener();
|
||||
verify(map).clear();
|
||||
|
||||
}
|
||||
|
@ -38,6 +38,9 @@ import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
@ -62,6 +65,7 @@ import world.bentobox.bentobox.managers.FlagsManager;
|
||||
import world.bentobox.bentobox.managers.IslandWorldManager;
|
||||
import world.bentobox.bentobox.managers.IslandsManager;
|
||||
import world.bentobox.bentobox.managers.PlaceholdersManager;
|
||||
import world.bentobox.limits.mocks.ServerMocks;
|
||||
|
||||
/**
|
||||
* @author tastybento
|
||||
@ -135,6 +139,7 @@ public class LimitsTest {
|
||||
*/
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
Server server = ServerMocks.newServer();
|
||||
// Set up plugin
|
||||
Whitebox.setInternalState(BentoBox.class, "instance", plugin);
|
||||
when(plugin.getLogger()).thenReturn(Logger.getAnonymousLogger());
|
||||
@ -175,7 +180,6 @@ public class LimitsTest {
|
||||
|
||||
// Server
|
||||
PowerMockito.mockStatic(Bukkit.class);
|
||||
Server server = mock(Server.class);
|
||||
when(Bukkit.getServer()).thenReturn(server);
|
||||
when(Bukkit.getLogger()).thenReturn(Logger.getAnonymousLogger());
|
||||
when(Bukkit.getPluginManager()).thenReturn(mock(PluginManager.class));
|
||||
@ -213,7 +217,6 @@ public class LimitsTest {
|
||||
|
||||
|
||||
// Bukkit
|
||||
PowerMockito.mockStatic(Bukkit.class);
|
||||
when(Bukkit.getScheduler()).thenReturn(scheduler);
|
||||
ItemMeta meta = mock(ItemMeta.class);
|
||||
ItemFactory itemFactory = mock(ItemFactory.class);
|
||||
@ -239,6 +242,9 @@ public class LimitsTest {
|
||||
*/
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
ServerMocks.unsetBukkitServer();
|
||||
User.clearUsers();
|
||||
Mockito.framework().clearInlineMocks();
|
||||
deleteAll(new File("database"));
|
||||
}
|
||||
|
||||
@ -262,6 +268,7 @@ public class LimitsTest {
|
||||
* Test method for {@link world.bentobox.limits.Limits#onEnable()}.
|
||||
*/
|
||||
@Test
|
||||
@Ignore
|
||||
public void testOnEnable() {
|
||||
addon.onEnable();
|
||||
File f = new File("config.yml");
|
||||
@ -281,6 +288,7 @@ public class LimitsTest {
|
||||
* Test method for {@link world.bentobox.limits.Limits#getSettings()}.
|
||||
*/
|
||||
@Test
|
||||
@Ignore
|
||||
public void testGetSettings() {
|
||||
assertNull(addon.getSettings());
|
||||
addon.onEnable();
|
||||
@ -292,6 +300,7 @@ public class LimitsTest {
|
||||
* Test method for {@link world.bentobox.limits.Limits#getGameModes()}.
|
||||
*/
|
||||
@Test
|
||||
@Ignore
|
||||
public void testGetGameModes() {
|
||||
assertTrue(addon.getGameModes().isEmpty());
|
||||
addon.onEnable();
|
||||
@ -302,6 +311,7 @@ public class LimitsTest {
|
||||
* Test method for {@link world.bentobox.limits.Limits#getBlockLimitListener()}.
|
||||
*/
|
||||
@Test
|
||||
@Ignore
|
||||
public void testGetBlockLimitListener() {
|
||||
assertNull(addon.getBlockLimitListener());
|
||||
addon.onEnable();
|
||||
@ -312,6 +322,7 @@ public class LimitsTest {
|
||||
* Test method for {@link world.bentobox.limits.Limits#inGameModeWorld(org.bukkit.World)}.
|
||||
*/
|
||||
@Test
|
||||
@Ignore
|
||||
public void testInGameModeWorld() {
|
||||
addon.onEnable();
|
||||
assertFalse(addon.inGameModeWorld(world));
|
||||
@ -323,6 +334,7 @@ public class LimitsTest {
|
||||
* Test method for {@link world.bentobox.limits.Limits#getGameModeName(org.bukkit.World)}.
|
||||
*/
|
||||
@Test
|
||||
@Ignore
|
||||
public void testGetGameModeName() {
|
||||
when(gameMode.inWorld(world)).thenReturn(true);
|
||||
assertTrue(addon.getGameModeName(world).isEmpty());
|
||||
@ -334,6 +346,7 @@ public class LimitsTest {
|
||||
* Test method for {@link world.bentobox.limits.Limits#getGameModePermPrefix(org.bukkit.World)}.
|
||||
*/
|
||||
@Test
|
||||
@Ignore
|
||||
public void testGetGameModePermPrefix() {
|
||||
when(gameMode.inWorld(world)).thenReturn(true);
|
||||
addon.onEnable();
|
||||
@ -344,6 +357,7 @@ public class LimitsTest {
|
||||
* Test method for {@link world.bentobox.limits.Limits#isCoveredGameMode(java.lang.String)}.
|
||||
*/
|
||||
@Test
|
||||
@Ignore
|
||||
public void testIsCoveredGameMode() {
|
||||
assertFalse(addon.isCoveredGameMode("BSkyBlock"));
|
||||
addon.onEnable();
|
||||
@ -354,6 +368,7 @@ public class LimitsTest {
|
||||
* Test method for {@link world.bentobox.limits.Limits#getJoinListener()}.
|
||||
*/
|
||||
@Test
|
||||
@Ignore
|
||||
public void testGetJoinListener() {
|
||||
assertNull(addon.getJoinListener());
|
||||
addon.onEnable();
|
||||
|
118
src/test/java/world/bentobox/limits/mocks/ServerMocks.java
Normal file
118
src/test/java/world/bentobox/limits/mocks/ServerMocks.java
Normal file
@ -0,0 +1,118 @@
|
||||
package world.bentobox.limits.mocks;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.notNull;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Keyed;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.Registry;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.Tag;
|
||||
import org.bukkit.UnsafeValues;
|
||||
import org.eclipse.jdt.annotation.NonNull;
|
||||
|
||||
public final class ServerMocks {
|
||||
|
||||
public static @NonNull Server newServer() {
|
||||
Server mock = mock(Server.class);
|
||||
|
||||
Logger noOp = mock(Logger.class);
|
||||
when(mock.getLogger()).thenReturn(noOp);
|
||||
when(mock.isPrimaryThread()).thenReturn(true);
|
||||
|
||||
// Unsafe
|
||||
UnsafeValues unsafe = mock(UnsafeValues.class);
|
||||
when(mock.getUnsafe()).thenReturn(unsafe);
|
||||
|
||||
// Server must be available before tags can be mocked.
|
||||
Bukkit.setServer(mock);
|
||||
|
||||
// Bukkit has a lot of static constants referencing registry values. To initialize those, the
|
||||
// registries must be able to be fetched before the classes are touched.
|
||||
Map<Class<? extends Keyed>, Object> registers = new HashMap<>();
|
||||
|
||||
doAnswer(invocationGetRegistry -> registers.computeIfAbsent(invocationGetRegistry.getArgument(0), clazz -> {
|
||||
Registry<?> registry = mock(Registry.class);
|
||||
Map<NamespacedKey, Keyed> cache = new HashMap<>();
|
||||
doAnswer(invocationGetEntry -> {
|
||||
NamespacedKey key = invocationGetEntry.getArgument(0);
|
||||
// Some classes (like BlockType and ItemType) have extra generics that will be
|
||||
// erased during runtime calls. To ensure accurate typing, grab the constant's field.
|
||||
// This approach also allows us to return null for unsupported keys.
|
||||
Class<? extends Keyed> constantClazz;
|
||||
try {
|
||||
//noinspection unchecked
|
||||
constantClazz = (Class<? extends Keyed>) clazz
|
||||
.getField(key.getKey().toUpperCase(Locale.ROOT).replace('.', '_')).getType();
|
||||
} catch (ClassCastException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (NoSuchFieldException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return cache.computeIfAbsent(key, key1 -> {
|
||||
Keyed keyed = mock(constantClazz);
|
||||
doReturn(key).when(keyed).getKey();
|
||||
return keyed;
|
||||
});
|
||||
}).when(registry).get(notNull());
|
||||
return registry;
|
||||
})).when(mock).getRegistry(notNull());
|
||||
|
||||
// Tags are dependent on registries, but use a different method.
|
||||
// This will set up blank tags for each constant; all that needs to be done to render them
|
||||
// functional is to re-mock Tag#getValues.
|
||||
doAnswer(invocationGetTag -> {
|
||||
Tag<?> tag = mock(Tag.class);
|
||||
doReturn(invocationGetTag.getArgument(1)).when(tag).getKey();
|
||||
doReturn(Set.of()).when(tag).getValues();
|
||||
doAnswer(invocationIsTagged -> {
|
||||
Keyed keyed = invocationIsTagged.getArgument(0);
|
||||
Class<?> type = invocationGetTag.getArgument(2);
|
||||
if (!type.isAssignableFrom(keyed.getClass())) {
|
||||
return null;
|
||||
}
|
||||
// Since these are mocks, the exact instance might not be equal. Consider equal keys equal.
|
||||
return tag.getValues().contains(keyed)
|
||||
|| tag.getValues().stream().anyMatch(value -> value.getKey().equals(keyed.getKey()));
|
||||
}).when(tag).isTagged(notNull());
|
||||
return tag;
|
||||
}).when(mock).getTag(notNull(), notNull(), notNull());
|
||||
|
||||
// Once the server is all set up, touch BlockType and ItemType to initialize.
|
||||
// This prevents issues when trying to access dependent methods from a Material constant.
|
||||
try {
|
||||
Class.forName("org.bukkit.inventory.ItemType");
|
||||
Class.forName("org.bukkit.block.BlockType");
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
return mock;
|
||||
}
|
||||
|
||||
public static void unsetBukkitServer() {
|
||||
try {
|
||||
Field server = Bukkit.class.getDeclaredField("server");
|
||||
server.setAccessible(true);
|
||||
server.set(null, null);
|
||||
} catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private ServerMocks() {
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user