Skip to content

Commit d5200ac

Browse files
committed
Cache test data.
1 parent ca593b6 commit d5200ac

File tree

5 files changed

+35
-34
lines changed

5 files changed

+35
-34
lines changed

aockt-test/src/main/kotlin/AdventSpec.kt

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,6 @@ package io.github.jadarma.aockt.test
22

33
import io.github.jadarma.aockt.core.Solution
44
import io.github.jadarma.aockt.test.internal.AdventRootScopeImpl
5-
import io.github.jadarma.aockt.test.internal.PuzzleTestData
6-
import io.github.jadarma.aockt.test.internal.TestData
7-
import io.github.jadarma.aockt.test.internal.adventDay
8-
import io.github.jadarma.aockt.test.internal.id
95
import io.github.jadarma.aockt.test.internal.registerDebug
106
import io.github.jadarma.aockt.test.internal.registerTest
117
import io.kotest.common.ExperimentalKotest
@@ -50,8 +46,6 @@ public abstract class AdventSpec<T : Solution>(
5046
body: AdventRootScope.() -> Unit = {},
5147
) : FunSpec() {
5248

53-
internal val testData: PuzzleTestData = TestData.inputFor(this::class.adventDay.id)
54-
5549
init {
5650
AdventRootScopeImpl(owner = this::class).apply {
5751
body()

aockt-test/src/main/kotlin/internal/AdventConfig.kt

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ internal data class AdventProjectConfig(
2020
val efficiencyBenchmark: Duration,
2121
val executionMode: ExecMode,
2222
) : AbstractCoroutineContextElement(Key) {
23+
2324
init {
2425
if (efficiencyBenchmark.isPositive().not()) {
2526
throw ConfigurationException("Efficiency benchmark must be a positive value, but was: $efficiencyBenchmark")
@@ -37,6 +38,7 @@ internal data class AdventProjectConfig(
3738

3839
@Suppress("BooleanPropertyNaming")
3940
internal data class AdventTestConfig(
41+
val id: AdventDayID,
4042
val part: AdventDayPart,
4143
val partFunction: PartFunction,
4244
val enabled: Boolean,
@@ -53,33 +55,34 @@ internal data class AdventTestConfig(
5355
)
5456

5557
data class ForInput(
58+
val id: AdventDayID,
59+
val part: AdventDayPart,
5660
val enabled: Boolean,
5761
val partFunction: PartFunction,
5862
val expensive: Boolean,
5963
val efficiencyBenchmark: Duration,
60-
val input: PuzzleInput?,
61-
val correctAnswer: PuzzleAnswer?,
6264
)
6365
}
6466

6567
internal data class AdventDebugConfig(
68+
val id: AdventDayID,
6669
val solution: Solution,
6770
val test: AdventDebugScope.() -> Unit,
6871
)
6972

70-
internal fun AdventTestConfig.forExamples(defaults: AdventProjectConfig) =
73+
internal fun AdventTestConfig.forExamples(defaults: AdventProjectConfig): AdventTestConfig.ForExamples =
7174
AdventTestConfig.ForExamples(
7275
enabled = (executionMode ?: defaults.executionMode) != ExecMode.SkipExamples,
7376
partFunction = partFunction,
7477
examples = examples,
7578
)
7679

77-
internal fun AdventTestConfig.forInput(defaults: AdventProjectConfig, testData: PuzzleTestData) =
80+
internal fun AdventTestConfig.forInput(defaults: AdventProjectConfig): AdventTestConfig.ForInput =
7881
AdventTestConfig.ForInput(
82+
id = id,
83+
part = part,
7984
enabled = (executionMode ?: defaults.executionMode) != ExecMode.ExamplesOnly,
8085
partFunction = partFunction,
8186
expensive = expensive,
82-
efficiencyBenchmark = efficiencyBenchmark ?: defaults.efficiencyBenchmark,
83-
input = testData.input,
84-
correctAnswer = testData.solutionToPart(part),
87+
efficiencyBenchmark = efficiencyBenchmark ?: defaults.efficiencyBenchmark
8588
)

aockt-test/src/main/kotlin/internal/AdventRootScopeImpl.kt

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,14 @@ internal class AdventRootScopeImpl(
2828
) {
2929
if (partOne != null) throw DuplicateDefinitionException(owner, "partOne")
3030
partOne = AdventTestConfig(
31+
id = owner.adventDay.id,
3132
part = AdventDayPart.One,
3233
partFunction = solution.partFunction(AdventDayPart.One),
3334
enabled = enabled,
3435
expensive = expensive,
3536
executionMode = executionMode,
3637
efficiencyBenchmark = efficiencyBenchmark,
37-
examples = AdventPartScopeImpl().apply(examples).testCases
38+
examples = AdventPartScopeImpl().apply(examples).testCases,
3839
)
3940
}
4041

@@ -47,18 +48,23 @@ internal class AdventRootScopeImpl(
4748
) {
4849
if (partTwo != null) throw DuplicateDefinitionException(owner, "partTwo")
4950
partTwo = AdventTestConfig(
51+
id = owner.adventDay.id,
5052
part = AdventDayPart.Two,
5153
partFunction = solution.partFunction(AdventDayPart.Two),
5254
enabled = enabled,
5355
expensive = expensive,
5456
executionMode = executionMode,
5557
efficiencyBenchmark = efficiencyBenchmark,
56-
examples = AdventPartScopeImpl().apply(examples).testCases
58+
examples = AdventPartScopeImpl().apply(examples).testCases,
5759
)
5860
}
5961

6062
override fun debug(test: AdventDebugScope.() -> Unit) {
6163
if (debug != null) throw DuplicateDefinitionException(owner, "debug")
62-
debug = AdventDebugConfig(solution, test)
64+
debug = AdventDebugConfig(
65+
id = owner.adventDay.id,
66+
solution = solution,
67+
test = test,
68+
)
6369
}
6470
}

aockt-test/src/main/kotlin/internal/AdventSpecExt.kt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,17 +58,17 @@ internal fun AdventSpec<*>.registerTest(config: AdventTestConfig): Unit = with(c
5858
) {
5959
val projectConfig = currentCoroutineContext()[AdventProjectConfig.Key] ?: AdventProjectConfig.Default
6060
registerExamples(config.forExamples(projectConfig))
61-
registerInput(config.forInput(projectConfig, testData))
61+
registerInput(config.forInput(projectConfig))
6262
}
6363
}
6464

6565
/**
6666
* Register a focused root test to help debugging a [Solution].
6767
* All other tests will be ignored.
6868
*/
69-
@OptIn(ExperimentalKotest::class)
7069
internal fun AdventSpec<*>.registerDebug(config: AdventDebugConfig): Unit = with(config) {
7170
test(name = "f:Debug") {
71+
val testData = TestData.inputFor(config.id)
7272
withClue("Debug run completed exceptionally.") {
7373
shouldNotThrowAnyUnit {
7474
AdventDebugScopeImpl(solution, testData.input).run(test)
@@ -105,7 +105,10 @@ private suspend fun FunSpecContainerScope.registerExamples(config: AdventTestCon
105105
@OptIn(ExperimentalKotest::class)
106106
@Suppress("SuspendFunWithCoroutineScopeReceiver", "CognitiveComplexMethod")
107107
private suspend fun FunSpecContainerScope.registerInput(config: AdventTestConfig.ForInput): Unit = with(config) {
108-
if (input == null) return
108+
109+
val data = TestData.inputFor(config.id)
110+
val input = data.input ?: return
111+
val correctAnswer = data.solutionToPart(config.part)
109112

110113
context("The solution").config(enabled = enabled) {
111114
val isSolutionKnown = correctAnswer != null

aockt-test/src/main/kotlin/internal/TestData.kt

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.github.jadarma.aockt.test.internal
22

33
import io.github.jadarma.aockt.core.Solution
4+
import java.util.concurrent.ConcurrentHashMap
45

56
/**
67
* Reads [PuzzleTestData]s from classpath resources.
@@ -21,16 +22,15 @@ import io.github.jadarma.aockt.core.Solution
2122
*/
2223
internal object TestData {
2324

25+
private val data: ConcurrentHashMap<AdventDayID, PuzzleTestData> = ConcurrentHashMap()
26+
2427
/** Returns the available [PuzzleTestData] for a given [AdventDayID] by reading it from the resources. */
25-
fun inputFor(adventDayID: AdventDayID): PuzzleTestData {
28+
fun inputFor(adventDayID: AdventDayID): PuzzleTestData = data.computeIfAbsent(adventDayID) {
2629
val path = with(adventDayID) { "/aockt/y$year/d${day.toString().padStart(2, '0')}" }
27-
return PuzzleTestData(
30+
PuzzleTestData(
2831
input = readResourceAsTextOrNull("$path/input.txt").toPuzzleInput(),
2932
solutionPartOne = readResourceAsTextOrNull("$path/solution_part1.txt").toPuzzleAnswer(),
30-
solutionPartTwo = when(adventDayID.day) {
31-
25 -> PuzzleAnswer.NO_SOLUTION
32-
else -> readResourceAsTextOrNull("$path/solution_part2.txt").toPuzzleAnswer()
33-
},
33+
solutionPartTwo = readResourceAsTextOrNull("$path/solution_part2.txt").toPuzzleAnswer(),
3434
)
3535
}
3636

@@ -41,13 +41,13 @@ internal object TestData {
4141
?.use { String(it.readAllBytes()).trimEnd() }
4242

4343
/** Wraps a [String] into a [PuzzleAnswer] type. */
44-
private fun String?.toPuzzleAnswer(): PuzzleAnswer? = when(this) {
44+
private fun String?.toPuzzleAnswer(): PuzzleAnswer? = when (this) {
4545
null -> null
4646
else -> PuzzleAnswer(this)
4747
}
4848

4949
/** Wraps a [String] into a [PuzzleInput] type. */
50-
private fun String?.toPuzzleInput(): PuzzleInput? = when(this) {
50+
private fun String?.toPuzzleInput(): PuzzleInput? = when (this) {
5151
null -> null
5252
else -> PuzzleInput(this)
5353
}
@@ -78,9 +78,9 @@ internal value class PuzzleInput(private val input: String) {
7878

7979
/** Formats the input in a printable friendly manner. */
8080
@Suppress("MagicNumber")
81-
fun preview(): String = when(input.count { it == '\n' }) {
81+
fun preview(): String = when (input.count { it == '\n' }) {
8282
0 -> input
83-
in 1 .. 5 -> "\n$input\n"
83+
in 1..5 -> "\n$input\n"
8484
else -> buildString {
8585
val lines = input.lines()
8686
appendLine()
@@ -95,9 +95,4 @@ internal value class PuzzleInput(private val input: String) {
9595
@JvmInline
9696
internal value class PuzzleAnswer(private val answer: String) {
9797
override fun toString() = answer
98-
99-
companion object {
100-
/** In the case of some days, there is no part two requirement. */
101-
val NO_SOLUTION = PuzzleAnswer("=== No Solution ===")
102-
}
10398
}

0 commit comments

Comments
 (0)