1 // ConcurrentDictionaryTests.cs
3 // Copyright (c) 2008 Jérémie "Garuma" Laval
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to deal
7 // in the Software without restriction, including without limitation the rights
8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 using System.Threading;
28 using MonoTests.System.Threading.Tasks;
29 using System.Collections;
30 using System.Collections.Generic;
31 using System.Collections.Concurrent;
34 using NUnit.Framework;
36 using NUnit.Framework.SyntaxHelpers;
39 namespace MonoTests.System.Collections.Concurrent
42 public class ConcurrentDictionaryTests
44 ConcurrentDictionary<string, int> map;
49 map = new ConcurrentDictionary<string, int> ();
55 map.TryAdd ("foo", 1);
56 map.TryAdd ("bar", 2);
61 public void AddWithoutDuplicateTest ()
66 Assert.IsTrue (map.TryGetValue("baz", out val));
67 Assert.AreEqual(2, val);
68 Assert.AreEqual(2, map["baz"]);
69 Assert.AreEqual(4, map.Count);
73 public void AddParallelWithoutDuplicateTest ()
75 ParallelTestHelper.Repeat (delegate {
79 ParallelTestHelper.ParallelStressTest (map, delegate {
80 int own = Interlocked.Increment (ref index);
82 while (!map.TryAdd ("monkey" + own.ToString (), own));
86 Assert.AreEqual (7, map.Count);
89 Assert.IsTrue (map.TryGetValue ("monkey1", out value), "#1");
90 Assert.AreEqual (1, value, "#1b");
92 Assert.IsTrue (map.TryGetValue ("monkey2", out value), "#2");
93 Assert.AreEqual (2, value, "#2b");
95 Assert.IsTrue (map.TryGetValue ("monkey3", out value), "#3");
96 Assert.AreEqual (3, value, "#3b");
98 Assert.IsTrue (map.TryGetValue ("monkey4", out value), "#4");
99 Assert.AreEqual (4, value, "#4b");
104 public void RemoveParallelTest ()
106 ParallelTestHelper.Repeat (delegate {
109 bool r1 = false, r2 = false, r3 = false;
112 ParallelTestHelper.ParallelStressTest (map, delegate {
113 int own = Interlocked.Increment (ref index);
116 r1 = map.TryRemove ("foo", out val);
119 r2 =map.TryRemove ("bar", out val);
122 r3 = map.TryRemove ("foobar", out val);
127 Assert.AreEqual (0, map.Count);
130 Assert.IsTrue (r1, "1");
131 Assert.IsTrue (r2, "2");
132 Assert.IsTrue (r3, "3");
134 Assert.IsFalse (map.TryGetValue ("foo", out value), "#1b " + value.ToString ());
135 Assert.IsFalse (map.TryGetValue ("bar", out value), "#2b");
136 Assert.IsFalse (map.TryGetValue ("foobar", out value), "#3b");
141 public void AddWithDuplicate()
143 Assert.IsFalse (map.TryAdd("foo", 6));
147 public void GetValueTest()
149 Assert.AreEqual(1, map["foo"], "#1");
150 Assert.AreEqual(2, map["bar"], "#2");
151 Assert.AreEqual(3, map.Count, "#3");
154 [Test, ExpectedException(typeof(KeyNotFoundException))]
155 public void GetValueUnknownTest()
158 Assert.IsFalse(map.TryGetValue("barfoo", out val));
163 public void ModificationTest()
168 Assert.AreEqual(9, map["foo"], "#1");
169 Assert.IsTrue(map.TryGetValue("foo", out val), "#3");
170 Assert.AreEqual(9, val, "#4");
174 public void IterateTest ()
176 string[] keys = { "foo", "bar", "foobar" };
177 int[] occurence = new int[3];
179 foreach (var kvp in map) {
180 int index = Array.IndexOf (keys, kvp.Key);
181 Assert.AreNotEqual (-1, index, "#a");
182 Assert.AreEqual (index + 1, kvp.Value, "#b");
183 Assert.That (++occurence[index], Is.LessThan (2), "#c");
188 public void GetOrAddTest ()
190 Assert.AreEqual (1, map.GetOrAdd ("foo", (_) => 12));
191 Assert.AreEqual (13, map.GetOrAdd ("baz", (_) => 13));
195 public void TryUpdateTest ()
197 Assert.IsFalse (map.TryUpdate ("foo", 12, 11));
198 Assert.AreEqual (1, map["foo"]);
199 Assert.IsTrue (map.TryUpdate ("foo", 11, 1));
200 Assert.AreEqual (11, map["foo"]);
204 public void AddOrUpdateTest ()
206 Assert.AreEqual (11, map.AddOrUpdate ("bar", (_) => 12, (_, __) => 11));
207 Assert.AreEqual (12, map.AddOrUpdate ("baz", (_) => 12, (_, __) => 11));
211 public void ContainsTest ()
213 Assert.IsTrue (map.ContainsKey ("foo"));
214 Assert.IsTrue (map.ContainsKey ("bar"));
215 Assert.IsTrue (map.ContainsKey ("foobar"));
216 Assert.IsFalse (map.ContainsKey ("baz"));
217 Assert.IsFalse (map.ContainsKey ("oof"));
220 class DumbClass : IEquatable<DumbClass>
224 public DumbClass (int foo)
235 public override bool Equals (object rhs)
237 DumbClass temp = rhs as DumbClass;
238 return temp == null ? false : Equals (temp);
241 public bool Equals (DumbClass rhs)
243 return this.foo == rhs.foo;
246 public override int GetHashCode ()
253 public void SameHashCodeInsertTest ()
255 var classMap = new ConcurrentDictionary<DumbClass, string> ();
257 var class1 = new DumbClass (1);
258 var class2 = new DumbClass (2);
260 Assert.IsTrue (classMap.TryAdd (class1, "class1"), "class 1");
261 Console.WriteLine ();
262 Assert.IsTrue (classMap.TryAdd (class2, "class2"), "class 2");
264 Assert.AreEqual ("class1", classMap[class1], "class 1 check");
265 Assert.AreEqual ("class2", classMap[class2], "class 2 check");
269 public void InitWithEnumerableTest ()
271 int[] data = {1,2,3,4,5,6,7,8,9,10};
272 var ndic = data.ToDictionary (x => x);
273 var cdic = new ConcurrentDictionary<int, int> (ndic);
275 foreach (var index in data) {
276 Assert.IsTrue (cdic.ContainsKey (index));
278 Assert.IsTrue (cdic.TryGetValue (index, out val));
279 Assert.AreEqual (index, val);
284 public void QueryWithSameHashCodeTest ()
286 var ids = new long[] {
298 var dict = new ConcurrentDictionary<long, long>();
301 for (var i = 0; i < 20; i++)
302 dict[-i] = -i * 1000;
304 foreach (var id in ids)
305 Assert.IsFalse (dict.TryGetValue (id, out result), id.ToString ());
307 foreach (var id in ids) {
308 Assert.IsTrue (dict.TryAdd (id, id));
309 Assert.AreEqual (id, dict[id]);
312 foreach (var id in ids) {
313 Assert.IsTrue (dict.TryRemove (id, out result));
314 Assert.AreEqual (id, result);
317 foreach (var id in ids)
318 Assert.IsFalse (dict.TryGetValue (id, out result), id.ToString () + " (second)");
322 public void NullArgumentsTest ()
324 AssertThrowsArgumentNullException (() => { var x = map[null]; });
325 AssertThrowsArgumentNullException (() => map[null] = 0);
326 AssertThrowsArgumentNullException (() => map.AddOrUpdate (null, k => 0, (k, v) => v));
327 AssertThrowsArgumentNullException (() => map.AddOrUpdate ("", null, (k, v) => v));
328 AssertThrowsArgumentNullException (() => map.AddOrUpdate ("", k => 0, null));
329 AssertThrowsArgumentNullException (() => map.AddOrUpdate (null, 0, (k, v) => v));
330 AssertThrowsArgumentNullException (() => map.AddOrUpdate ("", 0, null));
331 AssertThrowsArgumentNullException (() => map.ContainsKey (null));
332 AssertThrowsArgumentNullException (() => map.GetOrAdd (null, 0));
334 AssertThrowsArgumentNullException (() => map.TryGetValue (null, out value));
335 AssertThrowsArgumentNullException (() => map.TryRemove (null, out value));
336 AssertThrowsArgumentNullException (() => map.TryUpdate (null, 0, 0));
340 public void IDictionaryNullOnNonExistingKey ()
342 IDictionary dict = new ConcurrentDictionary<long, string> ();
343 object val = dict [1234L];
347 void AssertThrowsArgumentNullException (Action action)
351 Assert.Fail ("Expected ArgumentNullException.");
352 } catch (ArgumentNullException ex) {
357 public void ContainsKeyPairTest ()
359 var validKeyPair = new KeyValuePair<string, string> ("key", "validValue");
360 var wrongKeyPair = new KeyValuePair<string, string> ("key", "wrongValue");
362 IDictionary<string, string> dict = new ConcurrentDictionary<string, string> ();
363 dict.Add (validKeyPair);
365 Assert.IsTrue (dict.Contains (validKeyPair));
366 Assert.IsFalse (dict.Contains (wrongKeyPair));