| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564 | #region Copyright notice and license// Protocol Buffers - Google's data interchange format// Copyright 2015 Google Inc.  All rights reserved.// https://developers.google.com/protocol-buffers///// Redistribution and use in source and binary forms, with or without// modification, are permitted provided that the following conditions are// met:////     * Redistributions of source code must retain the above copyright// notice, this list of conditions and the following disclaimer.//     * Redistributions in binary form must reproduce the above// copyright notice, this list of conditions and the following disclaimer// in the documentation and/or other materials provided with the// distribution.//     * Neither the name of Google Inc. nor the names of its// contributors may be used to endorse or promote products derived from// this software without specific prior written permission.//// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.#endregionusing System;using System.Collections.Generic;using Google.Protobuf.TestProtos;using NUnit.Framework;using System.Collections;using System.Linq;namespace Google.Protobuf.Collections{    /// <summary>    /// Tests for MapField which aren't reliant on the encoded format -    /// tests for serialization/deserialization are part of GeneratedMessageTest.    /// </summary>    public class MapFieldTest    {        [Test]        public void Clone_ClonesMessages()        {            var message = new ForeignMessage { C = 20 };            var map = new MapField<string, ForeignMessage> { { "x", message } };            var clone = map.Clone();            map["x"].C = 30;            Assert.AreEqual(20, clone["x"].C);        }        [Test]        public void NullValuesProhibited()        {            TestNullValues<int?>(0);            TestNullValues("");            TestNullValues(new TestAllTypes());        }        private void TestNullValues<T>(T nonNullValue)        {            var map = new MapField<int, T>();            var nullValue = (T) (object) null;            Assert.Throws<ArgumentNullException>(() => map.Add(0, nullValue));            Assert.Throws<ArgumentNullException>(() => map[0] = nullValue);            map.Add(1, nonNullValue);            map[1] = nonNullValue;        }        [Test]        public void Add_ForbidsNullKeys()        {            var map = new MapField<string, ForeignMessage>();            Assert.Throws<ArgumentNullException>(() => map.Add(null, new ForeignMessage()));        }        [Test]        public void Indexer_ForbidsNullKeys()        {            var map = new MapField<string, ForeignMessage>();            Assert.Throws<ArgumentNullException>(() => map[null] = new ForeignMessage());        }                [Test]        public void AddPreservesInsertionOrder()        {            var map = new MapField<string, string>();            map.Add("a", "v1");            map.Add("b", "v2");            map.Add("c", "v3");            map.Remove("b");            map.Add("d", "v4");            CollectionAssert.AreEqual(new[] { "a", "c", "d" }, map.Keys);            CollectionAssert.AreEqual(new[] { "v1", "v3", "v4" }, map.Values);        }        [Test]        public void EqualityIsOrderInsensitive()        {            var map1 = new MapField<string, string>();            map1.Add("a", "v1");            map1.Add("b", "v2");            var map2 = new MapField<string, string>();            map2.Add("b", "v2");            map2.Add("a", "v1");            EqualityTester.AssertEquality(map1, map2);        }        [Test]        public void EqualityIsKeySensitive()        {            var map1 = new MapField<string, string>();            map1.Add("first key", "v1");            map1.Add("second key", "v2");            var map2 = new MapField<string, string>();            map2.Add("third key", "v1");            map2.Add("fourth key", "v2");            EqualityTester.AssertInequality(map1, map2);        }        [Test]        public void Equality_Simple()        {            var map = new MapField<string, string>();            EqualityTester.AssertEquality(map, map);            EqualityTester.AssertInequality(map, null);            Assert.IsFalse(map.Equals(new object()));        }        [Test]        public void EqualityIsValueSensitive()        {            // Note: Without some care, it's a little easier than one might            // hope to see hash collisions, but only in some environments...            var map1 = new MapField<string, string>();            map1.Add("a", "first value");            map1.Add("b", "second value");            var map2 = new MapField<string, string>();            map2.Add("a", "third value");            map2.Add("b", "fourth value");            EqualityTester.AssertInequality(map1, map2);        }        [Test]        public void Add_Dictionary()        {            var map1 = new MapField<string, string>            {                { "x", "y" },                { "a", "b" }            };            var map2 = new MapField<string, string>            {                { "before", "" },                map1,                { "after", "" }            };            var expected = new MapField<string, string>            {                { "before", "" },                { "x", "y" },                { "a", "b" },                { "after", "" }            };            Assert.AreEqual(expected, map2);            CollectionAssert.AreEqual(new[] { "before", "x", "a", "after" }, map2.Keys);        }        // General IDictionary<TKey, TValue> behavior tests        [Test]        public void Add_KeyAlreadyExists()        {            var map = new MapField<string, string>();            map.Add("foo", "bar");            Assert.Throws<ArgumentException>(() => map.Add("foo", "baz"));        }        [Test]        public void Add_Pair()        {            var map = new MapField<string, string>();            ICollection<KeyValuePair<string, string>> collection = map;            collection.Add(NewKeyValuePair("x", "y"));            Assert.AreEqual("y", map["x"]);            Assert.Throws<ArgumentException>(() => collection.Add(NewKeyValuePair("x", "z")));        }        [Test]        public void Contains_Pair()        {            var map = new MapField<string, string> { { "x", "y" } };            ICollection<KeyValuePair<string, string>> collection = map;            Assert.IsTrue(collection.Contains(NewKeyValuePair("x", "y")));            Assert.IsFalse(collection.Contains(NewKeyValuePair("x", "z")));            Assert.IsFalse(collection.Contains(NewKeyValuePair("z", "y")));        }        [Test]        public void Remove_Key()        {            var map = new MapField<string, string>();            map.Add("foo", "bar");            Assert.AreEqual(1, map.Count);            Assert.IsFalse(map.Remove("missing"));            Assert.AreEqual(1, map.Count);            Assert.IsTrue(map.Remove("foo"));            Assert.AreEqual(0, map.Count);            Assert.Throws<ArgumentNullException>(() => map.Remove(null));        }        [Test]        public void Remove_Pair()        {            var map = new MapField<string, string>();            map.Add("foo", "bar");            ICollection<KeyValuePair<string, string>> collection = map;            Assert.AreEqual(1, map.Count);            Assert.IsFalse(collection.Remove(NewKeyValuePair("wrong key", "bar")));            Assert.AreEqual(1, map.Count);            Assert.IsFalse(collection.Remove(NewKeyValuePair("foo", "wrong value")));            Assert.AreEqual(1, map.Count);            Assert.IsTrue(collection.Remove(NewKeyValuePair("foo", "bar")));            Assert.AreEqual(0, map.Count);            Assert.Throws<ArgumentException>(() => collection.Remove(new KeyValuePair<string, string>(null, "")));        }        [Test]        public void CopyTo_Pair()        {            var map = new MapField<string, string>();            map.Add("foo", "bar");            ICollection<KeyValuePair<string, string>> collection = map;            KeyValuePair<string, string>[] array = new KeyValuePair<string, string>[3];            collection.CopyTo(array, 1);            Assert.AreEqual(NewKeyValuePair("foo", "bar"), array[1]);        }        [Test]        public void Clear()        {            var map = new MapField<string, string> { { "x", "y" } };            Assert.AreEqual(1, map.Count);            map.Clear();            Assert.AreEqual(0, map.Count);            map.Add("x", "y");            Assert.AreEqual(1, map.Count);        }        [Test]        public void Indexer_Get()        {            var map = new MapField<string, string> { { "x", "y" } };            Assert.AreEqual("y", map["x"]);            Assert.Throws<KeyNotFoundException>(() => { var ignored = map["z"]; });        }        [Test]        public void Indexer_Set()        {            var map = new MapField<string, string>();            map["x"] = "y";            Assert.AreEqual("y", map["x"]);            map["x"] = "z"; // This won't throw, unlike Add.            Assert.AreEqual("z", map["x"]);        }        [Test]        public void GetEnumerator_NonGeneric()        {            IEnumerable map = new MapField<string, string> { { "x", "y" } };            CollectionAssert.AreEqual(new[] { new KeyValuePair<string, string>("x", "y") },                map.Cast<object>().ToList());        }        // Test for the explicitly-implemented non-generic IDictionary interface        [Test]        public void IDictionary_GetEnumerator()        {            IDictionary map = new MapField<string, string> { { "x", "y" } };            var enumerator = map.GetEnumerator();            // Commented assertions show an ideal situation - it looks like            // the LinkedList enumerator doesn't throw when you ask for the current entry            // at an inappropriate time; fixing this would be more work than it's worth.            // Assert.Throws<InvalidOperationException>(() => enumerator.Current.GetHashCode());            Assert.IsTrue(enumerator.MoveNext());            Assert.AreEqual("x", enumerator.Key);            Assert.AreEqual("y", enumerator.Value);            Assert.AreEqual(new DictionaryEntry("x", "y"), enumerator.Current);            Assert.AreEqual(new DictionaryEntry("x", "y"), enumerator.Entry);            Assert.IsFalse(enumerator.MoveNext());            // Assert.Throws<InvalidOperationException>(() => enumerator.Current.GetHashCode());            enumerator.Reset();            // Assert.Throws<InvalidOperationException>(() => enumerator.Current.GetHashCode());            Assert.IsTrue(enumerator.MoveNext());            Assert.AreEqual("x", enumerator.Key); // Assume the rest are okay        }        [Test]        public void IDictionary_Add()        {            var map = new MapField<string, string> { { "x", "y" } };            IDictionary dictionary = map;            dictionary.Add("a", "b");            Assert.AreEqual("b", map["a"]);            Assert.Throws<ArgumentException>(() => dictionary.Add("a", "duplicate"));            Assert.Throws<InvalidCastException>(() => dictionary.Add(new object(), "key is bad"));            Assert.Throws<InvalidCastException>(() => dictionary.Add("value is bad", new object()));        }        [Test]        public void IDictionary_Contains()        {            var map = new MapField<string, string> { { "x", "y" } };            IDictionary dictionary = map;            Assert.IsFalse(dictionary.Contains("a"));            Assert.IsFalse(dictionary.Contains(5));            // Surprising, but IDictionary.Contains is only about keys.            Assert.IsFalse(dictionary.Contains(new DictionaryEntry("x", "y")));            Assert.IsTrue(dictionary.Contains("x"));        }        [Test]        public void IDictionary_Remove()        {            var map = new MapField<string, string> { { "x", "y" } };            IDictionary dictionary = map;            dictionary.Remove("a");            Assert.AreEqual(1, dictionary.Count);            dictionary.Remove(5);            Assert.AreEqual(1, dictionary.Count);            dictionary.Remove(new DictionaryEntry("x", "y"));            Assert.AreEqual(1, dictionary.Count);            dictionary.Remove("x");            Assert.AreEqual(0, dictionary.Count);            Assert.Throws<ArgumentNullException>(() => dictionary.Remove(null));        }        [Test]        public void IDictionary_CopyTo()        {            var map = new MapField<string, string> { { "x", "y" } };            IDictionary dictionary = map;            var array = new DictionaryEntry[3];            dictionary.CopyTo(array, 1);            CollectionAssert.AreEqual(new[] { default(DictionaryEntry), new DictionaryEntry("x", "y"), default(DictionaryEntry) },                array);            var objectArray = new object[3];            dictionary.CopyTo(objectArray, 1);            CollectionAssert.AreEqual(new object[] { null, new DictionaryEntry("x", "y"), null },                objectArray);        }        [Test]        public void IDictionary_IsFixedSize()        {            var map = new MapField<string, string> { { "x", "y" } };            IDictionary dictionary = map;            Assert.IsFalse(dictionary.IsFixedSize);        }        [Test]        public void IDictionary_Keys()        {            IDictionary dictionary = new MapField<string, string> { { "x", "y" } };            CollectionAssert.AreEqual(new[] { "x" }, dictionary.Keys);        }        [Test]        public void IDictionary_Values()        {            IDictionary dictionary = new MapField<string, string> { { "x", "y" } };            CollectionAssert.AreEqual(new[] { "y" }, dictionary.Values);        }        [Test]        public void IDictionary_IsSynchronized()        {            IDictionary dictionary = new MapField<string, string> { { "x", "y" } };            Assert.IsFalse(dictionary.IsSynchronized);        }        [Test]        public void IDictionary_SyncRoot()        {            IDictionary dictionary = new MapField<string, string> { { "x", "y" } };            Assert.AreSame(dictionary, dictionary.SyncRoot);        }        [Test]        public void IDictionary_Indexer_Get()        {            IDictionary dictionary = new MapField<string, string> { { "x", "y" } };            Assert.AreEqual("y", dictionary["x"]);            Assert.IsNull(dictionary["a"]);            Assert.IsNull(dictionary[5]);            Assert.Throws<ArgumentNullException>(() => dictionary[null].GetHashCode());        }        [Test]        public void IDictionary_Indexer_Set()        {            var map = new MapField<string, string> { { "x", "y" } };            IDictionary dictionary = map;            map["a"] = "b";            Assert.AreEqual("b", map["a"]);            map["a"] = "c";            Assert.AreEqual("c", map["a"]);            Assert.Throws<InvalidCastException>(() => dictionary[5] = "x");            Assert.Throws<InvalidCastException>(() => dictionary["x"] = 5);            Assert.Throws<ArgumentNullException>(() => dictionary[null] = "z");            Assert.Throws<ArgumentNullException>(() => dictionary["x"] = null);        }        [Test]        public void KeysReturnsLiveView()        {            var map = new MapField<string, string>();            var keys = map.Keys;            CollectionAssert.AreEqual(new string[0], keys);            map["foo"] = "bar";            map["x"] = "y";            CollectionAssert.AreEqual(new[] { "foo", "x" }, keys);        }        [Test]        public void ValuesReturnsLiveView()        {            var map = new MapField<string, string>();            var values = map.Values;            CollectionAssert.AreEqual(new string[0], values);            map["foo"] = "bar";            map["x"] = "y";            CollectionAssert.AreEqual(new[] { "bar", "y" }, values);        }        // Just test keys - we know the implementation is the same for values        [Test]        public void ViewsAreReadOnly()        {            var map = new MapField<string, string>();            var keys = map.Keys;            Assert.IsTrue(keys.IsReadOnly);            Assert.Throws<NotSupportedException>(() => keys.Clear());            Assert.Throws<NotSupportedException>(() => keys.Remove("a"));            Assert.Throws<NotSupportedException>(() => keys.Add("a"));        }        // Just test keys - we know the implementation is the same for values        [Test]        public void ViewCopyTo()        {            var map = new MapField<string, string> { { "foo", "bar" }, { "x", "y" } };            var keys = map.Keys;            var array = new string[4];            Assert.Throws<ArgumentException>(() => keys.CopyTo(array, 3));            Assert.Throws<ArgumentOutOfRangeException>(() => keys.CopyTo(array, -1));            keys.CopyTo(array, 1);            CollectionAssert.AreEqual(new[] { null, "foo", "x", null }, array);        }                // Just test keys - we know the implementation is the same for values        [Test]        public void NonGenericViewCopyTo()        {            IDictionary map = new MapField<string, string> { { "foo", "bar" }, { "x", "y" } };            ICollection keys = map.Keys;            // Note the use of the Array type here rather than string[]            Array array = new string[4];            Assert.Throws<ArgumentException>(() => keys.CopyTo(array, 3));            Assert.Throws<ArgumentOutOfRangeException>(() => keys.CopyTo(array, -1));            keys.CopyTo(array, 1);            CollectionAssert.AreEqual(new[] { null, "foo", "x", null }, array);        }        [Test]        public void KeysContains()        {            var map = new MapField<string, string> { { "foo", "bar" }, { "x", "y" } };            var keys = map.Keys;            Assert.IsTrue(keys.Contains("foo"));            Assert.IsFalse(keys.Contains("bar")); // It's a value!            Assert.IsFalse(keys.Contains("1"));            // Keys can't be null, so we should prevent contains check            Assert.Throws<ArgumentNullException>(() => keys.Contains(null));        }        [Test]        public void KeysCopyTo()        {            var map = new MapField<string, string> { { "foo", "bar" }, { "x", "y" } };            var keys = map.Keys.ToArray(); // Uses CopyTo internally            CollectionAssert.AreEquivalent(new[] { "foo", "x" }, keys);        }        [Test]        public void ValuesContains()        {            var map = new MapField<string, string> { { "foo", "bar" }, { "x", "y" } };            var values = map.Values;            Assert.IsTrue(values.Contains("bar"));            Assert.IsFalse(values.Contains("foo")); // It's a key!            Assert.IsFalse(values.Contains("1"));            // Values can be null, so this makes sense            Assert.IsFalse(values.Contains(null));        }        [Test]        public void ValuesCopyTo()        {            var map = new MapField<string, string> { { "foo", "bar" }, { "x", "y" } };            var values = map.Values.ToArray(); // Uses CopyTo internally            CollectionAssert.AreEquivalent(new[] { "bar", "y" }, values);        }        [Test]        public void ToString_StringToString()        {            var map = new MapField<string, string> { { "foo", "bar" }, { "x", "y" } };            Assert.AreEqual("{ \"foo\": \"bar\", \"x\": \"y\" }", map.ToString());        }        [Test]        public void ToString_UnsupportedKeyType()        {            var map = new MapField<byte, string> { { 10, "foo" } };            Assert.Throws<ArgumentException>(() => map.ToString());        }#if !NET35        [Test]        public void IDictionaryKeys_Equals_IReadOnlyDictionaryKeys()        {            var map = new MapField<string, string> { { "foo", "bar" }, { "x", "y" } };            CollectionAssert.AreEquivalent(((IDictionary<string, string>)map).Keys, ((IReadOnlyDictionary<string, string>)map).Keys);        }        [Test]        public void IDictionaryValues_Equals_IReadOnlyDictionaryValues()        {            var map = new MapField<string, string> { { "foo", "bar" }, { "x", "y" } };            CollectionAssert.AreEquivalent(((IDictionary<string, string>)map).Values, ((IReadOnlyDictionary<string, string>)map).Values);        }#endif        private static KeyValuePair<TKey, TValue> NewKeyValuePair<TKey, TValue>(TKey key, TValue value)        {            return new KeyValuePair<TKey, TValue>(key, value);        }    }}
 |