diff --git a/pom.xml b/pom.xml index 80507e9..7c9d7f4 100644 --- a/pom.xml +++ b/pom.xml @@ -52,10 +52,12 @@ UTF-8 21 - 2.0.9 + 5.10.2 + 5.11.0 + v1.21-SNAPSHOT - 1.21.5-R0.1-SNAPSHOT - 3.7.4 + 1.21.10-R0.1-SNAPSHOT + 3.10.2 1.12.0 @@ -67,7 +69,7 @@ -LOCAL - 2.22.1 + 2.23.0 BentoBoxWorld_Level bentobox-world https://sonarcloud.io @@ -124,24 +126,24 @@ - spigot-repo - https://hub.spigotmc.org/nexus/content/repositories/snapshots + jitpack.io + https://jitpack.io - codemc - https://repo.codemc.org/repository/maven-snapshots/ + codemc-repo + https://repo.codemc.org/repository/maven-public - codemc-repo - https://repo.codemc.org/repository/maven-public/ + papermc + https://repo.papermc.io/repository/maven-public/ - bentoboxworld - https://repo.codemc.org/repository/bentoboxworld/ + codemc + https://repo.codemc.org/repository/maven-snapshots/ - jitpack.io - https://jitpack.io + bentoboxworld + https://repo.codemc.org/repository/bentoboxworld/ @@ -172,36 +174,49 @@ - + - org.spigotmc - spigot-api - ${spigot.version} - provided - - + com.github.MockBukkit + MockBukkit + ${mock-bukkit.version} + test + + + + org.junit.jupiter + junit-jupiter-api + ${junit.version} + test + + + org.junit.jupiter + junit-jupiter-engine + ${junit.version} + test + + + org.mockito + mockito-junit-jupiter + 5.11.0 + test + org.mockito mockito-core - 3.11.1 + ${mockito.version} test + - org.powermock - powermock-module-junit4 - ${powermock.version} - test - - - org.powermock - powermock-api-mockito2 - ${powermock.version} - test + io.papermc.paper + paper-api + ${paper.version} + provided world.bentobox bentobox - 3.7.4-SNAPSHOT + 3.10.0 world.bentobox @@ -354,7 +369,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.13.0 + 3.14.1 ${java.version} @@ -362,10 +377,11 @@ org.apache.maven.plugins maven-surefire-plugin - 3.5.2 + 3.5.4 ${argLine} + -XX:+EnableDynamicAgentLoading --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.math=ALL-UNNAMED --add-opens java.base/java.io=ALL-UNNAMED @@ -478,7 +494,7 @@ org.jacoco jacoco-maven-plugin - 0.8.10 + 0.8.13 true diff --git a/src/main/java/world/bentobox/level/LevelsManager.java b/src/main/java/world/bentobox/level/LevelsManager.java index ac9c46b..d32bced 100644 --- a/src/main/java/world/bentobox/level/LevelsManager.java +++ b/src/main/java/world/bentobox/level/LevelsManager.java @@ -57,6 +57,7 @@ public LevelsManager(Level addon) { // Set up the database handler to store and retrieve data // Note that these are saved by the BentoBox database handler = new Database<>(addon, IslandLevels.class); + // Initialize the cache levelsCache = new HashMap<>(); // Initialize top ten lists @@ -237,7 +238,6 @@ private long getNumBlocks(final long initialLevel) throws ParseException, IOExce * * @param world - world where the island is * @param targetPlayer - target player UUID - * @param ownerOnly - return level only if the target player is the owner * @return Level of the player's island or zero if player is unknown or UUID is * null */ @@ -492,7 +492,6 @@ public void setInitialIslandCount(@NonNull Island island, long lv) { * member * * @param world - world - * @param island - island * @param lv - level */ public void setIslandLevel(@NonNull World world, @NonNull UUID targetPlayer, long lv) { diff --git a/src/main/java/world/bentobox/level/calculators/Results.java b/src/main/java/world/bentobox/level/calculators/Results.java index 6dbd2a5..db8124c 100644 --- a/src/main/java/world/bentobox/level/calculators/Results.java +++ b/src/main/java/world/bentobox/level/calculators/Results.java @@ -173,7 +173,7 @@ public long getInitialCount() { } /** - * @param long1 the initialCount to set + * @param count the initialCount to set */ public void setInitialCount(Long count) { this.initialCount.set(count); diff --git a/src/main/java/world/bentobox/level/config/BlockConfig.java b/src/main/java/world/bentobox/level/config/BlockConfig.java index feb7495..1ebfcba 100644 --- a/src/main/java/world/bentobox/level/config/BlockConfig.java +++ b/src/main/java/world/bentobox/level/config/BlockConfig.java @@ -240,7 +240,7 @@ public Integer getValue(World world, Object obj) { /** * Return true if the block should be hidden - * @param m block material or entity type of spawner + * @param obj object that can be a material or string * @return true if hidden */ public boolean isHiddenBlock(Object obj) { @@ -254,7 +254,7 @@ public boolean isHiddenBlock(Object obj) { /** * Return true if the block should not be hidden - * @param m block material + * @param obj object that can be a material or string * @return false if hidden */ public boolean isNotHiddenBlock(Object obj) { diff --git a/src/test/java/world/bentobox/level/CommonTestSetup.java b/src/test/java/world/bentobox/level/CommonTestSetup.java new file mode 100644 index 0000000..876424a --- /dev/null +++ b/src/test/java/world/bentobox/level/CommonTestSetup.java @@ -0,0 +1,336 @@ +package world.bentobox.level; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.atLeast; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +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; +import org.bukkit.event.entity.PlayerDeathEvent; +import org.bukkit.inventory.ItemFactory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; +import org.bukkit.metadata.FixedMetadataValue; +import org.bukkit.metadata.MetadataValue; +import org.bukkit.plugin.PluginManager; +import org.bukkit.scheduler.BukkitScheduler; +import org.bukkit.util.Vector; +import org.eclipse.jdt.annotation.Nullable; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.mockbukkit.mockbukkit.MockBukkit; +import org.mockbukkit.mockbukkit.ServerMock; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.mockito.stubbing.Answer; + +import com.google.common.collect.ImmutableSet; + +import net.md_5.bungee.api.chat.TextComponent; +import world.bentobox.bentobox.BentoBox; +import world.bentobox.bentobox.Settings; +import world.bentobox.bentobox.api.addons.GameModeAddon; +import world.bentobox.bentobox.api.commands.CompositeCommand; +import world.bentobox.bentobox.api.configuration.WorldSettings; +import world.bentobox.bentobox.api.user.Notifier; +import world.bentobox.bentobox.api.user.User; +import world.bentobox.bentobox.database.objects.Island; +import world.bentobox.bentobox.database.objects.Players; +import world.bentobox.bentobox.managers.BlueprintsManager; +import world.bentobox.bentobox.managers.FlagsManager; +import world.bentobox.bentobox.managers.HooksManager; +import world.bentobox.bentobox.managers.IslandWorldManager; +import world.bentobox.bentobox.managers.IslandsManager; +import world.bentobox.bentobox.managers.LocalesManager; +import world.bentobox.bentobox.managers.PlaceholdersManager; +import world.bentobox.bentobox.managers.PlayersManager; +import world.bentobox.bentobox.util.Util; + +/** + * Common items for testing. Don't forget to use super.setUp()! + *

+ * Sets up BentoBox plugin, pluginManager and ItemFactory. + * Location, world, playersManager and player. + * IWM, Addon and WorldSettings. IslandManager with one + * island with protection and nothing allowed by default. + * Owner of island is player with same UUID. + * Locales, placeholders. + * @author tastybento + * + */ +public abstract class CommonTestSetup { + + protected UUID uuid = UUID.randomUUID(); + + @Mock + protected GameModeAddon gameModeAddon; + @Mock + protected Level addon; + @Mock + protected Player p; + @Mock + protected PluginManager pim; + @Mock + protected ItemFactory itemFactory; + @Mock + protected Location location; + @Mock + protected World world; + @Mock + protected IslandWorldManager iwm; + @Mock + protected IslandsManager im; + @Mock + protected Island island; + @Mock + protected BentoBox plugin; + @Mock + protected PlayerInventory inv; + @Mock + protected Notifier notifier; + @Mock + protected FlagsManager fm; + @Mock + protected Spigot spigot; + @Mock + protected HooksManager hooksManager; + @Mock + protected BlueprintsManager bm; + + protected ServerMock server; + + protected MockedStatic mockedBukkit; + protected MockedStatic mockedUtil; + + protected AutoCloseable closeable; + + @Mock + protected BukkitScheduler sch; + @Mock + protected LocalesManager lm; + @Mock + protected CompositeCommand ic; + + + @BeforeEach + public void setUp() throws Exception { + MockitoAnnotations.openMocks(this); + // Processes the @Mock annotations and initializes the field + closeable = MockitoAnnotations.openMocks(this); + server = MockBukkit.mock(); + // Bukkit + // Set up plugin + WhiteBox.setInternalState(BentoBox.class, "instance", plugin); + + // Register the static mock + mockedBukkit = Mockito.mockStatic(Bukkit.class, Mockito.RETURNS_DEEP_STUBS); + mockedBukkit.when(Bukkit::getMinecraftVersion).thenReturn("1.21.10"); + mockedBukkit.when(Bukkit::getBukkitVersion).thenReturn(""); + mockedBukkit.when(Bukkit::getPluginManager).thenReturn(pim); + mockedBukkit.when(Bukkit::getItemFactory).thenReturn(itemFactory); + mockedBukkit.when(Bukkit::getServer).thenReturn(server); + + // World + when(world.toString()).thenReturn("world"); + when(world.getName()).thenReturn("BSkyBlock_world"); + + // Location + when(location.getWorld()).thenReturn(world); + when(location.getBlockX()).thenReturn(0); + when(location.getBlockY()).thenReturn(0); + when(location.getBlockZ()).thenReturn(0); + when(location.toVector()).thenReturn(new Vector(0,0,0)); + when(location.clone()).thenReturn(location); // Paper + + // Players Manager and meta data + PlayersManager pm = mock(PlayersManager.class); + when(plugin.getPlayers()).thenReturn(pm); + Players players = mock(Players.class); + when(players.getMetaData()).thenReturn(Optional.empty()); + when(pm.getPlayer(any(UUID.class))).thenReturn(players); + + // Player + when(p.getUniqueId()).thenReturn(uuid); + when(p.getLocation()).thenReturn(location); + when(p.getWorld()).thenReturn(world); + when(p.getName()).thenReturn("tastybento"); + when(p.getInventory()).thenReturn(inv); + when(p.spigot()).thenReturn(spigot); + when(p.getType()).thenReturn(EntityType.PLAYER); + when(p.getWorld()).thenReturn(world); + + User.setPlugin(plugin); + User.clearUsers(); + User.getInstance(p); + + // IWM + when(plugin.getIWM()).thenReturn(iwm); + when(iwm.inWorld(any(Location.class))).thenReturn(true); + when(iwm.inWorld(any(World.class))).thenReturn(true); + when(iwm.getFriendlyName(any())).thenReturn("BSkyBlock"); + // Addon + when(iwm.getAddon(any())).thenReturn(Optional.empty()); + + // World Settings + WorldSettings worldSet = new TestWorldSettings(); + when(iwm.getWorldSettings(any())).thenReturn(worldSet); + + // Island Manager + when(plugin.getIslands()).thenReturn(im); + Optional optionalIsland = Optional.of(island); + when(im.getProtectedIslandAt(any())).thenReturn(optionalIsland); + + // Island - nothing is allowed by default + when(island.isAllowed(any())).thenReturn(false); + when(island.isAllowed(any(User.class), any())).thenReturn(false); + when(island.getOwner()).thenReturn(uuid); + when(island.getMemberSet()).thenReturn(ImmutableSet.of(uuid)); + + // Enable reporting from Flags class + MetadataValue mdv = new FixedMetadataValue(plugin, "_why_debug"); + when(p.getMetadata(anyString())).thenReturn(Collections.singletonList(mdv)); + + // Locales & Placeholders + when(lm.get(any(), any())).thenAnswer((Answer) invocation -> invocation.getArgument(1, String.class)); + PlaceholdersManager phm = mock(PlaceholdersManager.class); + when(plugin.getPlaceholdersManager()).thenReturn(phm); + when(phm.replacePlaceholders(any(), any())).thenAnswer((Answer) invocation -> invocation.getArgument(1, String.class)); + when(plugin.getLocalesManager()).thenReturn(lm); + // Notifier + when(plugin.getNotifier()).thenReturn(notifier); + + // Fake players + Settings settings = new Settings(); + when(plugin.getSettings()).thenReturn(settings); + + //Util + mockedUtil = Mockito.mockStatic(Util.class, Mockito.CALLS_REAL_METHODS); + mockedUtil.when(() -> Util.getWorld(any())).thenReturn(mock(World.class)); + Util.setPlugin(plugin); + + // Util + mockedUtil.when(() -> Util.findFirstMatchingEnum(any(), any())).thenCallRealMethod(); + // Util translate color codes (used in user translate methods) + //mockedUtil.when(() -> translateColorCodes(anyString())).thenAnswer((Answer) invocation -> invocation.getArgument(0, String.class)); + + // Server & Scheduler + mockedBukkit.when(() -> Bukkit.getScheduler()).thenReturn(sch); + + // Hooks + when(hooksManager.getHook(anyString())).thenReturn(Optional.empty()); + when(plugin.getHooks()).thenReturn(hooksManager); + + // Blueprints Manager + when(plugin.getBlueprintsManager()).thenReturn(bm); + + // Addon + when(addon.getPlugin()).thenReturn(plugin); + when(addon.getIslands()).thenReturn(im); + when(addon.getIslandsManager()).thenReturn(im); + + // Command + when(ic.getAddon()).thenReturn(addon); + when(ic.getPermissionPrefix()).thenReturn("bskyblock."); + when(ic.getLabel()).thenReturn("island"); + when(ic.getTopLabel()).thenReturn("island"); + when(ic.getWorld()).thenReturn(world); + when(ic.getTopLabel()).thenReturn("bsb"); + + } + + /** + * @throws Exception + */ + @AfterEach + public void tearDown() throws Exception { + // IMPORTANT: Explicitly close the mock to prevent leakage + mockedBukkit.closeOnDemand(); + mockedUtil.closeOnDemand(); + closeable.close(); + MockBukkit.unmock(); + User.clearUsers(); + Mockito.framework().clearInlineMocks(); + deleteAll(new File("database")); + deleteAll(new File("database_backup")); + } + + protected static void deleteAll(File file) throws IOException { + if (file.exists()) { + Files.walk(file.toPath()).sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete); + } + + } + + /** + * Check that spigot sent the message + * @param message - message to check + */ + public void checkSpigotMessage(String expectedMessage) { + checkSpigotMessage(expectedMessage, 1); + } + + @SuppressWarnings("deprecation") + public void checkSpigotMessage(String expectedMessage, int expectedOccurrences) { + // Capture the argument passed to spigot().sendMessage(...) if messages are sent + ArgumentCaptor captor = ArgumentCaptor.forClass(TextComponent.class); + + // Verify that sendMessage() was called at least 0 times (capture any sent messages) + verify(spigot, atLeast(0)).sendMessage(captor.capture()); + + // Get all captured TextComponents + List capturedMessages = captor.getAllValues(); + + // Count the number of occurrences of the expectedMessage in the captured messages + long actualOccurrences = capturedMessages.stream().map(component -> component.toLegacyText()) // Convert each TextComponent to plain text + .filter(messageText -> messageText.contains(expectedMessage)) // Check if the message contains the expected text + .count(); // Count how many times the expected message appears + + // Assert that the number of occurrences matches the expectedOccurrences + assertEquals(expectedOccurrences, + actualOccurrences, "Expected message occurrence mismatch: " + expectedMessage); + } + + /** + * Get the explode event + * @param entity + * @param l + * @param list + * @return + */ + public EntityExplodeEvent getExplodeEvent(Entity entity, Location l, List list) { + //return new EntityExplodeEvent(entity, l, list, 0, null); + return new EntityExplodeEvent(entity, l, list, 0, null); + } + + public PlayerDeathEvent getPlayerDeathEvent(Player player, List drops, int droppedExp, int newExp, + int newTotalExp, int newLevel, @Nullable String deathMessage) { + //Technically this null is not allowed, but it works right now + return new PlayerDeathEvent(player, null, drops, droppedExp, newExp, + newTotalExp, newLevel, deathMessage); + } + +} diff --git a/src/test/java/world/bentobox/level/LevelTest.java b/src/test/java/world/bentobox/level/LevelTest.java index 2dd0e87..550509a 100644 --- a/src/test/java/world/bentobox/level/LevelTest.java +++ b/src/test/java/world/bentobox/level/LevelTest.java @@ -16,8 +16,8 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; import java.util.Collections; -import java.util.Comparator; import java.util.Optional; import java.util.UUID; import java.util.jar.JarEntry; @@ -25,78 +25,50 @@ import java.util.logging.Logger; import org.bukkit.Bukkit; -import org.bukkit.Server; -import org.bukkit.UnsafeValues; -import org.bukkit.World; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemFactory; -import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.plugin.PluginManager; -import org.bukkit.scheduler.BukkitScheduler; import org.eclipse.jdt.annotation.NonNull; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.Mock; +import org.mockito.MockedStatic; 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; -import org.powermock.reflect.Whitebox; -import world.bentobox.bentobox.BentoBox; import world.bentobox.bentobox.Settings; import world.bentobox.bentobox.api.addons.AddonDescription; import world.bentobox.bentobox.api.addons.GameModeAddon; import world.bentobox.bentobox.api.commands.CompositeCommand; import world.bentobox.bentobox.api.user.User; import world.bentobox.bentobox.database.DatabaseSetup.DatabaseType; -import world.bentobox.bentobox.database.objects.Island; import world.bentobox.bentobox.hooks.ItemsAdderHook; import world.bentobox.bentobox.managers.AddonsManager; import world.bentobox.bentobox.managers.CommandsManager; import world.bentobox.bentobox.managers.FlagsManager; import world.bentobox.bentobox.managers.HooksManager; -import world.bentobox.bentobox.managers.IslandWorldManager; -import world.bentobox.bentobox.managers.IslandsManager; import world.bentobox.bentobox.managers.PlaceholdersManager; import world.bentobox.bentobox.util.Util; import world.bentobox.level.config.BlockConfig; import world.bentobox.level.config.ConfigSettings; import world.bentobox.level.listeners.IslandActivitiesListeners; import world.bentobox.level.listeners.JoinLeaveListener; -import world.bentobox.level.mocks.ServerMocks; /** * @author tastybento * */ -@SuppressWarnings("deprecation") -@RunWith(PowerMockRunner.class) -@PrepareForTest({ Bukkit.class, BentoBox.class, User.class, Util.class, ItemsAdderHook.class }) -public class LevelTest { +public class LevelTest extends CommonTestSetup { private static File jFile; @Mock private User user; @Mock - private IslandsManager im; - @Mock - private Island island; - @Mock - private BentoBox plugin; - @Mock private FlagsManager fm; @Mock private GameModeAddon gameMode; @Mock private AddonsManager am; - @Mock - private BukkitScheduler scheduler; @Mock private Settings pluginSettings; @@ -111,29 +83,25 @@ public class LevelTest { private CompositeCommand cmd; @Mock private CompositeCommand adminCmd; - @Mock - private World world; - private UUID uuid; - @Mock - private PluginManager pim; @Mock private BlockConfig blockConfig; @Mock private HooksManager hm; + private MockedStatic itemsAdderMock; - @BeforeClass + @BeforeAll public static void beforeClass() throws IOException { // Make the addon jar jFile = new File("addon.jar"); // Copy over config file from src folder Path fromPath = Paths.get("src/main/resources/config.yml"); Path path = Paths.get("config.yml"); - Files.copy(fromPath, path); + Files.copy(fromPath, path, StandardCopyOption.REPLACE_EXISTING); // Copy over block config file from src folder fromPath = Paths.get("src/main/resources/blockconfig.yml"); path = Paths.get("blockconfig.yml"); - Files.copy(fromPath, path); + Files.copy(fromPath, path, StandardCopyOption.REPLACE_EXISTING); try (JarOutputStream tempJarOutputStream = new JarOutputStream(new FileOutputStream(jFile))) { // Added the new files to the jar. try (FileInputStream fis = new FileInputStream(path.toFile())) { @@ -151,29 +119,25 @@ public static void beforeClass() throws IOException { /** * @throws java.lang.Exception */ - @Before + @Override + @BeforeEach public void setUp() throws Exception { + super.setUp(); when(plugin.getHooks()).thenReturn(hm); - Server server = ServerMocks.newServer(); - // Set up plugin - Whitebox.setInternalState(BentoBox.class, "instance", plugin); - when(plugin.getLogger()).thenReturn(Logger.getAnonymousLogger()); - // The database type has to be created one line before the thenReturn() to work! DatabaseType value = DatabaseType.JSON; when(plugin.getSettings()).thenReturn(pluginSettings); when(pluginSettings.getDatabaseType()).thenReturn(value); // ItemsAdderHook - PowerMockito.mockStatic(ItemsAdderHook.class, Mockito.RETURNS_MOCKS); - when(ItemsAdderHook.isInRegistry(anyString())).thenReturn(true); + itemsAdderMock = Mockito.mockStatic(ItemsAdderHook.class, Mockito.RETURNS_MOCKS); + itemsAdderMock.when(() -> ItemsAdderHook.isInRegistry(anyString())).thenReturn(true); // Command manager CommandsManager cm = mock(CommandsManager.class); when(plugin.getCommandsManager()).thenReturn(cm); // Player - Player p = mock(Player.class); // Sometimes use Mockito.withSettings().verboseLogging() when(user.isOp()).thenReturn(false); uuid = UUID.randomUUID(); @@ -182,29 +146,17 @@ public void setUp() throws Exception { when(user.getName()).thenReturn("tastybento"); User.setPlugin(plugin); - // Island World Manager - IslandWorldManager iwm = mock(IslandWorldManager.class); - when(plugin.getIWM()).thenReturn(iwm); - // Player has island to begin with when(im.getIsland(Mockito.any(), Mockito.any(UUID.class))).thenReturn(island); - when(plugin.getIslands()).thenReturn(im); // Locales // Return the reference (USE THIS IN THE FUTURE) when(user.getTranslation(Mockito.anyString())) .thenAnswer((Answer) invocation -> invocation.getArgument(0, String.class)); - // Server - PowerMockito.mockStatic(Bukkit.class); - when(Bukkit.getServer()).thenReturn(server); - when(Bukkit.getLogger()).thenReturn(Logger.getAnonymousLogger()); - when(Bukkit.getPluginManager()).thenReturn(mock(PluginManager.class)); - when(Bukkit.getBukkitVersion()).thenReturn(""); // Util - PowerMockito.mockStatic(Util.class, Mockito.RETURNS_MOCKS); - when(Util.inTest()).thenReturn(true); + mockedUtil.when(() -> Util.inTest()).thenReturn(true); // Addon addon = new Level(); @@ -236,37 +188,22 @@ public void setUp() throws Exception { when(plugin.getFlagsManager()).thenReturn(fm); when(fm.getFlags()).thenReturn(Collections.emptyList()); - // Bukkit - when(Bukkit.getScheduler()).thenReturn(scheduler); - ItemMeta meta = mock(ItemMeta.class); - ItemFactory itemFactory = mock(ItemFactory.class); - when(itemFactory.getItemMeta(any())).thenReturn(meta); - when(Bukkit.getItemFactory()).thenReturn(itemFactory); - UnsafeValues unsafe = mock(UnsafeValues.class); - when(unsafe.getDataVersion()).thenReturn(777); - when(Bukkit.getUnsafe()).thenReturn(unsafe); - when(Bukkit.getPluginManager()).thenReturn(pim); - // placeholders when(plugin.getPlaceholdersManager()).thenReturn(phm); - // World - when(world.getName()).thenReturn("bskyblock-world"); - // Island - when(island.getWorld()).thenReturn(world); - when(island.getOwner()).thenReturn(uuid); } /** * @throws java.lang.Exception */ - @After + @Override + @AfterEach public void tearDown() throws Exception { - ServerMocks.unsetBukkitServer(); + super.tearDown(); deleteAll(new File("database")); } - @AfterClass + @AfterAll public static void cleanUp() throws Exception { new File("addon.jar").delete(); new File("config.yml").delete(); @@ -274,17 +211,12 @@ public static void cleanUp() throws Exception { deleteAll(new File("addons")); } - private static void deleteAll(File file) throws IOException { - if (file.exists()) { - Files.walk(file.toPath()).sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete); - } - } - /** * Test method for {@link world.bentobox.level.Level#allLoaded() */ @Test public void testAllLoaded() { + mockedBukkit.when(() -> Bukkit.getWorld("acidisland_world")).thenReturn(null); addon.allLoaded(); verify(plugin).log("[Level] Level hooking into BSkyBlock"); verify(cmd, times(4)).getAddon(); // 4 commands diff --git a/src/test/java/world/bentobox/level/LevelsManagerTest.java b/src/test/java/world/bentobox/level/LevelsManagerTest.java index a790604..ab96e75 100644 --- a/src/test/java/world/bentobox/level/LevelsManagerTest.java +++ b/src/test/java/world/bentobox/level/LevelsManagerTest.java @@ -12,11 +12,7 @@ import static org.mockito.Mockito.when; import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; import java.util.ArrayList; -import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Optional; @@ -27,36 +23,24 @@ import org.bukkit.World; import org.bukkit.entity.Player; import org.bukkit.inventory.Inventory; -import org.bukkit.inventory.ItemFactory; -import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.plugin.PluginManager; -import org.bukkit.scheduler.BukkitScheduler; -import org.junit.After; -import org.junit.Before; -import org.junit.BeforeClass; import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.mockito.ArgumentCaptor; import org.mockito.Mock; +import org.mockito.MockedStatic; 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; -import org.powermock.reflect.Whitebox; import com.google.common.collect.ImmutableSet; -import world.bentobox.bentobox.BentoBox; import world.bentobox.bentobox.Settings; -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; import world.bentobox.bentobox.database.DatabaseSetup.DatabaseType; import world.bentobox.bentobox.database.objects.Island; import world.bentobox.bentobox.managers.IslandWorldManager; -import world.bentobox.bentobox.managers.IslandsManager; import world.bentobox.bentobox.managers.PlayersManager; import world.bentobox.level.calculators.Pipeliner; import world.bentobox.level.calculators.Results; @@ -68,29 +52,18 @@ * @author tastybento * */ -@RunWith(PowerMockRunner.class) -@PrepareForTest({ Bukkit.class, BentoBox.class, DatabaseSetup.class, PanelBuilder.class }) -public class LevelsManagerTest { +public class LevelsManagerTest extends CommonTestSetup { @Mock - private static AbstractDatabaseHandler handler; - @Mock - Level addon; - @Mock - private BentoBox plugin; + private AbstractDatabaseHandler handler; @Mock private Settings pluginSettings; // Class under test private LevelsManager lm; @Mock - private Island island; - @Mock private Pipeliner pipeliner; private CompletableFuture cf; - private UUID uuid; - @Mock - private World world; @Mock private Player player; @@ -104,43 +77,26 @@ public class LevelsManagerTest { @Mock private IslandWorldManager iwm; @Mock - private PluginManager pim; - @Mock private IslandLevels levelsData; - @Mock - private IslandsManager im; - @Mock - private BukkitScheduler scheduler; + //@Mock + //private BukkitScheduler scheduler; + /** + * @throws java.lang.Exception + */ @SuppressWarnings("unchecked") - @BeforeClass - public static void beforeClass() { - // This has to be done beforeClass otherwise the tests will interfere with each - // other + @Override + @BeforeEach + public void setUp() throws Exception { + super.setUp(); + handler = mock(AbstractDatabaseHandler.class); // Database - PowerMockito.mockStatic(DatabaseSetup.class); + MockedStatic mockedDatabaseSetup = Mockito.mockStatic(DatabaseSetup.class); DatabaseSetup dbSetup = mock(DatabaseSetup.class); - when(DatabaseSetup.getDatabase()).thenReturn(dbSetup); + mockedDatabaseSetup.when(() -> DatabaseSetup.getDatabase()).thenReturn(dbSetup); when(dbSetup.getHandler(any())).thenReturn(handler); - } - - /** - * @throws java.lang.Exception - */ - @SuppressWarnings("deprecation") - @Before - public void setUp() throws Exception { when(addon.getPlugin()).thenReturn(plugin); - // Set up plugin - Whitebox.setInternalState(BentoBox.class, "instance", plugin); - - // Bukkit - PowerMockito.mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS); - when(Bukkit.getWorld(anyString())).thenReturn(world); - when(Bukkit.getPluginManager()).thenReturn(pim); - when(Bukkit.getPlayer(any(UUID.class))).thenReturn(player); - when(Bukkit.getScheduler()).thenReturn(scheduler); // The database type has to be created one line before the thenReturn() to work! DatabaseType value = DatabaseType.JSON; @@ -153,8 +109,6 @@ public void setUp() throws Exception { when(pipeliner.addIsland(any())).thenReturn(cf); // Island - when(addon.getIslands()).thenReturn(im); - uuid = UUID.randomUUID(); ImmutableSet iset = ImmutableSet.of(uuid); when(island.getMemberSet()).thenReturn(iset); when(island.getOwner()).thenReturn(uuid); @@ -196,12 +150,6 @@ public void setUp() throws Exception { "player9", "player10" ); - // Mock item factory (for itemstacks) - ItemFactory itemFactory = mock(ItemFactory.class); - when(Bukkit.getItemFactory()).thenReturn(itemFactory); - ItemMeta itemMeta = mock(ItemMeta.class); - when(itemFactory.getItemMeta(any())).thenReturn(itemMeta); - // Has perms when(player.hasPermission(anyString())).thenReturn(true); // Make island levels @@ -226,10 +174,10 @@ public void setUp() throws Exception { // Inventory GUI - when(Bukkit.createInventory(any(), anyInt(), anyString())).thenReturn(inv); + mockedBukkit.when(() -> Bukkit.createInventory(any(), anyInt(), anyString())).thenReturn(inv); // IWM - when(plugin.getIWM()).thenReturn(iwm); + // when(plugin.getIWM()).thenReturn(iwm); when(iwm.getPermissionPrefix(any())).thenReturn("bskyblock."); lm = new LevelsManager(addon); @@ -239,19 +187,15 @@ public void setUp() throws Exception { /** * @throws java.lang.Exception */ - @After + @Override + @AfterEach public void tearDown() throws Exception { + super.tearDown(); deleteAll(new File("database")); User.clearUsers(); Mockito.framework().clearInlineMocks(); } - private static void deleteAll(File file) throws IOException { - if (file.exists()) { - Files.walk(file.toPath()).sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete); - } - } - /** * Test method for * {@link world.bentobox.level.LevelsManager#calculateLevel(UUID, world.bentobox.bentobox.database.objects.Island)}. @@ -266,9 +210,6 @@ public void testCalculateLevel() { cf.complete(results); assertEquals(10000L, lm.getLevelsData(island).getLevel()); - // Map tt = lm.getTopTen(world, 10); - // assertEquals(1, tt.size()); - // assertTrue(tt.get(uuid) == 10000); assertEquals(10000L, lm.getIslandMaxLevel(world, uuid)); results.setLevel(5000); @@ -397,9 +338,8 @@ public void testHasTopTenPerm() { public void testLoadTopTens() { ArgumentCaptor task = ArgumentCaptor.forClass(Runnable.class); lm.loadTopTens(); - PowerMockito.verifyStatic(Bukkit.class); // 1 - Bukkit.getScheduler(); - verify(scheduler).runTaskAsynchronously(eq(plugin), task.capture()); // Capture the task in the scheduler + mockedBukkit.verify(() -> Bukkit.getScheduler()); + verify(sch).runTaskAsynchronously(eq(plugin), task.capture()); // Capture the task in the scheduler task.getValue().run(); // run it verify(addon).log("Generating rankings"); verify(addon).log("Generated rankings for bskyblock-world"); diff --git a/src/test/java/world/bentobox/level/PlaceholderManagerTest.java b/src/test/java/world/bentobox/level/PlaceholderManagerTest.java index 10bf0d0..3b6b02d 100644 --- a/src/test/java/world/bentobox/level/PlaceholderManagerTest.java +++ b/src/test/java/world/bentobox/level/PlaceholderManagerTest.java @@ -22,39 +22,30 @@ import org.bukkit.Location; import org.bukkit.World; import org.eclipse.jdt.annotation.NonNull; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.Mock; import org.mockito.stubbing.Answer; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; -import world.bentobox.bentobox.BentoBox; import world.bentobox.bentobox.api.addons.AddonDescription; import world.bentobox.bentobox.api.addons.GameModeAddon; import world.bentobox.bentobox.api.user.User; import world.bentobox.bentobox.database.objects.Island; -import world.bentobox.bentobox.managers.IslandsManager; import world.bentobox.bentobox.managers.PlaceholdersManager; import world.bentobox.bentobox.managers.PlayersManager; import world.bentobox.bentobox.managers.RanksManager; +import world.bentobox.level.config.BlockConfig; import world.bentobox.level.objects.IslandLevels; /** * @author tastybento * */ -@RunWith(PowerMockRunner.class) -@PrepareForTest({ BentoBox.class }) -public class PlaceholderManagerTest { +public class PlaceholderManagerTest extends CommonTestSetup { - @Mock - private Level addon; @Mock private GameModeAddon gm; - @Mock - private BentoBox plugin; private PlaceholderManager phm; @Mock @@ -62,25 +53,19 @@ public class PlaceholderManagerTest { @Mock private LevelsManager lm; @Mock - private World world; - @Mock - private IslandsManager im; - @Mock - private Island island; - @Mock private User user; private static final Map names = new LinkedHashMap<>(); static { - names.put(UUID.randomUUID(), "tasty"); - names.put(UUID.randomUUID(), "bento"); - names.put(UUID.randomUUID(), "fred"); - names.put(UUID.randomUUID(), "bonne"); - names.put(UUID.randomUUID(), "cyprien"); - names.put(UUID.randomUUID(), "mael"); - names.put(UUID.randomUUID(), "joe"); - names.put(UUID.randomUUID(), "horacio"); - names.put(UUID.randomUUID(), "steph"); - names.put(UUID.randomUUID(), "vicky"); + names.put(UUID.randomUUID(), "tasty"); + names.put(UUID.randomUUID(), "bento"); + names.put(UUID.randomUUID(), "fred"); + names.put(UUID.randomUUID(), "bonne"); + names.put(UUID.randomUUID(), "cyprien"); + names.put(UUID.randomUUID(), "mael"); + names.put(UUID.randomUUID(), "joe"); + names.put(UUID.randomUUID(), "horacio"); + names.put(UUID.randomUUID(), "steph"); + names.put(UUID.randomUUID(), "vicky"); } private Map islands = new HashMap<>(); private Map map = new LinkedHashMap<>(); @@ -88,21 +73,25 @@ public class PlaceholderManagerTest { private @NonNull IslandLevels data; @Mock private PlayersManager pm; + @Mock + private BlockConfig bc; /** * @throws java.lang.Exception */ - @Before + @Override + @BeforeEach public void setUp() throws Exception { - when(addon.getPlugin()).thenReturn(plugin); - - // Users + super.setUp(); + + // Addon when(addon.getPlayers()).thenReturn(pm); - + when(addon.getBlockConfig()).thenReturn(bc); + // Users when(user.getWorld()).thenReturn(world); when(user.getLocation()).thenReturn(mock(Location.class)); - + int i = 0; for (Entry n : names.entrySet()) { UUID uuid = UUID.randomUUID(); // Random island ID @@ -123,24 +112,23 @@ public void setUp() throws Exception { Map members = new HashMap<>(); names.forEach((uuid, l) -> members.put(uuid, RanksManager.MEMBER_RANK)); islands.values().forEach(is -> is.setMembers(members)); - - + + // Placeholders manager for plugin when(plugin.getPlaceholdersManager()).thenReturn(bpm); - + // Game mode AddonDescription desc = new AddonDescription.Builder("bentobox", "AOneBlock", "1.3").description("test").authors("tasty").build(); when(gm.getDescription()).thenReturn(desc); when(gm.getOverWorld()).thenReturn(world); when(gm.inWorld(world)).thenReturn(true); - + // Islands when(im.getIsland(any(World.class), any(User.class))).thenReturn(island); when(im.getIslandAt(any(Location.class))).thenReturn(Optional.of(island)); when(im.getIslandById(anyString())).thenAnswer((Answer>) invocation -> Optional.of(islands.get(invocation.getArgument(0, String.class)))); when(im.getIslands(any(), any(UUID.class))).thenReturn(new ArrayList<>(islands.values())); - when(addon.getIslands()).thenReturn(im); - + // Levels Manager when(lm.getIslandLevel(any(), any())).thenReturn(1234567L); when(lm.getIslandLevelString(any(), any())).thenReturn("1234567"); @@ -149,7 +137,7 @@ public void setUp() throws Exception { when(lm.getTopTen(world, Level.TEN)).thenReturn(map); when(lm.getWeightedTopTen(world, Level.TEN)).thenReturn(map2); when(lm.formatLevel(any())).thenAnswer((Answer) invocation -> invocation.getArgument(0, Long.class).toString()); - + data = new IslandLevels("uniqueId"); data.setTotalPoints(12345678); when(lm.getLevelsData(island)).thenReturn(data); @@ -158,13 +146,19 @@ public void setUp() throws Exception { phm = new PlaceholderManager(addon); } + @Override + @AfterEach + public void tearDown() throws Exception { + super.tearDown(); + } + /** * Test method for * {@link world.bentobox.level.PlaceholderManager#PlaceholderManager(world.bentobox.level.Level)}. */ @Test public void testPlaceholderManager() { - verify(addon).getPlugin(); + verify(addon).getPlugin(); } /** @@ -173,32 +167,32 @@ public void testPlaceholderManager() { */ @Test public void testRegisterPlaceholders() { - phm.registerPlaceholders(gm); - // Island Level - verify(bpm).registerPlaceholder(eq(addon), eq("aoneblock_island_level"), any()); - verify(bpm).registerPlaceholder(eq(addon), eq("aoneblock_island_level_raw"), any()); - verify(bpm).registerPlaceholder(eq(addon), eq("aoneblock_island_total_points"), any()); - - verify(bpm).registerPlaceholder(eq(addon), eq("aoneblock_points_to_next_level"), any()); - verify(bpm).registerPlaceholder(eq(addon), eq("aoneblock_island_level_max"), any()); - - // Visited Island Level - verify(bpm).registerPlaceholder(eq(addon), eq("aoneblock_visited_island_level"), any()); - - // Register Top Ten Placeholders - for (int i = 1; i < 11; i++) { - // Name - verify(bpm).registerPlaceholder(eq(addon), eq("aoneblock_top_name_" + i), any()); - // Island Name - verify(bpm).registerPlaceholder(eq(addon), eq("aoneblock_top_island_name_" + i), any()); - // Members - verify(bpm).registerPlaceholder(eq(addon), eq("aoneblock_top_members_" + i), any()); - // Level - verify(bpm).registerPlaceholder(eq(addon), eq("aoneblock_top_value_" + i), any()); - } - - // Personal rank - verify(bpm).registerPlaceholder(eq(addon), eq("aoneblock_rank_value"), any()); + phm.registerPlaceholders(gm); + // Island Level + verify(bpm).registerPlaceholder(eq(addon), eq("aoneblock_island_level"), any()); + verify(bpm).registerPlaceholder(eq(addon), eq("aoneblock_island_level_raw"), any()); + verify(bpm).registerPlaceholder(eq(addon), eq("aoneblock_island_total_points"), any()); + + verify(bpm).registerPlaceholder(eq(addon), eq("aoneblock_points_to_next_level"), any()); + verify(bpm).registerPlaceholder(eq(addon), eq("aoneblock_island_level_max"), any()); + + // Visited Island Level + verify(bpm).registerPlaceholder(eq(addon), eq("aoneblock_visited_island_level"), any()); + + // Register Top Ten Placeholders + for (int i = 1; i < 11; i++) { + // Name + verify(bpm).registerPlaceholder(eq(addon), eq("aoneblock_top_name_" + i), any()); + // Island Name + verify(bpm).registerPlaceholder(eq(addon), eq("aoneblock_top_island_name_" + i), any()); + // Members + verify(bpm).registerPlaceholder(eq(addon), eq("aoneblock_top_members_" + i), any()); + // Level + verify(bpm).registerPlaceholder(eq(addon), eq("aoneblock_top_value_" + i), any()); + } + + // Personal rank + verify(bpm).registerPlaceholder(eq(addon), eq("aoneblock_rank_value"), any()); } @@ -208,14 +202,14 @@ public void testRegisterPlaceholders() { */ @Test public void testGetRankName() { - // Test extremes - assertEquals("tasty", phm.getRankName(world, 0, false)); - assertEquals("vicky", phm.getRankName(world, 100, false)); - // Test the ranks - int rank = 1; - for (String name : names.values()) { - assertEquals(name, phm.getRankName(world, rank++, false)); - } + // Test extremes + assertEquals("tasty", phm.getRankName(world, 0, false)); + assertEquals("vicky", phm.getRankName(world, 100, false)); + // Test the ranks + int rank = 1; + for (String name : names.values()) { + assertEquals(name, phm.getRankName(world, rank++, false)); + } } @@ -225,14 +219,14 @@ public void testGetRankName() { */ @Test public void testGetRankIslandName() { - // Test extremes - assertEquals("tasty's island", phm.getRankIslandName(world, 0, false)); - assertEquals("vicky's island", phm.getRankIslandName(world, 100, false)); - // Test the ranks - int rank = 1; - for (String name : names.values()) { - assertEquals(name + "'s island", phm.getRankIslandName(world, rank++, false)); - } + // Test extremes + assertEquals("tasty's island", phm.getRankIslandName(world, 0, false)); + assertEquals("vicky's island", phm.getRankIslandName(world, 100, false)); + // Test the ranks + int rank = 1; + for (String name : names.values()) { + assertEquals(name + "'s island", phm.getRankIslandName(world, rank++, false)); + } } @@ -242,19 +236,19 @@ public void testGetRankIslandName() { */ @Test public void testGetRankMembers() { - // Test extremes - check(1, phm.getRankMembers(world, 0, false)); - check(2, phm.getRankMembers(world, 100, false)); - // Test the ranks - for (int rank = 1; rank < 11; rank++) { - check(3, phm.getRankMembers(world, rank, false)); - } + // Test extremes + check(1, phm.getRankMembers(world, 0, false)); + check(2, phm.getRankMembers(world, 100, false)); + // Test the ranks + for (int rank = 1; rank < 11; rank++) { + check(3, phm.getRankMembers(world, rank, false)); + } } void check(int indicator, String list) { - for (String n : names.values()) { - assertTrue(n + " is missing for test " + indicator, list.contains(n)); - } + for (String n : names.values()) { + assertTrue(n + " is missing for test " + indicator, list.contains(n)); + } } /** @@ -263,13 +257,13 @@ void check(int indicator, String list) { */ @Test public void testGetRankLevel() { - // Test extremes - assertEquals("100", phm.getRankLevel(world, 0, false)); - assertEquals("91", phm.getRankLevel(world, 100, false)); - // Test the ranks - for (int rank = 1; rank < 11; rank++) { - assertEquals(String.valueOf(101 - rank), phm.getRankLevel(world, rank, false)); - } + // Test extremes + assertEquals("100", phm.getRankLevel(world, 0, false)); + assertEquals("91", phm.getRankLevel(world, 100, false)); + // Test the ranks + for (int rank = 1; rank < 11; rank++) { + assertEquals(String.valueOf(101 - rank), phm.getRankLevel(world, rank, false)); + } } @@ -279,13 +273,13 @@ public void testGetRankLevel() { */ @Test public void testGetWeightedRankLevel() { - // Test extremes - assertEquals("100", phm.getRankLevel(world, 0, true)); - assertEquals("91", phm.getRankLevel(world, 100, true)); - // Test the ranks - for (int rank = 1; rank < 11; rank++) { - assertEquals(String.valueOf(101 - rank), phm.getRankLevel(world, rank, true)); - } + // Test extremes + assertEquals("100", phm.getRankLevel(world, 0, true)); + assertEquals("91", phm.getRankLevel(world, 100, true)); + // Test the ranks + for (int rank = 1; rank < 11; rank++) { + assertEquals(String.valueOf(101 - rank), phm.getRankLevel(world, rank, true)); + } } @@ -295,7 +289,7 @@ public void testGetWeightedRankLevel() { */ @Test public void testGetVisitedIslandLevelNullUser() { - assertEquals("", phm.getVisitedIslandLevel(gm, null)); + assertEquals("", phm.getVisitedIslandLevel(gm, null)); } @@ -307,7 +301,7 @@ public void testGetVisitedIslandLevelUserNotInWorld() { // Another world when(user.getWorld()).thenReturn(mock(World.class)); assertEquals("", phm.getVisitedIslandLevel(gm, user)); - + } /** @@ -316,7 +310,7 @@ public void testGetVisitedIslandLevelUserNotInWorld() { */ @Test public void testGetVisitedIslandLevel() { - assertEquals("1234567", phm.getVisitedIslandLevel(gm, user)); + assertEquals("1234567", phm.getVisitedIslandLevel(gm, user)); } @@ -327,7 +321,7 @@ public void testGetVisitedIslandLevel() { public void testGetVisitedIslandLevelNoIsland() { when(im.getIslandAt(any(Location.class))).thenReturn(Optional.empty()); assertEquals("0", phm.getVisitedIslandLevel(gm, user)); - + } } diff --git a/src/test/java/world/bentobox/level/TestWorldSettings.java b/src/test/java/world/bentobox/level/TestWorldSettings.java new file mode 100644 index 0000000..291d577 --- /dev/null +++ b/src/test/java/world/bentobox/level/TestWorldSettings.java @@ -0,0 +1,409 @@ +package world.bentobox.level; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.bukkit.Difficulty; +import org.bukkit.GameMode; +import org.bukkit.entity.EntityType; +import org.eclipse.jdt.annotation.NonNull; + +import world.bentobox.bentobox.api.configuration.WorldSettings; +import world.bentobox.bentobox.api.flags.Flag; + +/** + * Class for tests that require world settings + * @author tastybento + * + */ +public class TestWorldSettings implements WorldSettings { + + private long epoch; + + @Override + public GameMode getDefaultGameMode() { + + return GameMode.SURVIVAL; + } + + @Override + public Map getDefaultIslandFlags() { + + return Collections.emptyMap(); + } + + @Override + public Map getDefaultIslandSettings() { + + return Collections.emptyMap(); + } + + @Override + public Difficulty getDifficulty() { + + return Difficulty.EASY; + } + + @Override + public void setDifficulty(Difficulty difficulty) { + + + } + + @Override + public String getFriendlyName() { + + return "friendly_name"; + } + + @Override + public int getIslandDistance() { + + return 0; + } + + @Override + public int getIslandHeight() { + + return 0; + } + + @Override + public int getIslandProtectionRange() { + + return 0; + } + + @Override + public int getIslandStartX() { + + return 0; + } + + @Override + public int getIslandStartZ() { + + return 0; + } + + @Override + public int getIslandXOffset() { + + return 0; + } + + @Override + public int getIslandZOffset() { + + return 0; + } + + @Override + public List getIvSettings() { + + return Collections.emptyList(); + } + + @Override + public int getMaxHomes() { + + return 3; + } + + @Override + public int getMaxIslands() { + + return 0; + } + + @Override + public int getMaxTeamSize() { + + return 4; + } + + @Override + public int getNetherSpawnRadius() { + + return 10; + } + + @Override + public String getPermissionPrefix() { + + return "perm."; + } + + @Override + public Set getRemoveMobsWhitelist() { + + return Collections.emptySet(); + } + + @Override + public int getSeaHeight() { + + return 0; + } + + @Override + public List getHiddenFlags() { + + return Collections.emptyList(); + } + + @Override + public List getVisitorBannedCommands() { + + return Collections.emptyList(); + } + + @Override + public Map getWorldFlags() { + + return Collections.emptyMap(); + } + + @Override + public String getWorldName() { + + return "world_name"; + } + + @Override + public boolean isDragonSpawn() { + + return false; + } + + @Override + public boolean isEndGenerate() { + + return true; + } + + @Override + public boolean isEndIslands() { + + return true; + } + + @Override + public boolean isNetherGenerate() { + + return true; + } + + @Override + public boolean isNetherIslands() { + + return true; + } + + @Override + public boolean isOnJoinResetEnderChest() { + + return false; + } + + @Override + public boolean isOnJoinResetInventory() { + + return false; + } + + @Override + public boolean isOnJoinResetMoney() { + + return false; + } + + @Override + public boolean isOnJoinResetHealth() { + + return false; + } + + @Override + public boolean isOnJoinResetHunger() { + + return false; + } + + @Override + public boolean isOnJoinResetXP() { + + return false; + } + + @Override + public @NonNull List getOnJoinCommands() { + + return Collections.emptyList(); + } + + @Override + public boolean isOnLeaveResetEnderChest() { + + return false; + } + + @Override + public boolean isOnLeaveResetInventory() { + + return false; + } + + @Override + public boolean isOnLeaveResetMoney() { + + return false; + } + + @Override + public boolean isOnLeaveResetHealth() { + + return false; + } + + @Override + public boolean isOnLeaveResetHunger() { + + return false; + } + + @Override + public boolean isOnLeaveResetXP() { + + return false; + } + + @Override + public @NonNull List getOnLeaveCommands() { + + return Collections.emptyList(); + } + + @Override + public boolean isUseOwnGenerator() { + + return false; + } + + @Override + public boolean isWaterUnsafe() { + + return false; + } + + @Override + public List getGeoLimitSettings() { + + return Collections.emptyList(); + } + + @Override + public int getResetLimit() { + + return 0; + } + + @Override + public long getResetEpoch() { + + return epoch; + } + + @Override + public void setResetEpoch(long timestamp) { + this.epoch = timestamp; + + } + + @Override + public boolean isTeamJoinDeathReset() { + + return false; + } + + @Override + public int getDeathsMax() { + + return 0; + } + + @Override + public boolean isDeathsCounted() { + + return true; + } + + @Override + public boolean isDeathsResetOnNewIsland() { + + return true; + } + + @Override + public boolean isAllowSetHomeInNether() { + + return false; + } + + @Override + public boolean isAllowSetHomeInTheEnd() { + + return false; + } + + @Override + public boolean isRequireConfirmationToSetHomeInNether() { + + return false; + } + + @Override + public boolean isRequireConfirmationToSetHomeInTheEnd() { + + return false; + } + + @Override + public int getBanLimit() { + + return 10; + } + + @Override + public boolean isLeaversLoseReset() { + + return true; + } + + @Override + public boolean isKickedKeepInventory() { + + return true; + } + + @Override + public boolean isCreateIslandOnFirstLoginEnabled() { + + return false; + } + + @Override + public int getCreateIslandOnFirstLoginDelay() { + + return 0; + } + + @Override + public boolean isCreateIslandOnFirstLoginAbortOnLogout() { + + return false; + } + +} diff --git a/src/test/java/world/bentobox/level/WhiteBox.java b/src/test/java/world/bentobox/level/WhiteBox.java new file mode 100644 index 0000000..a0f2e51 --- /dev/null +++ b/src/test/java/world/bentobox/level/WhiteBox.java @@ -0,0 +1,26 @@ +package world.bentobox.level; + +public class WhiteBox { + /** + * Sets the value of a private static field using Java Reflection. + * @param targetClass The class containing the static field. + * @param fieldName The name of the private static field. + * @param value The value to set the field to. + */ + public static void setInternalState(Class targetClass, String fieldName, Object value) { + try { + // 1. Get the Field object from the class + java.lang.reflect.Field field = targetClass.getDeclaredField(fieldName); + + // 2. Make the field accessible (required for private fields) + field.setAccessible(true); + + // 3. Set the new value. The first argument is 'null' for static fields. + field.set(null, value); + + } catch (NoSuchFieldException | IllegalAccessException e) { + // Wrap reflection exceptions in a runtime exception for clarity + throw new RuntimeException("Failed to set static field '" + fieldName + "' on class " + targetClass.getName(), e); + } + } +} diff --git a/src/test/java/world/bentobox/level/commands/AdminStatsCommandTest.java b/src/test/java/world/bentobox/level/commands/AdminStatsCommandTest.java index 21d26d0..55f4f55 100644 --- a/src/test/java/world/bentobox/level/commands/AdminStatsCommandTest.java +++ b/src/test/java/world/bentobox/level/commands/AdminStatsCommandTest.java @@ -1,11 +1,10 @@ package world.bentobox.level.commands; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -16,131 +15,62 @@ import java.util.Random; import java.util.UUID; -import org.bukkit.Bukkit; -import org.bukkit.Server; import org.bukkit.World; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemFactory; -import org.bukkit.inventory.meta.ItemMeta; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.Mock; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; -import org.powermock.reflect.Whitebox; -import world.bentobox.bentobox.BentoBox; -import world.bentobox.bentobox.api.addons.GameModeAddon; -import world.bentobox.bentobox.api.commands.CompositeCommand; import world.bentobox.bentobox.api.user.User; -import world.bentobox.bentobox.database.objects.Island; -import world.bentobox.bentobox.managers.IslandWorldManager; -import world.bentobox.bentobox.managers.IslandsManager; -import world.bentobox.bentobox.managers.LocalesManager; import world.bentobox.bentobox.managers.PlayersManager; -import world.bentobox.level.Level; +import world.bentobox.level.CommonTestSetup; import world.bentobox.level.LevelsManager; import world.bentobox.level.objects.TopTenData; /** * @author tastybento */ -@RunWith(PowerMockRunner.class) -@PrepareForTest({ Bukkit.class, BentoBox.class }) -public class AdminStatsCommandTest { +public class AdminStatsCommandTest extends CommonTestSetup { @Mock - private CompositeCommand ic; - private UUID uuid; - @Mock - private User user; - @Mock - private IslandsManager im; - @Mock - private Island island; - @Mock - private Level addon; - @Mock - private World world; - @Mock - private IslandWorldManager iwm; - @Mock - private GameModeAddon gameModeAddon; - @Mock - private Player p; - @Mock - private LocalesManager lm; + private LevelsManager manager; @Mock private PlayersManager pm; - + @Mock + private User user; + private AdminStatsCommand asc; private TopTenData ttd; - @Mock - private LevelsManager manager; - @Mock - private Server server; - - @Before - public void setUp() { - // Set up plugin - BentoBox plugin = mock(BentoBox.class); - Whitebox.setInternalState(BentoBox.class, "instance", plugin); - User.setPlugin(plugin); - when(addon.getPlugin()).thenReturn(plugin); - - // Addon - when(ic.getAddon()).thenReturn(addon); - when(ic.getPermissionPrefix()).thenReturn("bskyblock."); - when(ic.getLabel()).thenReturn("island"); - when(ic.getTopLabel()).thenReturn("island"); - when(ic.getWorld()).thenReturn(world); - when(ic.getTopLabel()).thenReturn("bsb"); - - // IWM friendly name - when(plugin.getIWM()).thenReturn(iwm); - when(iwm.getFriendlyName(any())).thenReturn("BSkyBlock"); - - // World - when(world.toString()).thenReturn("world"); - when(world.getName()).thenReturn("BSkyBlock_world"); - - // Player manager - when(plugin.getPlayers()).thenReturn(pm); - when(pm.getUser(anyString())).thenReturn(user); - // topTen - when(addon.getManager()).thenReturn(manager); - // User - uuid = UUID.randomUUID(); - when(user.getUniqueId()).thenReturn(uuid); - when(user.getTranslation(any())).thenAnswer(invocation -> invocation.getArgument(0, String.class)); - - // Bukkit - PowerMockito.mockStatic(Bukkit.class); - when(Bukkit.getServer()).thenReturn(server); - // Mock item factory (for itemstacks) - ItemFactory itemFactory = mock(ItemFactory.class); - ItemMeta itemMeta = mock(ItemMeta.class); - when(itemFactory.getItemMeta(any())).thenReturn(itemMeta); - when(server.getItemFactory()).thenReturn(itemFactory); - when(Bukkit.getItemFactory()).thenReturn(itemFactory); - // Top ten - ttd = new TopTenData(world); - Map topten = new HashMap<>(); - Random r = new Random(); - for (int i = 0; i < 1000; i++) { - topten.put(UUID.randomUUID().toString(), r.nextLong(20000)); - } - ttd.setTopTen(topten); - asc = new AdminStatsCommand(addon, ic); + @Override + @BeforeEach + public void setUp() throws Exception { + super.setUp(); + + // Player manager + when(plugin.getPlayers()).thenReturn(pm); + when(pm.getUser(anyString())).thenReturn(user); + // topTen + when(addon.getManager()).thenReturn(manager); + // User + when(user.getUniqueId()).thenReturn(uuid); + when(user.getTranslation(any())).thenAnswer(invocation -> invocation.getArgument(0, String.class)); + + // Top ten + ttd = new TopTenData(world); + Map topten = new HashMap<>(); + Random r = new Random(); + for (int i = 0; i < 1000; i++) { + topten.put(UUID.randomUUID().toString(), r.nextLong(20000)); + } + ttd.setTopTen(topten); + asc = new AdminStatsCommand(addon, ic); } - @After - public void tearDown() { - User.clearUsers(); + @Override + @AfterEach + public void tearDown() throws Exception { + super.tearDown(); } /** @@ -149,9 +79,9 @@ public void tearDown() { */ @Test public void testSetup() { - assertEquals("bskyblock.admin.stats", asc.getPermission()); - assertFalse(asc.isOnlyPlayer()); - assertEquals("admin.stats.description", asc.getDescription()); + assertEquals("bskyblock.admin.stats", asc.getPermission()); + assertFalse(asc.isOnlyPlayer()); + assertEquals("admin.stats.description", asc.getDescription()); } @@ -161,9 +91,9 @@ public void testSetup() { */ @Test public void testExecuteUserStringListOfString() { - assertFalse(asc.execute(user, "", List.of())); - verify(user).sendMessage("admin.stats.title"); - verify(user).sendMessage("admin.stats.no-data"); + assertFalse(asc.execute(user, "", List.of())); + verify(user).sendMessage("admin.stats.title"); + verify(user).sendMessage("admin.stats.no-data"); } /** @@ -172,12 +102,12 @@ public void testExecuteUserStringListOfString() { */ @Test public void testExecuteUserStringListOfStringLevels() { - Map map = new HashMap<>(); - map.put(world, ttd); - when(manager.getTopTenLists()).thenReturn(map); - assertTrue(asc.execute(user, "", List.of())); - verify(user).sendMessage("admin.stats.title"); - verify(user, never()).sendMessage("admin.stats.no-data"); + Map map = new HashMap<>(); + map.put(world, ttd); + when(manager.getTopTenLists()).thenReturn(map); + assertTrue(asc.execute(user, "", List.of())); + verify(user).sendMessage("admin.stats.title"); + verify(user, never()).sendMessage("admin.stats.no-data"); } } diff --git a/src/test/java/world/bentobox/level/commands/AdminTopRemoveCommandTest.java b/src/test/java/world/bentobox/level/commands/AdminTopRemoveCommandTest.java index 8a49c25..41a9c3a 100644 --- a/src/test/java/world/bentobox/level/commands/AdminTopRemoveCommandTest.java +++ b/src/test/java/world/bentobox/level/commands/AdminTopRemoveCommandTest.java @@ -5,7 +5,6 @@ import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -13,33 +12,15 @@ import java.util.List; import java.util.UUID; -import org.bukkit.Bukkit; -import org.bukkit.Server; -import org.bukkit.World; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemFactory; -import org.bukkit.inventory.meta.ItemMeta; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.mockito.Mock; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; -import org.powermock.reflect.Whitebox; - -import world.bentobox.bentobox.BentoBox; -import world.bentobox.bentobox.api.addons.GameModeAddon; -import world.bentobox.bentobox.api.commands.CompositeCommand; + import world.bentobox.bentobox.api.localization.TextVariables; import world.bentobox.bentobox.api.user.User; -import world.bentobox.bentobox.database.objects.Island; -import world.bentobox.bentobox.managers.IslandWorldManager; -import world.bentobox.bentobox.managers.IslandsManager; -import world.bentobox.bentobox.managers.LocalesManager; import world.bentobox.bentobox.managers.PlayersManager; -import world.bentobox.level.Level; +import world.bentobox.level.CommonTestSetup; import world.bentobox.level.LevelsManager; import world.bentobox.level.objects.TopTenData; @@ -47,98 +28,45 @@ * @author tastybento * */ -@RunWith(PowerMockRunner.class) -@PrepareForTest({ Bukkit.class, BentoBox.class }) -public class AdminTopRemoveCommandTest { +public class AdminTopRemoveCommandTest extends CommonTestSetup { - @Mock - private CompositeCommand ic; - private UUID uuid; @Mock private User user; @Mock - private IslandsManager im; - @Mock - private Island island; - @Mock - private Level addon; - @Mock - private World world; - @Mock - private IslandWorldManager iwm; - @Mock - private GameModeAddon gameModeAddon; - @Mock - private Player p; - @Mock - private LocalesManager lm; - @Mock private PlayersManager pm; - - private AdminTopRemoveCommand atrc; @Mock private TopTenData ttd; @Mock private LevelsManager manager; - @Mock - private Server server; - - @Before - public void setUp() { - // Set up plugin - BentoBox plugin = mock(BentoBox.class); - Whitebox.setInternalState(BentoBox.class, "instance", plugin); - User.setPlugin(plugin); - - // Addon - when(ic.getAddon()).thenReturn(addon); - when(ic.getPermissionPrefix()).thenReturn("bskyblock."); - when(ic.getLabel()).thenReturn("island"); - when(ic.getTopLabel()).thenReturn("island"); - when(ic.getWorld()).thenReturn(world); - when(ic.getTopLabel()).thenReturn("bsb"); - - // IWM friendly name - when(plugin.getIWM()).thenReturn(iwm); - when(iwm.getFriendlyName(any())).thenReturn("BSkyBlock"); - - // World - when(world.toString()).thenReturn("world"); - when(world.getName()).thenReturn("BSkyBlock_world"); - - // Player manager - when(plugin.getPlayers()).thenReturn(pm); - when(pm.getUser(anyString())).thenReturn(user); - // topTen - when(addon.getManager()).thenReturn(manager); - // User - uuid = UUID.randomUUID(); - when(user.getUniqueId()).thenReturn(uuid); - when(user.getTranslation(any())).thenAnswer(invocation -> invocation.getArgument(0, String.class)); - // Island - when(island.getUniqueId()).thenReturn(uuid.toString()); - when(island.getOwner()).thenReturn(uuid); - // Island Manager - when(plugin.getIslands()).thenReturn(im); - when(im.getIslands(any(), any(User.class))).thenReturn(List.of(island)); - when(im.getIslands(any(), any(UUID.class))).thenReturn(List.of(island)); - - // Bukkit - PowerMockito.mockStatic(Bukkit.class); - when(Bukkit.getServer()).thenReturn(server); - // Mock item factory (for itemstacks) - ItemFactory itemFactory = mock(ItemFactory.class); - ItemMeta itemMeta = mock(ItemMeta.class); - when(itemFactory.getItemMeta(any())).thenReturn(itemMeta); - when(server.getItemFactory()).thenReturn(itemFactory); - when(Bukkit.getItemFactory()).thenReturn(itemFactory); - - atrc = new AdminTopRemoveCommand(addon, ic); + + private AdminTopRemoveCommand atrc; + + @Override + @BeforeEach + public void setUp() throws Exception { + super.setUp(); + // Player manager + when(plugin.getPlayers()).thenReturn(pm); + when(pm.getUser(anyString())).thenReturn(user); + // topTen + when(addon.getManager()).thenReturn(manager); + // User + when(user.getUniqueId()).thenReturn(uuid); + when(user.getTranslation(any())).thenAnswer(invocation -> invocation.getArgument(0, String.class)); + // Island + when(island.getUniqueId()).thenReturn(uuid.toString()); + when(island.getOwner()).thenReturn(uuid); + // Island Manager + when(im.getIslands(any(), any(User.class))).thenReturn(List.of(island)); + when(im.getIslands(any(), any(UUID.class))).thenReturn(List.of(island)); + + atrc = new AdminTopRemoveCommand(addon, ic); } - @After - public void tearDown() { - User.clearUsers(); + @Override + @AfterEach + public void tearDown() throws Exception { + super.tearDown(); } /** @@ -147,8 +75,8 @@ public void tearDown() { */ @Test public void testAdminTopRemoveCommand() { - assertEquals("remove", atrc.getLabel()); - assertEquals("delete", atrc.getAliases().get(0)); + assertEquals("remove", atrc.getLabel()); + assertEquals("delete", atrc.getAliases().get(0)); } /** @@ -157,10 +85,10 @@ public void testAdminTopRemoveCommand() { */ @Test public void testSetup() { - assertEquals("bskyblock.admin.top.remove", atrc.getPermission()); - assertEquals("admin.top.remove.parameters", atrc.getParameters()); - assertEquals("admin.top.remove.description", atrc.getDescription()); - assertFalse(atrc.isOnlyPlayer()); + assertEquals("bskyblock.admin.top.remove", atrc.getPermission()); + assertEquals("admin.top.remove.parameters", atrc.getParameters()); + assertEquals("admin.top.remove.description", atrc.getDescription()); + assertFalse(atrc.isOnlyPlayer()); } @@ -170,8 +98,8 @@ public void testSetup() { */ @Test public void testCanExecuteWrongArgs() { - assertFalse(atrc.canExecute(user, "delete", Collections.emptyList())); - verify(user).sendMessage("commands.help.header", TextVariables.LABEL, "BSkyBlock"); + assertFalse(atrc.canExecute(user, "delete", Collections.emptyList())); + verify(user).sendMessage("commands.help.header", TextVariables.LABEL, "BSkyBlock"); } /** @@ -190,7 +118,7 @@ public void testCanExecuteUnknown() { */ @Test public void testCanExecuteKnown() { - assertTrue(atrc.canExecute(user, "delete", Collections.singletonList("tastybento"))); + assertTrue(atrc.canExecute(user, "delete", Collections.singletonList("tastybento"))); } /** @@ -199,10 +127,10 @@ public void testCanExecuteKnown() { */ @Test public void testExecuteUserStringListOfString() { - testCanExecuteKnown(); - assertTrue(atrc.execute(user, "delete", Collections.singletonList("tastybento"))); - verify(manager).removeEntry(world, uuid.toString()); - verify(user).sendMessage("general.success"); + testCanExecuteKnown(); + assertTrue(atrc.execute(user, "delete", Collections.singletonList("tastybento"))); + verify(manager).removeEntry(world, uuid.toString()); + verify(user).sendMessage("general.success"); } } diff --git a/src/test/java/world/bentobox/level/mocks/ServerMocks.java b/src/test/java/world/bentobox/level/mocks/ServerMocks.java deleted file mode 100644 index 568b529..0000000 --- a/src/test/java/world/bentobox/level/mocks/ServerMocks.java +++ /dev/null @@ -1,118 +0,0 @@ -package world.bentobox.level.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, Object> registers = new HashMap<>(); - - doAnswer(invocationGetRegistry -> registers.computeIfAbsent(invocationGetRegistry.getArgument(0), clazz -> { - Registry registry = mock(Registry.class); - Map 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 constantClazz; - try { - //noinspection unchecked - constantClazz = (Class) 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() { - } - -} \ No newline at end of file