diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 825b18d..956c975 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,11 +14,11 @@ jobs: - uses: actions/checkout@v3 with: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis - - name: Set up JDK 17 + - name: Set up JDK 21 uses: actions/setup-java@v3 with: - distribution: 'adopt' - java-version: 17 + distribution: 'temurin' + java-version: 21 - name: Cache SonarCloud packages uses: actions/cache@v3 with: @@ -35,4 +35,5 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + MAVEN_OPTS: "-XX:+EnableDynamicAgentLoading" run: mvn -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar \ No newline at end of file diff --git a/pom.xml b/pom.xml index 912a519..fe049d9 100644 --- a/pom.xml +++ b/pom.xml @@ -55,18 +55,18 @@ UTF-8 UTF-8 - 17 + 21 - 2.0.9 + 5.12.0 - 1.20.3-R0.1-SNAPSHOT - 2.0.0-SNAPSHOT + 1.20.4-R0.1-SNAPSHOT + 2.4.1-SNAPSHOT ${build.version}-SNAPSHOT -LOCAL - 1.12.0 + 1.13.0 BentoBoxWorld_addon-invSwitcher bentobox-world @@ -142,19 +142,19 @@ org.mockito mockito-core - 3.11.2 + ${mockito.version} test - org.powermock - powermock-module-junit4 - ${powermock.version} + org.mockito + mockito-inline + 5.0.0 test - org.powermock - powermock-api-mockito2 - ${powermock.version} + junit + junit + 4.13.2 test @@ -202,7 +202,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.7.0 + 3.13.0 ${java.version} @@ -210,7 +210,7 @@ org.apache.maven.plugins maven-surefire-plugin - 3.0.0-M5 + 3.3.0 ${argLine} @@ -283,7 +283,7 @@ org.jacoco jacoco-maven-plugin - 0.8.10 + 0.8.12 true diff --git a/src/main/java/com/wasteofplastic/invswitcher/Store.java b/src/main/java/com/wasteofplastic/invswitcher/Store.java index d218f27..4dec084 100644 --- a/src/main/java/com/wasteofplastic/invswitcher/Store.java +++ b/src/main/java/com/wasteofplastic/invswitcher/Store.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017 - 2021 tastybento + * Copyright (c) 2017 - 2024 tastybento * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -58,11 +58,6 @@ public class Store { private static final CharSequence THE_END = "_the_end"; private static final CharSequence NETHER = "_nether"; - @SuppressWarnings("deprecation") - private static final List BLOCKS = Arrays.stream(Material.values()).filter(Material::isBlock).filter(m -> !m.isLegacy()).toList(); - @SuppressWarnings("deprecation") - private static final List ITEMS = Arrays.stream(Material.values()).filter(Material::isItem).filter(m -> !m.isLegacy()).toList(); - private static final List LIVING_ENTITIES = Arrays.stream(EntityType.values()).filter(EntityType::isAlive).toList(); private final Database database; private final Map cache; private final InvSwitcher addon; @@ -265,21 +260,24 @@ private void saveStats(InventoryStorage store, Player player, String worldName) Map entMap; switch (s.getType()) { case BLOCK -> { - map = BLOCKS.stream().filter(m -> player.getStatistic(s, m) > 0) + map = Arrays.stream(Material.values()).filter(Material::isBlock).filter(m -> !m.isLegacy()) + .filter(m -> player.getStatistic(s, m) > 0) .collect(Collectors.toMap(k -> k, v -> player.getStatistic(s, v))); if (!map.isEmpty()) { store.getBlockStats(worldName).put(s, map); } } case ITEM -> { - map = ITEMS.stream().filter(m -> player.getStatistic(s, m) > 0) + map = Arrays.stream(Material.values()).filter(Material::isItem).filter(m -> !m.isLegacy()) + .filter(m -> player.getStatistic(s, m) > 0) .collect(Collectors.toMap(k -> k, v -> player.getStatistic(s, v))); if (!map.isEmpty()) { store.getItemStats(worldName).put(s, map); } } case ENTITY -> { - entMap = LIVING_ENTITIES.stream().filter(m -> player.getStatistic(s, m) > 0) + entMap = Arrays.stream(EntityType.values()).filter(EntityType::isAlive) + .filter(m -> player.getStatistic(s, m) > 0) .collect(Collectors.toMap(k -> k, v -> player.getStatistic(s, v))); if (!entMap.isEmpty()) { store.getEntityStats(worldName).put(s, entMap); @@ -364,11 +362,15 @@ private void resetAdv(Player player) { } } + @SuppressWarnings("deprecation") private void resetStats(Player player, Statistic s) { switch (s.getType()) { - case BLOCK -> BLOCKS.forEach(m -> player.setStatistic(s, m, 0)); - case ITEM -> ITEMS.forEach(m -> player.setStatistic(s, m, 0)); - case ENTITY -> LIVING_ENTITIES.forEach(en -> player.setStatistic(s, en, 0)); + case BLOCK -> Arrays.stream(Material.values()).filter(Material::isBlock).filter(m -> !m.isLegacy()) + .forEach(m -> player.setStatistic(s, m, 0)); + case ITEM -> Arrays.stream(Material.values()).filter(Material::isItem).filter(m -> !m.isLegacy()) + .forEach(m -> player.setStatistic(s, m, 0)); + case ENTITY -> + Arrays.stream(EntityType.values()).filter(EntityType::isAlive).forEach(en -> player.setStatistic(s, en, 0)); case UNTYPED -> player.setStatistic(s, 0); } } diff --git a/src/test/java/com/wasteofplastic/invswitcher/InvSwitcherTest.java b/src/test/java/com/wasteofplastic/invswitcher/InvSwitcherTest.java index 401bb08..646ade7 100644 --- a/src/test/java/com/wasteofplastic/invswitcher/InvSwitcherTest.java +++ b/src/test/java/com/wasteofplastic/invswitcher/InvSwitcherTest.java @@ -6,6 +6,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mockStatic; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -15,6 +16,7 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.lang.reflect.Field; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -34,10 +36,9 @@ import org.junit.Test; import org.junit.runner.RunWith; 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 org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; import com.wasteofplastic.invswitcher.listeners.PlayerListener; @@ -52,8 +53,7 @@ * @author tastybento * */ -@RunWith(PowerMockRunner.class) -@PrepareForTest({Bukkit.class, BentoBox.class}) +@RunWith(MockitoJUnitRunner.class) public class InvSwitcherTest { private static File jFile; @@ -95,11 +95,20 @@ public static void beforeClass() throws IOException { } /** + * @throws SecurityException + * @throws NoSuchFieldException + * @throws IllegalAccessException + * @throws IllegalArgumentException */ @Before - public void setUp() { + public void setUp() + throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { // Set up plugin - Whitebox.setInternalState(BentoBox.class, "instance", plugin); + // Use reflection to set the private static field "instance" in BentoBox + Field instanceField = BentoBox.class.getDeclaredField("instance"); + + instanceField.setAccessible(true); + instanceField.set(null, plugin); when(plugin.getLogger()).thenReturn(Logger.getAnonymousLogger()); // The database type has to be created one line before the thenReturn() to work! @@ -117,10 +126,6 @@ public void setUp() { // Addons manager when(plugin.getAddonsManager()).thenReturn(am); - // Bukkit - PowerMockito.mockStatic(Bukkit.class); - when(Bukkit.getWorld(anyString())).thenReturn(world); - // World when(world.getName()).thenReturn("bskyblock-world"); } @@ -165,12 +170,17 @@ public void testOnEnable() { */ @Test public void testOnDisable() { - addon.onLoad(); - addon.getSettings().setWorlds(Set.of("bskyblock-world")); - addon.allLoaded(); - addon.onDisable(); - PowerMockito.verifyStatic(Bukkit.class); - Bukkit.getOnlinePlayers(); + // Mock the static method + try (MockedStatic mockedBukkit = mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS)) { + when(Bukkit.getWorld(anyString())).thenReturn(world); + // Run code to test + addon.onLoad(); + addon.getSettings().setWorlds(Set.of("bskyblock-world")); + addon.allLoaded(); + addon.onDisable(); + // Verify that the static method was never called + mockedBukkit.verify(() -> Bukkit.getOnlinePlayers()); + } } /** @@ -188,12 +198,17 @@ public void testOnLoad() { */ @Test public void testAllLoaded() { - addon.onLoad(); - addon.getSettings().setWorlds(Set.of("bskyblock-world")); - addon.allLoaded(); - verify(plugin).log("[InvSwitcher] Hooking into the following worlds:"); - verify(plugin, times(3)).log("[InvSwitcher] bskyblock-world"); - verify(am).registerListener(eq(addon), any(PlayerListener.class)); + // Mock the static method + try (MockedStatic mockedBukkit = mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS)) { + when(Bukkit.getWorld(anyString())).thenReturn(world); + // Run code to test + addon.onLoad(); + addon.getSettings().setWorlds(Set.of("bskyblock-world")); + addon.allLoaded(); + verify(plugin).log("[InvSwitcher] Hooking into the following worlds:"); + verify(plugin, times(3)).log("[InvSwitcher] bskyblock-world"); + verify(am).registerListener(eq(addon), any(PlayerListener.class)); + } } diff --git a/src/test/java/com/wasteofplastic/invswitcher/StoreTest.java b/src/test/java/com/wasteofplastic/invswitcher/StoreTest.java index c447828..24b87f7 100644 --- a/src/test/java/com/wasteofplastic/invswitcher/StoreTest.java +++ b/src/test/java/com/wasteofplastic/invswitcher/StoreTest.java @@ -1,11 +1,14 @@ package com.wasteofplastic.invswitcher; -import static org.junit.Assert.*; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyFloat; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -13,9 +16,9 @@ import java.io.File; import java.io.IOException; +import java.lang.reflect.Field; import java.nio.file.Files; import java.nio.file.Path; -import java.util.Collections; import java.util.Comparator; import java.util.UUID; import java.util.logging.Logger; @@ -23,6 +26,7 @@ import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.World; +import org.bukkit.World.Environment; import org.bukkit.attribute.AttributeInstance; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; @@ -33,11 +37,9 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; +import org.mockito.MockedStatic; import org.mockito.Mockito; -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 org.mockito.junit.MockitoJUnitRunner; import world.bentobox.bentobox.BentoBox; import world.bentobox.bentobox.Settings; @@ -48,8 +50,7 @@ * @author tastybento * */ -@RunWith(PowerMockRunner.class) -@PrepareForTest({Bukkit.class, Util.class}) +@RunWith(MockitoJUnitRunner.Silent.class) public class StoreTest { @Mock @@ -58,24 +59,29 @@ public class StoreTest { private Player player; @Mock private World world; + @Mock + private Settings settings; private Store s; + private com.wasteofplastic.invswitcher.Settings sets; @Mock private Logger logger; @Before - public void setUp() { - // Bukkit - PowerMockito.mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS); + public void setUp() + throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { // BentoBox BentoBox plugin = mock(BentoBox.class); - Whitebox.setInternalState(BentoBox.class, "instance", plugin); - Settings settings = mock(Settings.class); + // Use reflection to set the private static field "instance" in BentoBox + Field instanceField = BentoBox.class.getDeclaredField("instance"); + + instanceField.setAccessible(true); + instanceField.set(null, plugin); + when(plugin.getSettings()).thenReturn(settings); - when(settings.getDatabaseType()).thenReturn(DatabaseType.YAML); // Player mock UUID uuid = UUID.randomUUID(); @@ -93,22 +99,25 @@ public void setUp() { // World mock when(world.getName()).thenReturn("world_the_end_nether"); + when(world.getEnvironment()).thenReturn(Environment.NORMAL); // World 2 World fromWorld = mock(World.class); - when(fromWorld.getName()).thenReturn("from_the_end_nether"); // Settings sets = new com.wasteofplastic.invswitcher.Settings(); when(addon.getSettings()).thenReturn(sets); - when(addon.getWorlds()).thenReturn(Collections.singleton(world)); // Addon when(addon.getLogger()).thenReturn(logger); - PowerMockito.mockStatic(Util.class); - when(Util.getWorld(world)).thenReturn(world); - when(Util.getWorld(fromWorld)).thenReturn(fromWorld); + //PowerMockito.mockStatic(Util.class); + try (MockedStatic utilities = Mockito.mockStatic(Util.class)) { + utilities.when(() -> Util.getWorld(world)).thenReturn(world); + utilities.when(() -> Util.getWorld(fromWorld)).thenReturn(fromWorld); + } + DatabaseType mockDbt = mock(DatabaseType.class); + when(settings.getDatabaseType()).thenReturn(mockDbt); // Class under test s = new Store(addon); @@ -141,7 +150,11 @@ public void testStore() { @Test public void testIsWorldStored() { assertFalse(s.isWorldStored(player, world)); - s.storeInventory(player, world); + // Mock the static method + try (MockedStatic mockedBukkit = mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS)) { + // Run the code under test + s.storeInventory(player, world); + } assertTrue(s.isWorldStored(player, world)); } @@ -181,7 +194,14 @@ public void testStoreInventoryNothing() { sets.setHealth(false); sets.setInventory(false); sets.setStatistics(false); - s.storeInventory(player, world); + // Mock the static method + try (MockedStatic mockedBukkit = mockStatic(Bukkit.class)) { + // Run the code under test + s.storeInventory(player, world); + + // Verify that the static method was never called + mockedBukkit.verify(() -> Bukkit.advancementIterator(), never()); + } verify(player, never()).getInventory(); verify(player, never()).getEnderChest(); verify(player, never()).getFoodLevel(); @@ -190,8 +210,7 @@ public void testStoreInventoryNothing() { verify(player, never()).getHealth(); verify(player, never()).getGameMode(); verify(player, never()).getAdvancementProgress(any()); - PowerMockito.verifyStatic(Bukkit.class, never()); - Bukkit.advancementIterator(); + // No Player clearing verify(player, never()).setExp(anyFloat()); verify(player, never()).setLevel(anyInt()); @@ -216,7 +235,14 @@ public void testStoreInventoryAll() { sets.setHealth(true); sets.setInventory(true); sets.setStatistics(true); - s.storeInventory(player, world); + // Mock the static method + try (MockedStatic mockedBukkit = mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS)) { + // Run the code under test + s.storeInventory(player, world); + + // Verify that the static method was called + mockedBukkit.verify(() -> Bukkit.advancementIterator(), times(2)); + } verify(player, times(2)).getInventory(); verify(player, times(2)).getEnderChest(); verify(player).getFoodLevel(); @@ -224,8 +250,6 @@ public void testStoreInventoryAll() { verify(player, times(2)).getLevel(); verify(player).getHealth(); verify(player).getGameMode(); - PowerMockito.verifyStatic(Bukkit.class, times(2)); - Bukkit.advancementIterator(); // Player clearing verify(player).setExp(0); verify(player).setLevel(0); @@ -242,9 +266,14 @@ public void testStoreInventoryAll() { */ @Test public void testSaveOnlinePlayers() { - s.saveOnlinePlayers(); - PowerMockito.verifyStatic(Bukkit.class); - Bukkit.getOnlinePlayers(); + // Mock the static method + try (MockedStatic mockedBukkit = mockStatic(Bukkit.class)) { + // Run the code under test + s.saveOnlinePlayers(); + + // Verify that the static method was called + mockedBukkit.verify(() -> Bukkit.getOnlinePlayers()); + } } } diff --git a/src/test/java/com/wasteofplastic/invswitcher/dataobjects/InventoryStorageTest.java b/src/test/java/com/wasteofplastic/invswitcher/dataobjects/InventoryStorageTest.java index a0a39e8..fff1f4a 100644 --- a/src/test/java/com/wasteofplastic/invswitcher/dataobjects/InventoryStorageTest.java +++ b/src/test/java/com/wasteofplastic/invswitcher/dataobjects/InventoryStorageTest.java @@ -19,15 +19,16 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.powermock.modules.junit4.PowerMockRunner; +import org.mockito.junit.MockitoJUnitRunner; /** * @author tastybentos * */ -@RunWith(PowerMockRunner.class) +@RunWith(MockitoJUnitRunner.class) public class InventoryStorageTest { + private InventoryStorage is; /** diff --git a/src/test/java/com/wasteofplastic/invswitcher/listeners/PlayerListenerTest.java b/src/test/java/com/wasteofplastic/invswitcher/listeners/PlayerListenerTest.java index 04ff43b..901a30f 100644 --- a/src/test/java/com/wasteofplastic/invswitcher/listeners/PlayerListenerTest.java +++ b/src/test/java/com/wasteofplastic/invswitcher/listeners/PlayerListenerTest.java @@ -2,6 +2,7 @@ import static org.junit.Assert.assertNotNull; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mockStatic; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -17,10 +18,9 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; +import org.mockito.MockedStatic; import org.mockito.Mockito; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; +import org.mockito.junit.MockitoJUnitRunner; import com.wasteofplastic.invswitcher.InvSwitcher; import com.wasteofplastic.invswitcher.Store; @@ -31,8 +31,7 @@ * @author tastybento * */ -@RunWith(PowerMockRunner.class) -@PrepareForTest(Util.class) +@RunWith(MockitoJUnitRunner.class) public class PlayerListenerTest { @Mock @@ -52,8 +51,11 @@ public class PlayerListenerTest { @Before public void setUp() { // Util - PowerMockito.mockStatic(Util.class, Mockito.RETURNS_MOCKS); - when(Util.sameWorld(world, world)).thenReturn(true); + // Mock the static method + try (MockedStatic mockedBukkit = mockStatic(Util.class, Mockito.RETURNS_MOCKS)) { + when(Util.sameWorld(any(), any())).thenReturn(true); + } + when(world.getName()).thenReturn("world"); // Player when(player.getWorld()).thenReturn(world); // Addon @@ -87,9 +89,13 @@ public void testOnWorldEnterSameWorld() { @Test public void testOnWorldEnterDifferentWorld() { PlayerChangedWorldEvent event = new PlayerChangedWorldEvent(player, notWorld); - pl.onWorldEnter(event); - verify(store).storeInventory(any(), any()); - verify(store).getInventory(any(), any()); + // Mock the static method + try (MockedStatic mockedBukkit = mockStatic(Util.class, Mockito.RETURNS_MOCKS)) { + when(Util.sameWorld(world, world)).thenReturn(true); + pl.onWorldEnter(event); + verify(store).storeInventory(any(), any()); + verify(store).getInventory(any(), any()); + } } /**