Skip to content

Commit b161059

Browse files
committed
feat: refactor annotations part, finish testing part
1 parent 10537c1 commit b161059

File tree

28 files changed

+631
-257
lines changed

28 files changed

+631
-257
lines changed

docs/en/annotations/annotations.md

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,37 +14,37 @@ This page outlines in detail the list of all annotations that the CommandAPI's a
1414

1515
The `@Command` annotation is used to declare a command. The parameter is the name of the command that will be registered.
1616

17-
<<< @/../reference-code/src/main/java/annotations/Intro.java#declareCommand
17+
<<< @/../reference-code/src/main/java/annotations/WarpCommand.java#declareCommand
1818

1919
### `@Alias({...})`
2020

2121
The `@Alias` annotation is used to declare a list of aliases for a command. The parameter is a list of aliases which can be used for the command.
2222

23-
<<< @/../reference-code/src/main/java/annotations/Annotations.java#aliasClassExample
23+
<<< @/../reference-code/src/main/java/annotations/aliasClassExample/TeleportCommand.java#aliasClassExample
2424

2525
### `@Permission("permissionNode")`
2626

2727
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.
2828

29-
<<< @/../reference-code/src/main/java/annotations/Annotations.java#permissionClassExample
29+
<<< @/../reference-code/src/main/java/annotations/permissionClassExample/TeleportCommand.java#permissionClassExample
3030

3131
### `@NeedsOp`
3232

3333
The `@NeedsOp` annotation is used to indicate that a command needs to have operator privileges to run it. This annotation has no parameters.
3434

35-
<<< @/../reference-code/src/main/java/annotations/Annotations.java#needsOpClassExample
35+
<<< @/../reference-code/src/main/java/annotations/needsOpClassExample/TeleportCommand.java#needsOpClassExample
3636

3737
### `@Help("Full description")`
3838

3939
The `@Help` annotation is used to add a help topic to a command. This annotation can take two forms:
4040

4141
A simple form which just uses a string which is used as the full description for a command:
4242

43-
<<< @/../reference-code/src/main/java/annotations/Annotations.java#helpClassExample
43+
<<< @/../reference-code/src/main/java/annotations/helpClassExample/TeleportCommand.java#helpClassExample
4444

4545
A form with two parameters `value` and `shortDescription`, to provide the full description (`value`) and short description (`shortDescription`) content for a command:
4646

47-
<<< @/../reference-code/src/main/java/annotations/Annotations.java#shortHelpClassExample
47+
<<< @/../reference-code/src/main/java/annotations/shortHelpClassExample/TeleportCommand.java#shortHelpClassExample
4848

4949
## Annotations that go on methods
5050

@@ -54,27 +54,27 @@ To use annotations on methods, **methods must be static**.
5454

5555
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:
5656

57-
<<< @/../reference-code/src/main/java/annotations/Annotations.java#defaultMethodExample
57+
<<< @/../reference-code/src/main/java/annotations/DefaultMethodExample.java#defaultMethodExample
5858

5959
The `@Default` annotation does not mean that the command can't have arguments! Arguments can still be used and declared as shown:
6060

61-
<<< @/../reference-code/src/main/java/annotations/Annotations.java#defaultWithArgsMethodExample
61+
<<< @/../reference-code/src/main/java/annotations/DefaultMethodExample.java#defaultWithArgsMethodExample
6262

6363
### `@Subcommand`
6464

6565
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:
6666

67-
<<< @/../reference-code/src/main/java/annotations/Annotations.java#subcommandMethodExample
67+
<<< @/../reference-code/src/main/java/annotations/SubcommandMethodExample.java#subcommandMethodExample
6868

6969
Or, it can take in a list of strings which represent the _aliases_ that can also be used for the declared subcommand:
7070

71-
<<< @/../reference-code/src/main/java/annotations/Annotations.java#subcommandAliasesMethodExample
71+
<<< @/../reference-code/src/main/java/annotations/SubcommandMethodExample.java#subcommandAliasesMethodExample
7272

7373
### `@Permission`
7474

7575
The `@Permission` annotation can also be used on methods to indicate that a permission is required to execute a command.
7676

77-
<<< @/../reference-code/src/main/java/annotations/Annotations.java#permissionMethodExample
77+
<<< @/../reference-code/src/main/java/annotations/PermissionMethodExample.java#permissionMethodExample
7878

7979
### `@NeedsOp`
8080

@@ -95,7 +95,7 @@ $$\begin{align}
9595

9696
For example, we use `@AStringArgument` to indicate that this command takes a `StringArgument` as its first parameter:
9797

98-
<<< @/../reference-code/src/main/java/annotations/Annotations.java#simpleParameterExample
98+
<<< @/../reference-code/src/main/java/annotations/ParameterExample.java#simpleParameterExample
9999

100100
- **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`.
101101

@@ -107,18 +107,18 @@ Certain argument annotations have extra parameters that can be supplied to provi
107107

108108
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:
109109

110-
<<< @/../reference-code/src/main/java/annotations/Annotations.java#numericalParameterExample
110+
<<< @/../reference-code/src/main/java/annotations/ParameterExample.java#numericalParameterExample
111111

112112
#### Literal arguments
113113

114114
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.
115115

116116
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:
117117

118-
<<< @/../reference-code/src/main/java/annotations/Annotations.java#literalParameterExample
118+
<<< @/../reference-code/src/main/java/annotations/ParameterExample.java#literalParameterExample
119119

120120
#### Other arguments
121121

122122
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:
123123

124-
<<< @/../reference-code/src/main/java/annotations/Annotations.java#otherParameterExample
124+
<<< @/../reference-code/src/main/java/annotations/ParameterExample.java#otherParameterExample

docs/en/annotations/intro.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,30 +51,30 @@ Seems fairly straightforward, given everything else covered in this documentatio
5151

5252
I think it's best to show the example and the explain it afterwards:
5353

54-
<<< @/../reference-code/src/main/java/annotations/Intro.java#annotationsExample
54+
<<< @/../reference-code/src/main/java/annotations/WarpCommand.java#annotationsExample
5555

5656
<<< @/../reference-code/src/main/java/annotations/Intro.java#annotationsRegisterExample
5757

5858
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.
5959

6060
#### Command declaration
6161

62-
<<< @/../reference-code/src/main/java/annotations/Intro.java#declareCommand
62+
<<< @/../reference-code/src/main/java/annotations/WarpCommand.java#declareCommand
6363

6464
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.
6565

6666
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.
6767

6868
#### Default command
69-
<<< @/../reference-code/src/main/java/annotations/Intro.java#defaultExample
69+
<<< @/../reference-code/src/main/java/annotations/WarpCommand.java#defaultExample
7070

7171
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()`.
7272

7373
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.
7474

7575
#### Default command (again!)
7676

77-
<<< @/../reference-code/src/main/java/annotations/Intro.java#anotherDefaultExample
77+
<<< @/../reference-code/src/main/java/annotations/WarpCommand.java#anotherDefaultExample
7878

7979
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:
8080

@@ -88,7 +88,7 @@ The second argument is a `String` object, which represents the result of our arg
8888

8989
#### Subcommand
9090

91-
<<< @/../reference-code/src/main/java/annotations/Intro.java#subcommandExample
91+
<<< @/../reference-code/src/main/java/annotations/WarpCommand.java#subcommandExample
9292

9393
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.
9494

docs/en/annotations/registration.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ CommandAPI.registerCommand(className)
1616

1717
Say we have a simple command `/warp` that is defined as follows:
1818

19-
<<< @/../reference-code/src/main/java/annotations/Intro.java#annotationsExample
19+
<<< @/../reference-code/src/main/java/annotations/WarpCommand.java#annotationsExample
2020

2121
We can register this in our `onLoad()` method so we can use this command from within Minecraft functions:
2222

docs/en/contribution/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
---
22
title: CommandAPI Contribution
3-
order: 11
3+
order: 12
44
---

docs/en/internal/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
---
22
title: Internal CommandAPI
3-
order: 9
3+
order: 10
44
---

docs/en/test/index.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
title: Testing Framework
3+
order: 7
4+
---

docs/en/test/intro.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
---
2+
order: 1
3+
authors:
4+
- willkroboth
5+
---
6+
7+
# Testing Commands
8+
9+
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).
20+
21+
:::
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
---
2+
order: 3
3+
authors:
4+
- willkroboth
5+
---
6+
7+
# Loading The CommandAPI in Tests
8+
9+
## Plugin Dependency
10+
11+
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)`.
18+
19+
```java
20+
MockCommandAPIPlugin load(Consumer<CommandAPIBukkitConfig> configureSettings)
21+
```
22+
23+
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:
28+
29+
<<< @/../reference-code/src/test/java/test/LoadMockCommandAPI.java#loadMockCommandAPIExample
30+
31+
:::
32+
33+
## Shaded Dependency
34+
35+
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.
42+
43+
<<< @/../reference-code/src/test/java/test/LoadMockCommandAPI.java#loadCustomCommandAPIPlatformImplementationExample

docs/en/test/setup.md

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
---
2+
order: 2
3+
preferences: ['build-system']
4+
authors:
5+
- willkroboth
6+
- JorelAli
7+
---
8+
9+
# Setting up your project
10+
11+
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+
<div class="maven">
18+
19+
```xml
20+
<dependencies>
21+
<!-- See https://github.com/MockBukkit/MockBukkit?tab=readme-ov-file#mag-usage for latest version -->
22+
<dependency>
23+
<groupId>com.github.seeseemelk</groupId>
24+
<artifactId>MockBukkit-v1.21</artifactId>
25+
<version>3.128.0</version>
26+
<scope>test</scope>
27+
</dependency>
28+
29+
<dependency>
30+
<groupId>dev.jorel</groupId>
31+
<artifactId>commandapi-bukkit-test-toolkit</artifactId>
32+
<version>9.7.0</version>
33+
<scope>test</scope>
34+
</dependency>
35+
36+
<!-- May be the shade dependency and/or mojang-mapped -->
37+
<dependency>
38+
<groupId>dev.jorel</groupId>
39+
<artifactId>commandapi-bukkit-core</artifactId>
40+
<version>9.7.0</version>
41+
<scope>provided</scope>
42+
</dependency>
43+
44+
<!-- Can also be paper-api -->
45+
<dependency>
46+
<groupId>org.spigotmc</groupId>
47+
<artifactId>spigot-api</artifactId>
48+
<version>1.21.1-R0.1-SNAPSHOT</version>
49+
<scope>provided</scope>
50+
</dependency>
51+
52+
<!-- See https://junit.org/junit5/ for latest version -->
53+
<dependency>
54+
<groupId>org.junit.jupiter</groupId>
55+
<artifactId>junit-jupiter-engine</artifactId>
56+
<version>5.8.2</version>
57+
<scope>test</scope>
58+
</dependency>
59+
</dependencies>
60+
```
61+
62+
</div>
63+
64+
<div class="gradle">
65+
66+
<div class="groovy">
67+
68+
```groovy
69+
dependencies {
70+
// See https://github.com/MockBukkit/MockBukkit?tab=readme-ov-file#mag-usage for latest version
71+
testImplementation 'com.github.seeseemelk:MockBukkit-v1.21:3.128.0'
72+
73+
testImplementation 'dev.jorel.commandapi-bukkit-test-toolkit:9.6.2-SNAPSHOT'
74+
75+
// May be the shade dependency and/or mojang-mapped
76+
compileOnly 'dev.jorel:commandapi-bukkit-core:9.7.0'
77+
78+
// Can also be paper-api
79+
compileOnly 'org.spigotmc:spigot-api:1.21.1-R0.1-SNAPSHOT'
80+
81+
// See https://junit.org/junit5/ for latest version
82+
testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.8.2'
83+
}
84+
```
85+
86+
</div>
87+
<div class="kts">
88+
89+
```kotlin
90+
dependencies {
91+
// See https://github.com/MockBukkit/MockBukkit?tab=readme-ov-file#mag-usage for latest version
92+
testImplementation('com.github.seeseemelk:MockBukkit-v1.21:3.128.0')
93+
94+
testImplementation('dev.jorel.commandapi-bukkit-test-toolkit:9.6.2-SNAPSHOT')
95+
96+
// May be the shade dependency and/or mojang-mapped
97+
compileOnly('dev.jorel:commandapi-bukkit-core:9.7.0')
98+
99+
// Can also be paper-api
100+
compileOnly('org.spigotmc:spigot-api:1.21.1-R0.1-SNAPSHOT')
101+
102+
// See https://junit.org/junit5/ for latest version
103+
testImplementation('org.junit.jupiter:junit-jupiter-engine:5.8.2')
104+
}
105+
```
106+
107+
</div>
108+
109+
</div>

0 commit comments

Comments
 (0)