File: HttpRequestJsonExtensionsTests.cs
Web Access
Project: src\src\Http\Http.Extensions\test\Microsoft.AspNetCore.Http.Extensions.Tests.csproj (Microsoft.AspNetCore.Http.Extensions.Tests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization.Metadata;
 
#nullable enable
 
namespace Microsoft.AspNetCore.Http.Extensions.Tests;
 
public class HttpRequestJsonExtensionsTests
{
    [Theory]
    [InlineData(null, false)]
    [InlineData("", false)]
    [InlineData("application/xml", false)]
    [InlineData("text/json", false)]
    [InlineData("text/json; charset=utf-8", false)]
    [InlineData("application/json", true)]
    [InlineData("application/json; charset=utf-8", true)]
    [InlineData("application/ld+json", true)]
    [InlineData("APPLICATION/JSON", true)]
    [InlineData("APPLICATION/JSON; CHARSET=UTF-8", true)]
    [InlineData("APPLICATION/LD+JSON", true)]
    public void HasJsonContentType(string? contentType, bool hasJsonContentType)
    {
        var request = new DefaultHttpContext().Request;
        request.ContentType = contentType;
 
        Assert.Equal(hasJsonContentType, request.HasJsonContentType());
    }
 
    [Fact]
    public async Task ReadFromJsonAsyncGeneric_NonJsonContentType_ThrowError()
    {
        // Arrange
        var context = new DefaultHttpContext();
        context.Request.ContentType = "text/json";
 
        // Act
        var ex = await Assert.ThrowsAsync<InvalidOperationException>(async () => await context.Request.ReadFromJsonAsync<int>());
 
        // Assert
        var expectedMessage = $"Unable to read the request as JSON because the request content type 'text/json' is not a known JSON content type.";
        Assert.Equal(expectedMessage, ex.Message);
    }
 
    [Fact]
    public async Task ReadFromJsonAsyncGeneric_NoBodyContent_ThrowError()
    {
        // Arrange
        var context = new DefaultHttpContext();
        context.Request.ContentType = "application/json";
 
        // Act
        var ex = await Assert.ThrowsAsync<JsonException>(async () => await context.Request.ReadFromJsonAsync<int>());
 
        // Assert
        var expectedMessage = $"The input does not contain any JSON tokens. Expected the input to start with a valid JSON token, when isFinalBlock is true. Path: $ | LineNumber: 0 | BytePositionInLine: 0.";
        Assert.Equal(expectedMessage, ex.Message);
    }
 
    [Fact]
    public async Task ReadFromJsonAsyncGeneric_ValidBodyContent_ReturnValue()
    {
        // Arrange
        var context = new DefaultHttpContext();
        context.Request.ContentType = "application/json";
        context.Request.Body = new MemoryStream(Encoding.UTF8.GetBytes("1"));
 
        // Act
        var result = await context.Request.ReadFromJsonAsync<int>();
 
        // Assert
        Assert.Equal(1, result);
    }
 
    [Fact]
    public async Task ReadFromJsonAsyncGeneric_WithOptions_ReturnValue()
    {
        // Arrange
        var context = new DefaultHttpContext();
        context.Request.ContentType = "application/json";
        context.Request.Body = new MemoryStream(Encoding.UTF8.GetBytes("[1,2,]"));
 
        var options = new JsonSerializerOptions();
        options.AllowTrailingCommas = true;
 
        // Act
        var result = await context.Request.ReadFromJsonAsync<List<int>>(options);
 
        // Assert
        Assert.NotNull(result);
        Assert.Collection(result,
            i => Assert.Equal(1, i),
            i => Assert.Equal(2, i));
    }
 
    [Fact]
    public async Task ReadFromJsonAsyncGeneric_Utf8Encoding_ReturnValue()
    {
        // Arrange
        var context = new DefaultHttpContext();
        context.Request.ContentType = "application/json; charset=utf-8";
        context.Request.Body = new MemoryStream(Encoding.UTF8.GetBytes("[1,2]"));
 
        // Act
        var result = await context.Request.ReadFromJsonAsync<List<int>>();
 
        // Assert
        Assert.NotNull(result);
        Assert.Collection(result,
            i => Assert.Equal(1, i),
            i => Assert.Equal(2, i));
    }
 
    [Fact]
    public async Task ReadFromJsonAsyncGeneric_Utf16Encoding_ReturnValue()
    {
        // Arrange
        var context = new DefaultHttpContext();
        context.Request.ContentType = "application/json; charset=utf-16";
        context.Request.Body = new MemoryStream(Encoding.Unicode.GetBytes(@"{""name"": ""激光這兩個字是甚麼意思""}"{""name"": ""激光這兩個字是甚麼意思""}"));
 
        // Act
        var result = await context.Request.ReadFromJsonAsync<Dictionary<string, string>>();
 
        // Assert
        Assert.Equal("激光這兩個字是甚麼意思", result!["name"]);
    }
 
    [Fact]
    public async Task ReadFromJsonAsyncGeneric_WithCancellationToken_CancellationRaised()
    {
        // Arrange
        var context = new DefaultHttpContext();
        context.Request.ContentType = "application /json";
        context.Request.Body = new TestStream();
 
        var cts = new CancellationTokenSource();
 
        // Act
        var readTask = context.Request.ReadFromJsonAsync<List<int>>(cts.Token);
        Assert.False(readTask.IsCompleted);
 
        cts.Cancel();
 
        // Assert
        await Assert.ThrowsAsync<TaskCanceledException>(async () => await readTask);
    }
 
    [Fact]
    public async Task ReadFromJsonAsyncGeneric_InvalidEncoding_ThrowError()
    {
        // Arrange
        var context = new DefaultHttpContext();
        context.Request.ContentType = "application/json; charset=invalid";
 
        // Act
        var ex = await Assert.ThrowsAsync<InvalidOperationException>(async () => await context.Request.ReadFromJsonAsync<object>());
 
        // Assert
        Assert.Equal("Unable to read the request as JSON because the request content type charset 'invalid' is not a known encoding.", ex.Message);
    }
 
    [Fact]
    public async Task ReadFromJsonAsync_ValidBodyContent_ReturnValue()
    {
        // Arrange
        var context = new DefaultHttpContext();
        context.Request.ContentType = "application/json";
        context.Request.Body = new MemoryStream(Encoding.UTF8.GetBytes("1"));
 
        // Act
        var result = (int?)await context.Request.ReadFromJsonAsync(typeof(int));
 
        // Assert
        Assert.Equal(1, result);
    }
 
    [Fact]
    public async Task ReadFromJsonAsync_Utf16Encoding_ReturnValue()
    {
        // Arrange
        var context = new DefaultHttpContext();
        context.Request.ContentType = "application/json; charset=utf-16";
        context.Request.Body = new MemoryStream(Encoding.Unicode.GetBytes(@"{""name"": ""激光這兩個字是甚麼意思""}"{""name"": ""激光這兩個字是甚麼意思""}"));
 
        // Act
        var result = (Dictionary<string, string>?)await context.Request.ReadFromJsonAsync(typeof(Dictionary<string, string>));
 
        // Assert
        Assert.Equal("激光這兩個字是甚麼意思", result!["name"]);
    }
 
    [Fact]
    public async Task ReadFromJsonAsync_InvalidEncoding_ThrowError()
    {
        // Arrange
        var context = new DefaultHttpContext();
        context.Request.ContentType = "application/json; charset=invalid";
 
        // Act
        var ex = await Assert.ThrowsAsync<InvalidOperationException>(async () => await context.Request.ReadFromJsonAsync(typeof(object)));
 
        // Assert
        Assert.Equal("Unable to read the request as JSON because the request content type charset 'invalid' is not a known encoding.", ex.Message);
    }
 
    [Fact]
    public async Task ReadFromJsonAsync_WithOptions_ReturnValue()
    {
        // Arrange
        var context = new DefaultHttpContext();
        context.Request.ContentType = "application/json";
        context.Request.Body = new MemoryStream(Encoding.UTF8.GetBytes("[1,2,]"));
 
        var options = new JsonSerializerOptions();
        options.AllowTrailingCommas = true;
 
        // Act
        var result = (List<int>?)await context.Request.ReadFromJsonAsync(typeof(List<int>), options);
 
        // Assert
        Assert.NotNull(result);
        Assert.Collection(result,
            i => Assert.Equal(1, i),
            i => Assert.Equal(2, i));
    }
 
    [Fact]
    public async Task ReadFromJsonAsync_WithTypeInfo_ReturnValue()
    {
        // Arrange
        var context = new DefaultHttpContext();
        context.Request.ContentType = "application/json";
        context.Request.Body = new MemoryStream(Encoding.UTF8.GetBytes("[1,2,]"));
 
        var options = new JsonSerializerOptions();
        options.AllowTrailingCommas = true;
        options.TypeInfoResolver = new DefaultJsonTypeInfoResolver();
 
        // Act
        var result = (List<int>?)await context.Request.ReadFromJsonAsync(options.GetTypeInfo(typeof(List<int>)));
 
        // Assert
        Assert.NotNull(result);
        Assert.Collection(result,
            i => Assert.Equal(1, i),
            i => Assert.Equal(2, i));
    }
 
    [Fact]
    public async Task ReadFromJsonAsync_WithGenericTypeInfo_ReturnValue()
    {
        // Arrange
        var context = new DefaultHttpContext();
        context.Request.ContentType = "application/json";
        context.Request.Body = new MemoryStream(Encoding.UTF8.GetBytes("[1,2,]"));
 
        var options = new JsonSerializerOptions();
        options.AllowTrailingCommas = true;
        options.TypeInfoResolver = new DefaultJsonTypeInfoResolver();
 
        // Act
        var typeInfo = (JsonTypeInfo<List<int>>)options.GetTypeInfo(typeof(List<int>));
        var result = await context.Request.ReadFromJsonAsync(typeInfo);
 
        // Assert
        Assert.NotNull(result);
        Assert.Collection(result,
            i => Assert.Equal(1, i),
            i => Assert.Equal(2, i));
    }
}