using AdventOfCode.Common; using AdventOfCode.Models; using Microsoft.VisualStudio.TestTools.UnitTesting; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.RegularExpressions; namespace AdventOfCode.Tests { [TestClass] public class AdventOfCodeTests { [TestMethod] public void TestAllDays() { var dataDirectoryPath = Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar + "Data"; var directoryInfo = new DirectoryInfo(dataDirectoryPath); var validDays = GetValidDays(directoryInfo.EnumerateFiles().Where(x => x.Name.EndsWith(".tst.data"))); var error = false; foreach (var validDay in validDays) { try { var year = Convert.ToInt32(validDay.Split("_")[0]); var day = Convert.ToInt32(validDay.Split("_")[1]); var part = validDay.Split("_")[2]; Console.WriteLine($"Testing {year} Day {day} Part {part}"); var input = $"{year}_Input_Day_{day}.tst.data"; var answerData = $"{year}_Answer_Day_{day}{part}.tst.data"; var aocDay = GetAOCDay(year, day); var version = (AOCVersion)Enum.Parse(typeof(AOCVersion), part.ToUpper()); if (ShouldSkipAnswerCheck(aocDay, version)) { Console.WriteLine("Answer is marked to be skipped and not compared (visual answer).\n"); continue; } var resp = aocDay.ExecuteDay(new AOCRequest() { Version = version, IgnoreLogMessages = true, Input = File.ReadAllText(dataDirectoryPath + Path.DirectorySeparatorChar + input) }); var actualAnswer = File.ReadAllText(dataDirectoryPath + Path.DirectorySeparatorChar + answerData); Console.WriteLine($"Asserting that (Answer) [{actualAnswer}] == [{resp.Answer}] (Tested)\n"); Assert.AreEqual(resp.Answer.ToString(), actualAnswer); } catch (Exception e) { Console.WriteLine($"Failed {validDay} with " + e.Message + " _ " + e.StackTrace); error = true; } } if (error) Assert.IsNotNull(null); } private bool ShouldSkipAnswerCheck(AOCDay day, AOCVersion version) { var ignoreAttribute = (IgnoreTestAnswerAttribute) Attribute.GetCustomAttribute(day.GetType(), typeof(IgnoreTestAnswerAttribute)); if (ignoreAttribute != null) { return ignoreAttribute.ShouldIgnoreAnswer(version); } return false; } private string[] GetValidDays(IEnumerable files) { var validDays = new List(); for (int year = 2022; year < 2025; year++) { for (int i = 1; i <= 25; i++) { var inputName = $"{year}_Input_Day_{i}.tst.data"; var partAAnswer = $"{year}_Answer_Day_{i}A.tst.data"; var partBAnswer = $"{year}_Answer_Day_{i}B.tst.data"; if (!files.Any(x => x.Name == inputName)) continue; if (files.Any(x => x.Name == partAAnswer)) { validDays.Add($"{year}_{i}_A"); } if (files.Any(x => x.Name == partBAnswer)) { validDays.Add($"{year}_{i}_B"); } } } return validDays.ToArray(); } private AOCDay GetAOCDay(int year, int day) { AOCDay aocDay = null; var type = typeof(AOCDay); var types = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(s => s.GetTypes()) .Where(p => type.IsAssignableFrom(p) && !p.IsInterface && !p.IsAbstract); foreach (var x in types) { var aocAttribute = (AOCAttribute)Attribute.GetCustomAttribute(x, typeof(AOCAttribute)); if (aocAttribute != null) { if (aocAttribute.Year == year && aocAttribute.Day == day) { aocDay = (AOCDay)(IAOCService)Activator.CreateInstance(x); } } else { var ns = x.Namespace; var className = x.Name; var dayParsed = 0; _ = int.TryParse(Regex.Replace(className, "[^0-9.]", ""), out dayParsed); var match = Regex.Match(ns, @"\d{4}"); if (match.Success) { var yearParsed = 0; _ = int.TryParse(match.Value, out yearParsed); if (yearParsed == year && dayParsed == day) { aocDay = (AOCDay)(IAOCService)Activator.CreateInstance(x); } } } if (aocDay != null) break; } return aocDay; } } }