Require real merge commit and keep level tests embedded
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
package solutions.tretter.githugandroid
|
||||
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
import java.io.File
|
||||
@@ -99,104 +98,54 @@ class LevelSolutionsTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun upstreamFixtureBackedLevelsExposeSourceShapedSetup() {
|
||||
fun embeddedSetupChecksPass() {
|
||||
val gitBinary = testGitBinary()
|
||||
val runtimeRoot = testSandboxRoot().apply {
|
||||
deleteRecursively()
|
||||
mkdirs()
|
||||
}
|
||||
|
||||
fun prepared(level: Level): RepoState = GitRepositoryRuntime(runtimeRoot, gitBinary).prepareLevel(level)
|
||||
fun RepoState.fileContent(path: String): String = files.firstOrNull { it.name == path }?.content.orEmpty()
|
||||
val failures = allGithugLevels().flatMap { level ->
|
||||
if (level.setupChecks.isEmpty()) return@flatMap emptyList()
|
||||
val repo = GitRepositoryRuntime(runtimeRoot, gitBinary).prepareLevel(level)
|
||||
level.setupChecks
|
||||
.filterNot { check -> check.predicate(repo) }
|
||||
.map { check -> "${level.id} / ${check.name}: ${check.failureMessage}" }
|
||||
}
|
||||
|
||||
val conflict = prepared(conflictLevel())
|
||||
assertEquals("master", conflict.headBranch)
|
||||
assertTrue(conflict.fileContent("poem.txt").contains("Categorized shoes by color"))
|
||||
assertTrue(conflict.branches.containsKey("mybranch"))
|
||||
|
||||
val grep = prepared(grepLevel())
|
||||
assertTrue(grep.fileContent("app.rb").contains("# TODO Make site url variable."))
|
||||
assertTrue(grep.fileContent("config.rb").contains("# TODO Move password to a configuration file."))
|
||||
|
||||
val findOldBranch = prepared(findOldBranchLevel())
|
||||
assertEquals("master", findOldBranch.headBranch)
|
||||
assertEquals(
|
||||
setOf("blowup_sun_for_ransom", "cure_common_cold", "master", "solve_world_hunger"),
|
||||
findOldBranch.branches.keys,
|
||||
assertTrue(
|
||||
"Expected every embedded setup check to pass. Failures:\n${failures.joinToString("\n")}",
|
||||
failures.isEmpty(),
|
||||
)
|
||||
|
||||
val deleteBranch = prepared(deleteBranchLevel())
|
||||
assertTrue(deleteBranch.files.any { it.name == "readme" && it.tracked })
|
||||
assertTrue(deleteBranch.branches.containsKey("delete_me"))
|
||||
|
||||
val diff = prepared(diffLevel())
|
||||
assertTrue(diff.fileContent("app.rb").contains("@message = get_response('server.json')"))
|
||||
|
||||
val stash = prepared(stashLevel())
|
||||
assertTrue(stash.fileContent("lyrics.txt").contains("Hear them loudly cry:\nHey!"))
|
||||
|
||||
val cherryPick = prepared(cherryPickLevel())
|
||||
assertTrue(cherryPick.fileContent("README.md").contains("I'll fill in the file some time later.."))
|
||||
assertTrue(cherryPick.fileContent("hardcore-math.js").contains("console.log(42 * i);"))
|
||||
assertTrue(cherryPick.branches.containsKey("new-feature"))
|
||||
|
||||
val blame = prepared(blameLevel())
|
||||
assertTrue(blame.fileContent("config.rb").contains("@password = password || \"i<3evil\""))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun reportedRegressionCommandsDoNotSolveLevels() {
|
||||
val statusRepo = statusLevel().setup()
|
||||
val untrackedStatusFiles = statusRepo.files.filter { !it.staged && !it.tracked && !it.deleted }.map { it.name }
|
||||
assertEquals(listOf("database.yml"), untrackedStatusFiles)
|
||||
|
||||
fun embeddedNegativeScenariosDoNotSolveLevels() {
|
||||
val gitBinary = testGitBinary()
|
||||
val runtimeRoot = testSandboxRoot().apply {
|
||||
deleteRecursively()
|
||||
mkdirs()
|
||||
}
|
||||
|
||||
val mergeExercise = mergeLevel()
|
||||
val mergeRuntime = GitRepositoryRuntime(runtimeRoot, gitBinary)
|
||||
val mergeRepo = mergeRuntime.prepareLevel(mergeExercise)
|
||||
val (switchedRepo, _) = mergeRuntime.execute(mergeExercise, mergeRepo, "git switch feature")
|
||||
assertFalse("Switching to feature must not solve the merge level.", mergeExercise.validator(switchedRepo, "git switch feature"))
|
||||
val failures = allGithugLevels().flatMap { level ->
|
||||
level.negativeTestCases.mapNotNull { testCase ->
|
||||
val runtime = GitRepositoryRuntime(runtimeRoot, gitBinary)
|
||||
var repo = runtime.prepareLevel(level)
|
||||
var solved = false
|
||||
|
||||
val fetchExercise = fetchLevel()
|
||||
val fetchRuntime = GitRepositoryRuntime(runtimeRoot, gitBinary)
|
||||
val fetchRepo = fetchRuntime.prepareLevel(fetchExercise)
|
||||
val (pulledRepo, _) = fetchRuntime.execute(fetchExercise, fetchRepo, "git pull")
|
||||
assertFalse("Pulling must not solve the fetch level.", fetchExercise.validator(pulledRepo, "git pull"))
|
||||
testCase.commands.forEach { command ->
|
||||
val (nextRepo, _) = runtime.execute(level, repo, command)
|
||||
repo = nextRepo
|
||||
solved = level.validator(repo, command)
|
||||
}
|
||||
|
||||
val reorderExercise = reorderLevel()
|
||||
val reorderRuntime = GitRepositoryRuntime(runtimeRoot, gitBinary)
|
||||
val reorderRepo = reorderRuntime.prepareLevel(reorderExercise)
|
||||
val (bareInteractiveRebaseRepo, _) = reorderRuntime.execute(reorderExercise, reorderRepo, "git rebase -i")
|
||||
assertFalse(
|
||||
"Starting an interactive rebase without an upstream/range must not solve the reorder level.",
|
||||
reorderExercise.validator(bareInteractiveRebaseRepo, "git rebase -i"),
|
||||
)
|
||||
|
||||
val futureCommitExercise = commitInFutureLevel()
|
||||
val futureCommitRuntime = GitRepositoryRuntime(runtimeRoot, gitBinary)
|
||||
val futureCommitRepo = futureCommitRuntime.prepareLevel(futureCommitExercise)
|
||||
val (currentDateCommitRepo, _) = futureCommitRuntime.execute(futureCommitExercise, futureCommitRepo, "git commit -m \"Current date commit\"")
|
||||
assertFalse(
|
||||
"A normal commit using the current system date must not solve the commit_in_future level.",
|
||||
futureCommitExercise.validator(currentDateCommitRepo, "git commit -m \"Current date commit\""),
|
||||
)
|
||||
|
||||
val bisectExercise = bisectLevel()
|
||||
val bisectRuntime = GitRepositoryRuntime(runtimeRoot, gitBinary)
|
||||
var bisectRepo = bisectRuntime.prepareLevel(bisectExercise)
|
||||
listOf("git bisect start", "git bisect bad HEAD", "git bisect good known-good").forEach { command ->
|
||||
val (nextRepo, _) = bisectRuntime.execute(bisectExercise, bisectRepo, command)
|
||||
bisectRepo = nextRepo
|
||||
if (solved) "${level.id} / ${testCase.name}: ${testCase.commands.joinToString(" && ")}" else null
|
||||
}
|
||||
}
|
||||
val (bisectRunRepo, _) = bisectRuntime.execute(bisectExercise, bisectRepo, "git bisect run ./test-balance.sh")
|
||||
assertFalse(
|
||||
"Running bisect should not solve the bisect level until the learner enters the last good commit hash.",
|
||||
bisectExercise.validator(bisectRunRepo, "git bisect run ./test-balance.sh"),
|
||||
|
||||
assertTrue(
|
||||
"Expected every embedded negative scenario to remain unsolved. Failures:\n${failures.joinToString("\n")}",
|
||||
failures.isEmpty(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -281,7 +230,7 @@ class LevelSolutionsTest {
|
||||
appendLine(" <none>")
|
||||
} else {
|
||||
commits.forEach { commit ->
|
||||
appendLine(" ${commit.id} ${commit.authorTimestampSeconds ?: "unknown-time"} ${commit.message}")
|
||||
appendLine(" ${commit.id} parents=${commit.parentCount} ${commit.authorTimestampSeconds ?: "unknown-time"} ${commit.message}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user