diff --git a/FirstClassErrors.GenDoc.UnitTests/SolutionErrorDocumentationGeneratorTests.cs b/FirstClassErrors.GenDoc.UnitTests/SolutionErrorDocumentationGeneratorTests.cs index c3130c4..83a1c45 100644 --- a/FirstClassErrors.GenDoc.UnitTests/SolutionErrorDocumentationGeneratorTests.cs +++ b/FirstClassErrors.GenDoc.UnitTests/SolutionErrorDocumentationGeneratorTests.cs @@ -46,6 +46,29 @@ public void GetErrorDocumentationFromRejectsANonSolutionFile() { } } + [Theory(DisplayName = "GetErrorDocumentationFrom accepts the .sln and .slnx solution formats.")] + [InlineData(".sln")] + [InlineData(".slnx")] + public void GetErrorDocumentationFromAcceptsSolutionFormats(string extension) { + // Setup: a real file carrying a solution extension. It is not a valid solution, so the enumeration further + // down the pipeline will ultimately fail — but only *after* the extension validation, which is what this test + // guards. The rejected-extension path is the one that throws ArgumentException (see the sibling test); proving + // the format is accepted therefore means the call throws anything *but* an ArgumentException. + string path = Path.ChangeExtension(Path.GetTempFileName(), extension); + File.WriteAllText(path, string.Empty); + + try { + // Exercise + Exception? caught = Record.Exception( + () => SolutionErrorDocumentationGenerator.GetErrorDocumentationFrom(path, new SolutionGenerationOptions { BuildSolution = false }).ToList()); + + // Verify: the extension was accepted, so no ArgumentException was raised for it. + Check.That(caught).IsNotInstanceOf(); + } finally { + File.Delete(path); + } + } + [Fact(DisplayName = "GetErrorDocumentationFromAssemblies rejects a null path list.")] public void GetErrorDocumentationFromAssembliesRejectsANullPathList() { // Exercise & verify diff --git a/FirstClassErrors.GenDoc/SolutionErrorDocumentationGenerator.cs b/FirstClassErrors.GenDoc/SolutionErrorDocumentationGenerator.cs index 99f9b82..eb5f8b0 100644 --- a/FirstClassErrors.GenDoc/SolutionErrorDocumentationGenerator.cs +++ b/FirstClassErrors.GenDoc/SolutionErrorDocumentationGenerator.cs @@ -31,7 +31,14 @@ public static IEnumerable GetErrorDocumentationFrom(string s string fullSolutionPath = Path.GetFullPath(solutionPath); if (File.Exists(fullSolutionPath) is false) { throw new FileNotFoundException($"Solution file not found: '{fullSolutionPath}'", fullSolutionPath); } - if (string.Equals(Path.GetExtension(fullSolutionPath), ".sln", StringComparison.OrdinalIgnoreCase) is false) { throw new ArgumentException($"Expected a .sln file path, got: '{fullSolutionPath}'", nameof(solutionPath)); } + + // Accept both the classic (.sln) and the XML (.slnx) solution formats: "dotnet sln list", used below to + // enumerate the projects, handles the two uniformly. Solution filters (.slnf) are intentionally excluded — + // the "dotnet sln" subcommand does not process them. + string extension = Path.GetExtension(fullSolutionPath); + bool isSolution = string.Equals(extension, ".sln", StringComparison.OrdinalIgnoreCase) + || string.Equals(extension, ".slnx", StringComparison.OrdinalIgnoreCase); + if (isSolution is false) { throw new ArgumentException($"Expected a .sln or .slnx file path, got: '{fullSolutionPath}'", nameof(solutionPath)); } if (options.BuildSolution) { DotNetBuild(fullSolutionPath, options);