Skip to content

Commit

Permalink
feat: unmapped member handling during deserialization (#176)
Browse files Browse the repository at this point in the history
  • Loading branch information
VisualBean committed Jun 14, 2024
1 parent d4fe243 commit 3edac3e
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 5 deletions.
6 changes: 6 additions & 0 deletions src/LEGO.AsyncAPI.Readers/AsyncApiReaderSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ public class AsyncApiReaderSettings : AsyncApiSettings
public ReferenceResolutionSetting ReferenceResolution { get; set; } =
ReferenceResolutionSetting.ResolveInternalReferences;

/// <summary>
/// Indicates what should happen when unmapped members are encountered during deserialization.
/// Error and Warning will add an error or warning to the diagnostics object.
/// </summary>
public UnmappedMemberHandling UnmappedMemberHandling { get; set; } = UnmappedMemberHandling.Error;

/// <summary>
/// Dictionary of parsers for converting extensions into strongly typed classes.
/// </summary>
Expand Down
11 changes: 7 additions & 4 deletions src/LEGO.AsyncAPI.Readers/ParseNodes/PropertyNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ public void ParseField<T>(
IDictionary<string, Action<T, ParseNode>> fixedFields,
IDictionary<Func<string, bool>, Action<T, string, ParseNode>> patternFields)
{
var found = fixedFields.TryGetValue(this.Name, out var fixedFieldMap);

var _ = fixedFields.TryGetValue(this.Name, out var fixedFieldMap);
if (fixedFieldMap != null)
{
try
Expand Down Expand Up @@ -78,8 +77,12 @@ public void ParseField<T>(
}
else
{
this.Context.Diagnostic.Errors.Add(
new AsyncApiError(string.Empty, $"{this.Name} is not a valid property at {this.Context.GetLocation()}"));
switch (this.Context.Settings.UnmappedMemberHandling)
{
case UnmappedMemberHandling.Error:
this.Context.Diagnostic.Errors.Add(new AsyncApiError(string.Empty, $"{this.Name} is not a valid property at {this.Context.GetLocation()}"));
break;
}
}
}
}
Expand Down
20 changes: 20 additions & 0 deletions src/LEGO.AsyncAPI.Readers/UnmappedMemberHandling.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright (c) The LEGO Group. All rights reserved.

namespace LEGO.AsyncAPI.Readers
{
/// <summary>
/// Unmapped member handling.
/// </summary>
public enum UnmappedMemberHandling
{
/// <summary>
/// Add error to diagnostics for unmapped members.
/// </summary>
Error,

/// <summary>
/// Ignore unmapped members.
/// </summary>
Ignore,
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace LEGO.AsyncAPI.Readers
{
using System;
using LEGO.AsyncAPI.Exceptions;
using LEGO.AsyncAPI.Models;
using LEGO.AsyncAPI.Readers.Exceptions;
using LEGO.AsyncAPI.Readers.ParseNodes;
Expand Down Expand Up @@ -169,7 +170,7 @@ public static AvroSchema LoadSchema(ParseNode node)
mapNode.ParseFields(ref union, UnionFixedFields, UnionMetadataPatternFields);
return union;
default:
throw new InvalidOperationException($"Unsupported type: {type}");
throw new AsyncApiException($"Unsupported type: {type}");
}
}

Expand Down
93 changes: 93 additions & 0 deletions test/LEGO.AsyncAPI.Tests/AsyncApiReaderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ namespace LEGO.AsyncAPI.Tests
using System;
using System.Collections.Generic;
using System.Linq;
using FluentAssertions;
using LEGO.AsyncAPI.Exceptions;
using LEGO.AsyncAPI.Models;
using LEGO.AsyncAPI.Models.Interfaces;
Expand All @@ -30,6 +31,7 @@ public void Read_WithExtensionParser_Parses()
info:
title: test
version: 1.0.0
test: 1234
contact:
name: API Support
url: https://www.example.com/support
Expand Down Expand Up @@ -57,13 +59,104 @@ public void Read_WithExtensionParser_Parses()
{
{ extensionName, valueExtensionParser },
},
UnmappedMemberHandling = UnmappedMemberHandling.Ignore,
};

var reader = new AsyncApiStringReader(settings);
var doc = reader.Read(yaml, out var diagnostic);
Assert.AreEqual((doc.Channels["workspace"].Extensions[extensionName] as AsyncApiAny).GetValue<int>(), 1234);
}

[Test]
public void Read_WithUnmappedMemberHandlingError_AddsError()
{
var extensionName = "x-someValue";
var yaml = $"""
asyncapi: 2.3.0
info:
title: test
version: 1.0.0
test: 1234
contact:
name: API Support
url: https://www.example.com/support
email: [email protected]
channels:
workspace:
{extensionName}: onetwothreefour
""";
Func<AsyncApiAny, IAsyncApiExtension> valueExtensionParser = (any) =>
{
if (any.TryGetValue<string>(out var value))
{
if (value == "onetwothreefour")
{
return new AsyncApiAny(1234);
}
}

return new AsyncApiAny("No value provided");
};

var settings = new AsyncApiReaderSettings
{
ExtensionParsers = new Dictionary<string, Func<AsyncApiAny, IAsyncApiExtension>>
{
{ extensionName, valueExtensionParser },
},
UnmappedMemberHandling = UnmappedMemberHandling.Error,
};

var reader = new AsyncApiStringReader(settings);
var doc = reader.Read(yaml, out var diagnostic);
diagnostic.Errors.Should().HaveCount(1);
}

[Test]
public void Read_WithUnmappedMemberHandlingIgnore_NoErrors()
{
var extensionName = "x-someValue";
var yaml = $"""
asyncapi: 2.3.0
info:
title: test
version: 1.0.0
test: 1234
contact:
name: API Support
url: https://www.example.com/support
email: [email protected]
channels:
workspace:
{extensionName}: onetwothreefour
""";
Func<AsyncApiAny, IAsyncApiExtension> valueExtensionParser = (any) =>
{
if (any.TryGetValue<string>(out var value))
{
if (value == "onetwothreefour")
{
return new AsyncApiAny(1234);
}
}

return new AsyncApiAny("No value provided");
};

var settings = new AsyncApiReaderSettings
{
ExtensionParsers = new Dictionary<string, Func<AsyncApiAny, IAsyncApiExtension>>
{
{ extensionName, valueExtensionParser },
},
UnmappedMemberHandling = UnmappedMemberHandling.Ignore,
};

var reader = new AsyncApiStringReader(settings);
var doc = reader.Read(yaml, out var diagnostic);
diagnostic.Errors.Should().HaveCount(0);
}

[Test]
public void Read_WithThrowingExtensionParser_AddsToDiagnostics()
{
Expand Down

0 comments on commit 3edac3e

Please sign in to comment.