Завершить инженерную проверку этапа 2
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
package com.projectsacrifice.game;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
|
||||
import androidx.test.core.app.ActivityScenario;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public final class GameRestartTest {
|
||||
@Test
|
||||
public void restartClearsBodiesSignalsTimerAndHeldInput() throws Exception {
|
||||
try (ActivityScenario<MainActivity> activity = ActivityScenario.launch(MainActivity.class)) {
|
||||
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
GameView[] view = new GameView[1];
|
||||
activity.onActivity(current -> view[0] = current.gameViewForAutomation());
|
||||
|
||||
instrumentation.runOnMainSync(() -> {
|
||||
view[0].startLevelForAutomation(10);
|
||||
view[0].setAutomationInput(false, true, false);
|
||||
});
|
||||
await(instrumentation, view[0], 4_000L,
|
||||
snapshot -> snapshot.deaths() == 1 && snapshot.corpseCount() == 1);
|
||||
instrumentation.runOnMainSync(
|
||||
() -> view[0].setAutomationInput(false, false, false));
|
||||
await(instrumentation, view[0], 5_000L,
|
||||
GameView.AutomationSnapshot::firstMovingPlatformPowered);
|
||||
|
||||
instrumentation.runOnMainSync(() -> {
|
||||
view[0].setAutomationInput(false, true, true);
|
||||
view[0].restartLevelForAutomation();
|
||||
});
|
||||
GameView.AutomationSnapshot restarted = snapshot(instrumentation, view[0]);
|
||||
|
||||
assertEquals(10, restarted.levelNumber());
|
||||
assertTrue(restarted.playerAlive());
|
||||
assertEquals(0, restarted.deaths());
|
||||
assertEquals(0, restarted.corpseCount());
|
||||
assertFalse(restarted.firstMovingPlatformPowered());
|
||||
assertFalse(restarted.inputActive());
|
||||
assertTrue("Restarted timer must begin near zero: "
|
||||
+ restarted.elapsedMilliseconds(), restarted.elapsedMilliseconds() < 200L);
|
||||
assertTrue("Restarted player must be at the level spawn: x=" + restarted.playerX(),
|
||||
restarted.playerX() >= 125f && restarted.playerX() <= 135f);
|
||||
assertEquals(790f, restarted.firstMovingPlatformY(), 0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
private static GameView.AutomationSnapshot await(
|
||||
Instrumentation instrumentation,
|
||||
GameView view,
|
||||
long timeoutMillis,
|
||||
LevelPlaytestBot.SnapshotCondition condition
|
||||
) throws Exception {
|
||||
long deadline = System.currentTimeMillis() + timeoutMillis;
|
||||
GameView.AutomationSnapshot current = snapshot(instrumentation, view);
|
||||
while (System.currentTimeMillis() < deadline) {
|
||||
current = snapshot(instrumentation, view);
|
||||
if (condition.reached(current)) return current;
|
||||
Thread.sleep(32L);
|
||||
}
|
||||
throw new AssertionError("Restart setup timed out; level=" + current.levelNumber()
|
||||
+ ", x=" + current.playerX() + ", deaths=" + current.deaths()
|
||||
+ ", corpses=" + current.corpseCount());
|
||||
}
|
||||
|
||||
private static GameView.AutomationSnapshot snapshot(
|
||||
Instrumentation instrumentation,
|
||||
GameView view
|
||||
) {
|
||||
GameView.AutomationSnapshot[] value = new GameView.AutomationSnapshot[1];
|
||||
instrumentation.runOnMainSync(() -> value[0] = view.automationSnapshot());
|
||||
return value[0];
|
||||
}
|
||||
}
|
||||
@@ -126,6 +126,63 @@ public final class LateLevelPlaythroughTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sawDeliveredBodyKeepsLevelTenLiftPoweredAfterSettling() {
|
||||
try (ActivityScenario<MainActivity> activity = ActivityScenario.launch(MainActivity.class)) {
|
||||
GameDriver driver = GameDriver.from(activity);
|
||||
driver.startLevel(10);
|
||||
await(driver, 4_000L, false, true, false,
|
||||
snapshot -> snapshot.deaths() == 1 && snapshot.corpseCount() == 1);
|
||||
GameView.AutomationSnapshot engaged = await(driver, 5_000L, false, false, false,
|
||||
GameView.AutomationSnapshot::firstMovingPlatformPowered);
|
||||
driver.setInput(false, false, false);
|
||||
driver.waitForNextDecision(750L);
|
||||
|
||||
GameView.AutomationSnapshot settled = driver.snapshot();
|
||||
assertEquals("The body must settle when it engages the lift plate instead of sliding",
|
||||
engaged.firstCorpseX(), settled.firstCorpseX(), 2f);
|
||||
|
||||
driver.waitForNextDecision(6_000L);
|
||||
|
||||
settled = driver.snapshot();
|
||||
assertTrue("The saw-delivered body slid off the lift plate after settling; "
|
||||
+ "platformY=" + settled.firstMovingPlatformY()
|
||||
+ ", deaths=" + settled.deaths()
|
||||
+ ", corpses=" + settled.corpseCount(),
|
||||
settled.firstMovingPlatformPowered());
|
||||
assertEquals("The stability wait must not consume another volunteer",
|
||||
1, settled.deaths());
|
||||
assertEquals("The delivered body must remain in the level",
|
||||
1, settled.corpseCount());
|
||||
}
|
||||
}
|
||||
|
||||
private static GameView.AutomationSnapshot await(
|
||||
GameDriver driver,
|
||||
long timeoutMillis,
|
||||
boolean moveLeft,
|
||||
boolean moveRight,
|
||||
boolean jump,
|
||||
LevelPlaytestBot.SnapshotCondition condition
|
||||
) {
|
||||
long deadline = System.currentTimeMillis() + timeoutMillis;
|
||||
GameView.AutomationSnapshot snapshot = driver.snapshot();
|
||||
while (System.currentTimeMillis() < deadline) {
|
||||
snapshot = driver.snapshot();
|
||||
if (condition.reached(snapshot)) {
|
||||
driver.setInput(false, false, false);
|
||||
return snapshot;
|
||||
}
|
||||
driver.setInput(moveLeft, moveRight, jump);
|
||||
driver.waitForNextDecision(32L);
|
||||
}
|
||||
throw new AssertionError("Timed out waiting for level 10 lift body; x="
|
||||
+ snapshot.playerX() + ", y=" + snapshot.playerY()
|
||||
+ ", deaths=" + snapshot.deaths()
|
||||
+ ", corpses=" + snapshot.corpseCount()
|
||||
+ ", platformY=" + snapshot.firstMovingPlatformY());
|
||||
}
|
||||
|
||||
private static final class GameDriver implements LevelPlaytestBot.Driver {
|
||||
private final Instrumentation instrumentation;
|
||||
private final GameView gameView;
|
||||
|
||||
@@ -156,10 +156,27 @@ final class LateLevelScenarios {
|
||||
.step("Clear the lift body again", 2_000L,
|
||||
LevelPlaytestBot.Input.rightJump(),
|
||||
snapshot -> snapshot.playerAlive() && snapshot.playerX() >= 860f)
|
||||
.step("Prepare the frozen-block jump", 2_000L,
|
||||
.step("Release after the lift-body jump", 500L,
|
||||
LevelPlaytestBot.Input.none(),
|
||||
snapshot -> snapshot.playerAlive() && snapshot.playerY() >= 720f)
|
||||
.step("Jump over the frozen block", 2_500L,
|
||||
snapshot -> !snapshot.inputActive())
|
||||
.step("Land after the lift-body jump", 1_500L,
|
||||
LevelPlaytestBot.Input.none(),
|
||||
snapshot -> snapshot.playerAlive() && snapshot.playerOnGround())
|
||||
.step("Back away from the freezer", 1_000L,
|
||||
LevelPlaytestBot.Input.left(),
|
||||
snapshot -> snapshot.playerAlive()
|
||||
&& snapshot.playerX() <= 960f)
|
||||
.step("Jump onto the frozen block", 2_000L,
|
||||
LevelPlaytestBot.Input.rightJump(),
|
||||
snapshot -> snapshot.playerAlive()
|
||||
&& snapshot.playerX() >= 1_040f
|
||||
&& snapshot.playerY() <= 700f)
|
||||
.step("Settle on the frozen block", 1_500L,
|
||||
LevelPlaytestBot.Input.none(),
|
||||
snapshot -> snapshot.playerAlive()
|
||||
&& snapshot.playerOnGround()
|
||||
&& snapshot.playerY() <= 690f)
|
||||
.step("Jump from the frozen block", 2_000L,
|
||||
LevelPlaytestBot.Input.rightJump(),
|
||||
snapshot -> snapshot.playerAlive() && snapshot.playerX() >= 1_240f)
|
||||
.step("Power the final relay", 3_000L, LevelPlaytestBot.Input.right(),
|
||||
@@ -186,12 +203,34 @@ final class LateLevelScenarios {
|
||||
.step("Clear the retained lift body", 2_000L,
|
||||
LevelPlaytestBot.Input.rightJump(),
|
||||
snapshot -> snapshot.playerAlive() && snapshot.playerX() >= 860f)
|
||||
.step("Prepare the final frozen-block jump", 2_000L,
|
||||
.step("Release after the retained-body jump", 500L,
|
||||
LevelPlaytestBot.Input.none(),
|
||||
snapshot -> snapshot.playerAlive() && snapshot.playerY() >= 720f)
|
||||
.step("Clear the frozen block", 2_500L,
|
||||
snapshot -> !snapshot.inputActive())
|
||||
.step("Land after the retained-body jump", 1_500L,
|
||||
LevelPlaytestBot.Input.none(),
|
||||
snapshot -> snapshot.playerAlive() && snapshot.playerOnGround())
|
||||
.step("Back away from the retained freezer", 1_000L,
|
||||
LevelPlaytestBot.Input.left(),
|
||||
snapshot -> snapshot.playerAlive()
|
||||
&& snapshot.playerX() <= 960f)
|
||||
.step("Jump onto the retained frozen block", 2_000L,
|
||||
LevelPlaytestBot.Input.rightJump(),
|
||||
snapshot -> snapshot.playerAlive()
|
||||
&& snapshot.playerX() >= 1_040f
|
||||
&& snapshot.playerY() <= 700f)
|
||||
.step("Settle on the retained frozen block", 1_500L,
|
||||
LevelPlaytestBot.Input.none(),
|
||||
snapshot -> snapshot.playerAlive()
|
||||
&& snapshot.playerOnGround()
|
||||
&& snapshot.playerY() <= 690f)
|
||||
.step("Jump from the retained frozen block", 2_000L,
|
||||
LevelPlaytestBot.Input.rightJump(),
|
||||
snapshot -> snapshot.playerAlive() && snapshot.playerX() >= 1_240f)
|
||||
.step("Land before the powered relay", 1_500L,
|
||||
LevelPlaytestBot.Input.none(),
|
||||
snapshot -> snapshot.playerAlive()
|
||||
&& snapshot.playerOnGround()
|
||||
&& snapshot.playerY() >= 779f)
|
||||
.step("Approach the powered relay", 2_500L,
|
||||
LevelPlaytestBot.Input.right(),
|
||||
snapshot -> snapshot.playerX() >= 1_320f)
|
||||
@@ -201,15 +240,23 @@ final class LateLevelScenarios {
|
||||
.step("Clear the powered relay", 2_000L,
|
||||
LevelPlaytestBot.Input.right(),
|
||||
snapshot -> snapshot.playerAlive() && snapshot.playerX() >= 1_650f)
|
||||
.step("Wait for the lift at floor height", 6_000L,
|
||||
.step("Observe the lift above the launch floor", 6_000L,
|
||||
LevelPlaytestBot.Input.none(),
|
||||
snapshot -> snapshot.playerAlive()
|
||||
&& snapshot.playerY() >= 770f
|
||||
&& !Float.isNaN(snapshot.firstMovingPlatformY())
|
||||
&& snapshot.firstMovingPlatformY() >= 780f)
|
||||
&& snapshot.firstMovingPlatformY() <= 650f)
|
||||
.step("Wait for the lift at floor height", 9_000L,
|
||||
LevelPlaytestBot.Input.none(),
|
||||
snapshot -> snapshot.playerAlive()
|
||||
&& (snapshot.playerOnMovingPlatform()
|
||||
|| (snapshot.playerY() >= 770f
|
||||
&& !Float.isNaN(snapshot.firstMovingPlatformY())
|
||||
&& snapshot.firstMovingPlatformY() >= 780f)))
|
||||
.step("Take off toward the moving lift", 1_000L,
|
||||
LevelPlaytestBot.Input.rightJump(),
|
||||
snapshot -> snapshot.playerAlive() && snapshot.playerY() <= 670f)
|
||||
snapshot -> snapshot.playerAlive()
|
||||
&& (snapshot.playerOnMovingPlatform()
|
||||
|| snapshot.playerY() <= 670f))
|
||||
.step("Board the moving lift", 2_000L,
|
||||
LevelPlaytestBot.Input.right(),
|
||||
GameView.AutomationSnapshot::playerOnMovingPlatform)
|
||||
@@ -221,7 +268,7 @@ final class LateLevelScenarios {
|
||||
LevelPlaytestBot.Input.right(),
|
||||
snapshot -> snapshot.playerOnMovingPlatform()
|
||||
&& snapshot.playerX() >= 1_920f)
|
||||
.step("Ride the lift to the upper door", 5_000L,
|
||||
.step("Ride the lift to the upper door", 7_000L,
|
||||
LevelPlaytestBot.Input.none(),
|
||||
snapshot -> snapshot.playerY() <= 310f)
|
||||
.step("Move to the raised lift edge", 2_000L,
|
||||
@@ -236,4 +283,5 @@ final class LateLevelScenarios {
|
||||
GameView.AutomationSnapshot::completed)
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -79,7 +79,8 @@ final class LevelEightScenario {
|
||||
|
||||
snapshot = await(driver, deadline, "Wait for the moving platform",
|
||||
LevelPlaytestBot.Input.none(),
|
||||
current -> current.elapsedMilliseconds() >= timerStartedAt + 2_250L);
|
||||
current -> current.elapsedMilliseconds() >= timerStartedAt + 2_250L
|
||||
&& current.firstMovingPlatformX() <= 1_050f);
|
||||
if (failed(snapshot, deadline, driver)) return snapshot;
|
||||
|
||||
driver.setInput(false, true, true);
|
||||
@@ -87,7 +88,7 @@ final class LevelEightScenario {
|
||||
driver.setInput(false, true, false);
|
||||
snapshot = await(driver, deadline, "Land on the moving platform",
|
||||
LevelPlaytestBot.Input.right(),
|
||||
current -> current.elapsedMilliseconds() >= timerStartedAt + 3_200L);
|
||||
GameView.AutomationSnapshot::playerOnMovingPlatform);
|
||||
if (failed(snapshot, deadline, driver)) return snapshot;
|
||||
|
||||
driver.setInput(false, true, true);
|
||||
@@ -107,18 +108,15 @@ final class LevelEightScenario {
|
||||
private GameView.AutomationSnapshot awaitFarFloorLandingOnOriginalTimer(
|
||||
LevelPlaytestBot.Driver driver, long deadline
|
||||
) {
|
||||
boolean moveLeft = true;
|
||||
GameView.AutomationSnapshot snapshot = driver.snapshot();
|
||||
while (driver.currentTimeMillis() < deadline && snapshot.playerAlive()
|
||||
&& !(snapshot.playerX() >= 1_510f && snapshot.playerX() < 1_580f
|
||||
&& snapshot.playerY() >= 779f && snapshot.allDoorsOpen())) {
|
||||
driver.setInput(moveLeft, !moveLeft, false);
|
||||
moveLeft = !moveLeft;
|
||||
driver.waitForNextDecision(DECISION_MILLIS);
|
||||
snapshot = driver.snapshot();
|
||||
}
|
||||
driver.setInput(false, false, false);
|
||||
return snapshot;
|
||||
GameView.AutomationSnapshot snapshot = await(driver, deadline,
|
||||
"Land on the far floor", LevelPlaytestBot.Input.right(),
|
||||
current -> current.playerX() >= 1_510f
|
||||
&& current.playerY() >= 779f && current.allDoorsOpen());
|
||||
if (failed(snapshot, deadline, driver)) return snapshot;
|
||||
return await(driver, deadline, "Stabilize on the far floor",
|
||||
LevelPlaytestBot.Input.left(),
|
||||
current -> current.playerX() < 1_580f
|
||||
&& current.playerY() >= 779f && current.allDoorsOpen());
|
||||
}
|
||||
|
||||
private Result finishFromFarSide(LevelPlaytestBot.Driver driver, long deadline,
|
||||
|
||||
Reference in New Issue
Block a user