SteamWar/SpigotCore
Archiviert
13
0

CMD #141

Zusammengeführt
YoyoNow hat 29 Commits von CMD nach master 2021-12-12 15:58:20 +01:00 zusammengeführt
13 geänderte Dateien mit 508 neuen und 47 gelöschten Zeilen
Nur Änderungen aus Commit 13b6dcd74b werden angezeigt - Alle Commits anzeigen

Datei anzeigen

@ -40,6 +40,16 @@ sourceSets {
exclude '**/*.java', '**/*.kt'
}
}
test {
java {
srcDirs = ['testsrc']
}
resources {
srcDirs = ['testsrc']
exclude '**/*.java', '**/*.kt'
}
}
}
dependencies {
@ -51,6 +61,12 @@ dependencies {
testCompileOnly 'org.projectlombok:lombok:1.18.22'
annotationProcessor 'org.projectlombok:lombok:1.18.22'
testAnnotationProcessor 'org.projectlombok:lombok:1.18.22'
testImplementation files("${project.rootDir}/lib/Spigot-1.15.jar")
testImplementation files("${project.rootDir}/lib/WorldEdit-1.12.jar")
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.hamcrest:hamcrest:2.2'
}
processResources {

Datei anzeigen

@ -19,7 +19,7 @@
package de.steamwar.command;
public class CommandParseException extends Exception {
public class CommandParseException extends RuntimeException {
public CommandParseException() {
}

Datei anzeigen

@ -0,0 +1,119 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2020 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command;
import lombok.AllArgsConstructor;
import org.bukkit.command.CommandSender;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.List;
public class CommandPart {
private static final String[] EMPTY_ARRAY = new String[0];
@AllArgsConstructor
private static class CheckArgumentResult {
private final boolean success;
private final Object value;
}
private TypeMapper<?> typeMapper;
private GuardChecker guard;
private Class<?> varArgType = null;
private String optional = null;
private boolean help;
private CommandPart next = null;
CommandPart(TypeMapper<?> typeMapper, GuardChecker guard, Class<?> varArgType, String optional, boolean help) {
this.typeMapper = typeMapper;
this.guard = guard;
if (optional != null && varArgType != null) {
throw new IllegalArgumentException("A vararg part can't have an optional part!");
}
this.varArgType = varArgType;
this.optional = optional;
this.help = help;
}
void setNext(CommandPart next) {
if (varArgType != null) {
throw new IllegalArgumentException("There can't be a next part if this is a vararg part!");
}
this.next = next;
}
void generateArgumentArray(List<Object> current, CommandSender commandSender, String[] args, int startIndex) {
if (startIndex >= args.length) {
return;
}
if (varArgType != null) {
Object array = Array.newInstance(varArgType, args.length - startIndex);
for (int i = startIndex; i < args.length; i++) {
CheckArgumentResult validArgument = checkArgument(help ? GuardCheckType.HELP_COMMAND : GuardCheckType.COMMAND, commandSender, args, i);
if (!validArgument.success) {
throw new CommandParseException();
}
Array.set(array, i - startIndex, validArgument.value);
}
current.add(array);
return;
}
CheckArgumentResult validArgument = checkArgument(help ? GuardCheckType.HELP_COMMAND : GuardCheckType.COMMAND, commandSender, args, startIndex);
if (!validArgument.success && optional == null) {
throw new CommandParseException();
}
if (optional != null) {
current.add(typeMapper.map(commandSender, EMPTY_ARRAY, optional));
next.generateArgumentArray(current, commandSender, args, startIndex);
return;
}
current.add(validArgument.value);
next.generateArgumentArray(current, commandSender, args, startIndex + 1);
}
void generateTabComplete(List<String> current, CommandSender commandSender, String[] args, int startIndex) {
}
private CheckArgumentResult checkArgument(GuardCheckType guardCheckType, CommandSender commandSender, String[] args, int index) {
try {
Object value = typeMapper.map(commandSender, Arrays.copyOf(args, index - 1), args[index]);
if (guard != null) {
GuardResult guardResult = guard.guard(commandSender, GuardCheckType.TAB_COMPLETE, Arrays.copyOf(args, index - 1), args[index]);
switch (guardResult) {
case ALLOWED:
return new CheckArgumentResult(true, value);
case DENIED:
throw new CommandNoHelpException();
case DENIED_WITH_HELP:
default:
return new CheckArgumentResult(false, null);
}
}
return new CheckArgumentResult(true, value);
} catch (Exception e) {
return new CheckArgumentResult(false, null);
}
}
}

Datei anzeigen

@ -0,0 +1,63 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2020 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandMap;
import org.bukkit.command.SimpleCommandMap;
import java.lang.reflect.Field;
import java.util.Map;
class CommandRegistering {
private static final CommandMap commandMap;
private static final Map<String, Command> knownCommandMap;
static {
try {
final Field commandMapField = Bukkit.getServer().getClass().getDeclaredField("commandMap");
commandMapField.setAccessible(true);
commandMap = (CommandMap) commandMapField.get(Bukkit.getServer());
} catch (NoSuchFieldException | IllegalAccessException exception) {
Bukkit.shutdown();
throw new SecurityException("Oh shit. Commands cannot be registered.", exception);
}
try {
final Field knownCommandsField = SimpleCommandMap.class.getDeclaredField("knownCommands");
knownCommandsField.setAccessible(true);
knownCommandMap = (Map<String, Command>) knownCommandsField.get(commandMap);
} catch (NoSuchFieldException | IllegalAccessException exception) {
Bukkit.shutdown();
throw new SecurityException("Oh shit. Commands cannot be registered.", exception);
}
}
static void unregister(Command command) {
knownCommandMap.remove(command.getName());
command.getAliases().forEach(knownCommandMap::remove);
command.unregister(commandMap);
}
static void register(Command command) {
commandMap.register("steamwar", command);
}
}

Datei anzeigen

@ -61,13 +61,7 @@ public abstract class SWCommand {
if (!initialized) {
createMapping();
}
try {
if (!commandList.stream().anyMatch(s -> s.invoke(sender, args))) {
commandHelpList.stream().anyMatch(s -> s.invoke(sender, args));
}
} catch (CommandNoHelpException e) {
// Ignored
}
SWCommand.this.execute(sender, alias, args);
return false;
}
@ -76,21 +70,52 @@ public abstract class SWCommand {
if (!initialized) {
createMapping();
}
String string = args[args.length - 1].toLowerCase();
return commandList.stream()
.filter(s -> !s.noTabComplete)
.map(s -> s.tabComplete(sender, args))
.filter(Objects::nonNull)
.flatMap(Collection::stream)
.filter(s -> !s.isEmpty())
.filter(s -> s.toLowerCase().startsWith(string))
.collect(Collectors.toList());
return SWCommand.this.tabComplete(sender, alias, args);
}
};
unregister();
register();
}
// This is used for the tests!
SWCommand(boolean noRegister, String command, String... aliases) {
this.command = new Command(command, "", "/" + command, Arrays.asList(aliases)) {
@Override
public boolean execute(CommandSender sender, String alias, String[] args) {
SWCommand.this.execute(sender, alias, args);
return false;
}
@Override
public List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
return SWCommand.this.tabComplete(sender, alias, args);
}
};
createMapping();
}
void execute(CommandSender sender, String alias, String[] args) {
try {
if (!commandList.stream().anyMatch(s -> s.invoke(sender, args))) {
commandHelpList.stream().anyMatch(s -> s.invoke(sender, args));
}
} catch (CommandNoHelpException e) {
// Ignored
}
}
List<String> tabComplete(CommandSender sender, String alias, String[] args) throws IllegalArgumentException {
String string = args[args.length - 1].toLowerCase();
return commandList.stream()
.filter(s -> !s.noTabComplete)
.map(s -> s.tabComplete(sender, args))
.filter(Objects::nonNull)
.flatMap(Collection::stream)
.filter(s -> !s.isEmpty())
.filter(s -> s.toLowerCase().startsWith(string))
.collect(Collectors.toList());
}
private synchronized void createMapping() {
List<Method> methods = methods();
for (Method method : methods) {
@ -219,13 +244,11 @@ public abstract class SWCommand {
}
public void unregister() {
SWCommandUtils.knownCommandMap.remove(command.getName());
command.getAliases().forEach(SWCommandUtils.knownCommandMap::remove);
command.unregister(SWCommandUtils.commandMap);
CommandRegistering.unregister(command);
}
public void register() {
SWCommandUtils.commandMap.register("steamwar", this.command);
CommandRegistering.register(command);
}
@Register(help = true)
@ -332,6 +355,12 @@ public abstract class SWCommand {
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
protected @interface StaticValue {
String[] value() default {};
String[] value();
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
protected @interface OptionalValue {
String defaultValue(); // Will pe parsed against the TypeMapper specified by the parameter or annotation
}
}

Datei anzeigen

@ -91,28 +91,6 @@ public class SWCommandUtils {
MAPPER_FUNCTIONS.put(alternativeClazz.getTypeName(), mapper);
}
static final CommandMap commandMap;
static final Map<String, Command> knownCommandMap;
static {
try {
final Field commandMapField = Bukkit.getServer().getClass().getDeclaredField("commandMap");
commandMapField.setAccessible(true);
commandMap = (CommandMap) commandMapField.get(Bukkit.getServer());
} catch (NoSuchFieldException | IllegalAccessException exception) {
Bukkit.shutdown();
throw new SecurityException("Oh shit. Commands cannot be registered.", exception);
}
try {
final Field knownCommandsField = SimpleCommandMap.class.getDeclaredField("knownCommands");
knownCommandsField.setAccessible(true);
knownCommandMap = (Map<String, Command>) knownCommandsField.get(commandMap);
} catch (NoSuchFieldException | IllegalAccessException exception) {
Bukkit.shutdown();
throw new SecurityException("Oh shit. Commands cannot be registered.", exception);
}
}
static Object[] generateArgumentArray(CommandSender commandSender, TypeMapper<?>[] parameters, GuardChecker[] guards, String[] args, Class<?> varArgType, String[] subCommand) throws CommandParseException {
Object[] arguments = new Object[parameters.length + 1];
int index = 0;

Datei anzeigen

@ -179,10 +179,10 @@ class SubCommand {
method.invoke(swCommand, objects);
} catch (CommandNoHelpException e) {
throw e;
} catch (IllegalAccessException | RuntimeException | InvocationTargetException e) {
throw new SecurityException(e.getMessage(), e);
} catch (CommandParseException e) {
return false;
} catch (IllegalAccessException | RuntimeException | InvocationTargetException e) {
throw new SecurityException(e.getMessage(), e);
}
return true;
}

Datei anzeigen

@ -38,7 +38,6 @@ import java.util.logging.Level;
public class Core extends JavaPlugin{
private static Core instance;
private static final int version;
public static Message MESSAGE;

Datei anzeigen

Datei anzeigen

@ -0,0 +1,122 @@
/*
YoyoNow markierte diese Unterhaltung als gelöst
Review

Die testsrc/.gitkeep kann doch mittlerweile eigentlich weg, oder?

Die testsrc/.gitkeep kann doch mittlerweile eigentlich weg, oder?
Review

Da hast du recht.

Da hast du recht.
* This file is a part of the SteamWar software.
*
* Copyright (C) 2020 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar;
import org.bukkit.Server;
import org.bukkit.command.CommandSender;
import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionAttachment;
import org.bukkit.permissions.PermissionAttachmentInfo;
import org.bukkit.plugin.Plugin;
import java.util.Set;
public class TestCommandSender implements CommandSender {
@Override
public void sendMessage(String s) {
}
@Override
public void sendMessage(String[] strings) {
}
@Override
public Server getServer() {
return null;
}
@Override
public String getName() {
return null;
}
@Override
public Spigot spigot() {
return null;
}
@Override
public boolean isPermissionSet(String s) {
return false;
}
@Override
public boolean isPermissionSet(Permission permission) {
return false;
}
@Override
public boolean hasPermission(String s) {
return false;
}
@Override
public boolean hasPermission(Permission permission) {
return false;
}
@Override
public PermissionAttachment addAttachment(Plugin plugin, String s, boolean b) {
return null;
}
@Override
public PermissionAttachment addAttachment(Plugin plugin) {
return null;
}
@Override
public PermissionAttachment addAttachment(Plugin plugin, String s, boolean b, int i) {
return null;
}
@Override
public PermissionAttachment addAttachment(Plugin plugin, int i) {
return null;
}
@Override
public void removeAttachment(PermissionAttachment permissionAttachment) {
}
@Override
public void recalculatePermissions() {
}
@Override
public Set<PermissionAttachmentInfo> getEffectivePermissions() {
return null;
}
@Override
public boolean isOp() {
return false;
}
@Override
public void setOp(boolean b) {
}
}

Datei anzeigen

@ -0,0 +1,41 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2020 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command;
public class ExecutionIdentifier extends RuntimeException {
YoyoNow markierte diese Unterhaltung als gelöst
Review

Brauchst du den wirklich, oder hast du andernfalls silent-exceptions die irgendwo gecatcht und verworfen werden? Das wäre dann nämlich eher ein Zeichen davon, dass die Codearchitektur bescheiden ist. Eigentlich sollte man eine korrekte Ausführung daran erkennen, dass der Code ordnungsgemäß terminiert und Werte, welche sich ändern sollten, auf den korrekten Wert geändert wurden.

Brauchst du den wirklich, oder hast du andernfalls silent-exceptions die irgendwo gecatcht und verworfen werden? Das wäre dann nämlich eher ein Zeichen davon, dass die Codearchitektur bescheiden ist. Eigentlich sollte man eine korrekte Ausführung daran erkennen, dass der Code ordnungsgemäß terminiert und Werte, welche sich ändern sollten, auf den korrekten Wert geändert wurden.
Review

Naja ich will im test wissen, ob die methode wirklich ausgeführt wird, und das geht am besten indem ich wenn es ausgeführt wird eine Exception werfe und diese überprüfe.

Naja ich will im test wissen, ob die methode wirklich ausgeführt wird, und das geht am besten indem ich wenn es ausgeführt wird eine Exception werfe und diese überprüfe.
Review

Dann weißt du aber nie, ob der Code, welcher danach noch ausgeführt wird, nicht den Wert wieder zurücksetzen würde/fehler werfen würde.

Dann weißt du aber nie, ob der Code, welcher danach noch ausgeführt wird, nicht den Wert wieder zurücksetzen würde/fehler werfen würde.
Review

Das brauche ich mit dem Test nicht prüfen, ich will dort erstmal nur prüfen ob an sich die methode ausgeführt wird, andere Tests werden noch folgen. Aber soweit tut das Framework

Das brauche ich mit dem Test nicht prüfen, ich will dort erstmal nur prüfen ob an sich die methode ausgeführt wird, andere Tests werden noch folgen. Aber soweit tut das Framework
public ExecutionIdentifier() {
}
public ExecutionIdentifier(String message) {
super(message);
}
public ExecutionIdentifier(String message, Throwable cause) {
super(message, cause);
}
public ExecutionIdentifier(Throwable cause) {
super(cause);
}
public ExecutionIdentifier(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}

Datei anzeigen

@ -0,0 +1,34 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2020 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command;
import org.bukkit.command.CommandSender;
public class SimpleCommand extends SWCommand {
public SimpleCommand() {
super(true, "simple");
}
@Register
public void execute(CommandSender sender) {
throw new ExecutionIdentifier("Simple execute without any parameters");
}
}

Datei anzeigen

@ -0,0 +1,60 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2020 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command;
import de.steamwar.TestCommandSender;
import org.junit.Before;
import org.junit.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
public class SimpleCommandTest {
private SimpleCommand simpleCommand;
@Before
public void setUp() throws Exception {
simpleCommand = new SimpleCommand();
}
@Test
public void testCommandParsing() {
try {
simpleCommand.execute(new TestCommandSender(), "", new String[]{});
} catch (SecurityException securityException) {
if (securityException.getCause().getCause() instanceof ExecutionIdentifier) {
ExecutionIdentifier executionIdentifier = (ExecutionIdentifier) securityException.getCause().getCause();
assertThat(executionIdentifier.getMessage(), is("Simple execute without any parameters"));
return;
}
}
assert false;
}
@Test
public void testUnknownCommandParsing() {
try {
simpleCommand.execute(new TestCommandSender(), "", new String[]{"unknown"});
} catch (SecurityException securityException) {
assert false;
}
}
}