refactor: Java 21 support, config/API updates, GUI polish

This commit is contained in:
loki5512344 2026-06-10 23:18:10 +02:00
parent bfdf197de4
commit ceb4c804b7
76 changed files with 1210 additions and 999 deletions

View file

@ -1,8 +1,9 @@
package dev.loki.lomines.command;
import dev.loki.lomines.LoMinesPlugin;
import dev.loki.lomines.command.admin.AdminCommands;
import dev.loki.lomines.core.mine.Mine;
import dev.loki.lomines.core.Mines;
import dev.loki.lomines.core.mine.Mines;
import net.kyori.adventure.text.Component;
import org.bukkit.command.CommandSender;
import org.junit.jupiter.api.BeforeEach;

View file

@ -1,11 +1,14 @@
package dev.loki.lomines.core;
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 dev.loki.lomines.core.mine.Mine;
import dev.loki.lomines.data.config.MineConfig;
import dev.loki.lomines.data.config.block.BlockConfig;
import dev.loki.lomines.data.config.block.BlockKey;
import dev.loki.lomines.data.config.region.RegionConfig;
import dev.loki.lomines.util.location.Cuboid;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -13,7 +16,6 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.*;
@ -33,85 +35,74 @@ class MineTest {
@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
when(world.getName()).thenReturn("world");
}
@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);
void testCreateBlockSetter_WithOraxenPrefix_CreatesBukkitBlockSetter() {
// Oraxen integration is disabled — constructor throws IllegalArgumentException
Map<BlockKey, Double> blocks = new HashMap<>();
blocks.put(new BlockKey.Oraxen("custom_ore"), 50.0);
blocks.put(new BlockKey.Oraxen("rare_ore"), 30.0);
blocks.put(new BlockKey.Oraxen("other_ore"), 20.0);
MineConfig config = createTestConfig(blocks);
// Act
Mine mine = new Mine("test_mine", config, plugin);
// Assert
assertNotNull(mine.getBlockSetter());
assertInstanceOf(OraxenBlockSetter.class, mine.getBlockSetter(), "Expected OraxenBlockSetter for oraxen: prefix");
assertThrows(IllegalArgumentException.class,
() -> new Mine("test_mine", config, plugin),
"Expected IllegalArgumentException when Oraxen integration is disabled");
}
@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);
void testCreateBlockSetter_WithItemsAdderPrefix_CreatesBukkitBlockSetter() {
// ItemsAdder integration is disabled — constructor throws IllegalArgumentException
Map<BlockKey, Double> blocks = new HashMap<>();
blocks.put(new BlockKey.ItemsAdder("custom_block"), 60.0);
blocks.put(new BlockKey.ItemsAdder("special_block"), 40.0);
MineConfig config = createTestConfig(blocks);
// Act
Mine mine = new Mine("test_mine", config, plugin);
// Assert
assertNotNull(mine.getBlockSetter());
assertInstanceOf(ItemsAdderBlockSetter.class, mine.getBlockSetter(), "Expected ItemsAdderBlockSetter for itemsadder: prefix");
assertThrows(IllegalArgumentException.class,
() -> new Mine("test_mine", config, plugin),
"Expected IllegalArgumentException when ItemsAdder integration is disabled");
}
@Test
void testCreateBlockSetter_WithoutPrefix_CreatesBukkitBlockSetter() {
// Arrange
Map<String, Double> blocks = new HashMap<>();
blocks.put("STONE", 50.0);
blocks.put("COAL_ORE", 30.0);
blocks.put("IRON_ORE", 20.0);
Map<BlockKey, Double> blocks = new HashMap<>();
blocks.put(new BlockKey.Vanilla(Material.STONE), 50.0);
blocks.put(new BlockKey.Vanilla(Material.COAL_ORE), 30.0);
blocks.put(new BlockKey.Vanilla(Material.IRON_ORE), 20.0);
MineConfig config = createTestConfig(blocks);
// Act
Mine mine = new Mine("test_mine", config, plugin);
// Assert
assertNotNull(mine.getBlockSetter());
assertInstanceOf(BukkitBlockSetter.class, mine.getBlockSetter(), "Expected BukkitBlockSetter for vanilla blocks without prefix");
assertInstanceOf(dev.loki.lomines.block.BukkitBlockSetter.class, mine.getBlockSetter(),
"Expected BukkitBlockSetter for vanilla blocks");
}
@Test
void testCreateBlockSetter_WithEmptyBlocks_ThrowsException() {
// Arrange
Map<String, Double> blocks = new HashMap<>();
MineConfig config = createTestConfig(blocks);
Map<BlockKey, Double> blocks = new HashMap<>();
// Act & Assert
IllegalArgumentException exception = assertThrows(
assertThrows(
IllegalArgumentException.class,
() -> new Mine("test_mine", config, plugin)
() -> new BlockConfig(blocks, dev.loki.lomines.data.config.block.FillMode.CUBOID, null)
);
assertEquals("Mine must have at least one block type", exception.getMessage());
}
private MineConfig createTestConfig(Map<String, Double> blocks) {
when(world.getName()).thenReturn("world");
private MineConfig createTestConfig(Map<BlockKey, Double> blocks) {
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)
.resetTicks(6000)
RegionConfig region = RegionConfig.single(new Cuboid(loc1, loc2));
BlockConfig blockConfig = new BlockConfig(blocks, dev.loki.lomines.data.config.block.FillMode.CUBOID, null);
return MineConfig.builder("test_mine")
.region(region)
.blocks(blockConfig)
.build();
}
}

View file

@ -1,6 +1,8 @@
package dev.loki.lomines.core;
import dev.loki.lomines.LoMinesPlugin;
import dev.loki.lomines.core.mine.MineTicker;
import dev.loki.lomines.core.mine.Mines;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;

View file

@ -1,6 +1,8 @@
package dev.loki.lomines.core;
import dev.loki.lomines.LoMinesPlugin;
import dev.loki.lomines.core.mine.Mine;
import dev.loki.lomines.core.mine.Mines;
import dev.lolib.core.LoLogger;
import dev.lolib.scheduler.ScheduledTask;
import dev.lolib.scheduler.Scheduler;
@ -9,6 +11,7 @@ import org.bukkit.Material;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.block.data.BlockData;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
@ -25,18 +28,36 @@ import static org.mockito.Mockito.*;
/**
* Unit tests for Mines registry.
* Tests loading and creating mines.
*/
class MinesTest {
@TempDir
Path tempDir;
private Mines mines;
private LoMinesPlugin plugin;
private Scheduler scheduler;
// Keep Bukkit mock open for the whole test — WorldGuardRegionService calls
// Bukkit.getPluginManager() in the Mines constructor.
private MockedStatic<Bukkit> globalBukkit;
private MockedStatic<Scheduler> globalScheduler;
@BeforeEach
void setUp() {
globalBukkit = mockStatic(Bukkit.class);
globalScheduler = mockStatic(Scheduler.class);
PluginManager pluginManager = mock(org.bukkit.plugin.PluginManager.class);
Server server = mock(Server.class);
World world = mock(World.class);
BlockData blockData = mock(BlockData.class);
globalBukkit.when(Bukkit::getPluginManager).thenReturn(pluginManager);
globalBukkit.when(Bukkit::getServer).thenReturn(server);
globalBukkit.when(() -> Bukkit.getWorld(anyString())).thenReturn(world);
globalBukkit.when(() -> Bukkit.createBlockData(any(Material.class))).thenReturn(blockData);
when(world.getName()).thenReturn("world");
plugin = mock(LoMinesPlugin.class);
Logger logger = mock(Logger.class);
LoLogger loLogger = mock(LoLogger.class);
@ -46,59 +67,37 @@ class MinesTest {
when(plugin.getLogger()).thenReturn(logger);
when(plugin.loLogger()).thenReturn(loLogger);
globalScheduler.when(() -> Scheduler.get(plugin)).thenReturn(scheduler);
ScheduledTask task = mock(ScheduledTask.class);
when(scheduler.runTimer(any(Runnable.class), anyLong(), anyLong())).thenReturn(task);
mines = new Mines(plugin);
}
/**
* Helper method to set up Bukkit and Scheduler mocking for tests that create mines.
*/
private void setupBukkitAndScheduler(MockedStatic<Bukkit> bukkit, MockedStatic<Scheduler> schedulerStatic) {
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);
@AfterEach
void tearDown() {
if (globalScheduler != null) globalScheduler.close();
if (globalBukkit != null) globalBukkit.close();
}
@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
Files.createDirectories(tempDir.resolve("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
@ -118,36 +117,22 @@ class MinesTest {
broadcast-reset: ""
random-rewards: []
""";
Files.writeString(minesFolder.resolve("testmine.yml"), yamlContent);
Path configFile = minesFolder.resolve("testmine.yml");
Files.writeString(configFile, yamlContent);
mines.loadAll();
// 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());
}
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
@ -167,35 +152,23 @@ class MinesTest {
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)) {
mines.loadAll();
setupBukkitAndScheduler(bukkit, schedulerStatic);
// Load all mines
mines.loadAll();
// Verify all mines were loaded
assertEquals(3, mines.getAll().size());
assertTrue(mines.find("mine1").isPresent());
assertTrue(mines.find("mine2").isPresent());
assertTrue(mines.find("mine3").isPresent());
}
assertEquals(3, mines.getAll().size());
assertTrue(mines.find("mine1").isPresent());
assertTrue(mines.find("mine2").isPresent());
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
@ -205,196 +178,87 @@ class MinesTest {
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");
Files.writeString(minesFolder.resolve("readme.txt"), "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)) {
mines.loadAll();
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());
}
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);
Files.writeString(minesFolder.resolve("invalidmine.yml"), "selection.1: world;0;64;0;0.0;0.0\n");
// Create an invalid mine config file (missing required fields)
String invalidYaml = """
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());
}
assertDoesNotThrow(() -> mines.loadAll());
assertEquals(0, mines.getAll().size());
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)) {
mines.create("newmine");
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");
}
assertEquals(1, mines.getAll().size());
assertTrue(mines.find("newmine").isPresent());
Mine mine = mines.get("newmine");
assertNotNull(mine);
assertEquals("newmine", mine.getName());
assertTrue(Files.exists(tempDir.resolve("mines/newmine.yml")));
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));
}
assertFalse(Files.exists(tempDir.resolve("mines")));
mines.create("testmine");
assertTrue(Files.isDirectory(tempDir.resolve("mines")));
}
@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"));
}
mines.create("duplicate");
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
() -> mines.create("duplicate"));
assertTrue(ex.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"));
}
mines.create("TestMine");
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
() -> mines.create("testmine"));
assertTrue(ex.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)) {
mines.create("testmine");
setupBukkitAndScheduler(bukkit, schedulerStatic);
Mine mine = mines.get("testmine");
assertNotNull(mine);
assertEquals("testmine", mine.getName());
// 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);
}
Mine mine2 = mines.get("TestMine");
assertNotNull(mine2);
assertSame(mine, mine2);
}
@Test
void testGetNonExistentMineThrowsException() {
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
mines.get("nonexistent");
});
assertTrue(exception.getMessage().contains("Mine not found"));
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
() -> mines.get("nonexistent"));
assertTrue(ex.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());
}
mines.create("testmine");
assertTrue(mines.find("testmine").isPresent());
assertFalse(mines.find("nonexistent").isPresent());
}
}

View file

@ -1,6 +1,9 @@
package dev.loki.lomines.data;
import dev.loki.lomines.LoMinesPlugin;
import dev.loki.lomines.data.stats.Leaderboard;
import dev.loki.lomines.data.stats.LeaderboardEntry;
import dev.loki.lomines.data.stats.StatsManager;
import dev.lolib.core.LoLogger;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -48,7 +51,7 @@ class LeaderboardCacheIntegrationTest {
// Build cache
List<LeaderboardEntry> top1 = leaderboard.getTopTotal(10);
assertEquals(1, top1.size(), "Should have 1 player initially");
assertEquals(player1, top1.get(0).getPlayerId());
assertEquals(player1, top1.get(0).playerId());
// Increment blocks for player2 - this should invalidate cache
statsManager.incrementBlocks(player2, "mine1");
@ -58,8 +61,8 @@ class LeaderboardCacheIntegrationTest {
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");
assertEquals(player1, top2.get(0).playerId(), "Player1 should still be first");
assertEquals(player2, top2.get(1).playerId(), "Player2 should be second");
}
@Test
@ -73,7 +76,7 @@ class LeaderboardCacheIntegrationTest {
// Build cache
List<LeaderboardEntry> top1 = leaderboard.getTopTotal(10);
assertEquals(player2, top1.get(0).getPlayerId(), "Player2 should be first initially");
assertEquals(player2, top1.get(0).playerId(), "Player2 should be first initially");
// Increment player1 many times to overtake player2
for (int i = 0; i < 60; i++) {
@ -82,10 +85,10 @@ class LeaderboardCacheIntegrationTest {
// 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");
assertEquals(110, top2.get(0).getCount(), "Player1 should have 110 blocks");
assertEquals(player2, top2.get(1).getPlayerId(), "Player2 should be second");
assertEquals(100, top2.get(1).getCount(), "Player2 should still have 100 blocks");
assertEquals(player1, top2.get(0).playerId(), "Player1 should be first after increments");
assertEquals(110, top2.get(0).count(), "Player1 should have 110 blocks");
assertEquals(player2, top2.get(1).playerId(), "Player2 should be second");
assertEquals(100, top2.get(1).count(), "Player2 should still have 100 blocks");
}
@Test
@ -104,7 +107,7 @@ class LeaderboardCacheIntegrationTest {
// 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");
assertEquals(5, top2.get(0).count(), "Should have 5 blocks after 5 increments");
}
@Test
@ -150,7 +153,7 @@ class LeaderboardCacheIntegrationTest {
// Get with limit 2 - should use same cache
List<LeaderboardEntry> top2 = leaderboard.getTopTotal(2);
assertEquals(2, top2.size());
assertEquals(player3, top2.get(0).getPlayerId(), "Should have highest player");
assertEquals(player2, top2.get(1).getPlayerId(), "Should have second highest player");
assertEquals(player3, top2.get(0).playerId(), "Should have highest player");
assertEquals(player2, top2.get(1).playerId(), "Should have second highest player");
}
}

View file

@ -1,6 +1,10 @@
package dev.loki.lomines.data;
import dev.loki.lomines.LoMinesPlugin;
import dev.loki.lomines.data.stats.Leaderboard;
import dev.loki.lomines.data.stats.LeaderboardEntry;
import dev.loki.lomines.data.stats.PlayerStats;
import dev.loki.lomines.data.stats.StatsManager;
import dev.lolib.core.LoLogger;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -51,8 +55,8 @@ class LeaderboardTest {
List<LeaderboardEntry> top = leaderboard.getTopTotal(10);
assertEquals(1, top.size());
assertEquals(playerId, top.get(0).getPlayerId());
assertEquals(100, top.get(0).getCount());
assertEquals(playerId, top.get(0).playerId());
assertEquals(100, top.get(0).count());
}
@Test
@ -67,9 +71,9 @@ class LeaderboardTest {
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
assertEquals(player2, top.get(0).playerId()); // 200 blocks
assertEquals(player3, top.get(1).playerId()); // 100 blocks
assertEquals(player1, top.get(2).playerId()); // 50 blocks
}
@Test
@ -93,7 +97,7 @@ class LeaderboardTest {
List<LeaderboardEntry> top = leaderboard.getTopTotal(10);
assertEquals(1, top.size(), "Should filter out players with 0 blocks");
assertEquals(player1, top.get(0).getPlayerId());
assertEquals(player1, top.get(0).playerId());
}
@Test
@ -108,7 +112,7 @@ class LeaderboardTest {
List<LeaderboardEntry> top2 = leaderboard.getTopTotal(10);
assertEquals(top1.size(), top2.size());
assertEquals(top1.get(0).getPlayerId(), top2.get(0).getPlayerId());
assertEquals(top1.get(0).playerId(), top2.get(0).playerId());
}
@Test
@ -129,7 +133,7 @@ class LeaderboardTest {
// 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");
assertEquals(player2, top.get(0).playerId(), "New player should be first");
}
@Test
@ -144,9 +148,9 @@ class LeaderboardTest {
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
assertEquals(player2, top.get(0).playerId()); // 200 blocks
assertEquals(player3, top.get(1).playerId()); // 100 blocks
assertEquals(player1, top.get(2).playerId()); // 50 blocks
}
@Test
@ -159,7 +163,7 @@ class LeaderboardTest {
List<LeaderboardEntry> top = leaderboard.getTopByMine("mine1", 10);
assertEquals(1, top.size(), "Should filter out players with 0 blocks");
assertEquals(player1, top.get(0).getPlayerId());
assertEquals(player1, top.get(0).playerId());
}
@Test
@ -172,7 +176,7 @@ class LeaderboardTest {
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());
assertEquals(player1, top.get(0).playerId());
}
@Test

View file

@ -1,6 +1,8 @@
package dev.loki.lomines.data;
import dev.loki.lomines.LoMinesPlugin;
import dev.loki.lomines.data.stats.PlayerStats;
import dev.loki.lomines.data.stats.StatsManager;
import dev.lolib.core.LoLogger;
import dev.lolib.scheduler.ScheduledTask;
import dev.lolib.scheduler.Scheduler;

View file

@ -33,7 +33,8 @@ class UIConfigTest {
true,
"<red>{mine}</red>",
100.0,
"HH:mm:ss"
"HH:mm:ss",
null
);
assertTrue(config.actionBarEnabled());
@ -44,7 +45,7 @@ class UIConfigTest {
@Test
void testNullFormatDefaults() {
UIConfig config = new UIConfig(true, null, 50.0, null);
UIConfig config = new UIConfig(true, null, 50.0, null, null);
assertEquals(UIConfig.DEFAULT_ACTIONBAR_FORMAT, config.actionBarFormat());
assertEquals(UIConfig.DEFAULT_TIMER_FORMAT, config.timerFormat());
@ -52,7 +53,7 @@ class UIConfigTest {
@Test
void testBlankFormatDefaults() {
UIConfig config = new UIConfig(true, " ", 50.0, " ");
UIConfig config = new UIConfig(true, " ", 50.0, " ", null);
assertEquals(UIConfig.DEFAULT_ACTIONBAR_FORMAT, config.actionBarFormat());
assertEquals(UIConfig.DEFAULT_TIMER_FORMAT, config.timerFormat());
@ -60,14 +61,14 @@ class UIConfigTest {
@Test
void testNegativeRangeClamped() {
UIConfig config = new UIConfig(true, "test", -10.0, "mm:ss");
UIConfig config = new UIConfig(true, "test", -10.0, "mm:ss", null);
assertEquals(1.0, config.actionBarRange());
}
@Test
void testRangeSquared() {
UIConfig config = new UIConfig(true, "test", 50.0, "mm:ss");
UIConfig config = new UIConfig(true, "test", 50.0, "mm:ss", null);
assertEquals(2500.0, config.actionBarRangeSquared(), 0.001);
}
@ -85,7 +86,7 @@ class UIConfigTest {
@Test
void testFormatTimerMmSs() {
UIConfig config = new UIConfig(true, "", 0, "mm:ss");
UIConfig config = new UIConfig(true, "", 0, "mm:ss", null);
assertEquals("00:30", config.formatTimer(30));
assertEquals("05:00", config.formatTimer(300));
@ -94,7 +95,7 @@ class UIConfigTest {
@Test
void testFormatTimerHhMmSs() {
UIConfig config = new UIConfig(true, "", 0, "HH:mm:ss");
UIConfig config = new UIConfig(true, "", 0, "HH:mm:ss", null);
assertEquals("0:00:30", config.formatTimer(30));
assertEquals("0:05:00", config.formatTimer(300));

View file

@ -1,5 +1,7 @@
package dev.loki.lomines.util;
import dev.loki.lomines.util.format.ChunkUtils;
import dev.loki.lomines.util.location.Cuboid;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.World;

View file

@ -1,6 +1,7 @@
package dev.loki.lomines.util;
import dev.loki.lomines.data.config.parser.ConfigParseException;
import dev.loki.lomines.util.location.LocationParser;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;

View file

@ -1,7 +1,9 @@
package dev.loki.lomines.util;
import dev.loki.lomines.util.format.TimeFormatter;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

View file

@ -1,5 +1,6 @@
package dev.loki.lomines.util.selection;
import dev.loki.lomines.util.location.Cuboid;
import org.bukkit.Location;
import org.bukkit.World;
import org.junit.jupiter.api.BeforeEach;