diff --git a/CHANGELOG.md b/CHANGELOG.md index 87e8902..0cdbf0b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [1.3.0] - 2024-05-13 + +### Added + +- Implements IAsyncParseNodeFactory interface which adds async support + ## [1.2.3] - 2024-04-25 ### Changed diff --git a/Microsoft.Kiota.Serialization.Json.Tests/JsonAsyncParseNodeFactoryTests.cs b/Microsoft.Kiota.Serialization.Json.Tests/JsonAsyncParseNodeFactoryTests.cs new file mode 100644 index 0000000..9005719 --- /dev/null +++ b/Microsoft.Kiota.Serialization.Json.Tests/JsonAsyncParseNodeFactoryTests.cs @@ -0,0 +1,57 @@ +using System; +using System.IO; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.Kiota.Serialization.Json.Tests +{ + public class JsonAsyncParseNodeFactoryTests + { + private readonly JsonParseNodeFactory _jsonParseNodeFactory; + private const string TestJsonString = "{\"key\":\"value\"}"; + + public JsonAsyncParseNodeFactoryTests() + { + _jsonParseNodeFactory = new JsonParseNodeFactory(); + } + + [Fact] + public async Task GetsWriterForJsonContentType() + { + using var jsonStream = new MemoryStream(Encoding.UTF8.GetBytes(TestJsonString)); + var jsonWriter = await _jsonParseNodeFactory.GetRootParseNodeAsync(_jsonParseNodeFactory.ValidContentType, jsonStream); + + // Assert + Assert.NotNull(jsonWriter); + Assert.IsAssignableFrom(jsonWriter); + } + + [Fact] + public async Task ThrowsArgumentOutOfRangeExceptionForInvalidContentType() + { + var streamContentType = "application/octet-stream"; + using var jsonStream = new MemoryStream(Encoding.UTF8.GetBytes(TestJsonString)); + var exception = await Assert.ThrowsAsync( + async () => await _jsonParseNodeFactory.GetRootParseNodeAsync(streamContentType, jsonStream)); + + // Assert + Assert.NotNull(exception); + Assert.Equal($"expected a {_jsonParseNodeFactory.ValidContentType} content type", exception.ParamName); + } + + [Theory] + [InlineData(null)] + [InlineData("")] + public async Task ThrowsArgumentNullExceptionForNoContentType(string contentType) + { + using var jsonStream = new MemoryStream(Encoding.UTF8.GetBytes(TestJsonString)); + var exception = await Assert.ThrowsAsync( + async () => await _jsonParseNodeFactory.GetRootParseNodeAsync(contentType, jsonStream)); + + // Assert + Assert.NotNull(exception); + Assert.Equal("contentType", exception.ParamName); + } + } +} diff --git a/src/JsonParseNodeFactory.cs b/src/JsonParseNodeFactory.cs index 5a43615..561d706 100644 --- a/src/JsonParseNodeFactory.cs +++ b/src/JsonParseNodeFactory.cs @@ -5,6 +5,8 @@ using System; using System.IO; using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; using Microsoft.Kiota.Abstractions.Serialization; namespace Microsoft.Kiota.Serialization.Json @@ -12,7 +14,7 @@ namespace Microsoft.Kiota.Serialization.Json /// /// The implementation for json content types /// - public class JsonParseNodeFactory : IParseNodeFactory + public class JsonParseNodeFactory : IAsyncParseNodeFactory { private readonly KiotaJsonSerializationContext _jsonJsonSerializationContext; @@ -43,7 +45,8 @@ public JsonParseNodeFactory(KiotaJsonSerializationContext jsonJsonSerializationC /// /// The content type of the stream to be parsed /// The containing json to parse. - /// An instance of for json manipulation + /// An instance of for json manipulation + [Obsolete("Use GetRootParseNodeAsync instead")] public IParseNode GetRootParseNode(string contentType, Stream content) { if(string.IsNullOrEmpty(contentType)) @@ -56,5 +59,25 @@ public IParseNode GetRootParseNode(string contentType, Stream content) using var jsonDocument = JsonDocument.Parse(content); return new JsonParseNode(jsonDocument.RootElement.Clone(), _jsonJsonSerializationContext); } + /// + /// Asynchronously gets the root of the json to be read. + /// + /// The content type of the stream to be parsed + /// The containing json to parse. + /// The cancellation token for the task + /// An instance of for json manipulation + public async Task GetRootParseNodeAsync(string contentType, Stream content, + CancellationToken cancellationToken = default) + { + if(string.IsNullOrEmpty(contentType)) + throw new ArgumentNullException(nameof(contentType)); + else if(!ValidContentType.Equals(contentType, StringComparison.OrdinalIgnoreCase)) + throw new ArgumentOutOfRangeException($"expected a {ValidContentType} content type"); + + _ = content ?? throw new ArgumentNullException(nameof(content)); + + using var jsonDocument = await JsonDocument.ParseAsync(content, cancellationToken: cancellationToken).ConfigureAwait(false); + return new JsonParseNode(jsonDocument.RootElement.Clone(), _jsonJsonSerializationContext); + } } } diff --git a/src/Microsoft.Kiota.Serialization.Json.csproj b/src/Microsoft.Kiota.Serialization.Json.csproj index 9524010..97d17c5 100644 --- a/src/Microsoft.Kiota.Serialization.Json.csproj +++ b/src/Microsoft.Kiota.Serialization.Json.csproj @@ -15,7 +15,7 @@ https://aka.ms/kiota/docs true true - 1.2.3 + 1.3.0 true true