new version 1.3.3

This commit is contained in:
loki 2026-03-10 12:39:21 +01:00
parent 2d5c5eea48
commit d9eb747c1b
37 changed files with 1021 additions and 471 deletions

View file

@ -0,0 +1,140 @@
package dev.loki.loparkour.generator.jump;
import org.bukkit.Location;
import org.bukkit.World;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
/**
* Unit tests for JumpValidator.
* Tests jump possibility calculations for parkour generation.
*/
class JumpValidatorTest {
private JumpValidator validator;
@Mock
private World world;
@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
validator = new JumpValidator();
}
@Test
void testCanJump_SameLevel_Distance1() {
// 1 block forward, same height - always possible
Location from = new Location(world, 0, 100, 0);
Location to = new Location(world, 1, 100, 0);
assertTrue(validator.canJump(from, to), "1 block jump at same level should be possible");
}
@Test
void testCanJump_SameLevel_Distance4() {
// 4 blocks forward, same height - possible
Location from = new Location(world, 0, 100, 0);
Location to = new Location(world, 4, 100, 0);
assertTrue(validator.canJump(from, to), "4 block jump at same level should be possible");
}
@Test
void testCanJump_SameLevel_Distance5() {
// 5 blocks forward, same height - impossible without speed
Location from = new Location(world, 0, 100, 0);
Location to = new Location(world, 5, 100, 0);
assertFalse(validator.canJump(from, to), "5 block jump at same level should be impossible");
}
@Test
void testCanJump_Up1_Distance3() {
// 3 blocks forward, 1 block up - possible
Location from = new Location(world, 0, 100, 0);
Location to = new Location(world, 3, 101, 0);
assertTrue(validator.canJump(from, to), "3 block jump with 1 up should be possible");
}
@Test
void testCanJump_Up1_Distance4() {
// 4 blocks forward, 1 block up - impossible
Location from = new Location(world, 0, 100, 0);
Location to = new Location(world, 4, 101, 0);
assertFalse(validator.canJump(from, to), "4 block jump with 1 up should be impossible");
}
@Test
void testCanJump_Down1_Distance4() {
// 4 blocks forward, 1 block down - possible
Location from = new Location(world, 0, 100, 0);
Location to = new Location(world, 4, 99, 0);
assertTrue(validator.canJump(from, to), "4 block jump with 1 down should be possible");
}
@Test
void testCanJump_Down2_Distance4() {
// 4 blocks forward, 2 blocks down - possible
Location from = new Location(world, 0, 100, 0);
Location to = new Location(world, 4, 98, 0);
assertTrue(validator.canJump(from, to), "4 block jump with 2 down should be possible");
}
@Test
void testCanJump_Up2_Distance1() {
// 1 block forward, 2 blocks up - impossible (max jump height is 1.25)
Location from = new Location(world, 0, 100, 0);
Location to = new Location(world, 1, 102, 0);
assertFalse(validator.canJump(from, to), "Jump 2 blocks up should be impossible");
}
@Test
void testCanJump_Diagonal() {
// Diagonal jump - 3 blocks X, 2 blocks Z, same height
Location from = new Location(world, 0, 100, 0);
Location to = new Location(world, 3, 100, 2);
double distance = Math.sqrt(3*3 + 2*2); // ~3.6 blocks
assertTrue(validator.canJump(from, to), "Diagonal jump of ~3.6 blocks should be possible");
}
@Test
void testCanJump_NullLocations() {
// Test null safety
Location validLoc = new Location(world, 0, 100, 0);
assertFalse(validator.canJump((Location)null, validLoc),
"Should return false for null from location");
assertFalse(validator.canJump(validLoc, (Location)null),
"Should return false for null to location");
assertFalse(validator.canJump((Location)null, (Location)null),
"Should return false for both null locations");
}
@Test
void testCanJump_SameLocation() {
// Jump to same location - should be false
Location loc = new Location(world, 0, 100, 0);
assertFalse(validator.canJump(loc, loc), "Jump to same location should be impossible");
}
@Test
void testCanJump_VeryLongDistance() {
// 10 blocks forward - impossible
Location from = new Location(world, 0, 100, 0);
Location to = new Location(world, 10, 100, 0);
assertFalse(validator.canJump(from, to), "10 block jump should be impossible");
}
}

View file

@ -0,0 +1,180 @@
package dev.loki.loparkour.ghost;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
/**
* Unit tests for GhostData serialization and deserialization.
* Tests file I/O operations for ghost recordings.
*/
class GhostDataTest {
@Test
void testConstructor() {
// Test basic construction
List<GhostFrame> frames = new ArrayList<>();
frames.add(new GhostFrame(0, 0, 100, 0, 0, 0));
frames.add(new GhostFrame(1000, 1, 100, 0, 90, 0));
GhostData data = new GhostData("TestPlayer", "uuid-123", 42, frames);
assertEquals("TestPlayer", data.getPlayerName());
assertEquals("uuid-123", data.getPlayerUUID());
assertEquals(42, data.getScore());
assertEquals(2, data.getFrames().size());
}
@Test
void testSaveAndLoad(@TempDir Path tempDir) throws IOException {
// Create test data
List<GhostFrame> frames = new ArrayList<>();
frames.add(new GhostFrame(0, 0, 100, 0, 0, 0));
frames.add(new GhostFrame(500, 1, 100, 0, 45, 0));
frames.add(new GhostFrame(1000, 2, 100, 0, 90, 0));
GhostData original = new GhostData("Player1", "uuid-456", 100, frames);
// Save to file
File file = tempDir.resolve("test.ghost").toFile();
original.saveToFile(file);
assertTrue(file.exists(), "Ghost file should be created");
assertTrue(file.length() > 0, "Ghost file should not be empty");
// Load from file
GhostData loaded = GhostData.loadFromFile(file);
// Verify data
assertEquals(original.getPlayerName(), loaded.getPlayerName());
assertEquals(original.getPlayerUUID(), loaded.getPlayerUUID());
assertEquals(original.getScore(), loaded.getScore());
assertEquals(original.getFrames().size(), loaded.getFrames().size());
// Verify frames
for (int i = 0; i < original.getFrames().size(); i++) {
GhostFrame origFrame = original.getFrames().get(i);
GhostFrame loadedFrame = loaded.getFrames().get(i);
assertEquals(origFrame.getTimestamp(), loadedFrame.getTimestamp());
assertEquals(origFrame.getX(), loadedFrame.getX(), 0.001);
assertEquals(origFrame.getY(), loadedFrame.getY(), 0.001);
assertEquals(origFrame.getZ(), loadedFrame.getZ(), 0.001);
assertEquals(origFrame.getYaw(), loadedFrame.getYaw(), 0.001);
assertEquals(origFrame.getPitch(), loadedFrame.getPitch(), 0.001);
}
}
@Test
void testEmptyFrames(@TempDir Path tempDir) throws IOException {
// Test with no frames
GhostData data = new GhostData("EmptyPlayer", "uuid-789", 0, new ArrayList<>());
File file = tempDir.resolve("empty.ghost").toFile();
data.saveToFile(file);
GhostData loaded = GhostData.loadFromFile(file);
assertEquals(0, loaded.getFrames().size());
assertEquals("EmptyPlayer", loaded.getPlayerName());
}
@Test
void testLargeDataset(@TempDir Path tempDir) throws IOException {
// Test with many frames (simulate 60 seconds at 20 TPS)
List<GhostFrame> frames = new ArrayList<>();
for (int i = 0; i < 1200; i++) {
frames.add(new GhostFrame(
i * 50L, // 50ms per frame
i * 0.1, // X position
100.0, // Y position
i * 0.05, // Z position
(i % 360), // Yaw
0 // Pitch
));
}
GhostData data = new GhostData("LongRunner", "uuid-long", 1200, frames);
File file = tempDir.resolve("large.ghost").toFile();
data.saveToFile(file);
GhostData loaded = GhostData.loadFromFile(file);
assertEquals(1200, loaded.getFrames().size());
assertEquals(1200, loaded.getScore());
}
@Test
void testSpecialCharactersInName(@TempDir Path tempDir) throws IOException {
// Test with special characters in player name
GhostData data = new GhostData(
"Player_123-ABC",
"uuid-special",
50,
List.of(new GhostFrame(0, 0, 100, 0, 0, 0))
);
File file = tempDir.resolve("special.ghost").toFile();
data.saveToFile(file);
GhostData loaded = GhostData.loadFromFile(file);
assertEquals("Player_123-ABC", loaded.getPlayerName());
}
@Test
void testNegativeCoordinates(@TempDir Path tempDir) throws IOException {
// Test with negative coordinates
List<GhostFrame> frames = new ArrayList<>();
frames.add(new GhostFrame(0, -100, 50, -200, -90, -45));
frames.add(new GhostFrame(1000, -99, 51, -199, -45, 0));
GhostData data = new GhostData("NegativePlayer", "uuid-neg", 10, frames);
File file = tempDir.resolve("negative.ghost").toFile();
data.saveToFile(file);
GhostData loaded = GhostData.loadFromFile(file);
GhostFrame frame = loaded.getFrames().get(0);
assertEquals(-100, frame.getX(), 0.001);
assertEquals(50, frame.getY(), 0.001);
assertEquals(-200, frame.getZ(), 0.001);
assertEquals(-90, frame.getYaw(), 0.001);
assertEquals(-45, frame.getPitch(), 0.001);
}
@Test
void testLoadNonExistentFile() {
// Test loading from non-existent file
File file = new File("nonexistent.ghost");
assertThrows(IOException.class, () -> {
GhostData.loadFromFile(file);
}, "Should throw IOException for non-existent file");
}
@Test
void testFramesImmutability() {
// Test that frames list is copied (defensive copy)
List<GhostFrame> originalFrames = new ArrayList<>();
originalFrames.add(new GhostFrame(0, 0, 100, 0, 0, 0));
GhostData data = new GhostData("Player", "uuid", 10, originalFrames);
// Modify original list
originalFrames.add(new GhostFrame(1000, 1, 100, 0, 0, 0));
// GhostData should still have only 1 frame
assertEquals(1, data.getFrames().size(),
"GhostData should create defensive copy of frames list");
}
}