aspnetcore/test/Microsoft.AspNetCore.Mvc.We.../DefaultContentNegotiatorTes...

701 lines
33 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.Linq;
using System.Net.Http.Formatting.Mocks;
using System.Net.Http.Headers;
using System.Text;
using Microsoft.AspNetCore.Testing;
using Microsoft.TestCommon;
using Newtonsoft.Json.Linq;
using Xunit;
namespace System.Net.Http.Formatting
{
public class DefaultContentNegotiatorTests
{
private readonly DefaultContentNegotiator _negotiator = new DefaultContentNegotiator();
private readonly HttpRequestMessage _request = new HttpRequestMessage();
public static TheoryData<string, string[], string> MatchRequestMediaTypeData
{
get
{
// string requestMediaType, string[] supportedMediaTypes, string expectedMediaType
return new TheoryData<string, string[], string>
{
{ "text/plain", new string[0], null },
{ "text/plain", new string[] { "text/xml", "application/xml" }, null },
{ "application/xml", new string[] { "application/xml", "text/xml" }, "application/xml" },
{ "APPLICATION/XML", new string[] { "text/xml", "application/xml" }, "application/xml" },
{ "application/xml; charset=utf-8", new string[] { "text/xml", "application/xml" }, "application/xml" },
{ "application/xml; charset=utf-8; parameter=value", new string[] { "text/xml", "application/xml" }, "application/xml" },
};
}
}
public static TheoryData<string[], string[], string, double, int> MatchAcceptHeaderData
{
get
{
// string[] acceptHeader, string[] supportedMediaTypes, string expectedMediaType, double matchQuality, int range
return new TheoryData<string[], string[], string, double, int>
{
{ new string[] { "text/plain" }, new string[0], null, 0.0, (int)MediaTypeFormatterMatchRanking.MatchOnRequestAcceptHeaderLiteral },
{ new string[] { "text/plain" }, new string[] { "text/xml", "application/xml" }, null, 0.0, (int)MediaTypeFormatterMatchRanking.None },
{ new string[] { "text/plain; q=0.5" }, new string[] { "text/xml", "application/xml" }, null, 0.0, (int)MediaTypeFormatterMatchRanking.None },
{ new string[] { "application/xml" }, new string[] { "application/xml", "text/xml" }, "application/xml", 1.0, (int)MediaTypeFormatterMatchRanking.MatchOnRequestAcceptHeaderLiteral },
{ new string[] { "APPLICATION/XML; q=0.5" }, new string[] { "text/xml", "application/xml" }, "application/xml", 0.5, (int)MediaTypeFormatterMatchRanking.MatchOnRequestAcceptHeaderLiteral },
{ new string[] { "text/xml; q=0.5", "APPLICATION/XML; q=0.7" }, new string[] { "text/xml", "application/xml" }, "application/xml", 0.7, (int)MediaTypeFormatterMatchRanking.MatchOnRequestAcceptHeaderLiteral },
{ new string[] { "application/xml; q=0.0" }, new string[] { "application/xml", "text/xml" }, null, 0.0, (int)MediaTypeFormatterMatchRanking.None },
{ new string[] { "APPLICATION/XML; q=0.0" }, new string[] { "text/xml", "application/xml" }, null, 0.0, (int)MediaTypeFormatterMatchRanking.None },
{ new string[] { "text/xml; q=0.0", "APPLICATION/XML; q=0.0" }, new string[] { "text/xml", "application/xml" }, null, 0.0, (int)MediaTypeFormatterMatchRanking.None },
{ new string[] { "text/*" }, new string[] { "text/xml", "application/xml" }, "text/xml", 1.0, (int)MediaTypeFormatterMatchRanking.MatchOnRequestAcceptHeaderSubtypeMediaRange },
{ new string[] { "text/*", "application/xml" }, new string[] { "text/xml", "application/xml" }, "application/xml", 1.0, (int)MediaTypeFormatterMatchRanking.MatchOnRequestAcceptHeaderLiteral },
{ new string[] { "text/*", "application/xml; q=0.5" }, new string[] { "text/xml", "application/xml" }, "text/xml", 1.0, (int)MediaTypeFormatterMatchRanking.MatchOnRequestAcceptHeaderSubtypeMediaRange },
{ new string[] { "text/*; q=0.5" }, new string[] { "text/xml", "application/xml" }, "text/xml", 0.5, (int)MediaTypeFormatterMatchRanking.MatchOnRequestAcceptHeaderSubtypeMediaRange },
{ new string[] { "text/*; q=0.5", "application/xml" }, new string[] { "text/xml", "application/xml" }, "application/xml", 1.0, (int)MediaTypeFormatterMatchRanking.MatchOnRequestAcceptHeaderLiteral },
{ new string[] { "text/*; q=0.0", "application/xml; q=0.0" }, new string[] { "text/xml", "application/xml" }, null, 0.0, (int)MediaTypeFormatterMatchRanking.None },
{ new string[] { "text/*; q=0.0", "application/xml" }, new string[] { "text/xml", "application/xml" }, "application/xml", 1.0, (int)MediaTypeFormatterMatchRanking.MatchOnRequestAcceptHeaderLiteral },
{ new string[] { "*/*; q=0.5" }, new string[] { "text/xml", "application/xml" }, "text/xml", 0.5, (int)MediaTypeFormatterMatchRanking.MatchOnRequestAcceptHeaderAllMediaRange },
{ new string[] { "*/*; q=0.0" }, new string[] { "text/xml", "application/xml" }, null, 0.0, (int)MediaTypeFormatterMatchRanking.None },
{ new string[] { "*/*; q=0.5", "application/xml" }, new string[] { "text/xml", "application/xml" }, "application/xml", 1.0, (int)MediaTypeFormatterMatchRanking.MatchOnRequestAcceptHeaderLiteral },
{ new string[] { "*/*; q=1.0", "application/xml; q=0.5" }, new string[] { "text/xml", "application/xml" }, "text/xml", 1.0, (int)MediaTypeFormatterMatchRanking.MatchOnRequestAcceptHeaderAllMediaRange },
{ new string[] { "*/*", "application/xml" }, new string[] { "text/xml", "application/xml" }, "application/xml", 1.0, (int)MediaTypeFormatterMatchRanking.MatchOnRequestAcceptHeaderLiteral },
{ new string[] { "text/*; q=0.5", "*/*; q=0.2", "application/xml; q=1.0" }, new string[] { "text/xml", "application/xml" }, "application/xml", 1.0, (int)MediaTypeFormatterMatchRanking.MatchOnRequestAcceptHeaderLiteral },
{ new string[] { "application/xml; q=0.5" }, new string[] { "text/xml", "application/xml" }, "application/xml", 0.5, (int)MediaTypeFormatterMatchRanking.MatchOnRequestAcceptHeaderLiteral },
};
}
}
public static TheoryData<bool, string[], bool> ShouldMatchOnTypeData
{
get
{
// bool excludeMatchOnType, string[] acceptHeaders, bool expectedResult
return new TheoryData<bool, string[], bool>
{
{ false, new string[0], true },
{ true, new string[0], true },
{ false, new string[] { "application/xml" }, true },
{ true, new string[] { "application/xml" }, false },
{ false, new string[] { "application/xml; q=1.0" }, true },
{ true, new string[] { "application/xml; q=1.0" }, false },
{ false, new string[] { "application/xml; q=0.0" }, true },
{ true, new string[] { "application/xml; q=0.0" }, false },
{ false, new string[] { "application/xml; q=0.0", "application/json" }, true },
{ true, new string[] { "application/xml; q=0.0", "application/json" }, false },
{ false, new string[] { "text/nomatch" }, true },
{ true, new string[] { "text/nomatch" }, false },
};
}
}
public static TheoryData<string[], string> MatchTypeData
{
get
{
// string[] supportedMediaTypes, string expectedMediaType
return new TheoryData<string[], string>
{
{ new string[0], "application/octet-stream" },
{ new string[] { "text/xml", "application/xml" }, "text/xml" },
{ new string[] { "application/xml", "text/xml" }, "application/xml" },
};
}
}
public static TheoryData<string[], string, string[], string> SelectResponseCharacterEncodingData
{
get
{
// string[] acceptEncodings, string requestEncoding, string[] supportedEncodings, string expectedEncoding
return new TheoryData<string[], string, string[], string>
{
{ new string[] { "utf-8" }, null, new string[0], null },
{ new string[0], "utf-8", new string[0], null },
{ new string[0], null, new string[] { "utf-8", "utf-16"}, "utf-8" },
{ new string[0], "utf-16", new string[] { "utf-8", "utf-16"}, "utf-16" },
{ new string[] { "utf-8" }, null, new string[] { "utf-8", "utf-16"}, "utf-8" },
{ new string[] { "utf-16" }, "utf-8", new string[] { "utf-8", "utf-16"}, "utf-16" },
{ new string[] { "utf-16; q=0.5" }, "utf-8", new string[] { "utf-8", "utf-16"}, "utf-16" },
{ new string[] { "utf-8; q=0.0" }, null, new string[] { "utf-8", "utf-16"}, "utf-8" },
{ new string[] { "utf-8; q=0.0" }, "utf-16", new string[] { "utf-8", "utf-16"}, "utf-16" },
{ new string[] { "utf-8; q=0.0", "utf-16; q=0.0" }, "utf-16", new string[] { "utf-8", "utf-16"}, "utf-16" },
{ new string[] { "utf-8; q=0.0", "utf-16; q=0.0" }, null, new string[] { "utf-8", "utf-16"}, "utf-8" },
{ new string[] { "*; q=0.0" }, null, new string[] { "utf-8", "utf-16"}, "utf-8" },
{ new string[] { "*; q=0.0" }, "utf-16", new string[] { "utf-8", "utf-16"}, "utf-16" },
};
}
}
public static TheoryData<ICollection<MediaTypeFormatterMatch>, MediaTypeFormatterMatch> SelectResponseMediaTypeData
{
get
{
MediaTypeFormatterMatch matchAccept10 = CreateMatch(1.0, MediaTypeFormatterMatchRanking.MatchOnRequestAcceptHeaderLiteral);
MediaTypeFormatterMatch matchAccept05 = CreateMatch(0.5, MediaTypeFormatterMatchRanking.MatchOnRequestAcceptHeaderLiteral);
MediaTypeFormatterMatch matchAcceptSubTypeRange10 = CreateMatch(1.0, MediaTypeFormatterMatchRanking.MatchOnRequestAcceptHeaderSubtypeMediaRange);
MediaTypeFormatterMatch matchAcceptSubTypeRange05 = CreateMatch(0.5, MediaTypeFormatterMatchRanking.MatchOnRequestAcceptHeaderSubtypeMediaRange);
MediaTypeFormatterMatch matchAcceptAllRange10 = CreateMatch(1.0, MediaTypeFormatterMatchRanking.MatchOnRequestAcceptHeaderAllMediaRange);
MediaTypeFormatterMatch matchAcceptAllRange05 = CreateMatch(0.5, MediaTypeFormatterMatchRanking.MatchOnRequestAcceptHeaderAllMediaRange);
MediaTypeFormatterMatch matchRequest10 = CreateMatch(1.0, MediaTypeFormatterMatchRanking.MatchOnRequestMediaType);
MediaTypeFormatterMatch matchType10 = CreateMatch(1.0, MediaTypeFormatterMatchRanking.MatchOnCanWriteType);
// ICollection<MediaTypeFormatterMatch> candidateMatches, MediaTypeFormatterMatch winner
return new TheoryData<ICollection<MediaTypeFormatterMatch>, MediaTypeFormatterMatch>
{
{ new List<MediaTypeFormatterMatch>(), null },
{ new List<MediaTypeFormatterMatch>() { matchType10 }, matchType10 },
{ new List<MediaTypeFormatterMatch>() { matchType10, matchRequest10 }, matchRequest10 },
{ new List<MediaTypeFormatterMatch>() { matchType10, matchRequest10, matchAcceptAllRange10 }, matchAcceptAllRange10 },
{ new List<MediaTypeFormatterMatch>() { matchType10, matchRequest10, matchAcceptAllRange10, matchAcceptSubTypeRange10 }, matchAcceptSubTypeRange10 },
{ new List<MediaTypeFormatterMatch>() { matchType10, matchRequest10, matchAcceptAllRange10, matchAcceptSubTypeRange10, matchAccept10 }, matchAccept10 },
{ new List<MediaTypeFormatterMatch>() { matchAccept05, matchAccept10 }, matchAccept10 },
{ new List<MediaTypeFormatterMatch>() { matchAccept10, matchAccept05 }, matchAccept10 },
{ new List<MediaTypeFormatterMatch>() { matchAcceptSubTypeRange05, matchAcceptSubTypeRange10 }, matchAcceptSubTypeRange10 },
{ new List<MediaTypeFormatterMatch>() { matchAcceptSubTypeRange10, matchAcceptSubTypeRange05 }, matchAcceptSubTypeRange10 },
{ new List<MediaTypeFormatterMatch>() { matchAcceptAllRange05, matchAcceptAllRange10 }, matchAcceptAllRange10 },
{ new List<MediaTypeFormatterMatch>() { matchAcceptAllRange10, matchAcceptAllRange05 }, matchAcceptAllRange10 },
};
}
}
public static TheoryData<MediaTypeFormatterMatch, MediaTypeFormatterMatch, bool> UpdateBestMatchData
{
get
{
MediaTypeFormatterMatch matchMapping10 = CreateMatch(1.0, MediaTypeFormatterMatchRanking.None);
MediaTypeFormatterMatch matchMapping05 = CreateMatch(0.5, MediaTypeFormatterMatchRanking.None);
// MediaTypeFormatterMatch current, MediaTypeFormatterMatch potentialReplacement, currentWins
return new TheoryData<MediaTypeFormatterMatch, MediaTypeFormatterMatch, bool>
{
{ null, matchMapping10, false },
{ null, matchMapping05, false },
{ matchMapping10, matchMapping10, true },
{ matchMapping10, matchMapping05, true },
{ matchMapping05, matchMapping10, false },
{ matchMapping05, matchMapping05, true },
};
}
}
private static MediaTypeFormatterMatch CreateMatch(double? quality, MediaTypeFormatterMatchRanking ranking)
{
MockMediaTypeFormatter formatter = new MockMediaTypeFormatter();
MediaTypeHeaderValue mediaType = new MediaTypeHeaderValue("text/test");
return new MediaTypeFormatterMatch(formatter, mediaType, quality, ranking);
}
[Fact]
public void TypeIsCorrect()
{
new TypeAssert().HasProperties(typeof(DefaultContentNegotiator), TypeAssert.TypeProperties.IsPublicVisibleClass);
}
[Fact]
public void Negotiate_ForEmptyFormatterCollection_ReturnsNull()
{
var result = _negotiator.Negotiate(typeof(string), _request, Enumerable.Empty<MediaTypeFormatter>());
Assert.Null(result);
}
[Fact]
public void Negotiate_ForRequestReturnsFirstMatchingFormatter()
{
MediaTypeHeaderValue mediaType = new MediaTypeHeaderValue("application/myMediaType");
MediaTypeFormatter formatter1 = new MockMediaTypeFormatter()
{
CanWriteTypeCallback = (Type t) => false
};
MediaTypeFormatter formatter2 = new MockMediaTypeFormatter()
{
CanWriteTypeCallback = (Type t) => true
};
formatter2.SupportedMediaTypes.Add(mediaType);
MediaTypeFormatterCollection collection = new MediaTypeFormatterCollection(
new MediaTypeFormatter[]
{
formatter1,
formatter2
});
_request.Content = new StringContent("test", Encoding.UTF8, mediaType.MediaType);
var result = _negotiator.Negotiate(typeof(string), _request, collection);
Assert.Same(formatter2, result.Formatter);
new MediaTypeAssert().AreEqual(mediaType, result.MediaType, "Expected the formatter's media type to be returned.");
}
[Fact]
public void Negotiate_SelectsJsonAsDefaultFormatter()
{
// Arrange
_request.Content = new StringContent("test");
// Act
var result = _negotiator.Negotiate(typeof(string), _request, new MediaTypeFormatterCollection());
// Assert
Assert.IsType<JsonMediaTypeFormatter>(result.Formatter);
Assert.Equal(MediaTypeConstants.ApplicationJsonMediaType.MediaType, result.MediaType.MediaType);
}
[Fact]
public void Negotiate_SelectsXmlFormatter_ForXhrRequestThatAcceptsXml()
{
// Arrange
_request.Content = new StringContent("test");
_request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
_request.Headers.Add("x-requested-with", "XMLHttpRequest");
// Act
var result = _negotiator.Negotiate(typeof(string), _request, new MediaTypeFormatterCollection());
// Assert
Assert.Equal("application/xml", result.MediaType.MediaType);
Assert.IsType<XmlMediaTypeFormatter>(result.Formatter);
}
[Fact]
public void Negotiate_SelectsJsonFormatter_ForXhrRequestThatDoesNotSpecifyAcceptHeaders()
{
// Arrange
_request.Content = new StringContent("test");
_request.Headers.Add("x-requested-with", "XMLHttpRequest");
// Act
var result = _negotiator.Negotiate(typeof(string), _request, new MediaTypeFormatterCollection());
// Assert
Assert.Equal("application/json", result.MediaType.MediaType);
Assert.IsType<JsonMediaTypeFormatter>(result.Formatter);
}
[Fact]
public void Negotiate_SelectsJsonFormatter_ForXHRAndJsonValueResponse()
{
// Arrange
_request.Content = new StringContent("test");
_request.Headers.Add("x-requested-with", "XMLHttpRequest");
// Act
// Mono issue - https://github.com/aspnet/External/issues/27
var type = TestPlatformHelper.IsMono ? typeof(string) : typeof(JToken);
var result = _negotiator.Negotiate(type, _request, new MediaTypeFormatterCollection());
Assert.Equal("application/json", result.MediaType.MediaType);
Assert.IsType<JsonMediaTypeFormatter>(result.Formatter);
}
[Fact]
public void Negotiate_SelectsJsonFormatter_ForXHRAndMatchAllAcceptHeader()
{
// Accept
_request.Content = new StringContent("test");
_request.Headers.Add("x-requested-with", "XMLHttpRequest");
_request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*"));
// Act
var result = _negotiator.Negotiate(typeof(string), _request, new MediaTypeFormatterCollection());
// Assert
Assert.Equal("application/json", result.MediaType.MediaType);
Assert.IsType<JsonMediaTypeFormatter>(result.Formatter);
}
[Fact]
public void Negotiate_UsesRequestedFormatterForXHRAndMatchAllPlusOtherAcceptHeader()
{
// Arrange
_request.Content = new StringContent("test");
_request.Headers.Add("x-requested-with", "XMLHttpRequest");
_request.Headers.Accept.ParseAdd("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"); // XHR header sent by Firefox 3b5
// Act
var result = _negotiator.Negotiate(typeof(string), _request, new MediaTypeFormatterCollection());
// Assert
Assert.Equal("application/xml", result.MediaType.MediaType);
Assert.IsType<XmlMediaTypeFormatter>(result.Formatter);
}
[Theory]
[InlineData(true)]
[InlineData(false)]
public void Negotiate_ObservesExcludeMatchOnTypeOnly(bool excludeMatchOnTypeOnly)
{
// Arrange
MockContentNegotiator negotiator = new MockContentNegotiator(excludeMatchOnTypeOnly);
_request.Content = new StringContent("test");
_request.Headers.Accept.ParseAdd("text/html");
// Act
var result = negotiator.Negotiate(typeof(string), _request, new MediaTypeFormatterCollection());
// Assert
if (excludeMatchOnTypeOnly)
{
Assert.Null(result);
}
else
{
Assert.NotNull(result);
Assert.Equal("application/json", result.MediaType.MediaType);
}
}
[Theory]
[MemberData(nameof(MatchAcceptHeaderData))]
public void MatchAcceptHeader_ReturnsMatch(string[] acceptHeaders, string[] supportedMediaTypes, string expectedMediaType, double expectedQuality, int ranking)
{
// Arrange
MockContentNegotiator negotiator = new MockContentNegotiator();
List<MediaTypeWithQualityHeaderValue> unsortedAcceptHeaders = acceptHeaders.Select(a => MediaTypeWithQualityHeaderValue.Parse(a)).ToList();
IEnumerable<MediaTypeWithQualityHeaderValue> sortedAcceptHeaders = negotiator.SortMediaTypeWithQualityHeaderValuesByQFactor(unsortedAcceptHeaders);
MockMediaTypeFormatter formatter = new MockMediaTypeFormatter();
foreach (string supportedMediaType in supportedMediaTypes)
{
formatter.SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse(supportedMediaType));
}
// Act
MediaTypeFormatterMatch match = negotiator.MatchAcceptHeader(sortedAcceptHeaders, formatter);
// Assert
if (expectedMediaType == null)
{
Assert.Null(match);
}
else
{
Assert.Same(formatter, match.Formatter);
Assert.Equal(MediaTypeHeaderValue.Parse(expectedMediaType), match.MediaType);
Assert.Equal(expectedQuality, match.Quality);
Assert.Equal(ranking, (int)match.Ranking);
}
}
[Theory]
[MemberData(nameof(MatchRequestMediaTypeData))]
public void MatchRequestMediaType_ReturnsMatch(string requestMediaType, string[] supportedMediaTypes, string expectedMediaType)
{
// Arrange
MockContentNegotiator negotiator = new MockContentNegotiator();
HttpRequestMessage request = new HttpRequestMessage();
request.Content = new StringContent(String.Empty);
request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse(requestMediaType);
MockMediaTypeFormatter formatter = new MockMediaTypeFormatter();
foreach (string supportedMediaType in supportedMediaTypes)
{
formatter.SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse(supportedMediaType));
}
// Act
MediaTypeFormatterMatch match = negotiator.MatchRequestMediaType(request, formatter);
// Assert
if (expectedMediaType == null)
{
Assert.Null(match);
}
else
{
Assert.Same(formatter, match.Formatter);
Assert.Equal(MediaTypeHeaderValue.Parse(expectedMediaType), match.MediaType);
Assert.Equal(1.0, match.Quality);
Assert.Equal(MediaTypeFormatterMatchRanking.MatchOnRequestMediaType, match.Ranking);
}
}
[Theory]
[MemberData(nameof(ShouldMatchOnTypeData))]
public void ShouldMatchOnType_ReturnsExpectedResult(bool excludeMatchOnType, string[] acceptHeaders, bool expectedResult)
{
// Arrange
MockContentNegotiator negotiator = new MockContentNegotiator(excludeMatchOnType);
List<MediaTypeWithQualityHeaderValue> unsortedAcceptHeaders = acceptHeaders.Select(a => MediaTypeWithQualityHeaderValue.Parse(a)).ToList();
IEnumerable<MediaTypeWithQualityHeaderValue> sortedAcceptHeaders = negotiator.SortMediaTypeWithQualityHeaderValuesByQFactor(unsortedAcceptHeaders);
// Act
bool result = negotiator.ShouldMatchOnType(sortedAcceptHeaders);
// Assert
Assert.Equal(expectedResult, result);
}
[Theory]
[MemberData(nameof(MatchTypeData))]
public void MatchType_ReturnsMatch(string[] supportedMediaTypes, string expectedMediaType)
{
// Arrange
MockContentNegotiator negotiator = new MockContentNegotiator();
MockMediaTypeFormatter formatter = new MockMediaTypeFormatter();
foreach (string supportedMediaType in supportedMediaTypes)
{
formatter.SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse(supportedMediaType));
}
// Act
MediaTypeFormatterMatch match = negotiator.MatchType(typeof(object), formatter);
// Assert
Assert.Same(formatter, match.Formatter);
Assert.Equal(MediaTypeHeaderValue.Parse(expectedMediaType), match.MediaType);
Assert.Equal(1.0, match.Quality);
Assert.Equal(MediaTypeFormatterMatchRanking.MatchOnCanWriteType, match.Ranking);
}
[Theory]
[MemberData(nameof(SelectResponseMediaTypeData))]
public void SelectResponseMediaTypeFormatter_SelectsMediaType(ICollection<MediaTypeFormatterMatch> matches, MediaTypeFormatterMatch expectedWinner)
{
// Arrange
MockContentNegotiator negotiator = new MockContentNegotiator();
// Act
MediaTypeFormatterMatch actualWinner = negotiator.SelectResponseMediaTypeFormatter(matches);
// Assert
Assert.Same(expectedWinner, actualWinner);
}
[Theory]
[MemberData(nameof(SelectResponseCharacterEncodingData))]
public void SelectResponseCharacterEncoding_SelectsEncoding(string[] acceptCharsetHeaders, string requestEncoding, string[] supportedEncodings, string expectedEncoding)
{
// Arrange
MockContentNegotiator negotiator = new MockContentNegotiator();
HttpRequestMessage request = new HttpRequestMessage();
foreach (string acceptCharsetHeader in acceptCharsetHeaders)
{
request.Headers.AcceptCharset.Add(StringWithQualityHeaderValue.Parse(acceptCharsetHeader));
}
if (requestEncoding != null)
{
Encoding reqEncoding = Encoding.GetEncoding(requestEncoding);
StringContent content = new StringContent("", reqEncoding, "text/plain");
request.Content = content;
}
MockMediaTypeFormatter formatter = new MockMediaTypeFormatter() { CallBase = true };
foreach (string supportedEncoding in supportedEncodings)
{
formatter.SupportedEncodings.Add(Encoding.GetEncoding(supportedEncoding));
}
// Act
Encoding actualEncoding = negotiator.SelectResponseCharacterEncoding(request, formatter);
// Assert
if (expectedEncoding == null)
{
Assert.Null(actualEncoding);
}
else
{
Assert.Equal(Encoding.GetEncoding(expectedEncoding), actualEncoding);
}
}
[Theory]
[TestDataSet(typeof(DefaultContentNegotiatorTests), nameof(MediaTypeWithQualityHeaderValueComparerTestsBeforeAfterSortedValues))]
public void SortMediaTypeWithQualityHeaderValuesByQFactor_SortsCorrectly(IEnumerable<string> unsorted, IEnumerable<string> expectedSorted)
{
// Arrange
MockContentNegotiator negotiator = new MockContentNegotiator();
List<MediaTypeWithQualityHeaderValue> unsortedValues =
new List<MediaTypeWithQualityHeaderValue>(unsorted.Select(u => MediaTypeWithQualityHeaderValue.Parse(u)));
List<MediaTypeWithQualityHeaderValue> expectedSortedValues =
new List<MediaTypeWithQualityHeaderValue>(expectedSorted.Select(u => MediaTypeWithQualityHeaderValue.Parse(u)));
// Act
IEnumerable<MediaTypeWithQualityHeaderValue> actualSorted = negotiator.SortMediaTypeWithQualityHeaderValuesByQFactor(unsortedValues);
// Assert
Assert.True(expectedSortedValues.SequenceEqual(actualSorted));
}
public static TheoryData<string[], string[]> MediaTypeWithQualityHeaderValueComparerTestsBeforeAfterSortedValues
{
get
{
return new TheoryData<string[], string[]>
{
{
new string[]
{
"application/*",
"text/plain",
"text/plain;q=1.0",
"text/plain",
"text/plain;q=0",
"*/*;q=0.8",
"*/*;q=1",
"text/*;q=1",
"text/plain;q=0.8",
"text/*;q=0.8",
"text/*;q=0.6",
"text/*;q=1.0",
"*/*;q=0.4",
"text/plain;q=0.6",
"text/xml",
},
new string[]
{
"text/plain",
"text/plain;q=1.0",
"text/plain",
"text/xml",
"application/*",
"text/*;q=1",
"text/*;q=1.0",
"*/*;q=1",
"text/plain;q=0.8",
"text/*;q=0.8",
"*/*;q=0.8",
"text/plain;q=0.6",
"text/*;q=0.6",
"*/*;q=0.4",
"text/plain;q=0",
}
}
};
}
}
[Theory]
[TestDataSet(typeof(DefaultContentNegotiatorTests), nameof(StringWithQualityHeaderValueComparerTestsBeforeAfterSortedValues))]
public void SortStringWithQualityHeaderValuesByQFactor_SortsCorrectly(IEnumerable<string> unsorted, IEnumerable<string> expectedSorted)
{
// Arrange
MockContentNegotiator negotiator = new MockContentNegotiator();
List<StringWithQualityHeaderValue> unsortedValues =
new List<StringWithQualityHeaderValue>(unsorted.Select(u => StringWithQualityHeaderValue.Parse(u)));
List<StringWithQualityHeaderValue> expectedSortedValues =
new List<StringWithQualityHeaderValue>(expectedSorted.Select(u => StringWithQualityHeaderValue.Parse(u)));
// Act
IEnumerable<StringWithQualityHeaderValue> actualSorted = negotiator.SortStringWithQualityHeaderValuesByQFactor(unsortedValues);
// Assert
Assert.True(expectedSortedValues.SequenceEqual(actualSorted));
}
public static TheoryData<string[], string[]> StringWithQualityHeaderValueComparerTestsBeforeAfterSortedValues
{
get
{
return new TheoryData<string[], string[]>
{
{
new string[]
{
"text",
"text;q=1.0",
"text",
"text;q=0",
"*;q=0.8",
"*;q=1",
"text;q=0.8",
"*;q=0.6",
"text;q=1.0",
"*;q=0.4",
"text;q=0.6",
},
new string[]
{
"text",
"text;q=1.0",
"text",
"text;q=1.0",
"*;q=1",
"text;q=0.8",
"*;q=0.8",
"text;q=0.6",
"*;q=0.6",
"*;q=0.4",
"text;q=0",
}
}
};
}
}
[Theory]
[MemberData(nameof(UpdateBestMatchData))]
public void UpdateBestMatch_SelectsCorrectly(MediaTypeFormatterMatch current, MediaTypeFormatterMatch replacement, bool currentWins)
{
// Arrange
MockContentNegotiator negotiator = new MockContentNegotiator();
// Act
MediaTypeFormatterMatch actualResult = negotiator.UpdateBestMatch(current, replacement);
// Assert
if (currentWins)
{
Assert.Same(current, actualResult);
}
else
{
Assert.Same(replacement, actualResult);
}
}
private class PlainTextFormatter : MediaTypeFormatter
{
public override bool CanReadType(Type type)
{
return true;
}
public override bool CanWriteType(Type type)
{
return true;
}
}
}
}