Merge pull request #409 from Alkarex/patch-1
[mono.git] / mcs / class / corlib / Test / System.Collections.Concurrent / ConcurrentDictionaryTests.cs
1 #if NET_4_0
2 // ConcurrentDictionaryTests.cs
3 //
4 // Copyright (c) 2008 Jérémie "Garuma" Laval
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a copy
7 // of this software and associated documentation files (the "Software"), to deal
8 // in the Software without restriction, including without limitation the rights
9 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 // copies of the Software, and to permit persons to whom the Software is
11 // furnished to do so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 // THE SOFTWARE.
23 //
24 //
25
26 using System;
27 using System.Linq;
28 using System.Threading;
29 using MonoTests.System.Threading.Tasks;
30 using System.Collections.Generic;
31 using System.Collections.Concurrent;
32
33 using NUnit;
34 using NUnit.Framework;
35
36 namespace MonoTests.System.Collections.Concurrent
37 {
38         [TestFixture]
39         public class ConcurrentDictionaryTests
40         {
41                 ConcurrentDictionary<string, int> map;
42                 
43                 [SetUp]
44                 public void Setup ()
45                 {
46                         map = new ConcurrentDictionary<string, int> ();
47                         AddStuff();
48                 }
49                 
50                 void AddStuff ()
51                 {
52                         map.TryAdd ("foo", 1);
53                         map.TryAdd ("bar", 2);
54                         map["foobar"] = 3;
55                 }
56                 
57                 [Test]
58                 public void AddWithoutDuplicateTest ()
59                 {
60                         map.TryAdd("baz", 2);
61                         int val;
62                         
63                         Assert.IsTrue (map.TryGetValue("baz", out val));
64                         Assert.AreEqual(2, val);
65                         Assert.AreEqual(2, map["baz"]);
66                         Assert.AreEqual(4, map.Count);
67                 }
68                 
69                 [Test]
70                 public void AddParallelWithoutDuplicateTest ()
71                 {
72                         ParallelTestHelper.Repeat (delegate {
73                                 Setup ();
74                                 int index = 0;
75                                 
76                                 ParallelTestHelper.ParallelStressTest (map, delegate {
77                                         int own = Interlocked.Increment (ref index);
78                                         
79                                         while (!map.TryAdd ("monkey" + own.ToString (), own));
80                                         
81                                 }, 4);
82                                 
83                                 Assert.AreEqual (7, map.Count);
84                                 int value;
85                                 
86                                 Assert.IsTrue (map.TryGetValue ("monkey1", out value), "#1");
87                                 Assert.AreEqual (1, value, "#1b");
88                                 
89                                 Assert.IsTrue (map.TryGetValue ("monkey2", out value), "#2");
90                                 Assert.AreEqual (2, value, "#2b");
91                                 
92                                 Assert.IsTrue (map.TryGetValue ("monkey3", out value), "#3");
93                                 Assert.AreEqual (3, value, "#3b");
94                                 
95                                 Assert.IsTrue (map.TryGetValue ("monkey4", out value), "#4");
96                                 Assert.AreEqual (4, value, "#4b");
97                         });
98                 }
99                 
100                 [Test]
101                 public void RemoveParallelTest ()
102                 {
103                         ParallelTestHelper.Repeat (delegate {
104                                 Setup ();
105                                 int index = 0;
106                                 bool r1 = false, r2 = false, r3 = false;
107                                 int val;
108                                 
109                                 ParallelTestHelper.ParallelStressTest (map, delegate {
110                                         int own = Interlocked.Increment (ref index);
111                                         switch (own) {
112                                         case 1:
113                                                 r1 = map.TryRemove ("foo", out val);
114                                                 break;
115                                         case 2:
116                                                 r2 =map.TryRemove ("bar", out val);
117                                                 break;
118                                         case 3:
119                                                 r3 = map.TryRemove ("foobar", out val);
120                                                 break;
121                                         }
122                                 }, 3);
123                                 
124                                 Assert.AreEqual (0, map.Count);
125                                 int value;
126         
127                                 Assert.IsTrue (r1, "1");
128                                 Assert.IsTrue (r2, "2");
129                                 Assert.IsTrue (r3, "3");
130                                 
131                                 Assert.IsFalse (map.TryGetValue ("foo", out value), "#1b " + value.ToString ());
132                                 Assert.IsFalse (map.TryGetValue ("bar", out value), "#2b");
133                                 Assert.IsFalse (map.TryGetValue ("foobar", out value), "#3b");
134                         });
135                 }
136                 
137                 [Test]
138                 public void AddWithDuplicate()
139                 {
140                         Assert.IsFalse (map.TryAdd("foo", 6));
141                 }
142                 
143                 [Test]
144                 public void GetValueTest()
145                 {
146                         Assert.AreEqual(1, map["foo"], "#1");
147                         Assert.AreEqual(2, map["bar"], "#2");
148                         Assert.AreEqual(3, map.Count, "#3");
149                 }
150                 
151                 [Test, ExpectedException(typeof(KeyNotFoundException))]
152                 public void GetValueUnknownTest()
153                 {
154                         int val;
155                         Assert.IsFalse(map.TryGetValue("barfoo", out val));
156                         val = map["barfoo"];
157                 }
158                 
159                 [Test]
160                 public void ModificationTest()
161                 {
162                         map["foo"] = 9;
163                         int val;
164                         
165                         Assert.AreEqual(9, map["foo"], "#1");
166                         Assert.IsTrue(map.TryGetValue("foo", out val), "#3");
167                         Assert.AreEqual(9, val, "#4");
168                 }
169
170                 [Test]
171                 public void IterateTest ()
172                 {
173                         string[] keys = { "foo", "bar", "foobar" };
174                         int[] occurence = new int[3];
175
176                         foreach (var kvp in map) {
177                                 int index = Array.IndexOf (keys, kvp.Key);
178                                 Assert.AreNotEqual (-1, index, "#a");
179                                 Assert.AreEqual (index + 1, kvp.Value, "#b");
180                                 Assert.Less (++occurence[index], 2, "#c");
181                         }
182                 }
183
184                 [Test]
185                 public void GetOrAddTest ()
186                 {
187                         Assert.AreEqual (1, map.GetOrAdd ("foo", (_) => 12));
188                         Assert.AreEqual (13, map.GetOrAdd ("baz", (_) => 13));
189                 }
190
191                 [Test]
192                 public void TryUpdateTest ()
193                 {
194                         Assert.IsFalse (map.TryUpdate ("foo", 12, 11));
195                         Assert.AreEqual (1, map["foo"]);
196                         Assert.IsTrue (map.TryUpdate ("foo", 11, 1));
197                         Assert.AreEqual (11, map["foo"]);
198                 }
199
200                 [Test]
201                 public void AddOrUpdateTest ()
202                 {
203                         Assert.AreEqual (11, map.AddOrUpdate ("bar", (_) => 12, (_, __) => 11));
204                         Assert.AreEqual (12, map.AddOrUpdate ("baz", (_) => 12, (_, __) => 11));
205                 }
206
207                 [Test]
208                 public void ContainsTest ()
209                 {
210                         Assert.IsTrue (map.ContainsKey ("foo"));
211                         Assert.IsTrue (map.ContainsKey ("bar"));
212                         Assert.IsTrue (map.ContainsKey ("foobar"));
213                         Assert.IsFalse (map.ContainsKey ("baz"));
214                         Assert.IsFalse (map.ContainsKey ("oof"));
215                 }
216
217                 class DumbClass : IEquatable<DumbClass>
218                 {
219                         int foo;
220
221                         public DumbClass (int foo)
222                         {
223                                 this.foo = foo;
224                         }
225
226                         public int Foo {
227                                 get {
228                                         return foo;
229                                 }
230                         }
231
232                         public override bool Equals (object rhs)
233                         {
234                                 DumbClass temp = rhs as DumbClass;
235                                 return temp == null ? false : Equals (temp);
236                         }
237
238                         public bool Equals (DumbClass rhs)
239                         {
240                                 return this.foo == rhs.foo;
241                         }
242
243                         public override int GetHashCode ()
244                         {
245                                 return 5;
246                         }
247                 }
248
249                 [Test]
250                 public void SameHashCodeInsertTest ()
251                 {
252                         var classMap = new ConcurrentDictionary<DumbClass, string> ();
253
254                         var class1 = new DumbClass (1);
255                         var class2 = new DumbClass (2);
256
257                         Assert.IsTrue (classMap.TryAdd (class1, "class1"), "class 1");
258                         Console.WriteLine ();
259                         Assert.IsTrue (classMap.TryAdd (class2, "class2"), "class 2");
260
261                         Assert.AreEqual ("class1", classMap[class1], "class 1 check");
262                         Assert.AreEqual ("class2", classMap[class2], "class 2 check");
263                 }
264
265                 [Test]
266                 public void InitWithEnumerableTest ()
267                 {
268                         int[] data = {1,2,3,4,5,6,7,8,9,10};
269                         var ndic = data.ToDictionary (x => x);
270                         var cdic = new ConcurrentDictionary<int, int> (ndic);
271
272                         foreach (var index in data) {
273                                 Assert.IsTrue (cdic.ContainsKey (index));
274                                 int val;
275                                 Assert.IsTrue (cdic.TryGetValue (index, out val));
276                                 Assert.AreEqual (index, val);
277                         }
278                 }
279
280                 [Test]
281                 public void QueryWithSameHashCodeTest ()
282                 {
283                         var ids = new long[] {
284                                 34359738370, 
285                                 34359738371, 
286                                 34359738372, 
287                                 34359738373, 
288                                 34359738374, 
289                                 34359738375, 
290                                 34359738376, 
291                                 34359738377, 
292                                 34359738420
293                         };
294
295                         var dict = new ConcurrentDictionary<long, long>();
296                         long result;
297
298                         for (var i = 0; i < 20; i++)
299                                 dict[-i] = -i * 1000;
300
301                         foreach (var id in ids)
302                                 Assert.IsFalse (dict.TryGetValue (id, out result), id.ToString ());
303
304                         foreach (var id in ids) {
305                                 Assert.IsTrue (dict.TryAdd (id, id));
306                                 Assert.AreEqual (id, dict[id]);
307                         }
308
309                         foreach (var id in ids) {
310                                 Assert.IsTrue (dict.TryRemove (id, out result));
311                                 Assert.AreEqual (id, result);
312                         }
313
314                         foreach (var id in ids)
315                                 Assert.IsFalse (dict.TryGetValue (id, out result), id.ToString () + " (second)");
316                 }
317
318                 [Test]
319                 public void NullArgumentsTest ()
320                 {
321                         AssertThrowsArgumentNullException (() => { var x = map[null]; });
322                         AssertThrowsArgumentNullException (() => map[null] = 0);
323                         AssertThrowsArgumentNullException (() => map.AddOrUpdate (null, k => 0, (k, v) => v));
324                         AssertThrowsArgumentNullException (() => map.AddOrUpdate ("", null, (k, v) => v));
325                         AssertThrowsArgumentNullException (() => map.AddOrUpdate ("", k => 0, null));
326                         AssertThrowsArgumentNullException (() => map.AddOrUpdate (null, 0, (k, v) => v));
327                         AssertThrowsArgumentNullException (() => map.AddOrUpdate ("", 0, null));
328                         AssertThrowsArgumentNullException (() => map.ContainsKey (null));
329                         AssertThrowsArgumentNullException (() => map.GetOrAdd (null, 0));
330                         int value;
331                         AssertThrowsArgumentNullException (() => map.TryGetValue (null, out value));
332                         AssertThrowsArgumentNullException (() => map.TryRemove (null, out value));
333                         AssertThrowsArgumentNullException (() => map.TryUpdate (null, 0, 0));
334                 } 
335
336                 void AssertThrowsArgumentNullException (Action action)
337                 {
338                         try {
339                                 action ();
340                                 Assert.Fail ("Expected ArgumentNullException.");
341                         } catch (ArgumentNullException ex) {
342                         }
343                 }
344         }
345 }
346 #endif