refactor(core): update all classes for new config system + add tab completion
BREAKING CHANGE: Core classes updated to use new section-based config Updated classes: - Mine.java - uses RegionConfig, BlockConfig, new FillMode - Mines.java - uses new ConfigLoader.ConfigLoadException - MineFileManager.java - creates configs with new system - MineRepository.java - uses new ConfigLoader - MaskScanService.java - uses BlockKey for markers - BukkitBlockSetter.java - uses Map<BlockKey, Double> Handlers updated: - ActionBarHandler.java - uses UIConfig with MiniMessage - MineBlockHandler.java - uses ResetConfig - MineRewardHandler.java - uses RewardConfig - MineResetHandler.java - uses new config sections Commands updated: - MaskCommands.java - updated exception handling Added: - LoMinesTabCompleter.java - Bukkit tab completion for all commands - RegistrationManager.registerTabCompleter() - registers tab completer Removed: - Old ConfigLoaderTest.java (uses deprecated config system) All classes now use: - Type-safe BlockKey instead of String - Section-based config (region, blocks, reset, rewards, ui, teleport) - Duration-based intervals instead of ticks - MiniMessage formatting for action bar
This commit is contained in:
parent
f1060f34d4
commit
8b8b9fee18
16 changed files with 564 additions and 878 deletions
|
|
@ -1,536 +0,0 @@
|
|||
package dev.loki.lomines.data;
|
||||
|
||||
import dev.loki.lomines.data.config.ConfigLoader;
|
||||
import dev.loki.lomines.data.config.MineConfig;
|
||||
import dev.loki.lomines.data.config.parser.ConfigParseException;
|
||||
import dev.loki.lomines.data.reward.Reward;
|
||||
import org.bukkit.*;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
import org.mockito.MockedStatic;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
/**
|
||||
* Unit tests for ConfigLoader.
|
||||
* Tests parsing of YAML configuration files into MineConfig objects.
|
||||
*/
|
||||
class ConfigLoaderTest {
|
||||
|
||||
@TempDir
|
||||
Path tempDir;
|
||||
private ConfigLoader configLoader;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
configLoader = new ConfigLoader();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLoadValidConfig() throws Exception {
|
||||
// Create a valid YAML config file
|
||||
String yamlContent = """
|
||||
selection.1: world;0;64;0;0.0;0.0
|
||||
selection.2: world;10;74;10;0.0;0.0
|
||||
contents:
|
||||
stone: 50
|
||||
coal_ore: 30
|
||||
iron_ore: 20
|
||||
reset:
|
||||
ticks: 6000
|
||||
percent: 10.0
|
||||
reset-on-percent: false
|
||||
actionbar:
|
||||
enabled: true
|
||||
message: "Mine resetting soon"
|
||||
range: 50.0
|
||||
timer-format: "mm:ss"
|
||||
teleport-on-reset: false
|
||||
reset-commands:
|
||||
- "say Mine reset!"
|
||||
broadcast-reset: "Mine has been reset"
|
||||
random-rewards:
|
||||
- chance: 1.0
|
||||
prevent-drops: false
|
||||
blocks:
|
||||
- diamond_ore
|
||||
items:
|
||||
- type: diamond
|
||||
amount: 1
|
||||
commands:
|
||||
- "eco give %player% 100"
|
||||
""";
|
||||
|
||||
Path configFile = tempDir.resolve("test-mine.yml");
|
||||
Files.writeString(configFile, yamlContent);
|
||||
|
||||
// Mock Bukkit
|
||||
try (MockedStatic<Bukkit> bukkit = mockStatic(Bukkit.class)) {
|
||||
Server server = mock(Server.class);
|
||||
World world = mock(World.class);
|
||||
|
||||
bukkit.when(Bukkit::getServer).thenReturn(server);
|
||||
bukkit.when(() -> Bukkit.getWorld(anyString())).thenReturn(world);
|
||||
|
||||
when(world.getName()).thenReturn("world");
|
||||
|
||||
// Load the config
|
||||
MineConfig config = configLoader.load(configFile);
|
||||
|
||||
// Verify selections
|
||||
assertNotNull(config.getSelections());
|
||||
assertEquals(2, config.getSelections().size());
|
||||
|
||||
// Verify blocks
|
||||
assertNotNull(config.getBlocks());
|
||||
assertEquals(3, config.getBlocks().size());
|
||||
assertTrue(config.getBlocks().containsKey("stone"));
|
||||
assertTrue(config.getBlocks().containsKey("coal_ore"));
|
||||
assertTrue(config.getBlocks().containsKey("iron_ore"));
|
||||
assertEquals(50.0, config.getBlocks().get("stone"));
|
||||
assertEquals(30.0, config.getBlocks().get("coal_ore"));
|
||||
assertEquals(20.0, config.getBlocks().get("iron_ore"));
|
||||
|
||||
// Verify rewards
|
||||
assertNotNull(config.getRewards());
|
||||
assertEquals(1, config.getRewards().size());
|
||||
Reward reward = config.getRewards().get(0);
|
||||
assertEquals(1.0, reward.getChance());
|
||||
assertFalse(reward.isPreventDrops());
|
||||
assertEquals(1, reward.getMaterials().size());
|
||||
assertTrue(reward.getMaterials().contains(Material.DIAMOND_ORE));
|
||||
|
||||
// Verify reset settings
|
||||
assertEquals(6000, config.getResetTicks());
|
||||
assertEquals(10.0, config.getResetPercent());
|
||||
assertFalse(config.isResetOnPercentEnabled());
|
||||
|
||||
// Verify action bar settings
|
||||
assertTrue(config.isActionBarEnabled());
|
||||
assertEquals("Mine resetting soon", config.getActionBarMessage());
|
||||
assertEquals(50.0, config.getActionBarRange());
|
||||
|
||||
// Verify other settings
|
||||
assertEquals("mm:ss", config.getTimerFormat());
|
||||
assertFalse(config.isTeleportOnReset());
|
||||
assertNull(config.getTeleportLocation());
|
||||
assertEquals(1, config.getResetCommands().size());
|
||||
assertEquals("say Mine reset!", config.getResetCommands().get(0));
|
||||
assertEquals("Mine has been reset", config.getBroadcastReset());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLoadMissingFile() {
|
||||
Path nonExistentFile = tempDir.resolve("nonexistent.yml");
|
||||
|
||||
assertThrows(IOException.class, () -> {
|
||||
configLoader.load(nonExistentFile);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLoadNullPath() {
|
||||
ConfigParseException exception = assertThrows(ConfigParseException.class, () -> {
|
||||
configLoader.load(null);
|
||||
});
|
||||
|
||||
assertTrue(exception.getMessage().contains("cannot be null"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLoadMissingSelections() throws Exception {
|
||||
String yamlContent = """
|
||||
contents:
|
||||
stone: 100
|
||||
""";
|
||||
|
||||
Path configFile = tempDir.resolve("test-mine.yml");
|
||||
Files.writeString(configFile, yamlContent);
|
||||
|
||||
ConfigParseException exception = assertThrows(ConfigParseException.class, () -> {
|
||||
configLoader.load(configFile);
|
||||
});
|
||||
|
||||
assertTrue(exception.getMessage().contains("No selection coordinates found"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLoadOddNumberOfSelections() throws Exception {
|
||||
String yamlContent = """
|
||||
selection.1: world;0;64;0;0.0;0.0
|
||||
selection.2: world;10;74;10;0.0;0.0
|
||||
selection.3: world;20;64;20;0.0;0.0
|
||||
contents:
|
||||
stone: 100
|
||||
""";
|
||||
|
||||
Path configFile = tempDir.resolve("test-mine.yml");
|
||||
Files.writeString(configFile, yamlContent);
|
||||
|
||||
try (MockedStatic<Bukkit> bukkit = mockStatic(Bukkit.class)) {
|
||||
Server server = mock(Server.class);
|
||||
World world = mock(World.class);
|
||||
|
||||
bukkit.when(Bukkit::getServer).thenReturn(server);
|
||||
bukkit.when(() -> Bukkit.getWorld(anyString())).thenReturn(world);
|
||||
|
||||
when(world.getName()).thenReturn("world");
|
||||
|
||||
ConfigParseException exception = assertThrows(ConfigParseException.class, () -> {
|
||||
configLoader.load(configFile);
|
||||
});
|
||||
|
||||
assertTrue(exception.getMessage().contains("must be in pairs"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLoadMissingContents() throws Exception {
|
||||
String yamlContent = """
|
||||
selection.1: world;0;64;0;0.0;0.0
|
||||
selection.2: world;10;74;10;0.0;0.0
|
||||
""";
|
||||
|
||||
Path configFile = tempDir.resolve("test-mine.yml");
|
||||
Files.writeString(configFile, yamlContent);
|
||||
|
||||
try (MockedStatic<Bukkit> bukkit = mockStatic(Bukkit.class)) {
|
||||
Server server = mock(Server.class);
|
||||
World world = mock(World.class);
|
||||
|
||||
bukkit.when(Bukkit::getServer).thenReturn(server);
|
||||
bukkit.when(() -> Bukkit.getWorld(anyString())).thenReturn(world);
|
||||
|
||||
when(world.getName()).thenReturn("world");
|
||||
|
||||
ConfigParseException exception = assertThrows(ConfigParseException.class, () -> {
|
||||
configLoader.load(configFile);
|
||||
});
|
||||
|
||||
assertTrue(exception.getMessage().contains("Missing required 'contents' section"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLoadInvalidMaterial() throws Exception {
|
||||
String yamlContent = """
|
||||
selection.1: world;0;64;0;0.0;0.0
|
||||
selection.2: world;10;74;10;0.0;0.0
|
||||
contents:
|
||||
invalid_material: 100
|
||||
""";
|
||||
|
||||
Path configFile = tempDir.resolve("test-mine.yml");
|
||||
Files.writeString(configFile, yamlContent);
|
||||
|
||||
try (MockedStatic<Bukkit> bukkit = mockStatic(Bukkit.class)) {
|
||||
Server server = mock(Server.class);
|
||||
World world = mock(World.class);
|
||||
|
||||
bukkit.when(Bukkit::getServer).thenReturn(server);
|
||||
bukkit.when(() -> Bukkit.getWorld(anyString())).thenReturn(world);
|
||||
|
||||
when(world.getName()).thenReturn("world");
|
||||
|
||||
ConfigParseException exception = assertThrows(ConfigParseException.class, () -> {
|
||||
configLoader.load(configFile);
|
||||
});
|
||||
|
||||
assertTrue(exception.getMessage().contains("Unknown material"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLoadInvalidBlockWeight() throws Exception {
|
||||
String yamlContent = """
|
||||
selection.1: world;0;64;0;0.0;0.0
|
||||
selection.2: world;10;74;10;0.0;0.0
|
||||
contents:
|
||||
stone: -10
|
||||
""";
|
||||
|
||||
Path configFile = tempDir.resolve("test-mine.yml");
|
||||
Files.writeString(configFile, yamlContent);
|
||||
|
||||
try (MockedStatic<Bukkit> bukkit = mockStatic(Bukkit.class)) {
|
||||
Server server = mock(Server.class);
|
||||
World world = mock(World.class);
|
||||
|
||||
bukkit.when(Bukkit::getServer).thenReturn(server);
|
||||
bukkit.when(() -> Bukkit.getWorld(anyString())).thenReturn(world);
|
||||
|
||||
when(world.getName()).thenReturn("world");
|
||||
|
||||
ConfigParseException exception = assertThrows(ConfigParseException.class, () -> {
|
||||
configLoader.load(configFile);
|
||||
});
|
||||
|
||||
assertTrue(exception.getMessage().contains("must be positive"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLoadInvalidRewardChance() throws Exception {
|
||||
String yamlContent = """
|
||||
selection.1: world;0;64;0;0.0;0.0
|
||||
selection.2: world;10;74;10;0.0;0.0
|
||||
contents:
|
||||
stone: 100
|
||||
random-rewards:
|
||||
- chance: 150
|
||||
blocks:
|
||||
- diamond_ore
|
||||
""";
|
||||
|
||||
Path configFile = tempDir.resolve("test-mine.yml");
|
||||
Files.writeString(configFile, yamlContent);
|
||||
|
||||
try (MockedStatic<Bukkit> bukkit = mockStatic(Bukkit.class)) {
|
||||
Server server = mock(Server.class);
|
||||
World world = mock(World.class);
|
||||
|
||||
bukkit.when(Bukkit::getServer).thenReturn(server);
|
||||
bukkit.when(() -> Bukkit.getWorld(anyString())).thenReturn(world);
|
||||
|
||||
when(world.getName()).thenReturn("world");
|
||||
|
||||
ConfigParseException exception = assertThrows(ConfigParseException.class, () -> {
|
||||
configLoader.load(configFile);
|
||||
});
|
||||
|
||||
assertTrue(exception.getMessage().contains("between 0 and 100"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testLoadWithTeleportLocation() throws Exception {
|
||||
String yamlContent = """
|
||||
selection.1: world;0;64;0;0.0;0.0
|
||||
selection.2: world;10;74;10;0.0;0.0
|
||||
contents:
|
||||
stone: 100
|
||||
teleport-on-reset: true
|
||||
teleport-location: world;5;70;5;90.0;0.0
|
||||
""";
|
||||
|
||||
Path configFile = tempDir.resolve("test-mine.yml");
|
||||
Files.writeString(configFile, yamlContent);
|
||||
|
||||
try (MockedStatic<Bukkit> bukkit = mockStatic(Bukkit.class)) {
|
||||
Server server = mock(Server.class);
|
||||
World world = mock(World.class);
|
||||
|
||||
bukkit.when(Bukkit::getServer).thenReturn(server);
|
||||
bukkit.when(() -> Bukkit.getWorld(anyString())).thenReturn(world);
|
||||
|
||||
when(world.getName()).thenReturn("world");
|
||||
|
||||
MineConfig config = configLoader.load(configFile);
|
||||
|
||||
assertTrue(config.isTeleportOnReset());
|
||||
assertNotNull(config.getTeleportLocation());
|
||||
assertEquals(5.0, config.getTeleportLocation().getX());
|
||||
assertEquals(70.0, config.getTeleportLocation().getY());
|
||||
assertEquals(5.0, config.getTeleportLocation().getZ());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testSaveAndLoadRoundTrip() throws Exception {
|
||||
// Create a config file to load (without items to avoid ItemStack initialization issues)
|
||||
String yamlContent = """
|
||||
selection.1: world;0;64;0;0.0;0.0
|
||||
selection.2: world;10;74;10;0.0;0.0
|
||||
contents:
|
||||
stone: 50
|
||||
coal_ore: 30
|
||||
reset:
|
||||
ticks: 6000
|
||||
percent: 10.0
|
||||
reset-on-percent: false
|
||||
actionbar:
|
||||
enabled: true
|
||||
message: "Mine resetting soon"
|
||||
range: 50.0
|
||||
timer-format: "mm:ss"
|
||||
teleport-on-reset: false
|
||||
reset-commands:
|
||||
- "say Mine reset!"
|
||||
broadcast-reset: "Mine has been reset"
|
||||
random-rewards:
|
||||
- chance: 1.0
|
||||
prevent-drops: false
|
||||
blocks:
|
||||
- diamond_ore
|
||||
commands:
|
||||
- "eco give %player% 100"
|
||||
""";
|
||||
|
||||
Path configFile = tempDir.resolve("test-mine.yml");
|
||||
Files.writeString(configFile, yamlContent);
|
||||
|
||||
// Mock Bukkit
|
||||
try (MockedStatic<Bukkit> bukkit = mockStatic(Bukkit.class)) {
|
||||
Server server = mock(Server.class);
|
||||
World world = mock(World.class);
|
||||
|
||||
bukkit.when(Bukkit::getServer).thenReturn(server);
|
||||
bukkit.when(() -> Bukkit.getWorld(anyString())).thenReturn(world);
|
||||
|
||||
when(world.getName()).thenReturn("world");
|
||||
|
||||
// Load the config
|
||||
MineConfig config = configLoader.load(configFile);
|
||||
|
||||
// Save to a new file
|
||||
Path savedFile = tempDir.resolve("saved-mine.yml");
|
||||
configLoader.save(config, savedFile);
|
||||
|
||||
// Verify the file was created
|
||||
assertTrue(Files.exists(savedFile));
|
||||
|
||||
// Verify the content is valid YAML
|
||||
String savedContent = Files.readString(savedFile);
|
||||
assertFalse(savedContent.isEmpty());
|
||||
|
||||
// Load the saved config
|
||||
MineConfig loadedConfig = configLoader.load(savedFile);
|
||||
|
||||
// Verify key properties match
|
||||
assertEquals(config.getResetTicks(), loadedConfig.getResetTicks());
|
||||
assertEquals(config.getResetPercent(), loadedConfig.getResetPercent());
|
||||
assertEquals(config.isResetOnPercentEnabled(), loadedConfig.isResetOnPercentEnabled());
|
||||
assertEquals(config.isActionBarEnabled(), loadedConfig.isActionBarEnabled());
|
||||
assertEquals(config.getActionBarMessage(), loadedConfig.getActionBarMessage());
|
||||
assertEquals(config.getActionBarRange(), loadedConfig.getActionBarRange());
|
||||
assertEquals(config.getTimerFormat(), loadedConfig.getTimerFormat());
|
||||
assertEquals(config.isTeleportOnReset(), loadedConfig.isTeleportOnReset());
|
||||
assertEquals(config.getBroadcastReset(), loadedConfig.getBroadcastReset());
|
||||
assertEquals(config.getResetCommands().size(), loadedConfig.getResetCommands().size());
|
||||
assertEquals(config.getRewards().size(), loadedConfig.getRewards().size());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSaveNullConfig() {
|
||||
Path configFile = tempDir.resolve("test.yml");
|
||||
|
||||
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
|
||||
configLoader.save(null, configFile);
|
||||
});
|
||||
|
||||
assertTrue(exception.getMessage().contains("Config cannot be null"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSaveNullPath() throws Exception {
|
||||
// Create a minimal config
|
||||
try (MockedStatic<Bukkit> bukkit = mockStatic(Bukkit.class)) {
|
||||
Server server = mock(Server.class);
|
||||
World world = mock(World.class);
|
||||
|
||||
bukkit.when(Bukkit::getServer).thenReturn(server);
|
||||
bukkit.when(() -> Bukkit.getWorld(anyString())).thenReturn(world);
|
||||
|
||||
when(world.getName()).thenReturn("world");
|
||||
|
||||
Location loc1 = new Location(world, 0, 64, 0, 0, 0);
|
||||
Location loc2 = new Location(world, 10, 74, 10, 0, 0);
|
||||
|
||||
MineConfig config = MineConfig.builder()
|
||||
.selections(List.of(loc1, loc2))
|
||||
.blocks(Map.of("stone", 100.0))
|
||||
.rewards(List.of())
|
||||
.build();
|
||||
|
||||
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
|
||||
configLoader.save(config, null);
|
||||
});
|
||||
|
||||
assertTrue(exception.getMessage().contains("Config file path cannot be null"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSaveWithTeleportLocation() throws Exception {
|
||||
try (MockedStatic<Bukkit> bukkit = mockStatic(Bukkit.class)) {
|
||||
Server server = mock(Server.class);
|
||||
World world = mock(World.class);
|
||||
|
||||
bukkit.when(Bukkit::getServer).thenReturn(server);
|
||||
bukkit.when(() -> Bukkit.getWorld(anyString())).thenReturn(world);
|
||||
|
||||
when(world.getName()).thenReturn("world");
|
||||
|
||||
Location loc1 = new Location(world, 0, 64, 0, 0, 0);
|
||||
Location loc2 = new Location(world, 10, 74, 10, 0, 0);
|
||||
Location teleportLoc = new Location(world, 5, 70, 5, 90, 0);
|
||||
|
||||
MineConfig config = MineConfig.builder()
|
||||
.selections(List.of(loc1, loc2))
|
||||
.blocks(Map.of("stone", 100.0))
|
||||
.rewards(List.of())
|
||||
.teleportOnReset(true)
|
||||
.teleportLocation(teleportLoc)
|
||||
.build();
|
||||
|
||||
Path savedFile = tempDir.resolve("with-teleport.yml");
|
||||
configLoader.save(config, savedFile);
|
||||
|
||||
// Verify the file was created
|
||||
assertTrue(Files.exists(savedFile));
|
||||
|
||||
// Load and verify
|
||||
MineConfig loadedConfig = configLoader.load(savedFile);
|
||||
assertTrue(loadedConfig.isTeleportOnReset());
|
||||
assertNotNull(loadedConfig.getTeleportLocation());
|
||||
assertEquals(5.0, loadedConfig.getTeleportLocation().getX());
|
||||
assertEquals(70.0, loadedConfig.getTeleportLocation().getY());
|
||||
assertEquals(5.0, loadedConfig.getTeleportLocation().getZ());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSaveEmptyRewards() throws Exception {
|
||||
try (MockedStatic<Bukkit> bukkit = mockStatic(Bukkit.class)) {
|
||||
Server server = mock(Server.class);
|
||||
World world = mock(World.class);
|
||||
|
||||
bukkit.when(Bukkit::getServer).thenReturn(server);
|
||||
bukkit.when(() -> Bukkit.getWorld(anyString())).thenReturn(world);
|
||||
|
||||
when(world.getName()).thenReturn("world");
|
||||
|
||||
Location loc1 = new Location(world, 0, 64, 0, 0, 0);
|
||||
Location loc2 = new Location(world, 10, 74, 10, 0, 0);
|
||||
|
||||
MineConfig config = MineConfig.builder()
|
||||
.selections(List.of(loc1, loc2))
|
||||
.blocks(Map.of("stone", 100.0))
|
||||
.rewards(List.of())
|
||||
.build();
|
||||
|
||||
Path savedFile = tempDir.resolve("no-rewards.yml");
|
||||
configLoader.save(config, savedFile);
|
||||
|
||||
// Verify the file was created
|
||||
assertTrue(Files.exists(savedFile));
|
||||
|
||||
// Load and verify
|
||||
MineConfig loadedConfig = configLoader.load(savedFile);
|
||||
assertTrue(loadedConfig.getRewards().isEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue