You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The `@Permission` annotation is used to add a permission node to a command. Users that want to run this command must have this permission. The parameter is the permission node required to run the command.
A form with two parameters `value` and `shortDescription`, to provide the full description (`value`) and short description (`shortDescription`) content for a command:
@@ -54,27 +54,27 @@ To use annotations on methods, **methods must be static**.
54
54
55
55
The `@Default` annotation indicates that the method is _not_ a subcommand. This acts in a similar way to regular Bukkit commands. Commands with the `@Default` annotation can be used to run the main code when the command named with the `@Command` annotation is stated, such as the following:
The `@Subcommand` simply tells the CommandAPI that the declared method is a subcommand. This acts in a similar way to the regular CommandAPI's `.withSubcommand()` method. The subcommand annotation can take in a single string which is the name of the subcommand:
-**The name of the argument (referred to as "nodeName" in the normal CommandAPI system) is the name of the variable assigned to the parameter.** In the above code, this means that the name of the argument is `warpName`.
101
101
@@ -107,18 +107,18 @@ Certain argument annotations have extra parameters that can be supplied to provi
107
107
108
108
The following numerical arguments can take both a `min` and `max` value. Both of these are completely optional. This indicates the range of values (inclusive) that is valid for this argument. For example:
Both the `LiteralArgument` and `MultiLiteralArgument` can be used. When these are used, the name of the variable assigned to the parameter is _ignored_ and not used as the argument's name.
115
115
116
116
For the `@ALiteralArgument` annotation, the parameter is the literal to be used for the command. For the `@AMultiLiteralArgument`, the parameter can be an array of multiple literals to use:
The `LocationArgument`, `Location2DArgument`, `EntitySelectorArgument` and `ScoreHolderArgument` can all take an extra parameter in their constructors. As a result, the annotation-equivalent of these arguments also allow you to provide the parameter in the annotation:
As we can see, the code certainly _looks_ very different to the normal registration method. Let's take it apart piece by piece to see what exactly is going on here.
Firstly, we declare our command `warp`. To do this, we use the `@Command` annotation and simply state the name of the command in the annotation. This annotation is attached to the class `WarpCommand`, which indicates that the whole class `WarpCommand` will be housing our command.
65
65
66
66
The annotation framework is designed in such a way that an entire command is represented by a single class. This provides a more modular approach to command declaration that allows you to easily contain the methods of a command in one location.
Here, declare the main command implementation using the `@Default` annotation. The `@Default` annotation informs the CommandAPI that the method it is attached to does not have any subcommands. This is effectively the same as registering a regular command without using `.withSubcommand()`.
72
72
73
73
Here, we simply write what happens when no arguments are run (i.e. the user just runs `/warp` on its own). As such, we don't include any parameters to our method.
We also have a second `@Default` annotated method, which handles our `/warp <warp>` command. Because this isn't a subcommand (the warp to teleport to is not a subcommand, it's an argument), we still using the `@Default` annotation. In this method, we include an argument with this command by using the `@AStringArgument` annotation. This argument uses the `StringArgument` class, and the name of this argument is "warpName", which is extracted from the name of the variable. Simply put, **the Annotation for an argument is A** followed by the name of the argument. This is synonymous with using the following:
80
80
@@ -88,7 +88,7 @@ The second argument is a `String` object, which represents the result of our arg
Lastly, we declare a subcommand to allow us to run `/warp create <name>`. To do this, we simply use the `@Subcommand` annotation. In this example, we also apply a permission node that is required to run the command by using the `@Permission` annotation. The rest is fairly straight forward - we declare an argument, in this case it's another `StringArgument` , so we use `@AStringArgument` and then declare everything else in a similar fashion to the default command executor.
When developing large projects, it is good practice to add automated tests for your code. This section of the documentation describes how to use the `commandapi-bukkit-test-toolkit` dependency along with [MockBukkit](https://github.com/MockBukkit/MockBukkit) and [JUnit](https://junit.org/junit5/) to test the usage of commands registered with the CommandAPI.
10
+
11
+
For a big-picture view, you can find example projects that include automated tests in the [CommandAPI GitHub repository](https://github.com/CommandAPI/CommandAPI/tree/master/examples).
12
+
13
+
:::danger Developer's Note:
14
+
15
+
Many methods have not yet been implemented in the test toolkit. Most notably, only [primitive arguments](../create-commands/arguments/types/primitive-arguments), [String arguments](../create-commands/arguments/types/string-arguments), [literal arguments](./category_literal_arguments.md), and the [`IntegerRangeArgument`](../create-commands/arguments/types/ranged-arguments) are fully implemented. The [`EntitySelectorArgument`, `PlayerArgument`, and `OfflinePlayerArgument`](../create-commands/arguments/types/entities-arguments) should mostly work, though [target selector arguments](https://minecraft.wiki/w/Target_selectors#Target_selector_arguments) (e.g. `@e[type=pig]`) are not yet implemented.
16
+
17
+
If a test ends up calling a method that has not yet been implemented, an `UnimplementedMethodException` will be thrown, causing the test to fail. If you see an `UnimplementedMethodException`, please tell us about it with a [GitHub Issue](https://github.com/CommandAPI/CommandAPI/issues) or a message in the CommandAPI Discord. Pull requests are also always welcome!
18
+
19
+
In the short term, you can try to resolve an `UnimplementedMethodException` by implementing the method yourself. The process for doing that is described [here](./test_loadmockcommandapi.md#loading-a-custom-commandapi-platform-implementation).
If your plugin depends on the CommandAPI plugin to load, when running tests you should load the `JavaPlugin``MockCommandAPIPlugin` before you use MockBukkit to [load your plugin](https://mockbukkit.readthedocs.io/en/latest/first_tests.html#creating-the-test-class). You can either load this class directly with `MockBukkit.load(MockCommandAPIPlugin.class)`, or use one of the static `MockCommandAPIPlugin#load` methods:
12
+
13
+
```java
14
+
MockCommandAPIPlugin load()
15
+
```
16
+
17
+
Loads the CommandAPI Plugin in the test environment. Works exactly the same as `MockBukkit.load(MockCommandAPIPlugin.class)`.
Loads the CommandAPI Plugin after applying the given consumer. This allows configuring any setting from the [config.yml](../user-setup/config#configuration-settings) using the methods provided by [CommandAPIBukkitConfig](../dev-setup/shading#loading).
24
+
25
+
:::tip Example - Loading test CommandAPI with settings
26
+
27
+
To change, for example, the `missing-executor-implementation` message while running tests, you can use the method `CommandAPIBukkitConfig#missingExecutorImplementationMessage` when the `configureSettings` callback is run:
If your plugin shades the CommandAPI, the CommandAPI will automatically load as usual when you use MockBukkit to load your plugin. Just note that you **must** call `CommandAPI.onDisable()` in your plugin's `onDisable` method in order for the test environment to reset properly after each test.
36
+
37
+
## Loading a custom CommandAPI platform implementation
38
+
39
+
By default, the testing environment will load `MockCommandAPIBukkit` as the CommandAPI platform object. This works for basic tests, but many methods in `MockCommandAPIBukkit` are not yet implemented and just throw an `UnimplementedMethodException`. This may cause your tests to fail if your code relies on any of these methods. If you see an `UnimplementedMethodException`, please tell us about it with a [GitHub Issue](https://github.com/CommandAPI/CommandAPI/issues) or a message in the CommandAPI Discord so we can get it solved for everyone.
40
+
41
+
In the short term, you can also try to avoid an `UnimplementedMethodException` by implementing the required method yourself. Simply create a class that extends `MockCommandAPIBukkit` and override the required method with an appropriate implementation. Before each test where you want to use your custom implementation, make sure to call `CommandAPIVersionHandler#usePlatformImplementation` to let the CommandAPI know what it should load.
In the most common simple case, tests can be added directly next to plugin code. Code that goes in your final jar file is located in the `/src/main/` directory, while tests go in `/src/test/`. You can find more information about setting up your project for tests in the [JUnit](https://junit.org/junit5/docs/current/user-guide/#overview-getting-started-example-projects) documentation.
12
+
13
+
## Dependencies
14
+
15
+
When you add the dependencies for MockBukkit and `commandapi-bukkit-test-toolkit`, make sure to place them before your main dependencies for the CommandAPI and Spigot/Paper API. This ensures that certain classes that are compatible with the testing environment override the regular classes when running tests.
16
+
17
+
<divclass="maven">
18
+
19
+
```xml
20
+
<dependencies>
21
+
<!-- See https://github.com/MockBukkit/MockBukkit?tab=readme-ov-file#mag-usage for latest version -->
0 commit comments