diff --git a/dough-data/src/main/java/io/github/bakedlibs/dough/collections/LoopIterator.java b/dough-data/src/main/java/io/github/bakedlibs/dough/collections/LoopIterator.java index 2b90eb77..d82f27ac 100644 --- a/dough-data/src/main/java/io/github/bakedlibs/dough/collections/LoopIterator.java +++ b/dough-data/src/main/java/io/github/bakedlibs/dough/collections/LoopIterator.java @@ -101,7 +101,7 @@ public Optional find(@Nonnull Predicate predicate) { int start = index; T current = next(); - while (index != start || predicate.test(current)) { + while (index != start && !predicate.test(current)) { current = next(); } diff --git a/dough-data/src/main/java/io/github/bakedlibs/dough/data/persistent/PersistentUUIDDataType.java b/dough-data/src/main/java/io/github/bakedlibs/dough/data/persistent/PersistentUUIDDataType.java index 2b57e46e..491a8e02 100644 --- a/dough-data/src/main/java/io/github/bakedlibs/dough/data/persistent/PersistentUUIDDataType.java +++ b/dough-data/src/main/java/io/github/bakedlibs/dough/data/persistent/PersistentUUIDDataType.java @@ -46,7 +46,7 @@ private PersistentUUIDDataType() {} Validate.notNull(ints, "The provided integer array cannot be null!"); Validate.isTrue(ints.length == 4, "The integer array must have a length of 4."); - return new UUID(ints[0] | ints[1] & 0xFFFFFFFFL, ints[2] | ints[3] & 0xFFFFFFFFL); + return new UUID(((long) ints[0] << 32) | ints[1] & 0xFFFFFFFFL, ((long) ints[2] << 32) | ints[3] & 0xFFFFFFFFL); } public static @Nonnull int[] toIntArray(@Nonnull UUID uuid) { diff --git a/dough-data/src/test/java/io/github/bakedlibs/dough/blocks/TestBlockPosition.java b/dough-data/src/test/java/io/github/bakedlibs/dough/blocks/TestBlockPosition.java new file mode 100644 index 00000000..e7470a5e --- /dev/null +++ b/dough-data/src/test/java/io/github/bakedlibs/dough/blocks/TestBlockPosition.java @@ -0,0 +1,91 @@ +package io.github.bakedlibs.dough.blocks; + +import be.seeseemelk.mockbukkit.MockBukkit; +import be.seeseemelk.mockbukkit.WorldMock; +import org.bukkit.Location; +import org.bukkit.World; +import org.junit.jupiter.api.*; + +class TestBlockPosition { + + @BeforeAll + static void init() { + MockBukkit.mock(); + } + + @AfterAll + static void teardown() { + MockBukkit.unmock(); + } + + @Test + @DisplayName("Test the coordinate getters") + void testCoordinateGetters() { + int x = 10; + int y = 1000; + int z = 50; + World world = new WorldMock(); + BlockPosition blockPosition = new BlockPosition(world, x, y, z); + Assertions.assertEquals(x, blockPosition.getX()); + Assertions.assertEquals(y, blockPosition.getY()); + Assertions.assertEquals(z, blockPosition.getZ()); + } + + @Test + void testCloning() { + int x = 10; + int y = 1000; + int z = 50; + World world = new WorldMock(); + BlockPosition blockPosition = new BlockPosition(world, x, y, z); + Location location = blockPosition.toLocation(); + Assertions.assertEquals(blockPosition.getPosition(), BlockPosition.getAsLong(location)); + Assertions.assertEquals(blockPosition, new BlockPosition(world, blockPosition.getPosition())); + Assertions.assertEquals(x, location.getBlockX()); + Assertions.assertEquals(y, location.getBlockY()); + Assertions.assertEquals(z, location.getBlockZ()); + Assertions.assertEquals(blockPosition, new BlockPosition(location)); + Assertions.assertEquals(blockPosition.hashCode(), new BlockPosition(location).hashCode()); + Assertions.assertEquals(x >> 4, blockPosition.getChunkX()); + Assertions.assertEquals(z >> 4, blockPosition.getChunkZ()); + } + + @Test + void testInvalidWorld() { + World world = new WorldMock(); + BlockPosition position = new BlockPosition(world, 1, 1, 1); + BlockPosition copy = new BlockPosition(world, 1, 1, 1); + world = null; + // Force garbage collection + System.gc(); + String msg = "The reference of this BlockPositions world has been cleared"; + Assertions.assertThrows(IllegalStateException.class, position::getWorld, msg); + Assertions.assertThrows(IllegalStateException.class, position::getBlock, msg); + Assertions.assertThrows(IllegalStateException.class, position::getChunk, msg); + // If the world is un-loaded the equals method should always return false. + Assertions.assertNotEquals(position, copy); + } + + @Test + void testInvalidEquality() { + World world = new WorldMock(); + Assertions.assertNotEquals(1, new BlockPosition(world, 1, 1, 1)); + } + + @Test + void testToString() { + String name = "world"; + WorldMock world = new WorldMock(); + world.setName(name); + BlockPosition position = new BlockPosition(world, 1, 1, 1); + String expected = "BlockPosition(world=world, x=1, y=1, z=1, position=" + position.getPosition() + ")"; + Assertions.assertEquals(expected, position.toString()); + String expectedNoRef = "BlockPosition(world=, x=1, y=1, z=1, position=" + position.getPosition() + ")"; + world = null; + // Force GC + System.gc(); + Assertions.assertEquals(expectedNoRef, position.toString()); + } + + +} diff --git a/dough-data/src/test/java/io/github/bakedlibs/dough/blocks/TestChunkPosition.java b/dough-data/src/test/java/io/github/bakedlibs/dough/blocks/TestChunkPosition.java new file mode 100644 index 00000000..1c9f22f2 --- /dev/null +++ b/dough-data/src/test/java/io/github/bakedlibs/dough/blocks/TestChunkPosition.java @@ -0,0 +1,97 @@ +package io.github.bakedlibs.dough.blocks; + +import be.seeseemelk.mockbukkit.MockBukkit; +import be.seeseemelk.mockbukkit.WorldMock; +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.World; +import org.junit.jupiter.api.*; + +class TestChunkPosition { + + @BeforeAll + static void init() { + MockBukkit.mock(); + } + + @AfterAll + static void teardown() { + MockBukkit.unmock(); + } + + @Test + @DisplayName("Test the coordinate getters") + void testCoordinateGetters() { + int x = 10; + int z = 50; + World world = new WorldMock(); + ChunkPosition chunkPosition = new ChunkPosition(world, x, z); + Assertions.assertEquals(x, chunkPosition.getX()); + Assertions.assertEquals(z, chunkPosition.getZ()); + } + + @Test + void testConstructors() { + int x = 10; + int z = 50; + World world = new WorldMock(); + ChunkPosition chunkPosition = new ChunkPosition(world, x, z); + ChunkPosition fromLocation = new ChunkPosition(new Location(world, x << 4, 1, z << 4)); + Assertions.assertEquals(chunkPosition, fromLocation); + Assertions.assertEquals(chunkPosition.hashCode(), fromLocation.hashCode()); + Assertions.assertEquals(chunkPosition, new ChunkPosition(world.getChunkAt(x, z))); + Assertions.assertEquals(chunkPosition.getPosition(), ChunkPosition.getAsLong(x, z)); + Assertions.assertEquals(chunkPosition, new ChunkPosition(world, chunkPosition.getPosition())); + } + + @Test + void testInvalidWorld() { + World world = new WorldMock(); + ChunkPosition position = new ChunkPosition(world, 1, 1); + ChunkPosition copy = new ChunkPosition(world, 1, 1); + world = null; + // Force garbage collection + System.gc(); + String msg = "The reference of this ChunkPositions world has been cleared"; + Assertions.assertThrows(IllegalStateException.class, position::getWorld, msg); + Assertions.assertThrows(IllegalStateException.class, position::getChunk, msg); + // If the world is un-loaded the equals method should always return false. + Assertions.assertNotEquals(position, copy); + } + + @Test + void testInvalidEquality() { + World world = new WorldMock(); + Assertions.assertNotEquals(1, new ChunkPosition(world, 1, 1)); + } + + @Test + void testToString() { + String name = "world"; + WorldMock world = new WorldMock(); + world.setName(name); + ChunkPosition position = new ChunkPosition(world, 1, 1); + String expected = "ChunkPosition(world=world, x=1, z=1, position=" + position.getPosition() + ")"; + Assertions.assertEquals(expected, position.toString()); + String expectedNoRef = "ChunkPosition(world=, x=1, z=1, position=" + position.getPosition() + ")"; + world = null; + // Force GC + System.gc(); + Assertions.assertEquals(expectedNoRef, position.toString()); + } + + @Test + void testIsLoaded() { + World world = new WorldMock(); + Chunk chunk = world.getChunkAt(1, 1); + ChunkPosition position = new ChunkPosition(chunk); + Assertions.assertEquals(chunk.isLoaded(), position.isLoaded()); + chunk = null; + world = null; + // Force GC + System.gc(); + Assertions.assertFalse(position.isLoaded()); + } + + +} diff --git a/dough-data/src/test/java/io/github/bakedlibs/dough/collections/CollectionTestUtils.java b/dough-data/src/test/java/io/github/bakedlibs/dough/collections/CollectionTestUtils.java new file mode 100644 index 00000000..b5eb750d --- /dev/null +++ b/dough-data/src/test/java/io/github/bakedlibs/dough/collections/CollectionTestUtils.java @@ -0,0 +1,50 @@ +package io.github.bakedlibs.dough.collections; + +import org.junit.jupiter.api.Assertions; + +import javax.annotation.Nonnull; +import java.util.Collection; +import java.util.Map; + +public class CollectionTestUtils { + + static void assertHaveEqualElements(@Nonnull Collection c1, @Nonnull Collection c2) { + Assertions.assertEquals(c1.size(), c2.size()); + Assertions.assertTrue(c1.containsAll(c2)); + } + + static void assertHaveEqualElements(@Nonnull Map m1, @Nonnull Map m2) { + Assertions.assertEquals(m1.size(), m2.size()); + for (Map.Entry entry : m1.entrySet()) { + Assertions.assertEquals(m2.get(entry.getKey()), entry.getValue()); + } + } + + static void assertHaveClonedElements(@Nonnull Collection c1, @Nonnull Collection c2) { + Assertions.assertEquals(c1.size(), c2.size()); + for (T t1 : c1) { + for (T t2 : c2) { + // If they are the same, it did not clone and thus we fail. + Assertions.assertNotSame(t1, t2); + if (t1.equals(t2)) { + // If they are equal, the element has been cloned, thus, we break and check the next element. + break; + } + } + } + } + + static void assertHaveClonedElements(@Nonnull Map m1, @Nonnull Map m2) { + Assertions.assertEquals(m1.size(), m2.size()); + for (Map.Entry entry : m1.entrySet()) { + V otherValue = m2.get(entry.getKey()); + // If they are the same, it did not clone and thus we fail. + Assertions.assertNotSame(entry.getValue(), otherValue); + if (entry.getValue().equals(otherValue)) { + // If they are equal, the element has been cloned, thus, we break and check the next element. + break; + } + } + } + +} diff --git a/dough-data/src/test/java/io/github/bakedlibs/dough/collections/DummyData.java b/dough-data/src/test/java/io/github/bakedlibs/dough/collections/DummyData.java new file mode 100644 index 00000000..0b205faf --- /dev/null +++ b/dough-data/src/test/java/io/github/bakedlibs/dough/collections/DummyData.java @@ -0,0 +1,49 @@ +package io.github.bakedlibs.dough.collections; + +import javax.annotation.Nonnull; + +class DummyData implements Cloneable { + + private final int value; + + DummyData(int value) { + this.value = value; + } + + private DummyData(@Nonnull DummyData other) { + this.value = other.value; + } + + @Override + public @Nonnull DummyData clone() { + try { + super.clone(); + } catch (CloneNotSupportedException ex) { + ex.printStackTrace(); + } + return new DummyData(this); + } + + @Override + public boolean equals(final Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + + DummyData dummyData = (DummyData) o; + + return value == dummyData.value; + } + + @Override + public int hashCode() { + return value; + } + + @Override + public String toString() { + return "DummyData{" + "value=" + value + '}'; + } + +} diff --git a/dough-data/src/test/java/io/github/bakedlibs/dough/collections/DummyKeyed.java b/dough-data/src/test/java/io/github/bakedlibs/dough/collections/DummyKeyed.java new file mode 100644 index 00000000..12c7399a --- /dev/null +++ b/dough-data/src/test/java/io/github/bakedlibs/dough/collections/DummyKeyed.java @@ -0,0 +1,21 @@ +package io.github.bakedlibs.dough.collections; + +import org.bukkit.Keyed; +import org.bukkit.NamespacedKey; + +import javax.annotation.Nonnull; + +public class DummyKeyed implements Keyed { + + private final NamespacedKey key; + + public DummyKeyed(@Nonnull NamespacedKey key) { + this.key = key; + } + + @Override + public @Nonnull NamespacedKey getKey() { + return key; + } + +} diff --git a/dough-data/src/test/java/io/github/bakedlibs/dough/collections/PairUtils.java b/dough-data/src/test/java/io/github/bakedlibs/dough/collections/PairUtils.java new file mode 100644 index 00000000..58a2b4c5 --- /dev/null +++ b/dough-data/src/test/java/io/github/bakedlibs/dough/collections/PairUtils.java @@ -0,0 +1,25 @@ +package io.github.bakedlibs.dough.collections; + +import org.junit.jupiter.api.Assertions; + +public class PairUtils { + + static void assertValues(Pair pair, P expectedPrimary, S expectedSecondary) { + Assertions.assertSame(expectedPrimary, pair.getFirstValue()); + Assertions.assertSame(expectedSecondary, pair.getSecondValue()); + } + + static void assertValues(OptionalPair pair, P expectedPrimary, S expectedSecondary) { + if (expectedPrimary == null) { + Assertions.assertFalse(pair.getFirstValue().isPresent()); + } else { + Assertions.assertEquals(expectedPrimary, pair.getFirstValue().orElse(null)); + } + if (expectedSecondary == null) { + Assertions.assertFalse(pair.getSecondValue().isPresent()); + } else { + Assertions.assertEquals(expectedSecondary, pair.getSecondValue().orElse(null)); + } + } + +} diff --git a/dough-data/src/test/java/io/github/bakedlibs/dough/collections/TestCopyUtils.java b/dough-data/src/test/java/io/github/bakedlibs/dough/collections/TestCopyUtils.java new file mode 100644 index 00000000..f0cc53e2 --- /dev/null +++ b/dough-data/src/test/java/io/github/bakedlibs/dough/collections/TestCopyUtils.java @@ -0,0 +1,67 @@ +package io.github.bakedlibs.dough.collections; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +class TestCopyUtils { + + @Test + @DisplayName("Test if collections are deeply cloned properly") + void testCloningCollections() { + Collection dummyCollection = + Arrays.asList(new DummyData(1), new DummyData(2), new DummyData(3)); + Collection clonedCollection = + CopyUtils.deepCopy(dummyCollection, DummyData::clone, ArrayList::new); + CollectionTestUtils.assertHaveEqualElements(dummyCollection, clonedCollection); + CollectionTestUtils.assertHaveClonedElements(dummyCollection, clonedCollection); + } + + @Test + @DisplayName("Test if maps are deeply cloned properly") + void testCloningMaps() { + Map dummyMap = new HashMap<>(); + dummyMap.put(1, new DummyData(1)); + dummyMap.put(2, new DummyData(2)); + dummyMap.put(3, new DummyData(3)); + Map clonedMap = CopyUtils.deepCopy(dummyMap, DummyData::clone, HashMap::new); + CollectionTestUtils.assertHaveEqualElements(dummyMap, clonedMap); + CollectionTestUtils.assertHaveClonedElements(dummyMap, clonedMap); + // We first perform a shallow copy from clonedMap + Map clonedMapDeepCopy = new HashMap<>(clonedMap); + // We then mutate the shallow copy and turn it into a deep copy. + CopyUtils.deepCopy(clonedMapDeepCopy, DummyData::clone); + CollectionTestUtils.assertHaveEqualElements(clonedMap, clonedMapDeepCopy); + CollectionTestUtils.assertHaveClonedElements(clonedMap, clonedMapDeepCopy); + } + + @Test + @DisplayName("Test if arrays are deeply cloned properly") + void testCloningArrays() { + DummyData[] dummyArray = new DummyData[]{new DummyData(1), new DummyData(2), new DummyData(3)}; + DummyData[] clonedArray = CopyUtils.deepCopy(dummyArray, DummyData::clone, DummyData[]::new); + CollectionTestUtils.assertHaveEqualElements(Arrays.asList(dummyArray), Arrays.asList(clonedArray)); + CollectionTestUtils.assertHaveClonedElements(Arrays.asList(dummyArray), Arrays.asList(clonedArray)); + DummyData[] deepClonedArray = new DummyData[clonedArray.length]; + CopyUtils.deepCopy(clonedArray, DummyData::clone, deepClonedArray); + CollectionTestUtils.assertHaveEqualElements(Arrays.asList(dummyArray), Arrays.asList(deepClonedArray)); + CollectionTestUtils.assertHaveClonedElements(Arrays.asList(dummyArray), Arrays.asList(deepClonedArray)); + // Cannot clone if the length of the sink < length of source + DummyData[] invalidArray = new DummyData[clonedArray.length - 1]; + Assertions.assertThrows(IllegalArgumentException.class, () -> CopyUtils.deepCopy(dummyArray, DummyData::clone, invalidArray)); + try { + DummyData[] validArray = new DummyData[clonedArray.length + 1]; + CopyUtils.deepCopy(dummyArray, DummyData::clone, validArray); + } catch (Exception ex) { + // Unexpected failure + Assertions.fail(ex); + } + } + +} diff --git a/dough-data/src/test/java/io/github/bakedlibs/dough/collections/TestKeyMap.java b/dough-data/src/test/java/io/github/bakedlibs/dough/collections/TestKeyMap.java new file mode 100644 index 00000000..c9b1807a --- /dev/null +++ b/dough-data/src/test/java/io/github/bakedlibs/dough/collections/TestKeyMap.java @@ -0,0 +1,32 @@ +package io.github.bakedlibs.dough.collections; + +import org.bukkit.NamespacedKey; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.Map; + +class TestKeyMap { + + @Test + @DisplayName("Test if the add method uses the correct key") + @SuppressWarnings("deprecation") + void testAdd() { + NamespacedKey key = new NamespacedKey("abc", "def"); + DummyKeyed dummyKeyed = new DummyKeyed(key); + KeyMap keyMap1 = new KeyMap<>(); + keyMap1.add(dummyKeyed); + Assertions.assertEquals(dummyKeyed, keyMap1.get(dummyKeyed.getKey()).orElse(null)); + } + + @Test + @DisplayName("Test if the constructor uses the output of the supplier") + void testConstructor() { + Map map = new HashMap<>(); + KeyMap keyMap2 = new KeyMap<>(() -> map); + Assertions.assertSame(map, keyMap2.getInternalMap()); + } + +} diff --git a/dough-data/src/test/java/io/github/bakedlibs/dough/collections/TestLoopIterator.java b/dough-data/src/test/java/io/github/bakedlibs/dough/collections/TestLoopIterator.java new file mode 100644 index 00000000..273b68bc --- /dev/null +++ b/dough-data/src/test/java/io/github/bakedlibs/dough/collections/TestLoopIterator.java @@ -0,0 +1,63 @@ +package io.github.bakedlibs.dough.collections; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.NoSuchElementException; +import java.util.stream.Collectors; + +class TestLoopIterator { + + @Test + void testLooping() { + Collection integers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + LoopIterator iterator = new LoopIterator<>(integers); + Assertions.assertTrue(iterator.hasNext()); + int index = 0; + for (Integer integer : integers) { + Assertions.assertTrue(iterator.hasNext()); + Assertions.assertEquals(index, iterator.getIndex()); + Assertions.assertEquals(integer, iterator.next()); + index++; + } + // Check loop + Assertions.assertTrue(iterator.hasNext()); + Assertions.assertEquals(1, iterator.next()); + } + + @Test + void testStream() { + Collection integers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + LoopIterator iterator = new LoopIterator<>(integers); + Collection integersCopy = iterator + .stream() + .limit(integers.size()) + .collect(Collectors.toList()); + CollectionTestUtils.assertHaveEqualElements(integers, integersCopy); + } + + @Test + void testInvalidCases() { + LoopIterator emptyIterator = new LoopIterator<>(Collections.emptyList()); + Assertions.assertFalse(emptyIterator.hasNext()); + Assertions.assertThrows(NoSuchElementException.class, emptyIterator::next, "The given collection was empty."); + Assertions.assertThrows(IllegalArgumentException.class, () -> new LoopIterator<>(emptyIterator), "Cannot loop-iterate over a LoopIterator"); + } + + @Test + void testFinding() { + Collection integers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + LoopIterator iterator = new LoopIterator<>(integers); + Assertions.assertTrue(iterator.find(i -> i <= 10 && i > 0).isPresent()); + Assertions.assertFalse(iterator.find(i -> i > 10 || i < 1).isPresent()); + } + + @Test + void testEmptyIterator() { + LoopIterator emptyIterator = new LoopIterator<>(Collections.emptyList()); + Assertions.assertFalse(emptyIterator.find(x -> true).isPresent()); + } +} diff --git a/dough-data/src/test/java/io/github/bakedlibs/dough/collections/TestOptionalMap.java b/dough-data/src/test/java/io/github/bakedlibs/dough/collections/TestOptionalMap.java new file mode 100644 index 00000000..2f84d3ff --- /dev/null +++ b/dough-data/src/test/java/io/github/bakedlibs/dough/collections/TestOptionalMap.java @@ -0,0 +1,79 @@ +package io.github.bakedlibs.dough.collections; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +class TestOptionalMap { + + @Test + void testNullSupplier() { + Assertions.assertThrows(IllegalStateException.class, () -> new OptionalMap<>(() -> null), "Internal Map is not allowed to be null!"); + } + + @Test + void testGetters() { + Map map = Collections.emptyMap(); + OptionalMap optionalMap = new OptionalMap<>(() -> map); + Assertions.assertFalse(optionalMap.get(1).isPresent()); + Assertions.assertFalse(optionalMap.containsKey(1)); + Assertions.assertFalse(optionalMap.containsValue(1)); + Assertions.assertEquals(0, optionalMap.size()); + Assertions.assertSame(map.keySet(), optionalMap.keySet()); + Assertions.assertSame(map.entrySet(), optionalMap.entrySet()); + Assertions.assertSame(map.values(), optionalMap.values()); + Assertions.assertSame(map.entrySet().iterator(), optionalMap.iterator()); + Assertions.assertSame(map, optionalMap.getInternalMap()); + Assertions.assertEquals(optionalMap, map); + Assertions.assertEquals(map.hashCode(), optionalMap.hashCode()); + Assertions.assertEquals(1, optionalMap.getOrDefault(10, 1)); + } + + @Test + void testMapModification() { + OptionalMap map = new OptionalMap<>(HashMap::new); + map.put(1, 1); + Assertions.assertTrue(map.containsKey(1)); + Assertions.assertTrue(map.get(1).isPresent()); + Assertions.assertEquals(1, map.get(1).orElse(null)); + Assertions.assertEquals(1, map.size()); + map.clear(); + Assertions.assertEquals(0, map.size()); + Assertions.assertTrue(map.isEmpty()); + map.put(1, 1); + Assertions.assertThrows(RuntimeException.class, + () -> map.ifPresent(1, x -> { + throw new RuntimeException("Value = " + x); + }), "Value = 1"); + map.remove(1); + Assertions.assertThrows(RuntimeException.class, + () -> map.ifAbsent(1, v -> { + // The value passed here must always be null + Assertions.assertNull(v); + throw new RuntimeException("Value not found!"); + }), "Value not found!"); + Assertions.assertEquals(2, map.computeIfAbsent(2, k -> k)); + Assertions.assertEquals(3, map.computeIfPresent(2, (k, v) -> v + 1)); + Assertions.assertNull(map.compute(4, (k, v) -> null)); + Assertions.assertEquals(4, map.compute(4, (k, v) -> k)); + // The value in the map for key=4 is 4, here we merge the values by summing them together. + Assertions.assertEquals(8, map.merge(4, 4, Integer::sum)); + // Since the value mapped for key=4 is 8, we check to see if 8 is whats returned. + Assertions.assertEquals(8, map.putIfAbsent(4, 4)); + // No value for key=5 so it should be null + Assertions.assertNull(map.putIfAbsent(5, 5)); + Assertions.assertEquals(5, map.get(5).orElse(null)); + Map map2 = new HashMap<>(); + map2.put(6, 6); + map2.put(7, 7); + map.putAll(map2); + Assertions.assertEquals(6, map.get(6).orElse(null)); + Assertions.assertEquals(7, map.get(7).orElse(null)); + } + + + +} diff --git a/dough-data/src/test/java/io/github/bakedlibs/dough/collections/TestOptionalPair.java b/dough-data/src/test/java/io/github/bakedlibs/dough/collections/TestOptionalPair.java new file mode 100644 index 00000000..e8307487 --- /dev/null +++ b/dough-data/src/test/java/io/github/bakedlibs/dough/collections/TestOptionalPair.java @@ -0,0 +1,70 @@ +package io.github.bakedlibs.dough.collections; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.AbstractMap; +import java.util.Map; + +class TestOptionalPair { + + @Test + void testGettersAndSetters() { + + Object primary = new Object(); + + Map.Entry entry = new AbstractMap.SimpleEntry<>(primary, null); + OptionalPair pair = new OptionalPair<>(primary, null); + OptionalPair pairFromEntry = new OptionalPair<>(entry); + + PairUtils.assertValues(pair, primary, null); + PairUtils.assertValues(pairFromEntry, primary, null); + + Object modifiedSecondary = new Object(); + + pair.setFirstValue(null); + pair.setSecondValue(modifiedSecondary); + PairUtils.assertValues(pair, null, modifiedSecondary); + + } + + @Test + void testEquality() { + + Object primary = new Object(); + Object secondary = new Object(); + + Map.Entry entry = new AbstractMap.SimpleEntry<>(primary, secondary); + OptionalPair optionalPair = new OptionalPair<>(primary, secondary); + OptionalPair pairFromEntry = new OptionalPair<>(entry); + OptionalPair optionalPairFromPair = new OptionalPair<>(new Pair<>(primary, secondary)); + + Assertions.assertTrue(optionalPairFromPair.getFirstValue().isPresent()); + Assertions.assertTrue(optionalPairFromPair.getSecondValue().isPresent()); + + Assertions.assertEquals(optionalPair, optionalPairFromPair); + Assertions.assertEquals(optionalPair.hashCode(), optionalPairFromPair.hashCode()); + Assertions.assertEquals(optionalPair, pairFromEntry); + Assertions.assertEquals(optionalPair.hashCode(), optionalPairFromPair.hashCode()); + Assertions.assertEquals(optionalPair, optionalPair); + + Assertions.assertNotEquals(null, optionalPair); + Assertions.assertEquals(optionalPair, new OptionalPair<>(primary, secondary)); + Assertions.assertNotEquals(optionalPair, new OptionalPair<>(primary, null)); + Assertions.assertNotEquals(optionalPair, new OptionalPair<>(null, secondary)); + + OptionalPair differentTypePair = new OptionalPair<>(primary, 10); + Assertions.assertNotEquals(optionalPair, differentTypePair); + + } + + @Test + void testToString() { + OptionalPair pair = new OptionalPair<>(1, null); + String expected = "OptionalPair(firstValue=Optional[1], secondValue=Optional.empty)"; + Assertions.assertEquals(expected, pair.toString()); + } + + + +} diff --git a/dough-data/src/test/java/io/github/bakedlibs/dough/collections/TestPair.java b/dough-data/src/test/java/io/github/bakedlibs/dough/collections/TestPair.java new file mode 100644 index 00000000..90fd205e --- /dev/null +++ b/dough-data/src/test/java/io/github/bakedlibs/dough/collections/TestPair.java @@ -0,0 +1,72 @@ +package io.github.bakedlibs.dough.collections; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.AbstractMap; +import java.util.Map; + +class TestPair { + + @Test + void testGettersAndSetters() { + + Object primary = new Object(); + Object secondary = new Object(); + + Map.Entry entry = new AbstractMap.SimpleEntry<>(primary, secondary); + OptionalPair optionalPair = new OptionalPair<>(primary, secondary); + Pair pair = new Pair<>(primary, secondary); + Pair pairFromOptional = new Pair<>(optionalPair); + Pair pairFromEntry = new Pair<>(entry); + + PairUtils.assertValues(pair, primary, secondary); + PairUtils.assertValues(pairFromOptional, primary, secondary); + PairUtils.assertValues(pairFromEntry, primary, secondary); + + Object modifiedPrimary = new Object(); + Object modifiedSecondary = new Object(); + + pair.setFirstValue(modifiedPrimary); + pair.setSecondValue(modifiedSecondary); + PairUtils.assertValues(pair, modifiedPrimary, modifiedSecondary); + + } + + @Test + void testEquality() { + Object primary = new Object(); + Object secondary = new Object(); + + Map.Entry entry = new AbstractMap.SimpleEntry<>(primary, secondary); + OptionalPair optionalPair = new OptionalPair<>(primary, secondary); + Pair pair = new Pair<>(primary, secondary); + Pair pairFromOptional = new Pair<>(optionalPair); + Pair pairFromEntry = new Pair<>(entry); + + Assertions.assertEquals(pair, pairFromOptional); + Assertions.assertEquals(pair.hashCode(), pairFromOptional.hashCode()); + Assertions.assertEquals(pair, pairFromEntry); + Assertions.assertEquals(pair.hashCode(), pairFromOptional.hashCode()); + Assertions.assertEquals(pair, pair); + + Assertions.assertNotEquals(null, pair); + Assertions.assertEquals(pair, new Pair<>(primary, secondary)); + Assertions.assertNotEquals(pair, new Pair<>(primary, new Object())); + Assertions.assertNotEquals(pair, new Pair<>(new Object(), secondary)); + + Pair differentTypePair = new Pair<>(primary, 10); + Assertions.assertNotEquals(pair, differentTypePair); + + } + + @Test + void testToString() { + Pair pair = new Pair<>(1, 2); + String expected = "Pair(firstValue=1, secondValue=2)"; + Assertions.assertEquals(expected, pair.toString()); + } + + + +} diff --git a/dough-data/src/test/java/io/github/bakedlibs/dough/collections/TestRandomizedSet.java b/dough-data/src/test/java/io/github/bakedlibs/dough/collections/TestRandomizedSet.java new file mode 100644 index 00000000..2a395034 --- /dev/null +++ b/dough-data/src/test/java/io/github/bakedlibs/dough/collections/TestRandomizedSet.java @@ -0,0 +1,74 @@ +package io.github.bakedlibs.dough.collections; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.*; + +class TestRandomizedSet { + + @Test + void testModification() { + RandomizedSet randomizedSet = new RandomizedSet<>(); + Assertions.assertTrue(randomizedSet.isEmpty()); + Assertions.assertEquals(0, randomizedSet.size()); + Assertions.assertThrows(IllegalArgumentException.class, () -> randomizedSet.add(1, 0), "A Weight may never be less than or equal to zero!"); + Assertions.assertTrue(randomizedSet.add(1, 1)); + Assertions.assertEquals(1, randomizedSet.size()); + Assertions.assertEquals(1, randomizedSet.sumWeights()); + Assertions.assertThrows(IllegalArgumentException.class, () -> randomizedSet.setWeight(1, 0), "A Weight may never be less than or equal to zero!"); + randomizedSet.setWeight(1, 0.5f); + Assertions.assertEquals(0.5f, randomizedSet.sumWeights()); + randomizedSet.setWeight(1, 1); + Assertions.assertThrows(IllegalStateException.class, () -> randomizedSet.setWeight(2, 1), "The specified Object is not contained in this Set"); + Assertions.assertFalse(randomizedSet.add(1, 2)); + // There is only one element in the set. + Assertions.assertEquals(1, randomizedSet.getRandom()); + Assertions.assertTrue(randomizedSet.remove(1)); + Assertions.assertNull(randomizedSet.getRandom()); + Assertions.assertFalse(randomizedSet.remove(1)); + randomizedSet.add(1, 1f); + randomizedSet.clear(); + Assertions.assertTrue(randomizedSet.isEmpty()); + Assertions.assertEquals(0, randomizedSet.sumWeights()); + + } + + @Test + void testProbability() { + RandomizedSet randomizedSet = new RandomizedSet<>(); + randomizedSet.add(1, 1); + randomizedSet.add(2, 1); + Assertions.assertEquals(2, randomizedSet.sumWeights()); + Map expectedWeights = new HashMap<>(); + expectedWeights.put(1, 0.5f); + expectedWeights.put(2, 0.5f); + CollectionTestUtils.assertHaveEqualElements(expectedWeights, randomizedSet.toMap()); + int ones = 0; + int twos = 0; + for (int i = 0; i < 1000; i++) { + if (randomizedSet.getRandom() == 1) { + ones++; + } else { + twos++; + } + } + // +- 10% + Assertions.assertEquals(500, ones, 50); + Assertions.assertEquals(500, twos, 50); + } + + @Test + void testRandomSubset() { + // 1, 2, 3, and 4 have an equal weight. + RandomizedSet randomizedSet = new RandomizedSet<>(Arrays.asList(1, 2, 3, 4)); + Set set = randomizedSet.getRandomSubset(2); + Assertions.assertEquals(2, set.size()); + Assertions.assertTrue(Arrays.asList(1, 2, 3, 4).containsAll(set)); + Assertions.assertThrows(IllegalArgumentException.class, () -> randomizedSet.getRandomSubset(5), "A random Subset may not be larger than the original Set! (5 > 4"); + Set sameSizeSet = randomizedSet.getRandomSubset(4); + Assertions.assertEquals(4, sameSizeSet.size()); + CollectionTestUtils.assertHaveEqualElements(new HashSet<>(Arrays.asList(1, 2, 3, 4)), sameSizeSet); + CollectionTestUtils.assertHaveEqualElements(sameSizeSet, Arrays.asList(randomizedSet.toArray(Integer[]::new))); + } +} diff --git a/dough-data/src/test/java/io/github/bakedlibs/dough/collections/TestWeightedNode.java b/dough-data/src/test/java/io/github/bakedlibs/dough/collections/TestWeightedNode.java new file mode 100644 index 00000000..85d56a8f --- /dev/null +++ b/dough-data/src/test/java/io/github/bakedlibs/dough/collections/TestWeightedNode.java @@ -0,0 +1,38 @@ +package io.github.bakedlibs.dough.collections; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +class TestWeightedNode { + + @Test + void testGettersAndSetters() { + float weight1 = 1.0f; + float weight2 = 2.0f; + Object object1 = new Object(); + Object object2 = new Object(); + WeightedNode node = new WeightedNode<>(weight1, object1); + Assertions.assertSame(object1, node.getObject()); + Assertions.assertEquals(weight1, node.getWeight()); + node.setWeight(weight2); + node.setObject(object2); + Assertions.assertSame(object2, node.getObject()); + Assertions.assertEquals(weight2, node.getWeight()); + Assertions.assertThrows(IllegalArgumentException.class, () -> node.setObject(null), "Object cannot be null"); + } + + @Test + void testEqualityChecking() { + float weight = 1.0f; + Object object = new Object(); + WeightedNode node = new WeightedNode<>(weight, object); + WeightedNode similarNode = new WeightedNode<>(weight, object); + Assertions.assertNotSame(node, similarNode); + Assertions.assertEquals(node, similarNode); + Assertions.assertEquals(node.hashCode(), similarNode.hashCode()); + WeightedNode differentNode = new WeightedNode<>(weight, weight); + Assertions.assertNotEquals(node, differentNode); + } + + +} diff --git a/dough-data/src/test/java/io/github/bakedlibs/dough/data/TestTriStateOptional.java b/dough-data/src/test/java/io/github/bakedlibs/dough/data/TestTriStateOptional.java new file mode 100644 index 00000000..c21eb425 --- /dev/null +++ b/dough-data/src/test/java/io/github/bakedlibs/dough/data/TestTriStateOptional.java @@ -0,0 +1,83 @@ +package io.github.bakedlibs.dough.data; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +class TestTriStateOptional { + + @Test + void testEmpty() { + TriStateOptional empty = TriStateOptional.empty(); + TriStateOptional nullObject = TriStateOptional.ofNullable(null); + Assertions.assertTrue(nullObject.isEmpty()); + + Assertions.assertTrue(empty.isEmpty()); + Assertions.assertTrue(empty.isComputed()); + Assertions.assertFalse(empty.isPresent()); + Assertions.assertThrows(IllegalAccessError.class, empty::get, "This Optional has no value! Check .isPresent() first!"); + Assertions.assertNull(empty.getOrElse(null)); + Assertions.assertFalse(empty.getAsOptional().isPresent()); + } + + @Test + void testComputed() { + TriStateOptional computed = TriStateOptional.createNew(); + Assertions.assertFalse(computed.isEmpty()); + Assertions.assertFalse(computed.isComputed()); + Assertions.assertFalse(computed.isPresent()); + Assertions.assertThrows(IllegalAccessError.class, computed::get, "This Optional has no value! Check .isPresent() first!"); + Assertions.assertThrows(IllegalStateException.class, () -> computed.getOrElse(null), "This Optional has not yet been computed!"); + Assertions.assertThrows(IllegalStateException.class, computed::getAsOptional, "This Optional has not yet been computed!"); + } + + @Test + void testPresent() { + Object object = new Object(); + TriStateOptional present = TriStateOptional.of(object); + Assertions.assertFalse(present.isEmpty()); + Assertions.assertTrue(present.isComputed()); + Assertions.assertSame(object, present.get()); + Assertions.assertSame(object, present.getOrElse(null)); + Assertions.assertTrue(present.getAsOptional().isPresent()); + Assertions.assertSame(object, present.getAsOptional().orElse(null)); + TriStateOptional presentFromNullable = TriStateOptional.ofNullable(object); + Assertions.assertFalse(presentFromNullable.isEmpty()); + Assertions.assertTrue(presentFromNullable.isComputed()); + Assertions.assertSame(object, presentFromNullable.get()); + Assertions.assertSame(object, presentFromNullable.getOrElse(null)); + Assertions.assertTrue(presentFromNullable.getAsOptional().isPresent()); + Assertions.assertSame(object, presentFromNullable.getAsOptional().orElse(null)); + } + + @Test + void testCompute() { + Object computedValue = new Object(); + TriStateOptional computed = TriStateOptional.createNew(); + Assertions.assertFalse(computed.isComputed()); + computed.compute(computedValue); + Assertions.assertTrue(computed.isComputed()); + Assertions.assertEquals(computedValue, computed.get()); + Assertions.assertEquals(computedValue, computed.getOrElse(null)); + Assertions.assertEquals(computedValue, computed.getAsOptional().orElse(null)); + Assertions.assertThrows(IllegalStateException.class, () -> computed.compute((Object) null), "This Optional has already been computed."); + Object otherComputedValue = new Object(); + TriStateOptional empty = TriStateOptional.createNew(); + empty.compute(() -> otherComputedValue); + Assertions.assertEquals(otherComputedValue, empty.get()); + TriStateOptional empty2 = TriStateOptional.createNew(); + empty2.compute((Object) null); + Assertions.assertTrue(empty2.isComputed()); + Assertions.assertTrue(empty2.isEmpty()); + } + + @Test + void testIfPresent() { + TriStateOptional optional = TriStateOptional.of(new Object()); + Assertions.assertThrows(RuntimeException.class, () -> optional.ifPresent(x -> { + throw new RuntimeException(); + })); + TriStateOptional empty = TriStateOptional.empty(); + empty.ifPresent(x -> Assertions.fail("Optional is not present!")); + } + +} diff --git a/dough-data/src/test/java/io/github/bakedlibs/dough/data/persistent/TestPersistentJson.java b/dough-data/src/test/java/io/github/bakedlibs/dough/data/persistent/TestPersistentJson.java new file mode 100644 index 00000000..0a9fe11c --- /dev/null +++ b/dough-data/src/test/java/io/github/bakedlibs/dough/data/persistent/TestPersistentJson.java @@ -0,0 +1,43 @@ +package io.github.bakedlibs.dough.data.persistent; + +import be.seeseemelk.mockbukkit.persistence.PersistentDataContainerMock; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import org.bukkit.NamespacedKey; +import org.bukkit.persistence.PersistentDataContainer; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +class TestPersistentJson { + + @SuppressWarnings("deprecation") + @Test + void testSerialization() { + + JsonArray jsonArray = new JsonArray(); + for (int i = 0; i < 100; i++) { + jsonArray.add(i); + } + JsonObject jsonObject = new JsonObject(); + JsonPrimitive primitiveString = new JsonPrimitive("aString"); + jsonObject.add("string", primitiveString); + PersistentDataContainer pdc = new PersistentDataContainerMock(); + NamespacedKey keyString = new NamespacedKey("dummy", "string"); + NamespacedKey keyArray = new NamespacedKey("dummy", "array"); + pdc.set(keyString, PersistentJsonDataType.JSON_OBJECT, jsonObject); + pdc.set(keyArray, PersistentJsonDataType.JSON_ARRAY, jsonArray); + + Assertions.assertTrue(pdc.has(keyString, PersistentJsonDataType.JSON_OBJECT)); + JsonObject deserialized = pdc.get(keyString, PersistentJsonDataType.JSON_OBJECT); + Assertions.assertNotNull(deserialized); + Assertions.assertEquals(jsonObject, deserialized); + + Assertions.assertTrue(pdc.has(keyArray, PersistentJsonDataType.JSON_ARRAY)); + JsonArray deserializedArray = pdc.get(keyArray, PersistentJsonDataType.JSON_ARRAY); + Assertions.assertNotNull(deserializedArray); + Assertions.assertEquals(jsonArray, deserializedArray); + + } + +} diff --git a/dough-data/src/test/java/io/github/bakedlibs/dough/data/persistent/TestPersistentUUID.java b/dough-data/src/test/java/io/github/bakedlibs/dough/data/persistent/TestPersistentUUID.java new file mode 100644 index 00000000..72898a7d --- /dev/null +++ b/dough-data/src/test/java/io/github/bakedlibs/dough/data/persistent/TestPersistentUUID.java @@ -0,0 +1,40 @@ +package io.github.bakedlibs.dough.data.persistent; + +import be.seeseemelk.mockbukkit.persistence.PersistentDataContainerMock; + +import org.bukkit.NamespacedKey; +import org.bukkit.persistence.PersistentDataContainer; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.UUID; + +class TestPersistentUUID { + + @SuppressWarnings("deprecation") + @Test + void testSerialization() { + UUID uuid = UUID.randomUUID(); + PersistentDataContainer pdc = new PersistentDataContainerMock(); + NamespacedKey key = new NamespacedKey("dummy", "key"); + + pdc.set(key, PersistentUUIDDataType.TYPE, uuid); + Assertions.assertEquals(uuid, pdc.get(key, PersistentUUIDDataType.TYPE)); + + } + + @Test + void testInvalidCases() { + Assertions.assertThrows(IllegalArgumentException.class, () -> PersistentUUIDDataType.fromIntArray(null), "The provided integer array cannot be null!"); + int[] invalidData = new int[0]; + Assertions.assertThrows(IllegalArgumentException.class, () -> PersistentUUIDDataType.fromIntArray(invalidData), "The integer array must have a length of 4."); + Assertions.assertThrows(IllegalArgumentException.class, () -> PersistentUUIDDataType.toIntArray(null), "The provided uuid cannot be null!"); + } + + @Test + void testTypeInformation() { + Assertions.assertEquals(UUID.class, PersistentUUIDDataType.TYPE.getComplexType()); + Assertions.assertEquals(int[].class, PersistentUUIDDataType.TYPE.getPrimitiveType()); + } + +} diff --git a/dough-data/src/test/java/io/github/bakedlibs/dough/data/persistent/TestPersistentYAML.java b/dough-data/src/test/java/io/github/bakedlibs/dough/data/persistent/TestPersistentYAML.java new file mode 100644 index 00000000..b36e905f --- /dev/null +++ b/dough-data/src/test/java/io/github/bakedlibs/dough/data/persistent/TestPersistentYAML.java @@ -0,0 +1,33 @@ +package io.github.bakedlibs.dough.data.persistent; + +import be.seeseemelk.mockbukkit.persistence.PersistentDataContainerMock; +import org.bukkit.NamespacedKey; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.persistence.PersistentDataContainer; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +class TestPersistentYAML { + + @Test + @SuppressWarnings("deprecation") + void testSerialization() { + FileConfiguration configuration = new YamlConfiguration(); + configuration.set("a", "b"); + PersistentDataContainer pdc = new PersistentDataContainerMock(); + NamespacedKey key = new NamespacedKey("dummy", "key"); + pdc.set(key, PersistentYAMLDataType.CONFIG, configuration); + Assertions.assertTrue(pdc.has(key, PersistentYAMLDataType.CONFIG)); + FileConfiguration deserialized = pdc.get(key, PersistentYAMLDataType.CONFIG); + Assertions.assertNotNull(deserialized); + Assertions.assertEquals("b", deserialized.get("a")); + } + + @Test + void testTypeInformation() { + Assertions.assertEquals(FileConfiguration.class, PersistentYAMLDataType.CONFIG.getComplexType()); + Assertions.assertEquals(String.class, PersistentYAMLDataType.CONFIG.getPrimitiveType()); + } + +}