Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Added

- An automated test suite, run by `mvn test` and by the existing `mvn package` step in CI, so a failing test now fails the build. The first tests lock down the `plugin.yml` contract: every permission node checked in code is registered or on an explicit knowingly-unregistered list (`rp.admin`, `rp.default`, `rp.card.show.others`, `rp.rphelp`), every registered node is checked somewhere, every registered command is dispatched by `CommandService` and vice versa, `rp.card.*` parents exactly the nine player card nodes and not `rp.card.forcesave` or `rp.card.forceload`, and the `USER_GUIDE.md` permission table matches what is registered. The `rp.card.*` guarantee is exercised through Bukkit's own `PermissibleBase` against a stub server, which is the check PR #335 could only establish with a throwaway class. This is the check that would have caught #321, #322 and #329 when they were introduced. `USER_GUIDE.md` gained the missing `rp.rphelp` entry under "Known Permission Discrepancies", which the new suite flagged on its first run.
- Unit tests for `ArgumentParser` and `ColorChecker.getColorByName`. They record current behavior without changing it: arguments are joined with single spaces and empty arguments are kept, and color names are matched only in all-lower-case or all-upper-case form (e.g. `dark_red` or `DARK_RED`), with any other name — including `Red` — resolving to white.

### Changed

Expand Down
63 changes: 63 additions & 0 deletions src/test/java/dansplugins/rpsystem/utils/ArgumentParserTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package dansplugins.rpsystem.utils;

import org.junit.Test;

import static org.junit.Assert.assertEquals;

/**
* Characterizes the two ways command arguments are joined back into a message: the card setters, {@code /bird}
* and {@code /me} use {@link ArgumentParser#createStringFromFirstArgOnwards}, while {@code /whisper}, {@code /yell},
* {@code /lo} and {@code /title} use {@link ArgumentParser#createStringFromArgs}.
*/
public class ArgumentParserTest {
private final ArgumentParser argumentParser = new ArgumentParser();

@Test
public void firstArgOnwardsJoinsFromTheStartingIndexWithSingleSpaces() {
String[] args = {"name", "Sir", "Roderick", "the", "Bold"};
assertEquals("Sir Roderick the Bold", argumentParser.createStringFromFirstArgOnwards(args, 1));
}

@Test
public void firstArgOnwardsFromZeroJoinsEveryArgument() {
String[] args = {"draws", "a", "sword"};
assertEquals("draws a sword", argumentParser.createStringFromFirstArgOnwards(args, 0));
}

@Test
public void firstArgOnwardsWithASingleRemainingArgumentHasNoTrailingSpace() {
String[] args = {"age", "42"};
assertEquals("42", argumentParser.createStringFromFirstArgOnwards(args, 1));
}

@Test
public void firstArgOnwardsPastTheLastArgumentIsEmpty() {
// Callers check args.length first, but a start index at or past the end yields "", not an exception.
assertEquals("", argumentParser.createStringFromFirstArgOnwards(new String[]{"name"}, 1));
assertEquals("", argumentParser.createStringFromFirstArgOnwards(new String[0], 0));
}

@Test
public void firstArgOnwardsKeepsEmptyArgumentsAsExtraSpaces() {
// Bukkit passes consecutive spaces through as empty arguments; they are joined, not collapsed.
String[] args = {"name", "Ser", "", "Brienne"};
assertEquals("Ser Brienne", argumentParser.createStringFromFirstArgOnwards(args, 1));
}

@Test
public void argsJoinsEveryArgumentWithSingleSpaces() {
String[] args = {"Is", "anyone", "there?"};
assertEquals("Is anyone there?", argumentParser.createStringFromArgs(args));
}

@Test
public void argsWithOneArgumentReturnsItUnchanged() {
assertEquals("Hello", argumentParser.createStringFromArgs(new String[]{"Hello"}));
}

@Test(expected = ArrayIndexOutOfBoundsException.class)
public void argsWithNoArgumentsThrows() {
// Every caller checks args.length > 0 before calling, so this is never reached from a command.
argumentParser.createStringFromArgs(new String[0]);
}
}
64 changes: 64 additions & 0 deletions src/test/java/dansplugins/rpsystem/utils/ColorCheckerTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package dansplugins.rpsystem.utils;

import org.bukkit.ChatColor;
import org.junit.Test;

import java.util.Locale;

import static org.junit.Assert.assertEquals;

/**
* Characterizes how the color names in {@code config.yml} ({@code localChatColor}, {@code emoteColor}, the alert
* colors and the rest documented in {@code CONFIG.md}) are resolved to a {@link ChatColor}.
* {@link ColorChecker#getColorByName} does not consult the plugin, so no plugin instance is needed.
*/
public class ColorCheckerTest {
private static final ChatColor[] SUPPORTED_COLORS = {
ChatColor.AQUA, ChatColor.BLACK, ChatColor.BLUE, ChatColor.DARK_AQUA, ChatColor.DARK_BLUE,
ChatColor.DARK_GRAY, ChatColor.DARK_GREEN, ChatColor.DARK_PURPLE, ChatColor.DARK_RED, ChatColor.GOLD,
ChatColor.GRAY, ChatColor.GREEN, ChatColor.LIGHT_PURPLE, ChatColor.RED, ChatColor.YELLOW, ChatColor.WHITE
};

private final ColorChecker colorChecker = new ColorChecker(null);

@Test
public void everyColorIsResolvedFromItsLowerCaseName() {
for (ChatColor color : SUPPORTED_COLORS) {
assertEquals(color, colorChecker.getColorByName(color.name().toLowerCase(Locale.ENGLISH)));
}
}

@Test
public void everyColorIsResolvedFromItsUpperCaseName() {
for (ChatColor color : SUPPORTED_COLORS) {
assertEquals(color, colorChecker.getColorByName(color.name()));
}
}

@Test
public void mixedCaseNamesAreNotRecognizedAndFallBackToWhite() {
// Only the all-lower-case and all-upper-case spellings are matched.
assertEquals(ChatColor.WHITE, colorChecker.getColorByName("Red"));
assertEquals(ChatColor.WHITE, colorChecker.getColorByName("Dark_Red"));
}

@Test
public void unknownNamesFallBackToWhite() {
assertEquals(ChatColor.WHITE, colorChecker.getColorByName("pink"));
assertEquals(ChatColor.WHITE, colorChecker.getColorByName("dark-red"));
assertEquals(ChatColor.WHITE, colorChecker.getColorByName(""));
}

@Test
public void formattingCodesAreNotColorsAndFallBackToWhite() {
assertEquals(ChatColor.WHITE, colorChecker.getColorByName("bold"));
assertEquals(ChatColor.WHITE, colorChecker.getColorByName("ITALIC"));
}

@Test(expected = NullPointerException.class)
public void aNullNameThrows() {
// A switch on a null String throws. ConfigService backfills every color option on enable, so callers are
// not expected to pass null; this records the behavior rather than endorsing it.
colorChecker.getColorByName(null);
}
}
Loading