feat(commands): add contextual completion and unlock listing
Release / release (push) Successful in 3m46s
CI / build (push) Successful in 57s

This commit is contained in:
dmg
2026-09-04 23:37:20 -04:00
parent 2bcba5071f
commit b0da1508b6
12 changed files with 220 additions and 20 deletions
@@ -1,5 +1,6 @@
package games.dmg.spigotstealth;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.contains;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -16,6 +17,51 @@ import org.bukkit.command.CommandSender;
import org.junit.jupiter.api.Test;
class StealthAdminCommandTest {
@Test
void completesAdministrativeOperationsByPrefix() {
UUID playerId = UUID.randomUUID();
try (Fixture fixture = fixture(playerId)) {
assertEquals(
List.of("grant"),
fixture.command.onTabComplete(
sender(true), mock(Command.class), "stealthadmin", new String[] {"gr"}));
assertEquals(
List.of("status", "grant", "reset", "list"),
fixture.command.onTabComplete(
sender(true), mock(Command.class), "stealthadmin", new String[] {""}));
}
}
@Test
void completesContextualArgumentsAndSuppressesIrrelevantSuggestions() {
UUID playerId = UUID.randomUUID();
try (Fixture fixture = fixture(playerId)) {
Command command = mock(Command.class);
CommandSender administrator = sender(true);
assertEquals(
List.of("Alex"),
fixture.command.onTabComplete(
administrator, command, "stealthadmin", new String[] {"status", "al"}));
assertEquals(
List.of("confirm"),
fixture.command.onTabComplete(
administrator, command, "stealthadmin", new String[] {"reset", "Alex", "co"}));
assertEquals(
List.of("unlocked"),
fixture.command.onTabComplete(
administrator, command, "stealthadmin", new String[] {"list", "un"}));
assertEquals(
List.of(),
fixture.command.onTabComplete(
administrator, command, "stealthadmin", new String[] {"status", "Alex", ""}));
assertEquals(
List.of(),
fixture.command.onTabComplete(
sender(false), command, "stealthadmin", new String[] {""}));
}
}
@Test
void statusInspectsKnownOfflinePlayerAndReportsAllState() {
UUID playerId = UUID.randomUUID();
@@ -28,6 +74,25 @@ class StealthAdminCommandTest {
}
}
@Test
void listsUnlockedPlayersAndClearlyReportsWhenThereAreNone() {
UUID playerId = UUID.randomUUID();
try (Fixture fixture = fixture(playerId)) {
Command command = mock(Command.class);
CommandSender emptySender = sender(true);
fixture.command.onCommand(
emptySender, command, "stealthadmin", new String[] {"list", "unlocked"});
verify(emptySender).sendMessage("No players have unlocked stealth.");
fixture.manager.update(state -> state.withPlayer(
state.player(playerId).withProgress(5000L, true))).join();
CommandSender populatedSender = sender(true);
fixture.command.onCommand(
populatedSender, command, "stealthadmin", new String[] {"list", "unlocked"});
verify(populatedSender).sendMessage("Stealth unlocked: Alex");
}
}
@Test
void grantPersistsThenReportsAndAuditsAction() {
UUID playerId = UUID.randomUUID();
@@ -58,6 +58,29 @@ class StealthAdministrationServiceTest {
}
}
@Test
void listsAllUnlockedPlayersByNameOrUuidInCaseInsensitiveOrder() {
UUID namelessId = UUID.randomUUID();
UUID lockedId = UUID.randomUUID();
UUID zoeId = UUID.randomUUID();
UUID alexId = UUID.randomUUID();
try (StealthStateManager manager = manager()) {
manager.update(state -> state
.withPlayer(PlayerStealthState.empty(namelessId).withProgress(0L, true))
.withPlayer(PlayerStealthState.empty(lockedId).withLastKnownName("Locked"))
.withPlayer(PlayerStealthState.empty(zoeId).withLastKnownName("zoe").withProgress(1L, true))
.withPlayer(PlayerStealthState.empty(alexId).withLastKnownName("Alex").withProgress(2L, true)))
.join();
StealthAdministrationService administration = service(manager, List::of, ignored -> { });
assertEquals(
List.of("Alex", namelessId.toString(), "zoe").stream()
.sorted(String.CASE_INSENSITIVE_ORDER)
.toList(),
administration.unlockedPlayerNames());
}
}
@Test
void listsOnlyCurrentlyOnlineConcealedPlayers() {
UUID concealedId = UUID.randomUUID();
@@ -8,6 +8,7 @@ import static org.mockito.Mockito.when;
import java.time.Duration;
import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicLong;
@@ -16,6 +17,24 @@ import org.bukkit.entity.Player;
import org.junit.jupiter.api.Test;
class StealthCommandTest {
@Test
void completesProgressByPrefixWithoutSuggestingPlayersElsewhere() {
try (StealthStateManager manager = manager()) {
QualifyingInvisibilityService progression = new QualifyingInvisibilityService(
manager, Duration.ofHours(8), System::nanoTime, ignored -> { });
StealthCommand command = new StealthCommand(manager, progression, StealthSettings.from(Map.of()));
Command bukkitCommand = mock(Command.class);
Player player = player(UUID.randomUUID());
org.junit.jupiter.api.Assertions.assertEquals(
List.of("progress"),
command.onTabComplete(player, bukkitCommand, "stealth", new String[] {"pr"}));
org.junit.jupiter.api.Assertions.assertEquals(
List.of(),
command.onTabComplete(player, bukkitCommand, "stealth", new String[] {"progress", ""}));
}
}
@Test
void reportsLiveProgressTargetAndRemainingTimeWithoutMutatingState() {
UUID playerId = UUID.randomUUID();