refactor: migrate package from com.loki to dev.loki
- Change base package from com.loki to dev.loki across all Java files - Update plugin.yml main class path - Fix ConfigParseException imports in test files - Update build.gradle.kts relocate patterns - Add missing imports in ConfigLoaderTest.java - Update TODO.md with current status BREAKING CHANGE: Package namespace changed from com.loki to dev.loki
This commit is contained in:
parent
41924ea97f
commit
f4e9458544
87 changed files with 2185 additions and 1767 deletions
|
|
@ -1,8 +1,8 @@
|
|||
package com.loki.lomines.command;
|
||||
package dev.loki.lomines.command;
|
||||
|
||||
import com.loki.lomines.LoMinesPlugin;
|
||||
import com.loki.lomines.core.Mine;
|
||||
import com.loki.lomines.core.Mines;
|
||||
import dev.loki.lomines.LoMinesPlugin;
|
||||
import dev.loki.lomines.core.Mine;
|
||||
import dev.loki.lomines.core.Mines;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
|
@ -13,6 +13,7 @@ import org.mockito.MockitoAnnotations;
|
|||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
|
|
@ -128,7 +129,7 @@ class AdminCommandsTest {
|
|||
|
||||
@Test
|
||||
void testListMinesEmpty() {
|
||||
when(mines.getAll()).thenReturn(Arrays.asList());
|
||||
when(mines.getAll()).thenReturn(List.of());
|
||||
|
||||
commands.list(sender);
|
||||
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
package com.loki.lomines.core;
|
||||
package dev.loki.lomines.core;
|
||||
|
||||
import com.loki.lomines.LoMinesPlugin;
|
||||
import com.loki.lomines.block.BukkitBlockSetter;
|
||||
import com.loki.lomines.block.ItemsAdderBlockSetter;
|
||||
import com.loki.lomines.block.OraxenBlockSetter;
|
||||
import com.loki.lomines.data.MineConfig;
|
||||
import dev.loki.lomines.LoMinesPlugin;
|
||||
import dev.loki.lomines.block.BukkitBlockSetter;
|
||||
import dev.loki.lomines.block.ItemsAdderBlockSetter;
|
||||
import dev.loki.lomines.block.OraxenBlockSetter;
|
||||
import dev.loki.lomines.data.MineConfig;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
|
@ -23,54 +23,52 @@ import static org.mockito.Mockito.when;
|
|||
* Unit tests for Mine class, specifically testing BlockSetter creation logic.
|
||||
*/
|
||||
class MineTest {
|
||||
|
||||
|
||||
@Mock
|
||||
private LoMinesPlugin plugin;
|
||||
|
||||
|
||||
@Mock
|
||||
private World world;
|
||||
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
MockitoAnnotations.openMocks(this);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testCreateBlockSetter_WithOraxenPrefix_CreatesOraxenBlockSetter() {
|
||||
// Arrange
|
||||
Map<String, Double> blocks = new HashMap<>();
|
||||
blocks.put("oraxen:custom_ore", 50.0);
|
||||
blocks.put("oraxen:rare_ore", 30.0);
|
||||
|
||||
|
||||
MineConfig config = createTestConfig(blocks);
|
||||
|
||||
|
||||
// Act
|
||||
Mine mine = new Mine("test_mine", config, plugin);
|
||||
|
||||
|
||||
// Assert
|
||||
assertNotNull(mine.getBlockSetter());
|
||||
assertTrue(mine.getBlockSetter() instanceof OraxenBlockSetter,
|
||||
"Expected OraxenBlockSetter for oraxen: prefix");
|
||||
assertInstanceOf(OraxenBlockSetter.class, mine.getBlockSetter(), "Expected OraxenBlockSetter for oraxen: prefix");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testCreateBlockSetter_WithItemsAdderPrefix_CreatesItemsAdderBlockSetter() {
|
||||
// Arrange
|
||||
Map<String, Double> blocks = new HashMap<>();
|
||||
blocks.put("itemsadder:custom_block", 60.0);
|
||||
blocks.put("itemsadder:special_block", 40.0);
|
||||
|
||||
|
||||
MineConfig config = createTestConfig(blocks);
|
||||
|
||||
|
||||
// Act
|
||||
Mine mine = new Mine("test_mine", config, plugin);
|
||||
|
||||
|
||||
// Assert
|
||||
assertNotNull(mine.getBlockSetter());
|
||||
assertTrue(mine.getBlockSetter() instanceof ItemsAdderBlockSetter,
|
||||
"Expected ItemsAdderBlockSetter for itemsadder: prefix");
|
||||
assertInstanceOf(ItemsAdderBlockSetter.class, mine.getBlockSetter(), "Expected ItemsAdderBlockSetter for itemsadder: prefix");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testCreateBlockSetter_WithoutPrefix_CreatesBukkitBlockSetter() {
|
||||
// Arrange
|
||||
|
|
@ -78,39 +76,38 @@ class MineTest {
|
|||
blocks.put("STONE", 50.0);
|
||||
blocks.put("COAL_ORE", 30.0);
|
||||
blocks.put("IRON_ORE", 20.0);
|
||||
|
||||
|
||||
MineConfig config = createTestConfig(blocks);
|
||||
|
||||
|
||||
// Act
|
||||
Mine mine = new Mine("test_mine", config, plugin);
|
||||
|
||||
|
||||
// Assert
|
||||
assertNotNull(mine.getBlockSetter());
|
||||
assertTrue(mine.getBlockSetter() instanceof BukkitBlockSetter,
|
||||
"Expected BukkitBlockSetter for vanilla blocks without prefix");
|
||||
assertInstanceOf(BukkitBlockSetter.class, mine.getBlockSetter(), "Expected BukkitBlockSetter for vanilla blocks without prefix");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testCreateBlockSetter_WithEmptyBlocks_ThrowsException() {
|
||||
// Arrange
|
||||
Map<String, Double> blocks = new HashMap<>();
|
||||
MineConfig config = createTestConfig(blocks);
|
||||
|
||||
|
||||
// Act & Assert
|
||||
IllegalArgumentException exception = assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> new Mine("test_mine", config, plugin)
|
||||
);
|
||||
|
||||
|
||||
assertEquals("Mine must have at least one block type", exception.getMessage());
|
||||
}
|
||||
|
||||
|
||||
private MineConfig createTestConfig(Map<String, Double> blocks) {
|
||||
when(world.getName()).thenReturn("world");
|
||||
|
||||
|
||||
Location loc1 = new Location(world, 0, 0, 0);
|
||||
Location loc2 = new Location(world, 10, 10, 10);
|
||||
|
||||
|
||||
return MineConfig.builder()
|
||||
.selections(List.of(loc1, loc2))
|
||||
.blocks(blocks)
|
||||
|
|
@ -1,12 +1,12 @@
|
|||
package com.loki.lomines.core;
|
||||
package dev.loki.lomines.core;
|
||||
|
||||
import com.loki.lomines.LoMinesPlugin;
|
||||
import dev.loki.lomines.LoMinesPlugin;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
|
||||
/**
|
||||
* Unit tests for MineTicker class.
|
||||
|
|
@ -14,38 +14,38 @@ import static org.junit.jupiter.api.Assertions.*;
|
|||
* These tests verify basic construction and null safety.
|
||||
*/
|
||||
class MineTickerTest {
|
||||
|
||||
|
||||
@Mock
|
||||
private LoMinesPlugin plugin;
|
||||
|
||||
|
||||
@Mock
|
||||
private Mines mines;
|
||||
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
MockitoAnnotations.openMocks(this);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testConstruction_WithValidParameters_DoesNotThrow() {
|
||||
// Act & Assert
|
||||
assertDoesNotThrow(() -> new MineTicker(mines, plugin));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testStop_WhenNotRunning_DoesNotThrow() {
|
||||
// Arrange
|
||||
MineTicker ticker = new MineTicker(mines, plugin);
|
||||
|
||||
|
||||
// Act & Assert
|
||||
assertDoesNotThrow(() -> ticker.stop());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testMultipleStops_DoNotThrow() {
|
||||
// Arrange
|
||||
MineTicker ticker = new MineTicker(mines, plugin);
|
||||
|
||||
|
||||
// Act & Assert
|
||||
assertDoesNotThrow(() -> {
|
||||
ticker.stop();
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
package com.loki.lomines.core;
|
||||
package dev.loki.lomines.core;
|
||||
|
||||
import com.loki.lomines.LoMinesPlugin;
|
||||
import dev.loki.lomines.LoMinesPlugin;
|
||||
import dev.lolib.core.LoLogger;
|
||||
import dev.lolib.scheduler.Scheduler;
|
||||
import dev.lolib.scheduler.ScheduledTask;
|
||||
import dev.lolib.scheduler.Scheduler;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Server;
|
||||
|
|
@ -28,28 +28,27 @@ import static org.mockito.Mockito.*;
|
|||
* Tests loading and creating mines.
|
||||
*/
|
||||
class MinesTest {
|
||||
|
||||
|
||||
@TempDir
|
||||
Path tempDir;
|
||||
private Mines mines;
|
||||
private LoMinesPlugin plugin;
|
||||
private Scheduler scheduler;
|
||||
|
||||
@TempDir
|
||||
Path tempDir;
|
||||
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
plugin = mock(LoMinesPlugin.class);
|
||||
Logger logger = mock(Logger.class);
|
||||
LoLogger loLogger = mock(LoLogger.class);
|
||||
scheduler = mock(Scheduler.class);
|
||||
|
||||
|
||||
when(plugin.getDataFolder()).thenReturn(tempDir.toFile());
|
||||
when(plugin.getLogger()).thenReturn(logger);
|
||||
when(plugin.loLogger()).thenReturn(loLogger);
|
||||
|
||||
|
||||
mines = new Mines(plugin);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper method to set up Bukkit and Scheduler mocking for tests that create mines.
|
||||
*/
|
||||
|
|
@ -57,131 +56,131 @@ class MinesTest {
|
|||
Server server = mock(Server.class);
|
||||
World world = mock(World.class);
|
||||
BlockData blockData = mock(BlockData.class);
|
||||
|
||||
|
||||
bukkit.when(Bukkit::getServer).thenReturn(server);
|
||||
bukkit.when(() -> Bukkit.getWorld(anyString())).thenReturn(world);
|
||||
bukkit.when(() -> Bukkit.createBlockData(any(Material.class))).thenReturn(blockData);
|
||||
|
||||
|
||||
when(world.getName()).thenReturn("world");
|
||||
|
||||
|
||||
schedulerStatic.when(() -> Scheduler.get(plugin)).thenReturn(scheduler);
|
||||
|
||||
|
||||
// Mock scheduler methods to execute callbacks immediately for testing
|
||||
ScheduledTask task = mock(ScheduledTask.class);
|
||||
when(scheduler.runTimer(any(Runnable.class), anyLong(), anyLong())).thenReturn(task);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testLoadAllWithNoMinesFolder() throws IOException {
|
||||
// When mines folder doesn't exist, loadAll should not throw
|
||||
assertDoesNotThrow(() -> mines.loadAll());
|
||||
|
||||
|
||||
// No mines should be loaded
|
||||
assertEquals(0, mines.getAll().size());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testLoadAllWithEmptyMinesFolder() throws IOException {
|
||||
// Create empty mines folder
|
||||
Path minesFolder = tempDir.resolve("mines");
|
||||
Files.createDirectories(minesFolder);
|
||||
|
||||
|
||||
// Load all mines
|
||||
mines.loadAll();
|
||||
|
||||
|
||||
// No mines should be loaded
|
||||
assertEquals(0, mines.getAll().size());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testLoadAllWithValidMine() throws IOException {
|
||||
// Create mines folder
|
||||
Path minesFolder = tempDir.resolve("mines");
|
||||
Files.createDirectories(minesFolder);
|
||||
|
||||
|
||||
// Create a valid mine 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: 100
|
||||
reset:
|
||||
ticks: 6000
|
||||
percent: 10.0
|
||||
reset-on-percent: false
|
||||
actionbar:
|
||||
enabled: true
|
||||
message: "Test mine"
|
||||
range: 50.0
|
||||
timer-format: "mm:ss"
|
||||
teleport-on-reset: false
|
||||
reset-commands: []
|
||||
broadcast-reset: ""
|
||||
random-rewards: []
|
||||
""";
|
||||
|
||||
selection.1: world;0;64;0;0.0;0.0
|
||||
selection.2: world;10;74;10;0.0;0.0
|
||||
contents:
|
||||
stone: 100
|
||||
reset:
|
||||
ticks: 6000
|
||||
percent: 10.0
|
||||
reset-on-percent: false
|
||||
actionbar:
|
||||
enabled: true
|
||||
message: "Test mine"
|
||||
range: 50.0
|
||||
timer-format: "mm:ss"
|
||||
teleport-on-reset: false
|
||||
reset-commands: []
|
||||
broadcast-reset: ""
|
||||
random-rewards: []
|
||||
""";
|
||||
|
||||
Path configFile = minesFolder.resolve("testmine.yml");
|
||||
Files.writeString(configFile, yamlContent);
|
||||
|
||||
|
||||
// Mock Bukkit and Scheduler
|
||||
try (MockedStatic<Bukkit> bukkit = mockStatic(Bukkit.class);
|
||||
MockedStatic<Scheduler> schedulerStatic = mockStatic(Scheduler.class)) {
|
||||
|
||||
|
||||
setupBukkitAndScheduler(bukkit, schedulerStatic);
|
||||
|
||||
|
||||
// Load all mines
|
||||
mines.loadAll();
|
||||
|
||||
|
||||
// Verify mine was loaded
|
||||
assertEquals(1, mines.getAll().size());
|
||||
assertTrue(mines.find("testmine").isPresent());
|
||||
|
||||
|
||||
Mine mine = mines.get("testmine");
|
||||
assertNotNull(mine);
|
||||
assertEquals("testmine", mine.getName());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testLoadAllWithMultipleMines() throws IOException {
|
||||
// Create mines folder
|
||||
Path minesFolder = tempDir.resolve("mines");
|
||||
Files.createDirectories(minesFolder);
|
||||
|
||||
|
||||
// Create multiple mine config files
|
||||
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
|
||||
reset:
|
||||
ticks: 6000
|
||||
percent: 10.0
|
||||
reset-on-percent: false
|
||||
actionbar:
|
||||
enabled: true
|
||||
message: "Test mine"
|
||||
range: 50.0
|
||||
timer-format: "mm:ss"
|
||||
teleport-on-reset: false
|
||||
reset-commands: []
|
||||
broadcast-reset: ""
|
||||
random-rewards: []
|
||||
""";
|
||||
|
||||
selection.1: world;0;64;0;0.0;0.0
|
||||
selection.2: world;10;74;10;0.0;0.0
|
||||
contents:
|
||||
stone: 100
|
||||
reset:
|
||||
ticks: 6000
|
||||
percent: 10.0
|
||||
reset-on-percent: false
|
||||
actionbar:
|
||||
enabled: true
|
||||
message: "Test mine"
|
||||
range: 50.0
|
||||
timer-format: "mm:ss"
|
||||
teleport-on-reset: false
|
||||
reset-commands: []
|
||||
broadcast-reset: ""
|
||||
random-rewards: []
|
||||
""";
|
||||
|
||||
Files.writeString(minesFolder.resolve("mine1.yml"), yamlContent);
|
||||
Files.writeString(minesFolder.resolve("mine2.yml"), yamlContent);
|
||||
Files.writeString(minesFolder.resolve("mine3.yml"), yamlContent);
|
||||
|
||||
|
||||
// Mock Bukkit and Scheduler
|
||||
try (MockedStatic<Bukkit> bukkit = mockStatic(Bukkit.class);
|
||||
MockedStatic<Scheduler> schedulerStatic = mockStatic(Scheduler.class)) {
|
||||
|
||||
|
||||
setupBukkitAndScheduler(bukkit, schedulerStatic);
|
||||
|
||||
|
||||
// Load all mines
|
||||
mines.loadAll();
|
||||
|
||||
|
||||
// Verify all mines were loaded
|
||||
assertEquals(3, mines.getAll().size());
|
||||
assertTrue(mines.find("mine1").isPresent());
|
||||
|
|
@ -189,211 +188,211 @@ class MinesTest {
|
|||
assertTrue(mines.find("mine3").isPresent());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testLoadAllIgnoresNonYamlFiles() throws IOException {
|
||||
// Create mines folder
|
||||
Path minesFolder = tempDir.resolve("mines");
|
||||
Files.createDirectories(minesFolder);
|
||||
|
||||
|
||||
// Create a valid mine 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: 100
|
||||
reset:
|
||||
ticks: 6000
|
||||
percent: 10.0
|
||||
""";
|
||||
|
||||
selection.1: world;0;64;0;0.0;0.0
|
||||
selection.2: world;10;74;10;0.0;0.0
|
||||
contents:
|
||||
stone: 100
|
||||
reset:
|
||||
ticks: 6000
|
||||
percent: 10.0
|
||||
""";
|
||||
|
||||
Files.writeString(minesFolder.resolve("validmine.yml"), yamlContent);
|
||||
Files.writeString(minesFolder.resolve("readme.txt"), "This is not a mine config");
|
||||
Files.writeString(minesFolder.resolve("backup.bak"), "Backup file");
|
||||
|
||||
|
||||
// Mock Bukkit and Scheduler
|
||||
try (MockedStatic<Bukkit> bukkit = mockStatic(Bukkit.class);
|
||||
MockedStatic<Scheduler> schedulerStatic = mockStatic(Scheduler.class)) {
|
||||
|
||||
|
||||
setupBukkitAndScheduler(bukkit, schedulerStatic);
|
||||
|
||||
|
||||
// Load all mines
|
||||
mines.loadAll();
|
||||
|
||||
|
||||
// Only the .yml file should be loaded
|
||||
assertEquals(1, mines.getAll().size());
|
||||
assertTrue(mines.find("validmine").isPresent());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testLoadAllWithInvalidMine() throws IOException {
|
||||
// Create mines folder
|
||||
Path minesFolder = tempDir.resolve("mines");
|
||||
Files.createDirectories(minesFolder);
|
||||
|
||||
|
||||
// Create an invalid mine config file (missing required fields)
|
||||
String invalidYaml = """
|
||||
selection.1: world;0;64;0;0.0;0.0
|
||||
""";
|
||||
|
||||
selection.1: world;0;64;0;0.0;0.0
|
||||
""";
|
||||
|
||||
Files.writeString(minesFolder.resolve("invalidmine.yml"), invalidYaml);
|
||||
|
||||
|
||||
// Mock Bukkit and Scheduler
|
||||
try (MockedStatic<Bukkit> bukkit = mockStatic(Bukkit.class);
|
||||
MockedStatic<Scheduler> schedulerStatic = mockStatic(Scheduler.class)) {
|
||||
|
||||
|
||||
setupBukkitAndScheduler(bukkit, schedulerStatic);
|
||||
|
||||
|
||||
// Load all mines - should not throw, but should log error
|
||||
assertDoesNotThrow(() -> mines.loadAll());
|
||||
|
||||
|
||||
// Invalid mine should not be loaded
|
||||
assertEquals(0, mines.getAll().size());
|
||||
|
||||
|
||||
// Verify error was logged
|
||||
verify(plugin.loLogger(), atLeastOnce()).error(anyString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testCreateNewMine() throws IOException {
|
||||
// Mock Bukkit and Scheduler
|
||||
try (MockedStatic<Bukkit> bukkit = mockStatic(Bukkit.class);
|
||||
MockedStatic<Scheduler> schedulerStatic = mockStatic(Scheduler.class)) {
|
||||
|
||||
|
||||
setupBukkitAndScheduler(bukkit, schedulerStatic);
|
||||
|
||||
|
||||
// Create a new mine
|
||||
mines.create("newmine");
|
||||
|
||||
|
||||
// Verify mine was created
|
||||
assertEquals(1, mines.getAll().size());
|
||||
assertTrue(mines.find("newmine").isPresent());
|
||||
|
||||
|
||||
Mine mine = mines.get("newmine");
|
||||
assertNotNull(mine);
|
||||
assertEquals("newmine", mine.getName());
|
||||
|
||||
|
||||
// Verify config file was created
|
||||
Path configFile = tempDir.resolve("mines/newmine.yml");
|
||||
assertTrue(Files.exists(configFile));
|
||||
|
||||
|
||||
// Verify logger was called
|
||||
verify(plugin.loLogger()).info("Created mine: newmine");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testCreateMineCreatesFolder() throws IOException {
|
||||
// Ensure mines folder doesn't exist
|
||||
Path minesFolder = tempDir.resolve("mines");
|
||||
assertFalse(Files.exists(minesFolder));
|
||||
|
||||
|
||||
// Mock Bukkit and Scheduler
|
||||
try (MockedStatic<Bukkit> bukkit = mockStatic(Bukkit.class);
|
||||
MockedStatic<Scheduler> schedulerStatic = mockStatic(Scheduler.class)) {
|
||||
|
||||
|
||||
setupBukkitAndScheduler(bukkit, schedulerStatic);
|
||||
|
||||
|
||||
// Create a new mine
|
||||
mines.create("testmine");
|
||||
|
||||
|
||||
// Verify mines folder was created
|
||||
assertTrue(Files.exists(minesFolder));
|
||||
assertTrue(Files.isDirectory(minesFolder));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testCreateDuplicateMineThrowsException() throws IOException {
|
||||
// Mock Bukkit and Scheduler
|
||||
try (MockedStatic<Bukkit> bukkit = mockStatic(Bukkit.class);
|
||||
MockedStatic<Scheduler> schedulerStatic = mockStatic(Scheduler.class)) {
|
||||
|
||||
|
||||
setupBukkitAndScheduler(bukkit, schedulerStatic);
|
||||
|
||||
|
||||
// Create a mine
|
||||
mines.create("duplicate");
|
||||
|
||||
|
||||
// Try to create the same mine again
|
||||
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
|
||||
mines.create("duplicate");
|
||||
});
|
||||
|
||||
|
||||
assertTrue(exception.getMessage().contains("Mine already exists"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testCreateMineIsCaseInsensitive() throws IOException {
|
||||
// Mock Bukkit and Scheduler
|
||||
try (MockedStatic<Bukkit> bukkit = mockStatic(Bukkit.class);
|
||||
MockedStatic<Scheduler> schedulerStatic = mockStatic(Scheduler.class)) {
|
||||
|
||||
|
||||
setupBukkitAndScheduler(bukkit, schedulerStatic);
|
||||
|
||||
|
||||
// Create a mine with mixed case
|
||||
mines.create("TestMine");
|
||||
|
||||
|
||||
// Try to create the same mine with different case
|
||||
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
|
||||
mines.create("testmine");
|
||||
});
|
||||
|
||||
|
||||
assertTrue(exception.getMessage().contains("Mine already exists"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testGetMineByName() throws IOException {
|
||||
// Mock Bukkit and Scheduler
|
||||
try (MockedStatic<Bukkit> bukkit = mockStatic(Bukkit.class);
|
||||
MockedStatic<Scheduler> schedulerStatic = mockStatic(Scheduler.class)) {
|
||||
|
||||
|
||||
setupBukkitAndScheduler(bukkit, schedulerStatic);
|
||||
|
||||
|
||||
// Create a mine
|
||||
mines.create("testmine");
|
||||
|
||||
|
||||
// Get mine by exact name
|
||||
Mine mine = mines.get("testmine");
|
||||
assertNotNull(mine);
|
||||
assertEquals("testmine", mine.getName());
|
||||
|
||||
|
||||
// Get mine by different case
|
||||
Mine mine2 = mines.get("TestMine");
|
||||
assertNotNull(mine2);
|
||||
assertEquals("testmine", mine2.getName());
|
||||
|
||||
|
||||
// Same mine instance
|
||||
assertSame(mine, mine2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testGetNonExistentMineThrowsException() {
|
||||
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
|
||||
mines.get("nonexistent");
|
||||
});
|
||||
|
||||
|
||||
assertTrue(exception.getMessage().contains("Mine not found"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testFindMineReturnsOptional() throws IOException {
|
||||
// Mock Bukkit and Scheduler
|
||||
try (MockedStatic<Bukkit> bukkit = mockStatic(Bukkit.class);
|
||||
MockedStatic<Scheduler> schedulerStatic = mockStatic(Scheduler.class)) {
|
||||
|
||||
|
||||
setupBukkitAndScheduler(bukkit, schedulerStatic);
|
||||
|
||||
|
||||
// Create a mine
|
||||
mines.create("testmine");
|
||||
|
||||
|
||||
// Find existing mine
|
||||
assertTrue(mines.find("testmine").isPresent());
|
||||
|
||||
|
||||
// Find non-existent mine
|
||||
assertFalse(mines.find("nonexistent").isPresent());
|
||||
}
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
package com.loki.lomines.data;
|
||||
package dev.loki.lomines.data;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.World;
|
||||
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;
|
||||
|
|
@ -25,72 +25,71 @@ import static org.mockito.Mockito.*;
|
|||
* Tests parsing of YAML configuration files into MineConfig objects.
|
||||
*/
|
||||
class ConfigLoaderTest {
|
||||
|
||||
private ConfigLoader configLoader;
|
||||
|
||||
|
||||
@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"
|
||||
""";
|
||||
|
||||
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());
|
||||
|
|
@ -100,7 +99,7 @@ class ConfigLoaderTest {
|
|||
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());
|
||||
|
|
@ -109,17 +108,17 @@ class ConfigLoaderTest {
|
|||
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());
|
||||
|
|
@ -129,68 +128,68 @@ class ConfigLoaderTest {
|
|||
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
|
||||
""";
|
||||
|
||||
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
|
||||
""";
|
||||
|
||||
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"));
|
||||
}
|
||||
}
|
||||
|
|
@ -198,146 +197,146 @@ class ConfigLoaderTest {
|
|||
@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
|
||||
""";
|
||||
|
||||
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
|
||||
""";
|
||||
|
||||
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
|
||||
""";
|
||||
|
||||
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
|
||||
""";
|
||||
|
||||
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
|
||||
""";
|
||||
|
||||
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());
|
||||
|
|
@ -351,32 +350,32 @@ class ConfigLoaderTest {
|
|||
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"
|
||||
""";
|
||||
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);
|
||||
|
|
@ -450,10 +449,10 @@ class ConfigLoaderTest {
|
|||
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();
|
||||
.selections(List.of(loc1, loc2))
|
||||
.blocks(Map.of("stone", 100.0))
|
||||
.rewards(List.of())
|
||||
.build();
|
||||
|
||||
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
|
||||
configLoader.save(config, null);
|
||||
|
|
@ -479,12 +478,12 @@ class ConfigLoaderTest {
|
|||
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();
|
||||
.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);
|
||||
|
|
@ -517,10 +516,10 @@ class ConfigLoaderTest {
|
|||
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();
|
||||
.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);
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
package com.loki.lomines.data;
|
||||
package dev.loki.lomines.data;
|
||||
|
||||
import com.loki.lomines.LoMinesPlugin;
|
||||
import dev.loki.lomines.LoMinesPlugin;
|
||||
import dev.lolib.core.LoLogger;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
|
@ -9,18 +9,20 @@ import java.io.File;
|
|||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Integration tests for Leaderboard caching with StatsManager.
|
||||
* Verifies that cache invalidation works correctly when statistics change.
|
||||
*/
|
||||
class LeaderboardCacheIntegrationTest {
|
||||
|
||||
|
||||
private StatsManager statsManager;
|
||||
private Leaderboard leaderboard;
|
||||
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
// Create a mock plugin
|
||||
|
|
@ -30,54 +32,54 @@ class LeaderboardCacheIntegrationTest {
|
|||
when(mockPlugin.getDataFolder()).thenReturn(mockDataFolder);
|
||||
when(mockPlugin.getLogger()).thenReturn(java.util.logging.Logger.getLogger("TestLogger"));
|
||||
when(mockPlugin.loLogger()).thenReturn(loLogger);
|
||||
|
||||
|
||||
statsManager = new StatsManager(mockPlugin);
|
||||
leaderboard = statsManager.getLeaderboard();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testCacheInvalidatedOnIncrementBlocks() {
|
||||
UUID player1 = UUID.randomUUID();
|
||||
UUID player2 = UUID.randomUUID();
|
||||
|
||||
|
||||
// Set initial stats
|
||||
statsManager.getOrCreate(player1).setTotalBlocks(100);
|
||||
|
||||
|
||||
// Build cache
|
||||
List<LeaderboardEntry> top1 = leaderboard.getTopTotal(10);
|
||||
assertEquals(1, top1.size(), "Should have 1 player initially");
|
||||
assertEquals(player1, top1.get(0).getPlayerId());
|
||||
|
||||
|
||||
// Increment blocks for player2 - this should invalidate cache
|
||||
statsManager.incrementBlocks(player2, "mine1");
|
||||
|
||||
|
||||
// Get top again - should rebuild cache with new player
|
||||
List<LeaderboardEntry> top2 = leaderboard.getTopTotal(10);
|
||||
assertEquals(2, top2.size(), "Should have 2 players after increment");
|
||||
|
||||
|
||||
// Verify order (player1 has 100, player2 has 1)
|
||||
assertEquals(player1, top2.get(0).getPlayerId(), "Player1 should still be first");
|
||||
assertEquals(player2, top2.get(1).getPlayerId(), "Player2 should be second");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testCacheRebuildsWithCorrectOrder() {
|
||||
UUID player1 = UUID.randomUUID();
|
||||
UUID player2 = UUID.randomUUID();
|
||||
|
||||
|
||||
// Set initial stats
|
||||
statsManager.getOrCreate(player1).setTotalBlocks(50);
|
||||
statsManager.getOrCreate(player2).setTotalBlocks(100);
|
||||
|
||||
|
||||
// Build cache
|
||||
List<LeaderboardEntry> top1 = leaderboard.getTopTotal(10);
|
||||
assertEquals(player2, top1.get(0).getPlayerId(), "Player2 should be first initially");
|
||||
|
||||
|
||||
// Increment player1 many times to overtake player2
|
||||
for (int i = 0; i < 60; i++) {
|
||||
statsManager.incrementBlocks(player1, "mine1");
|
||||
}
|
||||
|
||||
|
||||
// Get top again - cache should be rebuilt with new order
|
||||
List<LeaderboardEntry> top2 = leaderboard.getTopTotal(10);
|
||||
assertEquals(player1, top2.get(0).getPlayerId(), "Player1 should be first after increments");
|
||||
|
|
@ -85,26 +87,26 @@ class LeaderboardCacheIntegrationTest {
|
|||
assertEquals(player2, top2.get(1).getPlayerId(), "Player2 should be second");
|
||||
assertEquals(100, top2.get(1).getCount(), "Player2 should still have 100 blocks");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testMultipleIncrementsInvalidateCache() {
|
||||
UUID player1 = UUID.randomUUID();
|
||||
|
||||
|
||||
// Build empty cache
|
||||
List<LeaderboardEntry> top1 = leaderboard.getTopTotal(10);
|
||||
assertTrue(top1.isEmpty(), "Should be empty initially");
|
||||
|
||||
|
||||
// Increment blocks multiple times
|
||||
for (int i = 0; i < 5; i++) {
|
||||
statsManager.incrementBlocks(player1, "mine1");
|
||||
}
|
||||
|
||||
|
||||
// Get top - should show updated count
|
||||
List<LeaderboardEntry> top2 = leaderboard.getTopTotal(10);
|
||||
assertEquals(1, top2.size());
|
||||
assertEquals(5, top2.get(0).getCount(), "Should have 5 blocks after 5 increments");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testCachePerformance() {
|
||||
// Add many players
|
||||
|
|
@ -112,39 +114,39 @@ class LeaderboardCacheIntegrationTest {
|
|||
UUID playerId = UUID.randomUUID();
|
||||
statsManager.getOrCreate(playerId).setTotalBlocks(i + 1);
|
||||
}
|
||||
|
||||
|
||||
// First call - builds cache (slower)
|
||||
long start1 = System.nanoTime();
|
||||
List<LeaderboardEntry> top1 = leaderboard.getTopTotal(10);
|
||||
long time1 = System.nanoTime() - start1;
|
||||
|
||||
|
||||
// Second call - uses cache (should be much faster)
|
||||
long start2 = System.nanoTime();
|
||||
List<LeaderboardEntry> top2 = leaderboard.getTopTotal(10);
|
||||
long time2 = System.nanoTime() - start2;
|
||||
|
||||
|
||||
assertEquals(10, top1.size());
|
||||
assertEquals(10, top2.size());
|
||||
|
||||
|
||||
// Cache hit should be significantly faster (at least 2x)
|
||||
assertTrue(time2 < time1,
|
||||
String.format("Cache hit (%d ns) should be faster than cache miss (%d ns)", time2, time1));
|
||||
assertTrue(time2 < time1,
|
||||
String.format("Cache hit (%d ns) should be faster than cache miss (%d ns)", time2, time1));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testDifferentLimitsUseSameCache() {
|
||||
UUID player1 = UUID.randomUUID();
|
||||
UUID player2 = UUID.randomUUID();
|
||||
UUID player3 = UUID.randomUUID();
|
||||
|
||||
|
||||
statsManager.getOrCreate(player1).setTotalBlocks(100);
|
||||
statsManager.getOrCreate(player2).setTotalBlocks(200);
|
||||
statsManager.getOrCreate(player3).setTotalBlocks(300);
|
||||
|
||||
|
||||
// Build cache with limit 10
|
||||
List<LeaderboardEntry> top10 = leaderboard.getTopTotal(10);
|
||||
assertEquals(3, top10.size());
|
||||
|
||||
|
||||
// Get with limit 2 - should use same cache
|
||||
List<LeaderboardEntry> top2 = leaderboard.getTopTotal(2);
|
||||
assertEquals(2, top2.size());
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
package com.loki.lomines.data;
|
||||
package dev.loki.lomines.data;
|
||||
|
||||
import com.loki.lomines.LoMinesPlugin;
|
||||
import dev.loki.lomines.LoMinesPlugin;
|
||||
import dev.lolib.core.LoLogger;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
|
@ -9,18 +9,20 @@ import java.io.File;
|
|||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Unit tests for Leaderboard class.
|
||||
* Tests caching behavior, sorting, and filtering.
|
||||
*/
|
||||
class LeaderboardTest {
|
||||
|
||||
|
||||
private StatsManager statsManager;
|
||||
private Leaderboard leaderboard;
|
||||
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
// Create a mock plugin
|
||||
|
|
@ -30,175 +32,175 @@ class LeaderboardTest {
|
|||
when(mockPlugin.getDataFolder()).thenReturn(mockDataFolder);
|
||||
when(mockPlugin.getLogger()).thenReturn(java.util.logging.Logger.getLogger("TestLogger"));
|
||||
when(mockPlugin.loLogger()).thenReturn(loLogger);
|
||||
|
||||
|
||||
statsManager = new StatsManager(mockPlugin);
|
||||
leaderboard = statsManager.getLeaderboard();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testGetTopTotal_EmptyStats() {
|
||||
List<LeaderboardEntry> top = leaderboard.getTopTotal(10);
|
||||
assertTrue(top.isEmpty(), "Top list should be empty when no stats exist");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testGetTopTotal_SinglePlayer() {
|
||||
UUID playerId = UUID.randomUUID();
|
||||
PlayerStats stats = statsManager.getOrCreate(playerId);
|
||||
stats.setTotalBlocks(100);
|
||||
|
||||
|
||||
List<LeaderboardEntry> top = leaderboard.getTopTotal(10);
|
||||
assertEquals(1, top.size());
|
||||
assertEquals(playerId, top.get(0).getPlayerId());
|
||||
assertEquals(100, top.get(0).getCount());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testGetTopTotal_SortedDescending() {
|
||||
UUID player1 = UUID.randomUUID();
|
||||
UUID player2 = UUID.randomUUID();
|
||||
UUID player3 = UUID.randomUUID();
|
||||
|
||||
|
||||
statsManager.getOrCreate(player1).setTotalBlocks(50);
|
||||
statsManager.getOrCreate(player2).setTotalBlocks(200);
|
||||
statsManager.getOrCreate(player3).setTotalBlocks(100);
|
||||
|
||||
|
||||
List<LeaderboardEntry> top = leaderboard.getTopTotal(10);
|
||||
assertEquals(3, top.size());
|
||||
assertEquals(player2, top.get(0).getPlayerId()); // 200 blocks
|
||||
assertEquals(player3, top.get(1).getPlayerId()); // 100 blocks
|
||||
assertEquals(player1, top.get(2).getPlayerId()); // 50 blocks
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testGetTopTotal_LimitRespected() {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
UUID playerId = UUID.randomUUID();
|
||||
statsManager.getOrCreate(playerId).setTotalBlocks(i + 1);
|
||||
}
|
||||
|
||||
|
||||
List<LeaderboardEntry> top = leaderboard.getTopTotal(5);
|
||||
assertEquals(5, top.size(), "Should respect the limit parameter");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testGetTopTotal_FiltersZeroBlocks() {
|
||||
UUID player1 = UUID.randomUUID();
|
||||
UUID player2 = UUID.randomUUID();
|
||||
|
||||
|
||||
statsManager.getOrCreate(player1).setTotalBlocks(100);
|
||||
statsManager.getOrCreate(player2).setTotalBlocks(0);
|
||||
|
||||
|
||||
List<LeaderboardEntry> top = leaderboard.getTopTotal(10);
|
||||
assertEquals(1, top.size(), "Should filter out players with 0 blocks");
|
||||
assertEquals(player1, top.get(0).getPlayerId());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testGetTopTotal_CachingWorks() {
|
||||
UUID playerId = UUID.randomUUID();
|
||||
statsManager.getOrCreate(playerId).setTotalBlocks(100);
|
||||
|
||||
|
||||
// First call - builds cache
|
||||
List<LeaderboardEntry> top1 = leaderboard.getTopTotal(10);
|
||||
|
||||
|
||||
// Second call - should use cache (same reference)
|
||||
List<LeaderboardEntry> top2 = leaderboard.getTopTotal(10);
|
||||
|
||||
|
||||
assertEquals(top1.size(), top2.size());
|
||||
assertEquals(top1.get(0).getPlayerId(), top2.get(0).getPlayerId());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testInvalidateCache_ClearsCache() {
|
||||
UUID playerId = UUID.randomUUID();
|
||||
statsManager.getOrCreate(playerId).setTotalBlocks(100);
|
||||
|
||||
|
||||
// Build cache
|
||||
leaderboard.getTopTotal(10);
|
||||
|
||||
|
||||
// Invalidate cache
|
||||
leaderboard.invalidateCache();
|
||||
|
||||
|
||||
// Add new player
|
||||
UUID player2 = UUID.randomUUID();
|
||||
statsManager.getOrCreate(player2).setTotalBlocks(200);
|
||||
|
||||
|
||||
// Should rebuild cache with new player
|
||||
List<LeaderboardEntry> top = leaderboard.getTopTotal(10);
|
||||
assertEquals(2, top.size(), "Cache should be rebuilt after invalidation");
|
||||
assertEquals(player2, top.get(0).getPlayerId(), "New player should be first");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testGetTopByMine_SortedDescending() {
|
||||
UUID player1 = UUID.randomUUID();
|
||||
UUID player2 = UUID.randomUUID();
|
||||
UUID player3 = UUID.randomUUID();
|
||||
|
||||
|
||||
statsManager.getOrCreate(player1).setMineBlocks("mine1", 50);
|
||||
statsManager.getOrCreate(player2).setMineBlocks("mine1", 200);
|
||||
statsManager.getOrCreate(player3).setMineBlocks("mine1", 100);
|
||||
|
||||
|
||||
List<LeaderboardEntry> top = leaderboard.getTopByMine("mine1", 10);
|
||||
assertEquals(3, top.size());
|
||||
assertEquals(player2, top.get(0).getPlayerId()); // 200 blocks
|
||||
assertEquals(player3, top.get(1).getPlayerId()); // 100 blocks
|
||||
assertEquals(player1, top.get(2).getPlayerId()); // 50 blocks
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testGetTopByMine_FiltersZeroBlocks() {
|
||||
UUID player1 = UUID.randomUUID();
|
||||
UUID player2 = UUID.randomUUID();
|
||||
|
||||
|
||||
statsManager.getOrCreate(player1).setMineBlocks("mine1", 100);
|
||||
statsManager.getOrCreate(player2).setMineBlocks("mine1", 0);
|
||||
|
||||
|
||||
List<LeaderboardEntry> top = leaderboard.getTopByMine("mine1", 10);
|
||||
assertEquals(1, top.size(), "Should filter out players with 0 blocks");
|
||||
assertEquals(player1, top.get(0).getPlayerId());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testGetTopByMine_OnlyIncludesSpecificMine() {
|
||||
UUID player1 = UUID.randomUUID();
|
||||
UUID player2 = UUID.randomUUID();
|
||||
|
||||
|
||||
statsManager.getOrCreate(player1).setMineBlocks("mine1", 100);
|
||||
statsManager.getOrCreate(player2).setMineBlocks("mine2", 200);
|
||||
|
||||
|
||||
List<LeaderboardEntry> top = leaderboard.getTopByMine("mine1", 10);
|
||||
assertEquals(1, top.size(), "Should only include players with blocks in specified mine");
|
||||
assertEquals(player1, top.get(0).getPlayerId());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testGetPosition_ReturnsCorrectPosition() {
|
||||
UUID player1 = UUID.randomUUID();
|
||||
UUID player2 = UUID.randomUUID();
|
||||
UUID player3 = UUID.randomUUID();
|
||||
|
||||
|
||||
statsManager.getOrCreate(player1).setTotalBlocks(50);
|
||||
statsManager.getOrCreate(player2).setTotalBlocks(200);
|
||||
statsManager.getOrCreate(player3).setTotalBlocks(100);
|
||||
|
||||
|
||||
assertEquals(1, leaderboard.getPosition(player2), "Player with most blocks should be position 1");
|
||||
assertEquals(2, leaderboard.getPosition(player3), "Player with second most blocks should be position 2");
|
||||
assertEquals(3, leaderboard.getPosition(player1), "Player with least blocks should be position 3");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testGetPosition_ReturnsMinusOneForNonExistentPlayer() {
|
||||
UUID playerId = UUID.randomUUID();
|
||||
assertEquals(-1, leaderboard.getPosition(playerId), "Should return -1 for non-existent player");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testGetPosition_ReturnsMinusOneForZeroBlocks() {
|
||||
UUID playerId = UUID.randomUUID();
|
||||
statsManager.getOrCreate(playerId).setTotalBlocks(0);
|
||||
|
||||
|
||||
assertEquals(-1, leaderboard.getPosition(playerId), "Should return -1 for player with 0 blocks");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
package com.loki.lomines.data;
|
||||
package dev.loki.lomines.data;
|
||||
|
||||
import com.loki.lomines.LoMinesPlugin;
|
||||
import dev.loki.lomines.LoMinesPlugin;
|
||||
import dev.lolib.core.LoLogger;
|
||||
import dev.lolib.scheduler.Scheduler;
|
||||
import dev.lolib.scheduler.ScheduledTask;
|
||||
import dev.lolib.scheduler.Scheduler;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
|
@ -25,51 +25,50 @@ import static org.mockito.Mockito.*;
|
|||
* Tests loading, saving, and auto-saving of player statistics.
|
||||
*/
|
||||
class StatsManagerTest {
|
||||
|
||||
|
||||
@TempDir
|
||||
Path tempDir;
|
||||
private StatsManager statsManager;
|
||||
private LoMinesPlugin plugin;
|
||||
private Scheduler scheduler;
|
||||
|
||||
@TempDir
|
||||
Path tempDir;
|
||||
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
plugin = mock(LoMinesPlugin.class);
|
||||
LoLogger loLogger = mock(LoLogger.class);
|
||||
scheduler = mock(Scheduler.class);
|
||||
|
||||
|
||||
when(plugin.getDataFolder()).thenReturn(tempDir.toFile());
|
||||
when(plugin.getLogger()).thenReturn(Logger.getLogger("TestLogger"));
|
||||
when(plugin.loLogger()).thenReturn(loLogger);
|
||||
|
||||
|
||||
statsManager = new StatsManager(plugin);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testGetOrCreate() {
|
||||
UUID playerId = UUID.randomUUID();
|
||||
|
||||
|
||||
PlayerStats stats1 = statsManager.getOrCreate(playerId);
|
||||
assertNotNull(stats1);
|
||||
assertEquals(playerId, stats1.getPlayerId());
|
||||
|
||||
|
||||
// Should return the same instance
|
||||
PlayerStats stats2 = statsManager.getOrCreate(playerId);
|
||||
assertSame(stats1, stats2);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testIncrementBlocks() {
|
||||
UUID playerId = UUID.randomUUID();
|
||||
String mineName = "TestMine";
|
||||
|
||||
|
||||
statsManager.incrementBlocks(playerId, mineName);
|
||||
|
||||
|
||||
PlayerStats stats = statsManager.getOrCreate(playerId);
|
||||
assertEquals(1, stats.getTotalBlocks());
|
||||
assertEquals(1, stats.getMineBlocks(mineName));
|
||||
|
||||
|
||||
// Increment again
|
||||
statsManager.incrementBlocks(playerId, mineName);
|
||||
assertEquals(2, stats.getTotalBlocks());
|
||||
|
|
@ -79,85 +78,85 @@ class StatsManagerTest {
|
|||
@Test
|
||||
void testIncrementBlocksMultipleMines() {
|
||||
UUID playerId = UUID.randomUUID();
|
||||
|
||||
|
||||
statsManager.incrementBlocks(playerId, "Mine1");
|
||||
statsManager.incrementBlocks(playerId, "Mine2");
|
||||
statsManager.incrementBlocks(playerId, "Mine1");
|
||||
|
||||
|
||||
PlayerStats stats = statsManager.getOrCreate(playerId);
|
||||
assertEquals(3, stats.getTotalBlocks());
|
||||
assertEquals(2, stats.getMineBlocks("Mine1"));
|
||||
assertEquals(1, stats.getMineBlocks("Mine2"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testSaveEmptyStats() throws IOException {
|
||||
statsManager.save();
|
||||
|
||||
|
||||
Path statsFile = tempDir.resolve("stats.yml");
|
||||
assertTrue(Files.exists(statsFile));
|
||||
|
||||
|
||||
YamlConfiguration yaml = YamlConfiguration.loadConfiguration(statsFile.toFile());
|
||||
assertNull(yaml.getConfigurationSection("players"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testSaveWithStats() throws IOException {
|
||||
UUID playerId = UUID.randomUUID();
|
||||
statsManager.incrementBlocks(playerId, "TestMine");
|
||||
statsManager.incrementBlocks(playerId, "TestMine");
|
||||
statsManager.incrementBlocks(playerId, "AnotherMine");
|
||||
|
||||
|
||||
statsManager.save();
|
||||
|
||||
|
||||
Path statsFile = tempDir.resolve("stats.yml");
|
||||
assertTrue(Files.exists(statsFile));
|
||||
|
||||
|
||||
YamlConfiguration yaml = YamlConfiguration.loadConfiguration(statsFile.toFile());
|
||||
assertNotNull(yaml.getConfigurationSection("players"));
|
||||
|
||||
String playerPath = "players." + playerId.toString();
|
||||
|
||||
String playerPath = "players." + playerId;
|
||||
assertEquals(3, yaml.getLong(playerPath + ".total"));
|
||||
assertEquals(2, yaml.getLong(playerPath + ".mines.testmine"));
|
||||
assertEquals(1, yaml.getLong(playerPath + ".mines.anothermine"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testLoadNonExistentFile() throws IOException {
|
||||
// Should not throw exception, just log info
|
||||
statsManager.load();
|
||||
|
||||
|
||||
// Stats should be empty
|
||||
assertTrue(statsManager.getAllStats().isEmpty());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testLoadEmptyFile() throws IOException {
|
||||
Path statsFile = tempDir.resolve("stats.yml");
|
||||
Files.writeString(statsFile, "");
|
||||
|
||||
|
||||
statsManager.load();
|
||||
|
||||
|
||||
assertTrue(statsManager.getAllStats().isEmpty());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testLoadValidStats() throws IOException {
|
||||
UUID playerId = UUID.randomUUID();
|
||||
String yamlContent = String.format("""
|
||||
players:
|
||||
%s:
|
||||
total: 100
|
||||
mines:
|
||||
mine1: 60
|
||||
mine2: 40
|
||||
""", playerId.toString());
|
||||
|
||||
players:
|
||||
%s:
|
||||
total: 100
|
||||
mines:
|
||||
mine1: 60
|
||||
mine2: 40
|
||||
""", playerId);
|
||||
|
||||
Path statsFile = tempDir.resolve("stats.yml");
|
||||
Files.writeString(statsFile, yamlContent);
|
||||
|
||||
|
||||
statsManager.load();
|
||||
|
||||
|
||||
PlayerStats stats = statsManager.getOrCreate(playerId);
|
||||
assertEquals(100, stats.getTotalBlocks());
|
||||
assertEquals(60, stats.getMineBlocks("mine1"));
|
||||
|
|
@ -167,93 +166,93 @@ class StatsManagerTest {
|
|||
@Test
|
||||
void testLoadInvalidUUID() throws IOException {
|
||||
String yamlContent = """
|
||||
players:
|
||||
invalid-uuid:
|
||||
total: 100
|
||||
""";
|
||||
|
||||
players:
|
||||
invalid-uuid:
|
||||
total: 100
|
||||
""";
|
||||
|
||||
Path statsFile = tempDir.resolve("stats.yml");
|
||||
Files.writeString(statsFile, yamlContent);
|
||||
|
||||
|
||||
// Should not throw exception, just log warning
|
||||
statsManager.load();
|
||||
|
||||
|
||||
assertTrue(statsManager.getAllStats().isEmpty());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testSaveAndLoadRoundTrip() throws IOException {
|
||||
UUID player1 = UUID.randomUUID();
|
||||
UUID player2 = UUID.randomUUID();
|
||||
|
||||
|
||||
statsManager.incrementBlocks(player1, "Mine1");
|
||||
statsManager.incrementBlocks(player1, "Mine1");
|
||||
statsManager.incrementBlocks(player1, "Mine2");
|
||||
statsManager.incrementBlocks(player2, "Mine1");
|
||||
|
||||
|
||||
statsManager.save();
|
||||
|
||||
|
||||
// Create new manager and load
|
||||
StatsManager newManager = new StatsManager(plugin);
|
||||
newManager.load();
|
||||
|
||||
|
||||
PlayerStats stats1 = newManager.getOrCreate(player1);
|
||||
assertEquals(3, stats1.getTotalBlocks());
|
||||
assertEquals(2, stats1.getMineBlocks("Mine1"));
|
||||
assertEquals(1, stats1.getMineBlocks("Mine2"));
|
||||
|
||||
|
||||
PlayerStats stats2 = newManager.getOrCreate(player2);
|
||||
assertEquals(1, stats2.getTotalBlocks());
|
||||
assertEquals(1, stats2.getMineBlocks("Mine1"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testStartAutoSave() {
|
||||
try (MockedStatic<Scheduler> schedulerStatic = mockStatic(Scheduler.class)) {
|
||||
ScheduledTask task = mock(ScheduledTask.class);
|
||||
|
||||
|
||||
schedulerStatic.when(() -> Scheduler.get(plugin)).thenReturn(scheduler);
|
||||
when(scheduler.runTimerAsync(any(Runnable.class), anyLong(), anyLong())).thenReturn(task);
|
||||
|
||||
|
||||
statsManager.startAutoSave();
|
||||
|
||||
|
||||
// Verify that runTimerAsync was called with correct interval (5 minutes = 6000 ticks)
|
||||
verify(scheduler).runTimerAsync(any(Runnable.class), eq(6000L), eq(6000L));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testStopAutoSave() {
|
||||
try (MockedStatic<Scheduler> schedulerStatic = mockStatic(Scheduler.class)) {
|
||||
ScheduledTask task = mock(ScheduledTask.class);
|
||||
|
||||
|
||||
schedulerStatic.when(() -> Scheduler.get(plugin)).thenReturn(scheduler);
|
||||
when(scheduler.runTimerAsync(any(Runnable.class), anyLong(), anyLong())).thenReturn(task);
|
||||
|
||||
|
||||
statsManager.startAutoSave();
|
||||
statsManager.stopAutoSave();
|
||||
|
||||
|
||||
verify(task).cancel();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testStopAutoSaveWithoutStart() {
|
||||
// Should not throw exception
|
||||
assertDoesNotThrow(() -> statsManager.stopAutoSave());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testGetAllStats() {
|
||||
UUID player1 = UUID.randomUUID();
|
||||
UUID player2 = UUID.randomUUID();
|
||||
|
||||
|
||||
statsManager.incrementBlocks(player1, "Mine1");
|
||||
statsManager.incrementBlocks(player2, "Mine2");
|
||||
|
||||
|
||||
assertEquals(2, statsManager.getAllStats().size());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testGetLeaderboard() {
|
||||
assertNotNull(statsManager.getLeaderboard());
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.loki.lomines.util;
|
||||
package dev.loki.lomines.util;
|
||||
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
|
|
@ -11,7 +11,8 @@ import org.mockito.MockitoAnnotations;
|
|||
|
||||
import java.util.Collections;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
|
|
@ -20,135 +21,135 @@ import static org.mockito.Mockito.*;
|
|||
* Tests Paper detection and chunk update functionality.
|
||||
*/
|
||||
class ChunkUtilsTest {
|
||||
|
||||
|
||||
@Mock
|
||||
private World world;
|
||||
|
||||
|
||||
@Mock
|
||||
private Chunk chunk;
|
||||
|
||||
|
||||
@Mock
|
||||
private Player player;
|
||||
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
MockitoAnnotations.openMocks(this);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testUpdateChunks_withNullRegion_throwsException() {
|
||||
assertThrows(IllegalArgumentException.class, () -> {
|
||||
ChunkUtils.updateChunks(null);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testUpdateChunks_withSingleChunkRegion() {
|
||||
// Create a small region within a single chunk
|
||||
Location loc1 = new Location(world, 0, 64, 0);
|
||||
Location loc2 = new Location(world, 5, 70, 5);
|
||||
Cuboid region = new Cuboid(loc1, loc2);
|
||||
|
||||
|
||||
when(world.getChunkAt(anyInt(), anyInt())).thenReturn(chunk);
|
||||
when(world.getPlayers()).thenReturn(Collections.singletonList(player));
|
||||
when(chunk.getWorld()).thenReturn(world);
|
||||
when(chunk.getX()).thenReturn(0);
|
||||
when(chunk.getZ()).thenReturn(0);
|
||||
|
||||
|
||||
// Should not throw exception
|
||||
assertDoesNotThrow(() -> ChunkUtils.updateChunks(region));
|
||||
|
||||
|
||||
// Verify chunk was retrieved
|
||||
verify(world, atLeastOnce()).getChunkAt(0, 0);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testUpdateChunks_withMultipleChunks() {
|
||||
// Create a region spanning multiple chunks (16 blocks per chunk)
|
||||
Location loc1 = new Location(world, 0, 64, 0);
|
||||
Location loc2 = new Location(world, 32, 70, 32);
|
||||
Cuboid region = new Cuboid(loc1, loc2);
|
||||
|
||||
|
||||
when(world.getChunkAt(anyInt(), anyInt())).thenReturn(chunk);
|
||||
when(world.getPlayers()).thenReturn(Collections.singletonList(player));
|
||||
when(chunk.getWorld()).thenReturn(world);
|
||||
when(chunk.getX()).thenReturn(0);
|
||||
when(chunk.getZ()).thenReturn(0);
|
||||
|
||||
|
||||
assertDoesNotThrow(() -> ChunkUtils.updateChunks(region));
|
||||
|
||||
|
||||
// Should retrieve multiple chunks (0,0), (0,1), (0,2), (1,0), (1,1), (1,2), (2,0), (2,1), (2,2)
|
||||
// That's 9 chunks total for a 3x3 chunk area
|
||||
verify(world, atLeast(9)).getChunkAt(anyInt(), anyInt());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testUpdateChunks_withNegativeCoordinates() {
|
||||
// Test with negative coordinates
|
||||
Location loc1 = new Location(world, -16, 64, -16);
|
||||
Location loc2 = new Location(world, -1, 70, -1);
|
||||
Cuboid region = new Cuboid(loc1, loc2);
|
||||
|
||||
|
||||
when(world.getChunkAt(anyInt(), anyInt())).thenReturn(chunk);
|
||||
when(world.getPlayers()).thenReturn(Collections.singletonList(player));
|
||||
when(chunk.getWorld()).thenReturn(world);
|
||||
when(chunk.getX()).thenReturn(-1);
|
||||
when(chunk.getZ()).thenReturn(-1);
|
||||
|
||||
|
||||
assertDoesNotThrow(() -> ChunkUtils.updateChunks(region));
|
||||
|
||||
|
||||
// Verify chunk was retrieved for negative coordinates
|
||||
verify(world, atLeastOnce()).getChunkAt(-1, -1);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testUpdateChunks_withLargeRegion() {
|
||||
// Test with a large region spanning many chunks
|
||||
Location loc1 = new Location(world, 0, 0, 0);
|
||||
Location loc2 = new Location(world, 100, 100, 100);
|
||||
Cuboid region = new Cuboid(loc1, loc2);
|
||||
|
||||
|
||||
when(world.getChunkAt(anyInt(), anyInt())).thenReturn(chunk);
|
||||
when(world.getPlayers()).thenReturn(Collections.emptyList());
|
||||
when(chunk.getWorld()).thenReturn(world);
|
||||
|
||||
|
||||
assertDoesNotThrow(() -> ChunkUtils.updateChunks(region));
|
||||
|
||||
|
||||
// Should handle large regions without issues
|
||||
// 100 blocks = ~7 chunks per axis, so ~49 chunks total
|
||||
verify(world, atLeast(40)).getChunkAt(anyInt(), anyInt());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testUpdateChunks_withNoPlayers() {
|
||||
// Test behavior when no players are online
|
||||
Location loc1 = new Location(world, 0, 64, 0);
|
||||
Location loc2 = new Location(world, 5, 70, 5);
|
||||
Cuboid region = new Cuboid(loc1, loc2);
|
||||
|
||||
|
||||
when(world.getChunkAt(anyInt(), anyInt())).thenReturn(chunk);
|
||||
when(world.getPlayers()).thenReturn(Collections.emptyList());
|
||||
when(chunk.getWorld()).thenReturn(world);
|
||||
|
||||
|
||||
// Should not throw exception even with no players
|
||||
assertDoesNotThrow(() -> ChunkUtils.updateChunks(region));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testChunkCoordinateCalculation() {
|
||||
// Test that chunk coordinates are calculated correctly
|
||||
// Block 0-15 = chunk 0, block 16-31 = chunk 1, etc.
|
||||
|
||||
|
||||
Location loc1 = new Location(world, 0, 64, 0);
|
||||
Location loc2 = new Location(world, 15, 70, 15);
|
||||
Cuboid singleChunk = new Cuboid(loc1, loc2);
|
||||
|
||||
|
||||
when(world.getChunkAt(anyInt(), anyInt())).thenReturn(chunk);
|
||||
when(world.getPlayers()).thenReturn(Collections.emptyList());
|
||||
when(chunk.getWorld()).thenReturn(world);
|
||||
|
||||
|
||||
ChunkUtils.updateChunks(singleChunk);
|
||||
|
||||
|
||||
// Should only access chunk (0,0)
|
||||
verify(world, times(1)).getChunkAt(0, 0);
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
package com.loki.lomines.util;
|
||||
package dev.loki.lomines.util;
|
||||
|
||||
import com.loki.lomines.data.ConfigParseException;
|
||||
import dev.loki.lomines.data.config.parser.ConfigParseException;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
|
|
@ -9,19 +9,20 @@ import org.mockito.MockedStatic;
|
|||
import org.mockito.Mockito;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
class LocationParserTest {
|
||||
|
||||
|
||||
@Test
|
||||
void testParseValidLocation() throws ConfigParseException {
|
||||
try (MockedStatic<Bukkit> bukkit = Mockito.mockStatic(Bukkit.class)) {
|
||||
World mockWorld = mock(World.class);
|
||||
when(mockWorld.getName()).thenReturn("world");
|
||||
bukkit.when(() -> Bukkit.getWorld("world")).thenReturn(mockWorld);
|
||||
|
||||
|
||||
Location location = LocationParser.parse("world;100.5;64.0;-200.75;90.0;45.0");
|
||||
|
||||
|
||||
assertNotNull(location);
|
||||
assertEquals(mockWorld, location.getWorld());
|
||||
assertEquals(100.5, location.getX(), 0.001);
|
||||
|
|
@ -31,31 +32,31 @@ class LocationParserTest {
|
|||
assertEquals(45.0f, location.getPitch(), 0.001);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testParseIntegerCoordinates() throws ConfigParseException {
|
||||
try (MockedStatic<Bukkit> bukkit = Mockito.mockStatic(Bukkit.class)) {
|
||||
World mockWorld = mock(World.class);
|
||||
when(mockWorld.getName()).thenReturn("world_nether");
|
||||
bukkit.when(() -> Bukkit.getWorld("world_nether")).thenReturn(mockWorld);
|
||||
|
||||
|
||||
Location location = LocationParser.parse("world_nether;0;128;0;0;0");
|
||||
|
||||
|
||||
assertNotNull(location);
|
||||
assertEquals(0.0, location.getX(), 0.001);
|
||||
assertEquals(128.0, location.getY(), 0.001);
|
||||
assertEquals(0.0, location.getZ(), 0.001);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testParseNegativeCoordinates() throws ConfigParseException {
|
||||
try (MockedStatic<Bukkit> bukkit = Mockito.mockStatic(Bukkit.class)) {
|
||||
World mockWorld = mock(World.class);
|
||||
bukkit.when(() -> Bukkit.getWorld("world")).thenReturn(mockWorld);
|
||||
|
||||
|
||||
Location location = LocationParser.parse("world;-100;-64;-200;-180;-90");
|
||||
|
||||
|
||||
assertNotNull(location);
|
||||
assertEquals(-100.0, location.getX(), 0.001);
|
||||
assertEquals(-64.0, location.getY(), 0.001);
|
||||
|
|
@ -64,111 +65,111 @@ class LocationParserTest {
|
|||
assertEquals(-90.0f, location.getPitch(), 0.001);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testParseNullString() {
|
||||
ConfigParseException exception = assertThrows(
|
||||
ConfigParseException.class,
|
||||
() -> LocationParser.parse(null)
|
||||
ConfigParseException.class,
|
||||
() -> LocationParser.parse(null)
|
||||
);
|
||||
assertTrue(exception.getMessage().contains("cannot be null or empty"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testParseEmptyString() {
|
||||
ConfigParseException exception = assertThrows(
|
||||
ConfigParseException.class,
|
||||
() -> LocationParser.parse("")
|
||||
ConfigParseException.class,
|
||||
() -> LocationParser.parse("")
|
||||
);
|
||||
assertTrue(exception.getMessage().contains("cannot be null or empty"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testParseInvalidFormat() {
|
||||
ConfigParseException exception = assertThrows(
|
||||
ConfigParseException.class,
|
||||
() -> LocationParser.parse("world;100;64")
|
||||
ConfigParseException.class,
|
||||
() -> LocationParser.parse("world;100;64")
|
||||
);
|
||||
assertTrue(exception.getMessage().contains("Invalid location format"));
|
||||
assertTrue(exception.getMessage().contains("Expected format"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testParseInvalidNumbers() {
|
||||
ConfigParseException exception = assertThrows(
|
||||
ConfigParseException.class,
|
||||
() -> LocationParser.parse("world;abc;64;0;0;0")
|
||||
ConfigParseException.class,
|
||||
() -> LocationParser.parse("world;abc;64;0;0;0")
|
||||
);
|
||||
assertTrue(exception.getMessage().contains("Invalid location format"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testParseNonExistentWorld() {
|
||||
try (MockedStatic<Bukkit> bukkit = Mockito.mockStatic(Bukkit.class)) {
|
||||
bukkit.when(() -> Bukkit.getWorld("nonexistent")).thenReturn(null);
|
||||
|
||||
|
||||
ConfigParseException exception = assertThrows(
|
||||
ConfigParseException.class,
|
||||
() -> LocationParser.parse("nonexistent;0;64;0;0;0")
|
||||
ConfigParseException.class,
|
||||
() -> LocationParser.parse("nonexistent;0;64;0;0;0")
|
||||
);
|
||||
assertTrue(exception.getMessage().contains("does not exist"));
|
||||
assertTrue(exception.getMessage().contains("nonexistent"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testFormatValidLocation() {
|
||||
World mockWorld = mock(World.class);
|
||||
when(mockWorld.getName()).thenReturn("world");
|
||||
|
||||
|
||||
Location location = new Location(mockWorld, 100.5, 64.0, -200.75, 90.0f, 45.0f);
|
||||
String formatted = LocationParser.format(location);
|
||||
|
||||
|
||||
assertEquals("world;100.50;64.00;-200.75;90.00;45.00", formatted);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testFormatIntegerCoordinates() {
|
||||
World mockWorld = mock(World.class);
|
||||
when(mockWorld.getName()).thenReturn("world_nether");
|
||||
|
||||
|
||||
Location location = new Location(mockWorld, 0, 128, 0, 0, 0);
|
||||
String formatted = LocationParser.format(location);
|
||||
|
||||
|
||||
assertEquals("world_nether;0.00;128.00;0.00;0.00;0.00", formatted);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testFormatNullLocation() {
|
||||
IllegalArgumentException exception = assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> LocationParser.format(null)
|
||||
IllegalArgumentException.class,
|
||||
() -> LocationParser.format(null)
|
||||
);
|
||||
assertTrue(exception.getMessage().contains("Location cannot be null"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testFormatNullWorld() {
|
||||
Location location = new Location(null, 0, 0, 0);
|
||||
|
||||
|
||||
IllegalArgumentException exception = assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> LocationParser.format(location)
|
||||
IllegalArgumentException.class,
|
||||
() -> LocationParser.format(location)
|
||||
);
|
||||
assertTrue(exception.getMessage().contains("world cannot be null"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testRoundTrip() throws ConfigParseException {
|
||||
try (MockedStatic<Bukkit> bukkit = Mockito.mockStatic(Bukkit.class)) {
|
||||
World mockWorld = mock(World.class);
|
||||
when(mockWorld.getName()).thenReturn("world");
|
||||
bukkit.when(() -> Bukkit.getWorld("world")).thenReturn(mockWorld);
|
||||
|
||||
|
||||
Location original = new Location(mockWorld, 100.5, 64.0, -200.75, 90.0f, 45.0f);
|
||||
String formatted = LocationParser.format(original);
|
||||
Location parsed = LocationParser.parse(formatted);
|
||||
|
||||
|
||||
assertEquals(original.getX(), parsed.getX(), 0.01);
|
||||
assertEquals(original.getY(), parsed.getY(), 0.01);
|
||||
assertEquals(original.getZ(), parsed.getZ(), 0.01);
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.loki.lomines.util;
|
||||
package dev.loki.lomines.util;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
|
@ -9,119 +9,119 @@ import java.util.UUID;
|
|||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class SelectionManagerTest {
|
||||
|
||||
|
||||
private SelectionManager manager;
|
||||
private UUID playerId;
|
||||
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
manager = new SelectionManager();
|
||||
playerId = UUID.randomUUID();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void getSelection_createsNewSelectionIfNotExists() {
|
||||
Selection selection = manager.getSelection(playerId);
|
||||
|
||||
|
||||
assertNotNull(selection);
|
||||
assertTrue(manager.hasSelection(playerId));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void getSelection_returnsSameInstanceOnMultipleCalls() {
|
||||
Selection first = manager.getSelection(playerId);
|
||||
Selection second = manager.getSelection(playerId);
|
||||
|
||||
|
||||
assertSame(first, second);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void getSelection_throwsExceptionForNullPlayerId() {
|
||||
assertThrows(IllegalArgumentException.class, () -> {
|
||||
manager.getSelection(null);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void findSelection_returnsEmptyWhenNotExists() {
|
||||
Optional<Selection> result = manager.findSelection(playerId);
|
||||
|
||||
|
||||
assertTrue(result.isEmpty());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void findSelection_returnsSelectionWhenExists() {
|
||||
Selection created = manager.getSelection(playerId);
|
||||
Optional<Selection> found = manager.findSelection(playerId);
|
||||
|
||||
|
||||
assertTrue(found.isPresent());
|
||||
assertSame(created, found.get());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void findSelection_throwsExceptionForNullPlayerId() {
|
||||
assertThrows(IllegalArgumentException.class, () -> {
|
||||
manager.findSelection(null);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void hasSelection_returnsFalseWhenNotExists() {
|
||||
assertFalse(manager.hasSelection(playerId));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void hasSelection_returnsTrueWhenExists() {
|
||||
manager.getSelection(playerId);
|
||||
|
||||
|
||||
assertTrue(manager.hasSelection(playerId));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void hasSelection_throwsExceptionForNullPlayerId() {
|
||||
assertThrows(IllegalArgumentException.class, () -> {
|
||||
manager.hasSelection(null);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void clearSelection_removesSelection() {
|
||||
manager.getSelection(playerId);
|
||||
assertTrue(manager.hasSelection(playerId));
|
||||
|
||||
|
||||
manager.clearSelection(playerId);
|
||||
|
||||
|
||||
assertFalse(manager.hasSelection(playerId));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void clearSelection_doesNothingWhenSelectionNotExists() {
|
||||
assertDoesNotThrow(() -> {
|
||||
manager.clearSelection(playerId);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void clearSelection_throwsExceptionForNullPlayerId() {
|
||||
assertThrows(IllegalArgumentException.class, () -> {
|
||||
manager.clearSelection(null);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void multiplePlayersHaveIndependentSelections() {
|
||||
UUID player1 = UUID.randomUUID();
|
||||
UUID player2 = UUID.randomUUID();
|
||||
|
||||
|
||||
Selection selection1 = manager.getSelection(player1);
|
||||
Selection selection2 = manager.getSelection(player2);
|
||||
|
||||
|
||||
assertNotSame(selection1, selection2);
|
||||
assertTrue(manager.hasSelection(player1));
|
||||
assertTrue(manager.hasSelection(player2));
|
||||
|
||||
|
||||
manager.clearSelection(player1);
|
||||
|
||||
|
||||
assertFalse(manager.hasSelection(player1));
|
||||
assertTrue(manager.hasSelection(player2));
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.loki.lomines.util;
|
||||
package dev.loki.lomines.util;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
|
|
@ -13,207 +13,207 @@ import static org.mockito.Mockito.mock;
|
|||
import static org.mockito.Mockito.when;
|
||||
|
||||
class SelectionTest {
|
||||
|
||||
|
||||
private World world;
|
||||
private Selection selection;
|
||||
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
world = mock(World.class);
|
||||
selection = new Selection();
|
||||
when(world.getName()).thenReturn("world");
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testSetAndGetPoint() {
|
||||
Location loc = new Location(world, 10, 64, 20);
|
||||
|
||||
|
||||
selection.setPoint(0, loc);
|
||||
|
||||
|
||||
Optional<Location> result = selection.getPoint(0);
|
||||
assertTrue(result.isPresent());
|
||||
assertEquals(loc, result.get());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testGetPointReturnsEmptyWhenNotSet() {
|
||||
Optional<Location> result = selection.getPoint(5);
|
||||
assertFalse(result.isPresent());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testSetPointInvalidIndexThrows() {
|
||||
Location loc = new Location(world, 10, 64, 20);
|
||||
|
||||
|
||||
assertThrows(IllegalArgumentException.class, () -> selection.setPoint(-1, loc));
|
||||
assertThrows(IllegalArgumentException.class, () -> selection.setPoint(10, loc));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testGetPointInvalidIndexThrows() {
|
||||
assertThrows(IllegalArgumentException.class, () -> selection.getPoint(-1));
|
||||
assertThrows(IllegalArgumentException.class, () -> selection.getPoint(10));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testGetPair() {
|
||||
Location loc1 = new Location(world, 10, 64, 20);
|
||||
Location loc2 = new Location(world, 20, 74, 30);
|
||||
|
||||
|
||||
selection.setPoint(0, loc1);
|
||||
selection.setPoint(1, loc2);
|
||||
|
||||
|
||||
Location[] pair = selection.getPair(0);
|
||||
assertEquals(2, pair.length);
|
||||
assertEquals(loc1, pair[0]);
|
||||
assertEquals(loc2, pair[1]);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testGetPairWithNulls() {
|
||||
Location loc1 = new Location(world, 10, 64, 20);
|
||||
|
||||
|
||||
selection.setPoint(2, loc1);
|
||||
|
||||
|
||||
Location[] pair = selection.getPair(1);
|
||||
assertEquals(2, pair.length);
|
||||
assertEquals(loc1, pair[0]);
|
||||
assertNull(pair[1]);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testGetPairInvalidIndexThrows() {
|
||||
assertThrows(IllegalArgumentException.class, () -> selection.getPair(-1));
|
||||
assertThrows(IllegalArgumentException.class, () -> selection.getPair(5));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testHasPairReturnsTrueWhenBothSet() {
|
||||
Location loc1 = new Location(world, 10, 64, 20);
|
||||
Location loc2 = new Location(world, 20, 74, 30);
|
||||
|
||||
|
||||
selection.setPoint(0, loc1);
|
||||
selection.setPoint(1, loc2);
|
||||
|
||||
|
||||
assertTrue(selection.hasPair(0));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testHasPairReturnsFalseWhenOnlyOneSet() {
|
||||
Location loc1 = new Location(world, 10, 64, 20);
|
||||
|
||||
|
||||
selection.setPoint(0, loc1);
|
||||
|
||||
|
||||
assertFalse(selection.hasPair(0));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testHasPairReturnsFalseWhenNoneSet() {
|
||||
assertFalse(selection.hasPair(0));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testHasPairInvalidIndexThrows() {
|
||||
assertThrows(IllegalArgumentException.class, () -> selection.hasPair(-1));
|
||||
assertThrows(IllegalArgumentException.class, () -> selection.hasPair(5));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testClear() {
|
||||
Location loc1 = new Location(world, 10, 64, 20);
|
||||
Location loc2 = new Location(world, 20, 74, 30);
|
||||
|
||||
|
||||
selection.setPoint(0, loc1);
|
||||
selection.setPoint(1, loc2);
|
||||
selection.setPoint(5, loc1);
|
||||
|
||||
|
||||
selection.clear();
|
||||
|
||||
|
||||
assertFalse(selection.getPoint(0).isPresent());
|
||||
assertFalse(selection.getPoint(1).isPresent());
|
||||
assertFalse(selection.getPoint(5).isPresent());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testToCuboidsWithNoPairs() {
|
||||
List<Cuboid> cuboids = selection.toCuboids();
|
||||
|
||||
|
||||
assertTrue(cuboids.isEmpty());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testToCuboidsWithOnePair() {
|
||||
Location loc1 = new Location(world, 10, 64, 20);
|
||||
Location loc2 = new Location(world, 20, 74, 30);
|
||||
|
||||
|
||||
selection.setPoint(0, loc1);
|
||||
selection.setPoint(1, loc2);
|
||||
|
||||
|
||||
List<Cuboid> cuboids = selection.toCuboids();
|
||||
|
||||
|
||||
assertEquals(1, cuboids.size());
|
||||
assertTrue(cuboids.get(0).contains(new Location(world, 15, 69, 25)));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testToCuboidsWithMultiplePairs() {
|
||||
Location loc1 = new Location(world, 10, 64, 20);
|
||||
Location loc2 = new Location(world, 20, 74, 30);
|
||||
Location loc3 = new Location(world, 30, 64, 40);
|
||||
Location loc4 = new Location(world, 40, 74, 50);
|
||||
|
||||
|
||||
selection.setPoint(0, loc1);
|
||||
selection.setPoint(1, loc2);
|
||||
selection.setPoint(2, loc3);
|
||||
selection.setPoint(3, loc4);
|
||||
|
||||
|
||||
List<Cuboid> cuboids = selection.toCuboids();
|
||||
|
||||
|
||||
assertEquals(2, cuboids.size());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testToCuboidsSkipsIncompletePairs() {
|
||||
Location loc1 = new Location(world, 10, 64, 20);
|
||||
Location loc2 = new Location(world, 20, 74, 30);
|
||||
Location loc3 = new Location(world, 30, 64, 40);
|
||||
|
||||
|
||||
selection.setPoint(0, loc1);
|
||||
selection.setPoint(1, loc2);
|
||||
selection.setPoint(2, loc3);
|
||||
// Point 3 not set
|
||||
|
||||
|
||||
List<Cuboid> cuboids = selection.toCuboids();
|
||||
|
||||
|
||||
assertEquals(1, cuboids.size());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testPairInvariant() {
|
||||
// Test that pairs are organized as 2i and 2i+1
|
||||
Location loc1 = new Location(world, 10, 64, 20);
|
||||
Location loc2 = new Location(world, 20, 74, 30);
|
||||
|
||||
|
||||
// Pair 0: indices 0 and 1
|
||||
selection.setPoint(0, loc1);
|
||||
selection.setPoint(1, loc2);
|
||||
assertTrue(selection.hasPair(0));
|
||||
|
||||
|
||||
// Pair 1: indices 2 and 3
|
||||
selection.setPoint(2, loc1);
|
||||
selection.setPoint(3, loc2);
|
||||
assertTrue(selection.hasPair(1));
|
||||
|
||||
|
||||
// Pair 2: indices 4 and 5
|
||||
selection.setPoint(4, loc1);
|
||||
selection.setPoint(5, loc2);
|
||||
assertTrue(selection.hasPair(2));
|
||||
|
||||
|
||||
// Pair 3: indices 6 and 7
|
||||
selection.setPoint(6, loc1);
|
||||
selection.setPoint(7, loc2);
|
||||
assertTrue(selection.hasPair(3));
|
||||
|
||||
|
||||
// Pair 4: indices 8 and 9
|
||||
selection.setPoint(8, loc1);
|
||||
selection.setPoint(9, loc2);
|
||||
|
|
@ -1,98 +1,99 @@
|
|||
package com.loki.lomines.util;
|
||||
package dev.loki.lomines.util;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class TimeFormatterTest {
|
||||
|
||||
|
||||
@Test
|
||||
void testFormatMinutesSeconds() {
|
||||
// 1 minute = 60 seconds = 1200 ticks
|
||||
assertEquals("01:00", TimeFormatter.format(1200, "mm:ss"));
|
||||
|
||||
|
||||
// 2 minutes 30 seconds = 150 seconds = 3000 ticks
|
||||
assertEquals("02:30", TimeFormatter.format(3000, "mm:ss"));
|
||||
|
||||
|
||||
// 0 seconds
|
||||
assertEquals("00:00", TimeFormatter.format(0, "mm:ss"));
|
||||
|
||||
|
||||
// 59 seconds = 1180 ticks
|
||||
assertEquals("00:59", TimeFormatter.format(1180, "mm:ss"));
|
||||
|
||||
|
||||
// 10 minutes 5 seconds = 605 seconds = 12100 ticks
|
||||
assertEquals("10:05", TimeFormatter.format(12100, "mm:ss"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testFormatHoursMinutesSeconds() {
|
||||
// 1 hour = 3600 seconds = 72000 ticks
|
||||
assertEquals("01:00:00", TimeFormatter.format(72000, "hh:mm:ss"));
|
||||
|
||||
|
||||
// 1 hour 30 minutes 45 seconds = 5445 seconds = 108900 ticks
|
||||
assertEquals("01:30:45", TimeFormatter.format(108900, "hh:mm:ss"));
|
||||
|
||||
|
||||
// 0 seconds
|
||||
assertEquals("00:00:00", TimeFormatter.format(0, "hh:mm:ss"));
|
||||
|
||||
|
||||
// 2 hours 5 minutes 3 seconds = 7503 seconds = 150060 ticks
|
||||
assertEquals("02:05:03", TimeFormatter.format(150060, "hh:mm:ss"));
|
||||
|
||||
|
||||
// 23 hours 59 minutes 59 seconds = 86399 seconds = 1727980 ticks
|
||||
assertEquals("23:59:59", TimeFormatter.format(1727980, "hh:mm:ss"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testFormatSeconds() {
|
||||
// 100 ticks = 5 seconds
|
||||
assertEquals("5", TimeFormatter.format(100, "s"));
|
||||
|
||||
|
||||
// 1200 ticks = 60 seconds
|
||||
assertEquals("60", TimeFormatter.format(1200, "s"));
|
||||
|
||||
|
||||
// 0 ticks = 0 seconds
|
||||
assertEquals("0", TimeFormatter.format(0, "s"));
|
||||
|
||||
|
||||
// 6000 ticks = 300 seconds (5 minutes)
|
||||
assertEquals("300", TimeFormatter.format(6000, "s"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testFormatMinutes() {
|
||||
// 1200 ticks = 60 seconds = 1 minute
|
||||
assertEquals("1", TimeFormatter.format(1200, "m"));
|
||||
|
||||
|
||||
// 6000 ticks = 300 seconds = 5 minutes
|
||||
assertEquals("5", TimeFormatter.format(6000, "m"));
|
||||
|
||||
|
||||
// 0 ticks = 0 minutes
|
||||
assertEquals("0", TimeFormatter.format(0, "m"));
|
||||
|
||||
|
||||
// 72000 ticks = 3600 seconds = 60 minutes
|
||||
assertEquals("60", TimeFormatter.format(72000, "m"));
|
||||
|
||||
|
||||
// 1100 ticks = 55 seconds = 0 minutes (truncated)
|
||||
assertEquals("0", TimeFormatter.format(1100, "m"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testFormatHours() {
|
||||
// 72000 ticks = 3600 seconds = 1 hour
|
||||
assertEquals("1", TimeFormatter.format(72000, "h"));
|
||||
|
||||
|
||||
// 144000 ticks = 7200 seconds = 2 hours
|
||||
assertEquals("2", TimeFormatter.format(144000, "h"));
|
||||
|
||||
|
||||
// 0 ticks = 0 hours
|
||||
assertEquals("0", TimeFormatter.format(0, "h"));
|
||||
|
||||
|
||||
// 360000 ticks = 18000 seconds = 5 hours
|
||||
assertEquals("5", TimeFormatter.format(360000, "h"));
|
||||
|
||||
|
||||
// 71999 ticks = 3599 seconds = 0 hours (truncated)
|
||||
assertEquals("0", TimeFormatter.format(71999, "h"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testFormatCaseInsensitive() {
|
||||
assertEquals("01:00", TimeFormatter.format(1200, "MM:SS"));
|
||||
|
|
@ -101,7 +102,7 @@ class TimeFormatterTest {
|
|||
assertEquals("1", TimeFormatter.format(1200, "M"));
|
||||
assertEquals("1", TimeFormatter.format(72000, "H"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testFormatNegativeTicks() {
|
||||
// Negative ticks should be treated as 0
|
||||
|
|
@ -109,45 +110,45 @@ class TimeFormatterTest {
|
|||
assertEquals("00:00:00", TimeFormatter.format(-1000, "hh:mm:ss"));
|
||||
assertEquals("0", TimeFormatter.format(-50, "s"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testFormatNullFormat() {
|
||||
IllegalArgumentException exception = assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> TimeFormatter.format(1200, null)
|
||||
IllegalArgumentException.class,
|
||||
() -> TimeFormatter.format(1200, null)
|
||||
);
|
||||
assertTrue(exception.getMessage().contains("cannot be null or empty"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testFormatEmptyFormat() {
|
||||
IllegalArgumentException exception = assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> TimeFormatter.format(1200, "")
|
||||
IllegalArgumentException.class,
|
||||
() -> TimeFormatter.format(1200, "")
|
||||
);
|
||||
assertTrue(exception.getMessage().contains("cannot be null or empty"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testFormatWhitespaceFormat() {
|
||||
IllegalArgumentException exception = assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> TimeFormatter.format(1200, " ")
|
||||
IllegalArgumentException.class,
|
||||
() -> TimeFormatter.format(1200, " ")
|
||||
);
|
||||
assertTrue(exception.getMessage().contains("cannot be null or empty"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testFormatUnknownFormat() {
|
||||
IllegalArgumentException exception = assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> TimeFormatter.format(1200, "invalid")
|
||||
IllegalArgumentException.class,
|
||||
() -> TimeFormatter.format(1200, "invalid")
|
||||
);
|
||||
assertTrue(exception.getMessage().contains("Unknown time format"));
|
||||
assertTrue(exception.getMessage().contains("invalid"));
|
||||
assertTrue(exception.getMessage().contains("Supported formats"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testFormatLargeValues() {
|
||||
// 1 million ticks = 50000 seconds = 833 minutes = 13 hours 53 minutes 20 seconds
|
||||
|
|
@ -157,18 +158,18 @@ class TimeFormatterTest {
|
|||
assertEquals("833", TimeFormatter.format(1000000, "m"));
|
||||
assertEquals("13", TimeFormatter.format(1000000, "h"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testFormatResetTimerExample() {
|
||||
// Typical reset timer: 6000 ticks (5 minutes)
|
||||
assertEquals("05:00", TimeFormatter.format(6000, "mm:ss"));
|
||||
|
||||
|
||||
// After 1 minute: 4800 ticks remaining
|
||||
assertEquals("04:00", TimeFormatter.format(4800, "mm:ss"));
|
||||
|
||||
|
||||
// After 4 minutes 30 seconds: 600 ticks remaining
|
||||
assertEquals("00:30", TimeFormatter.format(600, "mm:ss"));
|
||||
|
||||
|
||||
// Just before reset: 20 ticks remaining (1 second)
|
||||
assertEquals("00:01", TimeFormatter.format(20, "mm:ss"));
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue