[boehm] Implement the finalization extension API.
[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;
31 using System.Collections.Generic;
32 using System.Collections.Concurrent;
33
34 using NUnit;
35 using NUnit.Framework;
36 #if !MOBILE
37 using NUnit.Framework.SyntaxHelpers;
38 #endif
39
40 namespace MonoTests.System.Collections.Concurrent
41 {
42         [TestFixture]
43         public class ConcurrentDictionaryTests
44         {
45                 ConcurrentDictionary<string, int> map;
46                 
47                 [SetUp]
48                 public void Setup ()
49                 {
50                         map = new ConcurrentDictionary<string, int> ();
51                         AddStuff();
52                 }
53                 
54                 void AddStuff ()
55                 {
56                         map.TryAdd ("foo", 1);
57                         map.TryAdd ("bar", 2);
58                         map["foobar"] = 3;
59                 }
60                 
61                 [Test]
62                 public void AddWithoutDuplicateTest ()
63                 {
64                         map.TryAdd("baz", 2);
65                         int val;
66                         
67                         Assert.IsTrue (map.TryGetValue("baz", out val));
68                         Assert.AreEqual(2, val);
69                         Assert.AreEqual(2, map["baz"]);
70                         Assert.AreEqual(4, map.Count);
71                 }
72                 
73                 [Test]
74                 public void AddParallelWithoutDuplicateTest ()
75                 {
76                         ParallelTestHelper.Repeat (delegate {
77                                 Setup ();
78                                 int index = 0;
79                                 
80                                 ParallelTestHelper.ParallelStressTest (map, delegate {
81                                         int own = Interlocked.Increment (ref index);
82                                         
83                                         while (!map.TryAdd ("monkey" + own.ToString (), own));
84                                         
85                                 }, 4);
86                                 
87                                 Assert.AreEqual (7, map.Count);
88                                 int value;
89                                 
90                                 Assert.IsTrue (map.TryGetValue ("monkey1", out value), "#1");
91                                 Assert.AreEqual (1, value, "#1b");
92                                 
93                                 Assert.IsTrue (map.TryGetValue ("monkey2", out value), "#2");
94                                 Assert.AreEqual (2, value, "#2b");
95                                 
96                                 Assert.IsTrue (map.TryGetValue ("monkey3", out value), "#3");
97                                 Assert.AreEqual (3, value, "#3b");
98                                 
99                                 Assert.IsTrue (map.TryGetValue ("monkey4", out value), "#4");
100                                 Assert.AreEqual (4, value, "#4b");
101                         });
102                 }
103                 
104                 [Test]
105                 public void RemoveParallelTest ()
106                 {
107                         ParallelTestHelper.Repeat (delegate {
108                                 Setup ();
109                                 int index = 0;
110                                 bool r1 = false, r2 = false, r3 = false;
111                                 int val;
112                                 
113                                 ParallelTestHelper.ParallelStressTest (map, delegate {
114                                         int own = Interlocked.Increment (ref index);
115                                         switch (own) {
116                                         case 1:
117                                                 r1 = map.TryRemove ("foo", out val);
118                                                 break;
119                                         case 2:
120                                                 r2 =map.TryRemove ("bar", out val);
121                                                 break;
122                                         case 3:
123                                                 r3 = map.TryRemove ("foobar", out val);
124                                                 break;
125                                         }
126                                 }, 3);
127                                 
128                                 Assert.AreEqual (0, map.Count);
129                                 int value;
130         
131                                 Assert.IsTrue (r1, "1");
132                                 Assert.IsTrue (r2, "2");
133                                 Assert.IsTrue (r3, "3");
134                                 
135                                 Assert.IsFalse (map.TryGetValue ("foo", out value), "#1b " + value.ToString ());
136                                 Assert.IsFalse (map.TryGetValue ("bar", out value), "#2b");
137                                 Assert.IsFalse (map.TryGetValue ("foobar", out value), "#3b");
138                         });
139                 }
140                 
141                 [Test]
142                 public void AddWithDuplicate()
143                 {
144                         Assert.IsFalse (map.TryAdd("foo", 6));
145                 }
146                 
147                 [Test]
148                 public void GetValueTest()
149                 {
150                         Assert.AreEqual(1, map["foo"], "#1");
151                         Assert.AreEqual(2, map["bar"], "#2");
152                         Assert.AreEqual(3, map.Count, "#3");
153                 }
154                 
155                 [Test, ExpectedException(typeof(KeyNotFoundException))]
156                 public void GetValueUnknownTest()
157                 {
158                         int val;
159                         Assert.IsFalse(map.TryGetValue("barfoo", out val));
160                         val = map["barfoo"];
161                 }
162                 
163                 [Test]
164                 public void ModificationTest()
165                 {
166                         map["foo"] = 9;
167                         int val;
168                         
169                         Assert.AreEqual(9, map["foo"], "#1");
170                         Assert.IsTrue(map.TryGetValue("foo", out val), "#3");
171                         Assert.AreEqual(9, val, "#4");
172                 }
173
174                 [Test]
175                 public void IterateTest ()
176                 {
177                         string[] keys = { "foo", "bar", "foobar" };
178                         int[] occurence = new int[3];
179
180                         foreach (var kvp in map) {
181                                 int index = Array.IndexOf (keys, kvp.Key);
182                                 Assert.AreNotEqual (-1, index, "#a");
183                                 Assert.AreEqual (index + 1, kvp.Value, "#b");
184                                 Assert.That (++occurence[index], Is.LessThan (2), "#c");
185                         }
186                 }
187
188                 [Test]
189                 public void GetOrAddTest ()
190                 {
191                         Assert.AreEqual (1, map.GetOrAdd ("foo", (_) => 12));
192                         Assert.AreEqual (13, map.GetOrAdd ("baz", (_) => 13));
193                 }
194
195                 [Test]
196                 public void TryUpdateTest ()
197                 {
198                         Assert.IsFalse (map.TryUpdate ("foo", 12, 11));
199                         Assert.AreEqual (1, map["foo"]);
200                         Assert.IsTrue (map.TryUpdate ("foo", 11, 1));
201                         Assert.AreEqual (11, map["foo"]);
202                 }
203
204                 [Test]
205                 public void AddOrUpdateTest ()
206                 {
207                         Assert.AreEqual (11, map.AddOrUpdate ("bar", (_) => 12, (_, __) => 11));
208                         Assert.AreEqual (12, map.AddOrUpdate ("baz", (_) => 12, (_, __) => 11));
209                 }
210
211                 [Test]
212                 public void ContainsTest ()
213                 {
214                         Assert.IsTrue (map.ContainsKey ("foo"));
215                         Assert.IsTrue (map.ContainsKey ("bar"));
216                         Assert.IsTrue (map.ContainsKey ("foobar"));
217                         Assert.IsFalse (map.ContainsKey ("baz"));
218                         Assert.IsFalse (map.ContainsKey ("oof"));
219                 }
220
221                 class DumbClass : IEquatable<DumbClass>
222                 {
223                         int foo;
224
225                         public DumbClass (int foo)
226                         {
227                                 this.foo = foo;
228                         }
229
230                         public int Foo {
231                                 get {
232                                         return foo;
233                                 }
234                         }
235
236                         public override bool Equals (object rhs)
237                         {
238                                 DumbClass temp = rhs as DumbClass;
239                                 return temp == null ? false : Equals (temp);
240                         }
241
242                         public bool Equals (DumbClass rhs)
243                         {
244                                 return this.foo == rhs.foo;
245                         }
246
247                         public override int GetHashCode ()
248                         {
249                                 return 5;
250                         }
251                 }
252
253                 [Test]
254                 public void SameHashCodeInsertTest ()
255                 {
256                         var classMap = new ConcurrentDictionary<DumbClass, string> ();
257
258                         var class1 = new DumbClass (1);
259                         var class2 = new DumbClass (2);
260
261                         Assert.IsTrue (classMap.TryAdd (class1, "class1"), "class 1");
262                         Console.WriteLine ();
263                         Assert.IsTrue (classMap.TryAdd (class2, "class2"), "class 2");
264
265                         Assert.AreEqual ("class1", classMap[class1], "class 1 check");
266                         Assert.AreEqual ("class2", classMap[class2], "class 2 check");
267                 }
268
269                 [Test]
270                 public void InitWithEnumerableTest ()
271                 {
272                         int[] data = {1,2,3,4,5,6,7,8,9,10};
273                         var ndic = data.ToDictionary (x => x);
274                         var cdic = new ConcurrentDictionary<int, int> (ndic);
275
276                         foreach (var index in data) {
277                                 Assert.IsTrue (cdic.ContainsKey (index));
278                                 int val;
279                                 Assert.IsTrue (cdic.TryGetValue (index, out val));
280                                 Assert.AreEqual (index, val);
281                         }
282                 }
283
284                 [Test]
285                 public void QueryWithSameHashCodeTest ()
286                 {
287                         var ids = new long[] {
288                                 34359738370, 
289                                 34359738371, 
290                                 34359738372, 
291                                 34359738373, 
292                                 34359738374, 
293                                 34359738375, 
294                                 34359738376, 
295                                 34359738377, 
296                                 34359738420
297                         };
298
299                         var dict = new ConcurrentDictionary<long, long>();
300                         long result;
301
302                         for (var i = 0; i < 20; i++)
303                                 dict[-i] = -i * 1000;
304
305                         foreach (var id in ids)
306                                 Assert.IsFalse (dict.TryGetValue (id, out result), id.ToString ());
307
308                         foreach (var id in ids) {
309                                 Assert.IsTrue (dict.TryAdd (id, id));
310                                 Assert.AreEqual (id, dict[id]);
311                         }
312
313                         foreach (var id in ids) {
314                                 Assert.IsTrue (dict.TryRemove (id, out result));
315                                 Assert.AreEqual (id, result);
316                         }
317
318                         foreach (var id in ids)
319                                 Assert.IsFalse (dict.TryGetValue (id, out result), id.ToString () + " (second)");
320                 }
321
322                 [Test]
323                 public void NullArgumentsTest ()
324                 {
325                         AssertThrowsArgumentNullException (() => { var x = map[null]; });
326                         AssertThrowsArgumentNullException (() => map[null] = 0);
327                         AssertThrowsArgumentNullException (() => map.AddOrUpdate (null, k => 0, (k, v) => v));
328                         AssertThrowsArgumentNullException (() => map.AddOrUpdate ("", null, (k, v) => v));
329                         AssertThrowsArgumentNullException (() => map.AddOrUpdate ("", k => 0, null));
330                         AssertThrowsArgumentNullException (() => map.AddOrUpdate (null, 0, (k, v) => v));
331                         AssertThrowsArgumentNullException (() => map.AddOrUpdate ("", 0, null));
332                         AssertThrowsArgumentNullException (() => map.ContainsKey (null));
333                         AssertThrowsArgumentNullException (() => map.GetOrAdd (null, 0));
334                         int value;
335                         AssertThrowsArgumentNullException (() => map.TryGetValue (null, out value));
336                         AssertThrowsArgumentNullException (() => map.TryRemove (null, out value));
337                         AssertThrowsArgumentNullException (() => map.TryUpdate (null, 0, 0));
338                 }
339
340                 [Test]
341                 public void IDictionaryNullOnNonExistingKey ()
342                 {
343                         IDictionary dict = new ConcurrentDictionary<long, string> ();
344                         object val = dict [1234L];
345                         Assert.IsNull (val);
346                 }
347
348                 void AssertThrowsArgumentNullException (Action action)
349                 {
350                         try {
351                                 action ();
352                                 Assert.Fail ("Expected ArgumentNullException.");
353                         } catch (ArgumentNullException ex) {
354                         }
355                 }
356         }
357 }
358 #endif