feat(commands): unify settings and admin commands
Release / release (push) Successful in 2m28s
CI / build (push) Successful in 1m3s

This commit is contained in:
dmg
2026-08-10 20:44:34 -04:00
parent 5c9dc5b361
commit 4278e08bf3
26 changed files with 1080 additions and 699 deletions
@@ -0,0 +1,227 @@
package games.dmg.spigotbase;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.plugin.java.JavaPlugin;
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
final class BaseAdminCommandTest {
@Test
void invalidPathShowsFriendlyUsage() {
CommandSender sender = mock(CommandSender.class);
when(sender.hasPermission("spigotbase.admin")).thenReturn(true);
PlayerState target = PlayerState.newPlayer(UUID.randomUUID(), "Builder");
BaseStateManager stateManager = mock(BaseStateManager.class);
when(stateManager.findByName("Builder")).thenReturn(Optional.of(target));
BaseAdminCommand command = new BaseAdminCommand(
mock(JavaPlugin.class),
stateManager,
mock(AdminProgressionService.class),
new PluginSettingsProvider(PluginSettings.from(Map.of()))
);
try (MockedStatic<Bukkit> bukkit = mockStatic(Bukkit.class)) {
bukkit.when(() -> Bukkit.getPlayerExact("Builder")).thenReturn(null);
command.onCommand(sender, null, "baseadmin",
new String[] {"setlevel", "Builder", "unknown", "1"});
}
verify(sender).sendMessage(ChatColor.RED
+ "Usage: /baseadmin setlevel <player> <base|size|flight|warmup|cooldown> <level>");
verify(stateManager, never()).update(any(), anyString(), any());
}
@Test
void autocompletesValidLevelsAndResetConfirmation() {
CommandSender sender = mock(CommandSender.class);
when(sender.hasPermission("spigotbase.admin")).thenReturn(true);
BaseAdminCommand command = new BaseAdminCommand(
mock(JavaPlugin.class),
mock(BaseStateManager.class),
mock(AdminProgressionService.class),
new PluginSettingsProvider(PluginSettings.from(Map.of()))
);
assertEquals(
List.of("0", "1", "2", "3", "4"),
command.onTabComplete(sender, null, "baseadmin",
new String[] {"setlevel", "Builder", "base", ""})
);
assertEquals(
List.of("0", "1", "2", "3"),
command.onTabComplete(sender, null, "baseadmin",
new String[] {"setlevel", "Builder", "flight", ""})
);
assertEquals(
List.of("confirm"),
command.onTabComplete(sender, null, "baseadmin",
new String[] {"reset", "Builder", "all", ""})
);
}
@Test
void autocompletesCommandSpecificOptions() {
CommandSender sender = mock(CommandSender.class);
when(sender.hasPermission("spigotbase.admin")).thenReturn(true);
BaseAdminCommand command = new BaseAdminCommand(
mock(JavaPlugin.class),
mock(BaseStateManager.class),
mock(AdminProgressionService.class),
new PluginSettingsProvider(PluginSettings.from(Map.of()))
);
assertEquals(
List.of("base", "size", "flight", "warmup", "cooldown"),
command.onTabComplete(sender, null, "baseadmin",
new String[] {"setlevel", "Builder", ""})
);
assertEquals(
List.of("grass_dirt", "stone", "deepslate", "obsidian", "placements", "base_breaks"),
command.onTabComplete(sender, null, "baseadmin",
new String[] {"setprogress", "Builder", ""})
);
assertEquals(
List.of("personal", "visitor", "all"),
command.onTabComplete(sender, null, "baseadmin",
new String[] {"clearcooldown", "Builder", ""})
);
assertEquals(
List.of("size", "flight", "warmup", "cooldown", "all"),
command.onTabComplete(sender, null, "baseadmin",
new String[] {"reset", "Builder", ""})
);
}
@Test
void autocompletesNumericConfigurationKeys() {
CommandSender sender = mock(CommandSender.class);
when(sender.hasPermission("spigotbase.admin")).thenReturn(true);
JavaPlugin plugin = mock(JavaPlugin.class);
FileConfiguration configuration = mock(FileConfiguration.class);
when(plugin.getConfig()).thenReturn(configuration);
when(configuration.getValues(false)).thenReturn(Map.of(
"base-unlock-blocks", 250,
"visitor-currency-material", "DIAMOND",
"title-stay-ticks", 70
));
BaseAdminCommand command = new BaseAdminCommand(
plugin,
mock(BaseStateManager.class),
mock(AdminProgressionService.class),
new PluginSettingsProvider(PluginSettings.from(Map.of()))
);
assertEquals(
List.of("base-unlock-blocks"),
command.onTabComplete(sender, null, "baseadmin", new String[] {"config", "base"})
);
}
@Test
void autocompletesKnownOfflinePlayers() {
CommandSender sender = mock(CommandSender.class);
when(sender.hasPermission("spigotbase.admin")).thenReturn(true);
BaseStateManager stateManager = mock(BaseStateManager.class);
PlayerState alex = PlayerState.newPlayer(UUID.randomUUID(), "Alex");
PlayerState blake = PlayerState.newPlayer(UUID.randomUUID(), "Blake");
when(stateManager.knownPlayers()).thenReturn(Map.of(
alex.playerId(), alex,
blake.playerId(), blake
));
BaseAdminCommand command = new BaseAdminCommand(
mock(JavaPlugin.class),
stateManager,
mock(AdminProgressionService.class),
new PluginSettingsProvider(PluginSettings.from(Map.of()))
);
assertEquals(
List.of("Alex", "Blake"),
command.onTabComplete(sender, null, "baseadmin", new String[] {"status", ""})
);
}
@Test
void autocompletesAdminSubcommandsForPermittedSenders() {
CommandSender sender = mock(CommandSender.class);
when(sender.hasPermission("spigotbase.admin")).thenReturn(true);
BaseAdminCommand command = new BaseAdminCommand(
mock(JavaPlugin.class),
mock(BaseStateManager.class),
mock(AdminProgressionService.class),
new PluginSettingsProvider(PluginSettings.from(Map.of()))
);
assertEquals(
List.of("status", "setlevel", "setprogress", "clearcooldown", "reset", "config"),
command.onTabComplete(sender, null, "baseadmin", new String[] {""})
);
}
@Test
void resetBaseRequiresConfirmedCompleteReset() {
CommandSender sender = mock(CommandSender.class);
when(sender.hasPermission("spigotbase.admin")).thenReturn(true);
PlayerState target = PlayerState.newPlayer(UUID.randomUUID(), "Builder");
BaseStateManager stateManager = mock(BaseStateManager.class);
when(stateManager.findByName("Builder")).thenReturn(Optional.of(target));
BaseAdminCommand command = new BaseAdminCommand(
mock(JavaPlugin.class),
stateManager,
mock(AdminProgressionService.class),
new PluginSettingsProvider(PluginSettings.from(Map.of()))
);
try (MockedStatic<Bukkit> bukkit = mockStatic(Bukkit.class)) {
bukkit.when(() -> Bukkit.getPlayerExact("Builder")).thenReturn(null);
command.onCommand(
sender,
null,
"baseadmin",
new String[] {"reset", "Builder", "base"}
);
}
verify(stateManager, never()).update(any(), anyString(), any());
verify(sender).sendMessage(ChatColor.RED
+ "Resetting base removes all progression. Use: /baseadmin reset Builder all confirm");
}
@Test
void statusDisplaysKnownPlayerProgress() {
CommandSender sender = mock(CommandSender.class);
when(sender.hasPermission("spigotbase.admin")).thenReturn(true);
PlayerState target = PlayerState.newPlayer(UUID.randomUUID(), "Builder");
BaseStateManager stateManager = mock(BaseStateManager.class);
when(stateManager.findByName("Builder")).thenReturn(Optional.of(target));
BaseAdminCommand command = new BaseAdminCommand(
mock(JavaPlugin.class),
stateManager,
mock(AdminProgressionService.class),
new PluginSettingsProvider(PluginSettings.from(Map.of()))
);
try (MockedStatic<Bukkit> bukkit = mockStatic(Bukkit.class)) {
bukkit.when(() -> Bukkit.getPlayerExact("Builder")).thenReturn(null);
command.onCommand(sender, null, "baseadmin", new String[] {"status", "Builder"});
}
verify(sender).sendMessage(ChatColor.GOLD + "=== Builder Base Progress ===");
}
}
@@ -1,59 +0,0 @@
package games.dmg.spigotbase;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.UnaryOperator;
import org.bukkit.entity.Player;
import org.junit.jupiter.api.Test;
final class BaseFlightCommandTest {
@Test
void autocompletesExplicitModes() {
BaseFlightCommand command = new BaseFlightCommand(
mock(BaseStateManager.class),
mock(BaseFlightController.class)
);
assertEquals(
List.of("off"),
command.onTabComplete(null, null, "baseflight", new String[] {"of"})
);
}
@Test
void explicitOnIsIdempotent() {
UUID playerId = UUID.randomUUID();
Player player = mock(Player.class);
when(player.getUniqueId()).thenReturn(playerId);
when(player.getName()).thenReturn("Builder");
PlayerState current = PlayerState.newPlayer(playerId, "Builder")
.withAdministrativeLevels(1, 0, 1, 0, 0, false, true, false);
AtomicReference<PlayerState> updated = new AtomicReference<>();
BaseStateManager stateManager = mock(BaseStateManager.class);
when(stateManager.player(playerId, "Builder")).thenReturn(current);
when(stateManager.update(any(), anyString(), any())).thenAnswer(invocation -> {
@SuppressWarnings("unchecked")
UnaryOperator<PlayerState> operation = invocation.getArgument(2);
PlayerState result = operation.apply(current);
updated.set(result);
return result;
});
BaseFlightCommand command = new BaseFlightCommand(
stateManager,
mock(BaseFlightController.class)
);
command.onCommand(player, null, "baseflight", new String[] {"on"});
assertTrue(updated.get().flightEnabled());
}
}
@@ -0,0 +1,230 @@
package games.dmg.spigotbase;
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 static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.UnaryOperator;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.junit.jupiter.api.Test;
final class BaseSettingsCommandTest {
@Test
void invalidArgumentsShowUsage() {
UUID playerId = UUID.randomUUID();
Player player = mock(Player.class);
when(player.getUniqueId()).thenReturn(playerId);
when(player.getName()).thenReturn("Builder");
BaseStateManager stateManager = mock(BaseStateManager.class);
when(stateManager.player(playerId, "Builder"))
.thenReturn(PlayerState.newPlayer(playerId, "Builder"));
BaseSettingsCommand command = new BaseSettingsCommand(
stateManager,
new PluginSettingsProvider(PluginSettings.from(Map.of())),
mock(BaseFlightController.class)
);
command.onCommand(player, null, "basesettings", new String[] {"unknown"});
verify(player).sendMessage(org.mockito.ArgumentMatchers.<String>argThat(
message -> message.contains("Usage: /basesettings")
));
}
@Test
void autocompletesValuesForEachSetting() {
BaseSettingsCommand command = new BaseSettingsCommand(
mock(BaseStateManager.class),
new PluginSettingsProvider(PluginSettings.from(Map.of())),
mock(BaseFlightController.class)
);
assertEquals(
List.of("allowed"),
command.onTabComplete(null, null, "basesettings", new String[] {"visitors", "a"})
);
for (String setting : List.of("navigation", "flight", "bossbar")) {
assertEquals(
List.of("disable"),
command.onTabComplete(null, null, "basesettings", new String[] {setting, "d"})
);
}
}
@Test
void autocompletesSettingNames() {
BaseSettingsCommand command = new BaseSettingsCommand(
mock(BaseStateManager.class),
new PluginSettingsProvider(PluginSettings.from(Map.of())),
mock(BaseFlightController.class)
);
assertEquals(
List.of("status", "upgrade", "visitors", "navigation", "flight", "bossbar"),
command.onTabComplete(null, null, "basesettings", new String[] {""})
);
}
@Test
void upgradePurchasesBaseIv() throws Exception {
UUID playerId = UUID.randomUUID();
Player player = mock(Player.class);
when(player.getUniqueId()).thenReturn(playerId);
when(player.getName()).thenReturn("Host");
PlayerInventory inventory = mock(PlayerInventory.class);
when(player.getInventory()).thenReturn(inventory);
when(inventory.getStorageContents()).thenReturn(new ItemStack[] {
new ItemStack(Material.DIAMOND, 64),
new ItemStack(Material.DIAMOND, 64)
});
PlayerState current = PlayerState.newPlayer(playerId, "Host")
.withAdministrativeLevels(3, 0, 0, 0, 0, false, false, false)
.withBase(
new BaseLocation(UUID.randomUUID(), "world", 0, 64, 0, 0, 0),
Instant.EPOCH
);
AtomicReference<PlayerState> updated = new AtomicReference<>();
BaseStateManager stateManager = mock(BaseStateManager.class);
when(stateManager.player(playerId, "Host")).thenReturn(current);
when(stateManager.updateAndSave(any(), anyString(), any())).thenAnswer(invocation -> {
@SuppressWarnings("unchecked")
UnaryOperator<PlayerState> operation = invocation.getArgument(2);
PlayerState result = operation.apply(current);
updated.set(result);
return result;
});
BaseSettingsCommand command = new BaseSettingsCommand(
stateManager,
new PluginSettingsProvider(PluginSettings.from(Map.of())),
mock(BaseFlightController.class)
);
command.onCommand(player, null, "basesettings", new String[] {"upgrade"});
assertEquals(4, updated.get().baseLevel());
assertTrue(updated.get().visitorsEnabled());
}
@Test
void bossbarEnableIsIdempotent() {
UUID playerId = UUID.randomUUID();
PlayerState current = PlayerState.newPlayer(playerId, "Miner");
CommandResult result = execute(current, "bossbar", "enable");
assertTrue(result.updated().bossBarEnabled());
}
@Test
void flightDisableIsIdempotentAndRemovesGrantedFlight() {
UUID playerId = UUID.randomUUID();
PlayerState current = PlayerState.newPlayer(playerId, "Pilot")
.withAdministrativeLevels(1, 0, 1, 0, 0, false, true, false);
CommandResult result = execute(current, "flight", "disable");
assertFalse(result.updated().flightEnabled());
verify(result.flightController()).removeGrantedFlight(any(Player.class));
}
@Test
void navigationDisableIsIdempotent() {
UUID playerId = UUID.randomUUID();
PlayerState current = PlayerState.newPlayer(playerId, "Explorer")
.withAdministrativeLevels(2, 0, 0, 0, 0, true, false, false)
.withBase(
new BaseLocation(UUID.randomUUID(), "world", 0, 64, 0, 0, 0),
Instant.EPOCH
);
CommandResult result = execute(current, "navigation", "disable");
assertFalse(result.updated().navigationEnabled());
}
@Test
void visitorsAllowedIsIdempotent() {
UUID playerId = UUID.randomUUID();
PlayerState current = PlayerState.newPlayer(playerId, "Host")
.withAdministrativeLevels(4, 0, 0, 0, 0, false, false, true);
CommandResult result = execute(current, "visitors", "allowed");
assertTrue(result.updated().visitorsEnabled());
}
@Test
void defaultAndStatusDisplayTheFullProgressReport() {
UUID playerId = UUID.randomUUID();
Player player = mock(Player.class);
when(player.getUniqueId()).thenReturn(playerId);
when(player.getName()).thenReturn("Builder");
BaseStateManager stateManager = mock(BaseStateManager.class);
when(stateManager.player(playerId, "Builder"))
.thenReturn(PlayerState.newPlayer(playerId, "Builder"));
BaseSettingsCommand command = new BaseSettingsCommand(
stateManager,
new PluginSettingsProvider(PluginSettings.from(Map.of())),
mock(BaseFlightController.class)
);
command.onCommand(player, null, "basesettings", new String[0]);
command.onCommand(player, null, "basesettings", new String[] {"status"});
verify(player, times(2)).sendMessage(ChatColor.GOLD + "=== Base Progress ===");
verify(player, times(2)).sendMessage(
org.mockito.ArgumentMatchers.<String>argThat(message ->
message.contains("Settings: visitors=")
&& message.contains("navigation=")
&& message.contains("flight=")
&& message.contains("bossbar=")
)
);
}
private static CommandResult execute(PlayerState current, String... arguments) {
Player player = mock(Player.class);
when(player.getUniqueId()).thenReturn(current.playerId());
when(player.getName()).thenReturn(current.latestName());
AtomicReference<PlayerState> updated = new AtomicReference<>();
BaseStateManager stateManager = mock(BaseStateManager.class);
when(stateManager.player(current.playerId(), current.latestName())).thenReturn(current);
when(stateManager.update(any(), anyString(), any())).thenAnswer(invocation -> {
@SuppressWarnings("unchecked")
UnaryOperator<PlayerState> operation = invocation.getArgument(2);
PlayerState result = operation.apply(current);
updated.set(result);
return result;
});
BaseFlightController flightController = mock(BaseFlightController.class);
BaseSettingsCommand command = new BaseSettingsCommand(
stateManager,
new PluginSettingsProvider(PluginSettings.from(Map.of())),
flightController
);
command.onCommand(player, null, "basesettings", arguments);
return new CommandResult(updated.get(), flightController);
}
private record CommandResult(PlayerState updated, BaseFlightController flightController) {
}
}
@@ -1,53 +0,0 @@
package games.dmg.spigotbase;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.UnaryOperator;
import org.bukkit.entity.Player;
import org.junit.jupiter.api.Test;
final class BaseVisitorsCommandTest {
@Test
void autocompletesExplicitModes() {
BaseVisitorsCommand command = new BaseVisitorsCommand(mock(BaseStateManager.class));
assertEquals(
List.of("on"),
command.onTabComplete(null, null, "basevisitors", new String[] {"on"})
);
}
@Test
void explicitOnIsIdempotent() {
UUID playerId = UUID.randomUUID();
Player player = mock(Player.class);
when(player.getUniqueId()).thenReturn(playerId);
when(player.getName()).thenReturn("Host");
PlayerState current = PlayerState.newPlayer(playerId, "Host")
.withAdministrativeLevels(4, 0, 0, 0, 0, false, false, true);
AtomicReference<PlayerState> updated = new AtomicReference<>();
BaseStateManager stateManager = mock(BaseStateManager.class);
when(stateManager.player(playerId, "Host")).thenReturn(current);
when(stateManager.update(any(), anyString(), any())).thenAnswer(invocation -> {
@SuppressWarnings("unchecked")
UnaryOperator<PlayerState> operation = invocation.getArgument(2);
PlayerState result = operation.apply(current);
updated.set(result);
return result;
});
BaseVisitorsCommand command = new BaseVisitorsCommand(stateManager);
command.onCommand(player, null, "basevisitors", new String[] {"on"});
assertTrue(updated.get().visitorsEnabled());
}
}
@@ -1,6 +1,7 @@
package games.dmg.spigotbase;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import java.io.InputStream;
@@ -10,6 +11,34 @@ import org.junit.jupiter.api.Test;
import org.yaml.snakeyaml.Yaml;
final class PluginMetadataTest {
@Test
void homeadminAliasesBaseadmin() {
Map<?, ?> commands = commands();
Map<?, ?> admin = (Map<?, ?>) commands.get("baseadmin");
assertEquals(List.of("homeadmin"), admin.get("aliases"));
}
@Test
void doesNotDeclareSupersededSettingsCommands() {
Map<?, ?> commands = commands();
for (String command : List.of(
"baseprogress", "basenavigation", "baseflight", "basevisitors"
)) {
assertFalse(commands.containsKey(command), command);
}
}
@Test
void homesettingsAliasesBasesettings() {
Map<?, ?> commands = commands();
Map<?, ?> settings = (Map<?, ?>) commands.get("basesettings");
assertNotNull(settings);
assertEquals(List.of("homesettings"), settings.get("aliases"));
}
@Test
void sethomeAliasesSetbase() {
Map<?, ?> commands = commands();
@@ -26,30 +55,6 @@ final class PluginMetadataTest {
assertEquals(List.of("home"), base.get("aliases"));
}
@Test
void homevisitorsAliasesBasevisitors() {
Map<?, ?> commands = commands();
Map<?, ?> visitors = (Map<?, ?>) commands.get("basevisitors");
assertEquals(List.of("homevisitors"), visitors.get("aliases"));
}
@Test
void homeflightAliasesBaseflight() {
Map<?, ?> commands = commands();
Map<?, ?> flight = (Map<?, ?>) commands.get("baseflight");
assertEquals(List.of("homeflight"), flight.get("aliases"));
}
@Test
void homenavigationAliasesBasenavigation() {
Map<?, ?> commands = commands();
Map<?, ?> navigation = (Map<?, ?>) commands.get("basenavigation");
assertEquals(List.of("homenavigation"), navigation.get("aliases"));
}
@Test
void visitAliasesGotobase() {
Map<?, ?> commands = commands();
@@ -70,8 +75,7 @@ final class PluginMetadataTest {
Map<?, ?> commands = (Map<?, ?>) plugin.get("commands");
for (String command : new String[] {
"setbase", "base", "basenavigation", "baseflight",
"basevisitors", "gotobase", "baseprogress", "baseadmin"
"setbase", "base", "gotobase", "basesettings", "baseadmin"
}) {
assertNotNull(commands.get(command), command);
}
@@ -1,35 +0,0 @@
package games.dmg.spigotbase;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
final class TogglePreferenceTest {
@Test
void noArgumentTogglesCurrentPreference() {
assertFalse(TogglePreference.resolve(true, new String[0]));
assertTrue(TogglePreference.resolve(false, new String[0]));
}
@Test
void explicitModesAreIdempotent() {
assertTrue(TogglePreference.resolve(true, new String[] {"on"}));
assertTrue(TogglePreference.resolve(false, new String[] {"on"}));
assertFalse(TogglePreference.resolve(true, new String[] {"off"}));
assertFalse(TogglePreference.resolve(false, new String[] {"off"}));
}
@Test
void rejectsUnknownOrExtraArguments() {
assertThrows(
IllegalArgumentException.class,
() -> TogglePreference.resolve(false, new String[] {"maybe"})
);
assertThrows(
IllegalArgumentException.class,
() -> TogglePreference.resolve(false, new String[] {"on", "off"})
);
}
}