Pillsgood.AdventOfCode
2.0.22
dotnet add package Pillsgood.AdventOfCode --version 2.0.22
NuGet\Install-Package Pillsgood.AdventOfCode -Version 2.0.22
<PackageReference Include="Pillsgood.AdventOfCode" Version="2.0.22" />
<PackageVersion Include="Pillsgood.AdventOfCode" Version="2.0.22" />
<PackageReference Include="Pillsgood.AdventOfCode" />
paket add Pillsgood.AdventOfCode --version 2.0.22
#r "nuget: Pillsgood.AdventOfCode, 2.0.22"
#:package Pillsgood.AdventOfCode@2.0.22
#addin nuget:?package=Pillsgood.AdventOfCode&version=2.0.22
#tool nuget:?package=Pillsgood.AdventOfCode&version=2.0.22
Pillsgood.AdventOfCode
Helpers for solving Advent of Code puzzles from unit tests. It handles:
- Fetching your puzzle input
- Converting input into convenient types
- Submitting/validating your answers
Built for use with NUnit but probably works with other test frameworks too.
Quick start (NUnit)
Add NuGet package
Pillsgood.AdventOfCodeto project.- Optionally, add
Pillsgood.AdventOfCode.Loginfor interactive login.
- Optionally, add
Add a one-time startup/teardown to your test assembly to initialize the library.
using NUnit.Framework; using Pillsgood.AdventOfCode; using Pillsgood.AdventOfCode.Login; // only if you want the login UI [SetUpFixture] public sealed class AdventSetup { private IDisposable? _app; [OneTimeSetUp] public void Start() { _app = Aoc.Start(cfg => { // Choose ONE of the following: // 1) Provide a session cookie directly: // cfg.WithSession("your_session_cookie_here"); // 2) Or use the interactive login window (from Pillsgood.AdventOfCode.Login): // cfg.WithLogin(); // Optional: only needed if your tests run from a helper assembly (probs works) // cfg.SetEntryAssembly(typeof(AdventSetup).Assembly); // Optional: you can add additional puzzle input converters here // cfg.AddInputConverter<SampleType>(() => new SampleTypeInputConverter()) }); } [OneTimeTearDown] public void Stop() { _app?.Dispose(); } }Create test classes that inherit from
AocFixture, and follow the naming conventions below. UseInputto read puzzle input andAnswerto submit/validate.using NUnit.Framework; using Pillsgood.AdventOfCode; // Class name (or namespace) must include the year and day (see Naming Conventions) namespace Y2024 { public class Day01Tests : AocFixture { [Test] public void Part1() { var lines = Input.Get<IEnumerable<string>>(); var result = SolvePart1(lines); // Validates against your previously accepted answer (or submits if new) Answer.Submit(result); } [Test] public void Part2() { var numbers = Input.Get<int>(System.Globalization.NumberStyles.Integer); var result = SolvePart2(numbers); Answer.Submit(result); } private static int SolvePart1(IEnumerable<string> lines) { // your solution here return lines.Count(); } private static long SolvePart2(IEnumerable<int> nums) { // your solution here return nums.Select(n => (long)n).Sum(); } } }
Naming conventions (how the library finds date and part)
The library automatically detects which puzzle you’re solving by inspecting the call stack:
- Year: any
20xxpresent in the test class' full name (namespace or type name) - Day:
DayNN(e.g.,Day1,Day01,Day25) present in the test class' full name - Part: inferred from the test method name
Part1orPart2
Examples that work:
- Namespace
AoC._2023.Day05and classDay05Tests - Namespace
AdventOfCode.Y2022and classDay1_PartTests
If detection fails, you’ll get an error like “Unable to resolve date/part.” Ensure your class and method names contain the patterns above.
Reading input
AocFixture exposes Input (an IPuzzleInputService) with helpers to parse your input:
// Reads raw text as string
var text = Input.Get<string>();
// Reads input as IEnumerable<string> (split by new lines)
var lines = Input.Get<IEnumerable<string>>();
// Read numbers with explicit number style and optional format provider
var ints = Input.Get<int>(System.Globalization.NumberStyles.Integer);
var longs = await Input.GetAsync<long>(System.Globalization.NumberStyles.Integer);
// Asynchronous versions exist for all operations: GetAsync<T>()
You can also access the raw stream:
await using var stream = await Input.GetInputStreamAsync(new DateOnly(2024, 12, 1));
Submitting/validating answers
Use Answer from AocFixture and call Submit(...) or SubmitAsync(...) inside your test method. The library:
- Figures out the Day and Part from the method name and type
- Submits the answer to AoC (if not known) and/or asserts against the stored, accepted answer
// Numbers:
Answer.Submit(12345); // infers Part from method name
await Answer.SubmitAsync(12345L);
// Strings:
Answer.Submit("ABCDEF");
await Answer.SubmitAsync("ABCDEF");
// Defer computation:
Answer.Submit(() => Compute());
await Answer.SubmitAsync(async () => await ComputeAsync());
If the answer was already accepted previously, the call will assert equality against the known-good answer instead of re-submitting.
Session setup options
You must authenticate once so the library can fetch inputs and submit answers.
Pick one in Aoc.Start(cfg => ...):
cfg.WithSession("<session_cookie>")— pass your AoC session cookie directly (great for CI/local). The cookie value is thesessioncookie fromadventofcode.com.cfg.WithLogin()(fromPillsgood.AdventOfCode.Login) — shows a low-effort Avalonia login window to acquire and cache the session.
The session is cached, if an invalid/expired session is detected, it will be cleared and you’ll be prompted again (or you’ll need to provide a valid cookie).
Configuration reference
Aoc.Start(cfg => { ... }) accepts the following options:
var app = Aoc.Start(cfg =>
{
// 1) Provide a session cookie directly (recommended for CI/local)
cfg.WithSession("your_session_cookie_here");
// 2) Or provide a custom session provider
// cfg.WithSessionProvider(() => new MySessionProvider());
// Tell the library which assembly contains your tests (optional)
// cfg.SetEntryAssembly(typeof(SomeTypeInYourTests).Assembly);
// Register custom input converters (optional)
// cfg.AddInputConverter<MyType>(() => new MyTypeInputConverter());
// Set the cache file path (defaults to "store.db")
// cfg.WithCachePath(".aoc-cache.db");
});
Dispose the returned IDisposable at the end of the test run to cleanly release services.
Create a custom base class for your tests
If you prefer not to inherit from AocFixture, you can create your own base class. Mark it with AocFixtureAttribute so the library can resolve the date/part from your call stack.
using NUnit.Framework;
using Pillsgood.AdventOfCode;
using Pillsgood.AdventOfCode.Common;
[AocFixture]
public abstract class MyAocBase
{
protected IPuzzleInputService Input => Locator.GetRequiredService<IPuzzleInputService>();
protected IAnswerAssertion Answer => Locator.GetRequiredService<IAnswerAssertion>();
}
public sealed class Day01Tests : MyAocBase
{
[Test]
public void Part1()
{
var lines = Input.Get<IEnumerable<string>>();
var result = SolvePart1(lines);
Answer.Submit(result);
}
}
Notes:
- You still need the global startup/teardown via
Aoc.Start(...)to initialize DI and caching. AocFixtureAttributeon your base class (or on the test class) ensures that year/day and part can be resolved by the library.
License
See LICENSE.md.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- AwesomeAssertions (>= 9.3.0)
- Microsoft.Extensions.Caching.Hybrid (>= 10.0.0)
- Microsoft.Extensions.DependencyInjection (>= 10.0.0)
- NeoSmart.Caching.Sqlite (>= 9.0.1)
- SoftCircuits.HtmlMonkey (>= 3.1.0)
- SourceGear.sqlite3 (>= 3.50.4.5)
- SQLitePCLRaw.config.e_sqlite3 (>= 3.0.2)
- SQLitePCLRaw.provider.e_sqlite3 (>= 3.0.2)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Pillsgood.AdventOfCode:
| Package | Downloads |
|---|---|
|
Pillsgood.AdventOfCode.Login
Package Description |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.0.22 | 9 | 12/2/2025 |
| 2.0.21 | 8 | 12/2/2025 |
| 2.0.20 | 27 | 12/2/2025 |
| 2.0.19 | 22 | 12/2/2025 |
| 2.0.18-alpha | 16 | 12/2/2025 |
| 2.0.13-alpha | 24 | 12/2/2025 |
| 2.0.8-alpha | 17 | 12/2/2025 |
| 2.0.7-alpha | 16 | 12/2/2025 |
| 2.0.6-alpha | 21 | 12/2/2025 |
| 1.1.2 | 237 | 11/21/2024 |
| 1.1.1 | 185 | 11/21/2024 |
| 1.1.0-alpha | 134 | 11/21/2024 |
| 1.0.1 | 467 | 12/7/2022 |
| 1.0.0 | 455 | 12/7/2022 |