diff --git a/pom.xml b/pom.xml
index 28f8df3..baa41dd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -30,6 +30,11 @@
${java.version}
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 3.2.5
+
org.apache.maven.plugins
maven-shade-plugin
@@ -123,5 +128,19 @@
2.12.2
provided
+
+
+ org.junit.jupiter
+ junit-jupiter
+ 5.10.2
+ test
+
+
+ org.mockito
+ mockito-core
+ 5.12.0
+ test
+
+
diff --git a/src/test/java/net/supremesurvival/supremecore/commandUtils/SupremeTabsTest.java b/src/test/java/net/supremesurvival/supremecore/commandUtils/SupremeTabsTest.java
new file mode 100644
index 0000000..7c50ac0
--- /dev/null
+++ b/src/test/java/net/supremesurvival/supremecore/commandUtils/SupremeTabsTest.java
@@ -0,0 +1,39 @@
+package net.supremesurvival.supremecore.commandUtils;
+
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+import org.junit.jupiter.api.Test;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.mock;
+
+class SupremeTabsTest {
+
+ @Test
+ void tabCompletesFromProvidedArguments() {
+ SupremeTabs tabs = new SupremeTabs(Arrays.asList("status", "start", "stop"));
+ CommandSender sender = mock(CommandSender.class);
+ Command command = mock(Command.class);
+
+ List result = tabs.onTabComplete(sender, command, "test", new String[]{"st"});
+
+ assertNotNull(result);
+ assertTrue(result.contains("status"));
+ assertTrue(result.contains("start"));
+ assertTrue(result.contains("stop"));
+ }
+
+ @Test
+ void returnsNullForSecondArgAndBeyond() {
+ SupremeTabs tabs = new SupremeTabs(Arrays.asList("one", "two"));
+ CommandSender sender = mock(CommandSender.class);
+ Command command = mock(Command.class);
+
+ List result = tabs.onTabComplete(sender, command, "test", new String[]{"one", "two"});
+
+ assertNull(result);
+ }
+}
diff --git a/src/test/java/net/supremesurvival/supremecore/mobUtils/MobLootTest.java b/src/test/java/net/supremesurvival/supremecore/mobUtils/MobLootTest.java
new file mode 100644
index 0000000..809c05a
--- /dev/null
+++ b/src/test/java/net/supremesurvival/supremecore/mobUtils/MobLootTest.java
@@ -0,0 +1,47 @@
+package net.supremesurvival.supremecore.mobUtils;
+
+import org.bukkit.Material;
+import org.bukkit.event.entity.EntityDeathEvent;
+import org.bukkit.inventory.ItemStack;
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+class MobLootTest {
+
+ @Test
+ void removesGoldFarmDrops() {
+ MobLoot mobLoot = new MobLoot();
+
+ ItemStack ingot = mock(ItemStack.class);
+ when(ingot.getType()).thenReturn(Material.GOLD_INGOT);
+
+ ItemStack nugget = mock(ItemStack.class);
+ when(nugget.getType()).thenReturn(Material.GOLD_NUGGET);
+
+ ItemStack sword = mock(ItemStack.class);
+ when(sword.getType()).thenReturn(Material.GOLDEN_SWORD);
+
+ ItemStack flesh = mock(ItemStack.class);
+ when(flesh.getType()).thenReturn(Material.ROTTEN_FLESH);
+
+ List drops = new ArrayList<>();
+ drops.add(ingot);
+ drops.add(nugget);
+ drops.add(sword);
+ drops.add(flesh);
+
+ EntityDeathEvent event = mock(EntityDeathEvent.class);
+ when(event.getDrops()).thenReturn(drops);
+
+ mobLoot.checkLoot(event);
+
+ assertEquals(1, drops.size());
+ assertEquals(Material.ROTTEN_FLESH, drops.get(0).getType());
+ }
+}
diff --git a/src/test/java/net/supremesurvival/supremecore/morality/player/MoralPlayerTest.java b/src/test/java/net/supremesurvival/supremecore/morality/player/MoralPlayerTest.java
new file mode 100644
index 0000000..d570f18
--- /dev/null
+++ b/src/test/java/net/supremesurvival/supremecore/morality/player/MoralPlayerTest.java
@@ -0,0 +1,39 @@
+package net.supremesurvival.supremecore.morality.player;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.UUID;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class MoralPlayerTest {
+
+ @Test
+ void constructorAndMutatorsWork() {
+ UUID id = UUID.randomUUID();
+ MoralPlayer player = new MoralPlayer(id, 10, "NEUTRAL", 100L);
+
+ assertEquals(id, player.getUuid());
+ assertEquals(10, player.getMorality());
+ assertEquals("NEUTRAL", player.getStanding());
+ assertEquals(100L, player.getLastUpdatedEpochSeconds());
+
+ player.setMorality(-25);
+ player.setStanding("CORRUPT");
+ player.setLastUpdatedEpochSeconds(250L);
+
+ assertEquals(-25, player.getMorality());
+ assertEquals("CORRUPT", player.getStanding());
+ assertEquals(250L, player.getLastUpdatedEpochSeconds());
+ }
+
+ @Test
+ void backwardsCompatibleConstructorDefaultsStandingAndTimestamp() {
+ UUID id = UUID.randomUUID();
+ MoralPlayer player = new MoralPlayer(id, 42);
+
+ assertEquals(id, player.getUuid());
+ assertEquals(42, player.getMorality());
+ assertEquals("NEUTRAL", player.getStanding());
+ }
+}
diff --git a/src/test/java/net/supremesurvival/supremecore/realestate/RealEstateManagerTest.java b/src/test/java/net/supremesurvival/supremecore/realestate/RealEstateManagerTest.java
new file mode 100644
index 0000000..41ab1ba
--- /dev/null
+++ b/src/test/java/net/supremesurvival/supremecore/realestate/RealEstateManagerTest.java
@@ -0,0 +1,51 @@
+package net.supremesurvival.supremecore.realestate;
+
+import org.junit.jupiter.api.Test;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class RealEstateManagerTest {
+
+ @Test
+ void filtersListingsByTownNameCaseInsensitive() throws Exception {
+ RealEstateManager manager = new RealEstateManager();
+ List listings = new ArrayList<>();
+ listings.add(new RealEstateListing(1, "Riverton", "world", 10, 10, 100.0));
+ listings.add(new RealEstateListing(2, "Darkvale", "world", 20, 20, 50.0));
+
+ setPrivateField(manager, "cachedListings", listings);
+ setPrivateField(manager, "lastRefresh", System.currentTimeMillis());
+
+ List filtered = manager.getListings("RIVER");
+
+ assertEquals(1, filtered.size());
+ assertEquals(1, filtered.get(0).id());
+ }
+
+ @Test
+ void returnsListingByIdFromCache() throws Exception {
+ RealEstateManager manager = new RealEstateManager();
+ List listings = new ArrayList<>();
+ listings.add(new RealEstateListing(3, "Stonehelm", "world", 5, 5, 250.0));
+
+ setPrivateField(manager, "cachedListings", listings);
+ setPrivateField(manager, "lastRefresh", System.currentTimeMillis());
+
+ RealEstateListing found = manager.getListingById(3);
+ RealEstateListing missing = manager.getListingById(99);
+
+ assertNotNull(found);
+ assertEquals("Stonehelm", found.townName());
+ assertNull(missing);
+ }
+
+ private static void setPrivateField(Object target, String fieldName, Object value) throws Exception {
+ Field field = target.getClass().getDeclaredField(fieldName);
+ field.setAccessible(true);
+ field.set(target, value);
+ }
+}