├── .gitattributes ├── .github ├── FUNDING.yml └── workflows │ └── testRunner.yml ├── .gitignore ├── AdventOfCSharp.AdditionalProblemSolutionTests ├── AdventOfCSharp.AdditionalProblemSolutionTests.csproj ├── DependingRunnerTests.cs └── Problems │ └── Year2021 │ └── Day2.cs ├── AdventOfCSharp.AnalysisTestsBase ├── AdventOfCSharp.AnalysisTestsBase.csproj ├── Helpers │ ├── AoCSMetadataReferences.cs │ ├── AoCSUsingsProvider.cs │ └── RuntimeReferences.cs ├── Resources │ ├── ExampleAttribute.cs │ ├── NotProblem.cs │ └── TestSecretsContainerBase.cs └── Verifiers │ ├── CSharpAnalyzerVerifier`1+Test.cs │ ├── CSharpAnalyzerVerifier`1.cs │ ├── CSharpCodeFixVerifier`2+Test.cs │ ├── CSharpCodeFixVerifier`2.cs │ ├── CSharpCodeRefactoringVerifier`1+Test.cs │ ├── CSharpCodeRefactoringVerifier`1.cs │ └── CSharpVerifierHelper.cs ├── AdventOfCSharp.Analyzers.Tests ├── AdventOfCSharp.Analyzers.Tests.csproj ├── AnswerStringConverters │ ├── AnswerStringConverterAnalyzerTests.cs │ ├── AoCS0016_Tests.cs │ ├── AoCS0017_Tests.cs │ └── AoCS0018_Tests.cs ├── BaseAoCSDiagnosticTests.cs ├── FinalDaySolutions │ ├── AoCS0011_Tests.cs │ ├── AoCS0012_Tests.cs │ └── FinalDayAnalyzerTests.cs ├── GuRoslynAssertsSetup.cs ├── PartSolutions │ ├── AoCS0001_Tests.cs │ ├── AoCS0002_Tests.cs │ └── PartSolutionAnalyzerTests.cs ├── PartSolverAttributes │ ├── AoCS0013_Tests.cs │ ├── AoCS0014_Tests.cs │ ├── AoCS0015_Tests.cs │ └── PartSolverAttributeAnalyzerTests.cs ├── ProblemClassNamings │ ├── AoCS0004_Tests.cs │ ├── AoCS0005_Tests.cs │ ├── AoCS0006_Tests.cs │ ├── AoCS0007_Tests.cs │ └── ProblemInheritanceAnalyzerTests.cs ├── ProblemSolutionClassInheritance │ ├── AoCS0003_Tests.cs │ └── ProblemInheritanceAnalyzerTests.cs ├── SecretContainers │ ├── AoCS0008_Tests.cs │ └── SecretsContainerAnalyzerTests.cs └── SecretStringProperties │ ├── AoCS0080_Tests.cs │ ├── AoCS0081_Tests.cs │ ├── AoCS0082_Tests.cs │ ├── AoCS0083_Tests.cs │ ├── AoCS0084_Tests.cs │ ├── CookiesTests.cs │ └── SecretStringPropertyAnalyzerTests.cs ├── AdventOfCSharp.Analyzers ├── AdventOfCSharp.Analyzers.csproj ├── AnalyzerReleases.Shipped.md ├── AnalyzerReleases.Unshipped.md ├── AnswerStringConverterAnalyzer.cs ├── AoCSAnalyzer.cs ├── AoCSDiagnosticDescriptorStorage.cs ├── AssemblyAttributes.cs ├── DiagnosticStringResources.Designer.cs ├── DiagnosticStringResources.resx ├── Diagnostics.cs ├── FinalDayAnalyzer.cs ├── PartSolutionAnalyzer.cs ├── PartSolverAttributeAnalyzer.cs ├── ProblemAoCSAnalyzer.cs ├── ProblemClassNamingAnalyzer.cs ├── ProblemInheritanceAnalyzer.cs ├── SecretStringPropertyAnalyzer.cs ├── SecretsContainerAnalyzer.cs ├── SymbolExtensions.cs └── Utilities │ └── AccessorListSyntaxExtensions.cs ├── AdventOfCSharp.Benchmarking.Common ├── AdventOfCSharp.Benchmarking.Common.csproj ├── BenchmarkDescriberAttribute.cs └── BenchmarkingParts.cs ├── AdventOfCSharp.Benchmarking ├── AdventOfCSharp.Benchmarking.csproj ├── BenchmarkDescriber.cs ├── BenchmarkDescriberExecution.cs ├── BenchmarkDescriberHelpers.cs ├── ProblemBenchmark.cs └── ProblemBenchmarkRunner.cs ├── AdventOfCSharp.CodeAnalysis.Core ├── AdventOfCSharp.CodeAnalysis.Core.csproj ├── AoCSAnalysisHelpers.cs ├── Extensions │ ├── BaseTypeDeclarationSyntaxExtensions.cs │ ├── CompilationExtensions.cs │ ├── IAssemblyOrModuleSymbolExtensions.cs │ ├── ISymbolExtensions.cs │ └── SyntaxTreeExtensions.cs └── KnownSymbolNames.cs ├── AdventOfCSharp.CodeFixes.Tests ├── AdventOfCSharp.CodeFixes.Tests.csproj ├── BaseCodeFixTests.cs ├── FinalDayUsage │ ├── AoCS0011_CodeFixTests.cs │ └── FinalDayUserCodeFixTests.cs └── ProblemClassSimplification │ ├── AoCS0003_CodeFixTests.cs │ └── ProblemClassSimplifierCodeFixTests.cs ├── AdventOfCSharp.CodeFixes ├── AdventOfCSharp.CodeFixes.csproj ├── AoCSCodeFixProvider.cs ├── CodeFixStringResources.Designer.cs ├── CodeFixStringResources.resx ├── FinalDayUser.cs └── ProblemClassSimplifier.cs ├── AdventOfCSharp.Common ├── AdventOfCSharp.Common.csproj ├── ISecretsContainer.cs ├── PartSolutionAttribute.cs ├── PartSolutionStatus.cs ├── PartSolverAttribute.cs ├── PrintsToConsoleAttribute.cs ├── ProblemDate.cs ├── SecretStringPropertyAttribute.cs └── Utilities │ └── LookupTable.cs ├── AdventOfCSharp.Package ├── AdventOfCSharp.Analyzers.Package.csproj └── tools │ ├── install.ps1 │ └── uninstall.ps1 ├── AdventOfCSharp.ProblemSolutionResources ├── AdventOfCSharp.ProblemSolutionResources.csproj ├── Inputs │ └── 2021 │ │ ├── 1.txt │ │ └── 1T1.txt ├── Outputs │ └── 2021 │ │ ├── 1.txt │ │ └── 1T1.txt ├── Problems │ └── Year2021 │ │ └── Day1.cs └── ResourceFileManagement.cs ├── AdventOfCSharp.ProblemSolutionTests └── AdventOfCSharp.ProblemSolutionTests.csproj ├── AdventOfCSharp.SourceGenerators.Tests ├── AdventOfCSharp.SourceGenerators.Tests.csproj ├── BaseSourceGeneratorTestContainer.cs ├── BenchmarkDescriberSourceGeneratorTests.cs ├── Helpers │ ├── BenchmarkSpecificMetadataReferences.cs │ ├── RuntimeReferences.cs │ └── TestingSpecificMetadataReferences.cs ├── ProblemValidationTestSourceGeneratorTests.cs ├── SourceFileListExtensions.cs └── Verifiers │ └── CSharpSourceGeneratorVerifier.cs ├── AdventOfCSharp.SourceGenerators ├── AdventOfCSharp.SourceGenerators.csproj ├── BenchmarkDescriberSourceGenerator.cs ├── ProblemValidationTestSourceGenerator.cs └── Utilities │ ├── GeneratedSourceMappings.cs │ ├── GeneratorExecutionConductor.cs │ └── ProblemClassIdentifier.cs ├── AdventOfCSharp.Testing.Common ├── AdventOfCSharp.Testing.Common.csproj ├── AoCSTestAssemblyAttribute.cs └── TestingFrameworkIdentifiers.cs ├── AdventOfCSharp.Testing.MSTest ├── AdventOfCSharp.Testing.MSTest.csproj └── MSTestProblemValidationTests.cs ├── AdventOfCSharp.Testing.NUnit ├── AdventOfCSharp.Testing.NUnit.csproj └── NUnitProblemValidationTests.cs ├── AdventOfCSharp.Testing.Tests.Common ├── AdventOfCSharp.Testing.Tests.Common.csproj └── AoCSTestAssemblyInfo.cs ├── AdventOfCSharp.Testing.Tests.MSTest ├── AdventOfCSharp.Testing.Tests.MSTest.csproj └── TestDeclaration.cs ├── AdventOfCSharp.Testing.Tests.NUnit ├── AdventOfCSharp.Testing.Tests.NUnit.csproj └── TestDeclaration.cs ├── AdventOfCSharp.Testing.Tests.XUnit ├── AdventOfCSharp.Testing.Tests.XUnit.csproj └── TestDeclaration.cs ├── AdventOfCSharp.Testing.xUnit ├── AdventOfCSharp.Testing.XUnit.csproj └── XUnitProblemValidationTests.cs ├── AdventOfCSharp.Testing ├── AdventOfCSharp.Testing.csproj └── FrameworkUnboundProblemValidationTests.cs ├── AdventOfCSharp.Tests ├── AdventOfCSharp.Tests.csproj ├── InputGeneratorTests.cs ├── ProblemRunnerTests.cs └── Utilities │ └── LookupTableTests.cs ├── AdventOfCSharp.sln ├── AdventOfCSharp ├── AdventOfCSharp.csproj ├── AnswerStringConversion.cs ├── AnswerStringConverter.cs ├── BaseProgram.cs ├── BufferHeightHandlingMode.cs ├── ConsoleBufferHandling.cs ├── Cookies.cs ├── ExecutionTimePrinting.cs ├── Extensions │ ├── ArrayExtensions.cs │ ├── ConsoleColorExtensions.cs │ ├── IEnumerableExtensions.cs │ ├── ISetExtensions.cs │ ├── ResourceSetExtensions.cs │ ├── StringExtensions.cs │ └── TypeExtensions.cs ├── FancyPrinting.cs ├── FileHelpers.cs ├── FinalDay.cs ├── Generation │ ├── InputGenerator.cs │ └── SolutionTemplateGeneration.cs ├── GlobalUsings.cs ├── GlyphGridAnswerStringConverter.cs ├── IGlyphGrid.cs ├── Month.cs ├── Parser.cs ├── Problem.cs ├── ProblemFiles.cs ├── ProblemOutput.cs ├── ProblemRunner.cs ├── ProblemSolverMethodProvider.cs ├── ProblemValidator.cs ├── ProblemsIndex.cs ├── ResourceFileHelpers.cs ├── Resources │ ├── GlyphResources.Designer.cs │ ├── GlyphResources.resx │ ├── GridFont.cs │ ├── GridFontStore.cs │ ├── GridGlyph.cs │ ├── Infrauth.txt │ └── Stargazer.txt ├── SecretsStorage.cs ├── ServerClock.cs ├── Utilities │ ├── AppDomainHelpers.cs │ ├── ConsoleAvailability.cs │ ├── ConsolePrinting.cs │ └── NextValueCounterDictionary.cs └── WebsiteScraping.cs ├── LICENSE ├── README.md └── docs ├── analyzers └── rules │ ├── AoCS0001.md │ ├── AoCS0002.md │ ├── AoCS0003.md │ ├── AoCS0004.md │ ├── AoCS0005.md │ ├── AoCS0006.md │ ├── AoCS0007.md │ ├── AoCS0008.md │ ├── AoCS0011.md │ ├── AoCS0012.md │ ├── AoCS0013.md │ ├── AoCS0014.md │ ├── AoCS0015.md │ ├── AoCS0016.md │ ├── AoCS0017.md │ ├── AoCS0018.md │ ├── AoCS0080.md │ ├── AoCS0081.md │ ├── AoCS0082.md │ ├── AoCS0083.md │ ├── AoCS0084.md │ └── index.md ├── benchmarks.md ├── cookie_retrieval.png ├── index.md ├── input-generation.md ├── setup-secrets.md └── unit-tests.md /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | patreon: Rekkon 4 | custom: buymeacoffee.com/Rekkon 5 | -------------------------------------------------------------------------------- /.github/workflows/testRunner.yml: -------------------------------------------------------------------------------- 1 | name: Run Tests 2 | 3 | on: [push] 4 | 5 | jobs: 6 | run-tests: 7 | runs-on: windows-latest 8 | 9 | strategy: 10 | matrix: 11 | project: 12 | - name: Tests 13 | - name: AdditionalProblemSolutionTests 14 | - name: Analyzers.Tests 15 | - name: CodeFixes.Tests 16 | - name: SourceGenerators.Tests 17 | 18 | - name: Testing.Tests.MSTest 19 | - name: Testing.Tests.NUnit 20 | - name: Testing.Tests.XUnit 21 | 22 | steps: 23 | - name: Setup .NET 6.0 24 | uses: actions/setup-dotnet@v1 25 | with: 26 | dotnet-version: 6.0.x 27 | 28 | - name: Checkout Code 29 | uses: actions/checkout@v1 30 | 31 | - name: Run Tests in Project 32 | run: dotnet test ${{ matrix.project.directory }}AdventOfCSharp.${{ matrix.project.name }}/AdventOfCSharp.${{ matrix.project.name }}.csproj 33 | -------------------------------------------------------------------------------- /AdventOfCSharp.AdditionalProblemSolutionTests/AdventOfCSharp.AdditionalProblemSolutionTests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net6.0 5 | enable 6 | 7 | false 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | all 16 | runtime; build; native; contentfiles; analyzers; buildtransitive 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /AdventOfCSharp.AdditionalProblemSolutionTests/DependingRunnerTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | 3 | namespace AdventOfCSharp.AdditionalProblemSolutionTests; 4 | 5 | public class DependingRunnerTests 6 | { 7 | [Test] 8 | public void ValidateProblem() 9 | { 10 | // Transitively inherited problem type from dependency 11 | AssertExistence(2021, 1); 12 | // Implemented in this project 13 | AssertExistence(2021, 2); 14 | } 15 | private static void AssertExistence(int year, int day) 16 | { 17 | Assert.NotNull(ProblemsIndex.Instance[year, day].ProblemType.ProblemClass); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /AdventOfCSharp.AdditionalProblemSolutionTests/Problems/Year2021/Day2.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCSharp.AdditionalProblemSolutionTests.Problems.Year2021; 2 | 3 | public class Day2 : Problem 4 | { 5 | public const int Part1Result = 142; 6 | public const int Part2Result = 234; 7 | 8 | public override int SolvePart1() 9 | { 10 | return Part1Result; 11 | } 12 | public override int SolvePart2() 13 | { 14 | return Part2Result; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /AdventOfCSharp.AnalysisTestsBase/AdventOfCSharp.AnalysisTestsBase.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net6.0 5 | 10.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /AdventOfCSharp.AnalysisTestsBase/Helpers/AoCSMetadataReferences.cs: -------------------------------------------------------------------------------- 1 | using AdventOfCSharp.AnalysisTestsBase.Resources; 2 | using Microsoft.CodeAnalysis; 3 | using RoseLynn; 4 | using System.Collections.Immutable; 5 | 6 | namespace AdventOfCSharp.AnalysisTestsBase.Helpers; 7 | 8 | public static class AoCSMetadataReferences 9 | { 10 | public static readonly ImmutableArray BaseReferences = ImmutableArray.Create(new MetadataReference[] 11 | { 12 | // AdventOfCSharp 13 | MetadataReferenceFactory.CreateFromType(), 14 | 15 | // AdventOfCSharp.Common 16 | MetadataReferenceFactory.CreateFromType(), 17 | 18 | // AdventOfCSharp.AnalysisTestsBase.Resources 19 | MetadataReferenceFactory.CreateFromType(), 20 | }); 21 | } 22 | -------------------------------------------------------------------------------- /AdventOfCSharp.AnalysisTestsBase/Helpers/AoCSUsingsProvider.cs: -------------------------------------------------------------------------------- 1 | using RoseLynn.Testing; 2 | 3 | namespace AdventOfCSharp.AnalysisTestsBase; 4 | 5 | public sealed class AoCSUsingsProvider : UsingsProviderBase 6 | { 7 | public static readonly AoCSUsingsProvider Instance = new(); 8 | 9 | public const string DefaultUsings = 10 | @" 11 | using AdventOfCSharp; 12 | using AdventOfCSharp.AnalysisTestsBase.Resources; 13 | using System; 14 | using System.Collections; 15 | using System.Collections.Generic; 16 | "; 17 | 18 | public override string DefaultNecessaryUsings => DefaultUsings; 19 | 20 | private AoCSUsingsProvider() { } 21 | } 22 | -------------------------------------------------------------------------------- /AdventOfCSharp.AnalysisTestsBase/Helpers/RuntimeReferences.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis; 2 | using Microsoft.CodeAnalysis.Testing; 3 | using RoseLynn; 4 | using System.IO; 5 | 6 | namespace AdventOfCSharp.AnalysisTestsBase.Helpers; 7 | 8 | public static class RuntimeReferences 9 | { 10 | public static readonly ReferenceAssemblies NET6_0Reference = new( 11 | "net6.0", 12 | new PackageIdentity( 13 | "Microsoft.NETCore.App.Ref", "6.0.0"), 14 | Path.Combine("ref", "net6.0")); 15 | 16 | public static readonly MetadataReference NETStandard2_0MetadataReference = MetadataReferenceFactory.CreateFromType(); 17 | } 18 | -------------------------------------------------------------------------------- /AdventOfCSharp.AnalysisTestsBase/Resources/ExampleAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace AdventOfCSharp.AnalysisTestsBase.Resources; 4 | 5 | [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] 6 | public class ExampleAttribute : Attribute 7 | { 8 | public ExampleAttribute(params object[] _) { } 9 | } 10 | -------------------------------------------------------------------------------- /AdventOfCSharp.AnalysisTestsBase/Resources/NotProblem.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCSharp.AnalysisTestsBase.Resources; 2 | 3 | public abstract class NotProblem 4 | { 5 | } 6 | public abstract class NotProblem : NotProblem 7 | { 8 | public abstract T1 SolvePart1(); 9 | public abstract T2 SolvePart2(); 10 | } 11 | public abstract class NotProblem : NotProblem 12 | { 13 | } 14 | -------------------------------------------------------------------------------- /AdventOfCSharp.AnalysisTestsBase/Resources/TestSecretsContainerBase.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCSharp.AnalysisTestsBase.Resources; 2 | 3 | public abstract class TestSecretsContainerBase : ISecretsContainer 4 | { 5 | public const string SecretsType = "Test"; 6 | } 7 | -------------------------------------------------------------------------------- /AdventOfCSharp.AnalysisTestsBase/Verifiers/CSharpAnalyzerVerifier`1+Test.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis.CSharp.Testing; 2 | using Microsoft.CodeAnalysis.Diagnostics; 3 | using Microsoft.CodeAnalysis.Testing.Verifiers; 4 | 5 | namespace AdventOfCSharp.AnalysisTestsBase.Verifiers; 6 | 7 | public static partial class CSharpAnalyzerVerifier 8 | where TAnalyzer : DiagnosticAnalyzer, new() 9 | { 10 | public class Test : CSharpAnalyzerTest 11 | { 12 | public Test() 13 | { 14 | CSharpVerifierHelper.SetupNET6AndAoCSDependencies(this); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /AdventOfCSharp.AnalysisTestsBase/Verifiers/CSharpAnalyzerVerifier`1.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis; 2 | using Microsoft.CodeAnalysis.CSharp.Testing; 3 | using Microsoft.CodeAnalysis.Diagnostics; 4 | using Microsoft.CodeAnalysis.Testing; 5 | using Microsoft.CodeAnalysis.Testing.Verifiers; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | 9 | namespace AdventOfCSharp.AnalysisTestsBase.Verifiers; 10 | 11 | public static partial class CSharpAnalyzerVerifier 12 | where TAnalyzer : DiagnosticAnalyzer, new() 13 | { 14 | /// 15 | public static DiagnosticResult Diagnostic() 16 | => CSharpAnalyzerVerifier.Diagnostic(); 17 | 18 | /// 19 | public static DiagnosticResult Diagnostic(string diagnosticId) 20 | => CSharpAnalyzerVerifier.Diagnostic(diagnosticId); 21 | 22 | /// 23 | public static DiagnosticResult Diagnostic(DiagnosticDescriptor descriptor) 24 | => CSharpAnalyzerVerifier.Diagnostic(descriptor); 25 | 26 | /// 27 | public static async Task VerifyAnalyzerAsync(string source, params DiagnosticResult[] expected) 28 | { 29 | var test = new Test 30 | { 31 | TestCode = source, 32 | }; 33 | 34 | test.ExpectedDiagnostics.AddRange(expected); 35 | await test.RunAsync(CancellationToken.None); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /AdventOfCSharp.AnalysisTestsBase/Verifiers/CSharpCodeFixVerifier`2+Test.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis.CodeFixes; 2 | using Microsoft.CodeAnalysis.CSharp.Testing; 3 | using Microsoft.CodeAnalysis.Diagnostics; 4 | using Microsoft.CodeAnalysis.Testing.Verifiers; 5 | 6 | namespace AdventOfCSharp.AnalysisTestsBase.Verifiers; 7 | 8 | public static partial class CSharpCodeFixVerifier 9 | where TAnalyzer : DiagnosticAnalyzer, new() 10 | where TCodeFix : CodeFixProvider, new() 11 | { 12 | public class Test : CSharpCodeFixTest 13 | { 14 | public Test() 15 | { 16 | CSharpVerifierHelper.SetupNET6AndAoCSDependencies(this); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /AdventOfCSharp.AnalysisTestsBase/Verifiers/CSharpCodeRefactoringVerifier`1+Test.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis.CodeRefactorings; 2 | using Microsoft.CodeAnalysis.CSharp.Testing; 3 | using Microsoft.CodeAnalysis.Testing.Verifiers; 4 | 5 | namespace AdventOfCSharp.AnalysisTestsBase.Verifiers; 6 | 7 | public static partial class CSharpCodeRefactoringVerifier 8 | where TCodeRefactoring : CodeRefactoringProvider, new() 9 | { 10 | public class Test : CSharpCodeRefactoringTest 11 | { 12 | public Test() 13 | { 14 | SolutionTransforms.Add((solution, projectId) => 15 | { 16 | var compilationOptions = solution.GetProject(projectId).CompilationOptions; 17 | compilationOptions = compilationOptions.WithSpecificDiagnosticOptions( 18 | compilationOptions.SpecificDiagnosticOptions.SetItems(CSharpVerifierHelper.NullableWarnings)); 19 | solution = solution.WithProjectCompilationOptions(projectId, compilationOptions); 20 | 21 | return solution; 22 | }); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /AdventOfCSharp.AnalysisTestsBase/Verifiers/CSharpCodeRefactoringVerifier`1.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis.CodeRefactorings; 2 | using Microsoft.CodeAnalysis.Testing; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | 6 | namespace AdventOfCSharp.AnalysisTestsBase.Verifiers; 7 | 8 | public static partial class CSharpCodeRefactoringVerifier 9 | where TCodeRefactoring : CodeRefactoringProvider, new() 10 | { 11 | /// 12 | public static async Task VerifyRefactoringAsync(string source, string fixedSource) 13 | { 14 | await VerifyRefactoringAsync(source, DiagnosticResult.EmptyDiagnosticResults, fixedSource); 15 | } 16 | 17 | /// 18 | public static async Task VerifyRefactoringAsync(string source, DiagnosticResult expected, string fixedSource) 19 | { 20 | await VerifyRefactoringAsync(source, new[] { expected }, fixedSource); 21 | } 22 | 23 | /// 24 | public static async Task VerifyRefactoringAsync(string source, DiagnosticResult[] expected, string fixedSource) 25 | { 26 | var test = new Test 27 | { 28 | TestCode = source, 29 | FixedCode = fixedSource, 30 | }; 31 | 32 | test.ExpectedDiagnostics.AddRange(expected); 33 | await test.RunAsync(CancellationToken.None); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers.Tests/AdventOfCSharp.Analyzers.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net6.0 5 | 10.0 6 | 7 | false 8 | 9 | true 10 | true 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers.Tests/AnswerStringConverters/AnswerStringConverterAnalyzerTests.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCSharp.Analyzers.Tests.AnswerStringConverters; 2 | 3 | public abstract class AnswerStringConverterAnalyzerTests : BaseAoCSDiagnosticTests 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers.Tests/AnswerStringConverters/AoCS0016_Tests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | 3 | namespace AdventOfCSharp.Analyzers.Tests.AnswerStringConverters; 4 | 5 | [TestClass] 6 | public sealed class AoCS0016_Tests : AnswerStringConverterAnalyzerTests 7 | { 8 | [TestMethod] 9 | public void DirectlyInheritAnswerStringConverter() 10 | { 11 | var testCode = 12 | @" 13 | namespace AoC.Converters; 14 | 15 | public class RawAnswerStringConverter : ↓AnswerStringConverter 16 | { 17 | public string Convert(object value) 18 | { 19 | return value.ToString(); 20 | } 21 | } 22 | "; 23 | 24 | AssertDiagnosticsWithUsings(testCode); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers.Tests/AnswerStringConverters/AoCS0017_Tests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | 3 | namespace AdventOfCSharp.Analyzers.Tests.AnswerStringConverters; 4 | 5 | [TestClass] 6 | public sealed class AoCS0017_Tests : AnswerStringConverterAnalyzerTests 7 | { 8 | [TestMethod] 9 | public void ObjectAnswerStringConverter() 10 | { 11 | var testCode = 12 | @" 13 | namespace AoC.Converters; 14 | 15 | public class ObjectAnswerStringConverter : ↓AnswerStringConverter 16 | { 17 | public override string Convert(object value) 18 | { 19 | return value.ToString(); 20 | } 21 | } 22 | "; 23 | 24 | AssertDiagnosticsWithUsings(testCode); 25 | } 26 | [TestMethod] 27 | public void Irrelevant() 28 | { 29 | var testCode = 30 | @" 31 | namespace AoC.Converters; 32 | 33 | public interface IIrrelevant { } 34 | 35 | public class Irrelevant : IIrrelevant 36 | { 37 | } 38 | "; 39 | 40 | ValidateCodeWithUsings(testCode); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers.Tests/AnswerStringConverters/AoCS0018_Tests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | 3 | namespace AdventOfCSharp.Analyzers.Tests.AnswerStringConverters; 4 | 5 | [TestClass] 6 | public sealed class AoCS0018_Tests : AnswerStringConverterAnalyzerTests 7 | { 8 | [DataTestMethod] 9 | [DataRow("byte")] 10 | [DataRow("short")] 11 | [DataRow("int")] 12 | [DataRow("long")] 13 | [DataRow("sbyte")] 14 | [DataRow("ushort")] 15 | [DataRow("uint")] 16 | [DataRow("ulong")] 17 | [DataRow("float")] 18 | [DataRow("double")] 19 | [DataRow("decimal")] 20 | [DataRow("string")] 21 | public void FrameworkHandledType(string typeKeyword) 22 | { 23 | var testCode = 24 | $@" 25 | namespace AoC.Converters; 26 | 27 | public class HandledTypeAnswerStringConverter : ↓AnswerStringConverter<{typeKeyword}> 28 | {{ 29 | public override string Convert({typeKeyword} value) 30 | {{ 31 | return value.ToString(); 32 | }} 33 | }} 34 | "; 35 | 36 | AssertDiagnosticsWithUsings(testCode); 37 | } 38 | [TestMethod] 39 | public void CustomData() 40 | { 41 | var testCode = 42 | @" 43 | namespace AoC.Converters; 44 | 45 | public interface ICustomData { } 46 | 47 | public class CustomData : AnswerStringConverter 48 | { 49 | public override string Convert(ICustomData custom) 50 | { 51 | return custom.ToString(); 52 | } 53 | } 54 | "; 55 | 56 | ValidateCodeWithUsings(testCode); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers.Tests/FinalDaySolutions/AoCS0011_Tests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | 3 | namespace AdventOfCSharp.Analyzers.Tests.FinalDaySolutions; 4 | 5 | [TestClass] 6 | public sealed class AoCS0011_Tests : FinalDayAnalyzerTests 7 | { 8 | [TestMethod] 9 | public void Problem1() 10 | { 11 | var testCode = 12 | $@" 13 | namespace AoC.Year2021; 14 | 15 | public class Day25 : ↓Problem 16 | {{ 17 | public override int SolvePart1() => -1; 18 | public override int SolvePart2() => -2; 19 | }} 20 | "; 21 | 22 | AssertDiagnosticsWithUsings(testCode); 23 | } 24 | [TestMethod] 25 | public void Problem2() 26 | { 27 | var testCode = 28 | $@" 29 | namespace AoC.Year2021; 30 | 31 | public class Day25 : ↓Problem 32 | {{ 33 | public override int SolvePart1() => -1; 34 | public override string SolvePart2() => default; 35 | }} 36 | "; 37 | 38 | AssertDiagnosticsWithUsings(testCode); 39 | } 40 | [TestMethod] 41 | public void FinalDay() 42 | { 43 | var testCode = 44 | $@" 45 | namespace AoC.Year2021; 46 | 47 | public class Day25 : FinalDay 48 | {{ 49 | public override int SolvePart1() => -1; 50 | }} 51 | "; 52 | 53 | ValidateCodeWithUsings(testCode); 54 | } 55 | [TestMethod] 56 | public void CustomFinalDay() 57 | { 58 | var testCode = 59 | $@" 60 | namespace AoC.Year2021; 61 | 62 | public class Day25 : CustomFinalDay 63 | {{ 64 | public override int SolvePart1() => -1; 65 | }} 66 | 67 | public abstract class CustomFinalDay : FinalDay {{ }} 68 | "; 69 | 70 | ValidateCodeWithUsings(testCode); 71 | } 72 | 73 | [TestMethod] 74 | public void NonProblemSolutionClass() 75 | { 76 | const string testCode = 77 | @" 78 | namespace AoC.Year2021 79 | 80 | public class Day25 : NotProblem 81 | { 82 | public override int SolvePart1() => default; 83 | public override string SolvePart2() => default; 84 | } 85 | "; 86 | 87 | ValidateCodeWithUsings(testCode); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers.Tests/FinalDaySolutions/AoCS0012_Tests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | 3 | namespace AdventOfCSharp.Analyzers.Tests.FinalDaySolutions; 4 | 5 | [TestClass] 6 | public sealed class AoCS0012_Tests : FinalDayAnalyzerTests 7 | { 8 | [TestMethod] 9 | public void FinalDay() 10 | { 11 | var testCode = 12 | $@" 13 | namespace AoC.Year2021; 14 | 15 | public class Day2 : ↓FinalDay 16 | {{ 17 | public override int SolvePart1() => -1; 18 | }} 19 | "; 20 | 21 | AssertDiagnosticsWithUsings(testCode); 22 | } 23 | [TestMethod] 24 | public void InvalidCustomFinalDay() 25 | { 26 | var testCode = 27 | $@" 28 | namespace AoC.Year2021; 29 | 30 | public class Day2 : ↓CustomFinalDay 31 | {{ 32 | public override int SolvePart1() => -1; 33 | }} 34 | 35 | public abstract class CustomFinalDay : FinalDay {{ }} 36 | "; 37 | 38 | AssertDiagnosticsWithUsings(testCode); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers.Tests/FinalDaySolutions/FinalDayAnalyzerTests.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCSharp.Analyzers.Tests.FinalDaySolutions; 2 | 3 | public abstract class FinalDayAnalyzerTests : BaseAoCSDiagnosticTests 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers.Tests/GuRoslynAssertsSetup.cs: -------------------------------------------------------------------------------- 1 | using Gu.Roslyn.Asserts; 2 | using System.Runtime.CompilerServices; 3 | 4 | namespace AdventOfCSharp.Analyzers.Tests; 5 | 6 | public static class GuRoslynAssertsSetup 7 | { 8 | [ModuleInitializer] 9 | public static void Setup() 10 | { 11 | Settings.Default = Settings.Default 12 | .WithAllowedCompilerDiagnostics(AllowedCompilerDiagnostics.WarningsAndErrors) 13 | .WithMetadataReferences(MetadataReferences.Transitive(typeof(GuRoslynAssertsSetup), typeof(Problem))) 14 | .WithCompilationOptions(Settings.Default.CompilationOptions.WithSuppressedDiagnostics(suppressedDiagnostics)); 15 | } 16 | 17 | private static readonly string[] suppressedDiagnostics = new[] 18 | { 19 | "CS8019" 20 | }; 21 | } -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers.Tests/PartSolutions/AoCS0001_Tests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | 3 | namespace AdventOfCSharp.Analyzers.Tests.PartSolutions; 4 | 5 | [TestClass] 6 | public sealed class AoCS0001_Tests : PartSolutionAnalyzerTests 7 | { 8 | [TestMethod] 9 | public void InvalidPartSolutionAttribute() 10 | { 11 | const string testCode = 12 | @" 13 | namespace AoC.Year2021; 14 | 15 | public class Day1 : Problem 16 | { 17 | [PartSolution(PartSolutionStatus.WIP)] 18 | public override int SolvePart1() => -1; 19 | [PartSolution(PartSolutionStatus.WIP)] 20 | public override int SolvePart2() => -2; 21 | 22 | [↓PartSolution(PartSolutionStatus.WIP)] 23 | public static void RandomFunction() { } 24 | 25 | [PartSolution(PartSolutionStatus.WIP)] 26 | [PartSolver] 27 | public int RandomSolver() => 1; 28 | } 29 | "; 30 | 31 | AssertDiagnosticsWithUsings(testCode); 32 | } 33 | [TestMethod] 34 | public void InvalidPartSolutionAttributeNotProblem() 35 | { 36 | const string testCode = 37 | @" 38 | namespace AoC.Year2021; 39 | 40 | public class Day1 : NotProblem 41 | { 42 | [↓PartSolution(PartSolutionStatus.WIP)] 43 | public override int SolvePart1() => -1; 44 | [↓PartSolution(PartSolutionStatus.WIP)] 45 | public override int SolvePart2() => -2; 46 | } 47 | "; 48 | 49 | AssertDiagnosticsWithUsings(testCode); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers.Tests/PartSolutions/AoCS0002_Tests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | 3 | namespace AdventOfCSharp.Analyzers.Tests.PartSolutions; 4 | 5 | [TestClass] 6 | public sealed class AoCS0002_Tests : PartSolutionAnalyzerTests 7 | { 8 | [TestMethod] 9 | public void InvalidPartSolutionStatusValues() 10 | { 11 | InvalidPartSolutionStatusValues(EnumLiteralCodeString(nameof(PartSolutionStatus.WIP)), false); 12 | InvalidPartSolutionStatusValues(EnumLiteralCodeString(nameof(PartSolutionStatus.Valid)), false); 13 | InvalidPartSolutionStatusValues(EnumLiteralCodeString(nameof(PartSolutionStatus.UnavailableLockedStar)), false); 14 | 15 | InvalidPartSolutionStatusValues(IntegerAsEnumLiteralCodeString(-1), true); 16 | InvalidPartSolutionStatusValues(IntegerAsEnumLiteralCodeString(1000), true); 17 | InvalidPartSolutionStatusValues(IntegerAsEnumLiteralCodeString(534789), true); 18 | } 19 | 20 | [TestMethod] 21 | public void IrrelevantAttribute() 22 | { 23 | string testCode = 24 | @" 25 | namespace AoC.Year2021; 26 | 27 | public class Day1 : Problem 28 | { 29 | [Random((DayOfWeek)456)] 30 | public override int SolvePart1() => -1; 31 | [Random((DayOfWeek)789)] 32 | public override int SolvePart2() => -2; 33 | } 34 | 35 | public sealed class RandomAttribute : Attribute 36 | { 37 | public RandomAttribute(DayOfWeek day) { } 38 | } 39 | "; 40 | 41 | ValidateCodeWithUsings(testCode); 42 | 43 | } 44 | 45 | private void InvalidPartSolutionStatusValues(string enumValueCode, bool assert) 46 | { 47 | string testCode = 48 | $@" 49 | namespace AoC.Year2021; 50 | 51 | public class Day1 : Problem 52 | {{ 53 | [PartSolution(↓{enumValueCode})] 54 | public override int SolvePart1() => -1; 55 | [PartSolution(↓{enumValueCode})] 56 | public override int SolvePart2() => -2; 57 | }} 58 | "; 59 | 60 | AssertOrValidateWithUsings(testCode, assert); 61 | } 62 | private static string EnumLiteralCodeString(string valueName) 63 | { 64 | return $"{nameof(PartSolutionStatus)}.{valueName}"; 65 | } 66 | private static string IntegerAsEnumLiteralCodeString(int value) 67 | { 68 | return $"({nameof(PartSolutionStatus)})({value})"; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers.Tests/PartSolutions/PartSolutionAnalyzerTests.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCSharp.Analyzers.Tests.PartSolutions; 2 | 3 | public abstract class PartSolutionAnalyzerTests : BaseAoCSDiagnosticTests 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers.Tests/PartSolverAttributes/AoCS0013_Tests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | 3 | namespace AdventOfCSharp.Analyzers.Tests.PartSolverAttributes; 4 | 5 | [TestClass] 6 | public sealed class AoCS0013_Tests : PartSolverAttributeAnalyzerTests 7 | { 8 | [TestMethod] 9 | public void NotProblemClass() 10 | { 11 | var testCode = 12 | @" 13 | namespace AoC.Random; 14 | 15 | public class Nothing : NotProblem 16 | { 17 | [↓PartSolver(""Solver"", SolverKind = PartSolverKind.Custom)] 18 | public int Solver() => -1; 19 | } 20 | "; 21 | 22 | AssertDiagnosticsWithUsings(testCode); 23 | } 24 | [TestMethod] 25 | public void InvalidSignaturePartSolvers() 26 | { 27 | var testCode = 28 | @" 29 | namespace AoC.Year2021; 30 | 31 | public class Day1 : Problem 32 | { 33 | public override int SolvePart1() => -1; 34 | public override int SolvePart2() => -2; 35 | 36 | [↓PartSolver(""Parameter"", SolverKind = PartSolverKind.Custom)] 37 | public int Parameter(int x) => x; 38 | [↓PartSolver(""Generic"", SolverKind = PartSolverKind.Custom)] 39 | public int Generic() => -1; 40 | [↓PartSolver(""Void"", SolverKind = PartSolverKind.Custom)] 41 | public void Void() { } 42 | 43 | [↓PartSolver(""Static"", SolverKind = PartSolverKind.Custom)] 44 | public static int Static() => -1; 45 | 46 | [↓PartSolver(""ProtectedInternal"", SolverKind = PartSolverKind.Custom)] 47 | protected internal int ProtectedInternal() => -1; 48 | [↓PartSolver(""Internal"", SolverKind = PartSolverKind.Custom)] 49 | internal int Internal() => -1; 50 | [↓PartSolver(""Protected"", SolverKind = PartSolverKind.Custom)] 51 | protected int Protected() => -1; 52 | [↓PartSolver(""PrivateProtected"", SolverKind = PartSolverKind.Custom)] 53 | private protected int PrivateProtected() => -1; 54 | [↓PartSolver(""Private"", SolverKind = PartSolverKind.Custom)] 55 | private int Private() => -1; 56 | } 57 | "; 58 | 59 | AssertDiagnosticsWithUsings(testCode); 60 | } 61 | 62 | [TestMethod] 63 | public void Problem2Declarer() 64 | { 65 | var testCode = 66 | @" 67 | public abstract class Problem : Problem 68 | { 69 | [PartSolver(""Part 1"", SolverKind = PartSolverKind.Custom)] 70 | public abstract T1 SolvePart1(); 71 | [PartSolver(""Part 2"", SolverKind = PartSolverKind.Custom)] 72 | public abstract T2 SolvePart2(); 73 | } 74 | "; 75 | 76 | ValidateCodeWithUsings(testCode); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers.Tests/PartSolverAttributes/AoCS0014_Tests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | 3 | namespace AdventOfCSharp.Analyzers.Tests.PartSolverAttributes; 4 | 5 | [TestClass] 6 | public sealed class AoCS0014_Tests : PartSolverAttributeAnalyzerTests 7 | { 8 | [TestMethod] 9 | public void DuplicateCustomPartName() 10 | { 11 | var testCode = 12 | @" 13 | namespace AoC.Year2022; 14 | 15 | public abstract class SomeCustomProblem : Problem 16 | { 17 | [PartSolver(""Part 3"", SolverKind = PartSolverKind.Custom)] 18 | public int SolvePart3() => -1; 19 | 20 | [PartSolver(↓""Part 4"", SolverKind = PartSolverKind.Custom)] 21 | public int SolvePart4A() => -1; 22 | [PartSolver(partName: ↓""Part 4"", SolverKind = PartSolverKind.Custom)] 23 | public int SolvePart4B() => -1; 24 | } 25 | "; 26 | 27 | AssertDiagnosticsWithUsings(testCode); 28 | } 29 | 30 | [TestMethod] 31 | public void DuplicateInheritedPartName() 32 | { 33 | var testCode = 34 | @" 35 | namespace AoC.Year2022; 36 | 37 | public abstract class SomeCustomProblem : Problem 38 | { 39 | [PartSolver(↓""Part 2"", SolverKind = PartSolverKind.Custom)] 40 | public int SolvePart2B() => -1; 41 | } 42 | "; 43 | 44 | AssertDiagnosticsWithUsings(testCode); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers.Tests/PartSolverAttributes/AoCS0015_Tests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | 3 | namespace AdventOfCSharp.Analyzers.Tests.PartSolverAttributes; 4 | 5 | [TestClass] 6 | public sealed class AoCS0015_Tests : PartSolverAttributeAnalyzerTests 7 | { 8 | [TestMethod] 9 | public void OverflowingCharacters() 10 | { 11 | var testCode = 12 | @" 13 | namespace AoC.Year2022; 14 | 15 | public abstract class SomeCustomProblem : Problem 16 | { 17 | [PartSolver(""01234567890123456789"", SolverKind = PartSolverKind.EasterEgg)] 18 | public int Exactly20() => -1; 19 | [PartSolver(↓""01234567890123456789abc"", SolverKind = PartSolverKind.EasterEgg)] 20 | public int Over20() => -1; 21 | [PartSolver(partName: ↓""01234567890123456789abc"", SolverKind = PartSolverKind.EasterEgg)] 22 | public int NamedOver20() => -1; 23 | [PartSolver(""0123456789\x69123456789"", SolverKind = PartSolverKind.EasterEgg)] 24 | public int EscapedCharactersExactly20() => -1; 25 | [PartSolver(""\x69\x69\x69\x69\x69\x69\x69\x69\x69\x69"", SolverKind = PartSolverKind.EasterEgg)] 26 | public int EscapedCharactersExactly10() => -1; 27 | } 28 | "; 29 | 30 | AssertDiagnosticsWithUsings(testCode); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers.Tests/PartSolverAttributes/PartSolverAttributeAnalyzerTests.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCSharp.Analyzers.Tests.PartSolverAttributes; 2 | 3 | public abstract class PartSolverAttributeAnalyzerTests : BaseAoCSDiagnosticTests 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers.Tests/ProblemClassNamings/AoCS0004_Tests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | 3 | namespace AdventOfCSharp.Analyzers.Tests.ProblemClassNamings; 4 | 5 | [TestClass] 6 | public sealed class AoCS0004_Tests : ProblemClassNamingAnalyzerTests 7 | { 8 | [TestMethod] 9 | public void ParentMatches() 10 | { 11 | AssertNamespace("AoC.Year2021.Specific", true); 12 | } 13 | [TestMethod] 14 | public void StartsButNotEnds() 15 | { 16 | AssertNamespace("AoC.Year2021F", true); 17 | } 18 | [TestMethod] 19 | public void NotStartsButEnds() 20 | { 21 | AssertNamespace("AoC.NotYear2021", true); 22 | } 23 | [TestMethod] 24 | public void OnlyContains() 25 | { 26 | AssertNamespace("AoC.NotYear2021F", true); 27 | } 28 | [TestMethod] 29 | public void IrrelevantName() 30 | { 31 | AssertNamespace("AoC.Blah", true); 32 | } 33 | 34 | [TestMethod] 35 | public void NonProblemSolutionClass() 36 | { 37 | const string testCode = 38 | @" 39 | namespace AoC.NotYear2021F.Something 40 | 41 | public class Day1 : NotProblem 42 | { 43 | public override int SolvePart1() => default; 44 | public override int SolvePart2() => default; 45 | } 46 | "; 47 | 48 | ValidateCodeWithUsings(testCode); 49 | } 50 | 51 | private void AssertNamespace(string namespaceString, bool assert) 52 | { 53 | var testCode = 54 | $@" 55 | namespace {namespaceString}; 56 | 57 | public class ↓Day1 : Problem 58 | {{ 59 | public override int SolvePart1() => -1; 60 | public override int SolvePart2() => -2; 61 | }} 62 | "; 63 | 64 | AssertOrValidateWithUsings(testCode, assert); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers.Tests/ProblemClassNamings/AoCS0005_Tests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | using System; 3 | 4 | namespace AdventOfCSharp.Analyzers.Tests.ProblemClassNamings; 5 | 6 | [TestClass] 7 | public sealed class AoCS0005_Tests : ProblemClassNamingAnalyzerTests 8 | { 9 | protected override void AssertDiagnostics(string testCode) 10 | { 11 | AssertDiagnosticsMicrosoftCodeAnalysis(testCode); 12 | } 13 | 14 | [TestMethod] 15 | public void TooEarly() 16 | { 17 | AssertNamespace(2014, true); 18 | } 19 | [TestMethod] 20 | public void Starting2015() 21 | { 22 | AssertNamespace(2015, false); 23 | } 24 | [TestMethod] 25 | public void TooShort() 26 | { 27 | AssertNamespace(20, true); 28 | } 29 | [TestMethod] 30 | public void TooLong() 31 | { 32 | AssertNamespace(204512, true); 33 | } 34 | [TestMethod] 35 | public void CurrentYear() 36 | { 37 | AssertNamespace(DateTime.Now.Year, false); 38 | } 39 | [TestMethod] 40 | public void NextYear() 41 | { 42 | AssertNamespace(DateTime.Now.Year + 1, true); 43 | } 44 | 45 | [TestMethod] 46 | public void NonProblemSolutionClass() 47 | { 48 | const string testCode = 49 | @" 50 | namespace AoC.Year{|*:2021645|}; 51 | 52 | public class Day1 : NotProblem 53 | { 54 | public override int SolvePart1() => default; 55 | public override int SolvePart2() => default; 56 | } 57 | "; 58 | 59 | AssertDiagnosticsWithUsings(testCode); 60 | } 61 | 62 | private void AssertNamespace(int year, bool assert) 63 | { 64 | var testCode = 65 | $@" 66 | namespace AoC.Year{{|*:{year}|}}; 67 | 68 | public class Day1 : Problem 69 | {{ 70 | public override int SolvePart1() => -1; 71 | public override int SolvePart2() => -2; 72 | }} 73 | "; 74 | 75 | AssertOrValidateMicrosoftCodeAnalysis(testCode, assert); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers.Tests/ProblemClassNamings/AoCS0006_Tests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | 3 | namespace AdventOfCSharp.Analyzers.Tests.ProblemClassNamings; 4 | 5 | [TestClass] 6 | public sealed class AoCS0006_Tests : ProblemClassNamingAnalyzerTests 7 | { 8 | [TestMethod] 9 | public void StartsButNotEnds() 10 | { 11 | AssertClass("Day1F", true); 12 | } 13 | [TestMethod] 14 | public void NotStartsButEnds() 15 | { 16 | AssertClass("NotDay1", true); 17 | } 18 | [TestMethod] 19 | public void OnlyContains() 20 | { 21 | AssertClass("NotDay1F", true); 22 | } 23 | [TestMethod] 24 | public void IrrelevantName() 25 | { 26 | AssertClass("Irrelevant", true); 27 | } 28 | 29 | [TestMethod] 30 | public void NonProblemSolutionClass() 31 | { 32 | const string testCode = 33 | @" 34 | namespace AoC.Year2021 35 | 36 | public class NothingLikeDay1 : NotProblem 37 | { 38 | public override int SolvePart1() => default; 39 | public override int SolvePart2() => default; 40 | } 41 | "; 42 | 43 | ValidateCodeWithUsings(testCode); 44 | } 45 | 46 | private void AssertClass(string className, bool assert) 47 | { 48 | var testCode = 49 | $@" 50 | namespace AoC.Year2021; 51 | 52 | public class ↓{className} : Problem 53 | {{ 54 | public override int SolvePart1() => -1; 55 | public override int SolvePart2() => -2; 56 | }} 57 | "; 58 | 59 | AssertOrValidateWithUsings(testCode, assert); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers.Tests/ProblemClassNamings/AoCS0007_Tests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | 3 | namespace AdventOfCSharp.Analyzers.Tests.ProblemClassNamings; 4 | 5 | [TestClass] 6 | public sealed class AoCS0007_Tests : ProblemClassNamingAnalyzerTests 7 | { 8 | protected override void AssertDiagnostics(string testCode) 9 | { 10 | AssertDiagnosticsMicrosoftCodeAnalysis(testCode); 11 | } 12 | 13 | [TestMethod] 14 | public void Day0() 15 | { 16 | AssertClass(0, true); 17 | } 18 | [TestMethod] 19 | public void AfterChristmas() 20 | { 21 | AssertClass(26, true); 22 | } 23 | [TestMethod] 24 | public void Day1() 25 | { 26 | AssertClass(1, false); 27 | } 28 | [TestMethod] 29 | public void Day25() 30 | { 31 | var testCode = 32 | $@" 33 | namespace AoC.Year2021; 34 | 35 | public class Day25 : FinalDay 36 | {{ 37 | public override int SolvePart1() => -1; 38 | }} 39 | "; 40 | 41 | ValidateCodeWithUsings(testCode); 42 | } 43 | [TestMethod] 44 | public void TooLong() 45 | { 46 | AssertClass(4531, true); 47 | } 48 | 49 | [TestMethod] 50 | public void NonProblemSolutionClass() 51 | { 52 | const string testCode = 53 | @" 54 | namespace AoC.Year2021 55 | 56 | public class Day124678 : NotProblem 57 | { 58 | public override int SolvePart1() => default; 59 | public override int SolvePart2() => default; 60 | } 61 | "; 62 | 63 | ValidateCodeWithUsings(testCode); 64 | } 65 | 66 | private void AssertClass(int day, bool assert) 67 | { 68 | var testCode = 69 | $@" 70 | namespace AoC.Year2021; 71 | 72 | public class Day{{|*:{day}|}} : Problem 73 | {{ 74 | public override int SolvePart1() => -1; 75 | public override int SolvePart2() => -2; 76 | }} 77 | "; 78 | 79 | AssertOrValidateWithUsings(testCode, assert); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers.Tests/ProblemClassNamings/ProblemInheritanceAnalyzerTests.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCSharp.Analyzers.Tests.ProblemClassNamings; 2 | 3 | public abstract class ProblemClassNamingAnalyzerTests : BaseAoCSDiagnosticTests 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers.Tests/ProblemSolutionClassInheritance/AoCS0003_Tests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | 3 | namespace AdventOfCSharp.Analyzers.Tests.ProblemSolutionClassInheritance; 4 | 5 | [TestClass] 6 | public sealed class AoCS0003_Tests : ProblemInheritanceAnalyzerTests 7 | { 8 | protected override void AssertDiagnostics(string testCode) 9 | { 10 | AssertDiagnosticsMicrosoftCodeAnalysis(testCode); 11 | } 12 | 13 | [TestMethod] 14 | public void RedundantReturnTypeRepetition() 15 | { 16 | const string testCode = 17 | @" 18 | namespace AoC.Year2021; 19 | 20 | public class Day1 : Problem 21 | { 22 | public override int SolvePart1() => -1; 23 | public override int SolvePart2() => -2; 24 | } 25 | public abstract class ProblemIntString : Problem 26 | { 27 | } 28 | public abstract class ProblemStringString : Problem 29 | { 30 | } 31 | public abstract class ProblemGlyphGrid : Problem 32 | { 33 | } 34 | public abstract class ProblemString : Problem 35 | { 36 | } 37 | "; 38 | 39 | AssertDiagnosticsWithUsings(testCode); 40 | } 41 | [TestMethod] 42 | public void RedundantReturnTypeRepetitionPartial() 43 | { 44 | const string testCode = 45 | @" 46 | namespace AoC.Year2021; 47 | 48 | public partial class Day1 : Problem 49 | { 50 | public override int SolvePart1() => -1; 51 | } 52 | public partial class Day1 : Problem 53 | { 54 | public override int SolvePart2() => -2; 55 | } 56 | public partial class Day1 : Problem 57 | { 58 | } 59 | public partial class Day1 60 | { 61 | } 62 | 63 | public class Day2 : Problem 64 | { 65 | public override int SolvePart1() => -1; 66 | public override int SolvePart2() => -2; 67 | } 68 | "; 69 | 70 | AssertDiagnosticsWithUsings(testCode); 71 | } 72 | 73 | [TestMethod] 74 | public void IrrelevantTypeParameterRepetition() 75 | { 76 | const string testCode = 77 | @" 78 | namespace AoC.Year2021; 79 | 80 | public class Day1 : Dictionary 81 | { 82 | } 83 | public class IntDictionary : Dictionary 84 | { 85 | } 86 | "; 87 | 88 | ValidateCodeWithUsings(testCode); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers.Tests/ProblemSolutionClassInheritance/ProblemInheritanceAnalyzerTests.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCSharp.Analyzers.Tests.ProblemSolutionClassInheritance; 2 | 3 | public abstract class ProblemInheritanceAnalyzerTests : BaseAoCSDiagnosticTests 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers.Tests/SecretContainers/AoCS0008_Tests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | 3 | namespace AdventOfCSharp.Analyzers.Tests.SecretContainers; 4 | 5 | [TestClass] 6 | public sealed class AoCS0008_Tests : SecretsContainerAnalyzerTests 7 | { 8 | [TestMethod] 9 | public void TemplateSecretsContainer() 10 | { 11 | const string testCode = 12 | @" 13 | namespace AoC; 14 | 15 | [SecretsContainer] 16 | internal sealed class MyCookies : Cookies 17 | { 18 | public override string GA => ""GA1.2.9999999999.9999999999""; 19 | public override string Session => ""ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff""; 20 | } 21 | "; 22 | 23 | ValidateCodeWithUsings(testCode); 24 | } 25 | 26 | [TestMethod] 27 | public void InvalidSecretsContainer() 28 | { 29 | const string testCode = 30 | @" 31 | namespace AoC; 32 | 33 | [↓SecretsContainer] 34 | public abstract class SomeSecrets : ISecretsContainer { } 35 | public abstract class SomeNotSecrets { } 36 | 37 | [SecretsContainer] 38 | internal sealed class MySecrets : SomeSecrets { } 39 | 40 | [↓SecretsContainer] 41 | internal sealed class InvalidConstructor : SomeSecrets 42 | { 43 | public InvalidConstructor(int x) { } 44 | } 45 | 46 | [↓SecretsContainer] 47 | internal class NotSealedSecrets : SomeSecrets { } 48 | 49 | [↓SecretsContainer] 50 | internal sealed class NotSecrets : SomeNotSecrets { } 51 | "; 52 | 53 | AssertDiagnosticsWithUsings(testCode); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers.Tests/SecretContainers/SecretsContainerAnalyzerTests.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCSharp.Analyzers.Tests.SecretContainers; 2 | 3 | public abstract class SecretsContainerAnalyzerTests : BaseAoCSDiagnosticTests 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers.Tests/SecretStringProperties/AoCS0080_Tests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | 3 | namespace AdventOfCSharp.Analyzers.Tests.SecretStringProperties; 4 | 5 | [TestClass] 6 | public sealed class AoCS0080_Tests : SecretStringPropertyAnalyzerTests 7 | { 8 | [TestMethod] 9 | public void SecretsPatternNotMatching() 10 | { 11 | const string testCode = 12 | @" 13 | public sealed class SomeSecrets : TestSecretsContainerBase 14 | { 15 | [SecretStringProperty(@""\d\w\d"", ""_test"", SecretsType)] 16 | public string SomeSecrets => ↓""not matching pattern""; 17 | } 18 | "; 19 | 20 | AssertDiagnosticsWithUsings(testCode); 21 | } 22 | [TestMethod] 23 | public void SecretsPatternMatching() 24 | { 25 | const string testCode = 26 | @" 27 | public sealed class SomeSecrets : TestSecretsContainerBase 28 | { 29 | [SecretStringProperty(@""\w{5}\d{2}"", ""_testRight"", SecretsType)] 30 | public string CorrectPattern => ""abcde12""; 31 | } 32 | "; 33 | 34 | ValidateCodeWithUsings(testCode); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers.Tests/SecretStringProperties/AoCS0081_Tests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | 3 | namespace AdventOfCSharp.Analyzers.Tests.SecretStringProperties; 4 | 5 | [TestClass] 6 | public sealed class AoCS0081_Tests : SecretStringPropertyAnalyzerTests 7 | { 8 | [TestMethod] 9 | public void WithoutSecretStringProperties() 10 | { 11 | const string testCode = 12 | @" 13 | public sealed class ↓NoSecrets : NoSecretsBase 14 | { 15 | public string NotSecretA => ""nothing""; 16 | public string NotSecretB => ""random""; 17 | public override int Value => 5; 18 | } 19 | public abstract class NoSecretsBase : TestSecretsContainerBase 20 | { 21 | public string NotSecretBase => ""base""; 22 | public abstract int Value { get; } 23 | } 24 | "; 25 | 26 | AssertDiagnosticsWithUsings(testCode); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers.Tests/SecretStringProperties/AoCS0082_Tests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | 3 | namespace AdventOfCSharp.Analyzers.Tests.SecretStringProperties; 4 | 5 | [TestClass] 6 | public sealed class AoCS0082_Tests : SecretStringPropertyAnalyzerTests 7 | { 8 | [TestMethod] 9 | public void NotConstantFieldForSecretType() 10 | { 11 | const string testCode = 12 | @" 13 | public sealed class SomeSecrets : TestSecretsContainerBase 14 | { 15 | [SecretStringProperty(@""\d"", ""_test"", ↓""not constant type"")] 16 | public string Secret => ""1""; 17 | } 18 | "; 19 | 20 | AssertDiagnosticsWithUsings(testCode); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers.Tests/SecretStringProperties/AoCS0083_Tests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | 3 | namespace AdventOfCSharp.Analyzers.Tests.SecretStringProperties; 4 | 5 | [TestClass] 6 | public sealed class AoCS0083_Tests : SecretStringPropertyAnalyzerTests 7 | { 8 | [DataTestMethod] 9 | [DataRow("bool")] 10 | [DataRow("char")] 11 | [DataRow("byte")] 12 | [DataRow("short")] 13 | [DataRow("int")] 14 | [DataRow("long")] 15 | [DataRow("sbyte")] 16 | [DataRow("ushort")] 17 | [DataRow("uint")] 18 | [DataRow("ulong")] 19 | [DataRow("float")] 20 | [DataRow("double")] 21 | [DataRow("decimal")] 22 | public void NotStringSecretType(string type) 23 | { 24 | string testCode = 25 | $@" 26 | public abstract class NonNumericalSecrets : TestSecretsContainerBase 27 | {{ 28 | [SecretStringProperty(@""\d"", ""numerical"", SecretsType)] 29 | public abstract ↓{type} Numerical {{ get; }} 30 | }} 31 | "; 32 | 33 | AssertDiagnosticsWithUsings(testCode); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers.Tests/SecretStringProperties/AoCS0084_Tests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | 3 | namespace AdventOfCSharp.Analyzers.Tests.SecretStringProperties; 4 | 5 | [TestClass] 6 | public sealed class AoCS0084_Tests : SecretStringPropertyAnalyzerTests 7 | { 8 | [TestMethod] 9 | public void NotSecretsContainerType() 10 | { 11 | string testCode = 12 | @" 13 | public class NotSecretContainer 14 | { 15 | public const string SecretsType = ""Test""; 16 | 17 | [↓SecretStringProperty(@""\d"", ""_test"", SecretsType)] 18 | public string Secret => ""1""; 19 | } 20 | "; 21 | 22 | AssertDiagnosticsWithUsings(testCode); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers.Tests/SecretStringProperties/CookiesTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis; 2 | using Microsoft.VisualStudio.TestTools.UnitTesting; 3 | 4 | namespace AdventOfCSharp.Analyzers.Tests.SecretStringProperties; 5 | 6 | [TestClass] 7 | public sealed class CookiesTests : SecretStringPropertyAnalyzerTests 8 | { 9 | public override DiagnosticDescriptor TestedDiagnosticRule => AoCSDiagnosticDescriptorStorage.Instance[0080]; 10 | 11 | [TestMethod] 12 | public void CorrectCookies() 13 | { 14 | // The cookies below are random mutations of existing ones 15 | // Do not attempt to use them, even if they are valid for somebody 16 | const string testCode = 17 | @" 18 | [SecretsContainer] 19 | internal sealed class MyCookies : Cookies 20 | { 21 | public override string GA => ""GA1.2.2949042032.1125072387""; 22 | public override string Session => ""04f0b5c0e6f05ca60d05b605a05468e056b1a056c026e156f05b605e0a202c050f050023b02e023a020c99833fe45c541c7b3af6b623d95718f2f9a23ecd7629""; 23 | } 24 | "; 25 | 26 | ValidateCodeWithUsings(testCode); 27 | } 28 | 29 | [TestMethod] 30 | public void IncorrectCookies() 31 | { 32 | // The cookies below are random mutations of existing ones 33 | // Do not attempt to use them, even if they are valid for somebody 34 | const string testCode = 35 | @" 36 | [SecretsContainer] 37 | internal sealed class MyCookies : Cookies 38 | { 39 | public override string GA => ↓""fgjdsrignjudtsignxzudi""; 40 | public override string Session => ↓""jhnbdsfgjhkgbfdsnudfjvnsjudtrignsudigndsikjugtn""; 41 | } 42 | "; 43 | 44 | AssertDiagnosticsWithUsings(testCode); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers.Tests/SecretStringProperties/SecretStringPropertyAnalyzerTests.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCSharp.Analyzers.Tests.SecretStringProperties; 2 | 3 | public abstract class SecretStringPropertyAnalyzerTests : BaseAoCSDiagnosticTests 4 | { 5 | } 6 | -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers/AdventOfCSharp.Analyzers.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 10.0 6 | 7 | false 8 | AdventOfCSharp.Analyzers.Core 9 | 10 | RS2003 11 | 12 | 13 | 14 | 15 | all 16 | runtime; build; native; contentfiles; analyzers; buildtransitive 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | True 33 | True 34 | DiagnosticStringResources.resx 35 | 36 | 37 | 38 | 39 | 40 | ResXFileCodeGenerator 41 | DiagnosticStringResources.Designer.cs 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers/AnalyzerReleases.Unshipped.md: -------------------------------------------------------------------------------- 1 | ; Unshipped analyzer release 2 | ; https://github.com/dotnet/roslyn-analyzers/blob/master/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md 3 | -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers/AoCSAnalyzer.cs: -------------------------------------------------------------------------------- 1 | using AdventOfCSharp.CodeAnalysis.Core; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.Diagnostics; 4 | using RoseLynn; 5 | using RoseLynn.Analyzers; 6 | using System.Linq; 7 | 8 | namespace AdventOfCSharp.Analyzers; 9 | 10 | #nullable enable 11 | 12 | public abstract class AoCSAnalyzer : CSharpDiagnosticAnalyzer 13 | { 14 | protected sealed override DiagnosticDescriptorStorageBase DiagnosticDescriptorStorage => AoCSDiagnosticDescriptorStorage.Instance; 15 | 16 | public sealed override void Initialize(AnalysisContext context) 17 | { 18 | context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); 19 | context.EnableConcurrentExecution(); 20 | 21 | RegisterAnalyzers(context); 22 | } 23 | protected abstract void RegisterAnalyzers(AnalysisContext context); 24 | 25 | protected static bool IsImportantAoCSClass(INamedTypeSymbol classSymbol) 26 | { 27 | return IsImportantAoCSClass(classSymbol, typeof(T).Name); 28 | } 29 | protected static bool IsImportantAoCSClass(INamedTypeSymbol classSymbol, string name) 30 | { 31 | return AoCSAnalysisHelpers.IsImportantAoCSClass(classSymbol, name); 32 | } 33 | protected static bool IsImportantAoCSClass(INamedTypeSymbol classSymbol, IdentifierWithArity name) 34 | { 35 | return AoCSAnalysisHelpers.IsImportantAoCSClass(classSymbol, name); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers/AssemblyAttributes.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | [assembly: InternalsVisibleTo("AdventOfCSharp.Analyzers.Tests")] 4 | [assembly: InternalsVisibleTo("AdventOfCSharp.CodeFixes")] 5 | [assembly: InternalsVisibleTo("AdventOfCSharp.CodeFixes.Tests")] 6 | -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers/FinalDayAnalyzer.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis; 2 | using Microsoft.CodeAnalysis.CSharp; 3 | using Microsoft.CodeAnalysis.CSharp.Syntax; 4 | using Microsoft.CodeAnalysis.Diagnostics; 5 | 6 | namespace AdventOfCSharp.Analyzers; 7 | 8 | #nullable enable 9 | 10 | [DiagnosticAnalyzer(LanguageNames.CSharp)] 11 | public sealed class FinalDayAnalyzer : ProblemAoCSAnalyzer 12 | { 13 | private const string day25Name = "Day25"; 14 | private const string finalDayClassName = "FinalDay`1"; 15 | private const string finalDayFullClassName = $"{nameof(AdventOfCSharp)}.FinalDay`1"; 16 | 17 | protected override void RegisterAnalyzers(AnalysisContext context) 18 | { 19 | context.RegisterSyntaxNodeAction(AnalyzeProblemSolutionType, SyntaxKind.ClassDeclaration); 20 | } 21 | 22 | private void AnalyzeProblemSolutionType(SyntaxNodeAnalysisContext context) 23 | { 24 | var classDeclaration = context.Node as ClassDeclarationSyntax; 25 | 26 | if (!IsProblemSolutionClass(classDeclaration, context.SemanticModel, out var classSymbol)) 27 | return; 28 | 29 | if (classSymbol!.IsAbstract) 30 | return; 31 | 32 | bool isDay25 = classDeclaration?.Identifier.ValueText is day25Name; 33 | 34 | if (InheritsFinalDayClass(classSymbol!) == isDay25) 35 | return; 36 | 37 | Diagnostics.FinalDayInheritanceDiagnosticCreator creator = isDay25 switch 38 | { 39 | true => Diagnostics.CreateAoCS0011, 40 | false => Diagnostics.CreateAoCS0012, 41 | }; 42 | context.ReportDiagnostic(creator(classDeclaration)); 43 | } 44 | 45 | private static bool InheritsFinalDayClass(INamedTypeSymbol classSymbol) 46 | { 47 | return IsImportantAoCSClass(classSymbol, finalDayClassName); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers/PartSolutionAnalyzer.cs: -------------------------------------------------------------------------------- 1 | using AdventOfCSharp.CodeAnalysis.Core; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.CSharp.Syntax; 4 | using Microsoft.CodeAnalysis.Diagnostics; 5 | using RoseLynn; 6 | 7 | namespace AdventOfCSharp.Analyzers; 8 | 9 | [DiagnosticAnalyzer(LanguageNames.CSharp)] 10 | public sealed class PartSolutionAnalyzer : ProblemAoCSAnalyzer 11 | { 12 | protected override void RegisterAnalyzers(AnalysisContext context) 13 | { 14 | context.RegisterSymbolAction(AnalyzeSolutionMethodDeclaration, SymbolKind.Method); 15 | context.RegisterSymbolAction(AnalyzePartSolutionAttributeUsage, SymbolKind.Method); 16 | } 17 | 18 | private void AnalyzeSolutionMethodDeclaration(SymbolAnalysisContext context) 19 | { 20 | switch (context.Symbol) 21 | { 22 | case IMethodSymbol methodSymbol: 23 | // If only I could use dependencies 24 | if (!methodSymbol.IsStatic) 25 | { 26 | bool isPartSolutionMethod = methodSymbol.HasInheritedAttributeMatchingType(); 27 | if (isPartSolutionMethod) 28 | return; 29 | } 30 | 31 | var solutionAttribute = GetPartSolutionAttributeData(methodSymbol); 32 | if (solutionAttribute is null) 33 | return; 34 | 35 | var solutionAttributeNode = solutionAttribute.ApplicationSyntaxReference.GetSyntax() as AttributeSyntax; 36 | context.ReportDiagnostic(Diagnostics.CreateAoCS0001(solutionAttributeNode)); 37 | break; 38 | } 39 | } 40 | 41 | private void AnalyzePartSolutionAttributeUsage(SymbolAnalysisContext context) 42 | { 43 | switch (context.Symbol) 44 | { 45 | case IMethodSymbol methodSymbol: 46 | var solutionAttribute = GetPartSolutionAttributeData(methodSymbol); 47 | if (solutionAttribute?.ConstructorArguments.Length is null or 0) 48 | return; 49 | 50 | var argument = solutionAttribute.ConstructorArguments[0]; 51 | if (argument.IsDefinedEnumValue()) 52 | return; 53 | 54 | var attributeNode = solutionAttribute.ApplicationSyntaxReference.GetSyntax() as AttributeSyntax; 55 | var undefinedEnumValueNode = attributeNode.ArgumentList.Arguments[0]; 56 | context.ReportDiagnostic(Diagnostics.CreateAoCS0002(undefinedEnumValueNode)); 57 | 58 | break; 59 | } 60 | } 61 | 62 | private static AttributeData? GetPartSolutionAttributeData(IMethodSymbol method) 63 | { 64 | return method.FirstOrDefaultAttributeNamed(nameof(PartSolutionAttribute)); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers/ProblemAoCSAnalyzer.cs: -------------------------------------------------------------------------------- 1 | using AdventOfCSharp.CodeAnalysis.Core; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.CSharp.Syntax; 4 | 5 | namespace AdventOfCSharp.Analyzers; 6 | 7 | #nullable enable 8 | 9 | public abstract class ProblemAoCSAnalyzer : AoCSAnalyzer 10 | { 11 | protected static bool IsProblemSolutionClass(ClassDeclarationSyntax? classDeclaration, SemanticModel semanticModel) 12 | { 13 | return IsProblemSolutionClass(classDeclaration, semanticModel, out _); 14 | } 15 | protected static bool IsProblemSolutionClass(ClassDeclarationSyntax? classDeclaration, SemanticModel semanticModel, out INamedTypeSymbol? classSymbol) 16 | { 17 | classSymbol = null; 18 | if (classDeclaration is null) 19 | return false; 20 | classSymbol = semanticModel.GetDeclaredSymbol(classDeclaration) as INamedTypeSymbol; 21 | return IsProblemSolutionClass(classSymbol!); 22 | } 23 | 24 | protected static bool IsProblemSolutionClass(INamedTypeSymbol classSymbol) 25 | { 26 | return IsImportantAoCSClass(classSymbol, KnownSymbolNames.Problem); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers/ProblemInheritanceAnalyzer.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis; 2 | using Microsoft.CodeAnalysis.CSharp; 3 | using Microsoft.CodeAnalysis.CSharp.Syntax; 4 | using Microsoft.CodeAnalysis.Diagnostics; 5 | using RoseLynn; 6 | using System.Linq; 7 | 8 | namespace AdventOfCSharp.Analyzers; 9 | 10 | [DiagnosticAnalyzer(LanguageNames.CSharp)] 11 | public sealed class ProblemInheritanceAnalyzer : AoCSAnalyzer 12 | { 13 | protected override void RegisterAnalyzers(AnalysisContext context) 14 | { 15 | context.RegisterSyntaxNodeAction(AnalyzeProblemSolutionClassInheritance, SyntaxKind.ClassDeclaration); 16 | } 17 | 18 | private void AnalyzeProblemSolutionClassInheritance(SyntaxNodeAnalysisContext context) 19 | { 20 | var semanticModel = context.SemanticModel; 21 | var classDeclarationNode = context.Node as ClassDeclarationSyntax; 22 | 23 | if (classDeclarationNode.BaseList is null) 24 | return; 25 | 26 | var declaredClass = semanticModel.GetDeclaredSymbol(classDeclarationNode); 27 | if (declaredClass is null) 28 | return; 29 | 30 | var baseType = declaredClass.BaseType; 31 | if (baseType is not INamedTypeSymbol baseNamedType) 32 | return; 33 | 34 | if (baseNamedType.Name != "Problem") 35 | return; 36 | 37 | if (baseNamedType.Arity != 2) 38 | return; 39 | 40 | var arguments = baseNamedType.TypeArguments; 41 | if (!arguments[0].Equals(arguments[1], SymbolEqualityComparer.Default)) 42 | return; 43 | 44 | var baseListTypes = classDeclarationNode.BaseList.Types; 45 | var baseTypeNode = baseListTypes.First(MatchesBaseType); 46 | context.ReportDiagnostic(Diagnostics.CreateAoCS0003(baseTypeNode.Type as GenericNameSyntax)); 47 | 48 | bool MatchesBaseType(BaseTypeSyntax baseTypeNode) 49 | { 50 | return baseType.Equals(semanticModel.GetSymbol(baseTypeNode.Type), SymbolEqualityComparer.Default); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers/SecretsContainerAnalyzer.cs: -------------------------------------------------------------------------------- 1 | using AdventOfCSharp.CodeAnalysis.Core; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.CSharp; 4 | using Microsoft.CodeAnalysis.CSharp.Syntax; 5 | using Microsoft.CodeAnalysis.Diagnostics; 6 | using RoseLynn; 7 | using RoseLynn.CSharp; 8 | using RoseLynn.CSharp.Syntax; 9 | 10 | namespace AdventOfCSharp.Analyzers; 11 | 12 | [DiagnosticAnalyzer(LanguageNames.CSharp)] 13 | public sealed class SecretsContainerAnalyzer : AoCSAnalyzer 14 | { 15 | protected override void RegisterAnalyzers(AnalysisContext context) 16 | { 17 | context.RegisterTargetAttributeSyntaxNodeAction(AnalyzeSecretsContainerType, nameof(SecretsContainerAttribute)); 18 | } 19 | 20 | // In an AoC project, attributes should not be too commonly used, meaning less nodes to iterate 21 | // An average solution project would contain loads of functions, causing far more invocations than necessary 22 | private void AnalyzeSecretsContainerType(SyntaxNodeAnalysisContext context) 23 | { 24 | var attributeNode = context.Node as AttributeSyntax; 25 | 26 | if (attributeNode!.GetParentAttributeList().Parent is not ClassDeclarationSyntax classDeclarationNode) 27 | return; 28 | 29 | var classSymbol = context.SemanticModel.GetDeclaredSymbol(classDeclarationNode)!; 30 | 31 | if (IsValidSecretsContainer(classSymbol)) 32 | return; 33 | 34 | context.ReportDiagnostic(Diagnostics.CreateAoCS0008(attributeNode)); 35 | } 36 | 37 | private static bool IsValidSecretsContainer(INamedTypeSymbol classSymbol) 38 | { 39 | return MeetsDeclarationCriteria(classSymbol); 40 | 41 | static bool MeetsDeclarationCriteria(INamedTypeSymbol classSymbol) 42 | { 43 | return classSymbol is 44 | { 45 | IsStatic: false, 46 | IsSealed: true, 47 | } 48 | && IsImportantAoCSClass(classSymbol) 49 | && classSymbol.HasPublicParameterlessInstanceConstructor(); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers/SymbolExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis; 2 | using System; 3 | using System.Linq; 4 | 5 | namespace AdventOfCSharp.Analyzers; 6 | 7 | public static class SymbolExtensions 8 | { 9 | public static bool HasAttributeMatchingType(this ISymbol symbol) 10 | where T : Attribute 11 | { 12 | return HasAttributeNamed(symbol, typeof(T).Name); 13 | } 14 | public static bool HasAttributeNamed(this ISymbol symbol, string attributeClassName) 15 | { 16 | return symbol.GetAttributes().Any(attribute => attribute.AttributeClass.Name == attributeClassName); 17 | } 18 | 19 | public static bool HasInheritedAttributeMatchingType(this IMethodSymbol symbol) 20 | where T : Attribute 21 | { 22 | return HasInheritedAttributeNamed(symbol, typeof(T).Name); 23 | } 24 | public static bool HasInheritedAttributeNamed(this IMethodSymbol symbol, string attributeClassName) 25 | { 26 | var current = symbol; 27 | while (current is not null) 28 | { 29 | if (HasAttributeNamed(current, attributeClassName)) 30 | return true; 31 | 32 | current = current.OverriddenMethod; 33 | } 34 | return false; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /AdventOfCSharp.Analyzers/Utilities/AccessorListSyntaxExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis; 2 | using Microsoft.CodeAnalysis.CSharp; 3 | using Microsoft.CodeAnalysis.CSharp.Syntax; 4 | 5 | namespace AdventOfCSharp.Analyzers.Utilities; 6 | 7 | #nullable enable 8 | 9 | public static class AccessorListSyntaxExtensions 10 | { 11 | public static AccessorDeclarationSyntax? GetAccessor(this AccessorListSyntax? accessorList, AccessorKind accessorKind) 12 | { 13 | if (accessorList is null) 14 | return null; 15 | 16 | var targetSyntaxKind = accessorKind.GetRepresentingKeywordSyntaxKind(); 17 | 18 | if (targetSyntaxKind is SyntaxKind.None) 19 | return null; 20 | 21 | foreach (var accessor in accessorList.Accessors) 22 | { 23 | if (accessor.Keyword.IsKind(targetSyntaxKind)) 24 | return accessor; 25 | } 26 | 27 | return null; 28 | } 29 | } 30 | 31 | public enum AccessorKind 32 | { 33 | None, 34 | 35 | Get, 36 | Set, 37 | Init, 38 | 39 | Add, 40 | Remove, 41 | } 42 | 43 | public static class AccessorKindExtensions 44 | { 45 | public static SyntaxKind GetRepresentingKeywordSyntaxKind(this AccessorKind kind) 46 | { 47 | return kind switch 48 | { 49 | AccessorKind.None => SyntaxKind.None, 50 | 51 | AccessorKind.Get => SyntaxKind.GetKeyword, 52 | AccessorKind.Set => SyntaxKind.SetKeyword, 53 | AccessorKind.Init => SyntaxKind.InitKeyword, 54 | 55 | AccessorKind.Add => SyntaxKind.AddKeyword, 56 | AccessorKind.Remove => SyntaxKind.RemoveKeyword, 57 | }; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /AdventOfCSharp.Benchmarking.Common/AdventOfCSharp.Benchmarking.Common.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 10.0 6 | 7 | true 8 | true 9 | 10 | AdventOfCSharp.Benchmarking 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /AdventOfCSharp.Benchmarking.Common/BenchmarkDescriberAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Immutable; 3 | 4 | namespace AdventOfCSharp.Benchmarking; 5 | 6 | public sealed class BenchmarkDescriberAttribute : Attribute { } 7 | 8 | public abstract class BaseBenchmarkDescriberAttribute : Attribute { } 9 | 10 | // Names can be this free because of the context being limited, barely touching other areas 11 | // that could cause confusion to the programmer 12 | // In the context of benchmarking AoC# solutions, the concepts of years, days and dates are 13 | // clear and distinct enough to the consumer 14 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] 15 | public sealed class YearsAttribute : BaseBenchmarkDescriberAttribute 16 | { 17 | public ImmutableArray Years { get; } 18 | 19 | public YearsAttribute(params int[] years) 20 | { 21 | Years = years.ToImmutableArray(); 22 | } 23 | } 24 | 25 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] 26 | public sealed class DaysAttribute : BaseBenchmarkDescriberAttribute 27 | { 28 | public ImmutableArray Days { get; } 29 | 30 | public DaysAttribute(params int[] days) 31 | { 32 | Days = days.ToImmutableArray(); 33 | } 34 | } 35 | 36 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)] 37 | public sealed class DatesAttribute : BaseBenchmarkDescriberAttribute 38 | { 39 | public int Year { get; } 40 | public ImmutableArray Days { get; } 41 | 42 | public DatesAttribute(int year, params int[] days) 43 | { 44 | Year = year; 45 | Days = days.ToImmutableArray(); 46 | } 47 | } 48 | 49 | // This attribute is specially treated to include all dates, 50 | // completely disregarding other date attributes 51 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] 52 | public sealed class AllDatesAttribute : BaseBenchmarkDescriberAttribute 53 | { } 54 | 55 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] 56 | public sealed class PartsAttribute : BaseBenchmarkDescriberAttribute 57 | { 58 | public BenchmarkingParts Parts { get; } 59 | 60 | public PartsAttribute(BenchmarkingParts parts) 61 | { 62 | Parts = parts; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /AdventOfCSharp.Benchmarking.Common/BenchmarkingParts.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCSharp.Benchmarking; 2 | 3 | public enum BenchmarkingParts 4 | { 5 | None = 0, 6 | 7 | Input = 1 << 0, 8 | Part1 = 1 << 1, 9 | Part2 = 1 << 2, 10 | 11 | OnlyParts = Part1 | Part2, 12 | 13 | All = Input | OnlyParts, 14 | } 15 | -------------------------------------------------------------------------------- /AdventOfCSharp.Benchmarking/AdventOfCSharp.Benchmarking.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Library 5 | net6.0 6 | enable 7 | enable 8 | 9 | True 10 | true 11 | 12 | 1.4.1 13 | 14 | advent-of-code, aoc, benchmark 15 | Benchmarking tools for the Advent of C# framework. 16 | © 2022, Alex Kalfakakos 17 | https://github.com/Rekkonnect/AdventOfCSharp 18 | Alex Kalfakakos 19 | MIT 20 | False 21 | AdventOfCSharp.Benchmarking 22 | AdventOfCSharp.Benchmarking 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /AdventOfCSharp.Benchmarking/BenchmarkDescriber.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCSharp.Benchmarking; 2 | 3 | // Until BDN fixes reference issues, keep this here 4 | internal abstract class BenchmarkDescriber 5 | { 6 | protected static void CreateAssignBenchmarkedActions(Problem instance, ref Action part1, ref Action part2, ref Action input) 7 | { 8 | BenchmarkDescriberHelpers.CreateAssignBenchmarkedActions(instance, ref part1, ref part2, ref input); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /AdventOfCSharp.Benchmarking/BenchmarkDescriberExecution.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Running; 2 | 3 | namespace AdventOfCSharp.Benchmarking; 4 | 5 | public static class BenchmarkDescriberExecution 6 | { 7 | public static void RunBenchmark(string customProblemFileBaseDirectory) 8 | { 9 | var previousBaseDirectory = ProblemFiles.CustomBaseDirectory; 10 | ProblemFiles.SetCustomBaseDirectorySyncEnvironmentVariable(customProblemFileBaseDirectory); 11 | BenchmarkRunner.Run(); 12 | ProblemFiles.RestoreBaseDirectoryClearEnvironmentVariable(previousBaseDirectory); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /AdventOfCSharp.Benchmarking/BenchmarkDescriberHelpers.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCSharp.Benchmarking; 2 | 3 | // sealed to allow being used as a type argument; static in reality 4 | public sealed class BenchmarkDescriberHelpers 5 | { 6 | public static void CreateAssignBenchmarkedActions(Problem instance, ref Action part1, ref Action part2, ref Action input) 7 | { 8 | part1 = ProblemSolverMethodProvider.CreateNoReturnSolverDelegate(1, instance); 9 | part2 = ProblemSolverMethodProvider.CreateNoReturnSolverDelegate(2, instance); 10 | input = ProblemSolverMethodProvider.CreateLoadStateDelegate(instance); 11 | } 12 | } -------------------------------------------------------------------------------- /AdventOfCSharp.Benchmarking/ProblemBenchmark.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Attributes; 2 | 3 | namespace AdventOfCSharp.Benchmarking; 4 | 5 | // Nullability is guaranteed given that the system operates as intended 6 | #nullable disable 7 | 8 | // Kept as internal for potential future consideration 9 | // If BDN ever adds the ability to add custom references to the compiled benchmarks 10 | [MemoryDiagnoser] 11 | internal class ProblemBenchmark 12 | { 13 | public int Year { get; set; } 14 | public int Day { get; set; } 15 | 16 | private Action solverPart1, solverPart2, loader; 17 | 18 | public ProblemBenchmark() { } 19 | 20 | [GlobalSetup] 21 | public void Setup() 22 | { 23 | var problemInfo = ProblemsIndex.Instance[Year, Day]; 24 | 25 | var instance = problemInfo.InitializeInstance(); 26 | solverPart1 = ProblemSolverMethodProvider.CreateNoReturnSolverDelegate(1, instance); 27 | solverPart2 = ProblemSolverMethodProvider.CreateNoReturnSolverDelegate(2, instance); 28 | loader = ProblemSolverMethodProvider.CreateLoadStateDelegate(instance); 29 | instance.EnsureLoadedState(); 30 | } 31 | 32 | [Benchmark] 33 | public void Input() 34 | { 35 | loader(); 36 | } 37 | [Benchmark] 38 | public void Part1() 39 | { 40 | solverPart1(); 41 | } 42 | [Benchmark] 43 | public void Part2() 44 | { 45 | solverPart2(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /AdventOfCSharp.CodeAnalysis.Core/AdventOfCSharp.CodeAnalysis.Core.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 10.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /AdventOfCSharp.CodeAnalysis.Core/AoCSAnalysisHelpers.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis; 2 | using RoseLynn; 3 | using System.Linq; 4 | 5 | namespace AdventOfCSharp.CodeAnalysis.Core; 6 | 7 | public static class AoCSAnalysisHelpers 8 | { 9 | public static bool IsImportantAoCSClass(INamedTypeSymbol classSymbol, string name) 10 | { 11 | var parsed = IdentifierWithArity.Parse(name); 12 | return IsImportantAoCSClass(classSymbol, parsed); 13 | } 14 | public static bool IsImportantAoCSClass(INamedTypeSymbol classSymbol, IdentifierWithArity name) 15 | { 16 | return IsImportantAoCSClass(classSymbol, ExpectedSymbolName()); 17 | 18 | FullSymbolName ExpectedSymbolName() => new(name, new[] { nameof(AdventOfCSharp) }); 19 | } 20 | 21 | public static bool IsImportantAoCSClass(INamedTypeSymbol classSymbol, FullSymbolName name) 22 | { 23 | return classSymbol.GetAllBaseTypesAndInterfaces().Any(Matches); 24 | 25 | bool Matches(INamedTypeSymbol baseType) 26 | { 27 | var fullBaseName = baseType.GetFullSymbolName(SymbolNameKind.Normal)!; 28 | return fullBaseName.Matches(name, SymbolNameMatchingLevel.Namespace); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /AdventOfCSharp.CodeAnalysis.Core/Extensions/BaseTypeDeclarationSyntaxExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis; 2 | using Microsoft.CodeAnalysis.CSharp.Syntax; 3 | using RoseLynn; 4 | 5 | namespace AdventOfCSharp.CodeAnalysis.Core.Extensions; 6 | 7 | public static class BaseTypeDeclarationSyntaxExtensions 8 | { 9 | public static string FullDeclaredSymbolName(this BaseTypeDeclarationSyntax typeDeclarationSyntax) 10 | { 11 | // Hate this type of code 12 | SyntaxNode current = typeDeclarationSyntax; 13 | var fullName = typeDeclarationSyntax.Identifier.Text; 14 | while (true) 15 | { 16 | var namespaceSyntax = current.GetNearestParentOfType(); 17 | if (namespaceSyntax is null) 18 | break; 19 | 20 | fullName = $"{namespaceSyntax.Name}.{fullName}"; 21 | current = namespaceSyntax; 22 | } 23 | 24 | return fullName; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /AdventOfCSharp.CodeAnalysis.Core/Extensions/CompilationExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace AdventOfCSharp.CodeAnalysis.Core.Extensions; 6 | 7 | public static class CompilationExtensions 8 | { 9 | public static IEnumerable NodesOfType(this Compilation compilation) 10 | where T : SyntaxNode 11 | { 12 | return compilation.SyntaxTrees.Select(tree => tree.NodesOfType()).SelectMany(nodes => nodes); 13 | } 14 | 15 | public static IEnumerable GetAllDefinedTypes(this Compilation compilation) 16 | { 17 | return compilation.Assembly.GlobalNamespace.GetAllContainedTypes(); 18 | } 19 | 20 | public static IEnumerable GetAllContainedTypes(this INamespaceSymbol namespaceSymbol) 21 | { 22 | var types = namespaceSymbol.GetTypeMembers(); 23 | var namespaces = namespaceSymbol.GetNamespaceMembers(); 24 | return types.Concat(namespaces.SelectMany(GetAllContainedTypes)); 25 | } 26 | 27 | public static IEnumerable GetAllSymbols(this Compilation compilation) 28 | { 29 | return compilation.References.Select(compilation.GetAssemblyOrModuleSymbol).Where(s => s is not null); 30 | } 31 | public static IEnumerable GetAllAssemblySymbols(this Compilation compilation) 32 | { 33 | return compilation.SourceModule.ReferencedAssemblySymbols.Concat(new[] { compilation.Assembly }); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /AdventOfCSharp.CodeAnalysis.Core/Extensions/IAssemblyOrModuleSymbolExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis; 2 | 3 | #nullable enable 4 | 5 | namespace AdventOfCSharp.CodeAnalysis.Core.Extensions; 6 | 7 | public static class IAssemblyOrModuleSymbolExtensions 8 | { 9 | public static INamespaceSymbol? GetGlobalNamespace(this ISymbol? symbol) 10 | { 11 | return symbol switch 12 | { 13 | IAssemblySymbol assemblySymbol => assemblySymbol.GlobalNamespace, 14 | IModuleSymbol moduleSymbol => moduleSymbol.GlobalNamespace, 15 | 16 | _ => null, 17 | }; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /AdventOfCSharp.CodeAnalysis.Core/Extensions/ISymbolExtensions.cs: -------------------------------------------------------------------------------- 1 | using AdventOfCSharp.CodeAnalysis.Core.Extensions; 2 | using Microsoft.CodeAnalysis; 3 | using RoseLynn; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | 8 | namespace AdventOfCSharp.CodeAnalysis.Core.Extensions; 9 | 10 | #nullable enable 11 | 12 | public static class ISymbolExtensions 13 | { 14 | public static bool HasAttributeNamed(this ISymbol symbol) 15 | where T : Attribute 16 | { 17 | return symbol.FirstOrDefaultAttributeNamed() is not null; 18 | } 19 | public static AttributeData? FirstOrDefaultAttributeNamed(this ISymbol symbol) 20 | where T : Attribute 21 | { 22 | return symbol.FirstOrDefaultAttributeNamed(typeof(T).Name); 23 | } 24 | public static IEnumerable GetAttributesNamed(this ISymbol symbol) 25 | where T : Attribute 26 | { 27 | return symbol.GetAttributes().Where(attribute => attribute.AttributeClass?.Name == typeof(T).Name); 28 | } 29 | 30 | // TODO: Implement for completeness in RoseLynn 31 | private static AttributeData? HasAttributeNamedFully(this ISymbol symbol, SymbolNameMatchingLevel matchingLevel = SymbolNameMatchingLevel.Namespace) 32 | where T : Attribute 33 | { 34 | return null; 35 | } 36 | private static AttributeData? FirstOrDefaultAttributeNamedFully(this ISymbol symbol, SymbolNameMatchingLevel matchingLevel = SymbolNameMatchingLevel.Namespace) 37 | where T : Attribute 38 | { 39 | return null; 40 | } 41 | private static IEnumerable GetAttributesNamedFully(this ISymbol symbol, SymbolNameMatchingLevel matchingLevel = SymbolNameMatchingLevel.Namespace) 42 | where T : Attribute 43 | { 44 | return null!; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /AdventOfCSharp.CodeAnalysis.Core/Extensions/SyntaxTreeExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace AdventOfCSharp.CodeAnalysis.Core.Extensions; 6 | 7 | public static class SyntaxTreeExtensions 8 | { 9 | public static IEnumerable NodesOfType(this SyntaxTree syntaxTree) 10 | where T : SyntaxNode 11 | { 12 | return syntaxTree.GetRoot().DescendantNodesAndSelf().OfType(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /AdventOfCSharp.CodeAnalysis.Core/KnownSymbolNames.cs: -------------------------------------------------------------------------------- 1 | using RoseLynn; 2 | 3 | namespace AdventOfCSharp.CodeAnalysis.Core; 4 | 5 | public static class KnownSymbolNames 6 | { 7 | public const string FinalDay = nameof(FinalDay); 8 | 9 | public const string Problem = nameof(Problem); 10 | 11 | public const string SolvePart1 = nameof(SolvePart1); 12 | public const string SolvePart2 = nameof(SolvePart2); 13 | 14 | public const string CommonAnswerStringConverter = nameof(CommonAnswerStringConverter); 15 | public const string AnswerStringConverter = nameof(AnswerStringConverter); 16 | 17 | public const string BenchmarkDescriber = nameof(BenchmarkDescriber); 18 | } 19 | 20 | public static class KnownFullSymbolNames 21 | { 22 | private static readonly string[] BaseAoCSNamespaces = new[] { nameof(AdventOfCSharp) }; 23 | private static readonly string[] BaseAoCSBenchmarkingNamespaces = new[] { nameof(AdventOfCSharp), nameof(AdventOfCSharp.Benchmarking) }; 24 | 25 | // AoCS 26 | public static readonly FullSymbolName CommonAnswerStringConverter = 27 | new(KnownSymbolNames.CommonAnswerStringConverter, BaseAoCSNamespaces); 28 | 29 | public static readonly FullSymbolName GenericAnswerStringConverter = 30 | new(new IdentifierWithArity(KnownSymbolNames.AnswerStringConverter, 1), BaseAoCSNamespaces); 31 | 32 | public static readonly FullSymbolName NonGenericAnswerStringConverter = 33 | new(KnownSymbolNames.AnswerStringConverter, BaseAoCSNamespaces); 34 | 35 | // AoCS.Benchmarking 36 | public static readonly FullSymbolName BenchmarkDescriber = 37 | new(KnownSymbolNames.BenchmarkDescriber, BaseAoCSBenchmarkingNamespaces); 38 | } 39 | -------------------------------------------------------------------------------- /AdventOfCSharp.CodeFixes.Tests/AdventOfCSharp.CodeFixes.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net6.0 5 | 10.0 6 | 7 | false 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /AdventOfCSharp.CodeFixes.Tests/BaseCodeFixTests.cs: -------------------------------------------------------------------------------- 1 | using AdventOfCSharp.AnalysisTestsBase; 2 | using AdventOfCSharp.AnalysisTestsBase.Verifiers; 3 | using AdventOfCSharp.Analyzers; 4 | using Microsoft.CodeAnalysis.Diagnostics; 5 | using Microsoft.VisualStudio.TestTools.UnitTesting; 6 | using RoseLynn.Analyzers; 7 | using RoseLynn.Testing; 8 | using System.Threading.Tasks; 9 | 10 | namespace AdventOfCSharp.CodeFixes.Tests; 11 | 12 | public abstract class BaseCodeFixTests : BaseCodeFixDiagnosticTests 13 | where TAnalyzer : DiagnosticAnalyzer, new() 14 | where TCodeFix : AoCSCodeFixProvider, new() 15 | { 16 | protected sealed override DiagnosticDescriptorStorageBase DiagnosticDescriptorStorage => AoCSDiagnosticDescriptorStorage.Instance; 17 | 18 | protected sealed override async Task VerifyCodeFixAsync(string markupCode, string expected, int codeActionIndex) 19 | { 20 | await CSharpCodeFixVerifier.VerifyCodeFixAsync(markupCode, expected, codeActionIndex); 21 | } 22 | 23 | [TestMethod] 24 | public void TestExistingCodeFixName() 25 | { 26 | Assert.IsNotNull(new TCodeFix().CodeFixTitle); 27 | } 28 | 29 | public void TestCodeFixWithUsings(string markupCode, string expected, int codeActionIndex = 0) 30 | { 31 | TestCodeFix(AoCSUsingsProvider.Instance.WithUsings(markupCode), AoCSUsingsProvider.Instance.WithUsings(expected), codeActionIndex); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /AdventOfCSharp.CodeFixes.Tests/FinalDayUsage/FinalDayUserCodeFixTests.cs: -------------------------------------------------------------------------------- 1 | using AdventOfCSharp.Analyzers; 2 | 3 | namespace AdventOfCSharp.CodeFixes.Tests.FinalDayUsage; 4 | 5 | public abstract class FinalDayUserCodeFixTests : BaseCodeFixTests 6 | { 7 | } 8 | -------------------------------------------------------------------------------- /AdventOfCSharp.CodeFixes.Tests/ProblemClassSimplification/AoCS0003_CodeFixTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | 3 | namespace AdventOfCSharp.CodeFixes.Tests.ProblemClassSimplification; 4 | 5 | [TestClass] 6 | public class AoCS0003_CodeFixTests : ProblemClassSimplifierCodeFixTests 7 | { 8 | [DataTestMethod] 9 | [DataRow("int")] 10 | [DataRow("string")] 11 | [DataRow("ulong")] 12 | public void ExpandedProblemCodeFix(string type) 13 | { 14 | var testCode = 15 | $@" 16 | namespace AoC.Year2021; 17 | 18 | public class Day1 : Problem<{type}{{|*:, {type}|}}> 19 | {{ 20 | public override {type} SolvePart1() => default; 21 | public override {type} SolvePart2() => default; 22 | }} 23 | "; 24 | 25 | var fixedCode = 26 | $@" 27 | namespace AoC.Year2021; 28 | 29 | public class Day1 : Problem<{type}> 30 | {{ 31 | public override {type} SolvePart1() => default; 32 | public override {type} SolvePart2() => default; 33 | }} 34 | "; 35 | TestCodeFixWithUsings(testCode, fixedCode); 36 | } 37 | 38 | [DataTestMethod] 39 | [DataRow("int")] 40 | [DataRow("string")] 41 | [DataRow("ulong")] 42 | public void ExpandedProblemBatchCodeFix(string type) 43 | { 44 | var testCode = 45 | $@" 46 | namespace AoC.Year2021; 47 | 48 | public class Day1 : Problem<{type}{{|*:, {type}|}}> 49 | {{ 50 | public override {type} SolvePart1() => default; 51 | public override {type} SolvePart2() => default; 52 | }} 53 | public class Day2 : Problem<{type}{{|*:, {type}|}}> 54 | {{ 55 | public override {type} SolvePart1() => default; 56 | public override {type} SolvePart2() => default; 57 | }} 58 | public class Day3 : Problem<{type}{{|*:, {type}|}}> 59 | {{ 60 | public override {type} SolvePart1() => default; 61 | public override {type} SolvePart2() => default; 62 | }} 63 | "; 64 | 65 | var fixedCode = 66 | $@" 67 | namespace AoC.Year2021; 68 | 69 | public class Day1 : Problem<{type}> 70 | {{ 71 | public override {type} SolvePart1() => default; 72 | public override {type} SolvePart2() => default; 73 | }} 74 | public class Day2 : Problem<{type}> 75 | {{ 76 | public override {type} SolvePart1() => default; 77 | public override {type} SolvePart2() => default; 78 | }} 79 | public class Day3 : Problem<{type}> 80 | {{ 81 | public override {type} SolvePart1() => default; 82 | public override {type} SolvePart2() => default; 83 | }} 84 | "; 85 | TestCodeFixWithUsings(testCode, fixedCode); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /AdventOfCSharp.CodeFixes.Tests/ProblemClassSimplification/ProblemClassSimplifierCodeFixTests.cs: -------------------------------------------------------------------------------- 1 | using AdventOfCSharp.Analyzers; 2 | 3 | namespace AdventOfCSharp.CodeFixes.Tests.ProblemClassSimplification; 4 | 5 | public abstract class ProblemClassSimplifierCodeFixTests : BaseCodeFixTests 6 | { 7 | } 8 | -------------------------------------------------------------------------------- /AdventOfCSharp.CodeFixes/AdventOfCSharp.CodeFixes.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 10.0 6 | false 7 | 1.1.0 8 | false 9 | Alex Kalfakakos 10 | 11 | © 2021, Alex Kalfakakos 12 | MIT 13 | https://github.com/Rekkonnect/AdventOfCSharp 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | True 27 | True 28 | CodeFixStringResources.resx 29 | 30 | 31 | 32 | 33 | 34 | ResXFileCodeGenerator 35 | CodeFixStringResources.Designer.cs 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /AdventOfCSharp.CodeFixes/AoCSCodeFixProvider.cs: -------------------------------------------------------------------------------- 1 | using RoseLynn.CodeFixes; 2 | using System.Resources; 3 | 4 | namespace AdventOfCSharp.CodeFixes; 5 | 6 | public abstract class AoCSCodeFixProvider : MultipleDiagnosticCodeFixProvider 7 | { 8 | protected sealed override ResourceManager ResourceManager => CodeFixStringResources.ResourceManager; 9 | } 10 | -------------------------------------------------------------------------------- /AdventOfCSharp.CodeFixes/ProblemClassSimplifier.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis; 2 | using Microsoft.CodeAnalysis.CodeFixes; 3 | using RoseLynn; 4 | using System.Collections.Generic; 5 | using System.Composition; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | using static AdventOfCSharp.Analyzers.AoCSDiagnosticDescriptorStorage; 9 | 10 | namespace AdventOfCSharp.CodeFixes; 11 | 12 | [Shared] 13 | [ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(ProblemClassSimplifier))] 14 | public sealed class ProblemClassSimplifier : AoCSCodeFixProvider 15 | { 16 | protected override IEnumerable FixableDiagnosticDescriptors => new DiagnosticDescriptor[] 17 | { 18 | Instance[0003] 19 | }; 20 | 21 | protected override async Task PerformCodeFixActionAsync(CodeFixContext context, SyntaxNode syntaxNode, CancellationToken cancellationToken) 22 | { 23 | return await context.Document.RemoveText(context.Diagnostics[0].Location, cancellationToken); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /AdventOfCSharp.Common/AdventOfCSharp.Common.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 10.0 6 | 7 | true 8 | true 9 | 10 | AdventOfCSharp 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /AdventOfCSharp.Common/ISecretsContainer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace AdventOfCSharp; 4 | 5 | /// Decorates a class to denote that it acts as a container for secrets. 6 | public interface ISecretsContainer { } 7 | 8 | /// Marks a class as a secrets container from which information should be retrieved. 9 | /// It is important that the marked class implements the interface. 10 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] 11 | public class SecretsContainerAttribute : Attribute 12 | { 13 | } 14 | -------------------------------------------------------------------------------- /AdventOfCSharp.Common/PartSolutionAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace AdventOfCSharp; 4 | 5 | /// Denotes a part solution's status. 6 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] 7 | public sealed class PartSolutionAttribute : Attribute 8 | { 9 | public PartSolutionStatus Status { get; } 10 | 11 | /// Initializes a new instance of the . 12 | /// The status of the part solution. 13 | public PartSolutionAttribute(PartSolutionStatus status) 14 | { 15 | Status = status; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /AdventOfCSharp.Common/PartSolutionStatus.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | 4 | namespace AdventOfCSharp; 5 | 6 | /// Denotes a part's solution status. 7 | public enum PartSolutionStatus 8 | { 9 | /// The solution has not begun yet. 10 | Uninitialized, 11 | 12 | /// The solution is in progress. 13 | WIP, 14 | /// The solution is valid, but unoptimized. 15 | /// This value should be used for solutions whose execution time is unexpectedly long, or above 10-15 seconds. 16 | Unoptimized, 17 | 18 | /// The solution is valid. 19 | Valid, 20 | 21 | /// 22 | /// Represents a locked star that is not currently available. 23 | /// This is (so far) only the case for D25P2 if not all other 49 stars have been claimed. 24 | /// 25 | [EditorBrowsable(EditorBrowsableState.Never)] 26 | UnavailableLockedStar, 27 | 28 | /// The solution is under a refactoring process. 29 | /// 30 | /// This value implies that the part has been previously solved, but the implementation is being refactored. 31 | /// Consider using if the part has not been solved in a previous timeframe. 32 | /// 33 | Refactoring, 34 | 35 | /// 36 | /// The solution is interactive with the user. In other words, the solution does not solve the entire part on its own, 37 | /// as it requires some form of interaction with the user, whose input is retrieved. 38 | /// 39 | /// 40 | /// Interactive solutions are considered complete, and the star is considered acclaimed. 41 | /// When attempting to refactor the interactive solution into an automated one, consider using .
42 | /// Live execution time printing is automatically disabled for interactive solutions. 43 | ///
44 | Interactive, 45 | 46 | // We spoiled the free star 47 | [Obsolete($"The value has been renamed to {nameof(UnavailableLockedStar)}. This will be removed at version 1.5.0.", true)] 48 | [EditorBrowsable(EditorBrowsableState.Never)] 49 | UnavailableFreeStar = UnavailableLockedStar, 50 | } 51 | 52 | public static class PartSolutionStatusExtensions 53 | { 54 | public static bool IsValidSolution(this PartSolutionStatus status) => status is PartSolutionStatus.Valid or PartSolutionStatus.Unoptimized; 55 | public static bool HasBeenSolved(this PartSolutionStatus status) => IsValidSolution(status) || status is PartSolutionStatus.Refactoring or PartSolutionStatus.Interactive; 56 | } -------------------------------------------------------------------------------- /AdventOfCSharp.Common/PartSolverAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | 4 | namespace AdventOfCSharp; 5 | 6 | /// Denotes that a method solves a problem's part. It applies to standard part 1 and 2 solvers, as well as custom part or easter egg solvers. 7 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] 8 | public sealed class PartSolverAttribute : Attribute 9 | { 10 | /// The name of the part. 11 | public string PartName { get; } 12 | 13 | /// Gets the for this part solver. 14 | public PartSolverKind SolverKind { get; set; } = PartSolverKind.Official; 15 | 16 | public PartSolverAttribute(string partName) 17 | { 18 | PartName = partName; 19 | } 20 | } 21 | 22 | /// Represents the part solver kind. 23 | public enum PartSolverKind 24 | { 25 | /// Represents a solver for an official part (part 1 or 2). 26 | [EditorBrowsable(EditorBrowsableState.Advanced)] 27 | Official, 28 | /// Represents a solver for a custom part (usually fanmade "part 3"). 29 | Custom, 30 | /// Represents a solver for an easter egg. 31 | EasterEgg, 32 | } 33 | -------------------------------------------------------------------------------- /AdventOfCSharp.Common/PrintsToConsoleAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace AdventOfCSharp; 4 | 5 | /// Denotes that a method prints to the console, used to avoid conflicts when multiple sources are printing. 6 | /// Using this attribuute hints to temporarily disable live execution display. 7 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] 8 | public sealed class PrintsToConsoleAttribute : Attribute 9 | { 10 | } 11 | -------------------------------------------------------------------------------- /AdventOfCSharp.Common/ProblemDate.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | #nullable enable 6 | 7 | namespace AdventOfCSharp; 8 | 9 | public struct ProblemDate : IEquatable, IComparable 10 | { 11 | private const int dayBitMaskBits = 5; 12 | 13 | private const uint dayBitMask = (1U << dayBitMaskBits) - 1; 14 | private const uint yearBitMask = ~dayBitMask; 15 | 16 | private uint bits; 17 | 18 | public int Year 19 | { 20 | get => (int)((bits & yearBitMask) >> dayBitMaskBits); 21 | set 22 | { 23 | if (value < 2015) 24 | throw new ArgumentException("The year must be at least 2015."); 25 | 26 | bits = (bits & ~yearBitMask) | ((uint)value << dayBitMaskBits); 27 | } 28 | } 29 | public int Day 30 | { 31 | get => (int)(bits & dayBitMask); 32 | set 33 | { 34 | if (value is < 1 or > 25) 35 | throw new ArgumentException("The day must be between 1 and 25."); 36 | 37 | bits = (bits & ~dayBitMask) | (uint)value; 38 | } 39 | } 40 | 41 | public ProblemDate(int year, int day) 42 | : this() 43 | { 44 | Year = year; 45 | Day = day; 46 | } 47 | 48 | public static ProblemDate[] Dates(int year, IEnumerable days) => Dates(year, days.ToArray()); 49 | public static ProblemDate[] Dates(int year, params int[] days) 50 | { 51 | var result = new ProblemDate[days.Length]; 52 | if (days.Length is 0) 53 | return result; 54 | 55 | for (int i = 0; i < days.Length; i++) 56 | result[i] = new(year, days[i]); 57 | 58 | return result; 59 | } 60 | 61 | public void Deconstruct(out int year, out int day) 62 | { 63 | year = Year; 64 | day = Day; 65 | } 66 | 67 | // Nice fucking boilerplate 68 | public static bool operator ==(ProblemDate left, ProblemDate right) => left.bits == right.bits; 69 | public static bool operator !=(ProblemDate left, ProblemDate right) => left.bits != right.bits; 70 | public static bool operator <(ProblemDate left, ProblemDate right) => left.bits < right.bits; 71 | public static bool operator <=(ProblemDate left, ProblemDate right) => left.bits <= right.bits; 72 | public static bool operator >(ProblemDate left, ProblemDate right) => left.bits > right.bits; 73 | public static bool operator >=(ProblemDate left, ProblemDate right) => left.bits >= right.bits; 74 | 75 | public int CompareTo(ProblemDate other) => bits.CompareTo(other.bits); 76 | public bool Equals(ProblemDate other) => bits == other.bits; 77 | public override bool Equals(object? obj) => obj is ProblemDate date && Equals(date); 78 | public override int GetHashCode() => (int)bits; 79 | 80 | public override string ToString() => $"{Year}/{Day:D2}"; 81 | } 82 | -------------------------------------------------------------------------------- /AdventOfCSharp.Common/SecretStringPropertyAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace AdventOfCSharp; 4 | 5 | #nullable enable 6 | 7 | [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] 8 | public sealed class SecretStringPropertyAttribute : Attribute 9 | { 10 | public string Pattern { get; } 11 | public string Name { get; } 12 | public string Type { get; } 13 | 14 | public SecretStringPropertyAttribute(string pattern, string name, string type) 15 | { 16 | Pattern = pattern; 17 | Name = name; 18 | Type = type; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /AdventOfCSharp.Common/Utilities/LookupTable.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace AdventOfCSharp.Utilities; 6 | 7 | #nullable enable 8 | 9 | public class LookupTable : IReadOnlyCollection 10 | { 11 | protected readonly int Offset; 12 | protected readonly T?[] Values; 13 | 14 | public int Start => Offset; 15 | public int End => Offset + Count; 16 | 17 | public int Count => Values.Length; 18 | 19 | public IEnumerable NonNullValues => Values.Where(NotNull) as IEnumerable; 20 | 21 | public LookupTable(int start, int end) 22 | { 23 | Offset = start; 24 | Values = new T[end - start + 1]; 25 | } 26 | public LookupTable(LookupTable other) 27 | : this(other.Start, other.End) 28 | { 29 | other.Values.CopyTo(Values, 0); 30 | } 31 | 32 | private static bool NotNull(U value) => value is not null; 33 | 34 | public bool Contains(int index) 35 | { 36 | return ValidIndex(index) && this[index] is not null; 37 | } 38 | 39 | public T? ValueOrDefault(int index) 40 | { 41 | if (ValidIndex(index)) 42 | return this[index]; 43 | 44 | return default; 45 | } 46 | public bool SetIfValidIndex(int index, T? value) 47 | { 48 | bool valid = ValidIndex(index); 49 | if (valid) 50 | this[index] = value; 51 | return valid; 52 | } 53 | 54 | public bool ValidIndex(int index) 55 | { 56 | var arrayIndex = index - Offset; 57 | return arrayIndex >= 0 && arrayIndex < Values.Length; 58 | } 59 | 60 | public virtual T? this[int index] 61 | { 62 | get => Values[index - Offset]; 63 | set => Values[index - Offset] = value; 64 | } 65 | 66 | public IEnumerator GetEnumerator() => NonNullValues.GetEnumerator(); 67 | IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); 68 | } 69 | -------------------------------------------------------------------------------- /AdventOfCSharp.Package/AdventOfCSharp.Analyzers.Package.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | false 7 | true 8 | true 9 | 10 | true 11 | 1.4.2 12 | 13 | Alex Kalfakakos 14 | 15 | advent-of-code, aoc 16 | Analyzers for using Advent of C#. 17 | © 2021-2022, Alex Kalfakakos 18 | MIT 19 | https://github.com/Rekkonnect/AdventOfCSharp 20 | False 21 | AdventOfCSharp.Analyzers 22 | AdventOfCSharp.Analyzers 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /AdventOfCSharp.Package/tools/install.ps1: -------------------------------------------------------------------------------- 1 | param($installPath, $toolsPath, $package, $project) 2 | 3 | if($project.Object.SupportsPackageDependencyResolution) 4 | { 5 | if($project.Object.SupportsPackageDependencyResolution()) 6 | { 7 | # Do not install analyzers via install.ps1, instead let the project system handle it. 8 | return 9 | } 10 | } 11 | 12 | $analyzersPaths = Join-Path (Join-Path (Split-Path -Path $toolsPath -Parent) "analyzers") * -Resolve 13 | 14 | foreach($analyzersPath in $analyzersPaths) 15 | { 16 | if (Test-Path $analyzersPath) 17 | { 18 | # Install the language agnostic analyzers. 19 | foreach ($analyzerFilePath in Get-ChildItem -Path "$analyzersPath\*.dll" -Exclude *.resources.dll) 20 | { 21 | if($project.Object.AnalyzerReferences) 22 | { 23 | $project.Object.AnalyzerReferences.Add($analyzerFilePath.FullName) 24 | } 25 | } 26 | } 27 | } 28 | 29 | # $project.Type gives the language name like (C# or VB.NET) 30 | $languageFolder = "" 31 | if($project.Type -eq "C#") 32 | { 33 | $languageFolder = "cs" 34 | } 35 | if($project.Type -eq "VB.NET") 36 | { 37 | $languageFolder = "vb" 38 | } 39 | if($languageFolder -eq "") 40 | { 41 | return 42 | } 43 | 44 | foreach($analyzersPath in $analyzersPaths) 45 | { 46 | # Install language specific analyzers. 47 | $languageAnalyzersPath = join-path $analyzersPath $languageFolder 48 | if (Test-Path $languageAnalyzersPath) 49 | { 50 | foreach ($analyzerFilePath in Get-ChildItem -Path "$languageAnalyzersPath\*.dll" -Exclude *.resources.dll) 51 | { 52 | if($project.Object.AnalyzerReferences) 53 | { 54 | $project.Object.AnalyzerReferences.Add($analyzerFilePath.FullName) 55 | } 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /AdventOfCSharp.Package/tools/uninstall.ps1: -------------------------------------------------------------------------------- 1 | param($installPath, $toolsPath, $package, $project) 2 | 3 | if($project.Object.SupportsPackageDependencyResolution) 4 | { 5 | if($project.Object.SupportsPackageDependencyResolution()) 6 | { 7 | # Do not uninstall analyzers via uninstall.ps1, instead let the project system handle it. 8 | return 9 | } 10 | } 11 | 12 | $analyzersPaths = Join-Path (Join-Path (Split-Path -Path $toolsPath -Parent) "analyzers") * -Resolve 13 | 14 | foreach($analyzersPath in $analyzersPaths) 15 | { 16 | # Uninstall the language agnostic analyzers. 17 | if (Test-Path $analyzersPath) 18 | { 19 | foreach ($analyzerFilePath in Get-ChildItem -Path "$analyzersPath\*.dll" -Exclude *.resources.dll) 20 | { 21 | if($project.Object.AnalyzerReferences) 22 | { 23 | $project.Object.AnalyzerReferences.Remove($analyzerFilePath.FullName) 24 | } 25 | } 26 | } 27 | } 28 | 29 | # $project.Type gives the language name like (C# or VB.NET) 30 | $languageFolder = "" 31 | if($project.Type -eq "C#") 32 | { 33 | $languageFolder = "cs" 34 | } 35 | if($project.Type -eq "VB.NET") 36 | { 37 | $languageFolder = "vb" 38 | } 39 | if($languageFolder -eq "") 40 | { 41 | return 42 | } 43 | 44 | foreach($analyzersPath in $analyzersPaths) 45 | { 46 | # Uninstall language specific analyzers. 47 | $languageAnalyzersPath = join-path $analyzersPath $languageFolder 48 | if (Test-Path $languageAnalyzersPath) 49 | { 50 | foreach ($analyzerFilePath in Get-ChildItem -Path "$languageAnalyzersPath\*.dll" -Exclude *.resources.dll) 51 | { 52 | if($project.Object.AnalyzerReferences) 53 | { 54 | try 55 | { 56 | $project.Object.AnalyzerReferences.Remove($analyzerFilePath.FullName) 57 | } 58 | catch 59 | { 60 | 61 | } 62 | } 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /AdventOfCSharp.ProblemSolutionResources/AdventOfCSharp.ProblemSolutionResources.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /AdventOfCSharp.ProblemSolutionResources/Inputs/2021/1.txt: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 3 4 | 4 5 | 5 6 | 6 7 | 7 8 | 8 9 | 9 10 | 10 11 | -------------------------------------------------------------------------------- /AdventOfCSharp.ProblemSolutionResources/Inputs/2021/1T1.txt: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 3 4 | 4 5 | 5 6 | -------------------------------------------------------------------------------- /AdventOfCSharp.ProblemSolutionResources/Outputs/2021/1.txt: -------------------------------------------------------------------------------- 1 | 11 2 | 55 3 | -------------------------------------------------------------------------------- /AdventOfCSharp.ProblemSolutionResources/Outputs/2021/1T1.txt: -------------------------------------------------------------------------------- 1 | 6 2 | 15 3 | -------------------------------------------------------------------------------- /AdventOfCSharp.ProblemSolutionResources/Problems/Year2021/Day1.cs: -------------------------------------------------------------------------------- 1 | #nullable disable 2 | 3 | using System.Linq; 4 | 5 | namespace AdventOfCSharp.ProblemSolutionResources.Problems.Year2021; 6 | 7 | public class Day1 : Problem 8 | { 9 | private int[] numbers; 10 | 11 | public override int SolvePart1() 12 | { 13 | return numbers.Min() + numbers.Max(); 14 | } 15 | public override int SolvePart2() 16 | { 17 | return numbers.Sum(); 18 | } 19 | 20 | protected override void LoadState() 21 | { 22 | numbers = FileNumbersInt32; 23 | } 24 | protected override void ResetState() 25 | { 26 | numbers = null; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /AdventOfCSharp.ProblemSolutionResources/ResourceFileManagement.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | 3 | namespace AdventOfCSharp.ProblemSolutionResources; 4 | 5 | public static class ResourceFileManagement 6 | { 7 | public static string GetProjectBaseDirectory() 8 | { 9 | var directoryName = $@"{nameof(AdventOfCSharp)}.{nameof(ProblemSolutionResources)}"; 10 | // This solution will work for as long as the project structure does not include any deeper nesting 11 | // No idea how abstractable this solution can be for other projects 12 | // TODO: Explore resource storages 13 | var solutionDirectory = Directory.GetParent(ResourceFileHelpers.GetBaseCodeDirectory())!.FullName; 14 | return $@"{solutionDirectory}\{directoryName}"; 15 | } 16 | 17 | public static void SetResourceProjectAsBaseProblemFileDirectory() 18 | { 19 | ProblemFiles.CustomBaseDirectory = GetProjectBaseDirectory(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /AdventOfCSharp.ProblemSolutionTests/AdventOfCSharp.ProblemSolutionTests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net6.0 5 | enable 6 | 7 | false 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | all 16 | runtime; build; native; contentfiles; analyzers; buildtransitive 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /AdventOfCSharp.SourceGenerators.Tests/AdventOfCSharp.SourceGenerators.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net6.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /AdventOfCSharp.SourceGenerators.Tests/Helpers/BenchmarkSpecificMetadataReferences.cs: -------------------------------------------------------------------------------- 1 | using AdventOfCSharp.AnalysisTestsBase.Helpers; 2 | using AdventOfCSharp.Benchmarking; 3 | using Microsoft.CodeAnalysis; 4 | using RoseLynn; 5 | using System; 6 | using System.Collections.Immutable; 7 | 8 | namespace AdventOfCSharp.SourceGenerators.Tests.Helpers; 9 | 10 | public static class BenchmarkSpecificMetadataReferences 11 | { 12 | public static readonly MetadataReference NET6_0MetadataReference; 13 | 14 | public static readonly ImmutableArray BaseBenchmarkReferences; 15 | public static readonly ImmutableArray AllBaseReferences; 16 | public static readonly ImmutableArray AllBaseReferencesWithRuntime; 17 | 18 | static BenchmarkSpecificMetadataReferences() 19 | { 20 | NET6_0MetadataReference = MetadataReferenceFactory.CreateFromType(); 21 | 22 | BaseBenchmarkReferences = ImmutableArray.Create(new MetadataReference[] 23 | { 24 | // AdventOfCSharp.Benchmarking 25 | MetadataReferenceFactory.CreateFromType(), 26 | 27 | // AdventOfCSharp.Benchmarking.Common 28 | MetadataReferenceFactory.CreateFromType(), 29 | 30 | MetadataReferenceFactory.CreateFromType(), 31 | }); 32 | 33 | AllBaseReferences = BaseBenchmarkReferences.AddRange(AoCSMetadataReferences.BaseReferences); 34 | 35 | AllBaseReferencesWithRuntime = AllBaseReferences.AddRange(RuntimeReferences.NET6_0); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /AdventOfCSharp.SourceGenerators.Tests/Helpers/RuntimeReferences.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis; 2 | using Microsoft.CodeAnalysis.Testing; 3 | using System.Collections.Immutable; 4 | using System.Threading; 5 | 6 | namespace AdventOfCSharp.SourceGenerators.Tests.Helpers; 7 | 8 | public static class RuntimeReferences 9 | { 10 | public static readonly ImmutableArray NET6_0; 11 | 12 | static RuntimeReferences() 13 | { 14 | NET6_0 = ReferenceAssemblies.Net.Net60.ResolveAsync(LanguageNames.CSharp, CancellationToken.None).Result; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /AdventOfCSharp.SourceGenerators.Tests/SourceFileListExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis.Testing; 2 | using Microsoft.CodeAnalysis.Text; 3 | using System.Collections.Generic; 4 | 5 | namespace AdventOfCSharp.SourceGenerators.Tests; 6 | 7 | public static class SourceFileListExtensions 8 | { 9 | public static void AddRange(this SourceFileList list, IEnumerable sources) 10 | { 11 | foreach (var source in sources) 12 | list.Add(source); 13 | } 14 | public static void AddRange(this SourceFileList list, IEnumerable sources) 15 | { 16 | foreach (var source in sources) 17 | list.Add(source); 18 | } 19 | } -------------------------------------------------------------------------------- /AdventOfCSharp.SourceGenerators.Tests/Verifiers/CSharpSourceGeneratorVerifier.cs: -------------------------------------------------------------------------------- 1 | using AdventOfCSharp.AnalysisTestsBase.Verifiers; 2 | using AdventOfCSharp.SourceGenerators.Tests.Helpers; 3 | using AdventOfCSharp.Testing; 4 | using Microsoft.CodeAnalysis; 5 | using Microsoft.CodeAnalysis.CSharp; 6 | using Microsoft.CodeAnalysis.CSharp.Testing; 7 | using Microsoft.CodeAnalysis.Testing; 8 | using Microsoft.CodeAnalysis.Testing.Verifiers; 9 | using System; 10 | using System.Collections.Immutable; 11 | using System.Threading; 12 | using System.Threading.Tasks; 13 | 14 | namespace AdventOfCSharp.SourceGenerators.Tests.Verifiers; 15 | 16 | public static class CSharpSourceGeneratorVerifier 17 | where TSourceGenerator : ISourceGenerator, new() 18 | { 19 | public class Test : CSharpSourceGeneratorTest 20 | { 21 | // Expose it like that 22 | public string AssemblyName => DefaultTestProjectName; 23 | 24 | public Test() 25 | { 26 | CSharpVerifierHelper.SetupNET6AndAoCSDependencies(this); 27 | TestState.AdditionalReferences.AddRange(BenchmarkSpecificMetadataReferences.BaseBenchmarkReferences); 28 | TestState.AdditionalReferences.AddRange(TestingSpecificMetadataReferences.BaseTestingReferences); 29 | } 30 | 31 | public void AddFrameworkReference(TestingFramework framework) 32 | { 33 | TestState.AdditionalReferences.AddRange(TestingSpecificMetadataReferences.ForFramework(framework).References); 34 | } 35 | 36 | protected override CompilationOptions CreateCompilationOptions() 37 | { 38 | var compilationOptions = base.CreateCompilationOptions(); 39 | return compilationOptions.WithSpecificDiagnosticOptions( 40 | compilationOptions.SpecificDiagnosticOptions.SetItems(GetNullableWarningsFromCompiler())); 41 | } 42 | 43 | public LanguageVersion LanguageVersion { get; set; } = LanguageVersion.Default; 44 | 45 | private static ImmutableDictionary GetNullableWarningsFromCompiler() 46 | { 47 | string[] args = { "/warnaserror:nullable" }; 48 | var commandLineArguments = CSharpCommandLineParser.Default.Parse(args, baseDirectory: Environment.CurrentDirectory, sdkDirectory: Environment.CurrentDirectory); 49 | var nullableWarnings = commandLineArguments.CompilationOptions.SpecificDiagnosticOptions; 50 | 51 | return nullableWarnings; 52 | } 53 | 54 | protected override ParseOptions CreateParseOptions() 55 | { 56 | return (base.CreateParseOptions() as CSharpParseOptions).WithLanguageVersion(LanguageVersion); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /AdventOfCSharp.SourceGenerators/AdventOfCSharp.SourceGenerators.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.0 5 | 10.0 6 | 7 | true 8 | true 9 | 10 | 1.4.0.1 11 | 12 | advent-of-code, aoc, source-generator, unit-test, test, benchmark 13 | Source generators for generating benchmarks and unit tests for the Advent of C# framework. 14 | © 2022, Alex Kalfakakos 15 | https://github.com/Rekkonnect/AdventOfCSharp 16 | Alex Kalfakakos 17 | MIT 18 | False 19 | AdventOfCSharp.SourceGenerators 20 | AdventOfCSharp.SourceGenerators 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | all 29 | runtime; build; native; contentfiles; analyzers; buildtransitive 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /AdventOfCSharp.SourceGenerators/Utilities/GeneratedSourceMappings.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis.Text; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace AdventOfCSharp.SourceGenerators.Utilities; 6 | 7 | public sealed class GeneratedSourceMappings : SortedDictionary 8 | { 9 | public GeneratedSourceMappings() { } 10 | public GeneratedSourceMappings(IComparer comparer) 11 | : base(comparer) { } 12 | 13 | public void Add(string hintName, string source) 14 | { 15 | Add(hintName, SourceText.From(source, Encoding.UTF8)); 16 | } 17 | 18 | public void Set(string hintName, string source) 19 | { 20 | this[hintName] = SourceText.From(source, Encoding.UTF8); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /AdventOfCSharp.Testing.Common/AdventOfCSharp.Testing.Common.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 10.0 6 | 7 | true 8 | true 9 | 10 | AdventOfCSharp.Testing 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /AdventOfCSharp.Testing.Common/AoCSTestAssemblyAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace AdventOfCSharp.Testing; 4 | 5 | [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false)] 6 | public sealed class AoCSTestAssemblyAttribute : Attribute 7 | { 8 | public string ProblemFileBaseDirectory { get; } 9 | 10 | public AoCSTestAssemblyAttribute(string problemFileBaseDirectory) 11 | { 12 | ProblemFileBaseDirectory = problemFileBaseDirectory; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /AdventOfCSharp.Testing.MSTest/AdventOfCSharp.Testing.MSTest.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | 7 | true 8 | true 9 | 10 | 1.4.1 11 | 12 | advent-of-code, aoc, testing, mstest 13 | Testing components for the Advent of C# framework for MSTest projects. 14 | © 2022, Alex Kalfakakos 15 | https://github.com/Rekkonnect/AdventOfCSharp 16 | Alex Kalfakakos 17 | MIT 18 | False 19 | AdventOfCSharp.Testing.MSTest 20 | AdventOfCSharp.Testing.MSTest 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /AdventOfCSharp.Testing.MSTest/MSTestProblemValidationTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.VisualStudio.TestTools.UnitTesting; 2 | 3 | namespace AdventOfCSharp.Testing.MSTest; 4 | 5 | public abstract class MSTestProblemValidationTests : FrameworkUnboundProblemValidationTests 6 | where TProblem : Problem, new() 7 | { 8 | protected sealed override void AssertEquality(T expected, T actual) 9 | { 10 | Assert.AreEqual(expected, actual); 11 | } 12 | } -------------------------------------------------------------------------------- /AdventOfCSharp.Testing.NUnit/AdventOfCSharp.Testing.NUnit.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | 7 | true 8 | true 9 | 10 | 1.4.1 11 | 12 | advent-of-code, aoc, testing, nunit 13 | Testing components for the Advent of C# framework for NUnit projects. 14 | © 2022, Alex Kalfakakos 15 | https://github.com/Rekkonnect/AdventOfCSharp 16 | Alex Kalfakakos 17 | MIT 18 | False 19 | AdventOfCSharp.Testing.NUnit 20 | AdventOfCSharp.Testing.NUnit 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /AdventOfCSharp.Testing.NUnit/NUnitProblemValidationTests.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | 3 | namespace AdventOfCSharp.Testing.NUnit; 4 | 5 | public abstract class NUnitProblemValidationTests : FrameworkUnboundProblemValidationTests 6 | where TProblem : Problem, new() 7 | { 8 | protected sealed override void AssertEquality(T expected, T actual) 9 | { 10 | Assert.AreEqual(expected, actual); 11 | } 12 | } -------------------------------------------------------------------------------- /AdventOfCSharp.Testing.Tests.Common/AdventOfCSharp.Testing.Tests.Common.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /AdventOfCSharp.Testing.Tests.Common/AoCSTestAssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCSharp.Testing.Tests.Common; 2 | 3 | public static class AoCSTestAssemblyInfo 4 | { 5 | // Relative pathing to hide actual path 6 | // Always prefer using absolute pathing when in a private environment 7 | public const string ProblemFileBaseDirectory = @"..\..\..\..\AdventOfCSharp.ProblemSolutionResources"; 8 | } 9 | -------------------------------------------------------------------------------- /AdventOfCSharp.Testing.Tests.MSTest/AdventOfCSharp.Testing.Tests.MSTest.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net6.0 5 | enable 6 | 7 | false 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | all 16 | runtime; build; native; contentfiles; analyzers; buildtransitive 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /AdventOfCSharp.Testing.Tests.MSTest/TestDeclaration.cs: -------------------------------------------------------------------------------- 1 | using AdventOfCSharp.Testing; 2 | using AdventOfCSharp.Testing.Tests.Common; 3 | 4 | [assembly: AoCSTestAssembly(AoCSTestAssemblyInfo.ProblemFileBaseDirectory)] 5 | -------------------------------------------------------------------------------- /AdventOfCSharp.Testing.Tests.NUnit/AdventOfCSharp.Testing.Tests.NUnit.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net6.0 5 | enable 6 | 7 | false 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | all 16 | runtime; build; native; contentfiles; analyzers; buildtransitive 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /AdventOfCSharp.Testing.Tests.NUnit/TestDeclaration.cs: -------------------------------------------------------------------------------- 1 | using AdventOfCSharp.Testing; 2 | using AdventOfCSharp.Testing.Tests.Common; 3 | 4 | [assembly: AoCSTestAssembly(AoCSTestAssemblyInfo.ProblemFileBaseDirectory)] 5 | -------------------------------------------------------------------------------- /AdventOfCSharp.Testing.Tests.XUnit/AdventOfCSharp.Testing.Tests.XUnit.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | 7 | false 8 | 9 | 10 | 11 | 12 | 13 | 14 | runtime; build; native; contentfiles; analyzers; buildtransitive 15 | all 16 | 17 | 18 | runtime; build; native; contentfiles; analyzers; buildtransitive 19 | all 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /AdventOfCSharp.Testing.Tests.XUnit/TestDeclaration.cs: -------------------------------------------------------------------------------- 1 | using AdventOfCSharp.Testing; 2 | using AdventOfCSharp.Testing.Tests.Common; 3 | 4 | [assembly: AoCSTestAssembly(AoCSTestAssemblyInfo.ProblemFileBaseDirectory)] 5 | -------------------------------------------------------------------------------- /AdventOfCSharp.Testing.xUnit/AdventOfCSharp.Testing.XUnit.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | 7 | true 8 | true 9 | 10 | 1.4.1 11 | 12 | advent-of-code, aoc, testing, xunit 13 | Testing components for the Advent of C# framework for xUnit projects. 14 | © 2022, Alex Kalfakakos 15 | https://github.com/Rekkonnect/AdventOfCSharp 16 | Alex Kalfakakos 17 | MIT 18 | False 19 | AdventOfCSharp.Testing.XUnit 20 | AdventOfCSharp.Testing.XUnit 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /AdventOfCSharp.Testing.xUnit/XUnitProblemValidationTests.cs: -------------------------------------------------------------------------------- 1 | using Xunit; 2 | 3 | namespace AdventOfCSharp.Testing.XUnit; 4 | 5 | public abstract class XUnitProblemValidationTests : FrameworkUnboundProblemValidationTests 6 | where TProblem : Problem, new() 7 | { 8 | protected sealed override void AssertEquality(T expected, T actual) 9 | { 10 | Assert.Equal(expected, actual); 11 | } 12 | } -------------------------------------------------------------------------------- /AdventOfCSharp.Testing/AdventOfCSharp.Testing.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | enable 7 | 8 | true 9 | true 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /AdventOfCSharp.Testing/FrameworkUnboundProblemValidationTests.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCSharp.Testing; 2 | 3 | public abstract class FrameworkUnboundProblemValidationTests 4 | where TProblem : Problem, new() 5 | { 6 | private readonly ProblemRunner runner = new(new TProblem()); 7 | 8 | protected FrameworkUnboundProblemValidationTests() 9 | { 10 | ExecutionTimePrinting.EnableLivePrinting = false; 11 | 12 | SetupProblemFileBaseDirectory(); 13 | } 14 | 15 | protected void PartTestImpl(int part) 16 | { 17 | runner.Problem.ResetLoadedState(); 18 | runner.Problem.EnsureLoadedState(); 19 | 20 | var validation = runner.ValidatePart(part); 21 | AssertEquality(ValidationResult.Valid, validation?.Result); 22 | } 23 | 24 | protected abstract void AssertEquality(T expected, T actual); 25 | 26 | protected void SetupProblemFileBaseDirectory() 27 | { 28 | ProblemFiles.CustomBaseDirectory = GetProblemFileBaseDirectory(); 29 | return; 30 | 31 | // In the case environment variables are needed 32 | var environmentBaseDirectory = ProblemFiles.ReadBaseDirectoryFromEnvironmentVariable(); 33 | if (environmentBaseDirectory is not null) 34 | return; 35 | 36 | var directory = GetProblemFileBaseDirectory(); 37 | ProblemFiles.SetCustomBaseDirectorySyncEnvironmentVariable(directory); 38 | } 39 | protected virtual string? GetProblemFileBaseDirectory() => null; 40 | } 41 | -------------------------------------------------------------------------------- /AdventOfCSharp.Tests/AdventOfCSharp.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net6.0 5 | enable 6 | 7 | false 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | all 16 | runtime; build; native; contentfiles; analyzers; buildtransitive 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /AdventOfCSharp.Tests/InputGeneratorTests.cs: -------------------------------------------------------------------------------- 1 | using AdventOfCSharp.Generation; 2 | using Garyon.Extensions; 3 | using NUnit.Framework; 4 | using System.Linq; 5 | 6 | namespace AdventOfCSharp.Tests; 7 | 8 | public class InputGeneratorTests 9 | { 10 | private const int numberCount = 1000; 11 | private const int minNumber = 1; 12 | private const int maxNumber = 5; 13 | 14 | [Test] 15 | public void Generate() 16 | { 17 | var generator = new DummyInputGenerator(); 18 | var next = generator.GenerateNext(); 19 | 20 | var lines = next.GetLines(); 21 | var parsedNumbers = lines.Select(int.Parse).ToArray(); 22 | Assert.AreEqual(numberCount, parsedNumbers.Length); 23 | foreach (var number in parsedNumbers) 24 | Assert.True(number is >= minNumber and <= maxNumber); 25 | } 26 | 27 | public sealed class DummyInputGenerator : InputGenerator 28 | { 29 | public override int Year => 2021; 30 | public override int Day => 1; 31 | 32 | protected override bool AlwaysGeneratesValidInputs => true; 33 | 34 | public override string GenerateNext() 35 | { 36 | return Integers(numberCount).Ranging(minNumber, maxNumber).PerLine().Build(); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /AdventOfCSharp.Tests/ProblemRunnerTests.cs: -------------------------------------------------------------------------------- 1 | using AdventOfCSharp.ProblemSolutionResources; 2 | using NUnit.Framework; 3 | 4 | namespace AdventOfCSharp.Tests; 5 | 6 | public class ProblemRunnerTests 7 | { 8 | [SetUp] 9 | public void Setup() 10 | { 11 | ResourceFileManagement.SetResourceProjectAsBaseProblemFileDirectory(); 12 | } 13 | 14 | /* 15 | * So far, this test alone proves that the following work right: 16 | * - Input loading 17 | * - Output loading 18 | * - Problem running 19 | * - Test case loading 20 | * - Output validation 21 | */ 22 | [Test] 23 | public void ValidateProblem() 24 | { 25 | var runner = ProblemRunner.ForProblem(2021, 1)!; 26 | Assert.False(runner.FullyValidateAllTestCases().HasInvalidResults); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /AdventOfCSharp.Tests/Utilities/LookupTableTests.cs: -------------------------------------------------------------------------------- 1 | using AdventOfCSharp.Utilities; 2 | using NUnit.Framework; 3 | 4 | namespace AdventOfCSharp.Tests.Utilities; 5 | 6 | public class LookupTableTests 7 | { 8 | [Test] 9 | public void TestValueContainer() 10 | { 11 | var table = new LookupTable(1, 10); 12 | Assert.AreEqual(10, table.Count); 13 | 14 | SetAssert(1, 3); 15 | SetAssert(10, 4); 16 | SetAssert(5, 6); 17 | 18 | void SetAssert(int index, int value) 19 | { 20 | table[index] = value; 21 | Assert.AreEqual(value, table[index]); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /AdventOfCSharp/AdventOfCSharp.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | 7 | true 8 | true 9 | 10 | 1.4.2 11 | 12 | advent-of-code, aoc 13 | An aspiring AoC problem solving framework. 14 | © 2021-2022, Alex Kalfakakos 15 | https://github.com/Rekkonnect/AdventOfCSharp 16 | Alex Kalfakakos 17 | MIT 18 | False 19 | AdventOfCSharp 20 | AdventOfCSharp 21 | Improvements: 22 | - Enhanced handling console buffer height overflows 23 | - Customizable by hand as well 24 | - Rename an enum value to avoid spoilers 25 | - Santa does not like spoilers 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | True 41 | True 42 | GlyphResources.resx 43 | 44 | 45 | 46 | 47 | 48 | ResXFileCodeGenerator 49 | GlyphResources.Designer.cs 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /AdventOfCSharp/AnswerStringConverter.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCSharp; 2 | 3 | public abstract class AnswerStringConverter 4 | { 5 | /// The value to convert. Its type must strictly match the target type of the converter. 6 | /// The string result that is to be given on the website. 7 | /// Do NOT use unless you do not know the type of the converter that will be used. 8 | public string? ConvertObject(object value) 9 | { 10 | var convertMethod = GetType().GetMethods().Single(method => method.HasCustomAttribute()); 11 | return convertMethod.Invoke(this, new[] { value }) as string; 12 | } 13 | } 14 | public abstract class AnswerStringConverter : AnswerStringConverter 15 | { 16 | [ConvertMethod] 17 | public abstract string? Convert(TSource value); 18 | } 19 | 20 | public sealed class CommonAnswerStringConverter : AnswerStringConverter 21 | { 22 | public static CommonAnswerStringConverter Instance { get; } = new(); 23 | 24 | public override string Convert(object value) => value.ToString()!; 25 | } 26 | 27 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] 28 | internal sealed class ConvertMethodAttribute : Attribute { } -------------------------------------------------------------------------------- /AdventOfCSharp/BufferHeightHandlingMode.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCSharp; 2 | 3 | /// 4 | /// Provides the available options to handling overflowing the 5 | /// console's buffer. 6 | /// 7 | public enum BufferHeightHandlingMode 8 | { 9 | /// 10 | /// Do nothing to handle the overflow. This means that there 11 | /// may be an exception thrown, or nothing being printed to 12 | /// the console, depending on the operating system and the 13 | /// terminal that this program runs on. 14 | /// 15 | /// 16 | /// This is not recommended for usage on standard platforms 17 | /// and terminals, including Windows, PowerShell, bash, etc. 18 | /// 19 | None, 20 | /// 21 | /// Increase the buffer height sufficiently so that the new 22 | /// content can be printed. Not recommended, as successive 23 | /// invocations may slow performance down. 24 | /// 25 | /// This is not yet implemented. 26 | [Obsolete("This is not implemented; read the documentation for more info.", true)] 27 | IncreaseBufferHeight, 28 | /// 29 | /// Increase the buffer height to the maximum value. This 30 | /// still does not guarantee going past the maximum value. 31 | /// This approach should suffice for most cases of normal 32 | /// usage of the program. 33 | /// 34 | /// 35 | /// This is only available on Windows. Other platforms do 36 | /// not support adjusting the buffer height. 37 | /// 38 | MaximizeBufferHeight, 39 | /// 40 | /// Clear the entire buffer and write the new content. 41 | /// This option will purposefully underestimate the remaining 42 | /// space to make room for the content that is intended to be 43 | /// printed. Previously important content may be lost and not 44 | /// reprinted on the buffer. 45 | /// 46 | ClearBuffer, 47 | /// 48 | /// Print newlines using 49 | /// until there is enough height to print the new content, or 50 | /// navigate the cursor around. Restrictingly low buffer 51 | /// heights may cause issues. 52 | /// 53 | /// 54 | /// This is the default option for most platforms and 55 | /// terminals. 56 | /// 57 | PrintNewlines, 58 | } 59 | -------------------------------------------------------------------------------- /AdventOfCSharp/ConsoleBufferHandling.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCSharp; 2 | 3 | using static Utilities.ConsolePrinting; 4 | 5 | public static class ConsoleBufferHandling 6 | { 7 | /// 8 | /// Gets or sets the current 9 | /// that will be used when setting the cursor position to heights 10 | /// beyond the currently available on the buffer. 11 | /// 12 | public static BufferHeightHandlingMode BufferHeightHandlingMode { get; set; } 13 | 14 | static ConsoleBufferHandling() 15 | { 16 | BufferHeightHandlingMode = DefaultBufferHeightHandlingModeForCurrentPlatform(); 17 | } 18 | 19 | public static void PrepareAccessingCursorTop(int lines) 20 | { 21 | int top = Console.CursorTop + lines; 22 | AccessCursorTop(top); 23 | } 24 | 25 | public static void AccessCursorTop(int top) 26 | { 27 | if (top < 0) 28 | throw new ArgumentOutOfRangeException(nameof(top), "The cursor top may not be a negative value."); 29 | 30 | int missingLines = top - Console.BufferHeight + 1; 31 | if (missingLines <= 0) 32 | return; 33 | 34 | switch (BufferHeightHandlingMode) 35 | { 36 | case BufferHeightHandlingMode.None: 37 | break; 38 | 39 | case BufferHeightHandlingMode.MaximizeBufferHeight: 40 | Console.BufferHeight = short.MaxValue; 41 | break; 42 | 43 | case BufferHeightHandlingMode.ClearBuffer: 44 | Console.Clear(); 45 | break; 46 | 47 | case BufferHeightHandlingMode.PrintNewlines: 48 | int previousLeft = Console.CursorLeft; 49 | WriteNewLines(missingLines); 50 | Console.CursorTop -= missingLines; 51 | Console.CursorLeft = previousLeft; 52 | break; 53 | } 54 | } 55 | 56 | /// 57 | /// Gets the default for 58 | /// the current platform. 59 | /// 60 | /// 61 | /// for all 62 | /// platforms; subject to change in the future depending on feedback 63 | /// and system-wide adjustments. 64 | /// 65 | public static BufferHeightHandlingMode DefaultBufferHeightHandlingModeForCurrentPlatform() 66 | { 67 | var operatingSystem = Environment.OSVersion; 68 | 69 | switch (operatingSystem.Platform) 70 | { 71 | case PlatformID.Win32NT: 72 | case PlatformID.Unix: 73 | case PlatformID.Other: 74 | return BufferHeightHandlingMode.PrintNewlines; 75 | 76 | default: 77 | return BufferHeightHandlingMode.None; 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /AdventOfCSharp/Cookies.cs: -------------------------------------------------------------------------------- 1 | #nullable enable 2 | 3 | using System.Net.Http; 4 | 5 | namespace AdventOfCSharp; 6 | 7 | /// Represents an uninitialized cookie container for performing input requests. 8 | /// WARNING: Do not eat! Santa will be sad! 9 | public abstract class Cookies : ISecretsContainer 10 | { 11 | private const string gaPattern = @"GA\d\.\d\.\d{10}\.\d{10}"; 12 | private const string sessionPattern = @"[0-9a-f]{128}"; 13 | 14 | private const string cookieName = "cookie"; 15 | 16 | [SecretStringProperty(gaPattern, "_ga", cookieName)] 17 | public abstract string GA { get; } 18 | [SecretStringProperty(sessionPattern, "session", cookieName)] 19 | public abstract string Session { get; } 20 | 21 | public void AddToDefaultRequestHeaders(HttpClient client) 22 | { 23 | client.DefaultRequestHeaders.Add("cookie", ToString()); 24 | } 25 | 26 | public override string ToString() 27 | { 28 | return $"_ga={GA}; session={Session}"; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /AdventOfCSharp/Extensions/ConsoleColorExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCSharp.Extensions; 2 | 3 | public static class ConsoleColorExtensions 4 | { 5 | public static ConsoleColor Darken(this ConsoleColor color) => color switch 6 | { 7 | ConsoleColor.Gray => ConsoleColor.DarkGray, 8 | >= ConsoleColor.DarkGray => color - 8, 9 | _ => color, 10 | }; 11 | public static ConsoleColor Lighten(this ConsoleColor color) => color switch 12 | { 13 | ConsoleColor.DarkGray => ConsoleColor.Gray, 14 | <= ConsoleColor.Gray => color + 8, 15 | _ => color, 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /AdventOfCSharp/Extensions/IEnumerableExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | 3 | namespace AdventOfCSharp.Extensions; 4 | 5 | public static class IEnumerableExtensions 6 | { 7 | public static IDictionary ToDictionaryWithNotNullKeys(this IEnumerable values, Func keySelector) 8 | where TKey : notnull 9 | { 10 | return new Dictionary(Pairs()); 11 | 12 | IEnumerable> Pairs() 13 | { 14 | foreach (var value in values) 15 | { 16 | var pair = new KeyValuePair(keySelector(value), value); 17 | if (pair.Key is null) 18 | continue; 19 | 20 | yield return pair; 21 | } 22 | } 23 | } 24 | public static IDictionary ToDictionaryFiltered(this IEnumerable values, Func keySelector, Predicate valuePredicate) 25 | where TKey : notnull 26 | { 27 | return values.WherePredicate(valuePredicate).ToDictionary(keySelector); 28 | } 29 | 30 | public static TSource? MinSource(this IEnumerable source, Func selector) 31 | where TKey : IComparable 32 | { 33 | return source.ExtremumSource(selector, ComparisonResult.Less); 34 | } 35 | public static TSource? MaxSource(this IEnumerable source, Func selector) 36 | where TKey : IComparable 37 | { 38 | return source.ExtremumSource(selector, ComparisonResult.Greater); 39 | } 40 | 41 | public static TSource? ExtremumSource(this IEnumerable source, Func selector, ComparisonResult matchingResult) 42 | where TKey : IComparable 43 | { 44 | var first = source.FirstOrDefault(); 45 | 46 | if (source.Count() <= 1) 47 | return first; 48 | 49 | var extremumSelected = selector(first!); 50 | var extremumSource = first; 51 | 52 | foreach (var sourceValue in source.Skip(1)) 53 | { 54 | var selected = selector(sourceValue); 55 | var comparison = selected.GetComparisonResult(extremumSelected); 56 | 57 | if (comparison == matchingResult) 58 | { 59 | extremumSource = sourceValue; 60 | extremumSelected = selected; 61 | } 62 | else if (comparison is ComparisonResult.Equal) 63 | { 64 | extremumSource = default; 65 | } 66 | } 67 | 68 | return extremumSource; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /AdventOfCSharp/Extensions/ISetExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCSharp.Extensions; 2 | 3 | public static class ISetExtensions 4 | { 5 | public static CollectionOperationResult ToggleElement(this ISet source, T element) 6 | { 7 | if (source.Add(element)) 8 | return CollectionOperationResult.Added; 9 | 10 | source.Remove(element); 11 | return CollectionOperationResult.Removed; 12 | } 13 | } 14 | 15 | public enum CollectionOperationResult 16 | { 17 | Added, 18 | Removed, 19 | // This could be theoretically expanded to support all sorts of operations 20 | } 21 | -------------------------------------------------------------------------------- /AdventOfCSharp/Extensions/ResourceSetExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Resources; 2 | 3 | namespace AdventOfCSharp.Extensions; 4 | 5 | public static class ResourceSetExtensions 6 | { 7 | public static IEnumerable AsEntries(this ResourceSet set) 8 | { 9 | return set.Cast(); 10 | } 11 | 12 | public static IEnumerable> GetStringEntries(this ResourceSet set) 13 | { 14 | return set.AsEntries().Where(entry => entry.Value is string).Select(DictionaryEntryExtensions.ToKeyValuePair); 15 | } 16 | public static IEnumerable GetStrings(this ResourceSet set) 17 | { 18 | return set.AsEntries().Select(entry => entry.Value).OfType(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /AdventOfCSharp/Extensions/StringExtensions.cs: -------------------------------------------------------------------------------- 1 | #nullable enable 2 | 3 | namespace AdventOfCSharp.Extensions; 4 | 5 | public static class StringExtensions 6 | { 7 | /// Evaluates whether the given string is not or empty. 8 | /// The string to evaluate. 9 | /// if the given string is or empty, otherwise the string itself. 10 | public static string? NullIfEmpty(this string s) 11 | { 12 | return s.IsNullOrEmpty() ? null : s; 13 | } 14 | /// Evaluates whether the given string is not or empty. 15 | /// The string to evaluate. 16 | /// if the given string is or empty, otherwise . 17 | public static bool IsNullOrEmpty(this string s) 18 | { 19 | return string.IsNullOrEmpty(s); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /AdventOfCSharp/Extensions/TypeExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCSharp.Extensions; 2 | 3 | public static class TypeExtensions 4 | { 5 | public static bool InheritsGenericDefinition(this Type type, Type genericType, out Type[] typeArguments) 6 | { 7 | if (!genericType.IsGenericTypeDefinition) 8 | throw new ArgumentException("The generic type must be a generic type definition, that is, it should not have any substituted type parameters."); 9 | 10 | if (!type.IsClass && !type.IsInterface) 11 | throw new ArgumentException("Only classes and interfaces can inherit from generic types."); 12 | 13 | if (genericType.IsInterface && type.IsClass) 14 | throw new ArgumentException("An interface cannot inherit from a class."); 15 | 16 | return InheritsGenericDefinitionUnsafe(type, genericType, out typeArguments); 17 | } 18 | private static bool InheritsGenericDefinitionUnsafe(Type type, Type genericType, out Type[] typeArguments) 19 | { 20 | typeArguments = null!; 21 | 22 | var baseType = type; 23 | 24 | while (baseType is not null) 25 | { 26 | // Garyon contains a bug here for sure 27 | if (baseType.IsGenericVariantOf(genericType)) 28 | { 29 | typeArguments = baseType.GenericTypeArguments; 30 | return true; 31 | } 32 | 33 | baseType = baseType.BaseType; 34 | } 35 | 36 | return false; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /AdventOfCSharp/FancyPrinting.cs: -------------------------------------------------------------------------------- 1 | using System.Text.RegularExpressions; 2 | 3 | namespace AdventOfCSharp; 4 | 5 | public static class FancyPrinting 6 | { 7 | private static readonly Regex partPattern = new(@"Part (\d*)$"); 8 | 9 | public static void PrintLabel(string partName) 10 | { 11 | GetPartLabelPrinter(partName)(partName); 12 | } 13 | public static PartLabelPrinter GetPartLabelPrinter(string partName) 14 | { 15 | var match = partPattern.Match(partName); 16 | 17 | if (match.Success) 18 | return PrintPartLabel; 19 | 20 | return PrintCustomPartLabel; 21 | } 22 | 23 | public delegate void PartLabelPrinter(string partName); 24 | 25 | public static void PrintCustomPartLabel(string partName) 26 | { 27 | if (partName.Length > 20) 28 | partName = partName[..20]; 29 | 30 | ConsoleUtilities.WriteWithColor(partName.PadLeft(20), ConsoleColor.Cyan); 31 | Console.Write(':'); 32 | } 33 | public static void PrintPartLabel(string partName) 34 | { 35 | int part = GetOfficialPartIndex(partName); 36 | var partString = part.ToString(); 37 | var partPrefix = partName[..^partString.Length]; 38 | ConsoleUtilities.WriteWithColor(partPrefix.PadLeft(20 - partString.Length), ConsoleColor.Cyan); 39 | ConsoleUtilities.WriteWithColor(partString, GetPartColor(part)); 40 | Console.Write(':'); 41 | } 42 | 43 | private static int GetOfficialPartIndex(string partName) 44 | { 45 | // Part indices >= 10 aren't supposed to exist 46 | return partName.Last().GetNumericValueInteger(); 47 | } 48 | 49 | private static ConsoleColor GetPartColor(int part) => part switch 50 | { 51 | 1 => ConsoleColor.DarkGray, 52 | 2 => ConsoleColor.DarkYellow, 53 | 54 | // This will catch some users off-guard 55 | 3 => ConsoleColor.DarkRed, 56 | > 3 => ConsoleColor.Magenta, 57 | 58 | // "Where did my 0 go?" 59 | _ => Console.BackgroundColor, 60 | }; 61 | } 62 | -------------------------------------------------------------------------------- /AdventOfCSharp/FileHelpers.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Threading.Tasks; 3 | 4 | namespace AdventOfCSharp; 5 | 6 | /// Provides some helper functions to operate on files. 7 | public static class FileHelpers 8 | { 9 | /// Writes all lines to a file at the specified path, while ensuring that its parent directory exists, by creating it if it doesn't. 10 | /// The path of the file that will be created. 11 | /// The lines to write to the file. 12 | public static void WriteAllLinesEnsuringDirectory(string path, IEnumerable lines) 13 | { 14 | EnsureDirectoryForPath(path); 15 | File.WriteAllLines(path, lines); 16 | } 17 | /// Writes all text to a file at the specified path, while ensuring that its parent directory exists, by creating it if it doesn't. 18 | /// The path of the file that will be created. 19 | /// The contents to write to the file. 20 | public static void WriteAllTextEnsuringDirectory(string path, string contents) 21 | { 22 | EnsureDirectoryForPath(path); 23 | File.WriteAllText(path, contents); 24 | } 25 | 26 | /// Asynchronously writes all lines to a file at the specified path, while ensuring that its parent directory exists, by creating it if it doesn't. 27 | /// The path of the file that will be created. 28 | /// The lines to write to the file. 29 | /// A that represents the operation of creating ensuring the parent directory's existence, and the write operation. 30 | public static async Task WriteAllLinesEnsuringDirectoryAsync(string path, IEnumerable lines) 31 | { 32 | EnsureDirectoryForPath(path); 33 | await File.WriteAllLinesAsync(path, lines); 34 | } 35 | /// Asynchronously writes all text to a file at the specified path, while ensuring that its parent directory exists, by creating it if it doesn't. 36 | /// The path of the file that will be created. 37 | /// The contents to write to the file. 38 | /// A that represents the operation of creating ensuring the parent directory's existence, and the write operation. 39 | public static async Task WriteAllTextEnsuringDirectoryAsync(string path, string contents) 40 | { 41 | EnsureDirectoryForPath(path); 42 | await File.WriteAllTextAsync(path, contents); 43 | } 44 | 45 | private static void EnsureDirectoryForPath(string path) 46 | { 47 | Directory.CreateDirectory(Path.GetDirectoryName(path)!); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /AdventOfCSharp/FinalDay.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCSharp; 2 | 3 | public interface IFinalDay 4 | { 5 | internal const string LockedPartString = "You have not collected all 49* to unlock this part!"; 6 | 7 | private protected static string GetCompletionCongratulationString(int year) => $"Congratulations on completing all of AoC {year}!"; 8 | 9 | public static bool IsAvailable(int year) 10 | { 11 | return ProblemsIndex.Instance.DetermineLastDayPart2Availability(year); 12 | } 13 | } 14 | 15 | public abstract class FinalDay : Problem, IFinalDay 16 | where T : notnull 17 | { 18 | public sealed override string SolvePart2() 19 | { 20 | if (!IFinalDay.IsAvailable(Year)) 21 | return IFinalDay.LockedPartString; 22 | 23 | return IFinalDay.GetCompletionCongratulationString(Year); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /AdventOfCSharp/GlobalUsings.cs: -------------------------------------------------------------------------------- 1 | global using Garyon.DataStructures; 2 | global using Garyon.Exceptions; 3 | global using Garyon.Extensions; 4 | global using Garyon.Extensions.ArrayExtensions; 5 | global using Garyon.Functions; 6 | global using Garyon.Objects; 7 | global using Garyon.Reflection; 8 | global using System; 9 | global using System.Collections; 10 | global using System.Collections.Generic; 11 | global using System.ComponentModel; 12 | global using System.Linq; 13 | global using System.Reflection; 14 | -------------------------------------------------------------------------------- /AdventOfCSharp/IGlyphGrid.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCSharp; 2 | 3 | /// Decorative interface to denote a glyph grid, so that the resulting answers can be converted through . 4 | public interface IGlyphGrid { } 5 | -------------------------------------------------------------------------------- /AdventOfCSharp/Month.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCSharp; 2 | 3 | public enum Month 4 | { 5 | January = 1, 6 | February, 7 | March, 8 | April, 9 | May, 10 | June, 11 | July, 12 | August, 13 | September, 14 | October, 15 | November, 16 | December, 17 | } 18 | -------------------------------------------------------------------------------- /AdventOfCSharp/Parser.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCSharp; 2 | 3 | public delegate T Parser(string raw); 4 | -------------------------------------------------------------------------------- /AdventOfCSharp/ProblemFiles.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCSharp; 2 | 3 | /// Contains information about the problem files, including inputs and outputs. 4 | public static class ProblemFiles 5 | { 6 | private const string baseDirectoryEnvironmentVariableName = "AoCS_ProblemFiles_BaseDirectory"; 7 | 8 | private static string? defaultBaseDirectory; 9 | 10 | public static string DefaultBaseDirectory 11 | { 12 | get 13 | { 14 | if (defaultBaseDirectory is null) 15 | return defaultBaseDirectory = CalculateDefaultBaseDirectory(); 16 | 17 | return defaultBaseDirectory; 18 | } 19 | } 20 | 21 | /// Gets or sets the custom base directory. A value will resort to using the default base directory. 22 | public static string? CustomBaseDirectory { get; set; } 23 | 24 | /// Gets the base directory of the problem files. 25 | /// If is not , it will override the default base directory. Otherwise, the default base directory will be used. 26 | public static string GetBaseDirectory() 27 | { 28 | var environmentVariable = ReadBaseDirectoryFromEnvironmentVariable(); 29 | 30 | if (CustomBaseDirectory is not null) 31 | return CustomBaseDirectory; 32 | 33 | if (environmentVariable is not null) 34 | return environmentVariable; 35 | 36 | return DefaultBaseDirectory; 37 | } 38 | 39 | public static string? ReadBaseDirectoryFromEnvironmentVariable() 40 | { 41 | var environmentVariable = Environment.GetEnvironmentVariable(baseDirectoryEnvironmentVariableName); 42 | CustomBaseDirectory ??= environmentVariable; 43 | return environmentVariable; 44 | } 45 | public static void DumpBaseDirectoryToEnvironmentVariable() 46 | { 47 | if (CustomBaseDirectory is null) 48 | return; 49 | 50 | Environment.SetEnvironmentVariable(baseDirectoryEnvironmentVariableName, CustomBaseDirectory); 51 | } 52 | 53 | public static void SetCustomBaseDirectorySyncEnvironmentVariable(string? customBaseDirectory) 54 | { 55 | CustomBaseDirectory = customBaseDirectory; 56 | DumpBaseDirectoryToEnvironmentVariable(); 57 | } 58 | public static void RestoreBaseDirectoryClearEnvironmentVariable(string? previousCustomBaseDirectory) 59 | { 60 | CustomBaseDirectory = previousCustomBaseDirectory; 61 | Environment.SetEnvironmentVariable(baseDirectoryEnvironmentVariableName, null); 62 | } 63 | 64 | private static string CalculateDefaultBaseDirectory() 65 | { 66 | return ResourceFileHelpers.GetBaseCodeDirectory(); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /AdventOfCSharp/ProblemOutput.cs: -------------------------------------------------------------------------------- 1 | #nullable enable 2 | 3 | using AdventOfCSharp.Extensions; 4 | 5 | namespace AdventOfCSharp; 6 | 7 | /// Represents a problem's correct outputs. 8 | /// The correct output for part 1. 9 | /// The correct output for part 2. 10 | public record ProblemOutput(string? Part1, string? Part2) 11 | { 12 | /// Gets the empty instance, where the outputs for both parts are . 13 | public static ProblemOutput Empty { get; } = new(null, null); 14 | 15 | public string GetFileString() 16 | { 17 | if (Part1 is null) 18 | return ""; 19 | 20 | if (Part2 is null) 21 | return Part1; 22 | 23 | return $"{Part1}\n{Part2}"; 24 | } 25 | 26 | public string? ForPart(int part) => part switch 27 | { 28 | 1 => Part1, 29 | 2 => Part2, 30 | }; 31 | 32 | public static ProblemOutput Parse(string fileString) 33 | { 34 | return Parse(fileString.GetLines()); 35 | } 36 | public static ProblemOutput Parse(string[] lines) 37 | { 38 | string? part1 = null; 39 | string? part2 = null; 40 | 41 | SetIfAvailable(ref part1, lines, 0); 42 | SetIfAvailable(ref part2, lines, 1); 43 | 44 | return new(part1, part2); 45 | 46 | static void SetIfAvailable(ref string? result, string[] array, int index) 47 | { 48 | if (array.Length > index) 49 | result = array[index].NullIfEmpty(); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /AdventOfCSharp/ProblemValidator.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCSharp; 2 | 3 | public sealed class ProblemValidator 4 | { 5 | public ValidationReport Report { get; } = new(); 6 | 7 | public ValidationProblemResult Validate(Problem instance) 8 | { 9 | var runner = new ProblemRunner(instance); 10 | var result = runner.ValidateAllParts(); 11 | Report.Add(instance, result); 12 | return result; 13 | } 14 | public ValidationProblemResult? Validate(ProblemType type) 15 | { 16 | var instance = type.InitializeInstance(); 17 | if (instance is null) 18 | return null; 19 | 20 | return Validate(instance); 21 | } 22 | public ValidationProblemResult? Validate(ProblemInfo info) 23 | { 24 | return Validate(info.ProblemType); 25 | } 26 | public ValidationProblemResult? Validate(int year, int day) 27 | { 28 | return Validate(ProblemsIndex.Instance[year, day]); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /AdventOfCSharp/ResourceFileHelpers.cs: -------------------------------------------------------------------------------- 1 | #nullable enable 2 | 3 | using System.IO; 4 | 5 | namespace AdventOfCSharp; 6 | 7 | public static class ResourceFileHelpers 8 | { 9 | public static string GetBaseCodeDirectory() 10 | { 11 | var entry = Assembly.GetEntryAssembly()!; 12 | var executableDirectory = Path.GetDirectoryName(entry.Location)!; 13 | return Directory.GetParent(executableDirectory)!.Parent!.Parent!.ToString(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /AdventOfCSharp/Resources/GridFontStore.cs: -------------------------------------------------------------------------------- 1 | using AdventOfCSharp.Extensions; 2 | using System.Globalization; 3 | using System.Resources; 4 | 5 | namespace AdventOfCSharp.Resources; 6 | 7 | public sealed class GridFontStore 8 | { 9 | public static readonly GridFontStore Default = new(GlyphResources.ResourceManager, CultureInfo.CurrentCulture); 10 | 11 | public IReadOnlyCollection Fonts { get; } 12 | public IDictionary NamedFonts { get; } 13 | 14 | public GridFont? Infrauth => NamedFonts[nameof(Infrauth)]; 15 | public GridFont? Stargazer => NamedFonts[nameof(Stargazer)]; 16 | 17 | public GridFontStore(ResourceManager resourceManager, CultureInfo culture) 18 | { 19 | var resourceSet = resourceManager.GetResourceSet(culture, true, true)!; 20 | Fonts = resourceSet.GetStringEntries().Select(ParseEntry).ToArray(); 21 | NamedFonts = Fonts.ToDictionaryWithNotNullKeys(font => font.Name!); 22 | 23 | static GridFont ParseEntry(KeyValuePair entry) 24 | { 25 | return GridFont.ParseFileContents(entry.Value, entry.Key); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /AdventOfCSharp/Resources/GridGlyph.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCSharp.Resources; 2 | 3 | public sealed class GridGlyph 4 | { 5 | private readonly string[] lines; 6 | 7 | public char GlyphChar { get; set; } 8 | public int Width { get; } 9 | public int Height => lines.Length; 10 | 11 | internal GridGlyph(char glyphChar, string[] sequenceLines) 12 | { 13 | GlyphChar = glyphChar; 14 | lines = sequenceLines; 15 | Width = lines.Max(line => line.Length); 16 | } 17 | 18 | public bool Matches(string[] glyphStringLines, int startingColumn, out int nextGlyphStartingColumn) 19 | { 20 | nextGlyphStartingColumn = startingColumn; 21 | 22 | int currentColumn = startingColumn; 23 | for (int x = 0; x < Width; x++, currentColumn++) 24 | { 25 | for (int y = 0; y < Height; y++) 26 | { 27 | // Consider that the resource is sanitized: 28 | // - all glyphs will only consist of . and # 29 | // - every line has the same width 30 | 31 | if (glyphStringLines[y][currentColumn] != lines[y][x]) 32 | return false; 33 | } 34 | } 35 | 36 | nextGlyphStartingColumn = currentColumn; 37 | return true; 38 | } 39 | 40 | internal static GridGlyph ParseRawEntry(string normalizedRawEntry) 41 | { 42 | // The glyphs are strictly stored in the following form: 43 | /* 44 | * [Character] 45 | * [Sequence of . and # for the first line] 46 | * [Sequence for the second line] 47 | * [etc.] 48 | * 49 | * Example: 50 | * 51 | * 0 52 | * .##. 53 | * #..# 54 | * #..# 55 | * #..# 56 | * .##. 57 | */ 58 | 59 | char glyphChar = normalizedRawEntry[0]; 60 | string representation = normalizedRawEntry[(normalizedRawEntry.IndexOf('\n') + 1)..]; 61 | return new(glyphChar, representation.GetLines(false)); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /AdventOfCSharp/Resources/Infrauth.txt: -------------------------------------------------------------------------------- 1 | A 2 | .##. 3 | #..# 4 | #..# 5 | #### 6 | #..# 7 | #..# 8 | 9 | B 10 | ###. 11 | #..# 12 | ###. 13 | #..# 14 | #..# 15 | ###. 16 | 17 | C 18 | .##. 19 | #..# 20 | #... 21 | #... 22 | #..# 23 | .##. 24 | 25 | E 26 | #### 27 | #... 28 | ###. 29 | #... 30 | #... 31 | #### 32 | 33 | F 34 | #### 35 | #... 36 | ###. 37 | #... 38 | #... 39 | #... 40 | 41 | G 42 | .##. 43 | #..# 44 | #... 45 | #.## 46 | #..# 47 | .### 48 | 49 | H 50 | #..# 51 | #..# 52 | #### 53 | #..# 54 | #..# 55 | #..# 56 | 57 | I 58 | ### 59 | .#. 60 | .#. 61 | .#. 62 | .#. 63 | ### 64 | 65 | J 66 | ..## 67 | ...# 68 | ...# 69 | ...# 70 | #..# 71 | .##. 72 | 73 | K 74 | #..# 75 | #.#. 76 | ##.. 77 | #.#. 78 | #.#. 79 | #..# 80 | 81 | L 82 | #... 83 | #... 84 | #... 85 | #... 86 | #... 87 | #### 88 | 89 | O 90 | .##. 91 | #..# 92 | #..# 93 | #..# 94 | #..# 95 | .##. 96 | 97 | P 98 | ###. 99 | #..# 100 | #..# 101 | ###. 102 | #... 103 | #... 104 | 105 | R 106 | ###. 107 | #..# 108 | #..# 109 | ###. 110 | #.#. 111 | #..# 112 | 113 | S 114 | .### 115 | #... 116 | #... 117 | .##. 118 | ...# 119 | ###. 120 | 121 | U 122 | #..# 123 | #..# 124 | #..# 125 | #..# 126 | #..# 127 | .##. 128 | 129 | Y 130 | #...# 131 | #...# 132 | .#.#. 133 | ..#.. 134 | ..#.. 135 | ..#.. 136 | 137 | Z 138 | #### 139 | ...# 140 | ..#. 141 | .#.. 142 | #... 143 | #### -------------------------------------------------------------------------------- /AdventOfCSharp/Resources/Stargazer.txt: -------------------------------------------------------------------------------- 1 | A 2 | ..##.. 3 | .#..#. 4 | #....# 5 | #....# 6 | #....# 7 | ###### 8 | #....# 9 | #....# 10 | #....# 11 | #....# 12 | 13 | B 14 | #####. 15 | #....# 16 | #....# 17 | #....# 18 | #####. 19 | #....# 20 | #....# 21 | #....# 22 | #....# 23 | #####. 24 | 25 | C 26 | .####. 27 | #....# 28 | #..... 29 | #..... 30 | #..... 31 | #..... 32 | #..... 33 | #..... 34 | #....# 35 | .####. 36 | 37 | E 38 | ###### 39 | #..... 40 | #..... 41 | #..... 42 | #####. 43 | #..... 44 | #..... 45 | #..... 46 | #..... 47 | ###### 48 | 49 | F 50 | ###### 51 | #..... 52 | #..... 53 | #..... 54 | #####. 55 | #..... 56 | #..... 57 | #..... 58 | #..... 59 | #..... 60 | 61 | G 62 | .####. 63 | #....# 64 | #..... 65 | #..... 66 | #..... 67 | #..### 68 | #....# 69 | #....# 70 | #...## 71 | .###.# 72 | 73 | H 74 | #....# 75 | #....# 76 | #....# 77 | #....# 78 | ###### 79 | #....# 80 | #....# 81 | #....# 82 | #....# 83 | #....# 84 | 85 | J 86 | ...### 87 | ....#. 88 | ....#. 89 | ....#. 90 | ....#. 91 | ....#. 92 | ....#. 93 | #...#. 94 | #...#. 95 | .###.. 96 | 97 | K 98 | #....# 99 | #...#. 100 | #..#.. 101 | #.#... 102 | ##.... 103 | ##.... 104 | #.#... 105 | #..#.. 106 | #...#. 107 | #....# 108 | 109 | L 110 | #..... 111 | #..... 112 | #..... 113 | #..... 114 | #..... 115 | #..... 116 | #..... 117 | #..... 118 | #..... 119 | ###### 120 | 121 | N 122 | #....# 123 | ##...# 124 | ##...# 125 | #.#..# 126 | #.#..# 127 | #..#.# 128 | #..#.# 129 | #...## 130 | #...## 131 | #....# 132 | 133 | P 134 | #####. 135 | #....# 136 | #....# 137 | #....# 138 | #####. 139 | #..... 140 | #..... 141 | #..... 142 | #..... 143 | #..... 144 | 145 | R 146 | #####. 147 | #....# 148 | #....# 149 | #....# 150 | #####. 151 | #..#.. 152 | #...#. 153 | #...#. 154 | #....# 155 | #....# 156 | 157 | X 158 | #....# 159 | #....# 160 | .#..#. 161 | .#..#. 162 | ..##.. 163 | ..##.. 164 | .#..#. 165 | .#..#. 166 | #....# 167 | #....# 168 | 169 | Z 170 | ###### 171 | .....# 172 | .....# 173 | ....#. 174 | ...#.. 175 | ..#... 176 | .#.... 177 | #..... 178 | #..... 179 | ###### -------------------------------------------------------------------------------- /AdventOfCSharp/SecretsStorage.cs: -------------------------------------------------------------------------------- 1 | #nullable enable 2 | 3 | using TypeEx = Garyon.Reflection.TypeExtensions; 4 | using MemberInfoEx = Garyon.Reflection.MemberInfoExtensions; 5 | 6 | namespace AdventOfCSharp; 7 | 8 | /// Provides the default instances for important types. 9 | public static class SecretsStorage 10 | { 11 | private static readonly Lazy lazyCookies = new(GetCookies); 12 | 13 | public static Cookies? Cookies => lazyCookies.Value; 14 | 15 | private static Cookies? GetCookies() 16 | { 17 | var cookiesClasses = AppDomainCache.Current.AllNonAbstractClasses.Where(TypeEx.Inherits); 18 | 19 | return cookiesClasses.FirstOrDefault(MemberInfoEx.HasCustomAttribute) 20 | ?.InitializeInstance(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /AdventOfCSharp/ServerClock.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCSharp; 2 | 3 | public static class ServerClock 4 | { 5 | /// Returns the current time adjusted to UTC-5, the timezone the server operates on. 6 | /// 7 | /// "Current time" refers to this system's time. There is currently no proper way to get the exact time on the server. 8 | /// High clock precision barely matters in this project. In most scenarios, server responses contain meaningful information 9 | /// regarding its server time, over the form of durations, intervals or remaining spans. 10 | /// 11 | public static DateTime Now => DateTime.UtcNow - TimeSpan.FromHours(5); 12 | } 13 | -------------------------------------------------------------------------------- /AdventOfCSharp/Utilities/AppDomainHelpers.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | 3 | namespace AdventOfCSharp.Utilities; 4 | 5 | // TODO: Migrate to Garyon 6 | public static class AppDomainHelpers 7 | { 8 | public static void ForceLoadAllAssemblies(this AppDomain domain) 9 | { 10 | // Graciously copied from some helpful guy on the internet 11 | // https://stackoverflow.com/a/2384679/11438007 12 | // This function should exist in the BCL 13 | var staticLoadedAssemblies = domain.GetAssemblies().Where(assembly => !assembly.IsDynamic); 14 | var staticLoadedPaths = staticLoadedAssemblies.Select(a => a.Location).ToArray(); 15 | 16 | var referencedPaths = Directory.GetFiles(domain.BaseDirectory, "*.dll"); 17 | var toLoad = referencedPaths.Except(staticLoadedPaths, StringComparer.InvariantCultureIgnoreCase).ToArray(); 18 | 19 | var names = toLoad.Select(AssemblyName.GetAssemblyName); 20 | foreach (var assemblyName in names) 21 | domain.Load(assemblyName); 22 | } 23 | public static void ForceLoadAllAssembliesCurrent() 24 | { 25 | ForceLoadAllAssemblies(AppDomain.CurrentDomain); 26 | } 27 | 28 | public static void NoReturnLoad(this AppDomain domain, AssemblyName name) 29 | { 30 | domain.Load(name); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /AdventOfCSharp/Utilities/ConsoleAvailability.cs: -------------------------------------------------------------------------------- 1 | namespace AdventOfCSharp.Utilities; 2 | 3 | public static class ConsoleAvailability 4 | { 5 | private static readonly Lazy hasInput = new(GetHasInput); 6 | private static readonly Lazy supportsCursorPosition = new(GetSupportsCursorPosition); 7 | 8 | public static bool HasInput => hasInput.Value; 9 | public static bool SupportsCursorPosition => supportsCursorPosition.Value; 10 | 11 | // Exception-driven programming pog 12 | private static bool GetHasInput() 13 | { 14 | try 15 | { 16 | _ = Console.In; 17 | return true; 18 | } 19 | catch 20 | { 21 | return false; 22 | } 23 | } 24 | private static bool GetSupportsCursorPosition() 25 | { 26 | try 27 | { 28 | _ = Console.CursorLeft; 29 | return true; 30 | } 31 | catch 32 | { 33 | return false; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /AdventOfCSharp/Utilities/ConsolePrinting.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | using static System.Console; 8 | 9 | namespace AdventOfCSharp.Utilities; 10 | 11 | public static class ConsolePrinting 12 | { 13 | // This kind of functionality must be available somewhere 14 | // I should browse some packages 15 | public static void ClearUntilCursorReposition(int startLeft, int startTop) 16 | { 17 | ClearUntilCursor(startLeft, startTop); 18 | SetCursorPosition(startLeft, startTop); 19 | } 20 | public static void ClearUntilCursor(int startLeft, int startTop) 21 | { 22 | int length = GetConsoleBufferDifference(startLeft, startTop); 23 | 24 | CursorTop = startTop; 25 | CursorLeft = startLeft; 26 | 27 | var clearString = new string(' ', length); 28 | Write(clearString); 29 | } 30 | public static int GetConsoleBufferDifference(int startLeft, int startTop) 31 | { 32 | var (endLeft, endTop) = GetCursorPosition(); 33 | return GetConsoleBufferDifference(startLeft, startTop, endLeft, endTop); 34 | } 35 | public static int GetConsoleBufferDifference(int startLeft, int startTop, int endLeft, int endTop) 36 | { 37 | int width = BufferWidth; 38 | int differenceLeft = endLeft - startLeft; 39 | int differenceTop = endTop - startTop; 40 | return differenceTop * width - differenceLeft; 41 | } 42 | 43 | public static void WriteNewLines(int newlineCount) 44 | { 45 | var newline = Environment.NewLine; 46 | var builder = new StringBuilder(newline.Length * newlineCount); 47 | for (int i = 0; i < newlineCount; i++) 48 | { 49 | builder.Append(newline); 50 | } 51 | 52 | Write(builder.ToString()); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021-2022 Alex Kalfakakos 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /docs/analyzers/rules/AoCS0001.md: -------------------------------------------------------------------------------- 1 | # AoCS0001 2 | 3 | ## Title 4 | Invalid `PartSolutionAttribute` on non-solution function 5 | 6 | ## Category 7 | Validity 8 | 9 | ## Severity 10 | Error 11 | 12 | ## Details 13 | This error is reported when the `PartSolutionAttribute` is applied on a function that does not define the solution for a problem part. 14 | 15 | ## Example 16 | ```csharp 17 | public class Day10 : Problem 18 | { 19 | [PartSolution(PartSolutionStatus.WIP)] 20 | public int SolvePart1() => NotSolution(); 21 | 22 | [PartSolution(PartSolutionStatus.WIP)] // AoCS0001 will appear here 23 | public void NotSolution() => 1; 24 | } 25 | ``` 26 | -------------------------------------------------------------------------------- /docs/analyzers/rules/AoCS0002.md: -------------------------------------------------------------------------------- 1 | # AoCS0002 2 | 3 | ## Title 4 | Invalid `PartSolutionStatus` value on `PartSolutionAttribute` 5 | 6 | ## Category 7 | Validity 8 | 9 | ## Severity 10 | Error 11 | 12 | ## Details 13 | This error is reported when the `PartSolutionStatus` value in a `PartSolutionAttribute` is not a valid value. 14 | 15 | ## Example 16 | ```csharp 17 | public class Day10 : Problem 18 | { 19 | [PartSolution((PartSolutionStatus)456)] // AoCS0002 will appear here 20 | public int SolvePart1() => NotSolution(); 21 | } 22 | ``` 23 | -------------------------------------------------------------------------------- /docs/analyzers/rules/AoCS0003.md: -------------------------------------------------------------------------------- 1 | # AoCS0003 2 | 3 | ## Title 4 | Prefer using `Problem` for problems whose both parts have the same return type 5 | 6 | ## Category 7 | Brevity 8 | 9 | ## Severity 10 | Info 11 | 12 | ## Details 13 | This warning is reported when the inherited class on a problem solution is `Problem` when both types are equal. 14 | 15 | ## Example 16 | ```csharp 17 | public class Day10 : Problem // AoCS0003 will appear here 18 | { 19 | } 20 | ``` 21 | -------------------------------------------------------------------------------- /docs/analyzers/rules/AoCS0004.md: -------------------------------------------------------------------------------- 1 | # AoCS0004 2 | 3 | ## Title 4 | Containing namespace of a problem solution class must end in `Year20XX` 5 | 6 | ## Category 7 | Convention 8 | 9 | ## Severity 10 | Error 11 | 12 | ## Details 13 | This error is reported when a problem solution class is defined in a namespace whose name does not match the regex pattern `Year\d*`. 14 | 15 | ## Example 16 | ```csharp 17 | namespace AoC.Problems; 18 | 19 | public class Day10 : Problem // AoCS0004 will appear here 20 | { 21 | } 22 | ``` 23 | -------------------------------------------------------------------------------- /docs/analyzers/rules/AoCS0005.md: -------------------------------------------------------------------------------- 1 | # AoCS0005 2 | 3 | ## Title 4 | Denoted problem year must be a valid year after 2015, up until the current one 5 | 6 | ## Category 7 | Convention 8 | 9 | ## Severity 10 | Error 11 | 12 | ## Details 13 | This error is reported when a problem solution namespace container denotes an invalid year. Valid years range from 2015 up until the current year at the time of compilation (does not require the month to be December). 14 | 15 | ## Example 16 | ```csharp 17 | namespace AoC.Problems.Year2099; // AoCS0005 will appear here 18 | ``` 19 | -------------------------------------------------------------------------------- /docs/analyzers/rules/AoCS0006.md: -------------------------------------------------------------------------------- 1 | # AoCS0006 2 | 3 | ## Title 4 | Problem solution class must be named `DayX` 5 | 6 | ## Category 7 | Convention 8 | 9 | ## Severity 10 | Error 11 | 12 | ## Details 13 | This error is reported when the name of a non-abstract runnable problem solution class does not match the regex pattern `Day\d*`. 14 | 15 | ## Example 16 | ```csharp 17 | namespace AoC.Problems.Year2021; 18 | 19 | public class NotNamedDay99 : Problem // AoCS0006 will appear here 20 | { 21 | } 22 | ``` 23 | -------------------------------------------------------------------------------- /docs/analyzers/rules/AoCS0007.md: -------------------------------------------------------------------------------- 1 | # AoCS0007 2 | 3 | ## Title 4 | Denoted problem day must be between 1 and 25 5 | 6 | ## Category 7 | Convention 8 | 9 | ## Severity 10 | Error 11 | 12 | ## Details 13 | This error is reported when the name of a problem solution class denotes a day that is not between 1 and 25. 14 | 15 | ## Example 16 | ```csharp 17 | namespace AoC.Problems.Year2021; 18 | 19 | public class Day99 : Problem // AoCS0007 will appear here 20 | { 21 | } 22 | ``` 23 | -------------------------------------------------------------------------------- /docs/analyzers/rules/AoCS0008.md: -------------------------------------------------------------------------------- 1 | # AoCS0008 2 | 3 | ## Title 4 | The `SecretsContainerAttribute` can only be used on a sealed class that inherits `ISecretsContainer` and provides a public parameterless constructor 5 | 6 | ## Category 7 | Validity 8 | 9 | ## Severity 10 | Error 11 | 12 | ## Details 13 | This error is reported when the `SecretsContainerAttribute` is used on a type that does not meet at least one of the following criteria: 14 | - Sealed class 15 | - Inherits ISecretsContainer 16 | - Public parameterless constructor 17 | 18 | ## Example 19 | ```csharp 20 | [SecretsContainer] // AoCS0008 will appear here 21 | public record NotSecrets(int Property); 22 | 23 | [SecretsContainer] // AoCS0008 will appear here 24 | public abstract class NotSecretsAbstractClass : ISecretsContainer { } 25 | 26 | [SecretsContainer] // AoCS0008 will appear here 27 | public sealed class NotSecretsClass { } 28 | 29 | [SecretsContainer] // AoCS0008 will appear here 30 | public sealed class SecretsClass : ISecretsContainer 31 | { 32 | public NotSecretsClass(int x) { } 33 | } 34 | ``` 35 | -------------------------------------------------------------------------------- /docs/analyzers/rules/AoCS0011.md: -------------------------------------------------------------------------------- 1 | # AoCS0011 2 | 3 | ## Title 4 | Prefer inheriting `FinalDay` for Day 25 solutions 5 | 6 | ## Category 7 | Design 8 | 9 | ## Severity 10 | Warning 11 | 12 | ## Details 13 | This warning is reported when a problem solution class for Day 25 does not inherit `FinalDay`. 14 | 15 | ## Example 16 | ```csharp 17 | public class Day25 : Problem // AoCS0011 will appear here 18 | ``` 19 | -------------------------------------------------------------------------------- /docs/analyzers/rules/AoCS0012.md: -------------------------------------------------------------------------------- 1 | # AoCS0012 2 | 3 | ## Title 4 | Only use `FinalDay` for Day 25 problems 5 | 6 | ## Category 7 | Validity 8 | 9 | ## Severity 10 | Error 11 | 12 | ## Details 13 | This error is reported when the `FinalDay` class is inherited for problems not representing the final day (Day 25). 14 | 15 | ## Example 16 | ```csharp 17 | public class FinalDayInt : FinalDay // AoCS0008 will NOT appear here 18 | { 19 | } 20 | 21 | public class Day21 : FinalDayInt // AoCS0008 will appear here 22 | { 23 | } 24 | ``` 25 | -------------------------------------------------------------------------------- /docs/analyzers/rules/AoCS0013.md: -------------------------------------------------------------------------------- 1 | # AoCS0013 2 | 3 | ## Title 4 | `PartSolverAttribute` should only be placed on public instance methods with no parameters or generic parameters with a non-`void` return type in a problem solution class 5 | 6 | ## Category 7 | Validity 8 | 9 | ## Severity 10 | Error 11 | 12 | ## Details 13 | This error is reported when the `PartSolverAttribute` is used on a type that does not meet at least one of the following criteria: 14 | - Public accessibility 15 | - Instance method 16 | - No parameters 17 | - No generic parameters (not generic) 18 | - Non-`void` return type 19 | - Contained in a problem solution class 20 | 21 | ## Example 22 | ```csharp 23 | public class Nothing : NotProblem 24 | { 25 | [PartSolver] // AoCS0013 will appear here 26 | public int Solver() => -1; 27 | } 28 | 29 | public class Day1 : Problem 30 | { 31 | [PartSolver] // AoCS0013 will appear here 32 | public int Parameter(int x) => x; 33 | [PartSolver] // AoCS0013 will appear here 34 | public int Generic() => -1; 35 | [PartSolver] // AoCS0013 will appear here 36 | public void Void() { } 37 | 38 | [PartSolver] // AoCS0013 will appear here 39 | public static int Static() => -1; 40 | } 41 | ``` 42 | -------------------------------------------------------------------------------- /docs/analyzers/rules/AoCS0014.md: -------------------------------------------------------------------------------- 1 | # AoCS0014 2 | 3 | ## Title 4 | Duplicate part name in the same solution class 5 | 6 | ## Category 7 | Validity 8 | 9 | ## Severity 10 | Error 11 | 12 | ## Details 13 | This error is reported when the `PartSolverAttribute` marks the solution method with a name that is already present for another method in the same solution class. 14 | 15 | ## Example 16 | ```csharp 17 | public class Day1 : Problem 18 | { 19 | [PartSolver("Part 3", SolverKind = PartSolverKind.Custom)] // AoCS0014 will appear here 20 | public int SolvePart3A() => -1; 21 | [PartSolver("Part 3", SolverKind = PartSolverKind.Custom)] // AoCS0014 will appear here 22 | public int SolvePart3B() => -1; 23 | 24 | [PartSolver("Part 4", SolverKind = PartSolverKind.Custom)] 25 | public int SolvePart4() => -1; 26 | 27 | [PartSolver("Part 2", SolverKind = PartSolverKind.Custom)] // AoCS0014 will appear here 28 | public int SolvePart2B() => -1 29 | } 30 | 31 | public class Day2 : Problem 32 | { 33 | // AoCS0014 will not appear here since the classes are irrelevant 34 | [PartSolver("Part 3", SolverKind = PartSolverKind.Custom)] 35 | public int SolvePart3() => -1; 36 | 37 | [PartSolver("Part 4", SolverKind = PartSolverKind.Custom)] 38 | public int SolvePart4() => -1; 39 | } 40 | ``` 41 | -------------------------------------------------------------------------------- /docs/analyzers/rules/AoCS0015.md: -------------------------------------------------------------------------------- 1 | # AoCS0015 2 | 3 | ## Title 4 | Limit part names to 20 characters max 5 | 6 | ## Category 7 | Information 8 | 9 | ## Severity 10 | Warning 11 | 12 | ## Details 13 | This warning is reported when the marked part name in a `PartSolverAttribute` exceeds the 20-character limit. 14 | 15 | ## Example 16 | ```csharp 17 | public class Day1 : Problem 18 | { 19 | [PartSolver("Long name over 20 characters", SolverKind = PartSolverKind.Custom)] // AoCS0015 will appear here 20 | public int SolveLongNamePart() => -1; 21 | } 22 | ``` 23 | -------------------------------------------------------------------------------- /docs/analyzers/rules/AoCS0016.md: -------------------------------------------------------------------------------- 1 | # AoCS0016 2 | 3 | ## Title 4 | Do not directly inherit `AnswerStringConverter` 5 | 6 | ## Category 7 | Validity 8 | 9 | ## Severity 10 | Error 11 | 12 | ## Details 13 | This error is reported when the non-generic `AnswerStringConverter` is directly inherited by a custom answer string converter. The generic `AnswerStringConverter` provides the `Convert` method that is being used to convert the objects in `ConvertObject`. 14 | 15 | ## Example 16 | ```csharp 17 | // AoCS0016 will appear here 18 | public class RawAnswerStringConverter : AnswerStringConverter 19 | { 20 | } 21 | ``` 22 | -------------------------------------------------------------------------------- /docs/analyzers/rules/AoCS0017.md: -------------------------------------------------------------------------------- 1 | # AoCS0017 2 | 3 | ## Title 4 | Do not declare object answer string converters 5 | 6 | ## Category 7 | Validity 8 | 9 | ## Severity 10 | Error 11 | 12 | ## Details 13 | This error is reported when the generic `AnswerStringConverter` is directly inherited by a custom answer string converter, and the specified type argument is `object`. Answer string converters are supposed to convert specific object types into answer strings. Unsupported object types use `CommonAnswerStringConverter`. 14 | 15 | ## Example 16 | ```csharp 17 | // AoCS0017 will appear here 18 | public class ObjectAnswerStringConverter : AnswerStringConverter 19 | { 20 | } 21 | ``` 22 | -------------------------------------------------------------------------------- /docs/analyzers/rules/AoCS0018.md: -------------------------------------------------------------------------------- 1 | # AoCS0018 2 | 3 | ## Title 4 | Some primitive types are handled by the framework 5 | 6 | ## Category 7 | Validity 8 | 9 | ## Severity 10 | Error 11 | 12 | ## Details 13 | This error is reported when the generic `AnswerStringConverter` is directly inherited by a custom answer string converter, and the specified type argument is an already handled primitive type. 14 | 15 | The primitive types that are automatically handled by `CommonAnswerStringConverter` are: 16 | - `byte` 17 | - `short` 18 | - `int` 19 | - `long` 20 | - `sbyte` 21 | - `ushort` 22 | - `uint` 23 | - `ulong` 24 | - `float` 25 | - `double` 26 | - `decimal` 27 | - `string` 28 | 29 | ## Example 30 | ```csharp 31 | // AoCS0018 will appear here 32 | public class StringAnswerStringConverter : AnswerStringConverter 33 | { 34 | } 35 | ``` 36 | -------------------------------------------------------------------------------- /docs/analyzers/rules/AoCS0080.md: -------------------------------------------------------------------------------- 1 | # AoCS0080 2 | 3 | ## Title 4 | Secret string does not match the pattern 5 | 6 | ## Category 7 | Validity 8 | 9 | ## Severity 10 | Error 11 | 12 | ## Details 13 | This error is reported when the returned constant value does not match the target pattern declared for the secret string. 14 | 15 | ## Example 16 | ```csharp 17 | public sealed class SomeSecrets : ISecretsContainer 18 | { 19 | public const string SecretsType = "test"; 20 | 21 | [SecretStringProperty(@"\d\w\d", "_test", SecretsType)] 22 | // AoCS0080 will appear here 23 | public string SomeSecrets => "not matching pattern"; 24 | } 25 | ``` 26 | -------------------------------------------------------------------------------- /docs/analyzers/rules/AoCS0081.md: -------------------------------------------------------------------------------- 1 | # AoCS0081 2 | 3 | ## Title 4 | Type inheriting `ISecretsContainer` does not contain any secret string properties 5 | 6 | ## Category 7 | Design 8 | 9 | ## Severity 10 | Warning 11 | 12 | ## Details 13 | This warning is reported when a type that inherits `ISecretsContainer` does not contain any secret string properties. 14 | 15 | ## Example 16 | ```csharp 17 | // AoCS0081 will appear here 18 | public sealed class NoSecrets : ISecretsContainer 19 | { 20 | public string NotSecretProperty => "base"; 21 | } 22 | ``` 23 | -------------------------------------------------------------------------------- /docs/analyzers/rules/AoCS0082.md: -------------------------------------------------------------------------------- 1 | # AoCS0082 2 | 3 | ## Title 4 | Prefer using a constant field for the type of the secret string 5 | 6 | ## Category 7 | Best Practice 8 | 9 | ## Severity 10 | Info 11 | 12 | ## Details 13 | This warning is reported when the type of the secret string property is not a constant field. 14 | 15 | ## Example 16 | ```csharp 17 | public sealed class SomeSecrets : ISecretsContainer 18 | { 19 | // AoCS0082 will appear on "type" 20 | [SecretStringProperty(@"\d", "_test", "type")] 21 | public string Secret => "1"; 22 | } 23 | ``` 24 | -------------------------------------------------------------------------------- /docs/analyzers/rules/AoCS0083.md: -------------------------------------------------------------------------------- 1 | # AoCS0083 2 | 3 | ## Title 4 | Numerical types are not valid for secret string properties 5 | 6 | ## Category 7 | Validity 8 | 9 | ## Severity 10 | Error 11 | 12 | ## Details 13 | This error is reported when the value type of the secret string property is a numerical one. 14 | 15 | ## Example 16 | ```csharp 17 | public sealed class SomeSecrets : ISecretsContainer 18 | { 19 | public const string SecretsType = "test"; 20 | 21 | [SecretStringProperty(@"\d", "_test", SecretsType)] 22 | // AoCS0083 will appear here 23 | public int Secret => 1; 24 | } 25 | ``` 26 | -------------------------------------------------------------------------------- /docs/analyzers/rules/AoCS0084.md: -------------------------------------------------------------------------------- 1 | # AoCS0084 2 | 3 | ## Title 4 | Proprties marked with `SecretStringPropertyAttribute` must be contained in a type inheriting `ISecretsContainer`. 5 | 6 | ## Category 7 | Validity 8 | 9 | ## Severity 10 | Error 11 | 12 | ## Details 13 | This error is reported when a type that does not inherit `ISecretsContainer` contains a property marked with `SecretStringPropertyAttribute`. 14 | 15 | ## Example 16 | ```csharp 17 | public class NotSecretContainer 18 | { 19 | public const string SecretsType = "Test"; 20 | 21 | // AoCS0084 will appear here 22 | [SecretStringProperty(@"\d", "_test", SecretsType)] 23 | public string Secret => "1"; 24 | } 25 | ``` 26 | -------------------------------------------------------------------------------- /docs/analyzers/rules/index.md: -------------------------------------------------------------------------------- 1 | # Rules 2 | Rule ID | Category | Severity 3 | ------------------------|---------------|--------- 4 | [AoCS0001](AoCS0001.md) | Validity | Error 5 | [AoCS0002](AoCS0002.md) | Validity | Error 6 | [AoCS0003](AoCS0003.md) | Brevity | Info 7 | [AoCS0004](AoCS0004.md) | Convention | Error 8 | [AoCS0005](AoCS0005.md) | Convention | Error 9 | [AoCS0006](AoCS0006.md) | Convention | Error 10 | [AoCS0007](AoCS0007.md) | Convention | Error 11 | [AoCS0008](AoCS0008.md) | Validity | Error 12 | [AoCS0011](AoCS0011.md) | Design | Warning 13 | [AoCS0012](AoCS0012.md) | Validity | Error 14 | [AoCS0013](AoCS0013.md) | Validity | Error 15 | [AoCS0014](AoCS0014.md) | Validity | Error 16 | [AoCS0015](AoCS0015.md) | Information | Warning 17 | [AoCS0016](AoCS0016.md) | Validity | Error 18 | [AoCS0017](AoCS0017.md) | Validity | Error 19 | [AoCS0018](AoCS0018.md) | Validity | Error 20 | [AoCS0080](AoCS0080.md) | Validity | Error 21 | [AoCS0081](AoCS0081.md) | Design | Warning 22 | [AoCS0082](AoCS0082.md) | Best Practice | Info 23 | [AoCS0083](AoCS0083.md) | Validity | Error 24 | [AoCS0084](AoCS0084.md) | Validity | Error 25 | 26 | ## Discontinued Rules 27 | Rule ID | Embodied Rule ID(s) 28 | ---------|------------------------ 29 | AoCS0009 | [AoCS0008](AoCS0008.md) 30 | AoCS0010 | [AoCS0008](AoCS0008.md) 31 | -------------------------------------------------------------------------------- /docs/cookie_retrieval.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rekkonnect/AdventOfCSharp/3ba28711b131bb010e9e1c70d05e0ff25801fbd8/docs/cookie_retrieval.png -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # Documentation 2 | 3 | ## General 4 | 5 | - [Problem input generation](input-generation.md) 6 | - [Setting up secrets](setup-secrets.md) 7 | 8 | ## Code Analysis 9 | 10 | - [Analyzer rules](/analyzers/rules/) 11 | 12 | ## Source-generator-based features 13 | 14 | - [Benchmarking](benchmarks.md) 15 | - [Unit testing](unit-tests.md) -------------------------------------------------------------------------------- /docs/setup-secrets.md: -------------------------------------------------------------------------------- 1 | ## Setup secrets 2 | 3 | Advent of C# provides the ability to automatically download your personalized missing input file for the specified problem. 4 | To enable this, you need to specify your secret cookie session. Don't worry, it's only used for the purposes of communicating with the event's servers. 5 | 6 | ### Disclaimer 7 | 8 | **No private data is collected by using any of this project's features, including this one.** 9 | 10 | ### Steps 11 | 12 | First of all, you need a class [like the one in the template](https://github.com/AlFasGD/AdventOfCSharp.Template/blob/master/AdventOfCSharp.Template/MyCookies.cs), that will contain your cookie secret strings. Note that the `SecretsContainer` attribute is necessary. Do not create more than one such classes. 13 | 14 | **IMPORTANT**: Do not forget to include your cookie file in .gitignore, if you're open-sourcing your solutions using Git! 15 | 16 | Then, you need to find your actual cookie. The most obvious and painless way is to use a network tracking mechanism. In Google Chrome, you can easily do this: 17 | 18 | - Connect to your account on the event site 19 | - Open Inspect Element (Ctrl + Shift + I) 20 | - Navigate to any page on the site (preferably anything that would be personalized, like the problems, the input, the settings, etc.) 21 | - In the loaded document, find the request header name `cookie` 22 | - Get the `_ga` and `session` values and put them in the respective properties in your class 23 | 24 | ### Example screenshot 25 | 26 | ![Chrome cookie discovery instructions](cookie_retrieval.png) 27 | 28 | Note that secrets are (partially) hidden. 29 | --------------------------------------------------------------------------------