diff --git a/src/ByteBard.AsyncAPI.Bindings/MQTT/MQTTMessageBinding.cs b/src/ByteBard.AsyncAPI.Bindings/MQTT/MQTTMessageBinding.cs index 93214f6..473bf23 100644 --- a/src/ByteBard.AsyncAPI.Bindings/MQTT/MQTTMessageBinding.cs +++ b/src/ByteBard.AsyncAPI.Bindings/MQTT/MQTTMessageBinding.cs @@ -97,7 +97,7 @@ private void SerializeProperties(IAsyncApiWriter writer, AsyncApiVersion version protected override FixedFieldMap FixedFieldMap => new() { { "bindingVersion", (a, n) => { a.BindingVersion = n.GetScalarValue(); } }, - { "payloadFormatIndicator", (a, n) => { a.PayloadFormatIndicator = n.GetIntegerValueOrDefault(); } }, + { "payloadFormatIndicator", (a, n) => { a.PayloadFormatIndicator = n.GetIntegerValue(); } }, { "correlationData", (a, n) => { a.CorrelationData = AsyncApiJsonSchemaDeserializer.LoadSchema(n); } }, { "contentType", (a, n) => { a.ContentType = n.GetScalarValue(); } }, { "responseTopic", (a, n) => { a.ResponseTopicValue = MQTTStringOrSchema.Parse(n); } }, diff --git a/src/ByteBard.AsyncAPI.Bindings/MQTT/MQTTServerBinding.cs b/src/ByteBard.AsyncAPI.Bindings/MQTT/MQTTServerBinding.cs index 0876fa9..e916fef 100644 --- a/src/ByteBard.AsyncAPI.Bindings/MQTT/MQTTServerBinding.cs +++ b/src/ByteBard.AsyncAPI.Bindings/MQTT/MQTTServerBinding.cs @@ -65,9 +65,9 @@ public int? MaximumPacketSize { { "bindingVersion", (a, n) => { a.BindingVersion = n.GetScalarValue(); } }, { "clientId", (a, n) => { a.ClientId = n.GetScalarValue(); } }, - { "cleanSession", (a, n) => { a.CleanSession = n.GetBooleanValueOrDefault(); } }, + { "cleanSession", (a, n) => { a.CleanSession = n.GetBooleanValue(); } }, { "lastWill", (a, n) => { a.LastWill = n.ParseMap(LastWillFixedFields); } }, - { "keepAlive", (a, n) => { a.KeepAlive = n.GetIntegerValueOrDefault(); } }, + { "keepAlive", (a, n) => { a.KeepAlive = n.GetIntegerValue(); } }, { "sessionExpiryInterval", (a, n) => { a.SessionExpiryIntervalValue = MQTTIntegerOrSchema.Parse(n); } }, { "maximumPacketSize", (a, n) => { a.MaximumPacketSizeValue = MQTTIntegerOrSchema.Parse(n); } }, }; @@ -75,7 +75,7 @@ public int? MaximumPacketSize private static FixedFieldMap LastWillFixedFields = new() { { "topic", (a, n) => { a.Topic = n.GetScalarValue(); } }, - { "qos", (a, n) => { a.QoS = (uint?)n.GetIntegerValueOrDefault(); } }, + { "qos", (a, n) => { a.QoS = (uint?)n.GetIntegerValue(); } }, { "message", (a, n) => { a.Message = n.GetScalarValue(); } }, { "retain", (a, n) => { a.Retain = n.GetBooleanValue(); } }, }; diff --git a/src/ByteBard.AsyncAPI.Bindings/ROS2/ROS2QosPolicies.cs b/src/ByteBard.AsyncAPI.Bindings/ROS2/ROS2QosPolicies.cs index bd33c46..4787fc7 100644 --- a/src/ByteBard.AsyncAPI.Bindings/ROS2/ROS2QosPolicies.cs +++ b/src/ByteBard.AsyncAPI.Bindings/ROS2/ROS2QosPolicies.cs @@ -21,10 +21,10 @@ public class ROS2QosPolicies : IAsyncApiElement { "reliability", (a, n) => { a.Reliability = n.GetScalarValue(); } }, { "history", (a, n) => { a.History = n.GetScalarValue(); } }, { "durability", (a, n) => { a.Durability = n.GetScalarValue(); } }, - { "lifespan", (a, n) => { a.Lifespan = n.GetIntegerValueOrDefault(); } }, - { "deadline", (a, n) => { a.Deadline = n.GetIntegerValueOrDefault(); } }, + { "lifespan", (a, n) => { a.Lifespan = n.GetIntegerValue(); } }, + { "deadline", (a, n) => { a.Deadline = n.GetIntegerValue(); } }, { "liveliness", (a, n) => { a.Liveliness = n.GetScalarValue(); } }, - { "leaseDuration", (a, n) => { a.LeaseDuration = n.GetIntegerValueOrDefault(); } }, + { "leaseDuration", (a, n) => { a.LeaseDuration = n.GetIntegerValue(); } }, }; /// diff --git a/src/ByteBard.AsyncAPI.Bindings/ROS2/ROS2ServerBinding.cs b/src/ByteBard.AsyncAPI.Bindings/ROS2/ROS2ServerBinding.cs index 9512645..bfefc06 100644 --- a/src/ByteBard.AsyncAPI.Bindings/ROS2/ROS2ServerBinding.cs +++ b/src/ByteBard.AsyncAPI.Bindings/ROS2/ROS2ServerBinding.cs @@ -18,7 +18,7 @@ public class ROS2ServerBinding : ServerBinding protected override FixedFieldMap FixedFieldMap => new() { { "rmwImplementation", (a, n) => { a.RmwImplementation = n.GetScalarValue(); } }, - { "domainId", (a, n) => { a.DomainId = n.GetIntegerValueOrDefault(); } }, + { "domainId", (a, n) => { a.DomainId = n.GetIntegerValue(); } }, }; /// diff --git a/test/ByteBard.AsyncAPI.Tests/Bindings/BindingInvalidScalars_Should.cs b/test/ByteBard.AsyncAPI.Tests/Bindings/BindingInvalidScalars_Should.cs new file mode 100644 index 0000000..b88b881 --- /dev/null +++ b/test/ByteBard.AsyncAPI.Tests/Bindings/BindingInvalidScalars_Should.cs @@ -0,0 +1,69 @@ +namespace ByteBard.AsyncAPI.Tests.Bindings +{ + using FluentAssertions; + using ByteBard.AsyncAPI.Bindings; + using ByteBard.AsyncAPI.Models; + using ByteBard.AsyncAPI.Readers; + using NUnit.Framework; + + internal class BindingInvalidScalars_Should : TestBase + { + [TestCase("mqtt", "cleanSession: yes-please", "bool")] + [TestCase("mqtt", "keepAlive: abc", "integer")] + [TestCase("mqtt", "lastWill:\n topic: /wills\n qos: high", "integer")] + [TestCase("ros2", "domainId: abc", "integer")] + public void ServerBinding_WithInvalidScalar_ReportsError(string bindingKey, string field, string expectedType) + { + var yaml = + "host: localhost\n" + + "protocol: " + bindingKey + "\n" + + "bindings:\n" + + " " + bindingKey + ":\n" + + Indent(field, 4); + + new AsyncApiStringReader(Settings()).ReadFragment(yaml, AsyncApiVersion.AsyncApi3_0, out var diagnostics); + + diagnostics.Errors.Should().ContainSingle().Which.Message.Should().Contain($"could not parse to {expectedType}"); + } + + [Test] + public void MessageBinding_WithInvalidPayloadFormatIndicator_ReportsError() + { + var yaml = + "bindings:\n" + + " mqtt:\n" + + " payloadFormatIndicator: abc\n"; + + new AsyncApiStringReader(Settings()).ReadFragment(yaml, AsyncApiVersion.AsyncApi3_0, out var diagnostics); + + diagnostics.Errors.Should().ContainSingle().Which.Message.Should().Contain("could not parse to integer"); + } + + [TestCase("lifespan")] + [TestCase("deadline")] + [TestCase("leaseDuration")] + public void ROS2OperationBinding_WithInvalidQosDuration_ReportsError(string field) + { + var yaml = + "action: send\n" + + "channel:\n" + + " $ref: '#/channels/camera'\n" + + "bindings:\n" + + " ros2:\n" + + " qosPolicies:\n" + + " " + field + ": forever\n"; + + new AsyncApiStringReader(Settings()).ReadFragment(yaml, AsyncApiVersion.AsyncApi3_0, out var diagnostics); + + diagnostics.Errors.Should().ContainSingle().Which.Message.Should().Contain("could not parse to integer"); + } + + private static AsyncApiReaderSettings Settings() => new() { Bindings = BindingsCollection.All }; + + private static string Indent(string value, int spaces) + { + var prefix = new string(' ', spaces); + return prefix + value.Replace("\n", "\n" + prefix) + "\n"; + } + } +}