mirror of
https://github.com/EssentialsX/Essentials.git
synced 2024-12-31 21:48:31 +01:00
Implement aliases, child validation and tree build tests
This commit is contained in:
parent
b8e33d995e
commit
c18f54bed1
@ -5,7 +5,10 @@ import org.bukkit.Server;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
public abstract class EssentialsCommandNode<T> {
|
public abstract class EssentialsCommandNode<T> {
|
||||||
private final ArrayList<EssentialsCommandNode<T>> childNodes = new ArrayList<>();
|
private final ArrayList<EssentialsCommandNode<T>> childNodes = new ArrayList<>();
|
||||||
@ -37,6 +40,10 @@ public abstract class EssentialsCommandNode<T> {
|
|||||||
throw new NoChargeException();
|
throw new NoChargeException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected List<EssentialsCommandNode<T>> getChildNodes() {
|
||||||
|
return Collections.unmodifiableList(childNodes);
|
||||||
|
}
|
||||||
|
|
||||||
public abstract boolean matches(final WalkContext<T> context);
|
public abstract boolean matches(final WalkContext<T> context);
|
||||||
|
|
||||||
public static Root<CommandSource> root(final Initializer<CommandSource> initializer) {
|
public static Root<CommandSource> root(final Initializer<CommandSource> initializer) {
|
||||||
@ -54,8 +61,8 @@ public abstract class EssentialsCommandNode<T> {
|
|||||||
this.node = node;
|
this.node = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void literal(final String name, final Initializer<T> initializer) {
|
public void literal(final String name, final Initializer<T> initializer, final String... aliases) {
|
||||||
node.childNodes.add(new Literal<>(name, initializer));
|
node.childNodes.add(new Literal<>(name, aliases, initializer));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void execute(final RunHandler<T> runHandler) {
|
public void execute(final RunHandler<T> runHandler) {
|
||||||
@ -112,6 +119,9 @@ public abstract class EssentialsCommandNode<T> {
|
|||||||
public static class Root<T> extends EssentialsCommandNode<T> {
|
public static class Root<T> extends EssentialsCommandNode<T> {
|
||||||
protected Root(Initializer<T> initializer) {
|
protected Root(Initializer<T> initializer) {
|
||||||
super(initializer);
|
super(initializer);
|
||||||
|
if (getChildNodes().isEmpty()) {
|
||||||
|
throw new RuntimeException("Root nodes must be initialised with at least one child");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -130,14 +140,24 @@ public abstract class EssentialsCommandNode<T> {
|
|||||||
|
|
||||||
public static class Literal<T> extends EssentialsCommandNode<T> {
|
public static class Literal<T> extends EssentialsCommandNode<T> {
|
||||||
private final String name;
|
private final String name;
|
||||||
|
private final HashSet<String> aliases;
|
||||||
|
|
||||||
protected Literal(String name, Initializer<T> initializer) {
|
protected Literal(String name, String[] aliases, Initializer<T> initializer) {
|
||||||
super(initializer);
|
super(initializer);
|
||||||
|
if (getChildNodes().isEmpty()) {
|
||||||
|
throw new RuntimeException("Literal nodes must be initialised with at least one child (node name: " + name + ")");
|
||||||
|
}
|
||||||
|
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
this.aliases = new HashSet<>();
|
||||||
|
this.aliases.add(name.toLowerCase(Locale.ROOT));
|
||||||
|
for (final String alias : aliases) {
|
||||||
|
this.aliases.add(alias.toLowerCase(Locale.ROOT));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean matches(WalkContext<T> context) {
|
public boolean matches(WalkContext<T> context) {
|
||||||
return context.args.length > 0 && context.args[0].equalsIgnoreCase(name);
|
return context.args.length > 0 && aliases.contains(context.args[0].toLowerCase(Locale.ROOT));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -6,13 +6,13 @@ import org.junit.jupiter.api.BeforeEach;
|
|||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.function.Executable;
|
import org.junit.jupiter.api.function.Executable;
|
||||||
import org.mockito.InOrder;
|
import org.mockito.InOrder;
|
||||||
import org.mockito.Mockito;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
import static org.mockito.Mockito.*;
|
import static org.mockito.Mockito.inOrder;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
class EssentialsCommandNodeTest {
|
class EssentialsCommandNodeTest {
|
||||||
private FakeServer fakeServer;
|
private FakeServer fakeServer;
|
||||||
@ -27,21 +27,18 @@ class EssentialsCommandNodeTest {
|
|||||||
consoleSource = mock(CommandSource.class);
|
consoleSource = mock(CommandSource.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
EssentialsCommandNode.Root<CommandSource> buildCommonTree() {
|
||||||
void testNonTerminateThrow() {
|
return EssentialsCommandNode.root(root -> {
|
||||||
final EssentialsCommandNode.Root<CommandSource> rootNode = EssentialsCommandNode.root(root -> {
|
root.literal("hello", hello -> hello.execute(ctx -> {
|
||||||
root.literal("hello", hello -> {
|
if (ctx.args().length < 1) {
|
||||||
hello.execute(ctx -> {
|
ctx.sender().sendMessage("hello to who?");
|
||||||
if (ctx.args().length < 1) {
|
} else if (ctx.args().length < 2) {
|
||||||
ctx.sender().sendMessage("hello to who?");
|
ctx.sender().sendMessage("hi there " + ctx.args()[0]);
|
||||||
} else if (ctx.args().length < 2) {
|
} else {
|
||||||
ctx.sender().sendMessage("hi there " + ctx.args()[0]);
|
ctx.sender().sendMessage("woah hi " + String.join(" and ", ctx.args()));
|
||||||
} else {
|
}
|
||||||
ctx.sender().sendMessage("woah hi " + String.join(" and ", ctx.args()));
|
System.out.println(Arrays.toString(ctx.args()));
|
||||||
}
|
}));
|
||||||
System.out.println(Arrays.toString(ctx.args()));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
root.literal("bye", bye -> {
|
root.literal("bye", bye -> {
|
||||||
bye.literal("forever just kidding", bye1 -> { bye1.execute(ctx -> { throw new RuntimeException("this shouldn't happen"); }); });
|
bye.literal("forever just kidding", bye1 -> { bye1.execute(ctx -> { throw new RuntimeException("this shouldn't happen"); }); });
|
||||||
bye.literal("forever", bye2 -> bye2.execute(ctx -> ctx.sender().sendMessage(":((")));
|
bye.literal("forever", bye2 -> bye2.execute(ctx -> ctx.sender().sendMessage(":((")));
|
||||||
@ -53,8 +50,23 @@ class EssentialsCommandNodeTest {
|
|||||||
ctx.sender().sendMessage("wait you can't leave");
|
ctx.sender().sendMessage("wait you can't leave");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
}, "farewell", "tschuss");
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testBuild() {
|
||||||
|
assertThrows(RuntimeException.class, () -> EssentialsCommandNode.root(root -> {}), "empty root");
|
||||||
|
assertThrows(RuntimeException.class, () -> EssentialsCommandNode.root(root -> {
|
||||||
|
root.literal("potato", potato -> {});
|
||||||
|
}), "empty literal");
|
||||||
|
|
||||||
|
assertDoesNotThrow(this::buildCommonTree, "build complete tree");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testEval() {
|
||||||
|
final EssentialsCommandNode.Root<CommandSource> rootNode = buildCommonTree();
|
||||||
|
|
||||||
assertThrows(NoChargeException.class, () -> rootNode.run(fakeServer, playerSource, "test", new String[]{""}), "wrongly parsed empty arg");
|
assertThrows(NoChargeException.class, () -> rootNode.run(fakeServer, playerSource, "test", new String[]{""}), "wrongly parsed empty arg");
|
||||||
assertThrows(NoChargeException.class, () -> rootNode.run(fakeServer, playerSource, "test", new String[]{"wilkommen"}), "wrongly parsed unknown literal"); // wrongly parsed German
|
assertThrows(NoChargeException.class, () -> rootNode.run(fakeServer, playerSource, "test", new String[]{"wilkommen"}), "wrongly parsed unknown literal"); // wrongly parsed German
|
||||||
@ -63,17 +75,17 @@ class EssentialsCommandNodeTest {
|
|||||||
Executable playerHelloOneArg = () -> rootNode.run(fakeServer, playerSource, "test", new String[]{"hello", "world"});
|
Executable playerHelloOneArg = () -> rootNode.run(fakeServer, playerSource, "test", new String[]{"hello", "world"});
|
||||||
Executable playerHelloManyArgs = () -> rootNode.run(fakeServer, playerSource, "test", new String[]{"hello", "jroy", "pop", "lax", "evident"});
|
Executable playerHelloManyArgs = () -> rootNode.run(fakeServer, playerSource, "test", new String[]{"hello", "jroy", "pop", "lax", "evident"});
|
||||||
Executable playerBye = () -> rootNode.run(fakeServer, playerSource, "test", new String[]{"bye", "legacy", "code"});
|
Executable playerBye = () -> rootNode.run(fakeServer, playerSource, "test", new String[]{"bye", "legacy", "code"});
|
||||||
Executable consoleBye = () -> rootNode.run(fakeServer, consoleSource, "test", new String[]{"bye", "player", "data"});
|
Executable consoleFarewell = () -> rootNode.run(fakeServer, consoleSource, "test", new String[]{"fAREWELL", "player", "data"});
|
||||||
Executable consoleByeForeverJk = () -> rootNode.run(fakeServer, consoleSource, "test", new String[]{"bye", "forever", "just", "kidding"});
|
Executable consoleByeForeverJk = () -> rootNode.run(fakeServer, consoleSource, "test", new String[]{"bye", "forever", "just", "kidding"});
|
||||||
|
|
||||||
assertDoesNotThrow(playerHelloNoArgs, "parsing first level no-arg command");
|
assertDoesNotThrow(playerHelloNoArgs, "parsing first level no-arg command");
|
||||||
assertDoesNotThrow(playerHelloOneArg, "parsing first level 1 arg command");
|
assertDoesNotThrow(playerHelloOneArg, "parsing first level 1 arg command");
|
||||||
assertDoesNotThrow(playerHelloManyArgs, "parsing first level multi-arg command");
|
assertDoesNotThrow(playerHelloManyArgs, "parsing first level multi-arg command");
|
||||||
assertDoesNotThrow(playerBye);
|
assertDoesNotThrow(playerBye);
|
||||||
assertDoesNotThrow(consoleBye);
|
assertDoesNotThrow(consoleFarewell, "parsing with literal alias");
|
||||||
assertDoesNotThrow(consoleByeForeverJk);
|
assertDoesNotThrow(consoleByeForeverJk);
|
||||||
|
|
||||||
InOrder ordered = Mockito.inOrder(playerSource, consoleSource);
|
InOrder ordered = inOrder(playerSource, consoleSource);
|
||||||
ordered.verify(playerSource).sendMessage("hello to who?");
|
ordered.verify(playerSource).sendMessage("hello to who?");
|
||||||
ordered.verify(playerSource).sendMessage("hi there world");
|
ordered.verify(playerSource).sendMessage("hi there world");
|
||||||
ordered.verify(playerSource).sendMessage("woah hi jroy and pop and lax and evident");
|
ordered.verify(playerSource).sendMessage("woah hi jroy and pop and lax and evident");
|
||||||
|
Loading…
Reference in New Issue
Block a user