diff --git a/src/main/java/com/gmail/nossr50/config/experience/ExperienceConfig.java b/src/main/java/com/gmail/nossr50/config/experience/ExperienceConfig.java index 929fdcefe..6863c0e55 100644 --- a/src/main/java/com/gmail/nossr50/config/experience/ExperienceConfig.java +++ b/src/main/java/com/gmail/nossr50/config/experience/ExperienceConfig.java @@ -296,6 +296,10 @@ public class ExperienceConfig extends BukkitConfig { } /* Combat XP Multipliers */ + public double getCombatXP(String entity) { + return config.getDouble("Experience_Values.Combat.Multiplier." + entity); + } + public double getCombatXP(EntityType entity) { return config.getDouble("Experience_Values.Combat.Multiplier." + StringUtils.getPrettyEntityTypeString(entity).replace(" ", "_")); } @@ -314,96 +318,73 @@ public class ExperienceConfig extends BukkitConfig { /* Materials */ public int getXp(PrimarySkillType skill, Material material) { - //TODO: Temporary measure to fix an exploit caused by a yet to be fixed Spigot bug (as of 7/3/2020) - if (material.toString().equalsIgnoreCase("LILY_PAD")) - return 0; - - String baseString = "Experience_Values." + StringUtils.getCapitalized(skill.toString()) + "."; - String explicitString = baseString + StringUtils.getExplicitConfigMaterialString(material); - if (config.contains(explicitString)) - return config.getInt(explicitString); - String friendlyString = baseString + StringUtils.getFriendlyConfigMaterialString(material); - if (config.contains(friendlyString)) - return config.getInt(friendlyString); - String wildcardString = baseString + StringUtils.getWildcardConfigMaterialString(material); - if (config.contains(wildcardString)) - return config.getInt(wildcardString); - return 0; + return getXpHelper(skill, StringUtils.getExplicitConfigMaterialString(material), + StringUtils.getFriendlyConfigMaterialString(material), + StringUtils.getWildcardConfigMaterialString(material)); } - /* Materials */ public int getXp(PrimarySkillType skill, BlockState blockState) { - Material data = blockState.getType(); - - String baseString = "Experience_Values." + StringUtils.getCapitalized(skill.toString()) + "."; - String explicitString = baseString + StringUtils.getExplicitConfigMaterialString(data); - if (config.contains(explicitString)) - return config.getInt(explicitString); - String friendlyString = baseString + StringUtils.getFriendlyConfigMaterialString(data); - if (config.contains(friendlyString)) - return config.getInt(friendlyString); - String wildcardString = baseString + StringUtils.getWildcardConfigMaterialString(data); - if (config.contains(wildcardString)) - return config.getInt(wildcardString); - return 0; + Material material = blockState.getType(); + return getXp(skill, material); } - /* Materials */ public int getXp(PrimarySkillType skill, Block block) { - Material data = block.getType(); - - String baseString = "Experience_Values." + StringUtils.getCapitalized(skill.toString()) + "."; - String explicitString = baseString + StringUtils.getExplicitConfigMaterialString(data); - if (config.contains(explicitString)) - return config.getInt(explicitString); - String friendlyString = baseString + StringUtils.getFriendlyConfigMaterialString(data); - if (config.contains(friendlyString)) - return config.getInt(friendlyString); - String wildcardString = baseString + StringUtils.getWildcardConfigMaterialString(data); - if (config.contains(wildcardString)) - return config.getInt(wildcardString); - return 0; + Material material = block.getType(); + return getXp(skill, material); } - /* Materials */ public int getXp(PrimarySkillType skill, BlockData data) { + return getXpHelper(skill, StringUtils.getExplicitConfigBlockDataString(data), + StringUtils.getFriendlyConfigBlockDataString(data), + StringUtils.getWildcardConfigBlockDataString(data)); + } + + private int getXpHelper(PrimarySkillType skill, String explicitString, String friendlyString, String wildcardString) { + if (explicitString.equalsIgnoreCase("LILY_PAD")) { + return 0; + } + String baseString = "Experience_Values." + StringUtils.getCapitalized(skill.toString()) + "."; - String explicitString = baseString + StringUtils.getExplicitConfigBlockDataString(data); - if (config.contains(explicitString)) - return config.getInt(explicitString); - String friendlyString = baseString + StringUtils.getFriendlyConfigBlockDataString(data); - if (config.contains(friendlyString)) - return config.getInt(friendlyString); - String wildcardString = baseString + StringUtils.getWildcardConfigBlockDataString(data); - if (config.contains(wildcardString)) - return config.getInt(wildcardString); + String[] configStrings = {explicitString, friendlyString, wildcardString}; + + for (String configString : configStrings) { + String fullPath = baseString + configString; + if (config.contains(fullPath)) { + return config.getInt(fullPath); + } + } + return 0; } - public boolean doesBlockGiveSkillXP(PrimarySkillType skill, Material data) { - String baseString = "Experience_Values." + StringUtils.getCapitalized(skill.toString()) + "."; - String explicitString = baseString + StringUtils.getExplicitConfigMaterialString(data); - if (config.contains(explicitString)) - return true; - String friendlyString = baseString + StringUtils.getFriendlyConfigMaterialString(data); - if (config.contains(friendlyString)) - return true; - String wildcardString = baseString + StringUtils.getWildcardConfigMaterialString(data); - return config.contains(wildcardString); + + public boolean doesBlockGiveSkillXP(PrimarySkillType skill, Material material) { + return doesBlockGiveSkillXPHelper(skill, StringUtils.getExplicitConfigMaterialString(material), + StringUtils.getFriendlyConfigMaterialString(material), + StringUtils.getWildcardConfigMaterialString(material)); } public boolean doesBlockGiveSkillXP(PrimarySkillType skill, BlockData data) { - String baseString = "Experience_Values." + StringUtils.getCapitalized(skill.toString()) + "."; - String explicitString = baseString + StringUtils.getExplicitConfigBlockDataString(data); - if (config.contains(explicitString)) - return true; - String friendlyString = baseString + StringUtils.getFriendlyConfigBlockDataString(data); - if (config.contains(friendlyString)) - return true; - String wildcardString = baseString + StringUtils.getWildcardConfigBlockDataString(data); - return config.contains(wildcardString); + return doesBlockGiveSkillXPHelper(skill, StringUtils.getExplicitConfigBlockDataString(data), + StringUtils.getFriendlyConfigBlockDataString(data), + StringUtils.getWildcardConfigBlockDataString(data)); } + private boolean doesBlockGiveSkillXPHelper(PrimarySkillType skill, String explicitString, String friendlyString, String wildcardString) { + String baseString = "Experience_Values." + StringUtils.getCapitalized(skill.toString()) + "."; + String[] configStrings = {explicitString, friendlyString, wildcardString}; + + for (String configString : configStrings) { + String fullPath = baseString + configString; + if (config.contains(fullPath)) { + return true; + } + } + + return false; + } + + /* * Experience Bar Stuff */ diff --git a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java index 1427be479..6923c32be 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/CombatUtils.java @@ -17,7 +17,6 @@ import com.gmail.nossr50.runnables.skills.AwardCombatXpTask; import com.gmail.nossr50.skills.acrobatics.AcrobaticsManager; import com.gmail.nossr50.skills.archery.ArcheryManager; import com.gmail.nossr50.skills.axes.AxesManager; -import com.gmail.nossr50.skills.crossbows.CrossbowsManager; import com.gmail.nossr50.skills.swords.SwordsManager; import com.gmail.nossr50.skills.taming.TamingManager; import com.gmail.nossr50.skills.tridents.TridentsManager; diff --git a/src/main/java/com/gmail/nossr50/util/skills/RankUtils.java b/src/main/java/com/gmail/nossr50/util/skills/RankUtils.java index 822228435..4af318e9d 100644 --- a/src/main/java/com/gmail/nossr50/util/skills/RankUtils.java +++ b/src/main/java/com/gmail/nossr50/util/skills/RankUtils.java @@ -317,7 +317,6 @@ public class RankUtils { * @param rank The target rank * @return The level at which this rank unlocks */ - @Deprecated public static int getRankUnlockLevel(SubSkillType subSkillType, int rank) { return RankConfig.getInstance().getSubSkillUnlockLevel(subSkillType, rank); diff --git a/src/test/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManagerTest.java b/src/test/java/com/gmail/nossr50/MMOTestEnvironment.java similarity index 53% rename from src/test/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManagerTest.java rename to src/test/java/com/gmail/nossr50/MMOTestEnvironment.java index d27f54e5d..81e0f6094 100644 --- a/src/test/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingManagerTest.java +++ b/src/test/java/com/gmail/nossr50/MMOTestEnvironment.java @@ -1,18 +1,16 @@ -package com.gmail.nossr50.skills.woodcutting; +package com.gmail.nossr50; import com.gmail.nossr50.config.AdvancedConfig; import com.gmail.nossr50.config.ChatConfig; import com.gmail.nossr50.config.GeneralConfig; import com.gmail.nossr50.config.RankConfig; +import com.gmail.nossr50.config.experience.ExperienceConfig; import com.gmail.nossr50.datatypes.player.McMMOPlayer; import com.gmail.nossr50.datatypes.player.PlayerProfile; import com.gmail.nossr50.datatypes.skills.PrimarySkillType; import com.gmail.nossr50.datatypes.skills.SubSkillType; -import com.gmail.nossr50.mcMMO; -import com.gmail.nossr50.util.EventUtils; -import com.gmail.nossr50.util.Misc; -import com.gmail.nossr50.util.Permissions; -import com.gmail.nossr50.util.TransientEntityTracker; +import com.gmail.nossr50.util.*; +import com.gmail.nossr50.util.blockmeta.ChunkManager; import com.gmail.nossr50.util.player.UserManager; import com.gmail.nossr50.util.skills.RankUtils; import com.gmail.nossr50.util.skills.SkillTools; @@ -20,83 +18,78 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.Server; import org.bukkit.World; -import org.bukkit.block.Block; -import org.bukkit.block.BlockState; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; import org.bukkit.plugin.PluginManager; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; import org.mockito.MockedStatic; import org.mockito.Mockito; import java.util.UUID; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -class WoodcuttingManagerTest { - private static final java.util.logging.Logger logger = java.util.logging.Logger.getLogger(WoodcuttingManagerTest.class.getName()); - private MockedStatic mockedMcMMO; - private MockedStatic mockedChatConfig; - private MockedStatic mockedPermissions; - private MockedStatic mockedRankUtils; - private MockedStatic mockedUserManager; - private MockedStatic mockedMisc; - private MockedStatic mockedSkillTools; - private MockedStatic mockedEventUtils; - private TransientEntityTracker transientEntityTracker; - private AdvancedConfig advancedConfig; - private GeneralConfig generalConfig; - private RankConfig rankConfig; - private SkillTools skillTools; - private Server server; - private PluginManager pluginManager; - private World world; - - private WoodcuttingManager woodcuttingManager; +public abstract class MMOTestEnvironment { + private final java.util.logging.Logger logger = java.util.logging.Logger.getLogger(MMOTestEnvironment.class.getName()); + protected MockedStatic mockedMcMMO; + protected MockedStatic mockedChatConfig; + protected MockedStatic experienceConfig; + protected MockedStatic mockedPermissions; + protected MockedStatic mockedRankUtils; + protected MockedStatic mockedUserManager; + protected MockedStatic mockedMisc; + protected MockedStatic mockedSkillTools; + protected MockedStatic mockedEventUtils; + protected TransientEntityTracker transientEntityTracker; + protected AdvancedConfig advancedConfig; + protected GeneralConfig generalConfig; + protected RankConfig rankConfig; + protected SkillTools skillTools; + protected Server server; + protected PluginManager pluginManager; + protected World world; /* Mocks */ - Player player; + protected Player player; - UUID playerUUID = UUID.randomUUID(); - ItemStack itemInMainHand; + protected UUID playerUUID = UUID.randomUUID(); + protected ItemStack itemInMainHand; - PlayerInventory playerInventory; - PlayerProfile playerProfile; - McMMOPlayer mmoPlayer; - String playerName = "testPlayer"; + protected PlayerInventory playerInventory; + protected PlayerProfile playerProfile; + protected McMMOPlayer mmoPlayer; + protected String playerName = "testPlayer"; - @BeforeEach - void setUp() { + protected ChunkManager chunkManager; + + protected void mockBaseEnvironment() { mockedMcMMO = Mockito.mockStatic(mcMMO.class); mcMMO.p = Mockito.mock(mcMMO.class); Mockito.when(mcMMO.p.getLogger()).thenReturn(logger); + // place store + chunkManager = Mockito.mock(ChunkManager.class); + Mockito.when(mcMMO.getPlaceStore()).thenReturn(chunkManager); + + // shut off mod manager for woodcutting + Mockito.when(mcMMO.getModManager()).thenReturn(Mockito.mock(ModManager.class)); + Mockito.when(mcMMO.getModManager().isCustomLog(any())).thenReturn(false); + // chat config mockedChatConfig = Mockito.mockStatic(ChatConfig.class); Mockito.when(ChatConfig.getInstance()).thenReturn(Mockito.mock(ChatConfig.class)); // general config - generalConfig = Mockito.mock(GeneralConfig.class); - Mockito.when(generalConfig.getTreeFellerThreshold()).thenReturn(100); - Mockito.when(generalConfig.getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, Material.OAK_LOG)).thenReturn(true); - Mockito.when(generalConfig.getLocale()).thenReturn("en_US"); - Mockito.when(mcMMO.p.getGeneralConfig()).thenReturn(generalConfig); + mockGeneralConfig(); // rank config - rankConfig = Mockito.mock(RankConfig.class); - Mockito.when(rankConfig.getSubSkillUnlockLevel(SubSkillType.WOODCUTTING_HARVEST_LUMBER, 1)).thenReturn(1); + mockRankConfig(); // wire advanced config - this.advancedConfig = Mockito.mock(AdvancedConfig.class); - Mockito.when(advancedConfig.getMaximumProbability(SubSkillType.WOODCUTTING_HARVEST_LUMBER)).thenReturn(100D); - Mockito.when(advancedConfig.getMaximumProbability(SubSkillType.WOODCUTTING_CLEAN_CUTS)).thenReturn(10D); - Mockito.when(advancedConfig.getMaxBonusLevel(SubSkillType.WOODCUTTING_HARVEST_LUMBER)).thenReturn(1000); - Mockito.when(advancedConfig.getMaxBonusLevel(SubSkillType.WOODCUTTING_CLEAN_CUTS)).thenReturn(10000); - Mockito.when(mcMMO.p.getAdvancedConfig()).thenReturn(advancedConfig); + mockAdvancedConfig(); + + // wire experience config + mockExperienceConfig(); // wire skill tools this.skillTools = new SkillTools(mcMMO.p); @@ -105,18 +98,9 @@ class WoodcuttingManagerTest { this.transientEntityTracker = new TransientEntityTracker(); Mockito.when(mcMMO.getTransientEntityTracker()).thenReturn(transientEntityTracker); - mockedPermissions = Mockito.mockStatic(Permissions.class); - Mockito.when(Permissions.isSubSkillEnabled(any(Player.class), any(SubSkillType.class))).thenReturn(true); - Mockito.when(Permissions.canUseSubSkill(any(Player.class), any(SubSkillType.class))).thenReturn(true); - Mockito.when(Permissions.isSubSkillEnabled(any(Player.class), any(SubSkillType.class))).thenReturn(true); - Mockito.when(Permissions.canUseSubSkill(any(Player.class), any(SubSkillType.class))).thenReturn(true); - Mockito.when(Permissions.lucky(player, PrimarySkillType.WOODCUTTING)).thenReturn(false); // player is not lucky + mockPermissions(); mockedRankUtils = Mockito.mockStatic(RankUtils.class); - Mockito.when(RankUtils.getRankUnlockLevel(SubSkillType.WOODCUTTING_HARVEST_LUMBER, 1)).thenReturn(1); // needed? - Mockito.when(RankUtils.getRankUnlockLevel(SubSkillType.WOODCUTTING_CLEAN_CUTS, 1)).thenReturn(1000); // needed? - Mockito.when(RankUtils.hasReachedRank(eq(1), any(Player.class), eq(SubSkillType.WOODCUTTING_HARVEST_LUMBER))).thenReturn(true); - Mockito.when(RankUtils.hasReachedRank(eq(1), any(Player.class), eq(SubSkillType.WOODCUTTING_CLEAN_CUTS))).thenReturn(true); // wire server this.server = Mockito.mock(Server.class); @@ -139,9 +123,7 @@ class WoodcuttingManagerTest { // wire inventory this.playerInventory = Mockito.mock(PlayerInventory.class); - this.itemInMainHand = new ItemStack(Material.DIAMOND_AXE); Mockito.when(player.getInventory()).thenReturn(playerInventory); - Mockito.when(playerInventory.getItemInMainHand()).thenReturn(itemInMainHand); // PlayerProfile and McMMOPlayer are partially mocked playerProfile = new PlayerProfile("testPlayer", player.getUniqueId(), 0); @@ -150,17 +132,51 @@ class WoodcuttingManagerTest { // wire user manager this.mockedUserManager = Mockito.mockStatic(UserManager.class); Mockito.when(UserManager.getPlayer(player)).thenReturn(mmoPlayer); - - // Set up spy for WoodcuttingManager - woodcuttingManager = Mockito.spy(new WoodcuttingManager(mmoPlayer)); } - @AfterEach - void tearDown() { + private void mockPermissions() { + mockedPermissions = Mockito.mockStatic(Permissions.class); + Mockito.when(Permissions.isSubSkillEnabled(any(Player.class), any(SubSkillType.class))).thenReturn(true); + Mockito.when(Permissions.canUseSubSkill(any(Player.class), any(SubSkillType.class))).thenReturn(true); + Mockito.when(Permissions.isSubSkillEnabled(any(Player.class), any(SubSkillType.class))).thenReturn(true); + Mockito.when(Permissions.canUseSubSkill(any(Player.class), any(SubSkillType.class))).thenReturn(true); + Mockito.when(Permissions.lucky(player, PrimarySkillType.WOODCUTTING)).thenReturn(false); // player is not lucky + } + + private void mockRankConfig() { + rankConfig = Mockito.mock(RankConfig.class); + } + + private void mockAdvancedConfig() { + this.advancedConfig = Mockito.mock(AdvancedConfig.class); + Mockito.when(mcMMO.p.getAdvancedConfig()).thenReturn(advancedConfig); + } + + private void mockGeneralConfig() { + generalConfig = Mockito.mock(GeneralConfig.class); + Mockito.when(generalConfig.getTreeFellerThreshold()).thenReturn(100); + Mockito.when(generalConfig.getDoubleDropsEnabled(PrimarySkillType.WOODCUTTING, Material.OAK_LOG)).thenReturn(true); + Mockito.when(generalConfig.getLocale()).thenReturn("en_US"); + Mockito.when(mcMMO.p.getGeneralConfig()).thenReturn(generalConfig); + } + + private void mockExperienceConfig() { + experienceConfig = Mockito.mockStatic(ExperienceConfig.class); + + Mockito.when(ExperienceConfig.getInstance()).thenReturn(Mockito.mock(ExperienceConfig.class)); + + // Combat + Mockito.when(ExperienceConfig.getInstance().getCombatXP("Cow")).thenReturn(1D); + } + + protected void cleanupBaseEnvironment() { // Clean up resources here if needed. if (mockedMcMMO != null) { mockedMcMMO.close(); } + if (experienceConfig != null) { + experienceConfig.close(); + } if (mockedChatConfig != null) { mockedChatConfig.close(); } @@ -180,39 +196,4 @@ class WoodcuttingManagerTest { mockedEventUtils.close(); } } - - @Test - void harvestLumberShouldDoubleDrop() { - mmoPlayer.modifySkill(PrimarySkillType.WOODCUTTING, 1000); - - BlockState blockState = Mockito.mock(BlockState.class); - Block block = Mockito.mock(Block.class); - // wire block - Mockito.when(blockState.getBlock()).thenReturn(block); - - Mockito.when(blockState.getBlock().getDrops(any())).thenReturn(null); - Mockito.when(blockState.getType()).thenReturn(Material.OAK_LOG); - woodcuttingManager.processBonusDropCheck(blockState); - - // verify bonus drops were spawned - Mockito.verify(woodcuttingManager, Mockito.times(1)).spawnHarvestLumberBonusDrops(blockState); - } - - - @Test - void harvestLumberShouldNotDoubleDrop() { - mmoPlayer.modifySkill(PrimarySkillType.WOODCUTTING, 0); - - BlockState blockState = Mockito.mock(BlockState.class); - Block block = Mockito.mock(Block.class); - // wire block - Mockito.when(blockState.getBlock()).thenReturn(block); - - Mockito.when(blockState.getBlock().getDrops(any())).thenReturn(null); - Mockito.when(blockState.getType()).thenReturn(Material.OAK_LOG); - woodcuttingManager.processBonusDropCheck(blockState); - - // verify bonus drops were not spawned - Mockito.verify(woodcuttingManager, Mockito.times(0)).spawnHarvestLumberBonusDrops(blockState); - } } diff --git a/src/test/java/com/gmail/nossr50/skills/tridents/TridentsTest.java b/src/test/java/com/gmail/nossr50/skills/tridents/TridentsTest.java new file mode 100644 index 000000000..194770f77 --- /dev/null +++ b/src/test/java/com/gmail/nossr50/skills/tridents/TridentsTest.java @@ -0,0 +1,38 @@ +package com.gmail.nossr50.skills.tridents; + +import com.gmail.nossr50.MMOTestEnvironment; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.mockito.Mockito; + +class TridentsTest extends MMOTestEnvironment { + private static final java.util.logging.Logger logger = java.util.logging.Logger.getLogger(TridentsTest.class.getName()); + + TridentsManager tridentsManager; + ItemStack trident; + @BeforeEach + void setUp() { + mockBaseEnvironment(); + + // setup player and player related mocks after everything else + this.player = Mockito.mock(Player.class); + Mockito.when(player.getUniqueId()).thenReturn(playerUUID); + + // wire inventory + this.playerInventory = Mockito.mock(PlayerInventory.class); + this.trident = new ItemStack(Material.TRIDENT); + Mockito.when(playerInventory.getItemInMainHand()).thenReturn(trident); + + // Set up spy for manager + tridentsManager = Mockito.spy(new TridentsManager(mmoPlayer)); + } + + @AfterEach + void tearDown() { + cleanupBaseEnvironment(); + } +} diff --git a/src/test/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingTest.java b/src/test/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingTest.java new file mode 100644 index 000000000..1de25cc71 --- /dev/null +++ b/src/test/java/com/gmail/nossr50/skills/woodcutting/WoodcuttingTest.java @@ -0,0 +1,107 @@ +package com.gmail.nossr50.skills.woodcutting; + +import com.gmail.nossr50.MMOTestEnvironment; +import com.gmail.nossr50.config.experience.ExperienceConfig; +import com.gmail.nossr50.datatypes.skills.PrimarySkillType; +import com.gmail.nossr50.datatypes.skills.SubSkillType; +import com.gmail.nossr50.util.skills.RankUtils; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockState; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; + +class WoodcuttingTest extends MMOTestEnvironment { + private static final java.util.logging.Logger logger = java.util.logging.Logger.getLogger(WoodcuttingTest.class.getName()); + + WoodcuttingManager woodcuttingManager; + @BeforeEach + void setUp() { + mockBaseEnvironment(); + Mockito.when(rankConfig.getSubSkillUnlockLevel(SubSkillType.WOODCUTTING_HARVEST_LUMBER, 1)).thenReturn(1); + + // wire advanced config + Mockito.when(advancedConfig.getMaximumProbability(SubSkillType.WOODCUTTING_HARVEST_LUMBER)).thenReturn(100D); + Mockito.when(advancedConfig.getMaximumProbability(SubSkillType.WOODCUTTING_CLEAN_CUTS)).thenReturn(10D); + Mockito.when(advancedConfig.getMaxBonusLevel(SubSkillType.WOODCUTTING_HARVEST_LUMBER)).thenReturn(1000); + Mockito.when(advancedConfig.getMaxBonusLevel(SubSkillType.WOODCUTTING_CLEAN_CUTS)).thenReturn(10000); + + Mockito.when(RankUtils.getRankUnlockLevel(SubSkillType.WOODCUTTING_HARVEST_LUMBER, 1)).thenReturn(1); // needed? + Mockito.when(RankUtils.getRankUnlockLevel(SubSkillType.WOODCUTTING_CLEAN_CUTS, 1)).thenReturn(1000); // needed? + Mockito.when(RankUtils.hasReachedRank(eq(1), any(Player.class), eq(SubSkillType.WOODCUTTING_HARVEST_LUMBER))).thenReturn(true); + Mockito.when(RankUtils.hasReachedRank(eq(1), any(Player.class), eq(SubSkillType.WOODCUTTING_CLEAN_CUTS))).thenReturn(true); + + // setup player and player related mocks after everything else + this.player = Mockito.mock(Player.class); + Mockito.when(player.getUniqueId()).thenReturn(playerUUID); + + // wire inventory + this.playerInventory = Mockito.mock(PlayerInventory.class); + this.itemInMainHand = new ItemStack(Material.DIAMOND_AXE); + Mockito.when(player.getInventory()).thenReturn(playerInventory); + Mockito.when(playerInventory.getItemInMainHand()).thenReturn(itemInMainHand); + + // Set up spy for WoodcuttingManager + woodcuttingManager = Mockito.spy(new WoodcuttingManager(mmoPlayer)); + } + + @AfterEach + void tearDown() { + cleanupBaseEnvironment(); + } + + @Test + void harvestLumberShouldDoubleDrop() { + mmoPlayer.modifySkill(PrimarySkillType.WOODCUTTING, 1000); + + BlockState blockState = Mockito.mock(BlockState.class); + Block block = Mockito.mock(Block.class); + // wire block + Mockito.when(blockState.getBlock()).thenReturn(block); + + Mockito.when(blockState.getBlock().getDrops(any())).thenReturn(null); + Mockito.when(blockState.getType()).thenReturn(Material.OAK_LOG); + woodcuttingManager.processBonusDropCheck(blockState); + + // verify bonus drops were spawned + Mockito.verify(woodcuttingManager, Mockito.times(1)).spawnHarvestLumberBonusDrops(blockState); + } + + + @Test + void harvestLumberShouldNotDoubleDrop() { + mmoPlayer.modifySkill(PrimarySkillType.WOODCUTTING, 0); + + BlockState blockState = Mockito.mock(BlockState.class); + Block block = Mockito.mock(Block.class); + // wire block + Mockito.when(blockState.getBlock()).thenReturn(block); + + Mockito.when(blockState.getBlock().getDrops(any())).thenReturn(null); + Mockito.when(blockState.getType()).thenReturn(Material.OAK_LOG); + woodcuttingManager.processBonusDropCheck(blockState); + + // verify bonus drops were not spawned + Mockito.verify(woodcuttingManager, Mockito.times(0)).spawnHarvestLumberBonusDrops(blockState); + } + + @Test + void testProcessWoodcuttingBlockXP() { + BlockState targetBlock = Mockito.mock(BlockState.class); + Mockito.when(targetBlock.getType()).thenReturn(Material.OAK_LOG); + // wire XP + Mockito.when(ExperienceConfig.getInstance().getXp(PrimarySkillType.WOODCUTTING, Material.OAK_LOG)).thenReturn(5); + + // Verify XP increased by 5 when processing XP + woodcuttingManager.processWoodcuttingBlockXP(targetBlock); + Mockito.verify(mmoPlayer, Mockito.times(1)).beginXpGain(eq(PrimarySkillType.WOODCUTTING), eq(5F), any(), any()); + } +}