File: Formatters\TextInputFormatterTest.cs
Web Access
Project: src\src\Mvc\Mvc.Core\test\Microsoft.AspNetCore.Mvc.Core.Test.csproj (Microsoft.AspNetCore.Mvc.Core.Test)
// 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 Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.ModelBinding;
 
namespace Microsoft.AspNetCore.Mvc.Formatters;
 
public class TextInputFormatterTest
{
    [Fact]
    public async Task ReadAsync_ReturnsFailure_IfItCanNotUnderstandTheContentTypeEncoding()
    {
        // Arrange
        var formatter = new TestFormatter();
        formatter.SupportedEncodings.Add(Encoding.ASCII);
 
        var context = new InputFormatterContext(
            new DefaultHttpContext(),
            "something",
            new ModelStateDictionary(),
            new EmptyModelMetadataProvider().GetMetadataForType(typeof(object)),
            (stream, encoding) => new StreamReader(stream, encoding));
 
        context.HttpContext.Request.ContentType = "application/json;charset=utf-8";
        context.HttpContext.Request.ContentLength = 1;
 
        // Act
        var result = await formatter.ReadAsync(context);
 
        // Assert
        Assert.True(result.HasError);
        Assert.True(context.ModelState.ContainsKey("something"));
        Assert.Single(context.ModelState["something"].Errors);
 
        var error = context.ModelState["something"].Errors[0];
        Assert.IsType<UnsupportedContentTypeException>(error.Exception);
    }
 
    [Fact]
    public void SelectCharacterEncoding_ThrowsInvalidOperationException_IfItDoesNotHaveAValidEncoding()
    {
        // Arrange
        var formatter = new TestFormatter();
 
        var context = new InputFormatterContext(
            new DefaultHttpContext(),
            "something",
            new ModelStateDictionary(),
            new EmptyModelMetadataProvider().GetMetadataForType(typeof(object)),
            (stream, encoding) => new StreamReader(stream, encoding));
 
        context.HttpContext.Request.ContentLength = 1;
 
        // Act & Assert
        Assert.Throws<InvalidOperationException>(() => formatter.TestSelectCharacterEncoding(context));
    }
 
    [Theory]
    [InlineData("utf-8")]
    [InlineData("invalid")]
    public void SelectCharacterEncoding_ReturnsNull_IfItCanNotUnderstandContentTypeEncoding(string charset)
    {
        // Arrange
        var formatter = new TestFormatter();
        formatter.SupportedEncodings.Add(Encoding.UTF32);
 
        var context = new InputFormatterContext(
            new DefaultHttpContext(),
            "something",
            new ModelStateDictionary(),
            new EmptyModelMetadataProvider().GetMetadataForType(typeof(object)),
            (stream, encoding) => new StreamReader(stream, encoding));
 
        context.HttpContext.Request.ContentType = "application/json;charset=" + charset;
 
        // Act
        var result = formatter.TestSelectCharacterEncoding(context);
 
        // Assert
        Assert.Null(result);
    }
 
    [Fact]
    public void SelectCharacterEncoding_ReturnsContentTypeEncoding_IfItCanUnderstandIt()
    {
        // Arrange
        var formatter = new TestFormatter();
        formatter.SupportedEncodings.Add(Encoding.UTF32);
        formatter.SupportedEncodings.Add(Encoding.UTF8);
 
        var context = new InputFormatterContext(
            new DefaultHttpContext(),
            "something",
            new ModelStateDictionary(),
            new EmptyModelMetadataProvider().GetMetadataForType(typeof(object)),
            (stream, encoding) => new StreamReader(stream, encoding));
 
        context.HttpContext.Request.ContentType = "application/json;charset=utf-8";
 
        // Act
        var result = formatter.TestSelectCharacterEncoding(context);
 
        // Assert
        Assert.Equal(Encoding.UTF8, result);
    }
 
    [Theory]
    [InlineData("unicode-1-1-utf-8")]
    [InlineData("unicode-2-0-utf-8")]
    public void SelectCharacterEncoding_ReturnsUTF8Encoding_IfContentTypeIsAnAlias(string charset)
    {
        // Arrange
        var formatter = new TestFormatter();
        formatter.SupportedEncodings.Add(Encoding.UTF32);
        formatter.SupportedEncodings.Add(Encoding.UTF8);
 
        var context = new InputFormatterContext(
            new DefaultHttpContext(),
            "something",
            new ModelStateDictionary(),
            new EmptyModelMetadataProvider().GetMetadataForType(typeof(object)),
            (stream, encoding) => new StreamReader(stream, encoding));
 
        context.HttpContext.Request.ContentType = "application/json;charset=" + charset;
 
        // Act
        var result = formatter.TestSelectCharacterEncoding(context);
 
        // Assert
        Assert.Equal(Encoding.UTF8, result);
    }
 
    [Theory]
    [InlineData("ANSI_X3.4-1968")]
    [InlineData("ANSI_X3.4-1986")]
    [InlineData("ascii")]
    [InlineData("cp367")]
    [InlineData("csASCII")]
    [InlineData("IBM367")]
    [InlineData("iso-ir-6")]
    [InlineData("ISO646-US")]
    [InlineData("ISO_646.irv:1991")]
    [InlineData("us")]
    public void SelectCharacterEncoding_ReturnsAsciiEncoding_IfContentTypeIsAnAlias(string charset)
    {
        // Arrange
        var formatter = new TestFormatter();
        formatter.SupportedEncodings.Add(Encoding.UTF32);
        formatter.SupportedEncodings.Add(Encoding.ASCII);
 
        var context = new InputFormatterContext(
            new DefaultHttpContext(),
            "something",
            new ModelStateDictionary(),
            new EmptyModelMetadataProvider().GetMetadataForType(typeof(object)),
            (stream, encoding) => new StreamReader(stream, encoding));
 
        context.HttpContext.Request.ContentType = "application/json;charset=\"" + charset + "\"";
 
        // Act
        var result = formatter.TestSelectCharacterEncoding(context);
 
        // Assert
        Assert.Equal(Encoding.ASCII, result);
    }
 
    [Theory]
    [InlineData("")]
    [InlineData("(garbage)")]
    [InlineData("(garbage); charset=utf-32")]
    [InlineData("text/(garbage)")]
    [InlineData("text/(garbage); charset=utf-32")]
    [InlineData("application/json")]
    [InlineData("application/json; charset")]
    [InlineData("application/json; charset=(garbage)")]
    [InlineData("application/json; version=(garbage); charset=utf-32")]
    public void SelectCharacterEncoding_ReturnsFirstEncoding_IfContentTypeIsMissingInvalidOrDoesNotHaveEncoding(
        string contentType)
    {
        // Arrange
        var formatter = new TestFormatter();
        formatter.SupportedEncodings.Add(Encoding.UTF8);
        formatter.SupportedEncodings.Add(Encoding.UTF32);
 
        var context = new InputFormatterContext(
            new DefaultHttpContext(),
            "something",
            new ModelStateDictionary(),
            new EmptyModelMetadataProvider().GetMetadataForType(typeof(object)),
            (stream, encoding) => new StreamReader(stream, encoding));
 
        context.HttpContext.Request.ContentType = contentType;
 
        // Act
        var result = formatter.TestSelectCharacterEncoding(context);
 
        // Assert
        Assert.Equal(Encoding.UTF8, result);
    }
 
    private class TestFormatter : TextInputFormatter
    {
        private readonly object _object;
 
        public TestFormatter() : this(null) { }
 
        public TestFormatter(object @object)
        {
            _object = @object;
        }
 
        public IList<Type> SupportedTypes { get; } = new List<Type>();
 
        protected override bool CanReadType(Type type)
        {
            return SupportedTypes.Count == 0 ? true : SupportedTypes.Contains(type);
        }
 
        public override Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
        {
            return InputFormatterResult.SuccessAsync(_object);
        }
 
        public Encoding TestSelectCharacterEncoding(InputFormatterContext context)
        {
            return SelectCharacterEncoding(context);
        }
    }
}