Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: show parsing errors in stderr #43

Merged
merged 1 commit into from
Jul 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 15 additions & 6 deletions src/Criteo.OpenApi.Comparator.Cli/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,21 @@ public static int Main(string[] args)

if (!oldFileFound || !newFileFound)
{
Console.WriteLine("Exiting.");
Console.Error.WriteLine("Exiting.");
return 1;
}

var differences = OpenApiComparator.Compare(
oldOpenApiSpecification, newOpenApiSpecification, options.StrictMode);
oldOpenApiSpecification, newOpenApiSpecification, out var parsingErrors, options.StrictMode);

if (parsingErrors.Any())
{
Console.Error.WriteLine("Errors occurred while parsing the OpenAPI specifications:");
foreach (var error in parsingErrors)
{
Console.Error.WriteLine(error);
}
}

DisplayOutput(differences, options.OutputFormat);

Expand All @@ -66,7 +75,7 @@ private static bool TryReadFile(string path, out string fileContent)
}
catch (UriFormatException)
{
Console.WriteLine($"Failed to interpret the provided URI: {path}.");
Console.Error.WriteLine($"Failed to interpret the provided URI: {path}.");
fileContent = null;
}
return false;
Expand All @@ -81,7 +90,7 @@ private static bool TryReadLocalFile(string path, out string fileContent)
}
catch (FileNotFoundException)
{
Console.WriteLine($"File not found for: {path}.");
Console.Error.WriteLine($"File not found for: {path}.");
fileContent = null;
return false;
}
Expand All @@ -97,7 +106,7 @@ private static bool TryReadRemoteFile(string path, out string fileContent)
}
catch (HttpRequestException exception)
{
Console.WriteLine($"Http request failed on {path}: {exception.Message}");
Console.Error.WriteLine($"Http request failed on {path}: {exception.Message}");
}
catch (AggregateException exception)
{
Expand All @@ -108,7 +117,7 @@ private static bool TryReadRemoteFile(string path, out string fileContent)
stringWriter.Write($"- {innerException.GetType()}: {exception.Message}");
return true;
});
Console.WriteLine(stringWriter.ToString());
Console.Error.WriteLine(stringWriter.ToString());
}
fileContent = null;
return false;
Expand Down
4 changes: 2 additions & 2 deletions src/Criteo.OpenApi.Comparator.UTest/OpenApiParserTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public void OpenApiParser_Should_Throw_Exception_When_Invalid_Json()
{
const string fileName = "invalid_json_file.txt";
var documentAsString = ReadOpenApiFile(fileName);
Assert.Throws<OpenApiUnsupportedSpecVersionException>(() => OpenApiParser.Parse(documentAsString));
Assert.Throws<OpenApiUnsupportedSpecVersionException>(() => OpenApiParser.Parse(documentAsString, out _));
}

/// <summary>
Expand All @@ -40,7 +40,7 @@ public void OpenApiParser_Should_Throw_Exception_When_Invalid_Json()
public void OpenApiParser_Should_Return_Valid_OpenApi_Document_Object(string fileName)
{
var documentAsString = ReadOpenApiFile(fileName);
var validOpenApiDocument = OpenApiParser.Parse(documentAsString);
var validOpenApiDocument = OpenApiParser.Parse(documentAsString, out _);
Assert.IsInstanceOf<JsonDocument<OpenApiDocument>>(validOpenApiDocument);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public void CompareOAS(string testcase)
var diffFileName = Path.Combine(resourceDirectory, testcase, "diff.json");

var differences = OpenApiComparator
.Compare(File.ReadAllText(oldFileName), File.ReadAllText(newFileName));
.Compare(File.ReadAllText(oldFileName), File.ReadAllText(newFileName), out _);

var expectedDifferencesText = File.ReadAllText(diffFileName);
var expectedDifferences = JsonSerializer
Expand Down
40 changes: 37 additions & 3 deletions src/Criteo.OpenApi.Comparator/OpenApiComparator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
// Licensed under the Apache 2.0 License. See LICENSE in the project root for license information.

using System.Collections.Generic;
using System.Linq;
using Criteo.OpenApi.Comparator.Comparators;
using Criteo.OpenApi.Comparator.Parser;
using Microsoft.OpenApi.Models;

namespace Criteo.OpenApi.Comparator
{
Expand All @@ -17,11 +19,20 @@ public static class OpenApiComparator
/// </summary>
/// <param name="oldOpenApiSpec">The content of the old OpenAPI Specification</param>
/// <param name="newOpenApiSpec">The content of the new OpenAPI Specification</param>
/// <param name="parsingErrors">Parsing errors</param>
/// <param name="strict">If true, then breaking changes are errors instead of warnings.</param>
public static IEnumerable<ComparisonMessage> Compare(string oldOpenApiSpec, string newOpenApiSpec, bool strict = false)
public static IEnumerable<ComparisonMessage> Compare(
string oldOpenApiSpec,
string newOpenApiSpec,
out IEnumerable<ParsingError> parsingErrors,
bool strict = false)
{
var oldOpenApiDocument = OpenApiParser.Parse(oldOpenApiSpec);
var newOpenApiDocument = OpenApiParser.Parse(newOpenApiSpec);
var oldOpenApiDocument = OpenApiParser.Parse(oldOpenApiSpec, out var oldSpecDiagnostic);
var newOpenApiDocument = OpenApiParser.Parse(newOpenApiSpec, out var newSpecDiagnostic);

parsingErrors = oldSpecDiagnostic.Errors
.Select(e => new ParsingError("old", e))
.Concat(newSpecDiagnostic.Errors.Select(e => new ParsingError("new", e)));

var context = new ComparisonContext(oldOpenApiDocument, newOpenApiDocument) { Strict = strict };

Expand All @@ -31,4 +42,27 @@ public static IEnumerable<ComparisonMessage> Compare(string oldOpenApiSpec, stri
return comparisonMessages;
}
}

/// <summary>
/// Represents an error that occurred while parsing an OpenAPI document.
/// </summary>
public class ParsingError
{
private readonly string _documentName;
private readonly OpenApiError _error;

/// <summary>
/// Initializes a new instance of the <see cref="ParsingError"/> class.
/// </summary>
/// <param name="documentName"></param>
/// <param name="error"></param>
public ParsingError(string documentName, OpenApiError error)
{
_documentName = documentName;
_error = error;
}

/// <inheritdoc/>
public override string ToString() => $"[{_documentName}] {_error}";
}
}
5 changes: 3 additions & 2 deletions src/Criteo.OpenApi.Comparator/Parser/OpenApiParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,15 @@ namespace Criteo.OpenApi.Comparator.Parser
internal static class OpenApiParser
{
/// <param name="openApiDocumentAsString">Swagger as string</param>
internal static JsonDocument<OpenApiDocument> Parse(string openApiDocumentAsString)
/// <param name="diagnostic"></param>
internal static JsonDocument<OpenApiDocument> Parse(string openApiDocumentAsString, out OpenApiDiagnostic diagnostic)
{
var openApiReaderSettings = new OpenApiReaderSettings
{
ReferenceResolution = ReferenceResolutionSetting.DoNotResolveReferences
};
var openApiReader = new OpenApiStringReader(openApiReaderSettings);
var openApiDocument = openApiReader.Read(openApiDocumentAsString, out _);
var openApiDocument = openApiReader.Read(openApiDocumentAsString, out diagnostic);

var textWriter = new StringWriter();
var openApiWriter = new OpenApiJsonWriter(textWriter);
Expand Down
Loading