327 lines
12 KiB
C#
327 lines
12 KiB
C#
// Copyright (c) .NET Foundation. All rights reserved.
|
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
|
|
using System.Collections.Generic;
|
|
using System.Net.Http.Formatting;
|
|
using System.Net.Http.Headers;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.AspNetCore.Mvc.WebApiCompatShim;
|
|
using Microsoft.AspNetCore.Testing;
|
|
using Microsoft.Extensions.Options;
|
|
using Moq;
|
|
using Xunit;
|
|
|
|
namespace System.Net.Http
|
|
{
|
|
public class HttpRequestMessageExtensionsTest
|
|
{
|
|
[Fact]
|
|
public void CreateResponse_MatchingMediaType_WhenMediaTypeStringIsInvalidFormat_Throws()
|
|
{
|
|
HttpRequestMessage request = CreateRequest(new DefaultHttpContext());
|
|
|
|
var ex = Assert.Throws<FormatException>(
|
|
() => request.CreateResponse(HttpStatusCode.OK, CreateValue(), "foo/bar; param=value"));
|
|
|
|
Assert.Contains("foo/bar; param=value", ex.Message);
|
|
}
|
|
|
|
[Fact]
|
|
public void CreateResponse_MatchingMediaType_WhenRequestDoesNotHaveHttpContextThrows()
|
|
{
|
|
HttpRequestMessage request = CreateRequest(null);
|
|
|
|
// Arrange
|
|
|
|
// Act
|
|
var ex = Assert.Throws<InvalidOperationException>(
|
|
() => request.CreateResponse(HttpStatusCode.OK, CreateValue(), mediaType: "foo/bar"));
|
|
|
|
Assert.Equal(
|
|
"The HttpRequestMessage instance is not properly initialized. " +
|
|
"Use HttpRequestMessageHttpContextExtensions.GetHttpRequestMessage to create an HttpRequestMessage " +
|
|
"for the current request.",
|
|
ex.Message);
|
|
}
|
|
|
|
[Fact]
|
|
public void CreateResponse_DoingConneg_OnlyContent_RetrievesContentNegotiatorFromServices()
|
|
{
|
|
// Arrange
|
|
var context = new DefaultHttpContext();
|
|
|
|
var services = new Mock<IServiceProvider>();
|
|
services
|
|
.Setup(s => s.GetService(typeof(IContentNegotiator)))
|
|
.Returns(Mock.Of<IContentNegotiator>())
|
|
.Verifiable();
|
|
|
|
var options = new WebApiCompatShimOptions();
|
|
options.Formatters.AddRange(new MediaTypeFormatterCollection());
|
|
|
|
var optionsAccessor = new Mock<IOptions<WebApiCompatShimOptions>>();
|
|
optionsAccessor.SetupGet(o => o.Value).Returns(options);
|
|
|
|
services
|
|
.Setup(s => s.GetService(typeof(IOptions<WebApiCompatShimOptions>)))
|
|
.Returns(optionsAccessor.Object);
|
|
|
|
context.RequestServices = services.Object;
|
|
|
|
var request = CreateRequest(context);
|
|
|
|
// Act
|
|
request.CreateResponse(CreateValue());
|
|
|
|
// Assert
|
|
services.Verify();
|
|
}
|
|
|
|
[Fact]
|
|
public void CreateResponse_DoingConneg_RetrievesContentNegotiatorFromServices()
|
|
{
|
|
// Arrange
|
|
var context = new DefaultHttpContext();
|
|
|
|
var services = new Mock<IServiceProvider>();
|
|
services
|
|
.Setup(s => s.GetService(typeof(IContentNegotiator)))
|
|
.Returns(Mock.Of<IContentNegotiator>())
|
|
.Verifiable();
|
|
|
|
var options = new WebApiCompatShimOptions();
|
|
options.Formatters.AddRange(new MediaTypeFormatterCollection());
|
|
|
|
var optionsAccessor = new Mock<IOptions<WebApiCompatShimOptions>>();
|
|
optionsAccessor.SetupGet(o => o.Value).Returns(options);
|
|
|
|
services
|
|
.Setup(s => s.GetService(typeof(IOptions<WebApiCompatShimOptions>)))
|
|
.Returns(optionsAccessor.Object);
|
|
|
|
context.RequestServices = services.Object;
|
|
|
|
var request = CreateRequest(context);
|
|
|
|
// Act
|
|
request.CreateResponse(HttpStatusCode.OK, CreateValue());
|
|
|
|
// Assert
|
|
services.Verify();
|
|
}
|
|
|
|
[Fact]
|
|
public void CreateResponse_DoingConneg_PerformsContentNegotiationAndCreatesContentUsingResults()
|
|
{
|
|
// Arrange
|
|
var context = new DefaultHttpContext();
|
|
|
|
var formatter = new XmlMediaTypeFormatter();
|
|
|
|
var contentNegotiator = new Mock<IContentNegotiator>();
|
|
contentNegotiator
|
|
.Setup(c => c.Negotiate(It.IsAny<Type>(), It.IsAny<HttpRequestMessage>(), It.IsAny<IEnumerable<MediaTypeFormatter>>()))
|
|
.Returns(new ContentNegotiationResult(formatter, mediaType: null));
|
|
|
|
context.RequestServices = CreateServices(contentNegotiator.Object, formatter);
|
|
|
|
var request = CreateRequest(context);
|
|
|
|
// Act
|
|
var response = request.CreateResponse<string>(HttpStatusCode.NoContent, "42");
|
|
|
|
// Assert
|
|
Assert.Equal(HttpStatusCode.NoContent, response.StatusCode);
|
|
Assert.Same(request, response.RequestMessage);
|
|
|
|
var objectContent = Assert.IsType<ObjectContent<string>>(response.Content);
|
|
Assert.Equal("42", objectContent.Value);
|
|
Assert.Same(formatter, objectContent.Formatter);
|
|
}
|
|
|
|
[Fact]
|
|
public void CreateResponse_MatchingMediaType_WhenMediaTypeDoesNotMatch_Throws()
|
|
{
|
|
// Arrange
|
|
var context = new DefaultHttpContext();
|
|
context.RequestServices = CreateServices(new DefaultContentNegotiator());
|
|
|
|
var request = CreateRequest(context);
|
|
|
|
// Act
|
|
var ex = Assert.Throws<InvalidOperationException>(
|
|
() => request.CreateResponse(HttpStatusCode.OK, CreateValue(), mediaType: "foo/bar"));
|
|
Assert.Equal(
|
|
"Could not find a formatter matching the media type 'foo/bar' that can write an instance of 'System.Object'.",
|
|
ex.Message);
|
|
}
|
|
|
|
[Fact]
|
|
public void CreateResponse_MatchingMediaType_FindsMatchingFormatterAndCreatesResponse()
|
|
{
|
|
// Arrange
|
|
var context = new DefaultHttpContext();
|
|
|
|
var formatter = new Mock<MediaTypeFormatter> { CallBase = true };
|
|
formatter.Setup(f => f.CanWriteType(typeof(object))).Returns(true).Verifiable();
|
|
formatter.Object.SupportedMediaTypes.Add(new MediaTypeHeaderValue("foo/bar"));
|
|
|
|
context.RequestServices = CreateServices(new DefaultContentNegotiator(), formatter.Object);
|
|
|
|
var expectedValue = CreateValue();
|
|
|
|
var request = CreateRequest(context);
|
|
|
|
// Act
|
|
var response = request.CreateResponse(HttpStatusCode.Gone, expectedValue, mediaType: "foo/bar");
|
|
|
|
// Assert
|
|
Assert.Equal(HttpStatusCode.Gone, response.StatusCode);
|
|
var content = Assert.IsType<ObjectContent<object>>(response.Content);
|
|
Assert.Same(expectedValue, content.Value);
|
|
Assert.Same(formatter.Object, content.Formatter);
|
|
Assert.Equal("foo/bar", content.Headers.ContentType.MediaType);
|
|
formatter.Verify();
|
|
}
|
|
|
|
[Fact]
|
|
public void CreateResponse_AcceptingFormatter_CreatesResponseWithDefaultMediaType()
|
|
{
|
|
// Arrange
|
|
var context = new DefaultHttpContext();
|
|
|
|
var formatter = new Mock<MediaTypeFormatter>() { CallBase = true };
|
|
formatter
|
|
.Setup(f => f.CanWriteType(typeof(object)))
|
|
.Returns(true)
|
|
.Verifiable();
|
|
formatter
|
|
.Setup(f => f.SetDefaultContentHeaders(typeof(object), It.IsAny<HttpContentHeaders>(), It.IsAny<MediaTypeHeaderValue>()))
|
|
.Callback<Type, HttpContentHeaders, MediaTypeHeaderValue>(SetMediaType)
|
|
.Verifiable();
|
|
|
|
formatter.Object.SupportedMediaTypes.Add(new MediaTypeHeaderValue("foo/bar"));
|
|
|
|
var expectedValue = CreateValue();
|
|
|
|
var request = CreateRequest(context);
|
|
|
|
// Act
|
|
var response = request.CreateResponse(
|
|
HttpStatusCode.MultipleChoices,
|
|
expectedValue,
|
|
formatter.Object,
|
|
mediaType: (string)null);
|
|
|
|
// Assert
|
|
Assert.Equal(HttpStatusCode.MultipleChoices, response.StatusCode);
|
|
var content = Assert.IsType<ObjectContent<object>>(response.Content);
|
|
Assert.Same(expectedValue, content.Value);
|
|
Assert.Same(formatter.Object, content.Formatter);
|
|
Assert.Equal("foo/bar", content.Headers.ContentType.MediaType);
|
|
|
|
formatter.Verify();
|
|
}
|
|
|
|
private static void SetMediaType(Type type, HttpContentHeaders headers, MediaTypeHeaderValue value)
|
|
{
|
|
headers.ContentType = new MediaTypeHeaderValue("foo/bar");
|
|
}
|
|
|
|
[Fact]
|
|
public void CreateResponse_AcceptingFormatter_WithOverridenMediaTypeString_CreatesResponse()
|
|
{
|
|
// Arrange
|
|
var context = new DefaultHttpContext();
|
|
|
|
var formatter = new Mock<MediaTypeFormatter> { CallBase = true };
|
|
formatter.Setup(f => f.CanWriteType(typeof(object))).Returns(true).Verifiable();
|
|
formatter.Object.SupportedMediaTypes.Add(new MediaTypeHeaderValue("foo/bar"));
|
|
|
|
var expectedValue = CreateValue();
|
|
|
|
var request = CreateRequest(context);
|
|
|
|
// Act
|
|
var response = request.CreateResponse(
|
|
HttpStatusCode.MultipleChoices,
|
|
CreateValue(),
|
|
formatter.Object,
|
|
mediaType: "bin/baz");
|
|
|
|
// Assert
|
|
Assert.Equal("bin/baz", response.Content.Headers.ContentType.MediaType);
|
|
}
|
|
|
|
[Fact]
|
|
public void CreateResponse_AcceptingFormatter_WithOverridenMediaTypeHeader_CreatesResponse()
|
|
{
|
|
// Arrange
|
|
var context = new DefaultHttpContext();
|
|
|
|
var formatter = new Mock<MediaTypeFormatter> { CallBase = true };
|
|
formatter.Setup(f => f.CanWriteType(typeof(object))).Returns(true).Verifiable();
|
|
formatter.Object.SupportedMediaTypes.Add(new MediaTypeHeaderValue("foo/bar"));
|
|
|
|
var expectedValue = CreateValue();
|
|
|
|
var request = CreateRequest(context);
|
|
|
|
// Act
|
|
var response = request.CreateResponse(
|
|
HttpStatusCode.MultipleChoices,
|
|
CreateValue(),
|
|
formatter.Object,
|
|
mediaType: new MediaTypeHeaderValue("bin/baz"));
|
|
|
|
// Assert
|
|
Assert.Equal("bin/baz", response.Content.Headers.ContentType.MediaType);
|
|
}
|
|
|
|
private static IServiceProvider CreateServices(
|
|
IContentNegotiator contentNegotiator = null,
|
|
MediaTypeFormatter formatter = null)
|
|
{
|
|
var options = new WebApiCompatShimOptions();
|
|
|
|
if (formatter == null)
|
|
{
|
|
options.Formatters.AddRange(new MediaTypeFormatterCollection());
|
|
}
|
|
else
|
|
{
|
|
options.Formatters.Add(formatter);
|
|
}
|
|
|
|
var optionsAccessor = new Mock<IOptions<WebApiCompatShimOptions>>();
|
|
optionsAccessor.SetupGet(o => o.Value).Returns(options);
|
|
|
|
var services = new Mock<IServiceProvider>(MockBehavior.Strict);
|
|
services
|
|
.Setup(s => s.GetService(typeof(IOptions<WebApiCompatShimOptions>)))
|
|
.Returns(optionsAccessor.Object);
|
|
|
|
if (contentNegotiator != null)
|
|
{
|
|
services
|
|
.Setup(s => s.GetService(typeof(IContentNegotiator)))
|
|
.Returns(contentNegotiator);
|
|
}
|
|
|
|
return services.Object;
|
|
}
|
|
|
|
private static object CreateValue()
|
|
{
|
|
return new object();
|
|
}
|
|
|
|
private static HttpRequestMessage CreateRequest(HttpContext context)
|
|
{
|
|
var request = new HttpRequestMessage();
|
|
request.Properties.Add(nameof(HttpContext), context);
|
|
return request;
|
|
}
|
|
}
|
|
}
|