update .sln too.
[mono.git] / mcs / class / corlib / Test / System.Threading / CancellationTokenSourceTest.cs
1 //
2 // CancellationTokenSourceTest.cs
3 //
4 // Authors:
5 //       Marek Safar (marek.safar@gmail.com)
6 //       Jeremie Laval (jeremie.laval@gmail.com)
7 //
8 // Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
29
30 #if NET_4_0
31
32 using System;
33 using System.Threading;
34 using NUnit.Framework;
35 using System.Threading.Tasks;
36 using MonoTests.System.Threading.Tasks;
37
38 namespace MonoTests.System.Threading
39 {
40         [TestFixture]
41         public class CancellationTokenSourceTest
42         {
43 #if NET_4_5
44
45                 [Test]
46                 public void Ctor_Invalid ()
47                 {
48                         try {
49                                 new CancellationTokenSource (-4);
50                                 Assert.Fail ("#1");
51                         } catch (ArgumentException) {
52                         }
53                 }
54
55                 [Test]
56                 public void Ctor_Timeout ()
57                 {
58                         int called = 0;
59                         var cts = new CancellationTokenSource (TimeSpan.FromMilliseconds (20));
60                         cts.Token.Register (() => called++);
61                         Thread.Sleep (50);
62                         Assert.AreEqual (1, called, "#1");
63                 }
64
65                 [Test]
66                 public void CancelAfter ()
67                 {
68                         int called = 0;
69                         var cts = new CancellationTokenSource ();
70                         cts.Token.Register (() => called++);
71                         cts.CancelAfter (20);
72                         Thread.Sleep (50);
73                         Assert.AreEqual (1, called, "#1");
74                 }
75
76                 [Test]
77                 public void CancelAfter_Invalid ()
78                 {
79                         var cts = new CancellationTokenSource ();
80                         try {
81                                 cts.CancelAfter (-9);
82                                 Assert.Fail ("#1");
83                         } catch (ArgumentException) {
84                         }
85                 }
86
87                 [Test]
88                 public void CancelAfter_Disposed ()
89                 {
90                         int called = 0;
91                         var cts = new CancellationTokenSource ();
92                         cts.Token.Register (() => called++);
93                         cts.CancelAfter (20);
94                         cts.Dispose ();
95                         Thread.Sleep (50);
96                         Assert.AreEqual (0, called, "#1");
97                 }
98
99 #endif
100
101                 [Test]
102                 public void Token ()
103                 {
104                         CancellationTokenSource cts = new CancellationTokenSource ();
105                         Assert.IsTrue (cts.Token.CanBeCanceled, "#1");
106                         Assert.IsFalse (cts.Token.IsCancellationRequested, "#2");
107                         Assert.IsNotNull (cts.Token.WaitHandle, "#3");
108                 }
109
110                 [Test]
111                 public void Cancel_NoRegistration ()
112                 {
113                         CancellationTokenSource cts = new CancellationTokenSource ();
114                         cts.Cancel ();
115                 }
116
117                 [Test]
118                 public void Cancel ()
119                 {
120                         var cts = new CancellationTokenSource ();
121
122                         int called = 0;
123                         cts.Token.Register (l => { Assert.AreEqual ("v", l); ++called; }, "v");
124                         cts.Cancel ();
125                         Assert.AreEqual (1, called, "#1");
126
127                         called = 0;
128                         cts.Token.Register (() => { called += 12; });
129                         cts.Cancel ();
130                         Assert.AreEqual (12, called, "#2");
131                 }
132
133
134                 [Test]
135                 public void CancelWithDispose ()
136                 {
137                         CancellationTokenSource cts = new CancellationTokenSource ();
138                         CancellationToken c = cts.Token;
139                         c.Register (() => {
140                                 cts.Dispose ();
141                         });
142
143                         int called = 0;
144                         c.Register (() => {
145                                 called++;
146                         });
147
148                         cts.Cancel ();
149                         Assert.AreEqual (1, called, "#1");
150                 }
151
152                 [Test]
153                 public void Cancel_SingleException ()
154                 {
155                         var cts = new CancellationTokenSource ();
156
157                         cts.Token.Register (() => { throw new ApplicationException (); });
158                         try {
159                                 cts.Cancel ();
160                                 Assert.Fail ("#1");
161                         } catch (AggregateException e) {
162                                 Assert.AreEqual (1, e.InnerExceptions.Count, "#2");
163                         }
164
165                         cts.Cancel ();
166                 }
167
168                 [Test]
169                 public void Cancel_MultipleExceptions ()
170                 {
171                         var cts = new CancellationTokenSource ();
172
173                         cts.Token.Register (() => { throw new ApplicationException ("1"); });
174                         cts.Token.Register (() => { throw new ApplicationException ("2"); });
175                         cts.Token.Register (() => { throw new ApplicationException ("3"); });
176
177                         try {
178                                 cts.Cancel ();
179                                 Assert.Fail ("#1");
180                         } catch (AggregateException e) {
181                                 Assert.AreEqual (3, e.InnerExceptions.Count, "#2");
182                         }
183
184                         cts.Cancel ();
185
186                         try {
187                                 cts.Token.Register (() => { throw new ApplicationException ("1"); });
188                                 Assert.Fail ("#11");
189                         } catch (ApplicationException) {
190                         }
191
192                         cts.Cancel ();
193                 }
194
195                 [Test]
196                 public void Cancel_MultipleException_Recursive ()
197                 {
198                         CancellationTokenSource cts = new CancellationTokenSource ();
199                         CancellationToken c = cts.Token;
200                         c.Register (() => {
201                                 cts.Cancel ();
202                         });
203
204                         c.Register (() => {
205                                 throw new ApplicationException ();
206                         });
207
208                         c.Register (() => {
209                                 throw new NotSupportedException ();
210                         });
211
212                         try {
213                                 cts.Cancel (false);
214                                 Assert.Fail ("#1");
215                         } catch (AggregateException e) {
216                                 Assert.AreEqual (2, e.InnerExceptions.Count, "#2");
217                         }
218                 }
219
220                 [Test]
221                 public void Cancel_MultipleExceptionsFirstThrows ()
222                 {
223                         var cts = new CancellationTokenSource ();
224
225                         cts.Token.Register (() => { throw new ApplicationException ("1"); });
226                         cts.Token.Register (() => { throw new ApplicationException ("2"); });
227                         cts.Token.Register (() => { throw new ApplicationException ("3"); });
228
229                         try {
230                                 cts.Cancel (true);
231                                 Assert.Fail ("#1");
232                         } catch (ApplicationException) {
233                         }
234
235                         cts.Cancel ();
236                 }
237
238                 [Test]
239                 public void CreateLinkedTokenSource_InvalidArguments ()
240                 {
241                         var cts = new CancellationTokenSource ();
242                         var token = cts.Token;
243
244                         try {
245                                 CancellationTokenSource.CreateLinkedTokenSource (null);
246                                 Assert.Fail ("#1");
247                         } catch (ArgumentNullException) {
248                         }
249
250                         try {
251                                 CancellationTokenSource.CreateLinkedTokenSource (new CancellationToken[0]);
252                                 Assert.Fail ("#2");
253                         } catch (ArgumentException) {
254                         }
255                 }
256
257                 [Test]
258                 public void CreateLinkedTokenSource ()
259                 {
260                         var cts = new CancellationTokenSource ();
261                         cts.Cancel ();
262
263                         var linked = CancellationTokenSource.CreateLinkedTokenSource (cts.Token);
264                         Assert.IsTrue (linked.IsCancellationRequested, "#1");
265
266                         linked = CancellationTokenSource.CreateLinkedTokenSource (new CancellationToken ());
267                         Assert.IsFalse (linked.IsCancellationRequested, "#2");
268                 }
269
270                 [Test]
271                 public void Dispose ()
272                 {
273                         var cts = new CancellationTokenSource ();
274                         var token = cts.Token;
275
276                         cts.Dispose ();
277                         cts.Dispose ();
278                         var b = cts.IsCancellationRequested;
279                         token.ThrowIfCancellationRequested ();
280
281                         try {
282                                 cts.Cancel ();
283                                 Assert.Fail ("#1");
284                         } catch (ObjectDisposedException) {
285                         }
286
287                         try {
288                                 var t = cts.Token;
289                                 Assert.Fail ("#2");
290                         } catch (ObjectDisposedException) {
291                         }
292
293                         try {
294                                 token.Register (() => { });
295                                 Assert.Fail ("#3");
296                         } catch (ObjectDisposedException) {
297                         }
298
299                         try {
300                                 var wh = token.WaitHandle;
301                                 Assert.Fail ("#4");
302                         } catch (ObjectDisposedException) {
303                         }
304
305                         try {
306                                 CancellationTokenSource.CreateLinkedTokenSource (token);
307                                 Assert.Fail ("#5");
308                         } catch (ObjectDisposedException) {
309                         }
310
311 #if NET_4_5
312                         try {
313                                 cts.CancelAfter (1);
314                                 Assert.Fail ("#6");
315                         } catch (ObjectDisposedException) {
316                         }
317 #endif
318                 }
319
320                 [Test]
321                 public void RegisterThenDispose ()
322                 {
323                         var cts1 = new CancellationTokenSource ();
324                         var reg1 = cts1.Token.Register (() => { throw new ApplicationException (); });
325
326                         var cts2 = new CancellationTokenSource ();
327                         var reg2 = cts2.Token.Register (() => { throw new ApplicationException (); });
328
329                         Assert.AreNotEqual (cts1, cts2, "#1");
330                         Assert.AreNotSame (cts1, cts2, "#2");
331
332                         reg1.Dispose ();
333                         cts1.Cancel ();
334
335                         try {
336                                 cts2.Cancel ();
337                                 Assert.Fail ("#3");
338                         } catch (AggregateException) {
339                         }
340                 }
341
342                 [Test]
343                 public void RegisterWhileCancelling ()
344                 {
345                         var cts = new CancellationTokenSource ();
346                         var mre = new ManualResetEvent (false);
347                         var mre2 = new ManualResetEvent (false);
348                         int called = 0;
349
350                         cts.Token.Register (() => {
351                                 Assert.IsTrue (cts.IsCancellationRequested, "#10");
352                                 Assert.IsTrue (cts.Token.WaitHandle.WaitOne (0), "#11");
353                                 mre2.Set ();
354                                 mre.WaitOne (3000);
355                                 called += 11;
356                         });
357
358                         var t = Task.Factory.StartNew (() => { cts.Cancel (); });
359
360                         Assert.IsTrue (mre2.WaitOne (1000), "#0");
361                         cts.Token.Register (() => { called++; });
362                         Assert.AreEqual (1, called, "#1");
363                         Assert.IsFalse (t.IsCompleted, "#2");
364
365                         mre.Set ();
366                         Assert.IsTrue (t.Wait (1000), "#3");
367                         Assert.AreEqual (12, called, "#4");
368                 }
369
370                 [Test]
371                 public void ReEntrantRegistrationTest ()
372                 {
373                         bool unregister = false;
374                         bool register = false;
375                         var source = new CancellationTokenSource ();
376                         var token = source.Token;
377
378                         var reg = new CancellationTokenRegistration ();
379                         Console.WriteLine ("Test1");
380                         token.Register (() => reg.Dispose ());
381                         reg = token.Register (() => unregister = true);
382                         token.Register (() => { Console.WriteLine ("Gnyah"); token.Register (() => register = true); });
383                         source.Cancel ();
384
385                         Assert.IsFalse (unregister);
386                         Assert.IsTrue (register);
387                 }
388
389                 [Test]
390                 public void DisposeAfterRegistrationTest ()
391                 {
392                         var source = new CancellationTokenSource ();
393                         bool ran = false;
394                         var req = source.Token.Register (() => ran = true);
395                         source.Dispose ();
396                         req.Dispose ();
397                         Assert.IsFalse (ran);
398                 }
399
400                 [Test]
401                 public void CancelLinkedTokenSource ()
402                 {
403                         var cts = new CancellationTokenSource ();
404                         bool canceled = false;
405                         cts.Token.Register (() => canceled = true);
406
407                         using (var linked = CancellationTokenSource.CreateLinkedTokenSource (cts.Token))
408                                 ;
409
410                         Assert.IsFalse (canceled, "#1");
411                         Assert.IsFalse (cts.IsCancellationRequested, "#2");
412
413                         cts.Cancel ();
414
415                         Assert.IsTrue (canceled, "#3");
416                 }
417
418                 [Test]
419                 public void ConcurrentCancelLinkedTokenSourceWhileDisposing ()
420                 {
421                         ParallelTestHelper.Repeat (delegate {
422                                 var src = new CancellationTokenSource ();
423                                 var linked = CancellationTokenSource.CreateLinkedTokenSource (src.Token);
424                                 var cntd = new CountdownEvent (2);
425
426                                 var t1 = new Thread (() => {
427                                         if (!cntd.Signal ())
428                                                 cntd.Wait (200);
429                                         src.Cancel ();
430                                 });
431                                 var t2 = new Thread (() => {
432                                         if (!cntd.Signal ())
433                                                 cntd.Wait (200);
434                                         linked.Dispose ();
435                                 });
436
437                                 t1.Start ();
438                                 t2.Start ();
439                                 t1.Join (500);
440                                 t2.Join (500);
441                         }, 500);
442                 }
443         }
444 }
445
446 #endif
447