Merge pull request #3127 from Multiverse/ben/mv5/testssss

More testsss
This commit is contained in:
Ben Woo 2024-11-20 21:48:37 +08:00 committed by GitHub
commit 1eeb265f4e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 358 additions and 32 deletions

View File

@ -136,7 +136,7 @@ dependencies {
// Tests // Tests
testImplementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.21' testImplementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.21'
testImplementation 'com.github.seeseemelk:MockBukkit-v1.21:3.133.0' testImplementation 'org.mockbukkit.mockbukkit:mockbukkit-v1.21:4.3.1'
testImplementation('com.googlecode.json-simple:json-simple:1.1.1') { testImplementation('com.googlecode.json-simple:json-simple:1.1.1') {
exclude group: 'junit', module: 'junit' exclude group: 'junit', module: 'junit'
} }

View File

@ -185,17 +185,12 @@ public class WorldManager {
return worldActionResult(CreateFailureReason.WORLD_EXIST_LOADED, options.worldName()); return worldActionResult(CreateFailureReason.WORLD_EXIST_LOADED, options.worldName());
} else if (getWorld(options.worldName()).isDefined()) { } else if (getWorld(options.worldName()).isDefined()) {
return worldActionResult(CreateFailureReason.WORLD_EXIST_UNLOADED, options.worldName()); return worldActionResult(CreateFailureReason.WORLD_EXIST_UNLOADED, options.worldName());
} else if (hasWorldFolder(options.worldName())) { } else if (worldNameChecker.hasWorldFolder(options.worldName())) {
return worldActionResult(CreateFailureReason.WORLD_EXIST_FOLDER, options.worldName()); return worldActionResult(CreateFailureReason.WORLD_EXIST_FOLDER, options.worldName());
} }
return worldActionResult(options); return worldActionResult(options);
} }
private boolean hasWorldFolder(String worldName) {
File worldFolder = new File(Bukkit.getWorldContainer(), worldName);
return worldFolder.exists();
}
private Attempt<LoadedMultiverseWorld, CreateFailureReason> createValidatedWorld( private Attempt<LoadedMultiverseWorld, CreateFailureReason> createValidatedWorld(
CreateWorldOptions options) { CreateWorldOptions options) {
String parsedGenerator = parseGenerator(options.worldName(), options.generator()); String parsedGenerator = parseGenerator(options.worldName(), options.generator());
@ -530,9 +525,6 @@ public class WorldManager {
Logging.severe("Invalid world name: " + newWorldName); Logging.severe("Invalid world name: " + newWorldName);
return worldActionResult(CloneFailureReason.INVALID_WORLDNAME, newWorldName); return worldActionResult(CloneFailureReason.INVALID_WORLDNAME, newWorldName);
} }
if (worldNameChecker.isValidWorldFolder(newWorldName)) {
return worldActionResult(CloneFailureReason.WORLD_EXIST_FOLDER, newWorldName);
}
if (isLoadedWorld(newWorldName)) { if (isLoadedWorld(newWorldName)) {
Logging.severe("World already loaded when attempting to clone: " + newWorldName); Logging.severe("World already loaded when attempting to clone: " + newWorldName);
return worldActionResult(CloneFailureReason.WORLD_EXIST_LOADED, newWorldName); return worldActionResult(CloneFailureReason.WORLD_EXIST_LOADED, newWorldName);
@ -541,6 +533,9 @@ public class WorldManager {
Logging.severe("World already exist unloaded: " + newWorldName); Logging.severe("World already exist unloaded: " + newWorldName);
return worldActionResult(CloneFailureReason.WORLD_EXIST_UNLOADED, newWorldName); return worldActionResult(CloneFailureReason.WORLD_EXIST_UNLOADED, newWorldName);
} }
if (worldNameChecker.hasWorldFolder(newWorldName)) {
return worldActionResult(CloneFailureReason.WORLD_EXIST_FOLDER, newWorldName);
}
return worldActionResult(options); return worldActionResult(options);
} }

View File

@ -4,6 +4,7 @@ import java.io.File;
import java.util.Set; import java.util.Set;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import io.vavr.control.Option;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -45,17 +46,32 @@ public class WorldNameChecker {
*/ */
@NotNull @NotNull
public NameStatus checkName(@Nullable String worldName) { public NameStatus checkName(@Nullable String worldName) {
if (BLACKLIST_NAMES.contains(worldName)) { return Option.of(worldName).map(name -> {
return NameStatus.BLACKLISTED; if (name.isEmpty()) {
} return NameStatus.EMPTY;
if (worldName == null || !WORLD_NAME_PATTERN.matcher(worldName).matches()) { }
return NameStatus.INVALID_CHARS; if (BLACKLIST_NAMES.contains(name)) {
} return NameStatus.BLACKLISTED;
return NameStatus.VALID; }
if (!WORLD_NAME_PATTERN.matcher(name).matches()) {
return NameStatus.INVALID_CHARS;
}
return NameStatus.VALID;
}).getOrElse(NameStatus.EMPTY);
} }
/** /**
* Checks if a world name has a valid world folder. * Check if a world name has a world folder directory. It may not contain valid world data.
*
* @param worldName The world name to check on.
* @return True if the folder exists, else false.
*/
public boolean hasWorldFolder(@Nullable String worldName) {
return checkFolder(worldName) != FolderStatus.DOES_NOT_EXIST;
}
/**
* Checks if a world name has a valid world folder with basic world data.
* *
* @param worldName The world name to check on. * @param worldName The world name to check on.
* @return True if check result is valid, else false. * @return True if check result is valid, else false.
@ -65,7 +81,7 @@ public class WorldNameChecker {
} }
/** /**
* Checks if a world folder is valid. * Checks if a world folder is valid with basic world data.
* *
* @param worldFolder The world folder to check on. * @param worldFolder The world folder to check on.
* @return True if check result is valid, else false. * @return True if check result is valid, else false.
@ -132,6 +148,11 @@ public class WorldNameChecker {
*/ */
INVALID_CHARS, INVALID_CHARS,
/**
* Name string that is null or length 0.
*/
EMPTY,
/** /**
* Name not valid as it is deemed blacklisted. * Name not valid as it is deemed blacklisted.
*/ */

View File

@ -1,27 +1,31 @@
package org.mvplugins.multiverse.core package org.mvplugins.multiverse.core
import be.seeseemelk.mockbukkit.MockBukkit import com.dumptruckman.minecraft.util.Logging
import be.seeseemelk.mockbukkit.ServerMock import org.mockbukkit.mockbukkit.MockBukkit
import org.mvplugins.multiverse.core.inject.PluginServiceLocator import org.mvplugins.multiverse.core.inject.PluginServiceLocator
import org.mvplugins.multiverse.core.mock.MVServerMock
import org.mvplugins.multiverse.core.utils.TestingMode import org.mvplugins.multiverse.core.utils.TestingMode
import kotlin.test.AfterTest import kotlin.test.AfterTest
import kotlin.test.BeforeTest import kotlin.test.BeforeTest
import kotlin.test.assertNotNull
/** /**
* Basic abstract test class that sets up MockBukkit and MultiverseCore. * Basic abstract test class that sets up MockBukkit and MultiverseCore.
*/ */
abstract class TestWithMockBukkit { abstract class TestWithMockBukkit {
protected lateinit var server: ServerMock protected lateinit var server: MVServerMock
protected lateinit var multiverseCore: MultiverseCore protected lateinit var multiverseCore: MultiverseCore
protected lateinit var serviceLocator : PluginServiceLocator protected lateinit var serviceLocator : PluginServiceLocator
@BeforeTest @BeforeTest
fun setUpMockBukkit() { fun setUpMockBukkit() {
TestingMode.enable() TestingMode.enable()
server = MockBukkit.mock() server = MockBukkit.mock(MVServerMock())
multiverseCore = MockBukkit.load(MultiverseCore::class.java) multiverseCore = MockBukkit.load(MultiverseCore::class.java)
Logging.setDebugLevel(3)
serviceLocator = multiverseCore.serviceLocator serviceLocator = multiverseCore.serviceLocator
assertNotNull(server.commandMap)
} }
@AfterTest @AfterTest

View File

@ -1,8 +1,8 @@
package org.mvplugins.multiverse.core.commands package org.mvplugins.multiverse.core.commands
import be.seeseemelk.mockbukkit.entity.PlayerMock
import org.bukkit.Bukkit import org.bukkit.Bukkit
import org.bukkit.ChatColor import org.bukkit.ChatColor
import org.mockbukkit.mockbukkit.entity.PlayerMock
import org.mvplugins.multiverse.core.TestWithMockBukkit import org.mvplugins.multiverse.core.TestWithMockBukkit
import kotlin.test.BeforeTest import kotlin.test.BeforeTest
import kotlin.test.Test import kotlin.test.Test

View File

@ -0,0 +1,53 @@
package org.mvplugins.multiverse.core.mock;
import org.bukkit.World;
import org.bukkit.WorldCreator;
import org.jetbrains.annotations.NotNull;
import org.mockbukkit.mockbukkit.ServerMock;
import org.mockbukkit.mockbukkit.command.CommandMapMock;
import org.mockbukkit.mockbukkit.world.WorldMock;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
public class MVServerMock extends ServerMock {
private final File worldContainer;
public MVServerMock() throws IOException {
super();
this.worldContainer = Files.createTempDirectory("world-container").toFile();
this.worldContainer.deleteOnExit();
System.out.println("Created test world folder: " + this.worldContainer.getAbsolutePath());
}
// This is required for acf reflection to work
@Override
public @NotNull CommandMapMock getCommandMap() {
return super.getCommandMap();
}
@Override
public @NotNull File getWorldContainer() {
return this.worldContainer;
}
@Override
public World createWorld(@NotNull WorldCreator creator) {
WorldMock world = new MVWorldMock(creator);
world.getWorldFolder().mkdirs();
createFile(new File(world.getWorldFolder(), "uid.dat"));
createFile(new File(world.getWorldFolder(), "level.dat"));
addWorld(world);
return world;
}
private void createFile(File file) {
try {
file.createNewFile();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -0,0 +1,30 @@
package org.mvplugins.multiverse.core.mock;
import org.bukkit.WorldCreator;
import org.jetbrains.annotations.NotNull;
import org.mockbukkit.mockbukkit.MockBukkit;
import org.mockbukkit.mockbukkit.world.WorldMock;
import java.io.File;
public class MVWorldMock extends WorldMock {
private final File worldFolder;
private final boolean generateStructures;
public MVWorldMock(@NotNull WorldCreator creator) {
super(creator);
this.worldFolder = new File(MockBukkit.getMock().getWorldContainer(), getName());
this.generateStructures = creator.generateStructures();
}
@Override
public @NotNull File getWorldFolder() {
return this.worldFolder;
}
@Override
public boolean canGenerateStructures() {
return this.generateStructures;
}
}

View File

@ -1,47 +1,209 @@
package org.mvplugins.multiverse.core.world package org.mvplugins.multiverse.core.world
import org.bukkit.Bukkit
import org.bukkit.World import org.bukkit.World
import org.bukkit.WorldType import org.bukkit.WorldType
import org.mvplugins.multiverse.core.TestWithMockBukkit import org.mvplugins.multiverse.core.TestWithMockBukkit
import org.mvplugins.multiverse.core.world.options.CloneWorldOptions
import org.mvplugins.multiverse.core.world.options.CreateWorldOptions import org.mvplugins.multiverse.core.world.options.CreateWorldOptions
import org.mvplugins.multiverse.core.world.options.RegenWorldOptions
import org.mvplugins.multiverse.core.world.options.UnloadWorldOptions
import org.mvplugins.multiverse.core.world.reasons.CloneFailureReason
import org.mvplugins.multiverse.core.world.reasons.CreateFailureReason
import org.mvplugins.multiverse.core.world.reasons.LoadFailureReason
import java.io.File
import kotlin.test.* import kotlin.test.*
class WorldManagerTest : TestWithMockBukkit() { class WorldManagerTest : TestWithMockBukkit() {
private lateinit var worldManager: WorldManager private lateinit var worldManager: WorldManager
private lateinit var world: LoadedMultiverseWorld private lateinit var world: LoadedMultiverseWorld
private lateinit var world2: LoadedMultiverseWorld
@BeforeTest @BeforeTest
fun setUp() { fun setUp() {
worldManager = serviceLocator.getActiveService(WorldManager::class.java).takeIf { it != null } ?: run { worldManager = serviceLocator.getActiveService(WorldManager::class.java).takeIf { it != null } ?: run {
throw IllegalStateException("WorldManager is not available as a service") } throw IllegalStateException("WorldManager is not available as a service") }
worldManager.createWorld(CreateWorldOptions.worldName("world")) assertTrue(worldManager.createWorld(CreateWorldOptions.worldName("world")).isSuccess)
world = worldManager.getLoadedWorld("world").get() world = worldManager.getLoadedWorld("world").get()
assertNotNull(world) assertNotNull(world)
assertTrue(worldManager.createWorld(CreateWorldOptions.worldName("world2")).isSuccess)
world2 = worldManager.getLoadedWorld("world2").get()
assertNotNull(world2)
} }
@Test @Test
fun `Creates a new world`() { fun `Create world with custom options`() {
worldManager.createWorld(CreateWorldOptions.worldName("world_nether") assertTrue(worldManager.createWorld(CreateWorldOptions.worldName("world_nether")
.environment(World.Environment.NETHER) .environment(World.Environment.NETHER)
.generateStructures(false) .generateStructures(false)
.seed(1234L) .seed(1234L)
.useSpawnAdjust(true) .useSpawnAdjust(false)
.worldType(WorldType.FLAT) .worldType(WorldType.FLAT)
) ).isSuccess)
val world = worldManager.getLoadedWorld("world_nether").get() val getWorld = worldManager.getLoadedWorld("world_nether")
assertTrue(getWorld.isDefined)
val world = getWorld.get()
assertNotNull(world) assertNotNull(world)
assertEquals("world_nether", world.name) assertEquals("world_nether", world.name)
assertEquals(World.Environment.NETHER, world.environment) assertEquals(World.Environment.NETHER, world.environment)
assertEquals("", world.generator) assertFalse(world.canGenerateStructures().get())
assertEquals(1234L, world.seed) assertEquals(1234L, world.seed)
assertFalse(world.adjustSpawn)
assertEquals(WorldType.FLAT, world.worldType.get())
assertEquals("", world.generator)
}
@Test
fun `Create world failed - invalid worldname`() {
assertEquals(
CreateFailureReason.INVALID_WORLDNAME,
worldManager.createWorld(CreateWorldOptions.worldName("*!@^&#*(")).failureReason
)
}
@Test
fun `Create world failed - world exists and loaded`() {
assertEquals(
CreateFailureReason.WORLD_EXIST_LOADED,
worldManager.createWorld(CreateWorldOptions.worldName("world")).failureReason
)
}
@Test
fun `Create world failed - world exists but unloaded`() {
assertTrue(worldManager.unloadWorld(UnloadWorldOptions.world(world)).isSuccess)
assertEquals(
CreateFailureReason.WORLD_EXIST_UNLOADED,
worldManager.createWorld(CreateWorldOptions.worldName("world")).failureReason
)
}
@Test
fun `Create world failed - world folder exists`() {
File(Bukkit.getWorldContainer(), "worldfolder").mkdir()
assertEquals(
CreateFailureReason.WORLD_EXIST_FOLDER,
worldManager.createWorld(CreateWorldOptions.worldName("worldfolder")).failureReason
)
}
@Test
fun `Remove world`() {
assertTrue(worldManager.removeWorld(world).isSuccess)
assertFalse(worldManager.getWorld("world").isDefined)
assertFalse(worldManager.getLoadedWorld("world").isDefined)
assertFalse(worldManager.getUnloadedWorld("world").isDefined)
} }
@Test @Test
fun `Delete world`() { fun `Delete world`() {
worldManager.deleteWorld(world) assertTrue(worldManager.deleteWorld(world).isSuccess)
assertFalse(worldManager.getLoadedWorld("world").isDefined) assertFalse(worldManager.getLoadedWorld("world").isDefined)
} }
@Test
fun `Unload and load world`() {
assertTrue(worldManager.unloadWorld(UnloadWorldOptions.world(world2).saveBukkitWorld(true)).isSuccess)
assertFalse(world2.isLoaded)
assertFalse(world2.bukkitWorld.isDefined)
assertFalse(worldManager.getLoadedWorld("world2").isDefined)
assertTrue(worldManager.getWorld("world2").isDefined)
assertTrue(worldManager.getUnloadedWorld("world2").isDefined)
assertTrue(worldManager.loadWorld("world2").isSuccess)
assertTrue(world2.isLoaded)
// todo: think what to do when a world is re-loaded with a different uid
// assertTrue(world2.bukkitWorld.isDefined)
assertTrue(worldManager.getLoadedWorld("world2").isDefined)
assertFalse(worldManager.getUnloadedWorld("world2").isDefined)
}
@Test
fun `Load world failed - non-existent world`() {
assertEquals(
LoadFailureReason.WORLD_NON_EXISTENT,
worldManager.loadWorld("ghost").failureReason
)
}
@Test
fun `Load world failed - world folder exists but not imported`() {
File(Bukkit.getWorldContainer(), "worldfolder").mkdir()
File(Bukkit.getWorldContainer(), "worldfolder/level.dat").createNewFile()
assertEquals(
LoadFailureReason.WORLD_EXIST_FOLDER,
worldManager.loadWorld("worldfolder").failureReason
)
}
@Test
fun `Regen world`() {
assertTrue(worldManager.regenWorld(RegenWorldOptions
.world(world2)
.seed(4321L)
).isSuccess)
val getWorld = worldManager.getLoadedWorld("world2")
assertTrue(getWorld.isDefined)
val world = getWorld.get()
assertNotNull(world)
assertEquals(4321L, world.seed)
}
@Test
fun `Clone world`() {
assertTrue(worldManager.cloneWorld(CloneWorldOptions.fromTo(world, "cloneworld")).isSuccess)
val getWorld = worldManager.getLoadedWorld("cloneworld")
assertTrue(getWorld.isDefined)
val world = getWorld.get()
assertNotNull(world)
assertEquals("cloneworld", world.name)
}
@Test
fun `Clone world failed - invalid world name`() {
assertEquals(
CloneFailureReason.INVALID_WORLDNAME,
worldManager.cloneWorld(CloneWorldOptions.fromTo(world, "HU(@*!#")).failureReason
)
}
@Test
fun `Clone world failed - target world exists and loaded`() {
assertEquals(
CloneFailureReason.WORLD_EXIST_LOADED,
worldManager.cloneWorld(CloneWorldOptions.fromTo(world, "world2")).failureReason
)
}
@Test
fun `Clone world failed - target world exists but unloaded`() {
assertTrue(worldManager.unloadWorld(UnloadWorldOptions.world(world2)).isSuccess)
assertEquals(
CloneFailureReason.WORLD_EXIST_UNLOADED,
worldManager.cloneWorld(CloneWorldOptions.fromTo(world, "world2")).failureReason
)
}
@Test
fun `Clone world failed - target world folder exists`() {
File(Bukkit.getWorldContainer(), "worldfolder").mkdir()
assertEquals(
CloneFailureReason.WORLD_EXIST_FOLDER,
worldManager.cloneWorld(CloneWorldOptions.fromTo(world, "worldfolder")).failureReason
)
}
@Test
fun `Get potential worlds`() {
File(Bukkit.getWorldContainer(), "newworld1").mkdir()
File(Bukkit.getWorldContainer(), "newworld1/level.dat").createNewFile()
File(Bukkit.getWorldContainer(), "newworld2").mkdir()
File(Bukkit.getWorldContainer(), "newworld2/level.dat").createNewFile()
assertEquals(listOf("newworld1", "newworld2"), worldManager.getPotentialWorlds())
}
} }

View File

@ -0,0 +1,61 @@
package org.mvplugins.multiverse.core.world
import org.bukkit.Bukkit
import org.mvplugins.multiverse.core.TestWithMockBukkit
import java.io.File
import kotlin.test.BeforeTest
import kotlin.test.Test
import kotlin.test.*
class WorldNameCheckerTest : TestWithMockBukkit() {
lateinit var worldNameChecker: WorldNameChecker
@BeforeTest
fun setUp() {
worldNameChecker = serviceLocator.getActiveService(WorldNameChecker::class.java).takeIf { it != null } ?: run {
throw IllegalStateException("WorldNameChecker is not available as a service") }
}
@Test
fun `Valid world name`() {
assertEquals(WorldNameChecker.NameStatus.VALID, worldNameChecker.checkName("test"))
}
@Test
fun `Invalid characters in world name`() {
assertEquals(WorldNameChecker.NameStatus.INVALID_CHARS, worldNameChecker.checkName("test!"))
}
@Test
fun `Empty world name`() {
assertEquals(WorldNameChecker.NameStatus.EMPTY, worldNameChecker.checkName(null))
assertEquals(WorldNameChecker.NameStatus.EMPTY, worldNameChecker.checkName(""))
}
@Test
fun `Blacklisted world name`() {
assertEquals(WorldNameChecker.NameStatus.BLACKLISTED, worldNameChecker.checkName("logs"))
assertEquals(WorldNameChecker.NameStatus.BLACKLISTED, worldNameChecker.checkName("plugins"))
}
@Test
fun `Valid world folder`() {
File(Bukkit.getWorldContainer(), "test").mkdir()
File(Bukkit.getWorldContainer(), "test/level.dat").createNewFile()
assertEquals(WorldNameChecker.FolderStatus.VALID, worldNameChecker.checkFolder("test"))
}
@Test
fun `Not a valid world folder`() {
File(Bukkit.getWorldContainer(), "test").mkdir()
File(Bukkit.getWorldContainer(), "test/random.txt").createNewFile()
assertEquals(WorldNameChecker.FolderStatus.NOT_A_WORLD, worldNameChecker.checkFolder("test"))
}
@Test
fun `World folder does not exist`() {
File(Bukkit.getWorldContainer(), "test").mkdir()
assertEquals(WorldNameChecker.FolderStatus.DOES_NOT_EXIST, worldNameChecker.checkFolder("test2"))
}
}