Home

Awesome

Advent of Code - Kotlin (AocKt)

Kotlin Kotest Build Status Maven Central Snapshot

AocKt (short for Advent of Code - Kotlin) is a simple library that makes running and testing your Kotlin solutions to Advent of Code puzzles a breeze.

It is an opinionated testing framework built on Kotest that defines a new AdventSpec specialized for testing AoC puzzle solutions with minimal boilerplate.

✨ Features

⚡ Quick Start

Gradle

To use AocKt, simply add the dependencies and configure your project to run unit tests with Kotest:

repositories {
    mavenCentral()
}

dependencies {
    implementation("io.github.jadarma.aockt:aockt-core:$aocktVersion")
    testImplementation("io.github.jadarma.aockt:aockt-test:$aocktVersion")
    testImplementation("io.kotest:kotest-runner-junit5:5.9.1")
}

tasks.test {
    useJUnitPlatform()
}

Project Template

For your convenience, there is an advent-of-code-kotlin-template repository which you can use to generate your own solutions repo, featuring a pre-configured Gradle project, modified source directory locations for easier navigation, and a detailed README with workflow examples. If you need a working example, you can check out my solutions repo as well.

📄 Usage Guide

<details open> <summary>Basic Test Definition</summary>
object Y9999D01 : Solution { /* ... */ }                // 1.

@AdventDay(9999, 1, "Magic Numbers")                    // 2.
class Y9999D01Test : AdventSpec<Y9999D01>({             // 3.
    partOne {                                           // 4.
        "1,2,3,4" shouldOutput 4                        // 5.
        listOf("2", "2,2", "2,4,6,8") shouldAllOutput 0 // 6.
    }
    partTwo()                                           // 7.
})

In the above example:

  1. Your solution should implement the Solution interface.
  2. Each test class should be annotated with the @AdventDay annotation. Title is optional, but the year and day are required, so the spec knows what user input to test with.
  3. Rather than passing it as an instance, the AdventSpec takes in your solution as a type parameter.
  4. Use the partOne and partTwo functions as needed. Inside the lambda you can define test cases. The Solution functions will only be invoked if the relevant part DSL is used. If you have not yet implemented the second part, or it doesn't exist (e.g.: Every year, part two of the last day just requires collecting all other 49 stars), then you may simply omit it.
  5. To define a test case, use the shouldOutput function. Each usage will define another test case. The value tested against is checked against its string value, so shouldOutput 4 and shouldOutput "4" are equivalent.
  6. As a shorthand for defining multiple examples that should output the same thing, use the shouldAllOutput function.
  7. If you don't have any examples, but do want to run the part against your input the lambda can be omitted.
</details> <details> <summary>Project Configuration</summary>

AocKt provides an extension you may register in your Kotest project to tweak the behaviour of the AdventSpec. Registering it is optional but recommended, and can be done like any other extension:

object TestConfig : AbstractProjectConfig() {

    override fun extensions() = listOf<Extension>(
        AocKtExtension(),
    )
}

The following optional parameters exist:

</details> <details> <summary>Testing Against User Input</summary>

By default, only the example defined in the DSL will run. However, the solution can be tested against real user input if it is detected. AocKt looks inside the test resources directory for them. The structure is fixed and must match the following:

testResourcesDir
  └──  aockt
     └── y{year}
        └── d{two-digit-day}
           └── input.txt
           └── solution_part1.txt
           └── solution_part2.txt

If the input.txt file exists, the Solution will be ran against it after the example tests. It is normal that at first the solutions are unknown, and therefore missing. The unverified solution will be added in parens at the end of the test name, which you can then submit to the website.

If the solution_part1 or solution_part2.txt exist, then the value contained within them is assumed to be the correct output when running against input.txt, and will be validated.

IMPORTANT!: The reason for keeping the user inputs separate from the tests (apart from readability) is that puzzle inputs should not be redistributed. If you plan on sharing your solutions repository publicly, either .gitignore the src/test/resources/aockt directory or commit them as encrypted blobs only you can read!

</details> <details> <summary>Execution configuration for Parts</summary>

The partOne and partTwo scopes can be configured with optional parameters. These allow you to modify the way the generated tests behave. They are mostly meant to help during development, and reverted once your solutions are complete.

The following optional parameters exist:

</details> <details> <summary>Multiple Solutions for the Same Puzzle</summary>

The AdventSpec is designed to test a single Solution at a time. However, that doesn't mean you need to duplicate the code if you want to show off multiple approaches to the solution! You can instead define an abstract specification for your test cases, and use it to derive an arbitrary number of specific implementation test classes, and supply the variant parameter to the AdventDay annotation to disambiguate between the two.

object SolutionA : Solution { /* ... */ }
object SolutionB : Solution { /* ... */ }

@AdventDay(9999, 1, "Magic Numbers", "Variant A")
class SolutionATest : Y9999D01Spec<SolutionA>()

@AdventDay(9999, 1, "Magic Numbers", "Variant B")
class SolutionBTest : Y9999D01Spec<SolutionB>()

abstract class Y9999D01Spec<T : Solution> : AdventSpec<T>({
    val exampleInput = "1,2,3,4"
    partOne { exampleInput shouldOutput 4 }
    partTwo { exampleInput shouldOutput 24 }
})
</details> <details> <summary>Workflow Example</summary>

For a complete workflow example, check out the project template.

</details>

👥 Contributing

If you'd like to help out:

⚖ License

This project is licensed under the MIT License - see the LICENSE for details.
Advent of Code is a registered trademark of Eric K Wastl in the United States.