package games.dmg.spigottyrant; 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 java.time.Duration; import java.time.Instant; import java.util.EnumSet; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.UUID; import org.junit.jupiter.api.Test; final class TyrantControlPanelModelTest { @Test void overviewShowsProgressPurchasesAssignmentsAndIntelligenceCooldown() { UUID tyrantId = UUID.fromString("11111111-1111-1111-1111-111111111111"); UUID assassinId = UUID.fromString("22222222-2222-2222-2222-222222222222"); Instant now = Instant.parse("2026-08-21T12:00:00Z"); GameState game = new GameState( GameLifecycle.RUNNING, Optional.of(tyrantId), Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), Duration.ZERO, 3, 2, Set.of(TyrantUnlock.ASSASSIN, TyrantUnlock.ROSTER_INTELLIGENCE) ); PlayerState tyrant = new PlayerState( tyrantId, "Tyrant", Optional.of(now), Optional.empty(), TyrantClass.NONE, Optional.empty(), Map.of(Ability.ROSTER_INTELLIGENCE, now.plusSeconds(90)), Set.of(), java.util.List.of() ); PlayerState assassin = new PlayerState( assassinId, "Blade", Optional.of(now), Optional.empty(), TyrantClass.ASSASSIN, Optional.empty(), Map.of(), Set.of(), java.util.List.of() ); TyrantControlPanelModel model = TyrantControlPanelModel.create( game, tyrant, Map.of(tyrantId, tyrant, assassinId, assassin), now ); assertEquals(3, model.level()); assertEquals(2, model.unspentChoices()); assertEquals(UnlockAvailability.PURCHASED, model.unlocks().get(TyrantUnlock.ASSASSIN)); assertEquals( Set.of(TyrantUnlock.ASSASSIN, TyrantUnlock.ROSTER_INTELLIGENCE), model.purchasedUnlocks() ); assertEquals("Blade", model.classHolders().get(TyrantClass.ASSASSIN)); assertEquals(Duration.ofSeconds(90), model.intelligenceCooldown()); } @Test void elytraMenuExplainsMissingPrerequisitesAndRefreshesAfterClaims() { Map unlocks = new java.util.EnumMap<>(TyrantUnlock.class); for (TyrantUnlock unlock : TyrantUnlock.values()) { unlocks.put(unlock, UnlockAvailability.PURCHASED); } TyrantControlPanelModel incomplete = new TyrantControlPanelModel( 16, 1, unlocks, Set.of(), Map.of(), Duration.ZERO); assertFalse(incomplete.armorAvailable(TyrantArmorPiece.ELYTRA)); assertTrue(incomplete.armorLore(TyrantArmorPiece.ELYTRA).contains( "Claim all nine regular legacy rewards first (0/9).")); TyrantControlPanelModel ready = new TyrantControlPanelModel( 16, 1, unlocks, TyrantArmorPiece.regularRewards(), Map.of(), Duration.ZERO); assertTrue(ready.armorAvailable(TyrantArmorPiece.ELYTRA)); assertTrue(ready.armorLore(TyrantArmorPiece.ELYTRA).contains("Status: AVAILABLE")); assertTrue(ready.armorLore(TyrantArmorPiece.ELYTRA).contains("Unbreakable")); TyrantControlPanelModel claimed = new TyrantControlPanelModel( 17, 1, unlocks, EnumSet.allOf(TyrantArmorPiece.class), Map.of(), Duration.ZERO); assertFalse(claimed.armorAvailable(TyrantArmorPiece.ELYTRA)); assertTrue(claimed.armorLore(TyrantArmorPiece.ELYTRA).contains("Status: CLAIMED")); TyrantControlPanelModel locked = new TyrantControlPanelModel( 0, 0, Map.of(), Set.of(), Map.of(), Duration.ZERO); assertTrue(locked.armorLore(TyrantArmorPiece.ELYTRA).contains( "Purchase all six standard unlocks first.")); assertTrue(locked.armorLore(TyrantArmorPiece.ELYTRA).contains("Earn another choice first.")); } @Test void armorAvailabilityRequiresAllUnlocksAChoiceAndAnUnclaimedSlot() { UUID tyrantId = UUID.fromString("11111111-1111-1111-1111-111111111111"); Instant now = Instant.parse("2026-09-04T00:00:00Z"); GameState game = new GameState( GameLifecycle.RUNNING, Optional.of(tyrantId), Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), Duration.ZERO, 6, 1, EnumSet.allOf(TyrantUnlock.class), Set.of(TyrantArmorPiece.HELMET) ); PlayerState tyrant = PlayerState.newPlayer(tyrantId, "Tyrant"); TyrantControlPanelModel model = TyrantControlPanelModel.create( game, tyrant, Map.of(tyrantId, tyrant), now ); assertTrue(model.allStandardUnlocksPurchased()); assertFalse(model.armorAvailable(TyrantArmorPiece.HELMET)); assertTrue(model.armorAvailable(TyrantArmorPiece.CHESTPLATE)); } }