154 lines
6.8 KiB
Java
154 lines
6.8 KiB
Java
package com.projectsacrifice.game;
|
|
|
|
import static org.junit.Assert.assertEquals;
|
|
import static org.junit.Assert.assertFalse;
|
|
import static org.junit.Assert.assertTrue;
|
|
|
|
import java.util.Collections;
|
|
import java.util.Arrays;
|
|
|
|
import org.junit.Test;
|
|
|
|
public final class PuzzleSystemTest {
|
|
@Test
|
|
public void toggleChannelChangesOnlyOnRisingEdgesAndPublishesEvents() {
|
|
PuzzleSystem system = new PuzzleSystem();
|
|
PuzzleSystem.Input held = PuzzleSystem.Input.toggle("lever-1", "gate", true);
|
|
|
|
system.update(0.016f, Collections.singletonList(held));
|
|
assertTrue(system.signalActive("gate"));
|
|
assertEquals(PuzzleSystem.Event.Kind.SIGNAL_ACTIVATED,
|
|
system.events().get(0).kind());
|
|
assertEquals("gate", system.events().get(0).channelId());
|
|
|
|
system.update(0.016f, Collections.singletonList(held));
|
|
assertTrue(system.signalActive("gate"));
|
|
assertTrue(system.events().isEmpty());
|
|
|
|
system.update(0.016f, Collections.singletonList(
|
|
PuzzleSystem.Input.toggle("lever-1", "gate", false)));
|
|
system.update(0.016f, Collections.singletonList(held));
|
|
assertFalse(system.signalActive("gate"));
|
|
assertEquals(PuzzleSystem.Event.Kind.SIGNAL_DEACTIVATED,
|
|
system.events().get(0).kind());
|
|
}
|
|
|
|
@Test
|
|
public void pressureChannelAggregatesEveryActiveSourceWithoutFlicker() {
|
|
PuzzleSystem system = new PuzzleSystem();
|
|
|
|
system.update(0.016f, Arrays.asList(
|
|
PuzzleSystem.Input.pressure("plate-left", "weight", true),
|
|
PuzzleSystem.Input.pressure("plate-right", "weight", false)));
|
|
assertTrue(system.signalActive("weight"));
|
|
assertEquals(1, system.events().size());
|
|
|
|
system.update(0.016f, Arrays.asList(
|
|
PuzzleSystem.Input.pressure("plate-left", "weight", false),
|
|
PuzzleSystem.Input.pressure("plate-right", "weight", true)));
|
|
assertTrue(system.signalActive("weight"));
|
|
assertTrue(system.events().isEmpty());
|
|
|
|
system.update(0.016f, Arrays.asList(
|
|
PuzzleSystem.Input.pressure("plate-left", "weight", false),
|
|
PuzzleSystem.Input.pressure("plate-right", "weight", false)));
|
|
assertFalse(system.signalActive("weight"));
|
|
assertEquals(PuzzleSystem.Event.Kind.SIGNAL_DEACTIVATED,
|
|
system.events().get(0).kind());
|
|
}
|
|
|
|
@Test
|
|
public void timedChannelStartsOnRisingEdgeExpiresAndCanBeRearmed() {
|
|
PuzzleSystem system = new PuzzleSystem();
|
|
|
|
system.update(0f, Collections.singletonList(
|
|
PuzzleSystem.Input.timed("clock-switch", "clock", true, 0.5f)));
|
|
assertTrue(system.signalActive("clock"));
|
|
assertEquals(0.5f, system.remainingSeconds("clock"), 0f);
|
|
|
|
system.update(0.2f, Collections.singletonList(
|
|
PuzzleSystem.Input.timed("clock-switch", "clock", true, 0.5f)));
|
|
assertEquals(0.3f, system.remainingSeconds("clock"), 0.0001f);
|
|
assertTrue(system.events().isEmpty());
|
|
|
|
system.update(0.31f, Collections.singletonList(
|
|
PuzzleSystem.Input.timed("clock-switch", "clock", false, 0.5f)));
|
|
assertFalse(system.signalActive("clock"));
|
|
assertEquals(PuzzleSystem.Event.Kind.SIGNAL_DEACTIVATED,
|
|
system.events().get(0).kind());
|
|
|
|
system.update(0f, Collections.singletonList(
|
|
PuzzleSystem.Input.timed("clock-switch", "clock", true, 0.5f)));
|
|
assertTrue(system.signalActive("clock"));
|
|
assertEquals(0.5f, system.remainingSeconds("clock"), 0f);
|
|
}
|
|
|
|
@Test
|
|
public void andDoorPublishesExplicitOpenAndCloseTransitions() {
|
|
DoorController exit = new DoorController("exit",
|
|
Arrays.asList("weight", "power"));
|
|
PuzzleSystem system = new PuzzleSystem(Collections.singletonList(exit));
|
|
|
|
system.update(0.016f, Arrays.asList(
|
|
PuzzleSystem.Input.pressure("plate", "weight", true),
|
|
PuzzleSystem.Input.relay("conductor", "power", false)));
|
|
assertEquals(DoorController.State.CLOSED, exit.state());
|
|
|
|
system.update(0.016f, Arrays.asList(
|
|
PuzzleSystem.Input.pressure("plate", "weight", true),
|
|
PuzzleSystem.Input.relay("conductor", "power", true)));
|
|
assertEquals(DoorController.State.OPEN, exit.state());
|
|
assertTrue(hasEvent(system, PuzzleSystem.Event.Kind.DOOR_OPENED, "exit"));
|
|
|
|
system.update(0.016f, Arrays.asList(
|
|
PuzzleSystem.Input.pressure("plate", "weight", false),
|
|
PuzzleSystem.Input.relay("conductor", "power", true)));
|
|
assertEquals(DoorController.State.CLOSED, exit.state());
|
|
assertTrue(hasEvent(system, PuzzleSystem.Event.Kind.DOOR_CLOSED, "exit"));
|
|
}
|
|
|
|
@Test
|
|
public void resetAndRestoreOwnAnImmutablePuzzleStateSnapshot() {
|
|
DoorController exit = new DoorController("exit", Arrays.asList("gate", "clock"));
|
|
PuzzleSystem source = new PuzzleSystem(Collections.singletonList(exit));
|
|
source.update(0f, Arrays.asList(
|
|
PuzzleSystem.Input.toggle("lever", "gate", true),
|
|
PuzzleSystem.Input.timed("timer", "clock", true, 2f)));
|
|
PuzzleSystem.State saved = source.snapshot();
|
|
|
|
source.reset();
|
|
assertFalse(source.signalActive("gate"));
|
|
assertFalse(source.signalActive("clock"));
|
|
assertEquals(DoorController.State.CLOSED, exit.state());
|
|
|
|
DoorController restoredDoor = new DoorController("exit",
|
|
Arrays.asList("gate", "clock"));
|
|
PuzzleSystem restored = new PuzzleSystem(Collections.singletonList(restoredDoor));
|
|
restored.restore(saved, Collections.singletonMap("lever", true));
|
|
|
|
assertTrue(restored.signalActive("gate"));
|
|
assertEquals(2f, restored.remainingSeconds("clock"), 0f);
|
|
assertEquals(DoorController.State.OPEN, restoredDoor.state());
|
|
restored.update(0f, Collections.singletonList(
|
|
PuzzleSystem.Input.toggle("lever", "gate", true)));
|
|
assertTrue("Held restored contact must not toggle again",
|
|
restored.signalActive("gate"));
|
|
assertEquals(Boolean.TRUE, saved.toggleSignals().get("gate"));
|
|
assertEquals(2f, saved.timedSignals().get("clock"), 0f);
|
|
try {
|
|
saved.toggleSignals().put("other", true);
|
|
throw new AssertionError("Puzzle state maps must be immutable");
|
|
} catch (UnsupportedOperationException expected) {
|
|
// Contract proven.
|
|
}
|
|
}
|
|
|
|
private static boolean hasEvent(PuzzleSystem system, PuzzleSystem.Event.Kind kind,
|
|
String targetId) {
|
|
for (PuzzleSystem.Event event : system.events()) {
|
|
if (event.kind() == kind && targetId.equals(event.targetId())) return true;
|
|
}
|
|
return false;
|
|
}
|
|
}
|