// 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; #if !NETFX_CORE using System.Net.Http.Formatting.Internal; #endif using System.Web.WebPages.TestUtils; using Microsoft.TestCommon; namespace System.Net.Http.Internal { public class HttpValueCollectionTest { #if !NETCOREAPP2_0 // Unused on .NET Core 2.0. private static readonly int _maxCollectionKeys = 1000; #endif private static HttpValueCollection CreateInstance() { #if NETFX_CORE return new HttpValueCollection(); #else return HttpValueCollection.Create(); #endif } private static void RunInIsolation(Action action) { AppDomainUtils.RunInSeparateAppDomain(action); } public static TheoryDataSet>> KeyValuePairs { get { return new TheoryDataSet>>() { new List> { new KeyValuePair(null, null), new KeyValuePair("n0", ""), new KeyValuePair("n1", "v1"), new KeyValuePair("n@2", "v@2"), new KeyValuePair("n 3", "v 3"), new KeyValuePair("n+4", "v+4"), new KeyValuePair("n;5", "v;5"), new KeyValuePair("n=5", "v=5"), } }; } } internal class TestPropertyHolder { public static TheoryDataSet ToStringTestData { get { TheoryDataSet dataSet = new TheoryDataSet(); var hvc1 = CreateInstance(); hvc1.Add(null, null); dataSet.Add(hvc1, ""); var hvc2 = CreateInstance(); hvc2.Add("name", null); dataSet.Add(hvc2, "name"); var hvc3 = CreateInstance(); hvc3.Add("name", ""); dataSet.Add(hvc3, "name"); var hvc4 = CreateInstance(); hvc4.Add("na me", ""); dataSet.Add(hvc4, "na+me"); #if NETFX_CORE string encoded5 = "n%22%2C%3B%5Cn"; #else string encoded5 = "n%22%2c%3b%5cn"; #endif var hvc5 = CreateInstance(); hvc5.Add("n\",;\\n", ""); dataSet.Add(hvc5, encoded5); var hvc6 = CreateInstance(); hvc6.Add("", "v1"); hvc6.Add("", "v2"); hvc6.Add("", "v3"); hvc6.Add("", "v4"); dataSet.Add(hvc6, "=v1&=v2&=v3&=v4"); var hvc7 = CreateInstance(); hvc7.Add("n1", "v1"); hvc7.Add("n2", "v2"); hvc7.Add("n3", "v3"); hvc7.Add("n4", "v4"); dataSet.Add(hvc7, "n1=v1&n2=v2&n3=v3&n4=v4"); #if NETFX_CORE string encoded8 = "n%2C1=v%2C1&n%3B2=v%3B2"; #else string encoded8 = "n%2c1=v%2c1&n%3b2=v%3b2"; #endif var hvc8 = CreateInstance(); hvc8.Add("n,1", "v,1"); hvc8.Add("n;2", "v;2"); dataSet.Add(hvc8, encoded8); #if NETFX_CORE string encoded9 = "n1=%26&n2=%3B&n3=%26&n4=%2B&n5=%26&n6=%3D&n7=%26"; #else string encoded9 = "n1=%26&n2=%3b&n3=%26&n4=%2b&n5=%26&n6=%3d&n7=%26"; #endif var hvc9 = CreateInstance(); hvc9.Add("n1", "&"); hvc9.Add("n2", ";"); hvc9.Add("n3", "&"); hvc9.Add("n4", "+"); hvc9.Add("n5", "&"); hvc9.Add("n6", "="); hvc9.Add("n7", "&"); dataSet.Add(hvc9, encoded9); var hvc10 = CreateInstance(); hvc10.Add("n1", "&"); hvc10.Add("n2", null); hvc10.Add("n3", "null"); dataSet.Add(hvc10, "n1=%26&n2&n3=null"); return dataSet; } } } [Fact] public void Create_CreatesEmptyCollection() { var nvc = CreateInstance(); Assert.IsType(nvc); Assert.Empty(nvc); } #if !NETCOREAPP2_0 // DBNull not serializable on .NET Core 2.0. // This set of tests requires running on a separate appdomain so we don't // touch the static property MediaTypeFormatter.MaxHttpCollectionKeys. [Fact] public void Create_CreateTooManyKeysThrows() { RunInIsolation(Create_CreateTooManyKeysThrowsPrivate); } private static void Create_CreateTooManyKeysThrowsPrivate() { // Arrange MediaTypeFormatter.MaxHttpCollectionKeys = _maxCollectionKeys; List> list = new List>(); for (int i = 0; i < _maxCollectionKeys + 1; i++) { list.Add(new KeyValuePair(i.ToString(), i.ToString())); } // Act & Assert Assert.Throws(() => HttpValueCollection.Create(list), TooManyKeysError); } private static string TooManyKeysError { get { return "The number of keys in a NameValueCollection has exceeded the limit of '" + _maxCollectionKeys + "'. You can adjust it by modifying the MaxHttpCollectionKeys property on the 'System.Net.Http.Formatting.MediaTypeFormatter' class."; } } [Fact] public void Create_CreateDoesntThrowTooManyValues() { RunInIsolation(Create_CreateDoesntThrowTooManyValuesPrivate); } private static void Create_CreateDoesntThrowTooManyValuesPrivate() { // note this is static, but also the expected type in a real run. MediaTypeFormatter.MaxHttpCollectionKeys = _maxCollectionKeys; List> list = new List>(); for (int i = 0; i < _maxCollectionKeys + 1; i++) { list.Add(new KeyValuePair("key", i.ToString())); } Assert.DoesNotThrow(() => HttpValueCollection.Create(list)); } [Fact] public void AddTooManyKeysThrows() { RunInIsolation(AddTooManyKeysThrowsPrivate); } private static void AddTooManyKeysThrowsPrivate() { // Note this is static, but also the expected type in a real run. MediaTypeFormatter.MaxHttpCollectionKeys = _maxCollectionKeys; HttpValueCollection collection = CreateInstance(); for (int i = 0; i < _maxCollectionKeys; i++) { collection.Add(i.ToString(), i.ToString()); } // Act && Assert Assert.Throws( () => collection.Add(_maxCollectionKeys.ToString(), _maxCollectionKeys.ToString()), TooManyKeysError); } [Fact] public void AddDoesntThrowTooManyValues() { RunInIsolation(AddDoesntThrowTooManyValuesPrivate); } private static void AddDoesntThrowTooManyValuesPrivate() { // Note this is static, but also the expected type in a real run. MediaTypeFormatter.MaxHttpCollectionKeys = _maxCollectionKeys; HttpValueCollection collection = CreateInstance(); // Act && Assert Assert.DoesNotThrow(() => { for (int i = 0; i < 1001; i++) { collection.Add("key", i.ToString()); } }); } #endif [Theory] [PropertyData("KeyValuePairs")] public void Create_InitializesCorrectly(IEnumerable> input) { var nvc = HttpValueCollection.Create(input); int count = input.Count(); Assert.IsType(nvc); Assert.Equal(count, nvc.Count); int index = 0; foreach (KeyValuePair kvp in input) { string expectedKey = kvp.Key ?? String.Empty; string expectedValue = kvp.Value ?? String.Empty; #if NETFX_CORE KeyValuePair actualKvp = nvc.List[index]; string actualKey = actualKvp.Key; string actualValue = actualKvp.Value; #else string actualKey = nvc.AllKeys[index]; string actualValue = nvc[index]; #endif index++; Assert.Equal(expectedKey, actualKey); Assert.Equal(expectedValue, actualValue); } } [Theory] [PropertyData("KeyValuePairs")] public void GetIsEquivalentToIndexerProperty(IEnumerable> input) { var nvc = HttpValueCollection.Create(input); int count = input.Count(); Assert.IsType(nvc); Assert.Equal(count, nvc.Count); foreach (KeyValuePair kvp in input) { Assert.Equal(nvc[kvp.Key], nvc.Get(kvp.Key)); } } [Theory] [PropertyData("ToStringTestData", PropertyType = typeof(TestPropertyHolder))] internal void ToString_GeneratesCorrectOutput(HttpValueCollection input, string expectedOutput) { string actualOutput = input.ToString(); Assert.Equal(expectedOutput, actualOutput); } } }