Implemented benchmark framework

This commit is contained in:
BoolPurist 2024-08-30 02:18:02 +02:00
parent 5a98c0541b
commit 854f1f1334
20 changed files with 612 additions and 79 deletions

96
Cargo.lock generated
View file

@ -6,10 +6,14 @@ version = 3
name = "advent_of_code_2023" name = "advent_of_code_2023"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow",
"clap", "clap",
"colonnade",
"derive_more", "derive_more",
"env_logger", "env_logger",
"log", "log",
"ron",
"serde",
"solutions_advent_of_code_2023", "solutions_advent_of_code_2023",
"thiserror", "thiserror",
] ]
@ -72,6 +76,27 @@ dependencies = [
"windows-sys", "windows-sys",
] ]
[[package]]
name = "anyhow"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
[[package]]
name = "base64"
version = "0.21.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
[[package]]
name = "bitflags"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "clap" name = "clap"
version = "4.5.16" version = "4.5.16"
@ -112,6 +137,16 @@ version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
[[package]]
name = "colonnade"
version = "1.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "833230a1f610c0f3418a80b03c387be9de15b1172b3785b702961ead07e3e475"
dependencies = [
"strip-ansi-escapes",
"unicode-segmentation",
]
[[package]] [[package]]
name = "colorchoice" name = "colorchoice"
version = "1.0.2" version = "1.0.2"
@ -297,6 +332,38 @@ version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
[[package]]
name = "ron"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94"
dependencies = [
"base64",
"bitflags",
"serde",
"serde_derive",
]
[[package]]
name = "serde"
version = "1.0.209"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.209"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "similar" name = "similar"
version = "2.6.0" version = "2.6.0"
@ -313,6 +380,15 @@ dependencies = [
"thiserror", "thiserror",
] ]
[[package]]
name = "strip-ansi-escapes"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55ff8ef943b384c414f54aefa961dd2bd853add74ec75e7ac74cf91dba62bcfa"
dependencies = [
"vte",
]
[[package]] [[package]]
name = "strsim" name = "strsim"
version = "0.11.1" version = "0.11.1"
@ -374,6 +450,26 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "vte"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f5022b5fbf9407086c180e9557be968742d839e68346af7792b8592489732197"
dependencies = [
"utf8parse",
"vte_generate_state_changes",
]
[[package]]
name = "vte_generate_state_changes"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e369bee1b05d510a7b4ed645f5faa90619e05437111783ea5848f28d97d3c2e"
dependencies = [
"proc-macro2",
"quote",
]
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.52.0" version = "0.52.0"

View file

@ -1,3 +0,0 @@
# TODO
- Implment subcommand to execute puzzle input files and print out how every long every one takes

View file

@ -8,7 +8,11 @@ solutions_advent_of_code_2023 = { path = "../solutions" }
derive_more = { workspace = true } derive_more = { workspace = true }
thiserror = { workspace = true } thiserror = { workspace = true }
serde = { version = "1.0.209", features = ["derive"] }
clap = { version = "4.5.15", features = ["derive"] } clap = { version = "4.5.15", features = ["derive"] }
env_logger = "0.11.5" env_logger = "0.11.5"
log = "0.4.22" log = "0.4.22"
anyhow = "1.0.86"
ron = "0.8.1"
colonnade = "1.3.3"

View file

@ -0,0 +1,96 @@
pub use benchmark_result::BenchmarkResult;
pub use file_to_benchmark::FileToBenchmark;
mod benchmark_result;
mod file_to_benchmark;
mod row_building;
use crate::{cli::BenchmarkCli, solving_given::solve_given, AppResult};
use anyhow::anyhow;
use colonnade::Colonnade;
use std::time::{Duration, Instant};
fn calc_average(sum: Duration, nanos_count: u64) -> Duration {
let average_raw = sum.div_duration_f64(Duration::from_nanos(nanos_count));
Duration::from_nanos(average_raw.round() as u64)
}
pub fn execute_benchmark(args: &BenchmarkCli) -> AppResult<String> {
let loaded = load_benchmarks(args)?;
let benchmarked = loaded
.into_iter()
.map(solve_and_keep_track_of_runtime)
.collect::<AppResult<Vec<BenchmarkResult>>>()?;
let sum: Duration = benchmarked.iter().map(|result| result.how_long()).sum();
let average = calc_average(sum, benchmarked.len() as u64);
let header = row_building::create_header();
let after_header = row_building::create_rows_for_every_solutions(benchmarked);
let table: Vec<Vec<String>> = after_header
.into_iter()
.chain(row_building::create_sum_row(sum))
.chain(row_building::create_average_row(average))
.chain(header)
.collect();
let lines = Colonnade::new(5, 100).unwrap().tabulate(table)?;
Ok(lines.join("\n"))
}
fn solve_and_keep_track_of_runtime(
(benchmark, content): (FileToBenchmark, String),
) -> AppResult<BenchmarkResult> {
let (day, task) = (benchmark.given_day(), benchmark.given_task());
let before = Instant::now();
let actual_ouput = solve_given(day, task, &content)?;
let after = Instant::now();
let how_long = after - before;
let result = BenchmarkResult::new(benchmark, actual_ouput, how_long);
Ok(result)
}
fn load_benchmarks(args: &BenchmarkCli) -> AppResult<Vec<(FileToBenchmark, String)>> {
let benchmarks = args
.files()
.iter()
.map(|path| {
let content = std::fs::read_to_string(path).map_err(|error| {
anyhow!(
"Could not read benchmark file at {:?}\n\
Details: {}",
path,
error
)
})?;
let parsed: Vec<FileToBenchmark> = ron::from_str(&content).map_err(|error| {
anyhow!(
"Content of benchmark file at ({:?}) is in an invalid ron format\n\
Details of invalid format: {}",
path,
error
)
})?;
Ok(parsed)
})
.collect::<AppResult<Vec<Vec<FileToBenchmark>>>>()?
.into_iter()
.flatten();
benchmarks
.into_iter()
.map(|benchmark| {
let where_to_look = benchmark.where_to_look();
let content = std::fs::read_to_string(where_to_look).map_err(|error| {
anyhow!(
"Could not read puzzle input file at {:?} for day {} and task {}\n\
Details: {}",
where_to_look,
benchmark.given_day(),
benchmark.given_task(),
error
)
})?;
Ok((benchmark, content))
})
.collect::<AppResult<Vec<(FileToBenchmark, String)>>>()
}

View file

@ -0,0 +1,66 @@
use std::time::Duration;
use crate::cli::{GivenDay, GivenTask};
use super::FileToBenchmark;
#[derive(Debug)]
pub struct BenchmarkResult {
task: GivenTask,
day: GivenDay,
how_long: Duration,
maybe_different_actual_output: Option<String>,
expected_output: String,
}
impl BenchmarkResult {
pub fn new(benchmarking: FileToBenchmark, actual_ouput: String, how_long: Duration) -> Self {
let (day, task, expected_output) = benchmarking.into();
let maybe_different_actual_output = if actual_ouput == expected_output {
None
} else {
Some(actual_ouput)
};
Self {
task,
day,
how_long,
maybe_different_actual_output,
expected_output,
}
}
pub fn matched_with_expected_output(&self) -> bool {
self.maybe_different_actual_output().is_none()
}
pub fn task(&self) -> GivenTask {
self.task
}
pub fn day(&self) -> GivenDay {
self.day
}
pub fn how_long_as_string(&self) -> String {
Self::convert_duration_to_secs_and_mili_txt(self.how_long)
}
pub fn maybe_different_actual_output(&self) -> Option<&str> {
self.maybe_different_actual_output.as_deref()
}
pub fn expected_output(&self) -> &str {
&self.expected_output
}
pub fn how_long(&self) -> Duration {
self.how_long
}
pub fn convert_duration_to_secs_and_mili_txt(how_long: Duration) -> String {
let secs = how_long.as_secs();
let mili_secs = how_long.as_nanos() % 1_000_000_000;
format!("{}:{}", secs, mili_secs)
}
}

View file

@ -0,0 +1,71 @@
use std::{
io,
path::{Path, PathBuf},
str::FromStr,
};
use derive_more::derive::Debug;
use ron::de::SpannedError;
use serde::{Deserialize, Serialize};
use crate::cli::{GivenDay, GivenTask};
use thiserror::Error;
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
pub struct FileToBenchmark {
given_day: GivenDay,
given_task: GivenTask,
where_to_look: PathBuf,
expected_output: String,
}
impl Into<(GivenDay, GivenTask, String)> for FileToBenchmark {
fn into(self) -> (GivenDay, GivenTask, String) {
(self.given_day, self.given_task, self.expected_output)
}
}
impl FromStr for FileToBenchmark {
type Err = CouldNotReadFileToBenchmark;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let path = PathBuf::from(s);
let content = std::fs::read_to_string(&path).map_err(|error| {
if error.kind() == io::ErrorKind::NotFound {
CouldNotReadFileToBenchmark::NotFound(s.to_owned())
} else {
error.into()
}
})?;
let parsed_content = ron::from_str(&content)?;
Ok(parsed_content)
}
}
#[derive(Debug, Error)]
pub enum CouldNotReadFileToBenchmark {
#[error("There is not file at {0:?}")]
NotFound(String),
#[error("Coud not read file at.\nDetails: {0}")]
IoError(#[from] io::Error),
#[error("File content is not in the correct format. Details: {0}")]
InvalidRon(#[from] SpannedError),
}
impl FileToBenchmark {
pub fn given_day(&self) -> GivenDay {
self.given_day
}
pub fn given_task(&self) -> GivenTask {
self.given_task
}
pub fn where_to_look(&self) -> &Path {
&self.where_to_look
}
pub fn expected_output(&self) -> &str {
&self.expected_output
}
}

View file

@ -0,0 +1,55 @@
use std::time::Duration;
use super::BenchmarkResult;
type MatrixReport = Vec<Vec<String>>;
pub fn create_header() -> std::iter::Once<Vec<String>> {
std::iter::once(vec![
"Day".to_string(),
"Task".to_string(),
"How long (Seconds:Mili)".to_string(),
"Expected".to_string(),
"Actual".to_string(),
])
}
pub fn create_sum_row(sum: Duration) -> std::iter::Once<Vec<String>> {
let passed_txt = BenchmarkResult::convert_duration_to_secs_and_mili_txt(sum);
std::iter::once(vec![
"Total".to_string(),
"Total".to_string(),
passed_txt,
"-".to_string(),
"-".to_string(),
])
}
pub fn create_average_row(average: Duration) -> std::iter::Once<Vec<String>> {
let passed_txt = BenchmarkResult::convert_duration_to_secs_and_mili_txt(average);
std::iter::once(vec![
"Average".to_string(),
"Average".to_string(),
passed_txt,
"-".to_string(),
"-".to_string(),
])
}
pub fn create_rows_for_every_solutions(loaded: Vec<BenchmarkResult>) -> MatrixReport {
let after_header = loaded
.into_iter()
.map(|result| {
vec![
result.day().to_string(),
result.task().to_string(),
result.how_long_as_string(),
result.expected_output().to_string(),
result
.maybe_different_actual_output()
.map(|unowned| unowned.to_string())
.unwrap_or_else(|| result.expected_output().to_string()),
]
})
.collect();
after_header
}

View file

@ -1,35 +1,29 @@
use clap::Parser; pub use benchmark_cli::BenchmarkCli;
mod given_day; use clap::{Parser, Subcommand};
mod given_task; pub use cli_solution_to_solve::CliSolutionToSolve;
pub use given_day::GivenDay; pub use given_day::GivenDay;
pub use given_task::GivenTask; pub use given_task::GivenTask;
mod benchmark_cli;
mod cli_solution_to_solve;
mod given_day;
mod given_task;
#[derive(Debug, Subcommand)]
pub enum AppCliSubcommands {
Solve(CliSolutionToSolve),
Benchmark(BenchmarkCli),
}
#[derive(Debug, Parser)] #[derive(Debug, Parser)]
pub struct AppCliArguments { pub struct AppCliArgs {
#[arg(short, long)] #[command(subcommand)]
day: GivenDay, sub_command: AppCliSubcommands,
#[arg(short, long)]
task: GivenTask,
#[arg(short, long)]
read_as_file: bool,
input: String,
} }
impl AppCliArguments { impl AppCliArgs {
pub fn day(&self) -> GivenDay { pub fn sub_command(&self) -> &AppCliSubcommands {
self.day &self.sub_command
}
pub fn task(&self) -> GivenTask {
self.task
}
pub fn input(&self) -> &str {
&self.input
}
pub fn read_as_file(&self) -> bool {
self.read_as_file
} }
} }

View file

@ -0,0 +1,14 @@
use std::path::PathBuf;
use clap::Parser;
#[derive(Debug, Parser)]
pub struct BenchmarkCli {
files: Vec<PathBuf>,
}
impl BenchmarkCli {
pub fn files(&self) -> &[PathBuf] {
&self.files
}
}

View file

@ -0,0 +1,32 @@
use clap::Parser;
use super::{GivenDay, GivenTask};
#[derive(Debug, Parser)]
pub struct CliSolutionToSolve {
#[arg(short, long)]
day: GivenDay,
#[arg(short, long)]
task: GivenTask,
#[arg(short, long)]
read_as_file: bool,
input: String,
}
impl CliSolutionToSolve {
pub fn day(&self) -> GivenDay {
self.day
}
pub fn task(&self) -> GivenTask {
self.task
}
pub fn input(&self) -> &str {
&self.input
}
pub fn read_as_file(&self) -> bool {
self.read_as_file
}
}

View file

@ -1,6 +1,7 @@
use std::{str::FromStr, sync::Arc}; use std::{str::FromStr, sync::Arc};
use derive_more::derive::Into; use derive_more::derive::{Display, Into};
use serde::{Deserialize, Serialize};
use thiserror::Error; use thiserror::Error;
use crate::constants; use crate::constants;
@ -16,7 +17,7 @@ pub enum InvalidGivenDayError {
InvalidRange(u32), InvalidRange(u32),
} }
#[derive(Debug, Copy, Clone, Into, PartialEq, Eq)] #[derive(Debug, Copy, Clone, Into, PartialEq, Eq, Serialize, Deserialize, Display)]
pub struct GivenDay(u32); pub struct GivenDay(u32);
impl GivenDay { impl GivenDay {

View file

@ -1,6 +1,7 @@
use std::{str::FromStr, sync::Arc}; use std::{str::FromStr, sync::Arc};
use derive_more::derive::Into; use derive_more::derive::{Display, Into};
use serde::{Deserialize, Serialize};
use thiserror::Error; use thiserror::Error;
use crate::constants; use crate::constants;
@ -18,7 +19,7 @@ pub enum InvalidGivenTaskError {
InvalidRange(u32), InvalidRange(u32),
} }
#[derive(Debug, Copy, Into, Clone, PartialEq, Eq)] #[derive(Debug, Copy, Into, Clone, PartialEq, Eq, Serialize, Deserialize, Display)]
pub struct GivenTask(u32); pub struct GivenTask(u32);
impl GivenTask { impl GivenTask {

View file

@ -1,3 +1,8 @@
pub mod benchmarking;
pub mod cli; pub mod cli;
pub mod constants; pub mod constants;
pub mod solutions; pub mod solutions;
pub mod solving_given;
pub type AppError = anyhow::Error;
pub type AppResult<T = ()> = anyhow::Result<T>;

View file

@ -1,14 +1,17 @@
use std::{fs, io, path::Path, process::ExitCode}; use std::process::ExitCode;
use advent_of_code_2023::{cli::AppCliArguments, solutions}; use advent_of_code_2023::{
benchmarking::execute_benchmark,
cli::{AppCliArgs, AppCliSubcommands},
solving_given::solve_given_from_cli,
AppResult,
};
use clap::Parser; use clap::Parser;
use thiserror::Error;
fn main() -> ExitCode { fn main() -> ExitCode {
let args = AppCliArguments::parse(); let args = AppCliArgs::parse();
env_logger::init(); env_logger::init();
let solution = solve_given(&args); let solution = handle_command(&args);
match solution { match solution {
Ok(found_solution) => { Ok(found_solution) => {
println!("{}", found_solution); println!("{}", found_solution);
@ -21,42 +24,9 @@ fn main() -> ExitCode {
} }
} }
fn solve_given(args: &AppCliArguments) -> Result<String, CouldNotSolveError> { fn handle_command(args: &AppCliArgs) -> AppResult<String> {
let all_solutions = solutions::create_solutions(); match args.sub_command() {
AppCliSubcommands::Solve(to_solve) => solve_given_from_cli(to_solve),
let found_task = { AppCliSubcommands::Benchmark(benchmark) => execute_benchmark(benchmark),
let day: u32 = args.day().into();
let task: u32 = args.task().into();
let found_day = all_solutions
.get(day.saturating_sub(1) as usize)
.ok_or_else(|| CouldNotSolveError::DayNotFound(day))?;
found_day
.get(task.saturating_sub(1) as usize)
.ok_or_else(|| CouldNotSolveError::TaskNotFound { day, task })
}?;
let puzzel_input = try_read_from_file_if_demanded(args)?;
let solved = (found_task)(&puzzel_input);
Ok(solved)
} }
fn try_read_from_file_if_demanded(args: &AppCliArguments) -> io::Result<String> {
let content = if args.read_as_file() {
let path = Path::new(args.input());
let input_as_file = fs::read_to_string(path)?;
input_as_file
} else {
args.input().to_string()
};
Ok(content)
}
#[derive(Debug, Error)]
enum CouldNotSolveError {
#[error("There is no solution for the day {0}")]
DayNotFound(u32),
#[error("There is not solution for task {task} under the day {day}")]
TaskNotFound { day: u32, task: u32 },
#[error("Could not read puzzel input from the given file\n {0}")]
CouldNotReadFromFile(#[from] io::Error),
} }

View file

@ -1,8 +1,12 @@
use std::sync::LazyLock;
use solutions_advent_of_code_2023::day5; use solutions_advent_of_code_2023::day5;
use solutions_advent_of_code_2023::day6; use solutions_advent_of_code_2023::day6;
use solutions_advent_of_code_2023::day7; use solutions_advent_of_code_2023::day7;
pub fn create_solutions() -> Vec<Vec<fn(&str) -> String>> { pub type SolutionMatrix = Vec<Vec<fn(&str) -> String>>;
pub static ALL_SOLUTIONS: LazyLock<SolutionMatrix> = LazyLock::new(|| create_solutions());
fn create_solutions() -> SolutionMatrix {
vec![ vec![
vec![not_implemented_yet, not_implemented_yet], vec![not_implemented_yet, not_implemented_yet],
vec![not_implemented_yet, not_implemented_yet], vec![not_implemented_yet, not_implemented_yet],

View file

@ -0,0 +1,51 @@
use std::{fs, io, path::Path};
use thiserror::Error;
use crate::{
cli::{CliSolutionToSolve, GivenDay, GivenTask},
solutions::ALL_SOLUTIONS,
AppResult,
};
pub fn solve_given(given_day: GivenDay, given_task: GivenTask, content: &str) -> AppResult<String> {
let found_task = {
let day: u32 = given_day.into();
let task: u32 = given_task.into();
let found_day = ALL_SOLUTIONS
.get(day.saturating_sub(1) as usize)
.ok_or_else(|| CouldNotSolveError::DayNotFound(day))?;
found_day
.get(task.saturating_sub(1) as usize)
.ok_or_else(|| CouldNotSolveError::TaskNotFound { day, task })
}?;
let solved = (found_task)(content);
Ok(solved)
}
pub fn solve_given_from_cli(args: &CliSolutionToSolve) -> AppResult<String> {
let puzzel_input = try_read_from_file_if_demanded(args)?;
let output = solve_given(args.day(), args.task(), &puzzel_input)?;
Ok(output)
}
fn try_read_from_file_if_demanded(args: &CliSolutionToSolve) -> io::Result<String> {
let content = if args.read_as_file() {
let path = Path::new(args.input());
let input_as_file = fs::read_to_string(path)?;
input_as_file
} else {
args.input().to_string()
};
Ok(content)
}
#[derive(Debug, Error)]
enum CouldNotSolveError {
#[error("There is no solution for the day {0}")]
DayNotFound(u32),
#[error("There is not solution for task {task} under the day {day}")]
TaskNotFound { day: u32, task: u32 },
#[error("Could not read puzzel input from the given file\n {0}")]
CouldNotReadFromFile(#[from] io::Error),
}

View file

@ -0,0 +1,38 @@
[
(
given_day: GivenDay(5),
given_task: GivenTask(2),
where_to_look: "file_input/day5_example.txt",
expected_output: "42",
),
(
given_day: GivenDay(5),
given_task: GivenTask(1),
where_to_look: "file_input/day5_example.txt",
expected_output: "42",
),
(
given_day: GivenDay(6),
given_task: GivenTask(1),
where_to_look: "file_input/day6_example.txt",
expected_output: "42",
),
(
given_day: GivenDay(6),
given_task: GivenTask(2),
where_to_look: "file_input/day6_example.txt",
expected_output: "42",
),
(
given_day: GivenDay(7),
given_task: GivenTask(1),
where_to_look: "file_input/day7_example.txt",
expected_output: "42",
),
(
given_day: GivenDay(7),
given_task: GivenTask(2),
where_to_look: "file_input/day7_example.txt",
expected_output: "42",
),
]

38
real_benchmark.ron Normal file
View file

@ -0,0 +1,38 @@
[
(
given_day: GivenDay(5),
given_task: GivenTask(2),
where_to_look: "real_puzzel_input/day5_real.txt",
expected_output: "42",
),
(
given_day: GivenDay(5),
given_task: GivenTask(1),
where_to_look: "real_puzzel_input/day5_real.txt",
expected_output: "42",
),
(
given_day: GivenDay(6),
given_task: GivenTask(1),
where_to_look: "real_puzzel_input/day6_real.txt",
expected_output: "42",
),
(
given_day: GivenDay(6),
given_task: GivenTask(2),
where_to_look: "real_puzzel_input/day6_real.txt",
expected_output: "42",
),
(
given_day: GivenDay(7),
given_task: GivenTask(1),
where_to_look: "real_puzzel_input/day7_real.txt",
expected_output: "42",
),
(
given_day: GivenDay(7),
given_task: GivenTask(2),
where_to_look: "real_puzzel_input/day7_real.txt",
expected_output: "42",
),
]