NMS independent test toolkit to allow developers to test their commands with MockBukkit
Aims to resolve https://github.com/JorelAli/CommandAPI/issues/356.
Currently, when developers try to load the CommandAPI in a MockBukkit environment, it is very hard to get the NMS code accessed by the CommandAPI to cooperate with MockBukkit. There is work on the dev/public-test-suite branch that is trying to make it easier to resolve these issues. As an alternative solution, this PR aims to create a framework for mocking an NMS-independent version of the CommandAPI. Various utilities are also included to make testing commands easier.
These features are accessible using the commandapi-bukkit-test-toolkit module. Developers should declare a test scope dependency on this module before their dependency on the plugin or shaded CommandAPI. This overrides CommandAPIVersionHandler when running tests to load MockCommandAPIBukkit instead, which doesn't rely on any NMS classes.
The class CommandAPITestUtilities provides many static methods for asserting particular behavior when running commands. The class CommandAPIHandlerSpy intercepts command registration in the background to enable verifying the arguments input when running a command without having to make any changes to the plugin code that registers commands.
In order to mock Arguments that usually rely upon NMS ArgumentTypes, we would have to implement the parsing logic ourselves. I've included IntegerRangeArgumentType as a proof of concept. Currently, any unimplemented NMS methods throw an UnimplementedMethodException. I don't think we need to worry about specific implementations for all these methods right now. As developers try to use this framework, the methods they actually use can be implemented first.
I've implemented two example projects that showcase how to set up and use the test toolkit, one that shades the CommandAPI and one that depends on the CommandAPI plugin. This also helps verify that each setup works. To more rigorously test the toolkit's features, additional tests have been added inside the src/test directory of the commandapi-bukkit-test-toolkit module. The result of these tests will appear in the Jacoco coverage report.
I still need to add javadocs and documentation, but I think this is a good start feature-wise. There are obviously many methods that throw an UnimplementedMethodException, but again I think developers can try using this first and show what methods are actually used. Feel free to suggest anything that should be included in an initial snapshot release of the framework though. Also, of course, code review is greatly appreciated!
Actually, I thought of one important system that should probably be implemented: default ArgumentType suggestions. The IntegerRangeArgument doesn't suggest anything by default, so I didn't think about it at first. There is a parser system in place to make creating new ArgumentType parsers easier, and I can probably add suggestions to that as well. I think I'll add support for the PlayerArgument, since that provides suggestions by default and is commonly used any way.
Alright, ArgumentType suggestions implemented and docs written. After code review, I'm happy to merge this so developers can try it and figure out which important methods I haven't implemented :P.
Also when there were selectors,
@nwas missing almost every time.
Ah, yeah good catch. I wrote most of this for 1.20.6, and @n was added in 1.21 so I didn't include it. I'll definitely update all the dependencies to match 1.21 and add @n.
Although, I wonder if this framework should provide some way to account for version-specific behavior? Maybe default to latest, but add something similar to CommandAPIVersionHandler#usePlatformImplementation to set a version. Shouldn't be too hard to add that.
Noticed a lot of Spigot API - is there a reason we can't use Paper?
I was originally thinking that since the CommandAPI is supposed to work on Spigot, the testing framework should work on Spigot, so the Spigot repo makes sure the testing framework doesn't accidentally use Paper-only API. However, I now know that MockBukkit is based on Paper API, so we actually end up having access to Paper API transitively. Technically, we could completely not list a dependency for Spigot/Paper and just transitively inherit it from MockBukkit, which might actually be good because MockBukkit depends on the correct version of the classes being loaded.
So yeah, since MockBukkit uses Paper API this testing framework probably should too?
With the 1.21.2/1.21.3 version release coming soon, I'll hold off on merging this (note to self: will have to update CommandAPI dependency versions manually after the release is done). Since this is just a framework with many methods left unimplemented, I think it would be good to release it in a snapshot version first. Developers can try it out and show which methods are important to implement before a full release.