aboutsummaryrefslogtreecommitdiff
path: root/core/src/test/java/coffee/liz/abstractionengine
diff options
context:
space:
mode:
authorElizabeth Hunt <me@liz.coffee>2026-01-23 20:22:30 -0800
committerElizabeth Hunt <me@liz.coffee>2026-01-23 20:22:30 -0800
commit52864cb701e59a1d847fd5586245519eb5e3b3bc (patch)
tree1d3df85b939e2c50ebf154ab4fcac6f02ad087c2 /core/src/test/java/coffee/liz/abstractionengine
downloadthe-abstraction-engine-v2-52864cb701e59a1d847fd5586245519eb5e3b3bc.tar.gz
the-abstraction-engine-v2-52864cb701e59a1d847fd5586245519eb5e3b3bc.zip
Move code over
Diffstat (limited to 'core/src/test/java/coffee/liz/abstractionengine')
-rw-r--r--core/src/test/java/coffee/liz/abstractionengine/grid/system/GridCollisionPropagatationSystemTest.java188
-rw-r--r--core/src/test/java/coffee/liz/abstractionengine/grid/system/GridIndexSystemTest.java70
-rw-r--r--core/src/test/java/coffee/liz/abstractionengine/grid/system/GridMovementSystemTest.java48
-rw-r--r--core/src/test/java/coffee/liz/abstractionengine/grid/system/GridPhysicsSystemTest.java46
4 files changed, 352 insertions, 0 deletions
diff --git a/core/src/test/java/coffee/liz/abstractionengine/grid/system/GridCollisionPropagatationSystemTest.java b/core/src/test/java/coffee/liz/abstractionengine/grid/system/GridCollisionPropagatationSystemTest.java
new file mode 100644
index 0000000..3743f3e
--- /dev/null
+++ b/core/src/test/java/coffee/liz/abstractionengine/grid/system/GridCollisionPropagatationSystemTest.java
@@ -0,0 +1,188 @@
+package coffee.liz.abstractionengine.grid.system;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import coffee.liz.abstractionengine.grid.component.GridCollidable;
+import coffee.liz.abstractionengine.grid.component.GridCollidable.CollisionBehavior;
+import coffee.liz.abstractionengine.grid.component.GridCollidable.CollisionBehavior.CollisionBehaviorType;
+import coffee.liz.abstractionengine.grid.component.GridInputState;
+import coffee.liz.abstractionengine.grid.component.GridMomentum;
+import coffee.liz.abstractionengine.grid.component.GridPosition;
+import coffee.liz.ecs.math.Vec2i;
+import coffee.liz.ecs.model.Entity;
+import coffee.liz.ecs.model.World;
+
+import lombok.Getter;
+import org.junit.jupiter.api.Test;
+
+import java.time.Duration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+final class GridCollisionPropagatationSystemTest {
+ private static final Duration FRAME = Duration.ZERO;
+ private static final GridCollidable WALL_COLLIDABLE = (me, them) -> CollisionBehavior.builder()
+ .collisionBehaviorType(CollisionBehaviorType.WALL).priority(10).build();
+ private static final GridCollidable PROPAGATE_COLLIDABLE = (me, them) -> CollisionBehavior.builder()
+ .collisionBehaviorType(CollisionBehaviorType.PROPAGATE).priority(0).build();
+
+ @Getter
+ private static class SwallowCollidable implements GridCollidable {
+ private final Set<Entity> swallowed = new HashSet<>();
+ @Override
+ public <T> void onSwallow(final Entity them, final World<T> world) {
+ swallowed.add(them);
+ }
+
+ @Override
+ public CollisionBehavior getCollisionBehaviorBetween(final Entity me, final Entity them) {
+ return CollisionBehavior.builder().collisionBehaviorType(CollisionBehaviorType.SWALLOW).priority(0).build();
+ }
+ }
+
+ @Test
+ public void testPrioritization() {
+ final World<GridInputState> world = mockWorld();
+ final GridIndexSystem indexSystem = mock(GridIndexSystem.class);
+ when(indexSystem.inBounds(any())).thenReturn(true);
+ when(world.getSystem(GridIndexSystem.class)).thenReturn(indexSystem);
+
+ final Entity pusher = Entity.builder().id(1).build().add(PROPAGATE_COLLIDABLE).add(new GridMomentum(Vec2i.EAST))
+ .add(new GridPosition(Vec2i.ZERO));
+ final Entity toPropagate = Entity.builder().id(2).build().add(PROPAGATE_COLLIDABLE)
+ .add(new GridPosition(Vec2i.EAST));
+ final Entity wall = Entity.builder().id(3).build().add(WALL_COLLIDABLE).add(new GridPosition(Vec2i.EAST));
+
+ // Propagation takes priority because priority(0) is lower
+ when(world.query(Set.of(GridMomentum.class, GridPosition.class, GridCollidable.class)))
+ .thenReturn(Set.of(pusher));
+
+ when(indexSystem.entitiesAt(Vec2i.ZERO)).thenReturn(List.of(pusher));
+ when(indexSystem.entitiesAt(Vec2i.EAST)).thenReturn(List.of(toPropagate, wall));
+
+ final GridCollisionPropagatationSystem system = new GridCollisionPropagatationSystem();
+ system.update(world, mock(GridInputState.class), FRAME);
+
+ assertEquals(Vec2i.EAST, pusher.get(GridMomentum.class).getVelocity());
+ assertEquals(Vec2i.EAST, toPropagate.get(GridMomentum.class).getVelocity());
+ }
+
+ @Test
+ public void testWallCollisionHaltsRayMomentum() {
+ final World<GridInputState> world = mockWorld();
+ final GridIndexSystem indexSystem = mock(GridIndexSystem.class);
+ when(indexSystem.inBounds(any())).thenReturn(true);
+ when(world.getSystem(GridIndexSystem.class)).thenReturn(indexSystem);
+
+ final Entity pusher = Entity.builder().id(1).build().add(PROPAGATE_COLLIDABLE).add(new GridMomentum(Vec2i.EAST))
+ .add(new GridPosition(Vec2i.ZERO));
+ final Entity toPropagate = Entity.builder().id(2).build().add(PROPAGATE_COLLIDABLE)
+ .add(new GridMomentum(Vec2i.EAST)).add(new GridPosition(Vec2i.EAST));
+ final Entity wall = Entity.builder().id(3).build().add(WALL_COLLIDABLE)
+ .add(new GridPosition(Vec2i.EAST.scale(2, 0)));
+
+ when(world.query(Set.of(GridMomentum.class, GridPosition.class, GridCollidable.class)))
+ .thenReturn(Set.of(pusher, toPropagate));
+
+ when(indexSystem.entitiesAt(Vec2i.ZERO)).thenReturn(List.of(pusher));
+ when(indexSystem.entitiesAt(Vec2i.EAST)).thenReturn(List.of(toPropagate));
+ when(indexSystem.entitiesAt(Vec2i.EAST.scale(2, 0))).thenReturn(List.of(wall));
+
+ final GridCollisionPropagatationSystem system = new GridCollisionPropagatationSystem();
+ system.update(world, GridInputState.builder().build(), FRAME);
+
+ assertEquals(Vec2i.ZERO, pusher.get(GridMomentum.class).getVelocity());
+ assertEquals(Vec2i.ZERO, toPropagate.get(GridMomentum.class).getVelocity());
+ }
+
+ @Test
+ public void testGoingOutOfBoundsHaltsMomentum() {
+ final World<GridInputState> world = mockWorld();
+ final GridIndexSystem indexSystem = mock(GridIndexSystem.class);
+
+ when(indexSystem.inBounds(any())).thenReturn(false);
+ when(world.getSystem(GridIndexSystem.class)).thenReturn(indexSystem);
+
+ final Entity pusher = Entity.builder().id(1).build().add(PROPAGATE_COLLIDABLE).add(new GridMomentum(Vec2i.EAST))
+ .add(new GridPosition(Vec2i.ZERO));
+
+ when(world.query(Set.of(GridMomentum.class, GridPosition.class, GridCollidable.class)))
+ .thenReturn(Set.of(pusher));
+
+ when(indexSystem.entitiesAt(Vec2i.ZERO)).thenReturn(List.of(pusher));
+
+ final GridCollisionPropagatationSystem system = new GridCollisionPropagatationSystem();
+ system.update(world, GridInputState.builder().build(), FRAME);
+
+ assertEquals(Vec2i.ZERO, pusher.get(GridMomentum.class).getVelocity());
+ }
+
+ @Test
+ public void testZeroVelocity() {
+ final World<GridInputState> world = mockWorld();
+ final GridIndexSystem indexSystem = mock(GridIndexSystem.class);
+
+ when(indexSystem.inBounds(any())).thenReturn(true);
+ when(world.getSystem(GridIndexSystem.class)).thenReturn(indexSystem);
+
+ final Entity pusher = Entity.builder().id(1).build().add(PROPAGATE_COLLIDABLE).add(new GridMomentum(Vec2i.ZERO))
+ .add(new GridPosition(Vec2i.ZERO));
+
+ when(world.query(Set.of(GridMomentum.class, GridPosition.class, GridCollidable.class)))
+ .thenReturn(Set.of(pusher));
+
+ when(indexSystem.entitiesAt(Vec2i.ZERO)).thenReturn(List.of(pusher));
+
+ final GridCollisionPropagatationSystem system = new GridCollisionPropagatationSystem();
+ system.update(world, GridInputState.builder().build(), FRAME);
+
+ assertEquals(Vec2i.ZERO, pusher.get(GridMomentum.class).getVelocity());
+ }
+
+ @Test
+ public void testSwallowInteraction() {
+ final World<GridInputState> world = mockWorld();
+ final GridIndexSystem indexSystem = mock(GridIndexSystem.class);
+
+ when(indexSystem.inBounds(any())).thenReturn(true);
+ when(world.getSystem(GridIndexSystem.class)).thenReturn(indexSystem);
+
+ final SwallowCollidable swallowCollidable = new SwallowCollidable();
+
+ final Entity pusher = Entity.builder().id(1).build().add(PROPAGATE_COLLIDABLE).add(new GridMomentum(Vec2i.EAST))
+ .add(new GridPosition(Vec2i.ZERO));
+
+ final Entity swallower = Entity.builder().id(2).build().add(swallowCollidable)
+ .add(new GridPosition(Vec2i.EAST));
+
+ when(world.query(Set.of(GridMomentum.class, GridPosition.class, GridCollidable.class)))
+ .thenReturn(Set.of(pusher));
+
+ when(indexSystem.entitiesAt(Vec2i.ZERO)).thenReturn(List.of(pusher));
+ when(indexSystem.entitiesAt(Vec2i.EAST)).thenReturn(List.of(swallower));
+
+ final GridCollisionPropagatationSystem system = new GridCollisionPropagatationSystem();
+ system.update(world, GridInputState.builder().build(), FRAME);
+
+ assertEquals(Vec2i.EAST, pusher.get(GridMomentum.class).getVelocity());
+ assertFalse(swallower.has(GridMomentum.class));
+
+ assertEquals(swallowCollidable.getSwallowed(), Set.of(pusher));
+ }
+
+ @Test
+ public void testDependencies() {
+ assertEquals(Set.of(GridMovementSystem.class, GridIndexSystem.class),
+ new GridCollisionPropagatationSystem().getDependencies());
+ }
+
+ @SuppressWarnings("unchecked")
+ private static World<GridInputState> mockWorld() {
+ return (World<GridInputState>) mock(World.class);
+ }
+}
diff --git a/core/src/test/java/coffee/liz/abstractionengine/grid/system/GridIndexSystemTest.java b/core/src/test/java/coffee/liz/abstractionengine/grid/system/GridIndexSystemTest.java
new file mode 100644
index 0000000..d9afde5
--- /dev/null
+++ b/core/src/test/java/coffee/liz/abstractionengine/grid/system/GridIndexSystemTest.java
@@ -0,0 +1,70 @@
+package coffee.liz.abstractionengine.grid.system;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.when;
+
+import coffee.liz.abstractionengine.grid.component.GridInputState;
+import coffee.liz.abstractionengine.grid.component.GridPosition;
+import coffee.liz.ecs.math.Vec2i;
+import coffee.liz.ecs.model.Entity;
+import coffee.liz.ecs.model.World;
+
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+import java.time.Duration;
+import java.util.Set;
+
+class GridIndexSystemTest {
+ @Test
+ public void testUpdateIndexesEntitiesIntoGridSlots() {
+ final GridIndexSystem system = new GridIndexSystem(new Vec2i(4, 4));
+ final World<GridInputState> world = mockWorld();
+ final Entity alpha = Entity.builder().id(11).build();
+ alpha.add(new GridPosition(new Vec2i(1, 2)));
+ final Entity beta = Entity.builder().id(12).build();
+ beta.add(new GridPosition(new Vec2i(0, 0)));
+ when(world.query(Set.of(GridPosition.class))).thenReturn(Set.of(alpha, beta));
+
+ system.update(world, GridInputState.builder().movement(Vec2i.NORTH).build(), Duration.ZERO);
+
+ assertTrue(system.entitiesAt(new Vec2i(1, 2)).contains(alpha));
+ assertTrue(system.entitiesAt(new Vec2i(0, 0)).contains(beta));
+ assertTrue(system.entitiesAt(new Vec2i(3, 3)).isEmpty());
+ }
+
+ @Test
+ public void testUpdateClearsPreviousIndexesBeforeRebuilding() {
+ final GridIndexSystem system = new GridIndexSystem(new Vec2i(2, 2));
+ final World<GridInputState> world = mockWorld();
+ final Entity moving = Entity.builder().id(77).build();
+ moving.add(new GridPosition(Vec2i.ZERO));
+ when(world.query(Set.of(GridPosition.class))).thenReturn(Set.of(moving)).thenReturn(Set.of());
+
+ system.update(world, GridInputState.builder().movement(Vec2i.EAST).build(), Duration.ZERO);
+ assertTrue(system.entitiesAt(Vec2i.ZERO).contains(moving));
+
+ system.update(world, GridInputState.builder().movement(Vec2i.NORTH).build(), Duration.ZERO);
+ assertTrue(system.entitiesAt(Vec2i.ZERO).isEmpty());
+ }
+
+ @Test
+ public void testEntitiesAtReturnsEmptySetForOutOfBoundsQuery() {
+ final GridIndexSystem system = new GridIndexSystem(new Vec2i(2, 2));
+
+ assertEquals(Set.of(), system.entitiesAt(new Vec2i(-1, 0)));
+ assertEquals(Set.of(), system.entitiesAt(new Vec2i(2, 1)));
+ assertEquals(Set.of(), system.entitiesAt(new Vec2i(1, 2)));
+ }
+
+ @Test
+ public void testDependencies() {
+ assertEquals(Set.of(), new GridIndexSystem(Vec2i.ZERO).getDependencies());
+ }
+
+ @SuppressWarnings("unchecked")
+ private static World<GridInputState> mockWorld() {
+ return (World<GridInputState>) Mockito.mock(World.class);
+ }
+}
diff --git a/core/src/test/java/coffee/liz/abstractionengine/grid/system/GridMovementSystemTest.java b/core/src/test/java/coffee/liz/abstractionengine/grid/system/GridMovementSystemTest.java
new file mode 100644
index 0000000..8bd8ff3
--- /dev/null
+++ b/core/src/test/java/coffee/liz/abstractionengine/grid/system/GridMovementSystemTest.java
@@ -0,0 +1,48 @@
+package coffee.liz.abstractionengine.grid.system;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.Mockito.when;
+
+import coffee.liz.abstractionengine.grid.component.GridControllable;
+import coffee.liz.abstractionengine.grid.component.GridInputState;
+import coffee.liz.abstractionengine.grid.component.GridMomentum;
+import coffee.liz.abstractionengine.grid.component.GridPosition;
+import coffee.liz.ecs.math.Vec2i;
+import coffee.liz.ecs.model.Entity;
+import coffee.liz.ecs.model.World;
+
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+import java.time.Duration;
+import java.util.Set;
+
+final class GridMovementSystemTest {
+ @Test
+ public void testUpdateAssignsMomentumToControllableEntities() {
+ final World<GridInputState> world = mockWorld();
+ final Entity subject = Entity.builder().id(1).build();
+ subject.add(new GridControllable());
+ subject.add(new GridPosition(Vec2i.ZERO));
+ final Set<Entity> controllableEntities = Set.of(subject);
+ when(world.query(Set.of(GridControllable.class, GridPosition.class))).thenReturn(controllableEntities);
+
+ final GridInputState inputState = GridInputState.builder().movement(Vec2i.SOUTH).build();
+ final GridMovementSystem system = new GridMovementSystem();
+
+ system.update(world, inputState, Duration.ofMillis(16));
+
+ final GridMomentum appliedMomentum = subject.get(GridMomentum.class);
+ assertEquals(Vec2i.SOUTH, appliedMomentum.getVelocity());
+ }
+
+ @Test
+ public void testDependencies() {
+ assertEquals(Set.of(), new GridMovementSystem().getDependencies());
+ }
+
+ @SuppressWarnings("unchecked")
+ private static World<GridInputState> mockWorld() {
+ return (World<GridInputState>) Mockito.mock(World.class);
+ }
+}
diff --git a/core/src/test/java/coffee/liz/abstractionengine/grid/system/GridPhysicsSystemTest.java b/core/src/test/java/coffee/liz/abstractionengine/grid/system/GridPhysicsSystemTest.java
new file mode 100644
index 0000000..c3bb01e
--- /dev/null
+++ b/core/src/test/java/coffee/liz/abstractionengine/grid/system/GridPhysicsSystemTest.java
@@ -0,0 +1,46 @@
+package coffee.liz.abstractionengine.grid.system;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.Mockito.when;
+
+import coffee.liz.abstractionengine.grid.component.GridInputState;
+import coffee.liz.abstractionengine.grid.component.GridMomentum;
+import coffee.liz.abstractionengine.grid.component.GridPosition;
+import coffee.liz.ecs.math.Vec2;
+import coffee.liz.ecs.math.Vec2i;
+import coffee.liz.ecs.model.Entity;
+import coffee.liz.ecs.model.World;
+
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+import java.time.Duration;
+import java.util.Set;
+
+final class GridPhysicsSystemTest {
+ @Test
+ public void testUpdateMovesEntitiesByMomentumAndResetsVelocity() {
+ final World<GridInputState> world = mockWorld();
+ final Entity body = Entity.builder().id(3).build();
+ body.add(new GridPosition(Vec2i.ZERO));
+ body.add(new GridMomentum(Vec2i.EAST));
+ when(world.query(Set.of(GridMomentum.class, GridPosition.class))).thenReturn(Set.of(body));
+
+ final GridPhysicsSystem system = new GridPhysicsSystem();
+ system.update(world, GridInputState.builder().movement(Vec2i.NORTH).build(), Duration.ZERO);
+
+ final Vec2<Integer> newPosition = body.get(GridPosition.class).getPosition();
+ assertEquals(Vec2i.EAST, newPosition);
+ assertEquals(Vec2i.ZERO, body.get(GridMomentum.class).getVelocity());
+ }
+
+ @Test
+ public void testDependencies() {
+ assertEquals(Set.of(GridCollisionPropagatationSystem.class), new GridPhysicsSystem().getDependencies());
+ }
+
+ @SuppressWarnings("unchecked")
+ private static World<GridInputState> mockWorld() {
+ return (World<GridInputState>) Mockito.mock(World.class);
+ }
+}