diff --git a/src/Microsoft.OpenApi/Writers/OpenApiWriterBase.cs b/src/Microsoft.OpenApi/Writers/OpenApiWriterBase.cs index 63096135b..172e3fa2a 100644 --- a/src/Microsoft.OpenApi/Writers/OpenApiWriterBase.cs +++ b/src/Microsoft.OpenApi/Writers/OpenApiWriterBase.cs @@ -157,13 +157,21 @@ public virtual void WriteValue(long value) } /// - /// Write dateTimeOffset value. + /// Write DateTime value. /// - /// The decimal value. + /// The DateTime value. + public virtual void WriteValue(DateTime value) + { + this.WriteValue(value.ToString("o")); + } + + /// + /// Write DateTimeOffset value. + /// + /// The DateTimeOffset value. public virtual void WriteValue(DateTimeOffset value) { - WriteValueSeparator(); - Writer.Write(value.ToString("o")); + this.WriteValue(value.ToString("o")); } /// @@ -218,6 +226,10 @@ public virtual void WriteValue(object value) { WriteValue((decimal)value); } + else if ( type == typeof(DateTime) || type == typeof(DateTime?) ) + { + WriteValue((DateTime)value); + } else if (type == typeof(DateTimeOffset) || type == typeof(DateTimeOffset?)) { WriteValue((DateTimeOffset)value); diff --git a/test/Microsoft.OpenApi.Tests/Writers/OpenApiJsonWriterTests.cs b/test/Microsoft.OpenApi.Tests/Writers/OpenApiJsonWriterTests.cs index e4a90c280..253e74c06 100644 --- a/test/Microsoft.OpenApi.Tests/Writers/OpenApiJsonWriterTests.cs +++ b/test/Microsoft.OpenApi.Tests/Writers/OpenApiJsonWriterTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System; using System.Collections; using System.Collections.Generic; using System.IO; @@ -134,6 +135,17 @@ public static IEnumerable WriteMapAsJsonShouldMatchExpectedTestCasesCo } }; + // DateTime + yield return new object[] + { + new Dictionary + { + ["property1"] = new DateTime(1970, 01, 01), + ["property2"] = new DateTimeOffset(new DateTime(1970, 01, 01)), + ["property3"] = new DateTime(2018, 04, 03), + } + }; + // Nested map yield return new object[] { @@ -183,7 +195,12 @@ public static IEnumerable WriteMapAsJsonShouldMatchExpectedTestCasesCo private void WriteValueRecursive(OpenApiJsonWriter writer, object value) { - if (value == null || value.GetType().IsPrimitive || value is decimal || value is string) + if (value == null + || value.GetType().IsPrimitive + || value is decimal + || value is string + || value is DateTimeOffset + || value is DateTime) { writer.WriteValue(value); } @@ -230,5 +247,49 @@ public void WriteMapAsJsonShouldMatchExpected(IDictionary inputM // Assert parsedObject.ShouldBeEquivalentTo(expectedObject); } + + public static IEnumerable WriteDateTimeAsJsonTestCases() + { + yield return new object[] + { + new DateTimeOffset(2018, 1, 1, 10, 20, 30, TimeSpan.Zero), + }; + + yield return new object[] + { + new DateTimeOffset(2018, 1, 1, 10, 20, 30, 100, TimeSpan.FromHours(14)), + }; + + yield return new object[] + { + DateTimeOffset.UtcNow + TimeSpan.FromDays(4) + }; + + yield return new object[] + { + DateTime.UtcNow + TimeSpan.FromDays(4) + }; + } + + [Theory] + [MemberData(nameof(WriteDateTimeAsJsonTestCases))] + public void WriteDateTimeAsJsonShouldMatchExpected(DateTimeOffset dateTimeOffset) + { + // Arrange + var outputString = new StringWriter(); + var writer = new OpenApiJsonWriter(outputString); + + // Act + writer.WriteValue(dateTimeOffset); + + var writtenString = outputString.GetStringBuilder().ToString(); + var expectedString = JsonConvert.SerializeObject(dateTimeOffset, new JsonSerializerSettings + { + DateFormatString = "yyyy-MM-ddTHH:mm:ss.fffffffK", + }); + + // Assert + writtenString.Should().Be(expectedString); + } } } \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Writers/OpenApiWriterAnyExtensionsTests.cs b/test/Microsoft.OpenApi.Tests/Writers/OpenApiWriterAnyExtensionsTests.cs index 9ad1aa322..cefc1e486 100644 --- a/test/Microsoft.OpenApi.Tests/Writers/OpenApiWriterAnyExtensionsTests.cs +++ b/test/Microsoft.OpenApi.Tests/Writers/OpenApiWriterAnyExtensionsTests.cs @@ -97,9 +97,10 @@ public void WriteOpenApiDateTimeAsJsonWorks(string inputString) var dateTimeValue = new OpenApiDateTime(input); var json = WriteAsJson(dateTimeValue); + var expectedJson = "\"" + input.ToString("o") + "\""; // Assert - json.Should().Be(input.ToString("o")); + json.Should().Be(expectedJson); } [Theory] diff --git a/test/Microsoft.OpenApi.Tests/Writers/OpenApiYamlWriterTests.cs b/test/Microsoft.OpenApi.Tests/Writers/OpenApiYamlWriterTests.cs index 757f9097b..ab26191c5 100644 --- a/test/Microsoft.OpenApi.Tests/Writers/OpenApiYamlWriterTests.cs +++ b/test/Microsoft.OpenApi.Tests/Writers/OpenApiYamlWriterTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. +using System; using System.Collections; using System.Collections.Generic; using System.IO; @@ -171,6 +172,20 @@ public static IEnumerable WriteMapAsYamlShouldMatchExpectedTestCasesCo property11: ''" }; + // DateTime + yield return new object[] + { + new Dictionary + { + ["property1"] = new DateTime(1970, 01, 01), + ["property2"] = new DateTimeOffset(new DateTime(1970, 01, 01), TimeSpan.FromHours(3)), + ["property3"] = new DateTime(2018, 04, 03), + }, + @"property1: '1970-01-01T00:00:00.0000000' +property2: '1970-01-01T00:00:00.0000000+03:00' +property3: '2018-04-03T00:00:00.0000000'" + }; + // Nested map yield return new object[] { @@ -237,13 +252,18 @@ public static IEnumerable WriteMapAsYamlShouldMatchExpectedTestCasesCo private void WriteValueRecursive(OpenApiYamlWriter writer, object value) { - if (value == null || value.GetType().IsPrimitive || value is decimal || value is string) + if (value == null + || value.GetType().IsPrimitive + || value is decimal + || value is string + || value is DateTimeOffset + || value is DateTime) { writer.WriteValue(value); } else if (value.GetType().IsGenericType && (typeof(IDictionary<,>).IsAssignableFrom(value.GetType().GetGenericTypeDefinition()) || - typeof(Dictionary<,>).IsAssignableFrom(value.GetType().GetGenericTypeDefinition()))) + typeof(Dictionary<,>).IsAssignableFrom(value.GetType().GetGenericTypeDefinition()) ) ) { writer.WriteStartObject(); foreach (var elementValue in (dynamic)(value)) @@ -284,5 +304,46 @@ public void WriteMapAsYamlShouldMatchExpected(IDictionary inputM expectedYaml = expectedYaml.MakeLineBreaksEnvironmentNeutral(); actualYaml.Should().Be(expectedYaml); } + + public static IEnumerable WriteDateTimeAsJsonTestCases() + { + yield return new object[] + { + new DateTimeOffset(2018, 1, 1, 10, 20, 30, TimeSpan.Zero) + }; + + yield return new object[] + { + new DateTimeOffset(2018, 1, 1, 10, 20, 30, 100, TimeSpan.FromHours(14)) + }; + + yield return new object[] + { + DateTimeOffset.UtcNow + TimeSpan.FromDays(4) + }; + + yield return new object[] + { + DateTime.UtcNow + TimeSpan.FromDays(4) + }; + } + + [Theory] + [MemberData(nameof(WriteDateTimeAsJsonTestCases))] + public void WriteDateTimeAsJsonShouldMatchExpected(DateTimeOffset dateTimeOffset) + { + // Arrange + var outputString = new StringWriter(); + var writer = new OpenApiYamlWriter(outputString); + + // Act + writer.WriteValue(dateTimeOffset); + + var writtenString = outputString.GetStringBuilder().ToString(); + var expectedString = " '" + dateTimeOffset.ToString("o") + "'"; + + // Assert + writtenString.Should().Be(expectedString); + } } } \ No newline at end of file