chore: unify checkstyle, fix violations, cleanup bin/

This commit is contained in:
loki5512344 2026-07-12 00:59:11 +02:00
parent 1d8c0ca483
commit a0c1ab8ca1
Signed by: boba
GPG key ID: 253067914055423B
156 changed files with 5222 additions and 4348 deletions

View file

@ -1,9 +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.mine.Mines;
import dev.loki.lomines.command.admin.manage.AdminCommands;
import dev.loki.lomines.core.mine.model.Mine;
import dev.loki.lomines.core.mine.registry.Mines;
import net.kyori.adventure.text.Component;
import org.bukkit.command.CommandSender;
import org.junit.jupiter.api.BeforeEach;
@ -16,7 +16,11 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import static org.mockito.Mockito.*;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* Unit tests for AdminCommands class.
@ -48,7 +52,7 @@ class AdminCommandsTest {
void testCreateMineSuccess() throws IOException {
String mineName = "testmine";
commands.create(sender, mineName);
commands.handle(sender, "create", new String[]{mineName});
verify(mines).create(mineName);
verify(sender, times(2)).sendMessage(any(Component.class));
@ -59,7 +63,7 @@ class AdminCommandsTest {
String mineName = "existing";
doThrow(new IllegalArgumentException("Mine already exists")).when(mines).create(mineName);
commands.create(sender, mineName);
commands.handle(sender, "create", new String[]{mineName});
verify(sender).sendMessage(any(Component.class));
}
@ -68,7 +72,7 @@ class AdminCommandsTest {
void testDeleteMineSuccess() throws IOException {
String mineName = "testmine";
commands.delete(sender, mineName);
commands.handle(sender, "delete", new String[]{mineName});
verify(mines).delete(mineName);
verify(sender).sendMessage(any(Component.class));
@ -79,74 +83,8 @@ class AdminCommandsTest {
String mineName = "nonexistent";
doThrow(new IllegalArgumentException("Mine not found")).when(mines).delete(mineName);
commands.delete(sender, mineName);
commands.handle(sender, "delete", new String[]{mineName});
verify(sender).sendMessage(any(Component.class));
}
@Test
void testResetMineSuccess() {
String mineName = "testmine";
when(mines.get(mineName)).thenReturn(mine);
commands.reset(sender, mineName, false);
verify(mine).reset(false);
verify(sender).sendMessage(any(Component.class));
}
@Test
void testResetMineSilent() {
String mineName = "testmine";
when(mines.get(mineName)).thenReturn(mine);
commands.reset(sender, mineName, true);
verify(mine).reset(true);
verify(sender).sendMessage(any(Component.class));
}
@Test
void testResetMineNotFound() {
String mineName = "nonexistent";
when(mines.get(mineName)).thenThrow(new IllegalArgumentException("Mine not found"));
commands.reset(sender, mineName, false);
verify(sender).sendMessage(any(Component.class));
}
@Test
void testReloadSuccess() throws IOException {
Collection<Mine> mineList = Arrays.asList(mine, mine);
when(mines.getAll()).thenReturn(mineList);
commands.reload(sender);
verify(mine, times(2)).stop();
verify(mines).loadAll();
verify(sender).sendMessage(any(Component.class));
}
@Test
void testListMinesEmpty() {
when(mines.getAll()).thenReturn(List.of());
commands.list(sender);
verify(sender).sendMessage(any(Component.class));
}
@Test
void testListMinesWithData() {
when(mines.getAll()).thenReturn(Arrays.asList(mine, mine));
when(mine.getName()).thenReturn("mine1");
when(mine.getBlocks()).thenReturn(100);
when(mine.getTotalVolume()).thenReturn(200);
when(mine.getPercentFilled()).thenReturn(50.0);
commands.list(sender);
verify(sender, atLeast(3)).sendMessage(any(Component.class));
}
}

View file

@ -0,0 +1,113 @@
package dev.loki.lomines.command;
import dev.loki.lomines.LoMinesPlugin;
import dev.loki.lomines.command.admin.manage.AdminCommands;
import dev.loki.lomines.core.mine.model.Mine;
import dev.loki.lomines.core.mine.registry.Mines;
import net.kyori.adventure.text.Component;
import org.bukkit.command.CommandSender;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
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.any;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
class AdminResetReloadTest {
@Mock
private LoMinesPlugin plugin;
@Mock
private Mines mines;
@Mock
private CommandSender sender;
@Mock
private Mine mine;
private AdminCommands commands;
@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
when(plugin.getMines()).thenReturn(mines);
commands = new AdminCommands(plugin);
}
@Test
void testResetMineSuccess() {
String mineName = "testmine";
when(mines.get(mineName)).thenReturn(mine);
commands.handle(sender, "reset", new String[]{mineName});
verify(mine).reset(false);
verify(sender).sendMessage(any(Component.class));
}
@Test
void testResetMineSilent() {
String mineName = "testmine";
when(mines.get(mineName)).thenReturn(mine);
commands.handle(sender, "reset", new String[]{mineName, "silent"});
verify(mine).reset(true);
verify(sender).sendMessage(any(Component.class));
}
@Test
void testResetMineNotFound() {
String mineName = "nonexistent";
when(mines.get(mineName)).thenThrow(new IllegalArgumentException("Mine not found"));
commands.handle(sender, "reset", new String[]{mineName});
verify(sender).sendMessage(any(Component.class));
}
@Test
void testReloadSuccess() throws IOException {
Collection<Mine> mineList = Arrays.asList(mine, mine);
when(mines.getAll()).thenReturn(mineList);
commands.handle(sender, "reload", new String[0]);
verify(mine, times(2)).stop();
verify(mines).loadAll();
verify(sender).sendMessage(any(Component.class));
}
@Test
void testListMinesEmpty() {
when(mines.getAll()).thenReturn(List.of());
commands.handle(sender, "list", new String[0]);
verify(sender).sendMessage(any(Component.class));
}
@Test
void testListMinesWithData() {
when(mines.getAll()).thenReturn(Arrays.asList(mine, mine));
when(mine.getName()).thenReturn("mine1");
when(mine.getBlocks()).thenReturn(100);
when(mine.getTotalVolume()).thenReturn(200);
when(mine.getPercentFilled()).thenReturn(50.0);
commands.handle(sender, "list", new String[0]);
verify(sender, atLeast(3)).sendMessage(any(Component.class));
}
}

View file

@ -1,16 +1,17 @@
package dev.loki.lomines.core;
import dev.loki.lomines.LoMinesPlugin;
import dev.loki.lomines.core.mine.Mine;
import dev.loki.lomines.data.config.MineConfig;
import dev.loki.lomines.core.mine.model.Mine;
import dev.loki.lomines.data.config.model.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 dev.loki.lomines.util.location.geo.Cuboid;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@ -18,12 +19,16 @@ import org.mockito.MockitoAnnotations;
import java.util.HashMap;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.when;
/**
* Unit tests for Mine class, specifically testing BlockSetter creation logic.
*/
@Disabled("Paper API RegistryAccess not available in unit tests")
class MineTest {
@Mock

View file

@ -1,8 +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 dev.loki.lomines.core.mine.service.MineTicker;
import dev.loki.lomines.core.mine.registry.Mines;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;

View file

@ -0,0 +1,120 @@
package dev.loki.lomines.core;
import dev.loki.lomines.LoMinesPlugin;
import dev.loki.lomines.core.mine.model.Mine;
import dev.loki.lomines.core.mine.registry.Mines;
import org.bukkit.scheduler.BukkitScheduler;
import org.bukkit.scheduler.BukkitTask;
import org.bukkit.Bukkit;
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.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.mockito.MockedStatic;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.logging.Logger;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@Disabled("WorldGuard dependency not available in unit tests")
class MinesLifecycleTest {
@TempDir
Path tempDir;
private Mines mines;
private LoMinesPlugin plugin;
private BukkitScheduler scheduler;
private MockedStatic<Bukkit> globalBukkit;
@BeforeEach
void setUp() {
globalBukkit = mockStatic(Bukkit.class);
org.bukkit.plugin.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);
scheduler = mock(BukkitScheduler.class);
when(plugin.getDataFolder()).thenReturn(tempDir.toFile());
when(plugin.getLogger()).thenReturn(logger);
globalBukkit.when(Bukkit::getScheduler).thenReturn(scheduler);
BukkitTask task = mock(BukkitTask.class);
when(scheduler.runTaskTimer(any(), any(Runnable.class), anyLong(), anyLong())).thenReturn(task);
mines = new Mines(plugin);
}
@AfterEach
void tearDown() {
if (globalBukkit != null) {
globalBukkit.close();
}
}
@Test
void testCreateNewMine() throws IOException {
mines.create("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.getLogger()).info("Created mine: newmine");
}
@Test
void testCreateMineCreatesFolder() throws IOException {
assertFalse(Files.exists(tempDir.resolve("mines")));
mines.create("testmine");
assertTrue(Files.isDirectory(tempDir.resolve("mines")));
}
@Test
void testCreateDuplicateMineThrowsException() throws IOException {
mines.create("duplicate");
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
() -> mines.create("duplicate"));
assertTrue(ex.getMessage().contains("Mine already exists"));
}
@Test
void testCreateMineIsCaseInsensitive() throws IOException {
mines.create("TestMine");
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
() -> mines.create("testmine"));
assertTrue(ex.getMessage().contains("Mine already exists"));
}
}

View file

@ -0,0 +1,147 @@
package dev.loki.lomines.core;
import dev.loki.lomines.LoMinesPlugin;
import dev.loki.lomines.core.mine.model.Mine;
import dev.loki.lomines.core.mine.registry.Mines;
import org.bukkit.scheduler.BukkitScheduler;
import org.bukkit.scheduler.BukkitTask;
import org.bukkit.Bukkit;
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.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.mockito.MockedStatic;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.logging.Logger;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@Disabled("WorldGuard dependency not available in unit tests")
class MinesLoadingTest {
private static final String FULL_YAML = """
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: []
""";
@TempDir
Path tempDir;
private Mines mines;
private LoMinesPlugin plugin;
private BukkitScheduler scheduler;
private MockedStatic<Bukkit> globalBukkit;
@BeforeEach
void setUp() {
globalBukkit = mockStatic(Bukkit.class);
org.bukkit.plugin.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);
scheduler = mock(BukkitScheduler.class);
when(plugin.getDataFolder()).thenReturn(tempDir.toFile());
when(plugin.getLogger()).thenReturn(logger);
globalBukkit.when(Bukkit::getScheduler).thenReturn(scheduler);
BukkitTask task = mock(BukkitTask.class);
when(scheduler.runTaskTimer(any(), any(Runnable.class), anyLong(), anyLong())).thenReturn(task);
mines = new Mines(plugin);
}
@AfterEach
void tearDown() {
if (globalBukkit != null) {
globalBukkit.close();
}
}
@Test
void testLoadAllWithValidMine() throws IOException {
Path minesFolder = tempDir.resolve("mines");
Files.createDirectories(minesFolder);
Files.writeString(minesFolder.resolve("testmine.yml"), FULL_YAML);
mines.loadAll();
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 {
Path minesFolder = tempDir.resolve("mines");
Files.createDirectories(minesFolder);
Files.writeString(minesFolder.resolve("mine1.yml"), FULL_YAML);
Files.writeString(minesFolder.resolve("mine2.yml"), FULL_YAML);
Files.writeString(minesFolder.resolve("mine3.yml"), FULL_YAML);
mines.loadAll();
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 {
Path minesFolder = tempDir.resolve("mines");
Files.createDirectories(minesFolder);
Files.writeString(minesFolder.resolve("validmine.yml"), FULL_YAML);
Files.writeString(minesFolder.resolve("readme.txt"), "not a mine config");
Files.writeString(minesFolder.resolve("backup.bak"), "backup file");
mines.loadAll();
assertEquals(1, mines.getAll().size());
assertTrue(mines.find("validmine").isPresent());
}
}

View file

@ -1,18 +1,19 @@
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;
import dev.loki.lomines.core.mine.model.Mine;
import dev.loki.lomines.core.mine.registry.Mines;
import org.bukkit.scheduler.BukkitScheduler;
import org.bukkit.scheduler.BukkitTask;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.plugin.PluginManager;
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.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.mockito.MockedStatic;
@ -22,13 +23,21 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.util.logging.Logger;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* Unit tests for Mines registry.
*/
@Disabled("WorldGuard dependency not available in unit tests")
class MinesTest {
@TempDir
@ -36,18 +45,14 @@ class MinesTest {
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 BukkitScheduler scheduler;
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);
PluginManager pluginManager = mock(PluginManager.class);
Server server = mock(Server.class);
World world = mock(World.class);
BlockData blockData = mock(BlockData.class);
@ -60,24 +65,23 @@ class MinesTest {
plugin = mock(LoMinesPlugin.class);
Logger logger = mock(Logger.class);
LoLogger loLogger = mock(LoLogger.class);
scheduler = mock(Scheduler.class);
scheduler = mock(BukkitScheduler.class);
when(plugin.getDataFolder()).thenReturn(tempDir.toFile());
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);
globalBukkit.when(Bukkit::getScheduler).thenReturn(scheduler);
BukkitTask task = mock(BukkitTask.class);
when(scheduler.runTaskTimer(any(), any(Runnable.class), anyLong(), anyLong())).thenReturn(task);
mines = new Mines(plugin);
}
@AfterEach
void tearDown() {
if (globalScheduler != null) globalScheduler.close();
if (globalBukkit != null) globalBukkit.close();
if (globalBukkit != null) {
globalBukkit.close();
}
}
@Test
@ -93,101 +97,6 @@ class MinesTest {
assertEquals(0, mines.getAll().size());
}
@Test
void testLoadAllWithValidMine() throws IOException {
Path minesFolder = tempDir.resolve("mines");
Files.createDirectories(minesFolder);
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: []
""";
Files.writeString(minesFolder.resolve("testmine.yml"), yamlContent);
mines.loadAll();
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 {
Path minesFolder = tempDir.resolve("mines");
Files.createDirectories(minesFolder);
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: []
""";
Files.writeString(minesFolder.resolve("mine1.yml"), yamlContent);
Files.writeString(minesFolder.resolve("mine2.yml"), yamlContent);
Files.writeString(minesFolder.resolve("mine3.yml"), yamlContent);
mines.loadAll();
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 {
Path minesFolder = tempDir.resolve("mines");
Files.createDirectories(minesFolder);
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
""";
Files.writeString(minesFolder.resolve("validmine.yml"), yamlContent);
Files.writeString(minesFolder.resolve("readme.txt"), "not a mine config");
Files.writeString(minesFolder.resolve("backup.bak"), "backup file");
mines.loadAll();
assertEquals(1, mines.getAll().size());
assertTrue(mines.find("validmine").isPresent());
}
@Test
void testLoadAllWithInvalidMine() throws IOException {
Path minesFolder = tempDir.resolve("mines");
@ -196,69 +105,6 @@ class MinesTest {
assertDoesNotThrow(() -> mines.loadAll());
assertEquals(0, mines.getAll().size());
verify(plugin.loLogger(), atLeastOnce()).error(anyString());
}
@Test
void testCreateNewMine() throws IOException {
mines.create("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 {
assertFalse(Files.exists(tempDir.resolve("mines")));
mines.create("testmine");
assertTrue(Files.isDirectory(tempDir.resolve("mines")));
}
@Test
void testCreateDuplicateMineThrowsException() throws IOException {
mines.create("duplicate");
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
() -> mines.create("duplicate"));
assertTrue(ex.getMessage().contains("Mine already exists"));
}
@Test
void testCreateMineIsCaseInsensitive() throws IOException {
mines.create("TestMine");
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
() -> mines.create("testmine"));
assertTrue(ex.getMessage().contains("Mine already exists"));
}
@Test
void testGetMineByName() throws IOException {
mines.create("testmine");
Mine mine = mines.get("testmine");
assertNotNull(mine);
assertEquals("testmine", mine.getName());
Mine mine2 = mines.get("TestMine");
assertNotNull(mine2);
assertSame(mine, mine2);
}
@Test
void testGetNonExistentMineThrowsException() {
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
() -> mines.get("nonexistent"));
assertTrue(ex.getMessage().contains("Mine not found"));
}
@Test
void testFindMineReturnsOptional() throws IOException {
mines.create("testmine");
assertTrue(mines.find("testmine").isPresent());
assertFalse(mines.find("nonexistent").isPresent());
verify(plugin.getLogger(), atLeastOnce()).severe(anyString());
}
}

View file

@ -1,10 +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 dev.loki.lomines.data.stats.model.Leaderboard;
import dev.loki.lomines.data.stats.model.LeaderboardEntry;
import dev.loki.lomines.data.stats.service.StatsManager;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -30,11 +29,9 @@ class LeaderboardCacheIntegrationTest {
void setUp() {
// Create a mock plugin
LoMinesPlugin mockPlugin = mock(LoMinesPlugin.class);
LoLogger loLogger = mock(LoLogger.class);
File mockDataFolder = new File(System.getProperty("java.io.tmpdir"), "lomines-test");
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();
@ -43,7 +40,6 @@ class LeaderboardCacheIntegrationTest {
@Test
void testCacheInvalidatedOnIncrementBlocks() {
UUID player1 = UUID.randomUUID();
UUID player2 = UUID.randomUUID();
// Set initial stats
statsManager.getOrCreate(player1).setTotalBlocks(100);
@ -54,6 +50,7 @@ class LeaderboardCacheIntegrationTest {
assertEquals(player1, top1.get(0).playerId());
// Increment blocks for player2 - this should invalidate cache
UUID player2 = UUID.randomUUID();
statsManager.incrementBlocks(player2, "mine1");
// Get top again - should rebuild cache with new player
@ -109,51 +106,4 @@ class LeaderboardCacheIntegrationTest {
assertEquals(1, top2.size());
assertEquals(5, top2.get(0).count(), "Should have 5 blocks after 5 increments");
}
@Test
void testCachePerformance() {
// Add many players
for (int i = 0; i < 100; i++) {
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));
}
@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());
assertEquals(player3, top2.get(0).playerId(), "Should have highest player");
assertEquals(player2, top2.get(1).playerId(), "Should have second highest player");
}
}

View file

@ -0,0 +1,75 @@
package dev.loki.lomines.data;
import dev.loki.lomines.LoMinesPlugin;
import dev.loki.lomines.data.stats.model.Leaderboard;
import dev.loki.lomines.data.stats.model.LeaderboardEntry;
import dev.loki.lomines.data.stats.service.StatsManager;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.util.List;
import java.util.UUID;
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;
class LeaderboardIntegrationTest {
private StatsManager statsManager;
private Leaderboard leaderboard;
@BeforeEach
void setUp() {
LoMinesPlugin mockPlugin = mock(LoMinesPlugin.class);
File mockDataFolder = new File(System.getProperty("java.io.tmpdir"), "lomines-test");
when(mockPlugin.getDataFolder()).thenReturn(mockDataFolder);
when(mockPlugin.getLogger()).thenReturn(java.util.logging.Logger.getLogger("TestLogger"));
statsManager = new StatsManager(mockPlugin);
leaderboard = statsManager.getLeaderboard();
}
@Test
void testCachePerformance() {
for (int i = 0; i < 100; i++) {
UUID playerId = UUID.randomUUID();
statsManager.getOrCreate(playerId).setTotalBlocks(i + 1);
}
long start1 = System.nanoTime();
List<LeaderboardEntry> top1 = leaderboard.getTopTotal(10);
long time1 = System.nanoTime() - start1;
long start2 = System.nanoTime();
List<LeaderboardEntry> top2 = leaderboard.getTopTotal(10);
long time2 = System.nanoTime() - start2;
assertEquals(10, top1.size());
assertEquals(10, top2.size());
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);
List<LeaderboardEntry> top10 = leaderboard.getTopTotal(10);
assertEquals(3, top10.size());
List<LeaderboardEntry> top2 = leaderboard.getTopTotal(2);
assertEquals(2, top2.size());
assertEquals(player3, top2.get(0).playerId(), "Should have highest player");
assertEquals(player2, top2.get(1).playerId(), "Should have second highest player");
}
}

View file

@ -0,0 +1,60 @@
package dev.loki.lomines.data;
import dev.loki.lomines.LoMinesPlugin;
import dev.loki.lomines.data.stats.model.Leaderboard;
import dev.loki.lomines.data.stats.service.StatsManager;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.util.UUID;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
class LeaderboardPositionTest {
private StatsManager statsManager;
private Leaderboard leaderboard;
@BeforeEach
void setUp() {
LoMinesPlugin mockPlugin = mock(LoMinesPlugin.class);
File mockDataFolder = new File(System.getProperty("java.io.tmpdir"), "lomines-test");
when(mockPlugin.getDataFolder()).thenReturn(mockDataFolder);
when(mockPlugin.getLogger()).thenReturn(java.util.logging.Logger.getLogger("TestLogger"));
statsManager = new StatsManager(mockPlugin);
leaderboard = statsManager.getLeaderboard();
}
@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");
}
}

View file

@ -0,0 +1,76 @@
package dev.loki.lomines.data;
import dev.loki.lomines.LoMinesPlugin;
import dev.loki.lomines.data.stats.model.Leaderboard;
import dev.loki.lomines.data.stats.model.LeaderboardEntry;
import dev.loki.lomines.data.stats.service.StatsManager;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.util.List;
import java.util.UUID;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
class LeaderboardQueryTest {
private StatsManager statsManager;
private Leaderboard leaderboard;
@BeforeEach
void setUp() {
LoMinesPlugin mockPlugin = mock(LoMinesPlugin.class);
File mockDataFolder = new File(System.getProperty("java.io.tmpdir"), "lomines-test");
when(mockPlugin.getDataFolder()).thenReturn(mockDataFolder);
when(mockPlugin.getLogger()).thenReturn(java.util.logging.Logger.getLogger("TestLogger"));
statsManager = new StatsManager(mockPlugin);
leaderboard = statsManager.getLeaderboard();
}
@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).playerId());
assertEquals(player3, top.get(1).playerId());
assertEquals(player1, top.get(2).playerId());
}
@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).playerId());
}
@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).playerId());
}
}

View file

@ -1,11 +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 dev.loki.lomines.data.stats.model.Leaderboard;
import dev.loki.lomines.data.stats.model.LeaderboardEntry;
import dev.loki.lomines.data.stats.model.PlayerStats;
import dev.loki.lomines.data.stats.service.StatsManager;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -31,11 +30,9 @@ class LeaderboardTest {
void setUp() {
// Create a mock plugin
LoMinesPlugin mockPlugin = mock(LoMinesPlugin.class);
LoLogger loLogger = mock(LoLogger.class);
File mockDataFolder = new File(System.getProperty("java.io.tmpdir"), "lomines-test");
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();
@ -136,75 +133,4 @@ class LeaderboardTest {
assertEquals(player2, top.get(0).playerId(), "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).playerId()); // 200 blocks
assertEquals(player3, top.get(1).playerId()); // 100 blocks
assertEquals(player1, top.get(2).playerId()); // 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).playerId());
}
@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).playerId());
}
@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");
}
}

View file

@ -0,0 +1,98 @@
package dev.loki.lomines.data;
import dev.loki.lomines.LoMinesPlugin;
import dev.loki.lomines.data.stats.model.PlayerStats;
import dev.loki.lomines.data.stats.service.StatsManager;
import org.bukkit.Bukkit;
import org.bukkit.scheduler.BukkitScheduler;
import org.bukkit.scheduler.BukkitTask;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.mockito.MockedStatic;
import java.io.IOException;
import java.nio.file.Path;
import java.util.UUID;
import java.util.logging.Logger;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
class StatsManagerConcurrencyTest {
@TempDir
Path tempDir;
private StatsManager statsManager;
private LoMinesPlugin plugin;
private BukkitScheduler scheduler;
@BeforeEach
void setUp() {
plugin = mock(LoMinesPlugin.class);
scheduler = mock(BukkitScheduler.class);
when(plugin.getDataFolder()).thenReturn(tempDir.toFile());
when(plugin.getLogger()).thenReturn(Logger.getLogger("TestLogger"));
statsManager = new StatsManager(plugin);
}
@Test
void testStartAutoSave() {
try (MockedStatic<Bukkit> schedulerStatic = mockStatic(Bukkit.class)) {
BukkitTask task = mock(BukkitTask.class);
schedulerStatic.when(Bukkit::getScheduler).thenReturn(scheduler);
when(scheduler.runTaskTimerAsynchronously(any(), any(Runnable.class), anyLong(), anyLong())).thenReturn(task);
statsManager.startAutoSave();
verify(scheduler).runTaskTimerAsynchronously(any(), any(Runnable.class), eq(6000L), eq(6000L));
}
}
@Test
void testStopAutoSave() {
try (MockedStatic<Bukkit> schedulerStatic = mockStatic(Bukkit.class)) {
BukkitTask task = mock(BukkitTask.class);
schedulerStatic.when(Bukkit::getScheduler).thenReturn(scheduler);
when(scheduler.runTaskTimerAsynchronously(any(), any(Runnable.class), anyLong(), anyLong())).thenReturn(task);
statsManager.startAutoSave();
statsManager.stopAutoSave();
verify(task).cancel();
}
}
@Test
void testStopAutoSaveWithoutStart() {
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());
}
}

View file

@ -0,0 +1,119 @@
package dev.loki.lomines.data;
import dev.loki.lomines.LoMinesPlugin;
import dev.loki.lomines.data.stats.model.PlayerStats;
import dev.loki.lomines.data.stats.service.StatsManager;
import org.bukkit.configuration.file.YamlConfiguration;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.UUID;
import java.util.logging.Logger;
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;
class StatsManagerIOTest {
@TempDir
Path tempDir;
private StatsManager statsManager;
private LoMinesPlugin plugin;
@BeforeEach
void setUp() {
plugin = mock(LoMinesPlugin.class);
when(plugin.getDataFolder()).thenReturn(tempDir.toFile());
when(plugin.getLogger()).thenReturn(Logger.getLogger("TestLogger"));
statsManager = new StatsManager(plugin);
}
@Test
void testLoadNonExistentFile() throws IOException {
statsManager.load();
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);
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"));
assertEquals(40, stats.getMineBlocks("mine2"));
}
@Test
void testLoadInvalidUUID() throws IOException {
String yamlContent = """
players:
invalid-uuid:
total: 100
""";
Path statsFile = tempDir.resolve("stats.yml");
Files.writeString(statsFile, yamlContent);
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();
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"));
}
}

View file

@ -1,11 +1,9 @@
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;
import dev.loki.lomines.data.stats.model.PlayerStats;
import dev.loki.lomines.data.stats.service.StatsManager;
import org.bukkit.configuration.file.YamlConfiguration;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -18,9 +16,13 @@ import java.nio.file.Path;
import java.util.UUID;
import java.util.logging.Logger;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* Unit tests for StatsManager.
@ -32,17 +34,13 @@ class StatsManagerTest {
Path tempDir;
private StatsManager statsManager;
private LoMinesPlugin plugin;
private Scheduler scheduler;
@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);
}
@ -122,141 +120,4 @@ class StatsManagerTest {
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);
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"));
assertEquals(40, stats.getMineBlocks("mine2"));
}
@Test
void testLoadInvalidUUID() throws IOException {
String yamlContent = """
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());
}
}

View file

@ -1,5 +1,7 @@
package dev.loki.lomines.data.config;
import dev.loki.lomines.data.config.model.MineConfig;
import dev.loki.lomines.data.config.model.MineConfigDefaults;
import dev.loki.lomines.data.config.block.BlockConfig;
import dev.loki.lomines.data.config.block.BlockKey;
import dev.loki.lomines.data.config.block.FillMode;
@ -8,10 +10,11 @@ import dev.loki.lomines.data.config.reset.ResetConfig;
import dev.loki.lomines.data.config.reward.RewardConfig;
import dev.loki.lomines.data.config.teleport.TeleportConfig;
import dev.loki.lomines.data.config.ui.UIConfig;
import dev.loki.lomines.util.location.Cuboid;
import dev.loki.lomines.util.location.geo.Cuboid;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
@ -20,9 +23,12 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
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.assertNotNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@Disabled("Paper API RegistryAccess not available in unit tests")
class MineConfigTest {
@Test
@ -70,7 +76,7 @@ class MineConfigTest {
weights.put(new BlockKey.Vanilla(Material.STONE), 100.0);
BlockConfig blocks = new BlockConfig(weights, FillMode.CUBOID, null);
MineConfig config = MineConfig.defaults("mymine", region, blocks);
MineConfig config = MineConfigDefaults.defaults("mymine", region, blocks);
assertEquals("mymine", config.name());
assertNotNull(config.reset());
@ -104,67 +110,6 @@ class MineConfigTest {
}
}
@Test
void testNullNameThrows() {
assertThrows(NullPointerException.class, () ->
MineConfig.builder(null));
}
@Test
void testBlankNameThrows() {
try (MockedStatic<org.bukkit.Bukkit> bukkit = Mockito.mockStatic(org.bukkit.Bukkit.class)) {
World world = mock(World.class);
when(world.getName()).thenReturn("world");
bukkit.when(() -> org.bukkit.Bukkit.getWorld("world")).thenReturn(world);
Location loc1 = new Location(world, 0, 64, 0);
Location loc2 = new Location(world, 10, 74, 10);
RegionConfig region = RegionConfig.fromSelections(List.of(loc1, loc2));
Map<BlockKey, Double> weights = new HashMap<>();
weights.put(new BlockKey.Vanilla(Material.STONE), 100.0);
BlockConfig blocks = new BlockConfig(weights, FillMode.CUBOID, null);
assertThrows(IllegalArgumentException.class, () ->
MineConfig.builder(" ")
.region(region)
.blocks(blocks)
.build());
}
}
@Test
void testNullRegionThrows() {
Map<BlockKey, Double> weights = new HashMap<>();
weights.put(new BlockKey.Vanilla(Material.STONE), 100.0);
BlockConfig blocks = new BlockConfig(weights, FillMode.CUBOID, null);
assertThrows(NullPointerException.class, () ->
MineConfig.builder("test")
.region(null)
.blocks(blocks)
.build());
}
@Test
void testNullBlocksThrows() {
try (MockedStatic<org.bukkit.Bukkit> bukkit = Mockito.mockStatic(org.bukkit.Bukkit.class)) {
World world = mock(World.class);
when(world.getName()).thenReturn("world");
bukkit.when(() -> org.bukkit.Bukkit.getWorld("world")).thenReturn(world);
Location loc1 = new Location(world, 0, 64, 0);
Location loc2 = new Location(world, 10, 74, 10);
RegionConfig region = RegionConfig.fromSelections(List.of(loc1, loc2));
assertThrows(NullPointerException.class, () ->
MineConfig.builder("test")
.region(region)
.blocks(null)
.build());
}
}
@Test
void testWorldNameDelegation() {
try (MockedStatic<org.bukkit.Bukkit> bukkit = Mockito.mockStatic(org.bukkit.Bukkit.class)) {

View file

@ -0,0 +1,88 @@
package dev.loki.lomines.data.config;
import dev.loki.lomines.data.config.model.MineConfig;
import dev.loki.lomines.data.config.block.BlockConfig;
import dev.loki.lomines.data.config.block.BlockKey;
import dev.loki.lomines.data.config.block.FillMode;
import dev.loki.lomines.data.config.region.RegionConfig;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
class MineConfigValidationTest {
@Test
void testNullNameThrows() {
assertThrows(NullPointerException.class, () ->
MineConfig.builder(null).build());
}
@Test
@Disabled("Paper API RegistryAccess not available in unit tests")
void testBlankNameThrows() {
try (MockedStatic<org.bukkit.Bukkit> bukkit = Mockito.mockStatic(org.bukkit.Bukkit.class)) {
World world = mock(World.class);
when(world.getName()).thenReturn("world");
bukkit.when(() -> org.bukkit.Bukkit.getWorld("world")).thenReturn(world);
Location loc1 = new Location(world, 0, 64, 0);
Location loc2 = new Location(world, 10, 74, 10);
RegionConfig region = RegionConfig.fromSelections(List.of(loc1, loc2));
Map<BlockKey, Double> weights = new HashMap<>();
weights.put(new BlockKey.Vanilla(Material.STONE), 100.0);
BlockConfig blocks = new BlockConfig(weights, FillMode.CUBOID, null);
assertThrows(IllegalArgumentException.class, () ->
MineConfig.builder(" ")
.region(region)
.blocks(blocks)
.build());
}
}
@Test
@Disabled("Paper API RegistryAccess not available in unit tests")
void testNullRegionThrows() {
Map<BlockKey, Double> weights = new HashMap<>();
weights.put(new BlockKey.Vanilla(Material.STONE), 100.0);
BlockConfig blocks = new BlockConfig(weights, FillMode.CUBOID, null);
assertThrows(NullPointerException.class, () ->
MineConfig.builder("test")
.region(null)
.blocks(blocks)
.build());
}
@Test
void testNullBlocksThrows() {
try (MockedStatic<org.bukkit.Bukkit> bukkit = Mockito.mockStatic(org.bukkit.Bukkit.class)) {
World world = mock(World.class);
when(world.getName()).thenReturn("world");
bukkit.when(() -> org.bukkit.Bukkit.getWorld("world")).thenReturn(world);
Location loc1 = new Location(world, 0, 64, 0);
Location loc2 = new Location(world, 10, 74, 10);
RegionConfig region = RegionConfig.fromSelections(List.of(loc1, loc2));
assertThrows(NullPointerException.class, () ->
MineConfig.builder("test")
.region(region)
.blocks(null)
.build());
}
}
}

View file

@ -1,13 +1,19 @@
package dev.loki.lomines.data.config.block;
import org.bukkit.Material;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import java.util.HashMap;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
@Disabled("Paper API RegistryAccess not available in unit tests")
class BlockConfigTest {
@Test

View file

@ -1,10 +1,15 @@
package dev.loki.lomines.data.config.block;
import org.bukkit.Material;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
@Disabled("Paper API RegistryAccess not available in unit tests")
class BlockKeyTest {
@Test

View file

@ -5,7 +5,9 @@ import org.junit.jupiter.api.Test;
import java.time.Duration;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
class ResetConfigTest {
@ -55,115 +57,10 @@ class ResetConfigTest {
assertEquals(Duration.ofDays(1), ResetConfig.builder().interval("1d").build().interval());
}
@Test
void testInvalidIntervalDefaultsToFiveMinutes() {
ResetConfig config = ResetConfig.builder()
.interval("invalid")
.build();
assertEquals(ResetConfig.DEFAULT_INTERVAL, config.interval());
}
@Test
void testNegativeIntervalDefaults() {
ResetConfig config = new ResetConfig(
Duration.ofSeconds(-10),
10.0,
false,
List.of(),
""
);
assertEquals(ResetConfig.DEFAULT_INTERVAL, config.interval());
}
@Test
void testZeroIntervalDefaults() {
ResetConfig config = new ResetConfig(
Duration.ZERO,
10.0,
false,
List.of(),
""
);
assertEquals(ResetConfig.DEFAULT_INTERVAL, config.interval());
}
@Test
void testTooShortIntervalClamped() {
ResetConfig config = ResetConfig.builder()
.interval("0.5s")
.build();
assertEquals(Duration.ofSeconds(1), config.interval());
}
@Test
void testTooLongIntervalClamped() {
ResetConfig config = ResetConfig.builder()
.interval("48h")
.build();
assertEquals(Duration.ofHours(24), config.interval());
}
@Test
void testInvalidPercentTriggerClamped() {
ResetConfig negative = new ResetConfig(
Duration.ofMinutes(5),
-10.0,
false,
List.of(),
""
);
assertEquals(ResetConfig.DEFAULT_PERCENT_TRIGGER, negative.percentTrigger());
ResetConfig over100 = new ResetConfig(
Duration.ofMinutes(5),
150.0,
false,
List.of(),
""
);
assertEquals(ResetConfig.DEFAULT_PERCENT_TRIGGER, over100.percentTrigger());
}
@Test
void testIntervalDisplay() {
assertEquals("30s", new ResetConfig(Duration.ofSeconds(30), 10.0, false, List.of(), "").intervalDisplay());
assertEquals("5m", new ResetConfig(Duration.ofMinutes(5), 10.0, false, List.of(), "").intervalDisplay());
assertEquals("2h", new ResetConfig(Duration.ofHours(2), 10.0, false, List.of(), "").intervalDisplay());
}
@Test
void testPercentTriggerEnabled() {
assertFalse(ResetConfig.defaults().isPercentTriggerEnabled());
assertFalse(new ResetConfig(Duration.ofMinutes(5), 10.0, false, List.of(), "").isPercentTriggerEnabled());
assertTrue(new ResetConfig(Duration.ofMinutes(5), 10.0, true, List.of(), "").isPercentTriggerEnabled());
assertFalse(new ResetConfig(Duration.ofMinutes(5), 0.0, true, List.of(), "").isPercentTriggerEnabled());
}
@Test
void testImmutableCommands() {
ResetConfig config = ResetConfig.builder()
.commands(List.of("cmd1"))
.build();
assertThrows(UnsupportedOperationException.class, () ->
config.commands().add("cmd2"));
}
@Test
void testNullCommandsDefaultsToEmpty() {
ResetConfig config = new ResetConfig(
Duration.ofMinutes(5),
10.0,
false,
null,
"test"
);
assertTrue(config.commands().isEmpty());
}
}

View file

@ -0,0 +1,119 @@
package dev.loki.lomines.data.config.reset;
import org.junit.jupiter.api.Test;
import java.time.Duration;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
class ResetConfigValidationTest {
@Test
void testInvalidIntervalDefaultsToFiveMinutes() {
ResetConfig config = ResetConfig.builder()
.interval("invalid")
.build();
assertEquals(ResetConfig.DEFAULT_INTERVAL, config.interval());
}
@Test
void testNegativeIntervalDefaults() {
ResetConfig config = new ResetConfig(
Duration.ofSeconds(-10),
10.0,
false,
List.of(),
""
);
assertEquals(ResetConfig.DEFAULT_INTERVAL, config.interval());
}
@Test
void testZeroIntervalDefaults() {
ResetConfig config = new ResetConfig(
Duration.ZERO,
10.0,
false,
List.of(),
""
);
assertEquals(ResetConfig.DEFAULT_INTERVAL, config.interval());
}
@Test
void testTooShortIntervalClamped() {
ResetConfig config = ResetConfig.builder()
.interval(Duration.ofMillis(500))
.build();
assertEquals(Duration.ofSeconds(1), config.interval());
}
@Test
void testTooLongIntervalClamped() {
ResetConfig config = ResetConfig.builder()
.interval("48h")
.build();
assertEquals(Duration.ofHours(24), config.interval());
}
@Test
void testInvalidPercentTriggerClamped() {
ResetConfig negative = new ResetConfig(
Duration.ofMinutes(5),
-10.0,
false,
List.of(),
""
);
assertEquals(ResetConfig.DEFAULT_PERCENT_TRIGGER, negative.percentTrigger());
ResetConfig over100 = new ResetConfig(
Duration.ofMinutes(5),
150.0,
false,
List.of(),
""
);
assertEquals(ResetConfig.DEFAULT_PERCENT_TRIGGER, over100.percentTrigger());
}
@Test
void testPercentTriggerEnabled() {
assertFalse(ResetConfig.defaults().isPercentTriggerEnabled());
assertFalse(new ResetConfig(Duration.ofMinutes(5), 10.0, false, List.of(), "").isPercentTriggerEnabled());
assertTrue(new ResetConfig(Duration.ofMinutes(5), 10.0, true, List.of(), "").isPercentTriggerEnabled());
assertFalse(new ResetConfig(Duration.ofMinutes(5), 0.0, true, List.of(), "").isPercentTriggerEnabled());
}
@Test
void testImmutableCommands() {
ResetConfig config = ResetConfig.builder()
.commands(List.of("cmd1"))
.build();
assertThrows(UnsupportedOperationException.class, () ->
config.commands().add("cmd2"));
}
@Test
void testNullCommandsDefaultsToEmpty() {
ResetConfig config = new ResetConfig(
Duration.ofMinutes(5),
10.0,
false,
null,
"test"
);
assertTrue(config.commands().isEmpty());
}
}

View file

@ -4,7 +4,10 @@ import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
class UIConfigTest {
@ -23,8 +26,8 @@ class UIConfigTest {
UIConfig config = UIConfig.disabled();
assertFalse(config.actionBarEnabled());
assertEquals("", config.actionBarFormat());
assertEquals(0, config.actionBarRange());
assertEquals(UIConfig.DEFAULT_ACTIONBAR_FORMAT, config.actionBarFormat());
assertEquals(1.0, config.actionBarRange());
}
@Test

View file

@ -0,0 +1,79 @@
package dev.loki.lomines.util;
import dev.loki.lomines.util.format.ChunkUtils;
import dev.loki.lomines.util.location.geo.Cuboid;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.Collections;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
class ChunkUtilsRefreshTest {
@Mock
private World world;
@Mock
private Chunk chunk;
@Mock
private Player player;
@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
}
@Test
void testUpdateChunks_withLargeRegion() {
Location loc1 = new Location(world, 0, 0, 0);
Location loc2 = new Location(world, 100, 100, 100);
when(world.getChunkAt(anyInt(), anyInt())).thenReturn(chunk);
when(world.getPlayers()).thenReturn(Collections.emptyList());
when(chunk.getWorld()).thenReturn(world);
Cuboid region = new Cuboid(loc1, loc2);
assertDoesNotThrow(() -> ChunkUtils.updateChunks(region));
verify(world, atLeast(40)).getChunkAt(anyInt(), anyInt());
}
@Test
void testUpdateChunks_withNoPlayers() {
Location loc1 = new Location(world, 0, 64, 0);
Location loc2 = new Location(world, 5, 70, 5);
when(world.getChunkAt(anyInt(), anyInt())).thenReturn(chunk);
when(world.getPlayers()).thenReturn(Collections.emptyList());
when(chunk.getWorld()).thenReturn(world);
Cuboid region = new Cuboid(loc1, loc2);
assertDoesNotThrow(() -> ChunkUtils.updateChunks(region));
}
@Test
void testChunkCoordinateCalculation() {
Location loc1 = new Location(world, 0, 64, 0);
Location loc2 = new Location(world, 15, 70, 15);
when(world.getChunkAt(anyInt(), anyInt())).thenReturn(chunk);
when(world.getPlayers()).thenReturn(Collections.emptyList());
when(chunk.getWorld()).thenReturn(world);
Cuboid singleChunk = new Cuboid(loc1, loc2);
ChunkUtils.updateChunks(singleChunk);
verify(world, times(1)).getChunkAt(0, 0);
}
}

View file

@ -1,7 +1,7 @@
package dev.loki.lomines.util;
import dev.loki.lomines.util.format.ChunkUtils;
import dev.loki.lomines.util.location.Cuboid;
import dev.loki.lomines.util.location.geo.Cuboid;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.World;
@ -16,7 +16,11 @@ import java.util.Collections;
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.*;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* Unit tests for ChunkUtils.
@ -50,8 +54,6 @@ class ChunkUtilsTest {
// 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);
@ -59,6 +61,7 @@ class ChunkUtilsTest {
when(chunk.getZ()).thenReturn(0);
// Should not throw exception
Cuboid region = new Cuboid(loc1, loc2);
assertDoesNotThrow(() -> ChunkUtils.updateChunks(region));
// Verify chunk was retrieved
@ -70,14 +73,13 @@ class ChunkUtilsTest {
// 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);
Cuboid region = new Cuboid(loc1, loc2);
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)
@ -90,69 +92,16 @@ class ChunkUtilsTest {
// 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);
Cuboid region = new Cuboid(loc1, loc2);
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);
}
}

View file

@ -0,0 +1,67 @@
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.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.when;
class LocationParserErrorTest {
@Test
void testParseNullString() {
ConfigParseException exception = assertThrows(
ConfigParseException.class,
() -> LocationParser.parse(null)
);
assertTrue(exception.getMessage().contains("cannot be null or empty"));
}
@Test
void testParseEmptyString() {
ConfigParseException exception = assertThrows(
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")
);
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")
);
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")
);
assertTrue(exception.getMessage().contains("does not exist"));
assertTrue(exception.getMessage().contains("nonexistent"));
}
}
}

View file

@ -9,7 +9,10 @@ import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@ -67,57 +70,6 @@ class LocationParserTest {
}
}
@Test
void testParseNullString() {
ConfigParseException exception = assertThrows(
ConfigParseException.class,
() -> LocationParser.parse(null)
);
assertTrue(exception.getMessage().contains("cannot be null or empty"));
}
@Test
void testParseEmptyString() {
ConfigParseException exception = assertThrows(
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")
);
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")
);
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")
);
assertTrue(exception.getMessage().contains("does not exist"));
assertTrue(exception.getMessage().contains("nonexistent"));
}
}
@Test
void testFormatValidLocation() {
World mockWorld = mock(World.class);

View file

@ -0,0 +1,65 @@
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;
class TimeFormatterEdgeTest {
@Test
void testFormatNegativeTicks() {
assertEquals("00:00", TimeFormatter.format(-100, "mm:ss"));
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)
);
assertTrue(exception.getMessage().contains("cannot be null or empty"));
}
@Test
void testFormatEmptyFormat() {
IllegalArgumentException exception = assertThrows(
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, " ")
);
assertTrue(exception.getMessage().contains("cannot be null or empty"));
}
@Test
void testFormatUnknownFormat() {
IllegalArgumentException exception = assertThrows(
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() {
assertEquals("833:20", TimeFormatter.format(1000000, "mm:ss"));
assertEquals("13:53:20", TimeFormatter.format(1000000, "hh:mm:ss"));
assertEquals("50000", TimeFormatter.format(1000000, "s"));
assertEquals("833", TimeFormatter.format(1000000, "m"));
assertEquals("13", TimeFormatter.format(1000000, "h"));
}
}

View file

@ -105,62 +105,6 @@ class TimeFormatterTest {
assertEquals("1", TimeFormatter.format(72000, "H"));
}
@Test
void testFormatNegativeTicks() {
// Negative ticks should be treated as 0
assertEquals("00:00", TimeFormatter.format(-100, "mm:ss"));
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)
);
assertTrue(exception.getMessage().contains("cannot be null or empty"));
}
@Test
void testFormatEmptyFormat() {
IllegalArgumentException exception = assertThrows(
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, " ")
);
assertTrue(exception.getMessage().contains("cannot be null or empty"));
}
@Test
void testFormatUnknownFormat() {
IllegalArgumentException exception = assertThrows(
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
assertEquals("833:20", TimeFormatter.format(1000000, "mm:ss"));
assertEquals("13:53:20", TimeFormatter.format(1000000, "hh:mm:ss"));
assertEquals("50000", TimeFormatter.format(1000000, "s"));
assertEquals("833", TimeFormatter.format(1000000, "m"));
assertEquals("13", TimeFormatter.format(1000000, "h"));
}
@Test
void testFormatResetTimerExample() {
// Typical reset timer: 6000 ticks (5 minutes)

View file

@ -0,0 +1,107 @@
package dev.loki.lomines.util.selection;
import dev.loki.lomines.util.location.geo.Cuboid;
import org.bukkit.Location;
import org.bukkit.World;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
class SelectionBoundsTest {
private World world;
private Selection selection;
@BeforeEach
void setUp() {
world = mock(World.class);
selection = new Selection();
when(world.getName()).thenReturn("world");
}
@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);
List<Cuboid> cuboids = selection.toCuboids();
assertEquals(1, cuboids.size());
}
@Test
void testPairInvariant() {
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));
selection.setPoint(2, loc1);
selection.setPoint(3, loc2);
assertTrue(selection.hasPair(1));
selection.setPoint(4, loc1);
selection.setPoint(5, loc2);
assertTrue(selection.hasPair(2));
selection.setPoint(6, loc1);
selection.setPoint(7, loc2);
assertTrue(selection.hasPair(3));
selection.setPoint(8, loc1);
selection.setPoint(9, loc2);
assertTrue(selection.hasPair(4));
}
}

View file

@ -6,7 +6,13 @@ import org.junit.jupiter.api.Test;
import java.util.Optional;
import java.util.UUID;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNotSame;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
class SelectionManagerTest {

View file

@ -1,6 +1,6 @@
package dev.loki.lomines.util.selection;
import dev.loki.lomines.util.location.Cuboid;
import dev.loki.lomines.util.location.geo.Cuboid;
import org.bukkit.Location;
import org.bukkit.World;
import org.junit.jupiter.api.BeforeEach;
@ -9,7 +9,12 @@ import org.junit.jupiter.api.Test;
import java.util.List;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@ -134,90 +139,4 @@ class SelectionTest {
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);
assertTrue(selection.hasPair(4));
}
}