• 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 //
5 // Use of this source code is governed by a BSD-style
6 // license that can be found in the LICENSE file or at
7 // https://developers.google.com/open-source/licenses/bsd
8 #endregion
9 
10 using System;
11 using System.Collections.Generic;
12 using Google.Protobuf.TestProtos;
13 using NUnit.Framework;
14 using System.Collections;
15 using System.Linq;
16 
17 namespace Google.Protobuf.Collections
18 {
19     /// <summary>
20     /// Tests for MapField which aren't reliant on the encoded format -
21     /// tests for serialization/deserialization are part of GeneratedMessageTest.
22     /// </summary>
23     public class MapFieldTest
24     {
25         [Test]
Clone_ClonesMessages()26         public void Clone_ClonesMessages()
27         {
28             var message = new ForeignMessage { C = 20 };
29             var map = new MapField<string, ForeignMessage> { { "x", message } };
30             var clone = map.Clone();
31             map["x"].C = 30;
32             Assert.AreEqual(20, clone["x"].C);
33         }
34 
35         [Test]
NullValuesProhibited()36         public void NullValuesProhibited()
37         {
38             TestNullValues<int?>(0);
39             TestNullValues("");
40             TestNullValues(new TestAllTypes());
41         }
42 
TestNullValues(T nonNullValue)43         private void TestNullValues<T>(T nonNullValue)
44         {
45             var map = new MapField<int, T>();
46             var nullValue = (T) (object) null;
47             Assert.Throws<ArgumentNullException>(() => map.Add(0, nullValue));
48             Assert.Throws<ArgumentNullException>(() => map[0] = nullValue);
49             map.Add(1, nonNullValue);
50             map[1] = nonNullValue;
51         }
52 
53         [Test]
Add_ForbidsNullKeys()54         public void Add_ForbidsNullKeys()
55         {
56             var map = new MapField<string, ForeignMessage>();
57             Assert.Throws<ArgumentNullException>(() => map.Add(null, new ForeignMessage()));
58         }
59 
60         [Test]
Indexer_ForbidsNullKeys()61         public void Indexer_ForbidsNullKeys()
62         {
63             var map = new MapField<string, ForeignMessage>();
64             Assert.Throws<ArgumentNullException>(() => map[null] = new ForeignMessage());
65         }
66 
67         [Test]
AddPreservesInsertionOrder()68         public void AddPreservesInsertionOrder()
69         {
70             var map = new MapField<string, string>();
71             map.Add("a", "v1");
72             map.Add("b", "v2");
73             map.Add("c", "v3");
74             map.Remove("b");
75             map.Add("d", "v4");
76             CollectionAssert.AreEqual(new[] { "a", "c", "d" }, map.Keys);
77             CollectionAssert.AreEqual(new[] { "v1", "v3", "v4" }, map.Values);
78         }
79 
80         [Test]
EqualityIsOrderInsensitive()81         public void EqualityIsOrderInsensitive()
82         {
83             var map1 = new MapField<string, string>();
84             map1.Add("a", "v1");
85             map1.Add("b", "v2");
86 
87             var map2 = new MapField<string, string>();
88             map2.Add("b", "v2");
89             map2.Add("a", "v1");
90 
91             EqualityTester.AssertEquality(map1, map2);
92         }
93 
94         [Test]
EqualityIsKeySensitive()95         public void EqualityIsKeySensitive()
96         {
97             var map1 = new MapField<string, string>();
98             map1.Add("first key", "v1");
99             map1.Add("second key", "v2");
100 
101             var map2 = new MapField<string, string>();
102             map2.Add("third key", "v1");
103             map2.Add("fourth key", "v2");
104 
105             EqualityTester.AssertInequality(map1, map2);
106         }
107 
108         [Test]
Equality_Simple()109         public void Equality_Simple()
110         {
111             var map = new MapField<string, string>();
112             EqualityTester.AssertEquality(map, map);
113             EqualityTester.AssertInequality(map, null);
114             Assert.IsFalse(map.Equals(new object()));
115         }
116 
117         [Test]
EqualityIsValueSensitive()118         public void EqualityIsValueSensitive()
119         {
120             // Note: Without some care, it's a little easier than one might
121             // hope to see hash collisions, but only in some environments...
122             var map1 = new MapField<string, string>();
123             map1.Add("a", "first value");
124             map1.Add("b", "second value");
125 
126             var map2 = new MapField<string, string>();
127             map2.Add("a", "third value");
128             map2.Add("b", "fourth value");
129 
130             EqualityTester.AssertInequality(map1, map2);
131         }
132 
133         [Test]
Add_Dictionary()134         public void Add_Dictionary()
135         {
136             var map1 = new MapField<string, string>
137             {
138                 { "x", "y" },
139                 { "a", "b" }
140             };
141             var map2 = new MapField<string, string>
142             {
143                 { "before", "" },
144                 map1,
145                 { "after", "" }
146             };
147             var expected = new MapField<string, string>
148             {
149                 { "before", "" },
150                 { "x", "y" },
151                 { "a", "b" },
152                 { "after", "" }
153             };
154             Assert.AreEqual(expected, map2);
155             CollectionAssert.AreEqual(new[] { "before", "x", "a", "after" }, map2.Keys);
156         }
157 
158         // General IDictionary<TKey, TValue> behavior tests
159         [Test]
Add_KeyAlreadyExists()160         public void Add_KeyAlreadyExists()
161         {
162             var map = new MapField<string, string>();
163             map.Add("foo", "bar");
164             Assert.Throws<ArgumentException>(() => map.Add("foo", "baz"));
165         }
166 
167         [Test]
Add_Pair()168         public void Add_Pair()
169         {
170             var map = new MapField<string, string>();
171             ICollection<KeyValuePair<string, string>> collection = map;
172             collection.Add(NewKeyValuePair("x", "y"));
173             Assert.AreEqual("y", map["x"]);
174             Assert.Throws<ArgumentException>(() => collection.Add(NewKeyValuePair("x", "z")));
175         }
176 
177         [Test]
Contains_Pair()178         public void Contains_Pair()
179         {
180             var map = new MapField<string, string> { { "x", "y" } };
181             ICollection<KeyValuePair<string, string>> collection = map;
182             Assert.IsTrue(collection.Contains(NewKeyValuePair("x", "y")));
183             Assert.IsFalse(collection.Contains(NewKeyValuePair("x", "z")));
184             Assert.IsFalse(collection.Contains(NewKeyValuePair("z", "y")));
185         }
186 
187         [Test]
Remove_Key()188         public void Remove_Key()
189         {
190             var map = new MapField<string, string>();
191             map.Add("foo", "bar");
192             Assert.AreEqual(1, map.Count);
193             Assert.IsFalse(map.Remove("missing"));
194             Assert.AreEqual(1, map.Count);
195             Assert.IsTrue(map.Remove("foo"));
196             Assert.AreEqual(0, map.Count);
197             Assert.Throws<ArgumentNullException>(() => map.Remove(null));
198         }
199 
200         [Test]
Remove_Pair()201         public void Remove_Pair()
202         {
203             var map = new MapField<string, string>();
204             map.Add("foo", "bar");
205             ICollection<KeyValuePair<string, string>> collection = map;
206             Assert.AreEqual(1, map.Count);
207             Assert.IsFalse(collection.Remove(NewKeyValuePair("wrong key", "bar")));
208             Assert.AreEqual(1, map.Count);
209             Assert.IsFalse(collection.Remove(NewKeyValuePair("foo", "wrong value")));
210             Assert.AreEqual(1, map.Count);
211             Assert.IsTrue(collection.Remove(NewKeyValuePair("foo", "bar")));
212             Assert.AreEqual(0, map.Count);
213             Assert.Throws<ArgumentException>(() => collection.Remove(new KeyValuePair<string, string>(null, "")));
214         }
215 
216         [Test]
CopyTo_Pair()217         public void CopyTo_Pair()
218         {
219             var map = new MapField<string, string>();
220             map.Add("foo", "bar");
221             ICollection<KeyValuePair<string, string>> collection = map;
222             KeyValuePair<string, string>[] array = new KeyValuePair<string, string>[3];
223             collection.CopyTo(array, 1);
224             Assert.AreEqual(NewKeyValuePair("foo", "bar"), array[1]);
225         }
226 
227         [Test]
Clear()228         public void Clear()
229         {
230             var map = new MapField<string, string> { { "x", "y" } };
231             Assert.AreEqual(1, map.Count);
232             map.Clear();
233             Assert.AreEqual(0, map.Count);
234             map.Add("x", "y");
235             Assert.AreEqual(1, map.Count);
236         }
237 
238         [Test]
Indexer_Get()239         public void Indexer_Get()
240         {
241             var map = new MapField<string, string> { { "x", "y" } };
242             Assert.AreEqual("y", map["x"]);
243             Assert.Throws<KeyNotFoundException>(() => { var ignored = map["z"]; });
244         }
245 
246         [Test]
Indexer_Set()247         public void Indexer_Set()
248         {
249             var map = new MapField<string, string>();
250             map["x"] = "y";
251             Assert.AreEqual("y", map["x"]);
252             map["x"] = "z"; // This won't throw, unlike Add.
253             Assert.AreEqual("z", map["x"]);
254         }
255 
256         [Test]
GetEnumerator_NonGeneric()257         public void GetEnumerator_NonGeneric()
258         {
259             IEnumerable map = new MapField<string, string> { { "x", "y" } };
260             CollectionAssert.AreEqual(new[] { new KeyValuePair<string, string>("x", "y") },
261                 map.Cast<object>().ToList());
262         }
263 
264         // Test for the explicitly-implemented non-generic IDictionary interface
265         [Test]
IDictionary_GetEnumerator()266         public void IDictionary_GetEnumerator()
267         {
268             IDictionary map = new MapField<string, string> { { "x", "y" } };
269             var enumerator = map.GetEnumerator();
270 
271             // Commented assertions show an ideal situation - it looks like
272             // the LinkedList enumerator doesn't throw when you ask for the current entry
273             // at an inappropriate time; fixing this would be more work than it's worth.
274             // Assert.Throws<InvalidOperationException>(() => enumerator.Current.GetHashCode());
275             Assert.IsTrue(enumerator.MoveNext());
276             Assert.AreEqual("x", enumerator.Key);
277             Assert.AreEqual("y", enumerator.Value);
278             Assert.AreEqual(new DictionaryEntry("x", "y"), enumerator.Current);
279             Assert.AreEqual(new DictionaryEntry("x", "y"), enumerator.Entry);
280             Assert.IsFalse(enumerator.MoveNext());
281             // Assert.Throws<InvalidOperationException>(() => enumerator.Current.GetHashCode());
282             enumerator.Reset();
283             // Assert.Throws<InvalidOperationException>(() => enumerator.Current.GetHashCode());
284             Assert.IsTrue(enumerator.MoveNext());
285             Assert.AreEqual("x", enumerator.Key); // Assume the rest are okay
286         }
287 
288         [Test]
IDictionary_Add()289         public void IDictionary_Add()
290         {
291             var map = new MapField<string, string> { { "x", "y" } };
292             IDictionary dictionary = map;
293             dictionary.Add("a", "b");
294             Assert.AreEqual("b", map["a"]);
295             Assert.Throws<ArgumentException>(() => dictionary.Add("a", "duplicate"));
296             Assert.Throws<InvalidCastException>(() => dictionary.Add(new object(), "key is bad"));
297             Assert.Throws<InvalidCastException>(() => dictionary.Add("value is bad", new object()));
298         }
299 
300         [Test]
IDictionary_Contains()301         public void IDictionary_Contains()
302         {
303             var map = new MapField<string, string> { { "x", "y" } };
304             IDictionary dictionary = map;
305 
306             Assert.IsFalse(dictionary.Contains("a"));
307             Assert.IsFalse(dictionary.Contains(5));
308             // Surprising, but IDictionary.Contains is only about keys.
309             Assert.IsFalse(dictionary.Contains(new DictionaryEntry("x", "y")));
310             Assert.IsTrue(dictionary.Contains("x"));
311         }
312 
313         [Test]
IDictionary_Remove()314         public void IDictionary_Remove()
315         {
316             var map = new MapField<string, string> { { "x", "y" } };
317             IDictionary dictionary = map;
318             dictionary.Remove("a");
319             Assert.AreEqual(1, dictionary.Count);
320             dictionary.Remove(5);
321             Assert.AreEqual(1, dictionary.Count);
322             dictionary.Remove(new DictionaryEntry("x", "y"));
323             Assert.AreEqual(1, dictionary.Count);
324             dictionary.Remove("x");
325             Assert.AreEqual(0, dictionary.Count);
326             Assert.Throws<ArgumentNullException>(() => dictionary.Remove(null));
327         }
328 
329         [Test]
IDictionary_CopyTo()330         public void IDictionary_CopyTo()
331         {
332             var map = new MapField<string, string> { { "x", "y" } };
333             IDictionary dictionary = map;
334             var array = new DictionaryEntry[3];
335             dictionary.CopyTo(array, 1);
336             CollectionAssert.AreEqual(new[] { default(DictionaryEntry), new DictionaryEntry("x", "y"), default(DictionaryEntry) },
337                 array);
338             var objectArray = new object[3];
339             dictionary.CopyTo(objectArray, 1);
340             CollectionAssert.AreEqual(new object[] { null, new DictionaryEntry("x", "y"), null },
341                 objectArray);
342         }
343 
344         [Test]
IDictionary_IsFixedSize()345         public void IDictionary_IsFixedSize()
346         {
347             var map = new MapField<string, string> { { "x", "y" } };
348             IDictionary dictionary = map;
349             Assert.IsFalse(dictionary.IsFixedSize);
350         }
351 
352         [Test]
IDictionary_Keys()353         public void IDictionary_Keys()
354         {
355             IDictionary dictionary = new MapField<string, string> { { "x", "y" } };
356             CollectionAssert.AreEqual(new[] { "x" }, dictionary.Keys);
357         }
358 
359         [Test]
IDictionary_Values()360         public void IDictionary_Values()
361         {
362             IDictionary dictionary = new MapField<string, string> { { "x", "y" } };
363             CollectionAssert.AreEqual(new[] { "y" }, dictionary.Values);
364         }
365 
366         [Test]
IDictionary_IsSynchronized()367         public void IDictionary_IsSynchronized()
368         {
369             IDictionary dictionary = new MapField<string, string> { { "x", "y" } };
370             Assert.IsFalse(dictionary.IsSynchronized);
371         }
372 
373         [Test]
IDictionary_SyncRoot()374         public void IDictionary_SyncRoot()
375         {
376             IDictionary dictionary = new MapField<string, string> { { "x", "y" } };
377             Assert.AreSame(dictionary, dictionary.SyncRoot);
378         }
379 
380         [Test]
IDictionary_Indexer_Get()381         public void IDictionary_Indexer_Get()
382         {
383             IDictionary dictionary = new MapField<string, string> { { "x", "y" } };
384             Assert.AreEqual("y", dictionary["x"]);
385             Assert.IsNull(dictionary["a"]);
386             Assert.IsNull(dictionary[5]);
387             Assert.Throws<ArgumentNullException>(() => dictionary[null].GetHashCode());
388         }
389 
390         [Test]
IDictionary_Indexer_Set()391         public void IDictionary_Indexer_Set()
392         {
393             var map = new MapField<string, string> { { "x", "y" } };
394             IDictionary dictionary = map;
395             map["a"] = "b";
396             Assert.AreEqual("b", map["a"]);
397             map["a"] = "c";
398             Assert.AreEqual("c", map["a"]);
399             Assert.Throws<InvalidCastException>(() => dictionary[5] = "x");
400             Assert.Throws<InvalidCastException>(() => dictionary["x"] = 5);
401             Assert.Throws<ArgumentNullException>(() => dictionary[null] = "z");
402             Assert.Throws<ArgumentNullException>(() => dictionary["x"] = null);
403         }
404 
405         [Test]
KeysReturnsLiveView()406         public void KeysReturnsLiveView()
407         {
408             var map = new MapField<string, string>();
409             var keys = map.Keys;
410             CollectionAssert.AreEqual(new string[0], keys);
411             map["foo"] = "bar";
412             map["x"] = "y";
413             CollectionAssert.AreEqual(new[] { "foo", "x" }, keys);
414         }
415 
416         [Test]
ValuesReturnsLiveView()417         public void ValuesReturnsLiveView()
418         {
419             var map = new MapField<string, string>();
420             var values = map.Values;
421             CollectionAssert.AreEqual(new string[0], values);
422             map["foo"] = "bar";
423             map["x"] = "y";
424             CollectionAssert.AreEqual(new[] { "bar", "y" }, values);
425         }
426 
427         // Just test keys - we know the implementation is the same for values
428         [Test]
ViewsAreReadOnly()429         public void ViewsAreReadOnly()
430         {
431             var map = new MapField<string, string>();
432             var keys = map.Keys;
433             Assert.IsTrue(keys.IsReadOnly);
434             Assert.Throws<NotSupportedException>(() => keys.Clear());
435             Assert.Throws<NotSupportedException>(() => keys.Remove("a"));
436             Assert.Throws<NotSupportedException>(() => keys.Add("a"));
437         }
438 
439         // Just test keys - we know the implementation is the same for values
440         [Test]
ViewCopyTo()441         public void ViewCopyTo()
442         {
443             var map = new MapField<string, string> { { "foo", "bar" }, { "x", "y" } };
444             var keys = map.Keys;
445             var array = new string[4];
446             Assert.Throws<ArgumentException>(() => keys.CopyTo(array, 3));
447             Assert.Throws<ArgumentOutOfRangeException>(() => keys.CopyTo(array, -1));
448             keys.CopyTo(array, 1);
449             CollectionAssert.AreEqual(new[] { null, "foo", "x", null }, array);
450         }
451 
452         // Just test keys - we know the implementation is the same for values
453         [Test]
NonGenericViewCopyTo()454         public void NonGenericViewCopyTo()
455         {
456             IDictionary map = new MapField<string, string> { { "foo", "bar" }, { "x", "y" } };
457             ICollection keys = map.Keys;
458             // Note the use of the Array type here rather than string[]
459             Array array = new string[4];
460             Assert.Throws<ArgumentException>(() => keys.CopyTo(array, 3));
461             Assert.Throws<ArgumentOutOfRangeException>(() => keys.CopyTo(array, -1));
462             keys.CopyTo(array, 1);
463             CollectionAssert.AreEqual(new[] { null, "foo", "x", null }, array);
464         }
465 
466         [Test]
KeysContains()467         public void KeysContains()
468         {
469             var map = new MapField<string, string> { { "foo", "bar" }, { "x", "y" } };
470             var keys = map.Keys;
471             Assert.IsTrue(keys.Contains("foo"));
472             Assert.IsFalse(keys.Contains("bar")); // It's a value!
473             Assert.IsFalse(keys.Contains("1"));
474             // Keys can't be null, so we should prevent contains check
475             Assert.Throws<ArgumentNullException>(() => keys.Contains(null));
476         }
477 
478         [Test]
ValuesContains()479         public void ValuesContains()
480         {
481             var map = new MapField<string, string> { { "foo", "bar" }, { "x", "y" } };
482             var values = map.Values;
483             Assert.IsTrue(values.Contains("bar"));
484             Assert.IsFalse(values.Contains("foo")); // It's a key!
485             Assert.IsFalse(values.Contains("1"));
486             // Values can be null, so this makes sense
487             Assert.IsFalse(values.Contains(null));
488         }
489 
490         [Test]
ToString_StringToString()491         public void ToString_StringToString()
492         {
493             var map = new MapField<string, string> { { "foo", "bar" }, { "x", "y" } };
494             Assert.AreEqual("{ \"foo\": \"bar\", \"x\": \"y\" }", map.ToString());
495         }
496 
497         [Test]
ToString_UnsupportedKeyType()498         public void ToString_UnsupportedKeyType()
499         {
500             var map = new MapField<byte, string> { { 10, "foo" } };
501             Assert.Throws<ArgumentException>(() => map.ToString());
502         }
503 
NewKeyValuePair(TKey key, TValue value)504         private static KeyValuePair<TKey, TValue> NewKeyValuePair<TKey, TValue>(TKey key, TValue value)
505         {
506             return new KeyValuePair<TKey, TValue>(key, value);
507         }
508     }
509 }
510