Align tests with runtime sandbox and polish terminal help
- Run level solution scenarios through GitRepositoryRuntime with a real filesystem sandbox and git binary so evidence logs match app behavior. - Materialize synthetic remotes as local bare repositories and configure upstream tracking for pull/push levels. - Route mobile-hostile Git interactions through shared sandbox semantics for clone, patch add, interactive rebase, squash merge, submodule, stash, revert, and related flows. - Relax affected level validators to inspect observable runtime state instead of fallback-only staged/index details. - Show .git in ls output for native and fallback helper commands. - Make tab completion resolve filenames and directories relative to the current working directory. - Integrate help controls into the callout overlay and reposition the prompt callout above the terminal prompt. - Add regression coverage for .git listing and subfolder completion.
This commit is contained in:
@@ -122,6 +122,31 @@ class GitSandboxEngineTest {
|
||||
assertTrue(".gitignore" in output)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun lsShowsGitDirectoryEntry() {
|
||||
val repo = RepoState(initialized = true)
|
||||
|
||||
val (_, output) = GitSandboxEngine.execute(repo, "ls")
|
||||
|
||||
assertTrue(".git" in output)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun fileCompletionUsesCurrentDirectory() {
|
||||
val repo = RepoState(
|
||||
initialized = true,
|
||||
currentDir = "src",
|
||||
files = listOf(
|
||||
GitFile("README"),
|
||||
GitFile("src/main.kt"),
|
||||
GitFile("src/model/User.kt"),
|
||||
),
|
||||
)
|
||||
|
||||
assertEquals(listOf("main.kt", "model/User.kt"), fileCompletionCandidates(repo).sorted())
|
||||
assertEquals(listOf("model/"), directoryCompletionCandidates(repo))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun cdDotDotShortcutMovesToParentDirectory() {
|
||||
val repo = RepoState(initialized = true, currentDir = "src/main")
|
||||
|
||||
@@ -31,22 +31,30 @@ class LevelSolutionsTest {
|
||||
@Test
|
||||
fun knownSolutionsCompleteEveryLevel() {
|
||||
val evidence = StringBuilder()
|
||||
val gitBinary = systemGitBinary()
|
||||
val runtimeRoot = testSandboxRoot().apply {
|
||||
deleteRecursively()
|
||||
mkdirs()
|
||||
}
|
||||
evidence.appendLine("GitHug Android level solution evidence")
|
||||
evidence.appendLine("Engine: GitSandboxEngine fallback")
|
||||
evidence.appendLine("Scope: validates fallback command handling and level validators; native runtime setup is covered by app runtime tests/builds.")
|
||||
evidence.appendLine("Engine: GitRepositoryRuntime filesystem sandbox")
|
||||
evidence.appendLine("Git binary: ${gitBinary.absolutePath}")
|
||||
evidence.appendLine("Sandbox root: ${runtimeRoot.absolutePath}")
|
||||
evidence.appendLine("Scope: executes embedded solution scenarios through the same runtime and per-level sandbox path used by the app.")
|
||||
evidence.appendLine("Levels: ${allGithugLevels().size}")
|
||||
evidence.appendLine()
|
||||
|
||||
val failures = allGithugLevels().flatMap { level ->
|
||||
val runtime = GitRepositoryRuntime(runtimeRoot, gitBinary)
|
||||
evidence.appendLine("================================================================================")
|
||||
evidence.appendLine("Level: ${level.id}")
|
||||
evidence.appendLine("Title: ${level.title}")
|
||||
evidence.appendLine("Initial repo:")
|
||||
evidence.append(level.setup().describeForEvidence().prependIndent(" "))
|
||||
evidence.append(runtime.prepareLevel(level).describeForEvidence().prependIndent(" "))
|
||||
evidence.appendLine()
|
||||
|
||||
level.testCases.mapNotNull { testCase ->
|
||||
var repo = level.setup()
|
||||
var repo = runtime.prepareLevel(level)
|
||||
var solved = false
|
||||
|
||||
evidence.appendLine("Scenario: ${testCase.name}")
|
||||
@@ -57,7 +65,7 @@ class LevelSolutionsTest {
|
||||
evidence.appendLine()
|
||||
|
||||
testCase.commands.forEachIndexed { index, command ->
|
||||
val (nextRepo, output) = GitSandboxEngine.execute(repo, command)
|
||||
val (nextRepo, output) = runtime.execute(level, repo, command)
|
||||
repo = nextRepo
|
||||
solved = level.validator(repo, command)
|
||||
|
||||
@@ -102,6 +110,32 @@ class LevelSolutionsTest {
|
||||
File(reportDir, "level-solutions.log").writeText(content)
|
||||
}
|
||||
|
||||
fun testSandboxRoot(): File {
|
||||
val repoRoot = File(System.getProperty("user.dir") ?: ".")
|
||||
val appDir = if (File(repoRoot, "app/build.gradle.kts").exists()) {
|
||||
File(repoRoot, "app")
|
||||
} else {
|
||||
repoRoot
|
||||
}
|
||||
return File(appDir, "build/test-sandboxes/level-solutions")
|
||||
}
|
||||
|
||||
fun systemGitBinary(): File {
|
||||
val candidates = listOf(
|
||||
File("/usr/bin/git"),
|
||||
File("/usr/local/bin/git"),
|
||||
)
|
||||
candidates.firstOrNull { it.exists() && it.canExecute() }?.let { return it }
|
||||
|
||||
val process = ProcessBuilder("sh", "-c", "command -v git")
|
||||
.redirectErrorStream(true)
|
||||
.start()
|
||||
val output = process.inputStream.bufferedReader().readText().trim()
|
||||
val exitCode = process.waitFor()
|
||||
assertTrue("A real git executable is required for level solution tests.", exitCode == 0 && output.isNotBlank())
|
||||
return File(output)
|
||||
}
|
||||
|
||||
fun RepoState.describeForEvidence(): String = buildString {
|
||||
appendLine("initialized=$initialized")
|
||||
appendLine("headBranch=$headBranch")
|
||||
|
||||
Reference in New Issue
Block a user