diff --git a/src/test/java/us/eunoians/mcrpg/event/quest/QuestRewardGrantEventTest.java b/src/test/java/us/eunoians/mcrpg/event/quest/QuestRewardGrantEventTest.java new file mode 100644 index 000000000..32700b59f --- /dev/null +++ b/src/test/java/us/eunoians/mcrpg/event/quest/QuestRewardGrantEventTest.java @@ -0,0 +1,147 @@ +package us.eunoians.mcrpg.event.quest; + +import org.bukkit.NamespacedKey; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; +import us.eunoians.mcrpg.quest.impl.QuestInstance; +import us.eunoians.mcrpg.quest.reward.QuestRewardType; +import us.eunoians.mcrpg.quest.reward.RewardGrantContext; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; + +class QuestRewardGrantEventTest { + + @Test + @DisplayName("Getters return values passed to the constructor") + void getters_returnConstructorValues() { + QuestInstance questInstance = mock(QuestInstance.class); + NamespacedKey questKey = new NamespacedKey("mcrpg", "test_quest"); + UUID playerUUID = UUID.randomUUID(); + List rewards = new ArrayList<>(); + rewards.add(mock(QuestRewardType.class)); + RewardGrantContext context = RewardGrantContext.INLINE; + + QuestRewardGrantEvent event = new QuestRewardGrantEvent( + questInstance, questKey, playerUUID, rewards, context); + + assertSame(questInstance, event.getQuestInstance()); + assertEquals(questKey, event.getQuestKey()); + assertEquals(playerUUID, event.getPlayerUUID()); + assertSame(rewards, event.getRewards()); + assertEquals(context, event.getContext()); + } + + @Test + @DisplayName("Null quest instance is returned when not tied to a live instance") + void nullQuestInstance_returnsNull() { + NamespacedKey questKey = new NamespacedKey("mcrpg", "test_quest"); + UUID playerUUID = UUID.randomUUID(); + List rewards = new ArrayList<>(); + + QuestRewardGrantEvent event = new QuestRewardGrantEvent( + null, questKey, playerUUID, rewards, RewardGrantContext.PENDING); + + assertNull(event.getQuestInstance()); + } + + @Test + @DisplayName("Event defaults to not cancelled") + void event_defaultsNotCancelled() { + NamespacedKey questKey = new NamespacedKey("mcrpg", "test_quest"); + UUID playerUUID = UUID.randomUUID(); + List rewards = new ArrayList<>(); + + QuestRewardGrantEvent event = new QuestRewardGrantEvent( + null, questKey, playerUUID, rewards, RewardGrantContext.INLINE); + + assertFalse(event.isCancelled()); + } + + @Test + @DisplayName("setCancelled toggles cancellation state") + void setCancelled_togglesState() { + NamespacedKey questKey = new NamespacedKey("mcrpg", "test_quest"); + UUID playerUUID = UUID.randomUUID(); + List rewards = new ArrayList<>(); + + QuestRewardGrantEvent event = new QuestRewardGrantEvent( + null, questKey, playerUUID, rewards, RewardGrantContext.INLINE); + + event.setCancelled(true); + assertTrue(event.isCancelled()); + + event.setCancelled(false); + assertFalse(event.isCancelled()); + } + + @Test + @DisplayName("Reward list is mutable — listeners can add entries") + void rewardList_isMutable() { + NamespacedKey questKey = new NamespacedKey("mcrpg", "test_quest"); + UUID playerUUID = UUID.randomUUID(); + List rewards = new ArrayList<>(); + + QuestRewardGrantEvent event = new QuestRewardGrantEvent( + null, questKey, playerUUID, rewards, RewardGrantContext.INLINE); + + QuestRewardType mockReward = mock(QuestRewardType.class); + event.getRewards().add(mockReward); + + assertEquals(1, event.getRewards().size()); + assertSame(mockReward, event.getRewards().getFirst()); + } + + @Test + @DisplayName("Reward list is mutable — listeners can remove entries") + void rewardList_canRemoveEntries() { + NamespacedKey questKey = new NamespacedKey("mcrpg", "test_quest"); + UUID playerUUID = UUID.randomUUID(); + QuestRewardType mockReward = mock(QuestRewardType.class); + List rewards = new ArrayList<>(List.of(mockReward)); + + QuestRewardGrantEvent event = new QuestRewardGrantEvent( + null, questKey, playerUUID, rewards, RewardGrantContext.DISTRIBUTION); + + event.getRewards().clear(); + + assertTrue(event.getRewards().isEmpty()); + } + + @ParameterizedTest + @EnumSource(RewardGrantContext.class) + @DisplayName("Each RewardGrantContext is correctly stored and returned") + void context_allValues_returnedCorrectly(RewardGrantContext context) { + NamespacedKey questKey = new NamespacedKey("mcrpg", "test_quest"); + UUID playerUUID = UUID.randomUUID(); + List rewards = new ArrayList<>(); + + QuestRewardGrantEvent event = new QuestRewardGrantEvent( + null, questKey, playerUUID, rewards, context); + + assertEquals(context, event.getContext()); + } + + @Test + @DisplayName("getHandlers and getHandlerList return the same HandlerList") + void handlers_returnStaticHandlerList() { + NamespacedKey questKey = new NamespacedKey("mcrpg", "test_quest"); + UUID playerUUID = UUID.randomUUID(); + List rewards = new ArrayList<>(); + + QuestRewardGrantEvent event = new QuestRewardGrantEvent( + null, questKey, playerUUID, rewards, RewardGrantContext.INLINE); + + assertSame(QuestRewardGrantEvent.getHandlerList(), event.getHandlers()); + } +} diff --git a/src/test/java/us/eunoians/mcrpg/event/quest/QuestRewardGrantedEventTest.java b/src/test/java/us/eunoians/mcrpg/event/quest/QuestRewardGrantedEventTest.java new file mode 100644 index 000000000..e86410881 --- /dev/null +++ b/src/test/java/us/eunoians/mcrpg/event/quest/QuestRewardGrantedEventTest.java @@ -0,0 +1,116 @@ +package us.eunoians.mcrpg.event.quest; + +import org.bukkit.NamespacedKey; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; +import us.eunoians.mcrpg.quest.impl.QuestInstance; +import us.eunoians.mcrpg.quest.reward.QuestRewardType; +import us.eunoians.mcrpg.quest.reward.RewardGrantContext; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.mock; + +class QuestRewardGrantedEventTest { + + @Test + @DisplayName("Getters return values passed to the constructor") + void getters_returnConstructorValues() { + QuestInstance questInstance = mock(QuestInstance.class); + NamespacedKey questKey = new NamespacedKey("mcrpg", "test_quest"); + UUID playerUUID = UUID.randomUUID(); + QuestRewardType mockReward = mock(QuestRewardType.class); + List rewards = List.of(mockReward); + RewardGrantContext context = RewardGrantContext.INLINE; + + QuestRewardGrantedEvent event = new QuestRewardGrantedEvent( + questInstance, questKey, playerUUID, rewards, context); + + assertSame(questInstance, event.getQuestInstance()); + assertEquals(questKey, event.getQuestKey()); + assertEquals(playerUUID, event.getPlayerUUID()); + assertEquals(1, event.getGrantedRewards().size()); + assertSame(mockReward, event.getGrantedRewards().getFirst()); + assertEquals(context, event.getContext()); + } + + @Test + @DisplayName("Null quest instance is returned when not tied to a live instance") + void nullQuestInstance_returnsNull() { + NamespacedKey questKey = new NamespacedKey("mcrpg", "test_quest"); + UUID playerUUID = UUID.randomUUID(); + List rewards = new ArrayList<>(); + + QuestRewardGrantedEvent event = new QuestRewardGrantedEvent( + null, questKey, playerUUID, rewards, RewardGrantContext.PENDING); + + assertNull(event.getQuestInstance()); + } + + @Test + @DisplayName("Granted rewards list is immutable (List.copyOf)") + void grantedRewards_isImmutable() { + NamespacedKey questKey = new NamespacedKey("mcrpg", "test_quest"); + UUID playerUUID = UUID.randomUUID(); + QuestRewardType mockReward = mock(QuestRewardType.class); + List rewards = new ArrayList<>(List.of(mockReward)); + + QuestRewardGrantedEvent event = new QuestRewardGrantedEvent( + null, questKey, playerUUID, rewards, RewardGrantContext.INLINE); + + assertThrows(UnsupportedOperationException.class, + () -> event.getGrantedRewards().add(mock(QuestRewardType.class))); + } + + @Test + @DisplayName("Modifying the source list after construction does not affect the event") + void grantedRewards_defensiveCopy() { + NamespacedKey questKey = new NamespacedKey("mcrpg", "test_quest"); + UUID playerUUID = UUID.randomUUID(); + QuestRewardType mockReward = mock(QuestRewardType.class); + List rewards = new ArrayList<>(List.of(mockReward)); + + QuestRewardGrantedEvent event = new QuestRewardGrantedEvent( + null, questKey, playerUUID, rewards, RewardGrantContext.DISTRIBUTION); + + rewards.clear(); + + assertEquals(1, event.getGrantedRewards().size()); + assertSame(mockReward, event.getGrantedRewards().getFirst()); + } + + @ParameterizedTest + @EnumSource(RewardGrantContext.class) + @DisplayName("Each RewardGrantContext is correctly stored and returned") + void context_allValues_returnedCorrectly(RewardGrantContext context) { + NamespacedKey questKey = new NamespacedKey("mcrpg", "test_quest"); + UUID playerUUID = UUID.randomUUID(); + List rewards = new ArrayList<>(); + + QuestRewardGrantedEvent event = new QuestRewardGrantedEvent( + null, questKey, playerUUID, rewards, context); + + assertEquals(context, event.getContext()); + } + + @Test + @DisplayName("getHandlers and getHandlerList return the same HandlerList") + void handlers_returnStaticHandlerList() { + NamespacedKey questKey = new NamespacedKey("mcrpg", "test_quest"); + UUID playerUUID = UUID.randomUUID(); + List rewards = new ArrayList<>(); + + QuestRewardGrantedEvent event = new QuestRewardGrantedEvent( + null, questKey, playerUUID, rewards, RewardGrantContext.INLINE); + + assertSame(QuestRewardGrantedEvent.getHandlerList(), event.getHandlers()); + } +} diff --git a/src/test/java/us/eunoians/mcrpg/event/quest/chain/QuestChainAbandonEventTest.java b/src/test/java/us/eunoians/mcrpg/event/quest/chain/QuestChainAbandonEventTest.java new file mode 100644 index 000000000..62090f4db --- /dev/null +++ b/src/test/java/us/eunoians/mcrpg/event/quest/chain/QuestChainAbandonEventTest.java @@ -0,0 +1,63 @@ +package us.eunoians.mcrpg.event.quest.chain; + +import org.bukkit.NamespacedKey; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockbukkit.mockbukkit.entity.PlayerMock; +import us.eunoians.mcrpg.McRPGBaseTest; +import us.eunoians.mcrpg.quest.chain.QuestChainDefinition; +import us.eunoians.mcrpg.quest.chain.QuestChainStep; + +import java.util.List; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; + +class QuestChainAbandonEventTest extends McRPGBaseTest { + + private static QuestChainDefinition buildDefinition() { + NamespacedKey chainKey = new NamespacedKey("mcrpg", "test_chain"); + NamespacedKey sourceKey = new NamespacedKey("mcrpg", "manual"); + NamespacedKey triggerKey = new NamespacedKey("mcrpg", "manual"); + List steps = List.of(QuestChainStep.simple(new NamespacedKey("mcrpg", "quest_one"))); + return new QuestChainDefinition.Builder(chainKey, sourceKey, triggerKey, steps).build(); + } + + @Test + @DisplayName("Getters return values passed to the constructor") + void getters_returnConstructorValues() { + QuestChainDefinition definition = buildDefinition(); + PlayerMock player = server.addPlayer(); + + QuestChainAbandonEvent event = new QuestChainAbandonEvent(definition, player, player.getUniqueId()); + + assertSame(definition, event.getChainDefinition()); + assertSame(player, event.getPlayer()); + assertEquals(player.getUniqueId(), event.getPlayerUUID()); + } + + @Test + @DisplayName("Null player is returned when constructed with offline player") + void nullPlayer_returnsNull() { + QuestChainDefinition definition = buildDefinition(); + UUID offlineUUID = UUID.randomUUID(); + + QuestChainAbandonEvent event = new QuestChainAbandonEvent(definition, null, offlineUUID); + + assertNull(event.getPlayer()); + assertEquals(offlineUUID, event.getPlayerUUID()); + } + + @Test + @DisplayName("getHandlers and getHandlerList return the same HandlerList") + void handlers_returnStaticHandlerList() { + QuestChainDefinition definition = buildDefinition(); + PlayerMock player = server.addPlayer(); + + QuestChainAbandonEvent event = new QuestChainAbandonEvent(definition, player, player.getUniqueId()); + + assertSame(QuestChainAbandonEvent.getHandlerList(), event.getHandlers()); + } +} diff --git a/src/test/java/us/eunoians/mcrpg/event/quest/chain/QuestChainExpireEventTest.java b/src/test/java/us/eunoians/mcrpg/event/quest/chain/QuestChainExpireEventTest.java new file mode 100644 index 000000000..bf79f6a8b --- /dev/null +++ b/src/test/java/us/eunoians/mcrpg/event/quest/chain/QuestChainExpireEventTest.java @@ -0,0 +1,91 @@ +package us.eunoians.mcrpg.event.quest.chain; + +import org.bukkit.NamespacedKey; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockbukkit.mockbukkit.entity.PlayerMock; +import us.eunoians.mcrpg.McRPGBaseTest; +import us.eunoians.mcrpg.quest.chain.QuestChainDefinition; +import us.eunoians.mcrpg.quest.chain.QuestChainStep; + +import java.util.List; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class QuestChainExpireEventTest extends McRPGBaseTest { + + private static QuestChainDefinition buildDefinition() { + NamespacedKey chainKey = new NamespacedKey("mcrpg", "expire_chain"); + NamespacedKey sourceKey = new NamespacedKey("mcrpg", "manual"); + NamespacedKey triggerKey = new NamespacedKey("mcrpg", "manual"); + List steps = List.of(QuestChainStep.simple(new NamespacedKey("mcrpg", "quest_one"))); + return new QuestChainDefinition.Builder(chainKey, sourceKey, triggerKey, steps).build(); + } + + @Test + @DisplayName("Getters return values passed to the constructor") + void getters_returnConstructorValues() { + QuestChainDefinition definition = buildDefinition(); + PlayerMock player = server.addPlayer(); + + QuestChainExpireEvent event = new QuestChainExpireEvent(definition, player.getUniqueId(), player); + + assertSame(definition, event.getChainDefinition()); + assertEquals(player.getUniqueId(), event.getPlayerUUID()); + assertTrue(event.getPlayer().isPresent()); + assertSame(player, event.getPlayer().get()); + } + + @Test + @DisplayName("getPlayer returns empty Optional when constructed with null player") + void nullPlayer_returnsEmptyOptional() { + QuestChainDefinition definition = buildDefinition(); + UUID offlineUUID = UUID.randomUUID(); + + QuestChainExpireEvent event = new QuestChainExpireEvent(definition, offlineUUID, null); + + assertTrue(event.getPlayer().isEmpty()); + assertEquals(offlineUUID, event.getPlayerUUID()); + } + + @Test + @DisplayName("Event defaults to not cancelled") + void event_defaultsNotCancelled() { + QuestChainDefinition definition = buildDefinition(); + PlayerMock player = server.addPlayer(); + + QuestChainExpireEvent event = new QuestChainExpireEvent(definition, player.getUniqueId(), player); + + assertFalse(event.isCancelled()); + } + + @Test + @DisplayName("setCancelled toggles cancellation state") + void setCancelled_togglesState() { + QuestChainDefinition definition = buildDefinition(); + PlayerMock player = server.addPlayer(); + + QuestChainExpireEvent event = new QuestChainExpireEvent(definition, player.getUniqueId(), player); + + event.setCancelled(true); + assertTrue(event.isCancelled()); + + event.setCancelled(false); + assertFalse(event.isCancelled()); + } + + @Test + @DisplayName("getHandlers and getHandlerList return the same HandlerList") + void handlers_returnStaticHandlerList() { + QuestChainDefinition definition = buildDefinition(); + PlayerMock player = server.addPlayer(); + + QuestChainExpireEvent event = new QuestChainExpireEvent(definition, player.getUniqueId(), player); + + assertSame(QuestChainExpireEvent.getHandlerList(), event.getHandlers()); + } +} diff --git a/src/test/java/us/eunoians/mcrpg/event/quest/chain/QuestChainFailEventTest.java b/src/test/java/us/eunoians/mcrpg/event/quest/chain/QuestChainFailEventTest.java new file mode 100644 index 000000000..cb01dce44 --- /dev/null +++ b/src/test/java/us/eunoians/mcrpg/event/quest/chain/QuestChainFailEventTest.java @@ -0,0 +1,63 @@ +package us.eunoians.mcrpg.event.quest.chain; + +import org.bukkit.NamespacedKey; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockbukkit.mockbukkit.entity.PlayerMock; +import us.eunoians.mcrpg.McRPGBaseTest; +import us.eunoians.mcrpg.quest.chain.QuestChainDefinition; +import us.eunoians.mcrpg.quest.chain.QuestChainStep; + +import java.util.List; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; + +class QuestChainFailEventTest extends McRPGBaseTest { + + private static QuestChainDefinition buildDefinition() { + NamespacedKey chainKey = new NamespacedKey("mcrpg", "fail_chain"); + NamespacedKey sourceKey = new NamespacedKey("mcrpg", "manual"); + NamespacedKey triggerKey = new NamespacedKey("mcrpg", "manual"); + List steps = List.of(QuestChainStep.simple(new NamespacedKey("mcrpg", "quest_one"))); + return new QuestChainDefinition.Builder(chainKey, sourceKey, triggerKey, steps).build(); + } + + @Test + @DisplayName("Getters return values passed to the constructor") + void getters_returnConstructorValues() { + QuestChainDefinition definition = buildDefinition(); + PlayerMock player = server.addPlayer(); + + QuestChainFailEvent event = new QuestChainFailEvent(definition, player, player.getUniqueId()); + + assertSame(definition, event.getChainDefinition()); + assertSame(player, event.getPlayer()); + assertEquals(player.getUniqueId(), event.getPlayerUUID()); + } + + @Test + @DisplayName("Null player is returned when constructed for offline player") + void nullPlayer_returnsNull() { + QuestChainDefinition definition = buildDefinition(); + UUID offlineUUID = UUID.randomUUID(); + + QuestChainFailEvent event = new QuestChainFailEvent(definition, null, offlineUUID); + + assertNull(event.getPlayer()); + assertEquals(offlineUUID, event.getPlayerUUID()); + } + + @Test + @DisplayName("getHandlers and getHandlerList return the same HandlerList") + void handlers_returnStaticHandlerList() { + QuestChainDefinition definition = buildDefinition(); + PlayerMock player = server.addPlayer(); + + QuestChainFailEvent event = new QuestChainFailEvent(definition, player, player.getUniqueId()); + + assertSame(QuestChainFailEvent.getHandlerList(), event.getHandlers()); + } +} diff --git a/src/test/java/us/eunoians/mcrpg/event/quest/chain/QuestChainRestartEventTest.java b/src/test/java/us/eunoians/mcrpg/event/quest/chain/QuestChainRestartEventTest.java new file mode 100644 index 000000000..06a81b8d7 --- /dev/null +++ b/src/test/java/us/eunoians/mcrpg/event/quest/chain/QuestChainRestartEventTest.java @@ -0,0 +1,82 @@ +package us.eunoians.mcrpg.event.quest.chain; + +import org.bukkit.NamespacedKey; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; +import org.mockbukkit.mockbukkit.entity.PlayerMock; +import us.eunoians.mcrpg.McRPGBaseTest; +import us.eunoians.mcrpg.quest.chain.QuestChainDefinition; +import us.eunoians.mcrpg.quest.chain.QuestChainStep; + +import java.util.List; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; + +class QuestChainRestartEventTest extends McRPGBaseTest { + + private static QuestChainDefinition buildDefinition() { + NamespacedKey chainKey = new NamespacedKey("mcrpg", "restart_chain"); + NamespacedKey sourceKey = new NamespacedKey("mcrpg", "manual"); + NamespacedKey triggerKey = new NamespacedKey("mcrpg", "manual"); + List steps = List.of(QuestChainStep.simple(new NamespacedKey("mcrpg", "quest_one"))); + return new QuestChainDefinition.Builder(chainKey, sourceKey, triggerKey, steps).build(); + } + + @Test + @DisplayName("Getters return values passed to the constructor") + void getters_returnConstructorValues() { + QuestChainDefinition definition = buildDefinition(); + PlayerMock player = server.addPlayer(); + + QuestChainRestartEvent event = new QuestChainRestartEvent( + definition, player, player.getUniqueId(), QuestChainRestartEvent.RestartReason.REPEAT_MODE); + + assertSame(definition, event.getChainDefinition()); + assertSame(player, event.getPlayer()); + assertEquals(player.getUniqueId(), event.getPlayerUUID()); + assertEquals(QuestChainRestartEvent.RestartReason.REPEAT_MODE, event.getReason()); + } + + @Test + @DisplayName("Null player is returned when constructed for offline player") + void nullPlayer_returnsNull() { + QuestChainDefinition definition = buildDefinition(); + UUID offlineUUID = UUID.randomUUID(); + + QuestChainRestartEvent event = new QuestChainRestartEvent( + definition, null, offlineUUID, QuestChainRestartEvent.RestartReason.REPEAT_MODE); + + assertNull(event.getPlayer()); + assertEquals(offlineUUID, event.getPlayerUUID()); + } + + @ParameterizedTest + @EnumSource(QuestChainRestartEvent.RestartReason.class) + @DisplayName("Each RestartReason is correctly returned by getReason") + void restartReason_allValues_returnedCorrectly(QuestChainRestartEvent.RestartReason reason) { + QuestChainDefinition definition = buildDefinition(); + PlayerMock player = server.addPlayer(); + + QuestChainRestartEvent event = new QuestChainRestartEvent( + definition, player, player.getUniqueId(), reason); + + assertEquals(reason, event.getReason()); + } + + @Test + @DisplayName("getHandlers and getHandlerList return the same HandlerList") + void handlers_returnStaticHandlerList() { + QuestChainDefinition definition = buildDefinition(); + PlayerMock player = server.addPlayer(); + + QuestChainRestartEvent event = new QuestChainRestartEvent( + definition, player, player.getUniqueId(), QuestChainRestartEvent.RestartReason.REPEAT_MODE); + + assertSame(QuestChainRestartEvent.getHandlerList(), event.getHandlers()); + } +} diff --git a/src/test/java/us/eunoians/mcrpg/event/quest/chain/QuestChainStepRetryEventTest.java b/src/test/java/us/eunoians/mcrpg/event/quest/chain/QuestChainStepRetryEventTest.java new file mode 100644 index 000000000..e661db2eb --- /dev/null +++ b/src/test/java/us/eunoians/mcrpg/event/quest/chain/QuestChainStepRetryEventTest.java @@ -0,0 +1,101 @@ +package us.eunoians.mcrpg.event.quest.chain; + +import org.bukkit.NamespacedKey; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockbukkit.mockbukkit.entity.PlayerMock; +import us.eunoians.mcrpg.McRPGBaseTest; +import us.eunoians.mcrpg.quest.chain.QuestChainDefinition; +import us.eunoians.mcrpg.quest.chain.QuestChainStep; + +import java.util.List; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; + +class QuestChainStepRetryEventTest extends McRPGBaseTest { + + private static QuestChainDefinition buildDefinition() { + NamespacedKey chainKey = new NamespacedKey("mcrpg", "retry_chain"); + NamespacedKey sourceKey = new NamespacedKey("mcrpg", "manual"); + NamespacedKey triggerKey = new NamespacedKey("mcrpg", "manual"); + List steps = List.of( + QuestChainStep.simple(new NamespacedKey("mcrpg", "step_one")), + QuestChainStep.simple(new NamespacedKey("mcrpg", "step_two")) + ); + return new QuestChainDefinition.Builder(chainKey, sourceKey, triggerKey, steps).build(); + } + + @Test + @DisplayName("Getters return values passed to the constructor") + void getters_returnConstructorValues() { + QuestChainDefinition definition = buildDefinition(); + PlayerMock player = server.addPlayer(); + QuestChainStep step = definition.getSteps().getFirst(); + + QuestChainStepRetryEvent event = new QuestChainStepRetryEvent( + definition, player, player.getUniqueId(), step, 2, 5); + + assertSame(definition, event.getChainDefinition()); + assertSame(player, event.getPlayer()); + assertEquals(player.getUniqueId(), event.getPlayerUUID()); + assertSame(step, event.getStep()); + assertEquals(2, event.getRetryNumber()); + assertEquals(5, event.getMaxRetries()); + } + + @Test + @DisplayName("Null player is returned when constructed for offline player") + void nullPlayer_returnsNull() { + QuestChainDefinition definition = buildDefinition(); + UUID offlineUUID = UUID.randomUUID(); + QuestChainStep step = definition.getSteps().getFirst(); + + QuestChainStepRetryEvent event = new QuestChainStepRetryEvent( + definition, null, offlineUUID, step, 1, 3); + + assertNull(event.getPlayer()); + assertEquals(offlineUUID, event.getPlayerUUID()); + } + + @Test + @DisplayName("maxRetries of -1 indicates unlimited retries") + void unlimitedRetries_maxRetriesIsNegativeOne() { + QuestChainDefinition definition = buildDefinition(); + PlayerMock player = server.addPlayer(); + QuestChainStep step = definition.getSteps().getFirst(); + + QuestChainStepRetryEvent event = new QuestChainStepRetryEvent( + definition, player, player.getUniqueId(), step, 1, -1); + + assertEquals(-1, event.getMaxRetries()); + } + + @Test + @DisplayName("First retry has retryNumber 1") + void firstRetry_retryNumberIsOne() { + QuestChainDefinition definition = buildDefinition(); + PlayerMock player = server.addPlayer(); + QuestChainStep step = definition.getSteps().getFirst(); + + QuestChainStepRetryEvent event = new QuestChainStepRetryEvent( + definition, player, player.getUniqueId(), step, 1, 5); + + assertEquals(1, event.getRetryNumber()); + } + + @Test + @DisplayName("getHandlers and getHandlerList return the same HandlerList") + void handlers_returnStaticHandlerList() { + QuestChainDefinition definition = buildDefinition(); + PlayerMock player = server.addPlayer(); + QuestChainStep step = definition.getSteps().getFirst(); + + QuestChainStepRetryEvent event = new QuestChainStepRetryEvent( + definition, player, player.getUniqueId(), step, 1, 3); + + assertSame(QuestChainStepRetryEvent.getHandlerList(), event.getHandlers()); + } +} diff --git a/src/test/java/us/eunoians/mcrpg/quest/chain/condition/QuestChainStartConditionTypeRegistryTest.java b/src/test/java/us/eunoians/mcrpg/quest/chain/condition/QuestChainStartConditionTypeRegistryTest.java new file mode 100644 index 000000000..5063d49e1 --- /dev/null +++ b/src/test/java/us/eunoians/mcrpg/quest/chain/condition/QuestChainStartConditionTypeRegistryTest.java @@ -0,0 +1,145 @@ +package us.eunoians.mcrpg.quest.chain.condition; + +import dev.dejvokep.boostedyaml.block.implementation.Section; +import org.bukkit.NamespacedKey; +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import us.eunoians.mcrpg.quest.chain.QuestChainStartCondition; + +import java.util.Collection; +import java.util.Optional; +import java.util.function.Supplier; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; + +class QuestChainStartConditionTypeRegistryTest { + + private QuestChainStartConditionTypeRegistry registry; + + @BeforeEach + void setUp() { + registry = new QuestChainStartConditionTypeRegistry(); + } + + private static QuestChainStartConditionType stubType(NamespacedKey key) { + return new QuestChainStartConditionType() { + @Override + public @NotNull NamespacedKey getKey() { + return key; + } + + @Override + public @NotNull QuestChainStartCondition parse(@NotNull Section config) { + return mock(QuestChainStartCondition.class); + } + + @Override + public @NotNull Optional getExpansionKey() { + return Optional.empty(); + } + }; + } + + @Test + @DisplayName("Registering a type makes it retrievable by key") + void register_makesRetrievableByKey() { + NamespacedKey key = new NamespacedKey("mcrpg", "time_gate"); + QuestChainStartConditionType type = stubType(key); + + registry.register(type); + + Optional result = registry.get(key); + assertTrue(result.isPresent()); + assertSame(type, result.get()); + } + + @Test + @DisplayName("registered() returns true for a registered type") + void registered_returnsTrue_whenRegistered() { + NamespacedKey key = new NamespacedKey("mcrpg", "permission_gate"); + QuestChainStartConditionType type = stubType(key); + + registry.register(type); + + assertTrue(registry.registered(type)); + } + + @Test + @DisplayName("registered() returns false for an unregistered type") + void registered_returnsFalse_whenNotRegistered() { + NamespacedKey key = new NamespacedKey("mcrpg", "unknown"); + QuestChainStartConditionType type = stubType(key); + + assertFalse(registry.registered(type)); + } + + @Test + @DisplayName("get() returns empty Optional for an unregistered key") + void get_returnsEmpty_whenNotRegistered() { + NamespacedKey key = new NamespacedKey("mcrpg", "nonexistent"); + + Optional result = registry.get(key); + + assertTrue(result.isEmpty()); + } + + @Test + @DisplayName("getAll() returns all registered types") + void getAll_returnsAllRegistered() { + QuestChainStartConditionType type1 = stubType(new NamespacedKey("mcrpg", "type_a")); + QuestChainStartConditionType type2 = stubType(new NamespacedKey("mcrpg", "type_b")); + + registry.register(type1); + registry.register(type2); + + Collection all = registry.getAll(); + assertEquals(2, all.size()); + assertTrue(all.contains(type1)); + assertTrue(all.contains(type2)); + } + + @Test + @DisplayName("getAll() returns empty collection when nothing is registered") + void getAll_returnsEmpty_whenNothingRegistered() { + Collection all = registry.getAll(); + + assertTrue(all.isEmpty()); + } + + @Test + @DisplayName("Registering a duplicate key silently replaces the previous entry") + void register_duplicateKey_replacesExisting() { + NamespacedKey key = new NamespacedKey("mcrpg", "duplicate"); + QuestChainStartConditionType original = stubType(key); + QuestChainStartConditionType replacement = stubType(key); + + registry.register(original); + registry.register(replacement); + + Optional result = registry.get(key); + assertTrue(result.isPresent()); + assertSame(replacement, result.get()); + assertEquals(1, registry.getAll().size()); + } + + @Test + @DisplayName("getAll() returns an unmodifiable collection") + void getAll_returnsUnmodifiableCollection() { + QuestChainStartConditionType type = stubType(new NamespacedKey("mcrpg", "test")); + registry.register(type); + + Collection all = registry.getAll(); + + assertThrows(UnsupportedOperationException.class, () -> all.add(stubType(new NamespacedKey("mcrpg", "hack")))); + } + + private static void assertThrows(Class expectedType, Runnable runnable) { + org.junit.jupiter.api.Assertions.assertThrows(expectedType, runnable::run); + } +}