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: improve AsyncApiAny api surface. #145

Merged
merged 5 commits into from
Feb 26, 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
2 changes: 2 additions & 0 deletions src/LEGO.AsyncAPI/Models/Any/AsyncAPIArray.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

namespace LEGO.AsyncAPI.Models
{
using System;
using System.Collections.ObjectModel;
using System.Text.Json.Nodes;
using LEGO.AsyncAPI.Models.Interfaces;
using LEGO.AsyncAPI.Writers;

[Obsolete("Please use AsyncApiAny instead")]
public class AsyncApiArray : Collection<AsyncApiAny>, IAsyncApiExtension, IAsyncApiElement
{

Check warning on line 13 in src/LEGO.AsyncAPI/Models/Any/AsyncAPIArray.cs

View workflow job for this annotation

GitHub Actions / build (macos-latest)


public static explicit operator AsyncApiArray(AsyncApiAny any)
{
Expand Down
2 changes: 2 additions & 0 deletions src/LEGO.AsyncAPI/Models/Any/AsyncAPIObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace LEGO.AsyncAPI.Models
{
using System;
using System.Collections.Generic;
using System.Text.Json.Nodes;
using LEGO.AsyncAPI.Models.Interfaces;
Expand All @@ -10,6 +11,7 @@ namespace LEGO.AsyncAPI.Models
/// <summary>
/// AsyncApi object.
/// </summary>
[Obsolete("Please use AsyncApiAny instead")]
public class AsyncApiObject : Dictionary<string, AsyncApiAny>, IAsyncApiExtension, IAsyncApiElement
{

Expand Down
104 changes: 102 additions & 2 deletions src/LEGO.AsyncAPI/Models/Any/AsyncApiAny.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace LEGO.AsyncAPI.Models
{
using System.Collections.Generic;
using System.Text.Json;
using System.Text.Json.Nodes;
using LEGO.AsyncAPI.Models.Interfaces;
using LEGO.AsyncAPI.Writers;
Expand All @@ -13,28 +15,126 @@ namespace LEGO.AsyncAPI.Models
/// <seealso cref="LEGO.AsyncAPI.Models.Interfaces.IAsyncApiExtension" />
public class AsyncApiAny : IAsyncApiElement, IAsyncApiExtension
{
private JsonSerializerOptions options = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
};

private JsonNode node;

/// <summary>
/// Initializes a new instance of the <see cref="AsyncApiAny"/> class.
/// Initializes a new instance of the <see cref="AsyncApiAny" /> class.
/// </summary>
/// <param name="node">The node.</param>
public AsyncApiAny(JsonNode node)
{
this.node = node;
}

/// <summary>
/// Initializes a new instance of the <see cref="AsyncApiAny"/> class.
/// </summary>
/// <param name="obj">The object.</param>
public AsyncApiAny(object obj)
{
this.node = JsonNode.Parse(JsonSerializer.Serialize(obj, this.options));
}

/// <summary>
/// Initializes a new instance of the <see cref="AsyncApiAny"/> class.
/// </summary>
/// <param name="node">The node.</param>
public AsyncApiAny(JsonArray node)
{
this.node = node;
}

/// <summary>
/// Initializes a new instance of the <see cref="AsyncApiAny"/> class.
/// </summary>
/// <param name="node">The node.</param>
public AsyncApiAny(JsonObject node)
{
this.node = node;
}

/// <summary>
/// Converts to <see cref="{T}" /> from an Extension.
/// </summary>
/// <typeparam name="T">T.</typeparam>
/// <param name="extension">The extension.</param>
/// <returns><see cref="{T}"/>.</returns>
public static T FromExtensionOrDefault<T>(IAsyncApiExtension extension)
{
if (extension is AsyncApiAny any)
{
return any.GetValueOrDefault<T>();
}
else
{
return default(T);
}
}

/// <summary>
/// Gets the node.
/// </summary>
/// <returns><see cref="JsonNode"/>.</returns>
/// <value>
/// The node.
/// </value>
public JsonNode GetNode() => this.node;

/// <summary>
/// Gets the value.
/// </summary>
/// <typeparam name="T"><see cref="{T}" />.</typeparam>
/// <returns><see cref="{T}" />.</returns>
public T GetValue<T>()
{
return this.node.GetValue<T>();
if (this.node is JsonValue)
{
return this.node.GetValue<T>();
}

return JsonSerializer.Deserialize<T>(this.node.ToJsonString());
}

/// <summary>
/// Gets the value or default.
/// </summary>
/// <typeparam name="T"><see cref="{T}" />.</typeparam>
/// <returns><see cref="{T}" /> or default.</returns>
public T GetValueOrDefault<T>()
{
try
{
return this.GetValue<T>();
}
catch (System.Exception)
{
return default(T);
}
}

/// <summary>
/// Tries the get value.
/// </summary>
/// <typeparam name="T"><see cref="{T}" />.</typeparam>
/// <param name="value">The value.</param>
/// <returns>true if the value could be converted, otherwise false.</returns>
public bool TryGetValue<T>(out T value)
{
try
{
value = this.GetValue<T>();
return true;
}
catch (System.Exception)
{
value = default(T);
return false;
}
}

/// <summary>
Expand Down
27 changes: 16 additions & 11 deletions test/LEGO.AsyncAPI.Tests/AsyncApiDocumentV2Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,21 @@ namespace LEGO.AsyncAPI.Tests
using System.Globalization;
using System.IO;
using System.Linq;
using LEGO.AsyncAPI.Bindings.Pulsar;
using LEGO.AsyncAPI.Bindings;
using LEGO.AsyncAPI.Bindings.Http;
using LEGO.AsyncAPI.Bindings.Kafka;
using LEGO.AsyncAPI.Bindings.Pulsar;
using LEGO.AsyncAPI.Models;
using LEGO.AsyncAPI.Models.Interfaces;
using LEGO.AsyncAPI.Readers;
using LEGO.AsyncAPI.Writers;
using NUnit.Framework;

public class ExtensionClass
{
public string Key { get; set; }
public long OtherKey { get; set; }
}
public class AsyncApiDocumentV2Tests
{
[Test]
Expand Down Expand Up @@ -838,8 +843,6 @@ public void SerializeV2_WithFullSpec_Serializes()
string traitTitle = "traitTitle";
string schemaTitle = "schemaTitle";
string schemaDescription = "schemaDescription";
string anyKey = "key";
string anyOtherKey = "otherKey";
string anyStringValue = "value";
long anyLongValue = long.MaxValue;
string exampleSummary = "exampleSummary";
Expand All @@ -864,6 +867,8 @@ public void SerializeV2_WithFullSpec_Serializes()
string refreshUrl = "https://example.com/refresh";
string authorizationUrl = "https://example.com/authorization";
string requirementString = "requirementItem";


var document = new AsyncApiDocument()
{
Id = documentId,
Expand Down Expand Up @@ -1016,11 +1021,11 @@ public void SerializeV2_WithFullSpec_Serializes()
Description = schemaDescription,
Examples = new List<AsyncApiAny>
{
new AsyncApiObject
new AsyncApiAny(new ExtensionClass
{
{ anyKey, new AsyncApiAny(anyStringValue) },
{ anyOtherKey, new AsyncApiAny(anyLongValue) },
},
Key = anyStringValue,
OtherKey = anyLongValue,
}),
},
},
Examples = new List<AsyncApiMessageExample>
Expand All @@ -1029,11 +1034,11 @@ public void SerializeV2_WithFullSpec_Serializes()
{
Summary = exampleSummary,
Name = exampleName,
Payload = new AsyncApiObject
Payload =new AsyncApiAny(new ExtensionClass
{
{ anyKey, new AsyncApiAny(anyStringValue) },
{ anyOtherKey, new AsyncApiAny(anyLongValue) },
},
Key = anyStringValue,
OtherKey = anyLongValue,
}),
Extensions = new Dictionary<string, IAsyncApiExtension>
{
{ extensionKey, new AsyncApiAny(extensionString) },
Expand Down
7 changes: 7 additions & 0 deletions test/LEGO.AsyncAPI.Tests/Bindings/Sns/SnsBindings_Should.cs
Original file line number Diff line number Diff line change
Expand Up @@ -381,12 +381,19 @@ public void SnsOperationBinding_WithFilledObject_SerializesAndDeserializes()
var settings = new AsyncApiReaderSettings();
settings.Bindings = BindingsCollection.Sns;
var binding = new AsyncApiStringReader(settings).ReadFragment<AsyncApiOperation>(actual, AsyncApiVersion.AsyncApi2_0, out _);
var binding2 = new AsyncApiStringReader(settings).ReadFragment<AsyncApiOperation>(expected, AsyncApiVersion.AsyncApi2_0, out _);
binding2.Bindings.First().Value.Extensions.TryGetValue("x-bindingExtension", out IAsyncApiExtension any);
var val = AsyncApiAny.FromExtensionOrDefault<ExtensionClass>(any);

// Assert
Assert.AreEqual(actual, expected);

var expectedSnsBinding = (SnsOperationBinding)operation.Bindings.Values.First();
expectedSnsBinding.Should().BeEquivalentTo((SnsOperationBinding)binding.Bindings.Values.First(), options => options.IgnoringCyclicReferences());
}
class ExtensionClass
{
public string bindingXPropertyName { get; set; }
}
}
}
1 change: 0 additions & 1 deletion test/LEGO.AsyncAPI.Tests/LEGO.AsyncAPI.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="xunit" Version="2.4.1" />
</ItemGroup>

<ItemGroup>
Expand Down
54 changes: 54 additions & 0 deletions test/LEGO.AsyncAPI.Tests/Models/AsyncApiAnyTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using LEGO.AsyncAPI.Models;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;

namespace LEGO.AsyncAPI.Tests
{

public class AsyncApiAnyTests
{
[Test]
public void GetValue_ReturnsCorrectConversions()
{
// Arrange
// Act
var a = new AsyncApiAny("string");
var b = new AsyncApiAny(1);
var c = new AsyncApiAny(1.1);
var d = new AsyncApiAny(true);
var e = new AsyncApiAny(new MyType("test"));
var f = new AsyncApiAny(new List<string>() { "test", "test2"});
var g = new AsyncApiAny(new List<string>() { "test", "test2"}.AsEnumerable());
var h = new AsyncApiAny(new List<MyType>() { new MyType("test") });
var i = new AsyncApiAny(new Dictionary<string, int>() { { "t", 2 } });
var j = new AsyncApiAny(new Dictionary<string, MyType>() { { "t", new MyType("test") } });

// Assert
Assert.AreEqual("string", a.GetValue<string>());
Assert.AreEqual(1, b.GetValue<int>());
Assert.AreEqual(1.1, c.GetValue<double>());
Assert.AreEqual(true, d.GetValue<bool>());
Assert.NotNull(e.GetValue<MyType>());
Assert.IsNotEmpty(f.GetValue<List<string>>());
Assert.IsNotEmpty(f.GetValue<IEnumerable<string>>());
Assert.IsNotEmpty(g.GetValue<List<string>>());
Assert.IsNotEmpty(g.GetValue<IEnumerable<string>>());
Assert.IsNotEmpty(h.GetValue<List<MyType>>());
Assert.IsNotEmpty(h.GetValue<IEnumerable<MyType>>());
Assert.IsNotEmpty(i.GetValue<Dictionary<string, int>>());
Assert.IsNotEmpty(j.GetValue<Dictionary<string, MyType>>());
}

class MyType
{
public MyType(string value)
{
this.Value = value;
}

public string Value { get; set; }
}
}
}
Loading