Command Tests (#1199)

This commit is contained in:
GoldenStack 2022-07-01 19:12:07 -05:00 committed by GitHub
parent 18ab44706b
commit 54a6bcd2af
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 1116 additions and 39 deletions

View File

@ -443,37 +443,6 @@ public final class CommandManager {
return node;
}
private static class IndexedArgument {
private final CommandSyntax syntax;
private final Argument<?> argument;
private final int index;
private record IndexedArgument(CommandSyntax syntax, Argument<?> argument, int index) {}
public IndexedArgument(CommandSyntax syntax, Argument<?> argument, int index) {
this.syntax = syntax;
this.argument = argument;
this.index = index;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
IndexedArgument that = (IndexedArgument) o;
return index == that.index && Objects.equals(syntax, that.syntax) && Objects.equals(argument, that.argument);
}
@Override
public int hashCode() {
return Objects.hash(syntax, argument, index);
}
@Override
public String toString() {
return "IndexedArgument{" +
"syntax=" + syntax +
", argument=" + argument +
", index=" + index +
'}';
}
}
}

View File

@ -220,7 +220,7 @@ public class ArgumentEntity extends Argument<EntityFinder> {
final boolean include = !value.startsWith("!");
final String gameModeName = include ? value : value.substring(1);
try {
final GameMode gameMode = GameMode.valueOf(gameModeName);
final GameMode gameMode = GameMode.valueOf(gameModeName.toUpperCase());
entityFinder.setGameMode(gameMode, include ? EntityFinder.ToggleableType.INCLUDE : EntityFinder.ToggleableType.EXCLUDE);
} catch (IllegalArgumentException e) {
throw new ArgumentSyntaxException("Invalid entity game mode", input, INVALID_ARGUMENT_VALUE);
@ -228,12 +228,16 @@ public class ArgumentEntity extends Argument<EntityFinder> {
break;
}
case "limit":
int limit;
try {
final int limit = Integer.parseInt(value);
limit = Integer.parseInt(value);
entityFinder.setLimit(limit);
} catch (NumberFormatException e) {
throw new ArgumentSyntaxException("Invalid limit number", input, INVALID_ARGUMENT_VALUE);
}
if (limit <= 0) {
throw new ArgumentSyntaxException("Limit must be positive", input, INVALID_ARGUMENT_VALUE);
}
break;
case "sort":
try {

View File

@ -10,7 +10,7 @@ import net.minestom.server.utils.math.FloatRange;
public class ArgumentFloatRange extends ArgumentRange<FloatRange, Float> {
public ArgumentFloatRange(String id) {
super(id, "minecraft:float_range", Float.MIN_VALUE, Float.MAX_VALUE, Float::parseFloat, FloatRange::new);
super(id, "minecraft:float_range", -Float.MAX_VALUE, Float.MAX_VALUE, Float::parseFloat, FloatRange::new);
}
@Override

View File

@ -56,7 +56,7 @@ abstract class ArgumentRelativeVec extends Argument<RelativeVec> {
if (type == null) {
type = modifierChar == LOCAL_CHAR ? LOCAL : RELATIVE;
} else if (type != (modifierChar == LOCAL_CHAR ? LOCAL : RELATIVE)) {
} else if ((type == LOCAL) != (modifierChar == LOCAL_CHAR)) {
throw new ArgumentSyntaxException("Cannot mix world & local coordinates (everything must either use ^ or not)", input, MIXED_TYPE_ERROR);
}

View File

@ -41,10 +41,10 @@ public class ArgumentParser {
ARGUMENT_FUNCTION_MAP.put("time", ArgumentTime::new);
ARGUMENT_FUNCTION_MAP.put("enchantment", ArgumentEnchantment::new);
ARGUMENT_FUNCTION_MAP.put("particle", ArgumentParticle::new);
ARGUMENT_FUNCTION_MAP.put("resourceLocation", ArgumentResourceLocation::new);
ARGUMENT_FUNCTION_MAP.put("resourcelocation", ArgumentResourceLocation::new);
ARGUMENT_FUNCTION_MAP.put("potion", ArgumentPotionEffect::new);
ARGUMENT_FUNCTION_MAP.put("entityType", ArgumentEntityType::new);
ARGUMENT_FUNCTION_MAP.put("blockState", ArgumentBlockState::new);
ARGUMENT_FUNCTION_MAP.put("entitytype", ArgumentEntityType::new);
ARGUMENT_FUNCTION_MAP.put("blockstate", ArgumentBlockState::new);
ARGUMENT_FUNCTION_MAP.put("intrange", ArgumentIntRange::new);
ARGUMENT_FUNCTION_MAP.put("floatrange", ArgumentFloatRange::new);

View File

@ -4,6 +4,8 @@ import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
public class SuggestionEntry {
private final String entry;
private final Component tooltip;
@ -24,4 +26,17 @@ public class SuggestionEntry {
public @Nullable Component getTooltip() {
return tooltip;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SuggestionEntry that = (SuggestionEntry) o;
return Objects.equals(entry, that.entry) && Objects.equals(tooltip, that.tooltip);
}
@Override
public int hashCode() {
return Objects.hash(entry, tooltip);
}
}

View File

@ -137,4 +137,17 @@ public final class RelativeVec {
private interface CoordinateConverter {
@NotNull Vec convert(Vec vec, Pos origin, boolean relativeX, boolean relativeY, boolean relativeZ);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
RelativeVec that = (RelativeVec) o;
return relativeX == that.relativeX && relativeY == that.relativeY && relativeZ == that.relativeZ && Objects.equals(vec, that.vec) && coordinateType == that.coordinateType;
}
@Override
public int hashCode() {
return Objects.hash(vec, coordinateType, relativeX, relativeY, relativeZ);
}
}

View File

@ -1,5 +1,7 @@
package net.minestom.server.utils.math;
import java.util.Objects;
/**
* Represents the base for any data type that is numeric.
*
@ -74,4 +76,18 @@ public abstract class Range<T> {
* otherwise {@code false}.
*/
public abstract boolean isInRange(T value);
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Range<?> range = (Range<?>) o;
return Objects.equals(minimum, range.minimum) && Objects.equals(maximum, range.maximum);
}
@Override
public int hashCode() {
return Objects.hash(minimum, maximum);
}
}

View File

@ -0,0 +1,58 @@
package net.minestom.server.command;
import net.minestom.server.command.builder.arguments.Argument;
import net.minestom.server.command.builder.arguments.ArgumentType;
import net.minestom.server.command.builder.parser.ArgumentParser;
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
public class ArgumentParserTest {
@Test
public void testArgumentParser() {
// Test each argument
assertParserEquals("Literal<example>", ArgumentType.Literal("example"));
assertParserEquals("Boolean<example>", ArgumentType.Boolean("example"));
assertParserEquals("Integer<example>", ArgumentType.Integer("example"));
assertParserEquals("Double<example>", ArgumentType.Double("example"));
assertParserEquals("Float<example>", ArgumentType.Float("example"));
assertParserEquals("String<example>", ArgumentType.String("example"));
assertParserEquals("Word<example>", ArgumentType.Word("example"));
assertParserEquals("StringArray<example>", ArgumentType.StringArray("example"));
assertParserEquals("Command<example>", ArgumentType.Command("example"));
assertParserEquals("Color<example>", ArgumentType.Color("example"));
assertParserEquals("Time<example>", ArgumentType.Time("example"));
assertParserEquals("Enchantment<example>", ArgumentType.Enchantment("example"));
assertParserEquals("Particle<example>", ArgumentType.Particle("example"));
assertParserEquals("ResourceLocation<example>", ArgumentType.ResourceLocation("example"));
assertParserEquals("Potion<example>", ArgumentType.Potion("example"));
assertParserEquals("EntityType<example>", ArgumentType.EntityType("example"));
assertParserEquals("BlockState<example>", ArgumentType.BlockState("example"));
assertParserEquals("IntRange<example>", ArgumentType.IntRange("example"));
assertParserEquals("FloatRange<example>", ArgumentType.FloatRange("example"));
assertParserEquals("ItemStack<example>", ArgumentType.ItemStack("example"));
assertParserEquals("Component<example>", ArgumentType.Component("example"));
assertParserEquals("UUID<example>", ArgumentType.UUID("example"));
assertParserEquals("NBT<example>", ArgumentType.NBT("example"));
assertParserEquals("NBTCompound<example>", ArgumentType.NbtCompound("example"));
assertParserEquals("RelativeBlockPosition<example>", ArgumentType.RelativeBlockPosition("example"));
assertParserEquals("RelativeVec2<example>", ArgumentType.RelativeVec2("example"));
assertParserEquals("RelativeVec3<example>", ArgumentType.RelativeVec3("example"));
assertParserEquals("Entities<example>", ArgumentType.Entity("example"));
assertParserEquals("Entity<example>", ArgumentType.Entity("example").singleEntity(true));
assertParserEquals("Players<example>", ArgumentType.Entity("example").onlyPlayers(true));
assertParserEquals("Player<example>", ArgumentType.Entity("example").onlyPlayers(true).singleEntity(true));
// Test multiple argument functionality
assertParserEquals("NBT<arg1> RelativeVec2<arg2>", ArgumentType.NBT("arg1"), ArgumentType.RelativeVec2("arg2"));
assertParserEquals("Word<arg1> UUID<arg2> NBT<arg3>", ArgumentType.Word("arg1"), ArgumentType.UUID("arg2"), ArgumentType.NBT("arg3"));
}
private static void assertParserEquals(@NotNull String input, @NotNull Argument<?> @NotNull ... args) {
assertArrayEquals(ArgumentParser.generate(input), args);
}
}

View File

@ -0,0 +1,56 @@
package net.minestom.server.command;
import net.minestom.server.command.builder.CommandContext;
import net.minestom.server.command.builder.arguments.Argument;
import net.minestom.server.command.builder.arguments.ArgumentType;
import net.minestom.server.command.builder.suggestion.Suggestion;
import net.minestom.server.command.builder.suggestion.SuggestionEntry;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
public class ArgumentTest {
@Test
public void testParseSelf() {
assertEquals("example", Argument.parse(ArgumentType.String("example")));
assertEquals(55, Argument.parse(ArgumentType.Integer("55")));
}
@Test
public void testCallback() {
var arg = ArgumentType.String("id");
assertFalse(arg.hasErrorCallback());
arg.setCallback((sender, exception) -> {});
assertTrue(arg.hasErrorCallback());
}
@Test
public void testDefaultValue() {
var arg = ArgumentType.String("id");
assertFalse(arg.isOptional());
arg.setDefaultValue("default value");
assertTrue(arg.isOptional());
assertEquals("default value", arg.getDefaultValue().get());
}
@Test
public void testSuggestionCallback() {
var arg = ArgumentType.String("id");
assertFalse(arg.hasSuggestion());
arg.setSuggestionCallback((sender, context, suggestion) -> suggestion.addEntry(new SuggestionEntry("entry")));
assertTrue(arg.hasSuggestion());
Suggestion suggestion = new Suggestion("input", 2, 4);
arg.getSuggestionCallback().apply(new ServerSender(), new CommandContext("input"), suggestion);
assertEquals(suggestion.getEntries(), List.of(new SuggestionEntry("entry")));
}
}

View File

@ -0,0 +1,539 @@
package net.minestom.server.command;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.Style;
import net.kyori.adventure.text.format.TextDecoration;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import net.minestom.server.command.builder.CommandContext;
import net.minestom.server.command.builder.arguments.ArgumentEnum;
import net.minestom.server.command.builder.arguments.ArgumentType;
import net.minestom.server.command.builder.exception.ArgumentSyntaxException;
import net.minestom.server.coordinate.Vec;
import net.minestom.server.entity.EntityType;
import net.minestom.server.instance.block.Block;
import net.minestom.server.item.Enchantment;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import net.minestom.server.particle.Particle;
import net.minestom.server.potion.PotionEffect;
import net.minestom.server.tag.Tag;
import net.minestom.server.utils.location.RelativeVec;
import net.minestom.server.utils.math.FloatRange;
import net.minestom.server.utils.math.IntRange;
import net.minestom.server.utils.time.TimeUnit;
import org.jglrxavpok.hephaistos.nbt.NBT;
import org.junit.jupiter.api.Test;
import java.time.Duration;
import java.util.List;
import java.util.UUID;
import static org.junit.jupiter.api.Assertions.*;
public class ArgumentTypeTest {
@Test
public void testArgumentEnchantment() {
var arg = ArgumentType.Enchantment("enchantment");
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("minecraft:invalid_enchantment"));
assertNotEquals(Enchantment.RESPIRATION, arg.parse(Enchantment.SWEEPING.namespace().asString()));
assertEquals(Enchantment.MENDING, arg.parse(Enchantment.MENDING.namespace().asString()));
assertEquals("Enchantment<enchantment>", arg.toString());
}
@Test
public void testArgumentEntityType() {
var arg = ArgumentType.EntityType("entity_type");
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("minecraft:invalid_entity_type"));
assertNotEquals(EntityType.ARMOR_STAND, arg.parse(EntityType.HUSK.namespace().asString()));
assertEquals(EntityType.PLAYER, arg.parse(EntityType.PLAYER.namespace().asString()));
assertEquals("EntityType<entity_type>", arg.toString());
}
@Test
public void testArgumentParticle() {
var arg = ArgumentType.Particle("particle");
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("minecraft:invalid_particle"));
assertNotEquals(Particle.BLOCK, arg.parse(Particle.CAMPFIRE_SIGNAL_SMOKE.namespace().asString()));
assertEquals(Particle.TOTEM_OF_UNDYING, arg.parse(Particle.TOTEM_OF_UNDYING.namespace().asString()));
assertEquals("Particle<particle>", arg.toString());
}
@Test
public void testArgumentPotionEffect() {
var arg = ArgumentType.Potion("potion");
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("minecraft:invalid_potion"));
assertNotEquals(PotionEffect.SPEED, arg.parse(PotionEffect.JUMP_BOOST.namespace().asString()));
assertEquals(PotionEffect.INSTANT_DAMAGE, arg.parse(PotionEffect.INSTANT_DAMAGE.namespace().asString()));
assertEquals("Potion<potion>", arg.toString());
}
@Test
public void testArgumentBlockState() {
var arg = ArgumentType.BlockState("block_state");
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("minecraft:invalid_block[invalid_property=invalid_key]"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("minecraft:stone[invalid_property=invalid_key]"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("minecraft:kelp[age=invalid_key]"));
assertEquals(Block.COBBLESTONE, arg.parse("minecraft:cobblestone"));
assertEquals(Block.KELP.withProperty("age", "14"), arg.parse("minecraft:kelp[age=14]"));
assertNotEquals(Block.KELP.withProperty("age", "15"), arg.parse("minecraft:kelp[age=14]"));
assertNotEquals(Block.ATTACHED_MELON_STEM, arg.parse("minecraft:cobblestone"));
assertEquals("BlockState<block_state>", arg.toString());
}
@Test
public void testArgumentColor() {
var arg = ArgumentType.Color("color");
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("invalid_color"));
assertNotEquals(Style.style(NamedTextColor.AQUA), arg.parse("blue"));
assertEquals(Style.style(NamedTextColor.DARK_PURPLE), arg.parse("dark_purple"));
assertEquals(Style.empty(), arg.parse("reset"));
assertEquals("Color<color>", arg.toString());
}
@Test
public void testArgumentComponent() {
var arg = ArgumentType.Component("component");
var component1 = Component.text("Example text", NamedTextColor.DARK_AQUA);
var component2 = Component.text("Other example text", Style.style(TextDecoration.OBFUSCATED));
var json1 = GsonComponentSerializer.gson().serialize(component1);
var json2 = GsonComponentSerializer.gson().serialize(component2);
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("invalid component"));
assertNotEquals(component1, arg.parse(json2));
assertEquals(component1, arg.parse(json1));
assertEquals("Other example text", PlainTextComponentSerializer.plainText().serialize(arg.parse(json2)));
assertEquals("Component<component>", arg.toString());
}
@Test
public void testArgumentEntity() {
var arg = ArgumentType.Entity("entity");
assertDoesNotThrow(() -> arg.parse("@a"));
assertDoesNotThrow(() -> arg.parse("@p"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("@x"));
assertDoesNotThrow(() -> arg.parse("@e[type=sheep]"));
assertDoesNotThrow(() -> arg.parse("@e[type=!cow]"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("@e[type=invalid_entity]"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("@e[type=!invalid_entity_two]"));
assertDoesNotThrow(() -> arg.parse("@e[gamemode=creative]"));
assertDoesNotThrow(() -> arg.parse("@e[gamemode=!survival]"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("@e[gamemode=invalid_gamemode]"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("@e[gamemode=!invalid_gamemode_2]"));
assertDoesNotThrow(() -> arg.parse("@e[limit=500]"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("@e[limit=-500]"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("@e[limit=invalid_integer]"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("@e[limit=2147483648]"));
assertDoesNotThrow(() -> arg.parse("@e[sort=nearest]"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("@e[sort=invalid_sort]"));
assertDoesNotThrow(() -> arg.parse("@e[level=55]"));
assertDoesNotThrow(() -> arg.parse("@e[level=100..500]"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("@e[level=20-50]"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("@e[level=2147483648]"));
assertDoesNotThrow(() -> arg.parse("@e[distance=500]"));
assertDoesNotThrow(() -> arg.parse("@e[distance=50..150]"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("@e[distance=-500-500]"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("@e[distance=2147483648]"));
assertEquals("Entities<entity>", arg.toString());
}
@Test
public void testArgumentFloatRange() {
var arg = ArgumentType.FloatRange("float_range");
assertEquals(new FloatRange(0f, 50f), arg.parse("0..50"));
assertEquals(new FloatRange(0f, 0f), arg.parse("0..0"));
assertEquals(new FloatRange(-50f, 0f), arg.parse("-50..0"));
assertEquals(new FloatRange(-Float.MAX_VALUE, 50f), arg.parse("..50"));
assertEquals(new FloatRange(0f, Float.MAX_VALUE), arg.parse("0.."));
assertEquals(new FloatRange(-Float.MAX_VALUE, Float.MAX_VALUE), arg.parse("-3.4028235E38..3.4028235E38"));
assertEquals(new FloatRange(0.5f, 24f), arg.parse("0.5..24"));
assertEquals(new FloatRange(12f, 45.6f), arg.parse("12..45.6"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse(".."));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("0..50.."));
assertEquals("FloatRange<float_range>", arg.toString());
}
@Test
public void testArgumentIntRange() {
var arg = ArgumentType.IntRange("int_range");
assertEquals(new IntRange(0, 50), arg.parse("0..50"));
assertEquals(new IntRange(0, 0), arg.parse("0..0"));
assertEquals(new IntRange(-50, 0), arg.parse("-50..0"));
assertEquals(new IntRange(Integer.MIN_VALUE, 50), arg.parse("..50"));
assertEquals(new IntRange(0, Integer.MAX_VALUE), arg.parse("0.."));
assertEquals(new IntRange(Integer.MIN_VALUE, Integer.MAX_VALUE), arg.parse("-2147483648..2147483647"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse(".."));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("-2147483649..2147483647"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("-2147483648..2147483648"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("0..50.."));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("0.5..24"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("12..45.6"));
assertEquals("IntRange<int_range>", arg.toString());
}
@Test
public void testArgumentItemStack() {
var arg = ArgumentType.ItemStack("item_stack");
assertEquals(ItemStack.AIR, arg.parse("air"));
assertEquals(ItemStack.of(Material.GLASS_PANE).withTag(Tag.String("tag"), "value"), arg.parse("glass_pane{tag:value}"));
assertEquals("ItemStack<item_stack>", arg.toString());
}
@Test
public void testArgumentNbtCompoundTag() {
var arg = ArgumentType.NbtCompound("nbt_compound");
assertEquals(NBT.Compound(mut -> mut.put("long_array", NBT.LongArray(12, 49, 119))), arg.parse("{\"long_array\":[L;12L,49L,119L]}"));
assertEquals(NBT.Compound(mut -> mut.put("nested", NBT.Compound(mut2 ->
mut2.put("complex", NBT.IntArray(124, 999, 33256))
))
), arg.parse("{\"nested\": {\"complex\": [I;124,999,33256]}}"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("string"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("\"string\""));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("44"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("[I;11,49,33]"));
assertEquals("NbtCompound<nbt_compound>", arg.toString());
}
@Test
public void testArgumentNbtTag() {
var arg = ArgumentType.NBT("nbt");
assertEquals(NBT.String("string"), arg.parse("string"));
assertEquals(NBT.String("string"), arg.parse("\"string\""));
assertEquals(NBT.Int(44), arg.parse("44"));
assertEquals(NBT.IntArray(11, 49, 33), arg.parse("[I;11,49,33]"));
assertEquals(NBT.Compound(mut -> mut.put("long_array", NBT.LongArray(12, 49, 119))), arg.parse("{\"long_array\":[L;12L,49L,119L]}"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("\"unbalanced string"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("dd}"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("{unquoted: string)}"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("{\"array\": [D;123L,5L]}"));
assertEquals("NBT<nbt>", arg.toString());
}
@Test
public void testArgumentResourceLocation() {
var arg = ArgumentType.ResourceLocation("resource_location");
assertEquals("minecraft:resource_location_example", arg.parse("minecraft:resource_location_example"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("minecraft:invalid resource location"));
assertEquals("ResourceLocation<resource_location>", arg.toString());
}
@Test
public void testArgumentTime() {
var arg = ArgumentType.Time("time");
assertEquals(Duration.of(20, TimeUnit.SERVER_TICK), arg.parse("20"));
assertEquals(Duration.of(40, TimeUnit.SERVER_TICK), arg.parse("40t"));
assertEquals(Duration.of(60, TimeUnit.SECOND), arg.parse("60s"));
assertEquals(Duration.of(80, TimeUnit.DAY), arg.parse("80d"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("100x"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("2147483648t"));
assertEquals("Time<time>", arg.toString());
}
@Test
public void testArgumentUUID() {
var arg = ArgumentType.UUID("uuid");
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("invalid_uuid"));
assertEquals(UUID.fromString("10515090-26f2-49fa-b2ba-9594d4d0451f"), arg.parse("10515090-26f2-49fa-b2ba-9594d4d0451f"));
assertEquals("UUID<uuid>", arg.toString());
}
@Test
public void testArgumentDouble() {
var arg = ArgumentType.Double("double");
assertEquals(2564d, arg.parse("2564"));
assertEquals(-591.981d, arg.parse("-591.981"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("-5.5.52"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("++2.99"));
assertEquals("Double<double>", arg.toString());
}
@Test
public void testArgumentFloat() {
var arg = ArgumentType.Float("float");
assertEquals(2564f, arg.parse("2564"));
assertEquals(-591.981f, arg.parse("-591.981"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("-5.5.52"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("++2.99"));
assertEquals("Float<float>", arg.toString());
}
@Test
public void testArgumentInteger() {
var arg = ArgumentType.Integer("integer");
assertEquals(2564, arg.parse("2564"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("256.4"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("2147483648"));
assertEquals("Integer<integer>", arg.toString());
}
@Test
public void testArgumentLong() {
var arg = ArgumentType.Long("long");
assertEquals(2564, arg.parse("2564"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("256.4"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("9223372036854775808"));
assertEquals("Long<long>", arg.toString());
}
@Test
public void testArgumentRelativeBlockPosition() {
var arg = ArgumentType.RelativeBlockPosition("relative_block_position");
var vec = new Vec(-3, 14, 255);
assertEquals(new RelativeVec(vec, RelativeVec.CoordinateType.ABSOLUTE, false, false, false), arg.parse("-3 14 +255"));
assertEquals(new RelativeVec(vec, RelativeVec.CoordinateType.RELATIVE, true, false, false), arg.parse("~-3 14 +255"));
assertEquals(new RelativeVec(vec, RelativeVec.CoordinateType.ABSOLUTE, false, true, false), arg.parse("-3 ~14 +255"));
assertEquals(new RelativeVec(vec, RelativeVec.CoordinateType.ABSOLUTE, false, false, true), arg.parse("-3 14 ~+255"));
assertEquals(new RelativeVec(vec, RelativeVec.CoordinateType.RELATIVE, true, true, true), arg.parse("~-3 ~14 ~+255"));
assertEquals(new RelativeVec(vec, RelativeVec.CoordinateType.LOCAL, true, true, true), arg.parse("^-3 ^14 ^+255"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("-3.50 14 +255"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("-3 14.25 +255"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("-3 14 +255.75"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("-3 14 +-255"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("-3 text -255"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("-3 14 ~~+255"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("^-3 ~14 ^+255"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("^-3 14 ^+255"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("1 2"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("1 2 3 4"));
assertEquals("RelativeBlockPosition<relative_block_position>", arg.toString());
}
@Test
public void testArgumentRelativeVec2() {
var arg = ArgumentType.RelativeVec2("relative_vec_2");
var vec = new Vec(-3, 14.25);
assertEquals(new RelativeVec(vec, RelativeVec.CoordinateType.ABSOLUTE, false, false, false), arg.parse("-3 14.25"));
assertEquals(new RelativeVec(vec, RelativeVec.CoordinateType.RELATIVE, true, false, false), arg.parse("~-3 14.25"));
assertEquals(new RelativeVec(vec, RelativeVec.CoordinateType.ABSOLUTE, false, false, true), arg.parse("-3 ~14.25"));
assertEquals(new RelativeVec(vec, RelativeVec.CoordinateType.ABSOLUTE, false, false, true), arg.parse("-3 ~14.25"));
assertEquals(new RelativeVec(vec, RelativeVec.CoordinateType.RELATIVE, true, false, true), arg.parse("~-3 ~14.25"));
assertEquals(new RelativeVec(vec, RelativeVec.CoordinateType.LOCAL, true, false, true), arg.parse("^-3 ^14.25"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("-3 +-14"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("-3 text"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("~~-3 14"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("^-3 ~14"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("^-3 14"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("1"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("1 2 3"));
assertEquals("RelativeVec2<relative_vec_2>", arg.toString());
}
@Test
public void testArgumentRelativeVec3() {
var arg = ArgumentType.RelativeVec3("relative_vec_3");
var vec = new Vec(-3, 14.25, 255);
assertEquals(new RelativeVec(vec, RelativeVec.CoordinateType.ABSOLUTE, false, false, false), arg.parse("-3 14.25 +255"));
assertEquals(new RelativeVec(vec, RelativeVec.CoordinateType.RELATIVE, true, false, false), arg.parse("~-3 14.25 +255"));
assertEquals(new RelativeVec(vec, RelativeVec.CoordinateType.ABSOLUTE, false, true, false), arg.parse("-3 ~14.25 +255"));
assertEquals(new RelativeVec(vec, RelativeVec.CoordinateType.ABSOLUTE, false, false, true), arg.parse("-3 14.25 ~+255"));
assertEquals(new RelativeVec(vec, RelativeVec.CoordinateType.RELATIVE, true, true, true), arg.parse("~-3 ~14.25 ~+255"));
assertEquals(new RelativeVec(vec, RelativeVec.CoordinateType.LOCAL, true, true, true), arg.parse("^-3 ^14.25 ^+255"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("-3 14 +-255"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("-3 text -255"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("-3 14 ~~+255"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("^-3 ~14 ^+255"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("^-3 14 ^+255"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("1 2"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("1 2 3 4"));
assertEquals("RelativeVec3<relative_vec_3>", arg.toString());
}
@Test
public void testArgumentBoolean() {
var arg = ArgumentType.Boolean("boolean");
assertEquals(true, arg.parse("true"));
assertNotEquals(false, arg.parse("true"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("invalid_boolean"));
assertEquals("Boolean<boolean>", arg.toString());
}
@Test
public void testArgumentEnum() {
enum ExampleEnum { FIRST, SECOND, Third, fourth }
var arg = ArgumentType.Enum("enum", ExampleEnum.class);
arg.setFormat(ArgumentEnum.Format.DEFAULT);
assertEquals(ExampleEnum.FIRST, arg.parse("FIRST"));
assertEquals(ExampleEnum.SECOND, arg.parse("SECOND"));
assertEquals(ExampleEnum.Third, arg.parse("Third"));
assertEquals(ExampleEnum.fourth, arg.parse("fourth"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("invalid argument"));
arg.setFormat(ArgumentEnum.Format.UPPER_CASED);
assertEquals(ExampleEnum.FIRST, arg.parse("FIRST"));
assertEquals(ExampleEnum.SECOND, arg.parse("SECOND"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("Third"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("fourth"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("invalid argument"));
arg.setFormat(ArgumentEnum.Format.LOWER_CASED);
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("FIRST"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("SECOND"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("Third"));
assertEquals(ExampleEnum.fourth, arg.parse("fourth"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("invalid argument"));
assertEquals("Enum<enum>", arg.toString());
}
@Test
public void testArgumentGroup() {
var arg = ArgumentType.Group("group", ArgumentType.Integer("integer"), ArgumentType.String("string"), ArgumentType.Double("double"));
System.out.println(arg.parse("1234 abcd 1234.5678"));
// Test normal input
var context1 = arg.parse("1234 1234 1234");
assertEquals(1234, context1.<Integer>get("integer"));
assertEquals("1234", context1.<String>get("string"));
assertEquals(1234.0, context1.<Double>get("double"));
// Test different input + trailing spaces
var context2 = arg.parse("1234 abcd 1234.5678 ");
assertEquals(1234, context2.<Integer>get("integer"));
assertEquals("abcd", context2.<String>get("string"));
assertEquals(1234.5678, context2.<Double>get("double"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse(""));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse(""));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse(""));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("1234.5678 1234 1234.5678"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("1234 1234 abcd"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("1234 1234 "));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("1234"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("1234 abcd 1234.5678 extra"));
}
@Test
public void testArgumentLiteral() {
var arg = ArgumentType.Literal("literal");
assertEquals("literal", arg.parse("literal"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("not_literal"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse(""));
assertEquals("Literal<literal>", arg.toString());
}
@Test
public void testArgumentLoop() {
var arg = ArgumentType.Loop("loop", ArgumentType.String("string"), ArgumentType.String("string2").map(s -> {
throw new IllegalArgumentException("This argument should never be triggered");
}));
assertEquals(List.of("a", "b", "c"), arg.parse("a b c"));
assertEquals(List.of("a", "b"), arg.parse("a b"));
}
@Test
public void testArgumentString() {
var arg = ArgumentType.String("string");
assertEquals("text", arg.parse("text"));
assertEquals("more text", arg.parse("\"more text\""));
assertEquals("more text, but with \"escaped\" quotes", arg.parse("\"more text, but with \\\"escaped\\\" quotes\""));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("\"unclosed quotes"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("\"unescaped \" quotes\""));
assertEquals("String<string>", arg.toString());
}
@Test
public void testArgumentStringArray() {
var arg = ArgumentType.StringArray("string_array");
assertArrayEquals(new String[]{"example", "text"}, arg.parse("example text"));
assertArrayEquals(new String[]{"some", "more", "placeholder", "text"}, arg.parse("some more placeholder text"));
assertArrayEquals(new String[]{""}, arg.parse(""));
assertArrayEquals(new String[0], arg.parse(" "));
assertArrayEquals(new String[0], arg.parse(" "));
assertEquals("StringArray<string_array>", arg.toString());
}
@Test
public void testArgumentWord() {
var arg = ArgumentType.Word("word").from("word1", "word2", "word3");
assertEquals("word1", arg.parse("word1"));
assertEquals("word2", arg.parse("word2"));
assertEquals("word3", arg.parse("word3"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("word"));
assertThrows(ArgumentSyntaxException.class, () -> arg.parse("word4"));
assertEquals("Word<word>", arg.toString());
}
}

View File

@ -0,0 +1,117 @@
package net.minestom.server.command;
import net.minestom.server.command.builder.Command;
import net.minestom.server.command.builder.arguments.Argument;
import net.minestom.server.command.builder.arguments.ArgumentType;
import org.junit.jupiter.api.Test;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import static org.junit.jupiter.api.Assertions.*;
public class CommandExecutionTest {
@Test
public void testAndCommand() {
var manager = new CommandManager();
var command = new Command("and");
manager.register(command);
var bool = new AtomicBoolean(false);
command.addSyntax((sender, context) -> {
boolean bool1 = context.get("bool1");
boolean bool2 = context.get("bool2");
bool.set(bool1 && bool2);
}, ArgumentType.Boolean("bool1"), ArgumentType.Boolean("bool2"));
assertFalse(bool.get());
manager.executeServerCommand("and true true");
assertTrue(bool.get());
manager.executeServerCommand("and false true");
assertFalse(bool.get());
}
@Test
public void testConditionalMessage() {
var manager = new CommandManager();
var command = new Command("allowed", "disallowed");
manager.register(command);
AtomicInteger counter = new AtomicInteger(0);
command.setCondition((sender, commandString) -> {
if (commandString == null) {
return true;
}
var result = commandString.startsWith("allowed");
counter.set(result ? 1 : 0);
return result;
});
command.setDefaultExecutor((sender, context) -> {
});
assertEquals(0, counter.get());
manager.executeServerCommand("allowed");
assertEquals(1, counter.get());
manager.executeServerCommand("disallowed");
assertEquals(0, counter.get());
}
@Test
public void singleInteger() {
List<List<Argument<?>>> args = List.of(
List.of(ArgumentType.Integer("number"))
);
assertSyntax(args, "5", ExpectedExecution.FIRST_SYNTAX);
assertSyntax(args, "5 5", ExpectedExecution.DEFAULT);
assertSyntax(args, "", ExpectedExecution.DEFAULT);
}
private static void assertSyntax(List<List<Argument<?>>> args, String input, ExpectedExecution expected) {
final String commandName = "name";
var manager = new CommandManager();
var command = new Command(commandName);
manager.register(command);
AtomicReference<ExpectedExecution> result = new AtomicReference<>();
command.setDefaultExecutor((sender, context) -> {
if (!result.compareAndSet(null, ExpectedExecution.DEFAULT)) {
fail("Multiple execution: " + result.get());
}
});
int i = ExpectedExecution.FIRST_SYNTAX.ordinal();
for (List<Argument<?>> t : args) {
ExpectedExecution id = ExpectedExecution.values()[i++];
command.addSyntax((sender, context) -> {
if (!result.compareAndSet(null, id)) {
fail("Multiple execution: " + result.get());
}
}, t.toArray(Argument[]::new));
}
final String executeString = commandName + " " + input;
manager.executeServerCommand(executeString);
assertEquals(expected, result.get());
}
enum ExpectedExecution {
DEFAULT,
FIRST_SYNTAX,
SECOND_SYNTAX,
THIRD_SYNTAX
}
}

View File

@ -0,0 +1,86 @@
package net.minestom.server.command;
import net.minestom.server.command.builder.Command;
import net.minestom.server.entity.Player;
import net.minestom.server.network.packet.server.play.DeclareCommandsPacket;
import org.junit.jupiter.api.Test;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
import static org.junit.jupiter.api.Assertions.*;
public class CommandManagerTest {
@Test
public void testCommandRegistration() {
var manager = new CommandManager();
var command = new Command("name1", "name2");
manager.register(command);
assertTrue(manager.commandExists("name1"));
assertTrue(manager.commandExists("name2"));
assertFalse(manager.commandExists("name3"));
manager.unregister(command);
assertFalse(manager.commandExists("name1"));
assertFalse(manager.commandExists("name2"));
assertFalse(manager.commandExists("name3"));
}
@Test
public void testUnknownCommandCallback() {
var manager = new CommandManager();
AtomicBoolean check = new AtomicBoolean(false);
manager.setUnknownCommandCallback((sender, command) -> check.set(true));
manager.register(new Command("valid_command"));
manager.executeServerCommand("valid_command");
assertFalse(check.get());
manager.executeServerCommand("invalid_command");
assertTrue(check.get());
}
@Test
public void testDeclareCommandsPacket() {
var manager = new CommandManager();
var player = new Player(UUID.randomUUID(), "TestPlayer", null) {
@Override
protected void playerConnectionInit() {
}
@Override
public boolean isOnline() {
return false;
}
};
manager.register(new Command("name"));
var packet = manager.createDeclareCommandsPacket(player);
assertEquals(packet.rootIndex(), 0);
assertEquals(packet.nodes().size(), 2);
assertNodeEquals(packet.nodes().get(0), (byte) 0, new int[]{1}, 0, "", "", null, "");
assertNodeEquals(packet.nodes().get(1), (byte) 5, new int[0], 0, "name", "", null, "");
}
private static void assertNodeEquals(DeclareCommandsPacket.Node node, byte flags, int[] children, int redirectedNode,
String name, String parser, byte[] properties, String suggestionsType) {
assertEquals(node.flags, flags);
assertArrayEquals(node.children, children);
assertEquals(node.redirectedNode, redirectedNode);
assertEquals(node.name, name);
assertEquals(node.parser, parser);
assertArrayEquals(node.properties, properties);
assertEquals(node.suggestionsType, suggestionsType);
}
}

View File

@ -0,0 +1,80 @@
package net.minestom.server.command;
import net.kyori.adventure.audience.MessageType;
import net.kyori.adventure.identity.Identity;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.minestom.server.permission.Permission;
import net.minestom.server.tag.TagHandler;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jglrxavpok.hephaistos.nbt.NBTCompound;
import org.junit.jupiter.api.Test;
import java.util.HashSet;
import java.util.Set;
import static org.junit.jupiter.api.Assertions.*;
public class CommandSenderTest {
@Test
public void testSenderPermissions() {
CommandSender sender = new SenderTest();
Permission permission = new Permission("permission.test", new NBTCompound());
assertEquals(sender.getAllPermissions(), Set.of());
sender.addPermission(permission);
assertEquals(sender.getPermission(permission.getPermissionName()), permission);
assertEquals(sender.getAllPermissions(), Set.of(permission));
sender.removePermission(permission.getPermissionName());
assertEquals(sender.getAllPermissions(), Set.of());
}
@Test
public void testMessageSending() {
SenderTest sender = new SenderTest();
assertNull(sender.getMostRecentMessage());
sender.sendMessage("Hey!!");
assertEquals(sender.getMostRecentMessage(), Component.text("Hey!!"));
sender.sendMessage(new String[]{"Message", "Sending", "Test"});
assertEquals(sender.getMostRecentMessage(), Component.text("Test"));
sender.sendMessage(Component.text("Message test!", NamedTextColor.GREEN));
assertEquals(sender.getMostRecentMessage(), Component.text("Message test!", NamedTextColor.GREEN));
}
private static final class SenderTest implements CommandSender {
private final Set<Permission> permissions = new HashSet<>();
private final TagHandler handler = TagHandler.newHandler();
private Component mostRecentMessage = null;
@Override
public @NotNull Set<Permission> getAllPermissions() {
return permissions;
}
@Override
public @NotNull TagHandler tagHandler() {
return handler;
}
@Override
public void sendMessage(@NotNull Identity source, @NotNull Component message, @NotNull MessageType type) {
mostRecentMessage = message;
}
public @Nullable Component getMostRecentMessage() {
return mostRecentMessage;
}
}
}

View File

@ -0,0 +1,55 @@
package net.minestom.server.command;
import net.minestom.server.command.builder.Command;
import net.minestom.server.command.builder.CommandContext;
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.Test;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import static org.junit.jupiter.api.Assertions.*;
public class CommandTest {
@Test
public void testNames() {
Command command = new Command("name1", "name2", "name3");
assertEquals("name1", command.getName());
assertArrayEquals(new String[]{"name2", "name3"}, command.getAliases());
// command#getNames does not have any order guarantee, so that cannot be relied on
assertEquals(Set.of("name1", "name2", "name3"), Set.of(command.getNames()));
assertTrue(Command.isValidName(command, "name1"));
assertTrue(Command.isValidName(command, "name2"));
}
@Test
public void testGlobalListener() {
var manager = new CommandManager();
AtomicBoolean hasRun = new AtomicBoolean(false);
var command = new Command("command") {
@Override
public void globalListener(@NotNull CommandSender sender, @NotNull CommandContext context, @NotNull String command) {
hasRun.set(true);
context.setArg("key", "value", "value");
}
};
manager.register(command);
AtomicBoolean checkSet = new AtomicBoolean(false);
command.setDefaultExecutor((sender, context) -> checkSet.set("value".equals(context.get("key"))));
manager.executeServerCommand("command");
assertTrue(hasRun.get());
assertTrue(checkSet.get());
}
}

View File

@ -0,0 +1,69 @@
package net.minestom.server.command;
import net.minestom.server.command.builder.Command;
import org.junit.jupiter.api.Test;
import java.util.concurrent.atomic.AtomicBoolean;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class SubcommandTest {
@Test
public void testSubCommands() {
var manager = new CommandManager();
var parent = new Command("parent");
var child = new Command("child");
parent.addSubcommand(child);
manager.register(parent);
AtomicBoolean parentExecuted = new AtomicBoolean(false);
AtomicBoolean childExecuted = new AtomicBoolean(false);
parent.setDefaultExecutor((sender, context) -> parentExecuted.set(true));
child.setDefaultExecutor((sender, context) -> childExecuted.set(true));
manager.executeServerCommand("parent child");
assertFalse(parentExecuted.get());
assertTrue(childExecuted.get());
}
@Test
public void testSubCommandConditions() {
var manager = new CommandManager();
var parent = new Command("parent");
var child = new Command("child");
parent.addSubcommand(child);
manager.register(parent);
AtomicBoolean parentConditionTriggered = new AtomicBoolean(false);
AtomicBoolean childConditionTriggered = new AtomicBoolean(false);
AtomicBoolean parentExecuted = new AtomicBoolean(false);
AtomicBoolean childExecuted = new AtomicBoolean(false);
parent.setCondition((sender, commandString) -> {
parentConditionTriggered.set(true);
return true; // Return true so the child's condition has a chance to get tested
});
child.setCondition((sender, commandString) -> {
childConditionTriggered.set(true);
return false;
});
parent.setDefaultExecutor((sender, context) -> parentExecuted.set(true));
child.setDefaultExecutor((sender, context) -> childExecuted.set(true));
manager.executeServerCommand("parent child");
assertTrue(parentConditionTriggered.get());
assertTrue(childConditionTriggered.get());
assertFalse(parentExecuted.get());
assertFalse(childExecuted.get());
}
}