Files
mcMMO/src/test/java/com/gmail/nossr50/events/items/McMMOModifyBlockDropItemEventTest.java

252 lines
9.1 KiB
Java

package com.gmail.nossr50.events.items;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.entity.Item;
import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList;
import org.bukkit.event.block.BlockDropItemEvent;
import org.bukkit.inventory.ItemStack;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
class McMMOModifyBlockDropItemEventTest {
private BlockDropItemEvent blockDropItemEvent;
private Item itemEntity;
private ItemStack itemStack;
private Player player;
private Block block;
private BlockState blockState;
@BeforeEach
void setUp() {
// Mocks for delegate passthroughs
player = mock(Player.class, RETURNS_DEEP_STUBS);
block = mock(Block.class, RETURNS_DEEP_STUBS);
blockState = mock(BlockState.class, RETURNS_DEEP_STUBS);
// Primary Bukkit event mock
blockDropItemEvent = mock(BlockDropItemEvent.class, RETURNS_DEEP_STUBS);
when(blockDropItemEvent.getPlayer()).thenReturn(player);
when(blockDropItemEvent.getBlock()).thenReturn(block);
when(blockDropItemEvent.getBlockState()).thenReturn(blockState);
// Item + ItemStack mock
itemStack = mock(ItemStack.class);
when(itemStack.getAmount()).thenReturn(3); // original count
itemEntity = mock(Item.class);
when(itemEntity.getItemStack()).thenReturn(itemStack);
}
private McMMOModifyBlockDropItemEvent newEvent(int bonus) {
return new McMMOModifyBlockDropItemEvent(blockDropItemEvent, itemEntity, bonus);
}
@Nested
@DisplayName("Constructor & validation")
class ConstructorValidation {
@Test
void ctorNullEventThrows() {
assertThrows(NullPointerException.class,
() -> new McMMOModifyBlockDropItemEvent(null, itemEntity, 1));
}
@Test
void ctorNullItemThrows() {
assertThrows(NullPointerException.class,
() -> new McMMOModifyBlockDropItemEvent(blockDropItemEvent, null, 1));
}
@Test
void ctorZeroBonusThrows() {
assertThrows(IllegalArgumentException.class,
() -> new McMMOModifyBlockDropItemEvent(blockDropItemEvent, itemEntity, 0));
}
@Test
void ctorNegativeBonusThrows() {
assertThrows(IllegalArgumentException.class,
() -> new McMMOModifyBlockDropItemEvent(blockDropItemEvent, itemEntity, -5));
}
@Test
void ctorSetsOriginalsAndModifiedCorrectly() {
// original amount = 3, bonus = 2
McMMOModifyBlockDropItemEvent ev = newEvent(2);
assertEquals(3, ev.getOriginalItemStackQuantity());
assertEquals(2, ev.getOriginalBonusAmountToAdd());
assertEquals(5, ev.getModifiedItemStackQuantity());
assertFalse(ev.isCancelled());
assertFalse(ev.isEffectivelyNoBonus());
}
}
@Nested
@DisplayName("Cancellable contract")
class Cancellation {
@Test
void cancelAndUncancel() {
McMMOModifyBlockDropItemEvent ev = newEvent(1);
assertFalse(ev.isCancelled());
ev.setCancelled(true);
assertTrue(ev.isCancelled());
ev.setCancelled(false);
assertFalse(ev.isCancelled());
}
}
@Nested
@DisplayName("Delta & absolute quantity semantics")
class DeltaAndAbsolute {
@Test
void getBonusAmountToAddReflectsDifferenceFromOriginal() {
// original 3, bonus 4 => modified 7
McMMOModifyBlockDropItemEvent ev = newEvent(4);
assertEquals(4, ev.getBonusAmountToAdd());
assertEquals(7, ev.getModifiedItemStackQuantity());
}
@Test
void setBonusAmountToAddUpdatesModifiedQuantity() {
McMMOModifyBlockDropItemEvent ev = newEvent(2); // original 3 -> modified 5
ev.setBonusAmountToAdd(10); // new modified should be 13
assertEquals(13, ev.getModifiedItemStackQuantity());
assertEquals(10, ev.getBonusAmountToAdd());
assertFalse(ev.isEffectivelyNoBonus());
}
@Test
void setBonusAmountToAddNegativeThrows() {
McMMOModifyBlockDropItemEvent ev = newEvent(1);
assertThrows(IllegalArgumentException.class, () -> ev.setBonusAmountToAdd(-1));
}
@Test
void setModifiedItemStackQuantityEqualToOriginalIsNoBonus() {
McMMOModifyBlockDropItemEvent ev = newEvent(2); // 3 -> 5
ev.setModifiedItemStackQuantity(3); // back to original => no bonus
assertEquals(3, ev.getModifiedItemStackQuantity());
assertEquals(0, ev.getBonusAmountToAdd());
assertTrue(ev.isEffectivelyNoBonus());
}
@Test
void setModifiedItemStackQuantityLessThanOriginalThrows() {
McMMOModifyBlockDropItemEvent ev = newEvent(1);
assertThrows(IllegalArgumentException.class, () -> ev.setModifiedItemStackQuantity(2)); // original is 3
}
@Test
void setModifiedItemStackQuantityGreaterThanOriginalUpdatesBonus() {
McMMOModifyBlockDropItemEvent ev = newEvent(1); // original 3 -> modified 4
ev.setModifiedItemStackQuantity(12);
assertEquals(12, ev.getModifiedItemStackQuantity());
assertEquals(9, ev.getBonusAmountToAdd()); // 12 - 3
assertFalse(ev.isEffectivelyNoBonus());
}
}
@Nested
@DisplayName("Delegate passthroughs")
class Delegates {
@Test
void getPlayerPassthrough() {
McMMOModifyBlockDropItemEvent ev = newEvent(1);
assertSame(player, ev.getPlayer());
verify(blockDropItemEvent, atLeastOnce()).getPlayer();
}
@Test
void getBlockPassthrough() {
McMMOModifyBlockDropItemEvent ev = newEvent(1);
assertSame(block, ev.getBlock());
verify(blockDropItemEvent, atLeastOnce()).getBlock();
}
@Test
void getBlockStatePassthrough() {
McMMOModifyBlockDropItemEvent ev = newEvent(1);
assertSame(blockState, ev.getBlockState());
verify(blockDropItemEvent, atLeastOnce()).getBlockState();
}
@Test
void getItemReturnsOriginalItemEntity() {
McMMOModifyBlockDropItemEvent ev = newEvent(1);
assertSame(itemEntity, ev.getItem());
}
}
@Nested
@DisplayName("HandlerList plumbing")
class HandlerListTests {
@Test
void handlerList_isNonNull_andShared() {
McMMOModifyBlockDropItemEvent ev = newEvent(1);
HandlerList fromInstance = ev.getHandlers();
HandlerList fromStatic = McMMOModifyBlockDropItemEvent.getHandlerList();
assertNotNull(fromInstance);
assertNotNull(fromStatic);
// Bukkit convention: same static instance
assertSame(fromStatic, fromInstance);
}
}
@Nested
@DisplayName("Object contracts")
class ObjectContracts {
@Test
void toStringContainsKeyFields() {
McMMOModifyBlockDropItemEvent ev = newEvent(2);
String s = ev.toString();
assertNotNull(s);
assertTrue(s.contains("originalBonusAmountToAdd=2"));
assertTrue(s.contains("modifiedItemStackQuantity=5"));
}
@Test
void equalsAndHashCodeReflectState() {
// Same inputs => equal (mocks are same instances)
McMMOModifyBlockDropItemEvent a = newEvent(2);
McMMOModifyBlockDropItemEvent b = newEvent(2);
assertEquals(a, b);
assertEquals(a.hashCode(), b.hashCode());
// Change cancellation and modified quantity => not equal
McMMOModifyBlockDropItemEvent c = newEvent(2);
c.setCancelled(true);
assertNotEquals(a, c);
McMMOModifyBlockDropItemEvent d = newEvent(2);
d.setModifiedItemStackQuantity(99);
assertNotEquals(a, d);
// Different underlying mocks => not equal
BlockDropItemEvent otherEvent = mock(BlockDropItemEvent.class, RETURNS_DEEP_STUBS);
when(otherEvent.getPlayer()).thenReturn(player);
when(otherEvent.getBlock()).thenReturn(block);
when(otherEvent.getBlockState()).thenReturn(blockState);
ItemStack otherStack = mock(ItemStack.class);
when(otherStack.getAmount()).thenReturn(3);
Item otherItem = mock(Item.class);
when(otherItem.getItemStack()).thenReturn(otherStack);
McMMOModifyBlockDropItemEvent e = new McMMOModifyBlockDropItemEvent(otherEvent, otherItem, 2);
assertNotEquals(a, e);
}
}
}