From 32e527be78d026967ce12a9efa74267afe82ad7d Mon Sep 17 00:00:00 2001 From: "Alex W. Carlsen" Date: Wed, 11 Oct 2023 17:03:31 +0200 Subject: [PATCH 1/4] Allow any type of reference --- ...eader.cs => AsyncApiJsonDocumentReader.cs} | 9 +-- .../AsyncApiReaderSettings.cs | 2 +- .../V2/AsyncApiV2VersionService.cs | 28 ++++++-- src/LEGO.AsyncAPI/Models/AsyncApiDocument.cs | 2 +- src/LEGO.AsyncAPI/Models/AsyncApiReference.cs | 45 ++++++++++++- .../Services/AsyncApiReferenceResolver.cs | 15 ++++- test/LEGO.AsyncAPI.Tests/ReferenceTests.cs | 64 +++++++++++++++++++ 7 files changed, 149 insertions(+), 16 deletions(-) rename src/LEGO.AsyncAPI.Readers/{AsyncApiYamlDocumentReader.cs => AsyncApiJsonDocumentReader.cs} (96%) create mode 100644 test/LEGO.AsyncAPI.Tests/ReferenceTests.cs diff --git a/src/LEGO.AsyncAPI.Readers/AsyncApiYamlDocumentReader.cs b/src/LEGO.AsyncAPI.Readers/AsyncApiJsonDocumentReader.cs similarity index 96% rename from src/LEGO.AsyncAPI.Readers/AsyncApiYamlDocumentReader.cs rename to src/LEGO.AsyncAPI.Readers/AsyncApiJsonDocumentReader.cs index fccdf3e3..5c0826af 100644 --- a/src/LEGO.AsyncAPI.Readers/AsyncApiYamlDocumentReader.cs +++ b/src/LEGO.AsyncAPI.Readers/AsyncApiJsonDocumentReader.cs @@ -1,10 +1,11 @@ -// Copyright (c) The LEGO Group. All rights reserved. +// Copyright (c) The LEGO Group. All rights reserved. namespace LEGO.AsyncAPI.Readers { using System.Collections.Generic; using System.Linq; using System.Text.Json.Nodes; + using System.Threading; using System.Threading.Tasks; using LEGO.AsyncAPI.Exceptions; using LEGO.AsyncAPI.Extensions; @@ -76,7 +77,7 @@ public AsyncApiDocument Read(JsonNode input, out AsyncApiDiagnostic diagnostic) return document; } - public Task ReadAsync(JsonNode input) + public async Task ReadAsync(JsonNode input, CancellationToken cancellationToken = default) { var diagnostic = new AsyncApiDiagnostic(); var context = new ParsingContext(diagnostic) @@ -106,11 +107,11 @@ public Task ReadAsync(JsonNode input) } } - return Task.FromResult(new ReadResult + return new ReadResult { AsyncApiDocument = document, AsyncApiDiagnostic = diagnostic, - }); + }; } private void ResolveReferences(AsyncApiDiagnostic diagnostic, AsyncApiDocument document) diff --git a/src/LEGO.AsyncAPI.Readers/AsyncApiReaderSettings.cs b/src/LEGO.AsyncAPI.Readers/AsyncApiReaderSettings.cs index 134acc75..7f759107 100644 --- a/src/LEGO.AsyncAPI.Readers/AsyncApiReaderSettings.cs +++ b/src/LEGO.AsyncAPI.Readers/AsyncApiReaderSettings.cs @@ -18,7 +18,7 @@ public enum ReferenceResolutionSetting DoNotResolveReferences, /// - /// ResolveAllReferences, effectively inlining them. + /// Resolve internal component references and inline them. /// ResolveReferences, } diff --git a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiV2VersionService.cs b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiV2VersionService.cs index 92a34c64..42562d9a 100644 --- a/src/LEGO.AsyncAPI.Readers/V2/AsyncApiV2VersionService.cs +++ b/src/LEGO.AsyncAPI.Readers/V2/AsyncApiV2VersionService.cs @@ -67,9 +67,21 @@ public AsyncApiReference ConvertToAsyncApiReference( Id = reference, }; } + + var asyncApiReference = new AsyncApiReference(); + if (reference.StartsWith("/")) + { + asyncApiReference.IsFragment = true; + } + + asyncApiReference.ExternalResource = segments[0]; + + return asyncApiReference; + } else if (segments.Length == 2) { + // Local reference if (reference.StartsWith("#")) { try @@ -84,7 +96,7 @@ public AsyncApiReference ConvertToAsyncApiReference( } var id = segments[1]; - + var asyncApiReference = new AsyncApiReference(); if (id.StartsWith("/components/")) { var localSegments = segments[1].Split('/'); @@ -103,12 +115,16 @@ public AsyncApiReference ConvertToAsyncApiReference( id = localSegments[3]; } - - return new AsyncApiReference + else { - Type = type, - Id = id, - }; + asyncApiReference.IsFragment = true; + } + + asyncApiReference.ExternalResource = segments[0]; + asyncApiReference.Type = type; + asyncApiReference.Id = id; + + return asyncApiReference; } } diff --git a/src/LEGO.AsyncAPI/Models/AsyncApiDocument.cs b/src/LEGO.AsyncAPI/Models/AsyncApiDocument.cs index b28168e2..1a5b7c71 100644 --- a/src/LEGO.AsyncAPI/Models/AsyncApiDocument.cs +++ b/src/LEGO.AsyncAPI/Models/AsyncApiDocument.cs @@ -150,7 +150,7 @@ internal T ResolveReference(AsyncApiReference reference) where T : class, IAs return this.ResolveReference(reference) as T; } - public IAsyncApiReferenceable ResolveReference(AsyncApiReference reference) + internal IAsyncApiReferenceable ResolveReference(AsyncApiReference reference) { if (reference == null) { diff --git a/src/LEGO.AsyncAPI/Models/AsyncApiReference.cs b/src/LEGO.AsyncAPI/Models/AsyncApiReference.cs index 2403b4ad..4f9660d1 100644 --- a/src/LEGO.AsyncAPI/Models/AsyncApiReference.cs +++ b/src/LEGO.AsyncAPI/Models/AsyncApiReference.cs @@ -11,6 +11,14 @@ namespace LEGO.AsyncAPI.Models /// public class AsyncApiReference : IAsyncApiSerializable { + /// + /// External resource in the reference. + /// It maybe: + /// 1. a absolute/relative file path, for example: ../commons/pet.json + /// 2. a Url, for example: http://localhost/pet.json + /// + public string ExternalResource { get; set; } + /// /// Gets or sets the element type referenced. /// @@ -27,17 +35,37 @@ public class AsyncApiReference : IAsyncApiSerializable public AsyncApiDocument HostDocument { get; set; } = null; /// - /// Gets the full reference string for v2.3. + /// Gets a flag indicating whether a file is a valid OpenAPI document or a fragment + /// + public bool IsFragment { get; set; } = false; + + /// + /// Gets a flag indicating whether this reference is an external reference. + /// + public bool IsExternal => this.ExternalResource != null; + + /// + /// Gets the full reference string for v2. /// public string Reference { get { + if (this.IsExternal) + { + return this.GetExternalReferenceV2(); + } + if (!this.Type.HasValue) { throw new ArgumentNullException(nameof(this.Type)); } + //if (this.Type == ReferenceType.SecurityScheme) + //{ + // return this.Id; + //} + return "#/components/" + this.Type.GetDisplayName() + "/" + this.Id; } } @@ -67,6 +95,21 @@ public void SerializeV2(IAsyncApiWriter writer) writer.WriteEndObject(); } + private string GetExternalReferenceV2() + { + if (this.Id != null) + { + if (this.IsFragment) + { + return this.ExternalResource + "#" + this.Id; + } + + return this.ExternalResource + "#/components/" + this.Type.GetDisplayName() + "/" + this.Id; + } + + return this.ExternalResource; + } + public void Write(IAsyncApiWriter writer) { this.SerializeV2(writer); diff --git a/src/LEGO.AsyncAPI/Services/AsyncApiReferenceResolver.cs b/src/LEGO.AsyncAPI/Services/AsyncApiReferenceResolver.cs index ca345b3f..88808cb8 100644 --- a/src/LEGO.AsyncAPI/Services/AsyncApiReferenceResolver.cs +++ b/src/LEGO.AsyncAPI/Services/AsyncApiReferenceResolver.cs @@ -154,7 +154,7 @@ public override void Visit(AsyncApiSchema schema) this.ResolveMap(schema.Properties); } - private void ResolveObject(T entity, Action assign) where T : class, IAsyncApiReferenceable + private void ResolveObject(T entity, Action assign) where T : class, IAsyncApiReferenceable, new() { if (entity == null) { @@ -184,7 +184,7 @@ private void ResolveObject(T entity, Action assign) where T : class, IAsyn } } - private void ResolveMap(IDictionary map) where T : class, IAsyncApiReferenceable + private void ResolveMap(IDictionary map) where T : class, IAsyncApiReferenceable, new() { if (map == null) { @@ -201,8 +201,17 @@ private void ResolveMap(IDictionary map) where T : class, IAsyncAp } } - private T ResolveReference(AsyncApiReference reference) where T : class, IAsyncApiReferenceable + private T ResolveReference(AsyncApiReference reference) where T : class, IAsyncApiReferenceable, new() { + if (reference.IsExternal) + { + return new () + { + UnresolvedReference = true, + Reference = reference, + }; + } + try { return this.currentDocument.ResolveReference(reference) as T; diff --git a/test/LEGO.AsyncAPI.Tests/ReferenceTests.cs b/test/LEGO.AsyncAPI.Tests/ReferenceTests.cs new file mode 100644 index 00000000..8a12a8ca --- /dev/null +++ b/test/LEGO.AsyncAPI.Tests/ReferenceTests.cs @@ -0,0 +1,64 @@ +// Copyright (c) The LEGO Group. All rights reserved. + +namespace LEGO.AsyncAPI.Tests +{ + using FluentAssertions; + using LEGO.AsyncAPI.Models; + using LEGO.AsyncAPI.Readers; + using NUnit.Framework; + + public class AsyncApiReference_Should + { + + [Test] + public void AsyncApiReference_WithExternalFragmentReference_AllowReference() + { + var actual = @"payload: + $ref: 'http://example.com/some-resource#/path/to/external/fragment' +"; + var reader = new AsyncApiStringReader(); + var deserialized = reader.ReadFragment(actual, AsyncApiVersion.AsyncApi2_0, out var diagnostic); + + diagnostic.Errors.Should().BeEmpty(); + var reference = deserialized.Payload.Reference; + reference.ExternalResource.Should().Be("http://example.com/some-resource"); + reference.Id.Should().Be("/path/to/external/fragment"); + reference.IsFragment.Should().BeTrue(); + reference.IsExternal.Should().BeTrue(); + } + + [Test] + public void AsyncApiReference_WithFragmentReference_AllowReference() + { + var actual = @"payload: + $ref: '/fragments/myFragment' +"; + var reader = new AsyncApiStringReader(); + var deserialized = reader.ReadFragment(actual, AsyncApiVersion.AsyncApi2_0, out var diagnostic); + + diagnostic.Errors.Should().BeEmpty(); + var reference = deserialized.Payload.Reference; + reference.ExternalResource.Should().Be("/fragments/myFragment"); + reference.Id.Should().BeNull(); + reference.IsFragment.Should().BeTrue(); + reference.IsExternal.Should().BeTrue(); + } + + [Test] + public void AsyncApiReference_WithExternalReference_AllowsReferenceDoesNotResolve() + { + var actual = @"payload: + $ref: http://example.com/json.json +"; + + var reader = new AsyncApiStringReader(); + var deserialized = reader.ReadFragment(actual, AsyncApiVersion.AsyncApi2_0, out var diagnostic); + diagnostic.Errors.Should().BeEmpty(); + var reference = deserialized.Payload.Reference; + reference.ExternalResource.Should().Be("http://example.com/json.json"); + reference.Id.Should().BeNull(); + reference.IsExternal.Should().BeTrue(); + diagnostic.Errors.Should().BeEmpty(); + } + } +} \ No newline at end of file From f34bdac3c0fe88cdced72eca54f1bfe02bca8dd2 Mon Sep 17 00:00:00 2001 From: "Alex W. Carlsen" Date: Wed, 11 Oct 2023 20:29:02 +0200 Subject: [PATCH 2/4] add another test --- .../Models/AsyncApiReference_Should.cs | 188 ++++++++++++++++++ test/LEGO.AsyncAPI.Tests/ReferenceTests.cs | 64 ------ 2 files changed, 188 insertions(+), 64 deletions(-) create mode 100644 test/LEGO.AsyncAPI.Tests/Models/AsyncApiReference_Should.cs delete mode 100644 test/LEGO.AsyncAPI.Tests/ReferenceTests.cs diff --git a/test/LEGO.AsyncAPI.Tests/Models/AsyncApiReference_Should.cs b/test/LEGO.AsyncAPI.Tests/Models/AsyncApiReference_Should.cs new file mode 100644 index 00000000..21eef8c1 --- /dev/null +++ b/test/LEGO.AsyncAPI.Tests/Models/AsyncApiReference_Should.cs @@ -0,0 +1,188 @@ +// Copyright (c) The LEGO Group. All rights reserved. + +namespace LEGO.AsyncAPI.Tests +{ + using FluentAssertions; + using LEGO.AsyncAPI.Models; + using LEGO.AsyncAPI.Readers; + using NUnit.Framework; + using System.Linq; + + public class AsyncApiReference_Should + { + + [Test] + public void AsyncApiReference_WithExternalFragmentReference_AllowReference() + { + // Arrange + var actual = @"payload: + $ref: http://example.com/some-resource#/path/to/external/fragment"; + var reader = new AsyncApiStringReader(); + + // Act + var deserialized = reader.ReadFragment(actual, AsyncApiVersion.AsyncApi2_0, out var diagnostic); + + // Assert + diagnostic.Errors.Should().BeEmpty(); + deserialized.Payload.UnresolvedReference.Should().BeTrue(); + + var reference = deserialized.Payload.Reference; + reference.ExternalResource.Should().Be("http://example.com/some-resource"); + reference.Id.Should().Be("/path/to/external/fragment"); + reference.IsFragment.Should().BeTrue(); + reference.IsExternal.Should().BeTrue(); + + var serialized = deserialized.SerializeAsYaml(AsyncApiVersion.AsyncApi2_0); + actual = actual.MakeLineBreaksEnvironmentNeutral(); + var expected = serialized.MakeLineBreaksEnvironmentNeutral(); + actual.Should().Be(expected); + } + + [Test] + public void AsyncApiReference_WithFragmentReference_AllowReference() + { + // Arrange + var actual = @"payload: + $ref: /fragments/myFragment"; + var reader = new AsyncApiStringReader(); + + // Act + var deserialized = reader.ReadFragment(actual, AsyncApiVersion.AsyncApi2_0, out var diagnostic); + + // Assert + diagnostic.Errors.Should().BeEmpty(); + deserialized.Payload.UnresolvedReference.Should().BeTrue(); + + var reference = deserialized.Payload.Reference; + reference.ExternalResource.Should().Be("/fragments/myFragment"); + reference.Id.Should().BeNull(); + reference.IsFragment.Should().BeTrue(); + reference.IsExternal.Should().BeTrue(); + var serialized = deserialized.SerializeAsYaml(AsyncApiVersion.AsyncApi2_0); + actual = actual.MakeLineBreaksEnvironmentNeutral(); + var expected = serialized.MakeLineBreaksEnvironmentNeutral(); + actual.Should().Be(expected); + } + + [Test] + public void AsyncApiReference_WithInternalComponentReference_AllowReference() + { + // Arrange + var actual = @"payload: + $ref: '#/components/schemas/test'"; + var reader = new AsyncApiStringReader(); + + // Act + var deserialized = reader.ReadFragment(actual, AsyncApiVersion.AsyncApi2_0, out var diagnostic); + + // Assert + diagnostic.Errors.Should().BeEmpty(); + var reference = deserialized.Payload.Reference; + reference.ExternalResource.Should().BeNull(); + reference.Type.Should().Be(ReferenceType.Schema); + reference.Id.Should().Be("test"); + reference.IsFragment.Should().BeFalse(); + reference.IsExternal.Should().BeFalse(); + + var serialized = deserialized.SerializeAsYaml(AsyncApiVersion.AsyncApi2_0); + actual = actual.MakeLineBreaksEnvironmentNeutral(); + var expected = serialized.MakeLineBreaksEnvironmentNeutral(); + actual.Should().Be(expected); + } + + [Test] + public void AsyncApiDocument_WithInternalComponentReference_ResolvesReference() + { + // Arrange + var actual = @"asyncapi: 2.6.0 +info: + title: My AsyncAPI Document + version: 1.0.0 +channels: + myChannel: + $ref: '#/components/channels/myChannel' +components: + channels: + myChannel: + description: customDescription"; + + var settings = new AsyncApiReaderSettings() + { + ReferenceResolution = ReferenceResolutionSetting.ResolveReferences, + }; + var reader = new AsyncApiStringReader(settings); + + // Act + var deserialized = reader.Read(actual, out var diagnostic); + + // Assert + diagnostic.Errors.Should().BeEmpty(); + var channel = deserialized.Channels.First().Value; + + channel.UnresolvedReference.Should().BeFalse(); + channel.Description.Should().Be("customDescription"); + channel.Reference.ExternalResource.Should().BeNull(); + channel.Reference.Id.Should().Be("myChannel"); + channel.Reference.IsExternal.Should().BeFalse(); + channel.Reference.Type.Should().Be(ReferenceType.Channel); + } + + [Test] + public void AsyncApiDocument_WithExternalReference_DoesNotResolve() + { + // Arrange + var actual = @"asyncapi: 2.6.0 +info: + title: My AsyncAPI Document + version: 1.0.0 +channels: + myChannel: + $ref: http://example.com/channel.json"; + + var settings = new AsyncApiReaderSettings() + { + ReferenceResolution = ReferenceResolutionSetting.ResolveReferences, + }; + var reader = new AsyncApiStringReader(settings); + + // Act + var deserialized = reader.Read(actual, out var diagnostic); + + // Assert + diagnostic.Errors.Should().BeEmpty(); + var channel = deserialized.Channels.First().Value; + + channel.UnresolvedReference.Should().BeTrue(); + channel.Description.Should().BeNull(); + channel.Reference.ExternalResource.Should().Be("http://example.com/channel.json"); + channel.Reference.Id.Should().BeNull(); + channel.Reference.IsExternal.Should().BeTrue(); + channel.Reference.Type.Should().BeNull(); + } + + [Test] + public void AsyncApiReference_WithExternalReference_AllowsReferenceDoesNotResolve() + { + // Arrange + var actual = @"payload: + $ref: http://example.com/json.json"; + var reader = new AsyncApiStringReader(); + + // Act + var deserialized = reader.ReadFragment(actual, AsyncApiVersion.AsyncApi2_0, out var diagnostic); + + // Assert + diagnostic.Errors.Should().BeEmpty(); + var reference = deserialized.Payload.Reference; + reference.ExternalResource.Should().Be("http://example.com/json.json"); + reference.Id.Should().BeNull(); + reference.IsExternal.Should().BeTrue(); + diagnostic.Errors.Should().BeEmpty(); + + var serialized = deserialized.SerializeAsYaml(AsyncApiVersion.AsyncApi2_0); + actual = actual.MakeLineBreaksEnvironmentNeutral(); + var expected = serialized.MakeLineBreaksEnvironmentNeutral(); + actual.Should().Be(expected); + } + } +} \ No newline at end of file diff --git a/test/LEGO.AsyncAPI.Tests/ReferenceTests.cs b/test/LEGO.AsyncAPI.Tests/ReferenceTests.cs deleted file mode 100644 index 8a12a8ca..00000000 --- a/test/LEGO.AsyncAPI.Tests/ReferenceTests.cs +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (c) The LEGO Group. All rights reserved. - -namespace LEGO.AsyncAPI.Tests -{ - using FluentAssertions; - using LEGO.AsyncAPI.Models; - using LEGO.AsyncAPI.Readers; - using NUnit.Framework; - - public class AsyncApiReference_Should - { - - [Test] - public void AsyncApiReference_WithExternalFragmentReference_AllowReference() - { - var actual = @"payload: - $ref: 'http://example.com/some-resource#/path/to/external/fragment' -"; - var reader = new AsyncApiStringReader(); - var deserialized = reader.ReadFragment(actual, AsyncApiVersion.AsyncApi2_0, out var diagnostic); - - diagnostic.Errors.Should().BeEmpty(); - var reference = deserialized.Payload.Reference; - reference.ExternalResource.Should().Be("http://example.com/some-resource"); - reference.Id.Should().Be("/path/to/external/fragment"); - reference.IsFragment.Should().BeTrue(); - reference.IsExternal.Should().BeTrue(); - } - - [Test] - public void AsyncApiReference_WithFragmentReference_AllowReference() - { - var actual = @"payload: - $ref: '/fragments/myFragment' -"; - var reader = new AsyncApiStringReader(); - var deserialized = reader.ReadFragment(actual, AsyncApiVersion.AsyncApi2_0, out var diagnostic); - - diagnostic.Errors.Should().BeEmpty(); - var reference = deserialized.Payload.Reference; - reference.ExternalResource.Should().Be("/fragments/myFragment"); - reference.Id.Should().BeNull(); - reference.IsFragment.Should().BeTrue(); - reference.IsExternal.Should().BeTrue(); - } - - [Test] - public void AsyncApiReference_WithExternalReference_AllowsReferenceDoesNotResolve() - { - var actual = @"payload: - $ref: http://example.com/json.json -"; - - var reader = new AsyncApiStringReader(); - var deserialized = reader.ReadFragment(actual, AsyncApiVersion.AsyncApi2_0, out var diagnostic); - diagnostic.Errors.Should().BeEmpty(); - var reference = deserialized.Payload.Reference; - reference.ExternalResource.Should().Be("http://example.com/json.json"); - reference.Id.Should().BeNull(); - reference.IsExternal.Should().BeTrue(); - diagnostic.Errors.Should().BeEmpty(); - } - } -} \ No newline at end of file From c604cc17e912bbeb01c2266025d3c178d9227f86 Mon Sep 17 00:00:00 2001 From: "Alex W. Carlsen" Date: Thu, 12 Oct 2023 15:41:22 +0200 Subject: [PATCH 3/4] add test case --- .../Models/AsyncApiReference_Should.cs | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/test/LEGO.AsyncAPI.Tests/Models/AsyncApiReference_Should.cs b/test/LEGO.AsyncAPI.Tests/Models/AsyncApiReference_Should.cs index 21eef8c1..b61352dc 100644 --- a/test/LEGO.AsyncAPI.Tests/Models/AsyncApiReference_Should.cs +++ b/test/LEGO.AsyncAPI.Tests/Models/AsyncApiReference_Should.cs @@ -90,6 +90,32 @@ public void AsyncApiReference_WithInternalComponentReference_AllowReference() actual.Should().Be(expected); } + [Test] + public void AsyncApiReference_WithExternalComponentReference_AllowReference() + { + // Arrange + var actual = @"payload: + $ref: someotherdocument.json#/components/schemas/test"; + var reader = new AsyncApiStringReader(); + + // Act + var deserialized = reader.ReadFragment(actual, AsyncApiVersion.AsyncApi2_0, out var diagnostic); + + // Assert + diagnostic.Errors.Should().BeEmpty(); + var reference = deserialized.Payload.Reference; + reference.ExternalResource.Should().Be("someotherdocument.json"); + reference.Type.Should().Be(ReferenceType.Schema); + reference.Id.Should().Be("test"); + reference.IsFragment.Should().BeFalse(); + reference.IsExternal.Should().BeTrue(); + + var serialized = deserialized.SerializeAsYaml(AsyncApiVersion.AsyncApi2_0); + actual = actual.MakeLineBreaksEnvironmentNeutral(); + var expected = serialized.MakeLineBreaksEnvironmentNeutral(); + actual.Should().Be(expected); + } + [Test] public void AsyncApiDocument_WithInternalComponentReference_ResolvesReference() { From d18e3a33a27d12c05cab4880c0f89033202c47e3 Mon Sep 17 00:00:00 2001 From: "Alex W. Carlsen" Date: Thu, 12 Oct 2023 20:47:34 +0200 Subject: [PATCH 4/4] fix tests --- .../Models/AsyncApiReference_Should.cs | 33 +++++++++++++++++-- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/test/LEGO.AsyncAPI.Tests/Models/AsyncApiReference_Should.cs b/test/LEGO.AsyncAPI.Tests/Models/AsyncApiReference_Should.cs index b61352dc..34831e86 100644 --- a/test/LEGO.AsyncAPI.Tests/Models/AsyncApiReference_Should.cs +++ b/test/LEGO.AsyncAPI.Tests/Models/AsyncApiReference_Should.cs @@ -12,7 +12,7 @@ public class AsyncApiReference_Should { [Test] - public void AsyncApiReference_WithExternalFragmentReference_AllowReference() + public void AsyncApiReference_WithExternalFragmentUriReference_AllowReference() { // Arrange var actual = @"payload: @@ -90,12 +90,37 @@ public void AsyncApiReference_WithInternalComponentReference_AllowReference() actual.Should().Be(expected); } + [Test] + public void AsyncApiReference_WithExternalFragmentReference_AllowReference() + { + // Arrange + var actual = @"payload: + $ref: ./myjsonfile.json#/fragment"; + var reader = new AsyncApiStringReader(); + + // Act + var deserialized = reader.ReadFragment(actual, AsyncApiVersion.AsyncApi2_0, out var diagnostic); + + // Assert + diagnostic.Errors.Should().BeEmpty(); + var reference = deserialized.Payload.Reference; + reference.ExternalResource.Should().Be("./myjsonfile.json"); + reference.Id.Should().Be("/fragment"); + reference.IsFragment.Should().BeTrue(); + reference.IsExternal.Should().BeTrue(); + + var serialized = deserialized.SerializeAsYaml(AsyncApiVersion.AsyncApi2_0); + actual = actual.MakeLineBreaksEnvironmentNeutral(); + var expected = serialized.MakeLineBreaksEnvironmentNeutral(); + actual.Should().Be(expected); + } + [Test] public void AsyncApiReference_WithExternalComponentReference_AllowReference() { // Arrange var actual = @"payload: - $ref: someotherdocument.json#/components/schemas/test"; + $ref: ./someotherdocument.json#/components/schemas/test"; var reader = new AsyncApiStringReader(); // Act @@ -104,7 +129,7 @@ public void AsyncApiReference_WithExternalComponentReference_AllowReference() // Assert diagnostic.Errors.Should().BeEmpty(); var reference = deserialized.Payload.Reference; - reference.ExternalResource.Should().Be("someotherdocument.json"); + reference.ExternalResource.Should().Be("./someotherdocument.json"); reference.Type.Should().Be(ReferenceType.Schema); reference.Id.Should().Be("test"); reference.IsFragment.Should().BeFalse(); @@ -183,6 +208,7 @@ public void AsyncApiDocument_WithExternalReference_DoesNotResolve() channel.Reference.ExternalResource.Should().Be("http://example.com/channel.json"); channel.Reference.Id.Should().BeNull(); channel.Reference.IsExternal.Should().BeTrue(); + channel.Reference.IsFragment.Should().BeFalse(); channel.Reference.Type.Should().BeNull(); } @@ -203,6 +229,7 @@ public void AsyncApiReference_WithExternalReference_AllowsReferenceDoesNotResolv reference.ExternalResource.Should().Be("http://example.com/json.json"); reference.Id.Should().BeNull(); reference.IsExternal.Should().BeTrue(); + reference.IsFragment.Should().BeFalse(); diagnostic.Errors.Should().BeEmpty(); var serialized = deserialized.SerializeAsYaml(AsyncApiVersion.AsyncApi2_0);