• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #region Copyright notice and license
2 // Protocol Buffers - Google's data interchange format
3 // Copyright 2015 Google Inc.  All rights reserved.
4 // https://developers.google.com/protocol-buffers/
5 //
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are
8 // met:
9 //
10 //     * Redistributions of source code must retain the above copyright
11 // notice, this list of conditions and the following disclaimer.
12 //     * Redistributions in binary form must reproduce the above
13 // copyright notice, this list of conditions and the following disclaimer
14 // in the documentation and/or other materials provided with the
15 // distribution.
16 //     * Neither the name of Google Inc. nor the names of its
17 // contributors may be used to endorse or promote products derived from
18 // this software without specific prior written permission.
19 //
20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #endregion
32 
33 using System;
34 using System.IO;
35 using System.Collections.Generic;
36 using Google.Protobuf.TestProtos;
37 using NUnit.Framework;
38 using System.Collections;
39 using System.Linq;
40 
41 namespace Google.Protobuf.Collections
42 {
43     /// <summary>
44     /// Tests for MapField which aren't reliant on the encoded format -
45     /// tests for serialization/deserialization are part of GeneratedMessageTest.
46     /// </summary>
47     public class MapFieldTest
48     {
49         [Test]
Clone_ClonesMessages()50         public void Clone_ClonesMessages()
51         {
52             var message = new ForeignMessage { C = 20 };
53             var map = new MapField<string, ForeignMessage> { { "x", message } };
54             var clone = map.Clone();
55             map["x"].C = 30;
56             Assert.AreEqual(20, clone["x"].C);
57         }
58 
59         [Test]
NullValuesProhibited()60         public void NullValuesProhibited()
61         {
62             TestNullValues<int?>(0);
63             TestNullValues("");
64             TestNullValues(new TestAllTypes());
65         }
66 
TestNullValues(T nonNullValue)67         private void TestNullValues<T>(T nonNullValue)
68         {
69             var map = new MapField<int, T>();
70             var nullValue = (T) (object) null;
71             Assert.Throws<ArgumentNullException>(() => map.Add(0, nullValue));
72             Assert.Throws<ArgumentNullException>(() => map[0] = nullValue);
73             map.Add(1, nonNullValue);
74             map[1] = nonNullValue;
75         }
76 
77         [Test]
Add_ForbidsNullKeys()78         public void Add_ForbidsNullKeys()
79         {
80             var map = new MapField<string, ForeignMessage>();
81             Assert.Throws<ArgumentNullException>(() => map.Add(null, new ForeignMessage()));
82         }
83 
84         [Test]
Indexer_ForbidsNullKeys()85         public void Indexer_ForbidsNullKeys()
86         {
87             var map = new MapField<string, ForeignMessage>();
88             Assert.Throws<ArgumentNullException>(() => map[null] = new ForeignMessage());
89         }
90 
91         [Test]
AddPreservesInsertionOrder()92         public void AddPreservesInsertionOrder()
93         {
94             var map = new MapField<string, string>();
95             map.Add("a", "v1");
96             map.Add("b", "v2");
97             map.Add("c", "v3");
98             map.Remove("b");
99             map.Add("d", "v4");
100             CollectionAssert.AreEqual(new[] { "a", "c", "d" }, map.Keys);
101             CollectionAssert.AreEqual(new[] { "v1", "v3", "v4" }, map.Values);
102         }
103 
104         [Test]
EqualityIsOrderInsensitive()105         public void EqualityIsOrderInsensitive()
106         {
107             var map1 = new MapField<string, string>();
108             map1.Add("a", "v1");
109             map1.Add("b", "v2");
110 
111             var map2 = new MapField<string, string>();
112             map2.Add("b", "v2");
113             map2.Add("a", "v1");
114 
115             EqualityTester.AssertEquality(map1, map2);
116         }
117 
118         [Test]
EqualityIsKeySensitive()119         public void EqualityIsKeySensitive()
120         {
121             var map1 = new MapField<string, string>();
122             map1.Add("first key", "v1");
123             map1.Add("second key", "v2");
124 
125             var map2 = new MapField<string, string>();
126             map2.Add("third key", "v1");
127             map2.Add("fourth key", "v2");
128 
129             EqualityTester.AssertInequality(map1, map2);
130         }
131 
132         [Test]
Equality_Simple()133         public void Equality_Simple()
134         {
135             var map = new MapField<string, string>();
136             EqualityTester.AssertEquality(map, map);
137             EqualityTester.AssertInequality(map, null);
138             Assert.IsFalse(map.Equals(new object()));
139         }
140 
141         [Test]
EqualityIsValueSensitive()142         public void EqualityIsValueSensitive()
143         {
144             // Note: Without some care, it's a little easier than one might
145             // hope to see hash collisions, but only in some environments...
146             var map1 = new MapField<string, string>();
147             map1.Add("a", "first value");
148             map1.Add("b", "second value");
149 
150             var map2 = new MapField<string, string>();
151             map2.Add("a", "third value");
152             map2.Add("b", "fourth value");
153 
154             EqualityTester.AssertInequality(map1, map2);
155         }
156 
157         [Test]
Add_Dictionary()158         public void Add_Dictionary()
159         {
160             var map1 = new MapField<string, string>
161             {
162                 { "x", "y" },
163                 { "a", "b" }
164             };
165             var map2 = new MapField<string, string>
166             {
167                 { "before", "" },
168                 map1,
169                 { "after", "" }
170             };
171             var expected = new MapField<string, string>
172             {
173                 { "before", "" },
174                 { "x", "y" },
175                 { "a", "b" },
176                 { "after", "" }
177             };
178             Assert.AreEqual(expected, map2);
179             CollectionAssert.AreEqual(new[] { "before", "x", "a", "after" }, map2.Keys);
180         }
181 
182         // General IDictionary<TKey, TValue> behavior tests
183         [Test]
Add_KeyAlreadyExists()184         public void Add_KeyAlreadyExists()
185         {
186             var map = new MapField<string, string>();
187             map.Add("foo", "bar");
188             Assert.Throws<ArgumentException>(() => map.Add("foo", "baz"));
189         }
190 
191         [Test]
Add_Pair()192         public void Add_Pair()
193         {
194             var map = new MapField<string, string>();
195             ICollection<KeyValuePair<string, string>> collection = map;
196             collection.Add(NewKeyValuePair("x", "y"));
197             Assert.AreEqual("y", map["x"]);
198             Assert.Throws<ArgumentException>(() => collection.Add(NewKeyValuePair("x", "z")));
199         }
200 
201         [Test]
Contains_Pair()202         public void Contains_Pair()
203         {
204             var map = new MapField<string, string> { { "x", "y" } };
205             ICollection<KeyValuePair<string, string>> collection = map;
206             Assert.IsTrue(collection.Contains(NewKeyValuePair("x", "y")));
207             Assert.IsFalse(collection.Contains(NewKeyValuePair("x", "z")));
208             Assert.IsFalse(collection.Contains(NewKeyValuePair("z", "y")));
209         }
210 
211         [Test]
Remove_Key()212         public void Remove_Key()
213         {
214             var map = new MapField<string, string>();
215             map.Add("foo", "bar");
216             Assert.AreEqual(1, map.Count);
217             Assert.IsFalse(map.Remove("missing"));
218             Assert.AreEqual(1, map.Count);
219             Assert.IsTrue(map.Remove("foo"));
220             Assert.AreEqual(0, map.Count);
221             Assert.Throws<ArgumentNullException>(() => map.Remove(null));
222         }
223 
224         [Test]
Remove_Pair()225         public void Remove_Pair()
226         {
227             var map = new MapField<string, string>();
228             map.Add("foo", "bar");
229             ICollection<KeyValuePair<string, string>> collection = map;
230             Assert.AreEqual(1, map.Count);
231             Assert.IsFalse(collection.Remove(NewKeyValuePair("wrong key", "bar")));
232             Assert.AreEqual(1, map.Count);
233             Assert.IsFalse(collection.Remove(NewKeyValuePair("foo", "wrong value")));
234             Assert.AreEqual(1, map.Count);
235             Assert.IsTrue(collection.Remove(NewKeyValuePair("foo", "bar")));
236             Assert.AreEqual(0, map.Count);
237             Assert.Throws<ArgumentException>(() => collection.Remove(new KeyValuePair<string, string>(null, "")));
238         }
239 
240         [Test]
CopyTo_Pair()241         public void CopyTo_Pair()
242         {
243             var map = new MapField<string, string>();
244             map.Add("foo", "bar");
245             ICollection<KeyValuePair<string, string>> collection = map;
246             KeyValuePair<string, string>[] array = new KeyValuePair<string, string>[3];
247             collection.CopyTo(array, 1);
248             Assert.AreEqual(NewKeyValuePair("foo", "bar"), array[1]);
249         }
250 
251         [Test]
Clear()252         public void Clear()
253         {
254             var map = new MapField<string, string> { { "x", "y" } };
255             Assert.AreEqual(1, map.Count);
256             map.Clear();
257             Assert.AreEqual(0, map.Count);
258             map.Add("x", "y");
259             Assert.AreEqual(1, map.Count);
260         }
261 
262         [Test]
Indexer_Get()263         public void Indexer_Get()
264         {
265             var map = new MapField<string, string> { { "x", "y" } };
266             Assert.AreEqual("y", map["x"]);
267             Assert.Throws<KeyNotFoundException>(() => { var ignored = map["z"]; });
268         }
269 
270         [Test]
Indexer_Set()271         public void Indexer_Set()
272         {
273             var map = new MapField<string, string>();
274             map["x"] = "y";
275             Assert.AreEqual("y", map["x"]);
276             map["x"] = "z"; // This won't throw, unlike Add.
277             Assert.AreEqual("z", map["x"]);
278         }
279 
280         [Test]
GetEnumerator_NonGeneric()281         public void GetEnumerator_NonGeneric()
282         {
283             IEnumerable map = new MapField<string, string> { { "x", "y" } };
284             CollectionAssert.AreEqual(new[] { new KeyValuePair<string, string>("x", "y") },
285                 map.Cast<object>().ToList());
286         }
287 
288         // Test for the explicitly-implemented non-generic IDictionary interface
289         [Test]
IDictionary_GetEnumerator()290         public void IDictionary_GetEnumerator()
291         {
292             IDictionary map = new MapField<string, string> { { "x", "y" } };
293             var enumerator = map.GetEnumerator();
294 
295             // Commented assertions show an ideal situation - it looks like
296             // the LinkedList enumerator doesn't throw when you ask for the current entry
297             // at an inappropriate time; fixing this would be more work than it's worth.
298             // Assert.Throws<InvalidOperationException>(() => enumerator.Current.GetHashCode());
299             Assert.IsTrue(enumerator.MoveNext());
300             Assert.AreEqual("x", enumerator.Key);
301             Assert.AreEqual("y", enumerator.Value);
302             Assert.AreEqual(new DictionaryEntry("x", "y"), enumerator.Current);
303             Assert.AreEqual(new DictionaryEntry("x", "y"), enumerator.Entry);
304             Assert.IsFalse(enumerator.MoveNext());
305             // Assert.Throws<InvalidOperationException>(() => enumerator.Current.GetHashCode());
306             enumerator.Reset();
307             // Assert.Throws<InvalidOperationException>(() => enumerator.Current.GetHashCode());
308             Assert.IsTrue(enumerator.MoveNext());
309             Assert.AreEqual("x", enumerator.Key); // Assume the rest are okay
310         }
311 
312         [Test]
IDictionary_Add()313         public void IDictionary_Add()
314         {
315             var map = new MapField<string, string> { { "x", "y" } };
316             IDictionary dictionary = map;
317             dictionary.Add("a", "b");
318             Assert.AreEqual("b", map["a"]);
319             Assert.Throws<ArgumentException>(() => dictionary.Add("a", "duplicate"));
320             Assert.Throws<InvalidCastException>(() => dictionary.Add(new object(), "key is bad"));
321             Assert.Throws<InvalidCastException>(() => dictionary.Add("value is bad", new object()));
322         }
323 
324         [Test]
IDictionary_Contains()325         public void IDictionary_Contains()
326         {
327             var map = new MapField<string, string> { { "x", "y" } };
328             IDictionary dictionary = map;
329 
330             Assert.IsFalse(dictionary.Contains("a"));
331             Assert.IsFalse(dictionary.Contains(5));
332             // Surprising, but IDictionary.Contains is only about keys.
333             Assert.IsFalse(dictionary.Contains(new DictionaryEntry("x", "y")));
334             Assert.IsTrue(dictionary.Contains("x"));
335         }
336 
337         [Test]
IDictionary_Remove()338         public void IDictionary_Remove()
339         {
340             var map = new MapField<string, string> { { "x", "y" } };
341             IDictionary dictionary = map;
342             dictionary.Remove("a");
343             Assert.AreEqual(1, dictionary.Count);
344             dictionary.Remove(5);
345             Assert.AreEqual(1, dictionary.Count);
346             dictionary.Remove(new DictionaryEntry("x", "y"));
347             Assert.AreEqual(1, dictionary.Count);
348             dictionary.Remove("x");
349             Assert.AreEqual(0, dictionary.Count);
350             Assert.Throws<ArgumentNullException>(() => dictionary.Remove(null));
351         }
352 
353         [Test]
IDictionary_CopyTo()354         public void IDictionary_CopyTo()
355         {
356             var map = new MapField<string, string> { { "x", "y" } };
357             IDictionary dictionary = map;
358             var array = new DictionaryEntry[3];
359             dictionary.CopyTo(array, 1);
360             CollectionAssert.AreEqual(new[] { default(DictionaryEntry), new DictionaryEntry("x", "y"), default(DictionaryEntry) },
361                 array);
362             var objectArray = new object[3];
363             dictionary.CopyTo(objectArray, 1);
364             CollectionAssert.AreEqual(new object[] { null, new DictionaryEntry("x", "y"), null },
365                 objectArray);
366         }
367 
368         [Test]
IDictionary_IsFixedSize()369         public void IDictionary_IsFixedSize()
370         {
371             var map = new MapField<string, string> { { "x", "y" } };
372             IDictionary dictionary = map;
373             Assert.IsFalse(dictionary.IsFixedSize);
374         }
375 
376         [Test]
IDictionary_Keys()377         public void IDictionary_Keys()
378         {
379             IDictionary dictionary = new MapField<string, string> { { "x", "y" } };
380             CollectionAssert.AreEqual(new[] { "x" }, dictionary.Keys);
381         }
382 
383         [Test]
IDictionary_Values()384         public void IDictionary_Values()
385         {
386             IDictionary dictionary = new MapField<string, string> { { "x", "y" } };
387             CollectionAssert.AreEqual(new[] { "y" }, dictionary.Values);
388         }
389 
390         [Test]
IDictionary_IsSynchronized()391         public void IDictionary_IsSynchronized()
392         {
393             IDictionary dictionary = new MapField<string, string> { { "x", "y" } };
394             Assert.IsFalse(dictionary.IsSynchronized);
395         }
396 
397         [Test]
IDictionary_SyncRoot()398         public void IDictionary_SyncRoot()
399         {
400             IDictionary dictionary = new MapField<string, string> { { "x", "y" } };
401             Assert.AreSame(dictionary, dictionary.SyncRoot);
402         }
403 
404         [Test]
IDictionary_Indexer_Get()405         public void IDictionary_Indexer_Get()
406         {
407             IDictionary dictionary = new MapField<string, string> { { "x", "y" } };
408             Assert.AreEqual("y", dictionary["x"]);
409             Assert.IsNull(dictionary["a"]);
410             Assert.IsNull(dictionary[5]);
411             Assert.Throws<ArgumentNullException>(() => dictionary[null].GetHashCode());
412         }
413 
414         [Test]
IDictionary_Indexer_Set()415         public void IDictionary_Indexer_Set()
416         {
417             var map = new MapField<string, string> { { "x", "y" } };
418             IDictionary dictionary = map;
419             map["a"] = "b";
420             Assert.AreEqual("b", map["a"]);
421             map["a"] = "c";
422             Assert.AreEqual("c", map["a"]);
423             Assert.Throws<InvalidCastException>(() => dictionary[5] = "x");
424             Assert.Throws<InvalidCastException>(() => dictionary["x"] = 5);
425             Assert.Throws<ArgumentNullException>(() => dictionary[null] = "z");
426             Assert.Throws<ArgumentNullException>(() => dictionary["x"] = null);
427         }
428 
429         [Test]
KeysReturnsLiveView()430         public void KeysReturnsLiveView()
431         {
432             var map = new MapField<string, string>();
433             var keys = map.Keys;
434             CollectionAssert.AreEqual(new string[0], keys);
435             map["foo"] = "bar";
436             map["x"] = "y";
437             CollectionAssert.AreEqual(new[] { "foo", "x" }, keys);
438         }
439 
440         [Test]
ValuesReturnsLiveView()441         public void ValuesReturnsLiveView()
442         {
443             var map = new MapField<string, string>();
444             var values = map.Values;
445             CollectionAssert.AreEqual(new string[0], values);
446             map["foo"] = "bar";
447             map["x"] = "y";
448             CollectionAssert.AreEqual(new[] { "bar", "y" }, values);
449         }
450 
451         // Just test keys - we know the implementation is the same for values
452         [Test]
ViewsAreReadOnly()453         public void ViewsAreReadOnly()
454         {
455             var map = new MapField<string, string>();
456             var keys = map.Keys;
457             Assert.IsTrue(keys.IsReadOnly);
458             Assert.Throws<NotSupportedException>(() => keys.Clear());
459             Assert.Throws<NotSupportedException>(() => keys.Remove("a"));
460             Assert.Throws<NotSupportedException>(() => keys.Add("a"));
461         }
462 
463         // Just test keys - we know the implementation is the same for values
464         [Test]
ViewCopyTo()465         public void ViewCopyTo()
466         {
467             var map = new MapField<string, string> { { "foo", "bar" }, { "x", "y" } };
468             var keys = map.Keys;
469             var array = new string[4];
470             Assert.Throws<ArgumentException>(() => keys.CopyTo(array, 3));
471             Assert.Throws<ArgumentOutOfRangeException>(() => keys.CopyTo(array, -1));
472             keys.CopyTo(array, 1);
473             CollectionAssert.AreEqual(new[] { null, "foo", "x", null }, array);
474         }
475 
476         // Just test keys - we know the implementation is the same for values
477         [Test]
NonGenericViewCopyTo()478         public void NonGenericViewCopyTo()
479         {
480             IDictionary map = new MapField<string, string> { { "foo", "bar" }, { "x", "y" } };
481             ICollection keys = map.Keys;
482             // Note the use of the Array type here rather than string[]
483             Array array = new string[4];
484             Assert.Throws<ArgumentException>(() => keys.CopyTo(array, 3));
485             Assert.Throws<ArgumentOutOfRangeException>(() => keys.CopyTo(array, -1));
486             keys.CopyTo(array, 1);
487             CollectionAssert.AreEqual(new[] { null, "foo", "x", null }, array);
488         }
489 
490         [Test]
KeysContains()491         public void KeysContains()
492         {
493             var map = new MapField<string, string> { { "foo", "bar" }, { "x", "y" } };
494             var keys = map.Keys;
495             Assert.IsTrue(keys.Contains("foo"));
496             Assert.IsFalse(keys.Contains("bar")); // It's a value!
497             Assert.IsFalse(keys.Contains("1"));
498             // Keys can't be null, so we should prevent contains check
499             Assert.Throws<ArgumentNullException>(() => keys.Contains(null));
500         }
501 
502         [Test]
KeysCopyTo()503         public void KeysCopyTo()
504         {
505             var map = new MapField<string, string> { { "foo", "bar" }, { "x", "y" } };
506             var keys = map.Keys.ToArray(); // Uses CopyTo internally
507             CollectionAssert.AreEquivalent(new[] { "foo", "x" }, keys);
508         }
509 
510         [Test]
ValuesContains()511         public void ValuesContains()
512         {
513             var map = new MapField<string, string> { { "foo", "bar" }, { "x", "y" } };
514             var values = map.Values;
515             Assert.IsTrue(values.Contains("bar"));
516             Assert.IsFalse(values.Contains("foo")); // It's a key!
517             Assert.IsFalse(values.Contains("1"));
518             // Values can be null, so this makes sense
519             Assert.IsFalse(values.Contains(null));
520         }
521 
522         [Test]
ValuesCopyTo()523         public void ValuesCopyTo()
524         {
525             var map = new MapField<string, string> { { "foo", "bar" }, { "x", "y" } };
526             var values = map.Values.ToArray(); // Uses CopyTo internally
527             CollectionAssert.AreEquivalent(new[] { "bar", "y" }, values);
528         }
529 
530         [Test]
ToString_StringToString()531         public void ToString_StringToString()
532         {
533             var map = new MapField<string, string> { { "foo", "bar" }, { "x", "y" } };
534             Assert.AreEqual("{ \"foo\": \"bar\", \"x\": \"y\" }", map.ToString());
535         }
536 
537         [Test]
ToString_UnsupportedKeyType()538         public void ToString_UnsupportedKeyType()
539         {
540             var map = new MapField<byte, string> { { 10, "foo" } };
541             Assert.Throws<ArgumentException>(() => map.ToString());
542         }
543 
544         [Test]
NaNValuesComparedBitwise()545         public void NaNValuesComparedBitwise()
546         {
547             var map1 = new MapField<string, double>
548             {
549                 { "x", SampleNaNs.Regular },
550                 { "y", SampleNaNs.SignallingFlipped }
551             };
552 
553             var map2 = new MapField<string, double>
554             {
555                 { "x", SampleNaNs.Regular },
556                 { "y", SampleNaNs.PayloadFlipped }
557             };
558 
559             var map3 = new MapField<string, double>
560             {
561                 { "x", SampleNaNs.Regular },
562                 { "y", SampleNaNs.SignallingFlipped }
563             };
564 
565             EqualityTester.AssertInequality(map1, map2);
566             EqualityTester.AssertEquality(map1, map3);
567             Assert.True(map1.Values.Contains(SampleNaNs.SignallingFlipped));
568             Assert.False(map2.Values.Contains(SampleNaNs.SignallingFlipped));
569         }
570 
571         // This wouldn't usually happen, as protos can't use doubles as map keys,
572         // but let's be consistent.
573         [Test]
NaNKeysComparedBitwise()574         public void NaNKeysComparedBitwise()
575         {
576             var map = new MapField<double, string>
577             {
578                 { SampleNaNs.Regular, "x" },
579                 { SampleNaNs.SignallingFlipped, "y" }
580             };
581             Assert.AreEqual("x", map[SampleNaNs.Regular]);
582             Assert.AreEqual("y", map[SampleNaNs.SignallingFlipped]);
583             string ignored;
584             Assert.False(map.TryGetValue(SampleNaNs.PayloadFlipped, out ignored));
585         }
586 
587         [Test]
AddEntriesFrom_CodedInputStream()588         public void AddEntriesFrom_CodedInputStream()
589         {
590             // map will have string key and string value
591             var keyTag = WireFormat.MakeTag(1, WireFormat.WireType.LengthDelimited);
592             var valueTag = WireFormat.MakeTag(2, WireFormat.WireType.LengthDelimited);
593 
594             var memoryStream = new MemoryStream();
595             var output = new CodedOutputStream(memoryStream);
596             output.WriteLength(20);  // total of keyTag + key + valueTag + value
597             output.WriteTag(keyTag);
598             output.WriteString("the_key");
599             output.WriteTag(valueTag);
600             output.WriteString("the_value");
601             output.Flush();
602 
603             var field = new MapField<string,string>();
604             var mapCodec = new MapField<string,string>.Codec(FieldCodec.ForString(keyTag, ""), FieldCodec.ForString(valueTag, ""), 10);
605             var input = new CodedInputStream(memoryStream.ToArray());
606 
607             // test the legacy overload of AddEntriesFrom that takes a CodedInputStream
608             field.AddEntriesFrom(input, mapCodec);
609             CollectionAssert.AreEquivalent(new[] { "the_key" }, field.Keys);
610             CollectionAssert.AreEquivalent(new[] { "the_value" }, field.Values);
611             Assert.IsTrue(input.IsAtEnd);
612         }
613 
614 #if !NET35
615         [Test]
IDictionaryKeys_Equals_IReadOnlyDictionaryKeys()616         public void IDictionaryKeys_Equals_IReadOnlyDictionaryKeys()
617         {
618             var map = new MapField<string, string> { { "foo", "bar" }, { "x", "y" } };
619             CollectionAssert.AreEquivalent(((IDictionary<string, string>)map).Keys, ((IReadOnlyDictionary<string, string>)map).Keys);
620         }
621 
622         [Test]
IDictionaryValues_Equals_IReadOnlyDictionaryValues()623         public void IDictionaryValues_Equals_IReadOnlyDictionaryValues()
624         {
625             var map = new MapField<string, string> { { "foo", "bar" }, { "x", "y" } };
626             CollectionAssert.AreEquivalent(((IDictionary<string, string>)map).Values, ((IReadOnlyDictionary<string, string>)map).Values);
627         }
628 #endif
629 
NewKeyValuePair(TKey key, TValue value)630         private static KeyValuePair<TKey, TValue> NewKeyValuePair<TKey, TValue>(TKey key, TValue value)
631         {
632             return new KeyValuePair<TKey, TValue>(key, value);
633         }
634     }
635 }
636