1 // Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
2 
3 using System.Collections.Generic;
4 using System.Collections.ObjectModel;
5 using System.Linq;
6 using System.Net.Http.Formatting.DataSets;
7 using System.Net.Http.Formatting.Mocks;
8 using System.Net.Http.Headers;
9 using System.Text;
10 using Microsoft.TestCommon;
11 using Moq;
12 using Xunit;
13 using Xunit.Extensions;
14 using Assert = Microsoft.TestCommon.AssertEx;
15 
16 namespace System.Net.Http.Formatting
17 {
18     public class MediaTypeFormatterTests
19     {
20         private const string TestMediaType = "text/test";
21 
22         [Fact]
23         [Trait("Description", "MediaTypeFormatter is public, abstract, and unsealed.")]
TypeIsCorrect()24         public void TypeIsCorrect()
25         {
26             Assert.Type.HasProperties(typeof(MediaTypeFormatter), TypeAssert.TypeProperties.IsPublicVisibleClass | TypeAssert.TypeProperties.IsAbstract);
27         }
28 
29         [Fact]
30         [Trait("Description", "MediaTypeFormatter() constructor (via derived class) sets SupportedMediaTypes and MediaTypeMappings.")]
Constructor()31         public void Constructor()
32         {
33             MockMediaTypeFormatter formatter = new MockMediaTypeFormatter();
34             Collection<MediaTypeHeaderValue> supportedMediaTypes = formatter.SupportedMediaTypes;
35             Assert.NotNull(supportedMediaTypes);
36             Assert.Equal(0, supportedMediaTypes.Count);
37 
38             Collection<MediaTypeMapping> mappings = formatter.MediaTypeMappings;
39             Assert.NotNull(mappings);
40             Assert.Equal(0, mappings.Count);
41         }
42 
43         [Fact]
MaxCollectionKeySize_RoundTrips()44         public void MaxCollectionKeySize_RoundTrips()
45         {
46             Assert.Reflection.IntegerProperty<MediaTypeFormatter, int>(
47                 null,
48                 c => MediaTypeFormatter.MaxHttpCollectionKeys,
49                 expectedDefaultValue: 1000,
50                 minLegalValue: 1,
51                 illegalLowerValue: 0,
52                 maxLegalValue: null,
53                 illegalUpperValue: null,
54                 roundTripTestValue: 125);
55         }
56 
57         [Fact]
58         [Trait("Description", "SupportedMediaTypes is a mutable collection.")]
SupportedMediaTypesIsMutable()59         public void SupportedMediaTypesIsMutable()
60         {
61             MockMediaTypeFormatter formatter = new MockMediaTypeFormatter();
62             Collection<MediaTypeHeaderValue> supportedMediaTypes = formatter.SupportedMediaTypes;
63             MediaTypeHeaderValue[] mediaTypes = HttpUnitTestDataSets.LegalMediaTypeHeaderValues.ToArray();
64             foreach (MediaTypeHeaderValue mediaType in mediaTypes)
65             {
66                 supportedMediaTypes.Add(mediaType);
67             }
68 
69             Assert.True(mediaTypes.SequenceEqual(formatter.SupportedMediaTypes));
70         }
71 
72         [Fact]
73         [Trait("Description", "SupportedMediaTypes Add throws with a null media type.")]
SupportedMediaTypesAddThrowsWithNullMediaType()74         public void SupportedMediaTypesAddThrowsWithNullMediaType()
75         {
76             MockMediaTypeFormatter formatter = new MockMediaTypeFormatter();
77             Collection<MediaTypeHeaderValue> supportedMediaTypes = formatter.SupportedMediaTypes;
78 
79             Assert.ThrowsArgumentNull(() => supportedMediaTypes.Add(null), "item");
80         }
81 
82         [Theory]
83         [TestDataSet(typeof(HttpUnitTestDataSets), "LegalMediaRangeValues")]
84         [Trait("Description", "SupportedMediaTypes Add throws with a media range.")]
SupportedMediaTypesAddThrowsWithMediaRange(MediaTypeHeaderValue mediaType)85         public void SupportedMediaTypesAddThrowsWithMediaRange(MediaTypeHeaderValue mediaType)
86         {
87             MockMediaTypeFormatter formatter = new MockMediaTypeFormatter();
88             Collection<MediaTypeHeaderValue> supportedMediaTypes = formatter.SupportedMediaTypes;
89             Assert.ThrowsArgument(() => supportedMediaTypes.Add(mediaType), "item", RS.Format(Properties.Resources.CannotUseMediaRangeForSupportedMediaType, typeof(MediaTypeHeaderValue).Name, mediaType.MediaType));
90         }
91 
92         [Fact]
93         [Trait("Description", "SupportedMediaTypes Insert throws with a null media type.")]
SupportedMediaTypesInsertThrowsWithNullMediaType()94         public void SupportedMediaTypesInsertThrowsWithNullMediaType()
95         {
96             MockMediaTypeFormatter formatter = new MockMediaTypeFormatter();
97             Collection<MediaTypeHeaderValue> supportedMediaTypes = formatter.SupportedMediaTypes;
98 
99             Assert.ThrowsArgumentNull(() => supportedMediaTypes.Insert(0, null), "item");
100         }
101 
102         [Theory]
103         [TestDataSet(typeof(HttpUnitTestDataSets), "LegalMediaRangeValues")]
104         [Trait("Description", "SupportedMediaTypes Insert throws with a media range.")]
SupportedMediaTypesInsertThrowsWithMediaRange(MediaTypeHeaderValue mediaType)105         public void SupportedMediaTypesInsertThrowsWithMediaRange(MediaTypeHeaderValue mediaType)
106         {
107             MockMediaTypeFormatter formatter = new MockMediaTypeFormatter();
108             Collection<MediaTypeHeaderValue> supportedMediaTypes = formatter.SupportedMediaTypes;
109 
110             Assert.ThrowsArgument(() => supportedMediaTypes.Insert(0, mediaType), "item", RS.Format(Properties.Resources.CannotUseMediaRangeForSupportedMediaType, typeof(MediaTypeHeaderValue).Name, mediaType.MediaType));
111         }
112 
113         [Fact]
114         [Trait("Description", "MediaTypeMappings is a mutable collection.")]
MediaTypeMappingsIsMutable()115         public void MediaTypeMappingsIsMutable()
116         {
117             MockMediaTypeFormatter formatter = new MockMediaTypeFormatter();
118             Collection<MediaTypeMapping> mappings = formatter.MediaTypeMappings;
119             MediaTypeMapping[] standardMappings = HttpUnitTestDataSets.StandardMediaTypeMappings.ToArray();
120             foreach (MediaTypeMapping mapping in standardMappings)
121             {
122                 mappings.Add(mapping);
123             }
124 
125             Assert.True(standardMappings.SequenceEqual(formatter.MediaTypeMappings));
126         }
127 
128         [Theory]
129         [TestDataSet(typeof(HttpUnitTestDataSets), "StandardMediaTypesWithQuality")]
130         [Trait("Description", "TryMatchSupportedMediaType(MediaTypeHeaderValue, out MediaTypeMatch) returns media type and quality.")]
TryMatchSupportedMediaTypeWithQuality(MediaTypeWithQualityHeaderValue mediaTypeWithQuality)131         public void TryMatchSupportedMediaTypeWithQuality(MediaTypeWithQualityHeaderValue mediaTypeWithQuality)
132         {
133             MockMediaTypeFormatter formatter = new MockMediaTypeFormatter();
134             MediaTypeHeaderValue mediaTypeWithoutQuality = new MediaTypeHeaderValue(mediaTypeWithQuality.MediaType);
135             formatter.SupportedMediaTypes.Add(mediaTypeWithoutQuality);
136             MediaTypeMatch match;
137             bool result = formatter.TryMatchSupportedMediaType(mediaTypeWithQuality, out match);
138             Assert.True(result, String.Format("TryMatchSupportedMediaType should have succeeded for '{0}'.", mediaTypeWithQuality));
139             Assert.NotNull(match);
140             double quality = mediaTypeWithQuality.Quality.Value;
141             Assert.Equal(quality, match.Quality);
142             Assert.NotNull(match.MediaType);
143             Assert.Equal(mediaTypeWithoutQuality.MediaType, match.MediaType.MediaType);
144         }
145 
146         [Theory]
147         [TestDataSet(typeof(HttpUnitTestDataSets), "StandardMediaTypesWithQuality")]
148         [Trait("Description", "TryMatchSupportedMediaType(MediaTypeHeaderValue, out MediaTypeMatch) returns cloned media type, not original.")]
TryMatchSupportedMediaTypeReturnsClone(MediaTypeWithQualityHeaderValue mediaTypeWithQuality)149         public void TryMatchSupportedMediaTypeReturnsClone(MediaTypeWithQualityHeaderValue mediaTypeWithQuality)
150         {
151             MockMediaTypeFormatter formatter = new MockMediaTypeFormatter();
152             MediaTypeHeaderValue mediaTypeWithoutQuality = new MediaTypeHeaderValue(mediaTypeWithQuality.MediaType);
153             formatter.SupportedMediaTypes.Add(mediaTypeWithoutQuality);
154             MediaTypeMatch match;
155             bool result = formatter.TryMatchSupportedMediaType(mediaTypeWithQuality, out match);
156 
157             Assert.True(result);
158             Assert.NotNull(match);
159             Assert.NotNull(match.MediaType);
160             Assert.NotSame(mediaTypeWithoutQuality, match.MediaType);
161         }
162 
163         [Theory]
164         [TestDataSet(typeof(HttpUnitTestDataSets), "MediaRangeValuesWithQuality")]
165         [Trait("Description", "TryMatchMediaTypeMapping(HttpRequestMessage, out MediaTypeMatch) returns media type and quality from media range with quality.")]
TryMatchMediaTypeMappingWithQuality(MediaTypeWithQualityHeaderValue mediaRangeWithQuality)166         public void TryMatchMediaTypeMappingWithQuality(MediaTypeWithQualityHeaderValue mediaRangeWithQuality)
167         {
168             MockMediaTypeFormatter formatter = new MockMediaTypeFormatter();
169             MediaTypeHeaderValue mediaRangeWithoutQuality = new MediaTypeHeaderValue(mediaRangeWithQuality.MediaType);
170             MediaTypeHeaderValue mediaType = new MediaTypeHeaderValue("application/xml");
171             MediaRangeMapping mapping = new MediaRangeMapping(mediaRangeWithoutQuality, mediaType);
172             formatter.MediaTypeMappings.Add(mapping);
173 
174             HttpRequestMessage request = new HttpRequestMessage();
175             request.Headers.Accept.Add(mediaRangeWithQuality);
176             MediaTypeMatch match;
177             bool result = formatter.TryMatchMediaTypeMapping(request, out match);
178             Assert.True(result, String.Format("TryMatchMediaTypeMapping should have succeeded for '{0}'.", mediaRangeWithQuality));
179             Assert.NotNull(match);
180             double quality = mediaRangeWithQuality.Quality.Value;
181             Assert.Equal(quality, match.Quality);
182             Assert.NotNull(match.MediaType);
183             Assert.Equal(mediaType.MediaType, match.MediaType.MediaType);
184         }
185 
186         [Theory]
187         [TestDataSet(typeof(HttpUnitTestDataSets), "MediaRangeValuesWithQuality")]
188         [Trait("Description", "TryMatchMediaTypeMapping(HttpRequestMessage, out MediaTypeMatch) returns a clone of the original media type.")]
TryMatchMediaTypeMappingClonesMediaType(MediaTypeWithQualityHeaderValue mediaRangeWithQuality)189         public void TryMatchMediaTypeMappingClonesMediaType(MediaTypeWithQualityHeaderValue mediaRangeWithQuality)
190         {
191             MockMediaTypeFormatter formatter = new MockMediaTypeFormatter();
192             MediaTypeHeaderValue mediaRangeWithoutQuality = new MediaTypeHeaderValue(mediaRangeWithQuality.MediaType);
193             MediaTypeHeaderValue mediaType = new MediaTypeHeaderValue("application/xml");
194             MediaRangeMapping mapping = new MediaRangeMapping(mediaRangeWithoutQuality, mediaType);
195             formatter.MediaTypeMappings.Add(mapping);
196 
197             HttpRequestMessage request = new HttpRequestMessage();
198             request.Headers.Accept.Add(mediaRangeWithQuality);
199             MediaTypeMatch match;
200             formatter.TryMatchMediaTypeMapping(request, out match);
201             Assert.NotNull(match);
202             Assert.NotNull(match.MediaType);
203             Assert.NotSame(mediaType, match.MediaType);
204         }
205 
206         [Fact]
207         [Trait("Description", "SelectResponseMediaType(Type, HttpRequestMessage) matches based only on type.")]
SelectResponseMediaTypeMatchesType()208         public void SelectResponseMediaTypeMatchesType()
209         {
210             MockMediaTypeFormatter formatter = new MockMediaTypeFormatter() { CallBase = true };
211             HttpRequestMessage request = new HttpRequestMessage();
212             ResponseMediaTypeMatch match = formatter.SelectResponseMediaType(typeof(string), request);
213 
214             Assert.NotNull(match);
215             Assert.Equal(ResponseFormatterSelectionResult.MatchOnCanWriteType, match.ResponseFormatterSelectionResult);
216             Assert.Null(match.MediaTypeMatch.MediaType);
217         }
218 
219         [Theory]
220         [TestDataSet(typeof(HttpUnitTestDataSets), "LegalMediaTypeHeaderValues")]
221         [Trait("Description", "SelectResponseMediaType(Type, HttpRequestMessage) matches media type from request content type.")]
SelectResponseMediaTypeMatchesRequestContentType(MediaTypeHeaderValue mediaType)222         public void SelectResponseMediaTypeMatchesRequestContentType(MediaTypeHeaderValue mediaType)
223         {
224             MockMediaTypeFormatter formatter = new MockMediaTypeFormatter() { CallBase = true };
225             formatter.SupportedMediaTypes.Add(mediaType);
226             HttpRequestMessage request = new HttpRequestMessage() { Content = new StringContent("fred") };
227             request.Content.Headers.ContentType = mediaType;
228             HttpResponseMessage response = new HttpResponseMessage() { RequestMessage = request };
229             ResponseMediaTypeMatch match = formatter.SelectResponseMediaType(typeof(string), request);
230 
231             Assert.NotNull(match);
232             Assert.Equal(ResponseFormatterSelectionResult.MatchOnRequestContentType, match.ResponseFormatterSelectionResult);
233             Assert.NotNull(match.MediaTypeMatch.MediaType);
234             Assert.Equal(mediaType.MediaType, match.MediaTypeMatch.MediaType.MediaType);
235         }
236 
237         [TestDataSet(typeof(HttpUnitTestDataSets), "LegalMediaTypeHeaderValues")]
238         [Trait("Description", "SelectResponseMediaType(Type, HttpRequestMessage) matches media type from response content type.")]
SelectResponseMediaTypeMatchesResponseContentType(MediaTypeHeaderValue mediaType)239         public void SelectResponseMediaTypeMatchesResponseContentType(MediaTypeHeaderValue mediaType)
240         {
241             MockMediaTypeFormatter formatter = new MockMediaTypeFormatter() { CallBase = true };
242             formatter.SupportedMediaTypes.Add(mediaType);
243             HttpRequestMessage request = new HttpRequestMessage();
244             HttpResponseMessage response = new HttpResponseMessage() { RequestMessage = request, Content = new StringContent("fred") };
245             response.Content.Headers.ContentType = mediaType;
246             ResponseMediaTypeMatch match = formatter.SelectResponseMediaType(typeof(string), request);
247 
248             Assert.NotNull(match);
249             Assert.Equal(ResponseFormatterSelectionResult.MatchOnResponseContentType, match.ResponseFormatterSelectionResult);
250             Assert.NotNull(match.MediaTypeMatch.MediaType);
251             Assert.Equal(mediaType.MediaType, match.MediaTypeMatch.MediaType.MediaType);
252         }
253 
254         [Theory]
255         [TestDataSet(typeof(HttpUnitTestDataSets), "StandardMediaTypesWithQuality")]
256         [Trait("Description", "SelectResponseMediaType(Type, HttpRequestMessage) matches supported media type from accept headers.")]
SelectResponseMediaTypeMatchesAcceptHeaderToSupportedMediaTypes(MediaTypeWithQualityHeaderValue mediaTypeWithQuality)257         public void SelectResponseMediaTypeMatchesAcceptHeaderToSupportedMediaTypes(MediaTypeWithQualityHeaderValue mediaTypeWithQuality)
258         {
259             MockMediaTypeFormatter formatter = new MockMediaTypeFormatter() { CallBase = true };
260             MediaTypeHeaderValue mediaTypeWithoutQuality = new MediaTypeHeaderValue(mediaTypeWithQuality.MediaType);
261             formatter.SupportedMediaTypes.Add(mediaTypeWithoutQuality);
262 
263             HttpRequestMessage request = new HttpRequestMessage();
264             request.Headers.Accept.Add(mediaTypeWithQuality);
265             ResponseMediaTypeMatch match = formatter.SelectResponseMediaType(typeof(string), request);
266 
267             Assert.NotNull(match);
268             Assert.Equal(ResponseFormatterSelectionResult.MatchOnRequestAcceptHeader, match.ResponseFormatterSelectionResult);
269             double quality = mediaTypeWithQuality.Quality.Value;
270             Assert.Equal(quality, match.MediaTypeMatch.Quality);
271             Assert.NotNull(match.MediaTypeMatch.MediaType);
272             Assert.Equal(mediaTypeWithoutQuality.MediaType, match.MediaTypeMatch.MediaType.MediaType);
273         }
274 
275         [TestDataSet(typeof(HttpUnitTestDataSets), "MediaRangeValuesWithQuality")]
276         [Trait("Description", "SelectResponseMediaType(Type, HttpRequestMessage) matches media type with quality from media type mapping.")]
SelectResponseMediaTypeMatchesWithMediaTypeMapping(MediaTypeWithQualityHeaderValue mediaRangeWithQuality)277         public void SelectResponseMediaTypeMatchesWithMediaTypeMapping(MediaTypeWithQualityHeaderValue mediaRangeWithQuality)
278         {
279             MockMediaTypeFormatter formatter = new MockMediaTypeFormatter() { CallBase = true };
280             MediaTypeHeaderValue mediaRangeWithoutQuality = new MediaTypeHeaderValue(mediaRangeWithQuality.MediaType);
281             MediaTypeHeaderValue mediaType = new MediaTypeHeaderValue("application/xml");
282             MediaRangeMapping mapping = new MediaRangeMapping(mediaRangeWithoutQuality, mediaType);
283             formatter.MediaTypeMappings.Add(mapping);
284 
285             HttpRequestMessage request = new HttpRequestMessage();
286             request.Headers.Accept.Add(mediaRangeWithQuality);
287             ResponseMediaTypeMatch match = formatter.SelectResponseMediaType(typeof(string), request);
288 
289             Assert.NotNull(match);
290             Assert.Equal(ResponseFormatterSelectionResult.MatchOnRequestWithMediaTypeMapping, match.ResponseFormatterSelectionResult);
291             double quality = mediaRangeWithQuality.Quality.Value;
292             Assert.Equal(quality, match.MediaTypeMatch.Quality);
293             Assert.NotNull(match.MediaTypeMatch.MediaType);
294             Assert.Equal(mediaType.MediaType, match.MediaTypeMatch.MediaType.MediaType);
295         }
296 
297         public static IEnumerable<object[]> SelectCharacterEncodingTestData
298         {
299             get
300             {
301                 yield return new object[]
302                 {
303                     null,
304                     new[] { "utf-8", "utf-16"},
305                     "utf-8"
306                 };
307                 yield return new object[]
308                 {
309                     null,
310                     new[] { "utf-16", "utf-8"},
311                     "utf-16"
312                 };
313                 yield return new object[]
314                 {
315                     "utf-32",
316                     new[] { "utf-8", "utf-16"},
317                     "utf-8"
318                 };
319                 yield return new object[]
320                 {
321                     "utf-32",
322                     new[] { "utf-8", "utf-16", "utf-32"},
323                     "utf-32"
324                 };
325             }
326         }
327 
328         public static IEnumerable<object[]> SelectResponseCharacterEncodingTestData
329         {
330             get
331             {
332                 yield return new object[]
333                 {
334                     new[] { "*;q=0.5", "utf-8;q=0.8", "utf-16;q=0.7" },
335                     null,
336                     new[] { "utf-16", "utf-8"},
337                     "utf-8"
338                 };
339                 yield return new object[]
340                 {
341                     new[] { "*;q=0.5", "utf-8;q=0.8", "utf-16;q=0.9" },
342                     null,
343                     new[] { "utf-8", "utf-16"},
344                     "utf-16"
345                 };
346                 yield return new object[]
347                 {
348                     new[] { "*;q=0.9", "utf-8;q=0.5", "utf-16;q=0.5" },
349                     null,
350                     new[] { "utf-8", "utf-16"},
351                     "utf-8"
352                 };
353                 yield return new object[]
354                 {
355                     new string[] { },
356                     "utf-16",
357                     new[] { "utf-8", "utf-16"},
358                     "utf-16"
359                 };
360                 yield return new object[]
361                 {
362                     new[] { "*;q=0.5" },
363                     "utf-16",
364                     new[] { "utf-8", "utf-16"},
365                     "utf-8"
366                 };
367                 yield return new object[]
368                 {
369                     new[] { "*;q=0.5", "utf-16;q=0.7", "utf-8;q=0.8" },
370                     "utf-16",
371                     new[] { "utf-8", "utf-16"},
372                     "utf-8"
373                 };
374             }
375         }
376 
377         [Fact]
SelectCharacterEncoding_ThrowsIfNoSupportedEncodings()378         public void SelectCharacterEncoding_ThrowsIfNoSupportedEncodings()
379         {
380             // Arrange
381             MockMediaTypeFormatter formatter = new MockMediaTypeFormatter { CallBase = true };
382             HttpContent content = new StringContent("Hello World", Encoding.UTF8, "text/plain");
383 
384             // Act
385             Assert.Throws<InvalidOperationException>(() => formatter.SelectCharacterEncoding(content.Headers));
386         }
387 
388         [Theory]
389         [PropertyData("SelectCharacterEncodingTestData")]
SelectCharacterEncoding_ReturnsBestEncoding(string bodyEncoding, string[] supportedEncodings, string expectedEncoding)390         public void SelectCharacterEncoding_ReturnsBestEncoding(string bodyEncoding, string[] supportedEncodings, string expectedEncoding)
391         {
392             // Arrange
393             MockMediaTypeFormatter formatter = new MockMediaTypeFormatter { CallBase = true };
394 
395             foreach (string supportedEncoding in supportedEncodings)
396             {
397                 formatter.SupportedEncodings.Add(Encoding.GetEncoding(supportedEncoding));
398             }
399 
400             HttpContentHeaders contentHeaders = null;
401             if (bodyEncoding != null)
402             {
403                 Encoding bodyEnc = Encoding.GetEncoding(bodyEncoding);
404                 HttpContent content = new StringContent("Hello World", bodyEnc, "text/plain");
405                 contentHeaders = content.Headers;
406             }
407 
408             // Act
409             Encoding actualEncoding = formatter.SelectCharacterEncoding(contentHeaders);
410 
411             // Assert
412             Encoding expectedEnc = expectedEncoding != null ? Encoding.GetEncoding(expectedEncoding) : null;
413             Assert.Equal(expectedEnc, actualEncoding);
414         }
415 
416         [Theory]
417         [PropertyData("SelectResponseCharacterEncodingTestData")]
SelectResponseCharacterEncoding_ReturnsBestEncodingBasedOnAcceptCharsetMatch(string[] acceptCharsetValues, string bodyEncoding, string[] supportedEncodings, string expectedEncoding)418         public void SelectResponseCharacterEncoding_ReturnsBestEncodingBasedOnAcceptCharsetMatch(string[] acceptCharsetValues, string bodyEncoding, string[] supportedEncodings, string expectedEncoding)
419         {
420             // Arrange
421             MockMediaTypeFormatter formatter = new MockMediaTypeFormatter() { CallBase = true };
422             HttpRequestMessage request = new HttpRequestMessage();
423             foreach (var acceptCharsetValue in acceptCharsetValues)
424             {
425                 request.Headers.AcceptCharset.Add(StringWithQualityHeaderValue.Parse(acceptCharsetValue));
426             }
427 
428             foreach (var supportedEncoding in supportedEncodings)
429             {
430                 Encoding supportedEnc = Encoding.GetEncoding(supportedEncoding);
431                 formatter.SupportedEncodings.Add(supportedEnc);
432             }
433 
434             if (bodyEncoding != null)
435             {
436                 Encoding bodyEnc = Encoding.GetEncoding(bodyEncoding);
437                 request.Method = HttpMethod.Post;
438                 request.Content = new StringContent("Hello World", bodyEnc, "text/plain");
439             }
440 
441             // Act
442             Encoding actualEncoding = formatter.SelectResponseCharacterEncoding(request);
443 
444             // Assert
445             Encoding expectedEnc = expectedEncoding != null ? Encoding.GetEncoding(expectedEncoding) : null;
446             Assert.Equal(expectedEnc, actualEncoding);
447         }
448 
449         [Theory]
450         [TestDataSet(
451             typeof(CommonUnitTestDataSets), "RepresentativeValueAndRefTypeTestDataCollection",
452             typeof(HttpUnitTestDataSets), "LegalMediaTypeStrings")]
453         [Trait("Description", "CanReadAs(Type, MediaTypeHeaderValue) returns true for all standard media types.")]
CanReadAsReturnsTrue(Type variationType, object testData, string mediaType)454         public void CanReadAsReturnsTrue(Type variationType, object testData, string mediaType)
455         {
456             MockMediaTypeFormatter formatter = new MockMediaTypeFormatter() { CallBase = true };
457             string[] legalMediaTypeStrings = HttpUnitTestDataSets.LegalMediaTypeStrings.ToArray();
458             foreach (string legalMediaType in legalMediaTypeStrings)
459             {
460                 formatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue(legalMediaType));
461             }
462 
463             MediaTypeHeaderValue contentType = new MediaTypeHeaderValue(mediaType);
464             Assert.True(formatter.CanReadAs(variationType, contentType));
465         }
466 
467         [Fact]
468         [Trait("Description", "CanReadAs(Type, MediaTypeHeaderValue) throws with null type.")]
CanReadAsThrowsWithNullType()469         public void CanReadAsThrowsWithNullType()
470         {
471             MockMediaTypeFormatter formatter = new MockMediaTypeFormatter();
472             Assert.ThrowsArgumentNull(() => formatter.CanReadAs(type: null, mediaType: null), "type");
473         }
474 
475         [Fact]
476         [Trait("Description", "CanReadAs(Type, MediaTypeHeaderValue) throws with null formatter context.")]
CanReadAsThrowsWithNullMediaType()477         public void CanReadAsThrowsWithNullMediaType()
478         {
479             MockMediaTypeFormatter formatter = new MockMediaTypeFormatter();
480             Assert.ThrowsArgumentNull(() => formatter.CanReadAs(typeof(int), mediaType: null), "mediaType");
481         }
482 
483         [Theory]
484         [TestDataSet(typeof(CommonUnitTestDataSets), "RepresentativeValueAndRefTypeTestDataCollection")]
485         [Trait("Description", "CanWriteAs(Type, MediaTypeHeaderValue, out MediaTypeHeaderValue) returns true always for supported media types.")]
CanWriteAsReturnsTrue(Type variationType, object testData)486         public void CanWriteAsReturnsTrue(Type variationType, object testData)
487         {
488             MockMediaTypeFormatter formatter = new MockMediaTypeFormatter() { CallBase = true };
489             foreach (string mediaType in HttpUnitTestDataSets.LegalMediaTypeStrings)
490             {
491                 formatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue(mediaType));
492             }
493 
494             MediaTypeHeaderValue matchedMediaType = null;
495             Assert.True(formatter.CanWriteAs(variationType, formatter.SupportedMediaTypes[0], out matchedMediaType));
496         }
497 
498         [Fact]
499         [Trait("Description", "CanWriteAs(Type, MediaTypeHeaderValue, out MediaTypeHeaderValue) throws with null content.")]
CanWriteAsThrowsWithNullContent()500         public void CanWriteAsThrowsWithNullContent()
501         {
502             MockMediaTypeFormatter formatter = new MockMediaTypeFormatter();
503             MediaTypeHeaderValue mediaType = null;
504             Assert.ThrowsArgumentNull(() => formatter.CanWriteAs(typeof(int), null, out mediaType), "mediaType");
505         }
506 
507         [Theory]
508         [TestDataSet(typeof(CommonUnitTestDataSets), "RepresentativeValueAndRefTypeTestDataCollection")]
509         [Trait("Description", "CanWriteAs(Type, MediaTypeHeaderValue, out MediaTypeHeaderValue) returns true always for supported media types.")]
CanWriteAsUsingRequestReturnsTrue(Type variationType, object testData)510         public void CanWriteAsUsingRequestReturnsTrue(Type variationType, object testData)
511         {
512             MockMediaTypeFormatter formatter = new MockMediaTypeFormatter() { CallBase = true };
513             foreach (string mediaType in HttpUnitTestDataSets.LegalMediaTypeStrings)
514             {
515                 formatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue(mediaType));
516             }
517 
518             MediaTypeHeaderValue matchedMediaType = null;
519             Assert.True(formatter.CanWriteAs(variationType, formatter.SupportedMediaTypes[0], out matchedMediaType));
520         }
521 
522         [Theory]
523         [TestDataSet(
524             typeof(CommonUnitTestDataSets), "RepresentativeValueAndRefTypeTestDataCollection",
525             typeof(HttpUnitTestDataSets), "LegalMediaTypeStrings")]
526         [Trait("Description", "CanReadType(Type) base implementation returns true for all types.")]
CanReadTypeReturnsTrue(Type variationType, object testData, string mediaType)527         public void CanReadTypeReturnsTrue(Type variationType, object testData, string mediaType)
528         {
529             MockMediaTypeFormatter formatter = new MockMediaTypeFormatter() { CallBase = true };
530             string[] legalMediaTypeStrings = HttpUnitTestDataSets.LegalMediaTypeStrings.ToArray();
531             foreach (string mediaTypeTmp in legalMediaTypeStrings)
532             {
533                 formatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue(mediaTypeTmp));
534             }
535 
536             // Invoke CanReadAs because it invokes CanReadType
537             Assert.True(formatter.CanReadAs(variationType, new MediaTypeHeaderValue(mediaType)));
538         }
539 
540         [Theory]
541         [TestDataSet(typeof(CommonUnitTestDataSets), "RepresentativeValueAndRefTypeTestDataCollection")]
542         [Trait("Description", "CanWriteType() base implementation returns true always.")]
CanWriteTypeReturnsTrue(Type variationType, object testData)543         public void CanWriteTypeReturnsTrue(Type variationType, object testData)
544         {
545             MockMediaTypeFormatter formatter = new MockMediaTypeFormatter() { CallBase = true };
546             foreach (string mediaType in HttpUnitTestDataSets.LegalMediaTypeStrings)
547             {
548                 formatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue(mediaType));
549             }
550 
551             MediaTypeHeaderValue matchedMediaType = null;
552             Assert.True(formatter.CanWriteAs(variationType, formatter.SupportedMediaTypes[0], out matchedMediaType));
553         }
554 
555         [Fact]
ReadFromStreamAsync_ThrowsNotSupportedException()556         public void ReadFromStreamAsync_ThrowsNotSupportedException()
557         {
558             var formatter = new Mock<MediaTypeFormatter> { CallBase = true }.Object;
559 
560             Assert.Throws<NotSupportedException>(() => formatter.ReadFromStreamAsync(null, null, null, null),
561                 "The media type formatter of type 'MediaTypeFormatterProxy' does not support reading because it does not implement the ReadFromStreamAsync method.");
562         }
563 
564         [Fact]
WriteToStreamAsync_ThrowsNotSupportedException()565         public void WriteToStreamAsync_ThrowsNotSupportedException()
566         {
567             var formatter = new Mock<MediaTypeFormatter> { CallBase = true }.Object;
568 
569             Assert.Throws<NotSupportedException>(() => formatter.WriteToStreamAsync(null, null, null, null, null),
570                 "The media type formatter of type 'MediaTypeFormatterProxy' does not support writing because it does not implement the WriteToStreamAsync method.");
571         }
572 
573         [Theory]
574         [InlineData(typeof(object))]
575         [InlineData(typeof(string))]
576         [InlineData(typeof(Nullable<int>))]
GetDefaultValueForType_ReturnsNullForReferenceTypes(Type referenceType)577         public void GetDefaultValueForType_ReturnsNullForReferenceTypes(Type referenceType)
578         {
579             Assert.Null(MediaTypeFormatter.GetDefaultValueForType(referenceType));
580         }
581 
582         [Theory]
583         [InlineData(false)]
584         [InlineData(0)]
585         [InlineData('a')]
GetDefaultValueForType_ReturnsValueForValueTypes(T value)586         public void GetDefaultValueForType_ReturnsValueForValueTypes<T>(T value)
587         {
588             Type valueType = value.GetType();
589             T defaultValue = default(T);
590             Assert.Equal(defaultValue, MediaTypeFormatter.GetDefaultValueForType(valueType));
591         }
592 
593         [Fact]
GetDefaultValueForType_ReturnsValueForStruct()594         public void GetDefaultValueForType_ReturnsValueForStruct()
595         {
596             TestStruct s = new TestStruct();
597 
598             TestStruct result = (TestStruct)MediaTypeFormatter.GetDefaultValueForType(typeof(TestStruct));
599 
600             Assert.Equal(s, result);
601         }
602 
603         [Fact]
SetDefaultContentHeaders_ThrowsOnNullType()604         public void SetDefaultContentHeaders_ThrowsOnNullType()
605         {
606             MockMediaTypeFormatter formatter = new MockMediaTypeFormatter();
607             HttpContentHeaders contentHeaders = FormattingUtilities.CreateEmptyContentHeaders();
608             Assert.ThrowsArgumentNull(() => formatter.SetDefaultContentHeaders(null, contentHeaders, TestMediaType), "type");
609         }
610 
611         [Fact]
SetDefaultContentHeaders_ThrowsOnNullHeaders()612         public void SetDefaultContentHeaders_ThrowsOnNullHeaders()
613         {
614             MockMediaTypeFormatter formatter = new MockMediaTypeFormatter();
615             Type type = typeof(object);
616             Assert.ThrowsArgumentNull(() => formatter.SetDefaultContentHeaders(type, null, TestMediaType), "headers");
617         }
618 
619         [Fact]
SetDefaultContentHeaders_UsesNonNullMediaType()620         public void SetDefaultContentHeaders_UsesNonNullMediaType()
621         {
622             // Arrange
623             MockMediaTypeFormatter formatter = new MockMediaTypeFormatter();
624             Type type = typeof(object);
625             HttpContentHeaders contentHeaders = FormattingUtilities.CreateEmptyContentHeaders();
626 
627             // Act
628             formatter.SetDefaultContentHeaders(type, contentHeaders, TestMediaType);
629 
630             // Assert
631             Assert.Equal(TestMediaType, contentHeaders.ContentType.MediaType);
632         }
633 
634         [Fact]
SetDefaultContentHeaders_UsesDefaultSupportedMediaType()635         public void SetDefaultContentHeaders_UsesDefaultSupportedMediaType()
636         {
637             // Arrange
638             MockMediaTypeFormatter formatter = new MockMediaTypeFormatter();
639             formatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue(TestMediaType));
640             Type type = typeof(object);
641             HttpContentHeaders contentHeaders = FormattingUtilities.CreateEmptyContentHeaders();
642 
643             // Act
644             formatter.SetDefaultContentHeaders(type, contentHeaders, null);
645 
646             // Assert
647             Assert.Equal(TestMediaType, contentHeaders.ContentType.MediaType);
648         }
649 
650         [Fact]
SetDefaultContentHeaders_UsesDefaultSupportedEncoding()651         public void SetDefaultContentHeaders_UsesDefaultSupportedEncoding()
652         {
653             // Arrange
654             MockMediaTypeFormatter formatter = new MockMediaTypeFormatter();
655             Encoding encoding = new UnicodeEncoding();
656             formatter.SupportedEncodings.Add(encoding);
657             Type type = typeof(object);
658             HttpContentHeaders contentHeaders = FormattingUtilities.CreateEmptyContentHeaders();
659 
660             // Act
661             formatter.SetDefaultContentHeaders(type, contentHeaders, TestMediaType);
662 
663             // Assert
664             Assert.Equal(TestMediaType, contentHeaders.ContentType.MediaType);
665             Assert.Equal(encoding.WebName, contentHeaders.ContentType.CharSet);
666         }
667 
668         [Fact]
SetDefaultContentHeaders_UsesDefaultSupportedMediaTypeAndEncoding()669         public void SetDefaultContentHeaders_UsesDefaultSupportedMediaTypeAndEncoding()
670         {
671             // Arrange
672             MockMediaTypeFormatter formatter = new MockMediaTypeFormatter();
673             formatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue(TestMediaType));
674             Encoding encoding = new UnicodeEncoding();
675             formatter.SupportedEncodings.Add(encoding);
676             Type type = typeof(object);
677             HttpContentHeaders contentHeaders = FormattingUtilities.CreateEmptyContentHeaders();
678 
679             // Act
680             formatter.SetDefaultContentHeaders(type, contentHeaders, null);
681 
682             // Assert
683             Assert.Equal(TestMediaType, contentHeaders.ContentType.MediaType);
684             Assert.Equal(encoding.WebName, contentHeaders.ContentType.CharSet);
685         }
686 
687         public struct TestStruct
688         {
689             private int I;
TestStructSystem.Net.Http.Formatting.MediaTypeFormatterTests.TestStruct690             public TestStruct(int i)
691             {
692                 I = i + 1;
693             }
694         }
695     }
696 }
697