Remove 'main command' and test empty command to improve coverage

This commit is contained in:
Norbi Peti 2023-07-31 20:43:20 +02:00
parent 7e511c169b
commit 2787c280f5
No known key found for this signature in database
GPG key ID: DBA4C4549A927E56
4 changed files with 17 additions and 23 deletions

View file

@ -154,25 +154,21 @@ abstract class Command2<TC : ICommand2<TP>, TP : Command2Sender>(
* @param command The command to register
* @return The Brigadier command node if you need it for something (like tab completion)
*/
protected fun registerCommandSuper(command: TC): CoreCommandNode<TP, *> {
var mainCommandNode: CoreCommandNode<TP, *>? = null
protected fun registerCommandSuper(command: TC): List<CoreExecutableNode<TP, TC>> {
val registeredNodes = mutableListOf<CoreExecutableNode<TP, TC>>()
for (meth in command.javaClass.methods) {
val ann = meth.getAnnotation(Subcommand::class.java) ?: continue
val fullPath = command.commandPath + CommandUtils.getCommandPath(meth.name, ' ')
assert(fullPath.isNotBlank()) { "No path found for command class ${command.javaClass.name} and method ${meth.name}" }
val (lastNode, mainNodeMaybe, remainingPath) = registerNodeFromPath(fullPath)
val (lastNode, remainingPath) = registerNodeFromPath(fullPath)
val execNode = getExecutableNode(meth, command, ann, remainingPath, CommandArgumentHelpManager(command), fullPath)
lastNode.addChild(execNode)
val mainNode = mainNodeMaybe ?: execNode
if (mainCommandNode == null) mainCommandNode = mainNode
else if (mainNode.name != mainCommandNode.name) {
MainPlugin.instance.logger.warning("Multiple commands are defined in the same class! This is not supported. Class: " + command.javaClass.simpleName)
}
registeredNodes.add(execNode)
}
if (mainCommandNode == null) {
throw RuntimeException("There are no subcommands defined in the command class " + command.javaClass.simpleName + "!")
if (registeredNodes.isEmpty()) {
throw RuntimeException("There are no subcommands defined in the command class ${command.javaClass.simpleName}!")
}
return mainCommandNode
return registeredNodes.toList()
}
/**
@ -236,19 +232,16 @@ abstract class Command2<TC : ICommand2<TP>, TP : Command2Sender>(
* @return The last no-op node that can be used to register the executable node,
* the main command node and the last part of the command path (that isn't registered yet)
*/
private fun registerNodeFromPath(path: String): Triple<CommandNode<TP>, CoreCommandNode<TP, *>?, String> {
private fun registerNodeFromPath(path: String): Pair<CommandNode<TP>, String> {
val split = path.split(" ")
var parent: CommandNode<TP> = dispatcher.root
var mainCommand: CoreCommandNode<TP, *>? = null
split.dropLast(1).forEachIndexed { i, part ->
split.dropLast(1).forEach { part ->
val child = parent.getChild(part)
if (child == null) parent.addChild(CoreCommandBuilder.literalNoOp<TP, TC>(part) { emptyArray() }
.executes(::executeHelpText).build().also { parent = it })
else parent = child
if (i == 0) mainCommand =
parent as CoreCommandNode<TP, *> // Has to be our own literal node, if not, well, error
}
return Triple(parent, mainCommand, split.last())
return Pair(parent, split.last())
}
fun getCommandList(sender: TP): Array<String> {

View file

@ -7,7 +7,6 @@ import buttondevteam.lib.architecture.ButtonPlugin
import buttondevteam.lib.architecture.Component
import buttondevteam.lib.chat.commands.CommandUtils
import buttondevteam.lib.chat.commands.CommandUtils.coreArgument
import buttondevteam.lib.chat.commands.CommandUtils.coreExecutable
import buttondevteam.lib.chat.commands.MCCommandSettings
import buttondevteam.lib.chat.commands.SubcommandData
import buttondevteam.lib.player.ChromaGamerBase
@ -37,14 +36,12 @@ class Command2MC : Command2<ICommand2MC, Command2MCSender>('/', true), Listener
* @param command The command to register
*/
override fun registerCommand(command: ICommand2MC) {
val commandNode = super.registerCommandSuper(command)
val bcmd = registerOfficially(command, commandNode)
// TODO: Support aliases
val nodes = super.registerCommandSuper(command)
val permPrefix = "chroma.command."
//Allow commands by default, it will check mod-only
val nodes = commandNode.coreExecutable<Command2MCSender, ICommand2MC>()
?.let { getSubcommands(commandNode) + it } ?: getSubcommands(commandNode)
for (node in nodes) {
val bcmd = registerOfficially(command, node)
// TODO: Support aliases
val subperm = permPrefix + node.data.fullPath.replace(' ', '.')
if (Bukkit.getPluginManager().getPermission(subperm) == null) //Check needed for plugin reset
Bukkit.getPluginManager().addPermission(Permission(subperm, PermissionDefault.TRUE))

View file

@ -119,6 +119,9 @@ abstract class Command2MCCommands {
}
}
@CommandClass
object TestEmptyCommand : ICommand2MC()
interface ITestCommand2MC {
var testCommandReceived: String?
}

View file

@ -53,6 +53,7 @@ class Command2MCTest {
TestNoMainCommand1.register()
TestNoMainCommand2.register()
TestParamsCommand.register()
assertEquals("There are no subcommands defined in the command class TestEmptyCommand!", assertFails { TestEmptyCommand.register() }.message)
}
@Test