package com.projectsacrifice.game; import static org.junit.Assert.assertEquals; 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 FoundationsPlaythroughTest { @Test public void firstReturnCompletesDeathlessThreeTimes() { runThree(FoundationsScenarios.levelNineteen(), 0, 0); } @Test public void coveredPathUsesExactlyTwoBodiesThreeTimes() { runThree(FoundationsScenarios.levelTwenty(), 2, 2); } @Test public void heldOpenUsesExactlyOnePlateBodyThreeTimes() { runThree(FoundationsScenarios.levelTwentyOne(), 1, 1); } @Test public void clockworkStepCompletesDeathlessThreeTimes() { runThree(FoundationsScenarios.levelTwentyTwo(), 0, 0); } private static void runThree(LevelPlaytestBot.Scenario scenario, int expectedDeaths, int expectedCorpses) { try (ActivityScenario activity = ActivityScenario.launch(MainActivity.class)) { Driver driver = Driver.from(activity); for (int run = 1; run <= 3; run++) { LevelPlaytestBot.Result result = new LevelPlaytestBot().run(driver, scenario, 30_000L); assertTrue("run=" + run + "; " + result.diagnostic(), result.completed()); assertEquals("run=" + run, expectedDeaths, result.deaths()); assertEquals("run=" + run, expectedCorpses, result.corpseCount()); assertTrue("run=" + run + "; collectible", driver.snapshot().collectibleFound()); } } } private static final class Driver implements LevelPlaytestBot.Driver { private final Instrumentation instrumentation; private final GameView view; private Driver(Instrumentation instrumentation, GameView view) { this.instrumentation = instrumentation; this.view = view; } static Driver from(ActivityScenario activity) { GameView[] target = new GameView[1]; activity.onActivity(current -> target[0] = current.gameViewForAutomation()); return new Driver(InstrumentationRegistry.getInstrumentation(), target[0]); } @Override public void startLevel(int oneBasedLevelNumber) { instrumentation.runOnMainSync(() -> { view.enableDeterministicAutomationClock(); view.startLevelForAutomation(oneBasedLevelNumber); }); } @Override public void setInput(boolean left, boolean right, boolean jump) { instrumentation.runOnMainSync(() -> view.setAutomationInput(left, right, jump)); } @Override public GameView.AutomationSnapshot snapshot() { GameView.AutomationSnapshot[] value = new GameView.AutomationSnapshot[1]; instrumentation.runOnMainSync(() -> value[0] = view.automationSnapshot()); return value[0]; } @Override public void waitForNextDecision(long millis) { instrumentation.runOnMainSync(() -> view.advanceDeterministicAutomation(Math.max(16L, millis))); } } }