[eglib] Prefer <langinfo.h> to <localcharset.h>
[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 (50);
94                         cts.Dispose ();
95                         Thread.Sleep (100);
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 Cancel_Order ()
136                 {
137                         var cts = new CancellationTokenSource ();
138                         var current = 0;
139                         Action<object> a = x => { Assert.AreEqual(current, x); current++; };
140
141                         cts.Token.Register (a, 2);
142                         cts.Token.Register (a, 1);
143                         cts.Token.Register (a, 0);
144                         cts.Cancel ();
145                 }
146
147
148                 [Test]
149                 public void CancelWithDispose ()
150                 {
151                         CancellationTokenSource cts = new CancellationTokenSource ();
152                         CancellationToken c = cts.Token;
153                         c.Register (() => {
154                                 cts.Dispose ();
155                         });
156
157                         int called = 0;
158                         c.Register (() => {
159                                 called++;
160                         });
161
162                         cts.Cancel ();
163                         Assert.AreEqual (1, called, "#1");
164                 }
165
166                 [Test]
167                 public void Cancel_SingleException ()
168                 {
169                         var cts = new CancellationTokenSource ();
170
171                         cts.Token.Register (() => { throw new ApplicationException (); });
172                         try {
173                                 cts.Cancel ();
174                                 Assert.Fail ("#1");
175                         } catch (AggregateException e) {
176                                 Assert.AreEqual (1, e.InnerExceptions.Count, "#2");
177                         }
178
179                         cts.Cancel ();
180                 }
181
182                 [Test]
183                 public void Cancel_MultipleExceptions ()
184                 {
185                         var cts = new CancellationTokenSource ();
186
187                         cts.Token.Register (() => { throw new ApplicationException ("1"); });
188                         cts.Token.Register (() => { throw new ApplicationException ("2"); });
189                         cts.Token.Register (() => { throw new ApplicationException ("3"); });
190
191                         try {
192                                 cts.Cancel ();
193                                 Assert.Fail ("#1");
194                         } catch (AggregateException e) {
195                                 Assert.AreEqual (3, e.InnerExceptions.Count, "#2");
196                         }
197
198                         cts.Cancel ();
199
200                         try {
201                                 cts.Token.Register (() => { throw new ApplicationException ("1"); });
202                                 Assert.Fail ("#11");
203                         } catch (ApplicationException) {
204                         }
205
206                         cts.Cancel ();
207                 }
208
209                 [Test]
210                 public void Cancel_ExceptionOrder ()
211                 {
212                         var cts = new CancellationTokenSource ();
213
214                         cts.Token.Register (() => { throw new ApplicationException ("1"); });
215                         cts.Token.Register (() => { throw new ApplicationException ("2"); });
216                         cts.Token.Register (() => { throw new ApplicationException ("3"); });
217
218                         try {
219                                 cts.Cancel ();
220                         } catch (AggregateException e) {
221                                 Assert.AreEqual (3, e.InnerExceptions.Count, "#2");
222                                 Assert.AreEqual ("3", e.InnerExceptions[0].Message, "#3");
223                                 Assert.AreEqual ("2", e.InnerExceptions[1].Message, "#4");
224                                 Assert.AreEqual ("1", e.InnerExceptions[2].Message, "#5");
225                         }
226                 }
227
228                 [Test]
229                 public void Cancel_MultipleException_Recursive ()
230                 {
231                         CancellationTokenSource cts = new CancellationTokenSource ();
232                         CancellationToken c = cts.Token;
233                         c.Register (() => {
234                                 cts.Cancel ();
235                         });
236
237                         c.Register (() => {
238                                 throw new ApplicationException ();
239                         });
240
241                         c.Register (() => {
242                                 throw new NotSupportedException ();
243                         });
244
245                         try {
246                                 cts.Cancel (false);
247                                 Assert.Fail ("#1");
248                         } catch (AggregateException e) {
249                                 Assert.AreEqual (2, e.InnerExceptions.Count, "#2");
250                         }
251                 }
252
253                 [Test]
254                 public void Cancel_MultipleExceptionsFirstThrows ()
255                 {
256                         var cts = new CancellationTokenSource ();
257
258                         cts.Token.Register (() => { throw new ApplicationException ("1"); });
259                         cts.Token.Register (() => { throw new ApplicationException ("2"); });
260                         cts.Token.Register (() => { throw new ApplicationException ("3"); });
261
262                         try {
263                                 cts.Cancel (true);
264                                 Assert.Fail ("#1");
265                         } catch (ApplicationException) {
266                         }
267
268                         cts.Cancel ();
269                 }
270
271                 [Test]
272                 public void CreateLinkedTokenSource_InvalidArguments ()
273                 {
274                         var cts = new CancellationTokenSource ();
275                         var token = cts.Token;
276
277                         try {
278                                 CancellationTokenSource.CreateLinkedTokenSource (null);
279                                 Assert.Fail ("#1");
280                         } catch (ArgumentNullException) {
281                         }
282
283                         try {
284                                 CancellationTokenSource.CreateLinkedTokenSource (new CancellationToken[0]);
285                                 Assert.Fail ("#2");
286                         } catch (ArgumentException) {
287                         }
288                 }
289
290                 [Test]
291                 public void CreateLinkedTokenSource ()
292                 {
293                         var cts = new CancellationTokenSource ();
294                         cts.Cancel ();
295
296                         var linked = CancellationTokenSource.CreateLinkedTokenSource (cts.Token);
297                         Assert.IsTrue (linked.IsCancellationRequested, "#1");
298
299                         linked = CancellationTokenSource.CreateLinkedTokenSource (new CancellationToken ());
300                         Assert.IsFalse (linked.IsCancellationRequested, "#2");
301                 }
302
303                 [Test]
304                 public void Dispose ()
305                 {
306                         var cts = new CancellationTokenSource ();
307                         var token = cts.Token;
308
309                         cts.Dispose ();
310                         cts.Dispose ();
311                         var b = cts.IsCancellationRequested;
312                         token.ThrowIfCancellationRequested ();
313
314                         try {
315                                 cts.Cancel ();
316                                 Assert.Fail ("#1");
317                         } catch (ObjectDisposedException) {
318                         }
319
320                         try {
321                                 var t = cts.Token;
322                                 Assert.Fail ("#2");
323                         } catch (ObjectDisposedException) {
324                         }
325
326                         try {
327                                 token.Register (() => { });
328                                 Assert.Fail ("#3");
329                         } catch (ObjectDisposedException) {
330                         }
331
332                         try {
333                                 var wh = token.WaitHandle;
334                                 Assert.Fail ("#4");
335                         } catch (ObjectDisposedException) {
336                         }
337
338                         try {
339                                 CancellationTokenSource.CreateLinkedTokenSource (token);
340                                 Assert.Fail ("#5");
341                         } catch (ObjectDisposedException) {
342                         }
343
344 #if NET_4_5
345                         try {
346                                 cts.CancelAfter (1);
347                                 Assert.Fail ("#6");
348                         } catch (ObjectDisposedException) {
349                         }
350 #endif
351                 }
352
353                 [Test]
354                 public void RegisterThenDispose ()
355                 {
356                         var cts1 = new CancellationTokenSource ();
357                         var reg1 = cts1.Token.Register (() => { throw new ApplicationException (); });
358
359                         var cts2 = new CancellationTokenSource ();
360                         var reg2 = cts2.Token.Register (() => { throw new ApplicationException (); });
361
362                         Assert.AreNotEqual (cts1, cts2, "#1");
363                         Assert.AreNotSame (cts1, cts2, "#2");
364
365                         reg1.Dispose ();
366                         cts1.Cancel ();
367
368                         try {
369                                 cts2.Cancel ();
370                                 Assert.Fail ("#3");
371                         } catch (AggregateException) {
372                         }
373                 }
374
375                 [Test]
376                 public void RegisterWhileCancelling ()
377                 {
378                         var cts = new CancellationTokenSource ();
379                         var mre = new ManualResetEvent (false);
380                         var mre2 = new ManualResetEvent (false);
381                         int called = 0;
382
383                         cts.Token.Register (() => {
384                                 Assert.IsTrue (cts.IsCancellationRequested, "#10");
385                                 Assert.IsTrue (cts.Token.WaitHandle.WaitOne (0), "#11");
386                                 mre2.Set ();
387                                 mre.WaitOne (3000);
388                                 called += 11;
389                         });
390
391                         var t = Task.Factory.StartNew (() => { cts.Cancel (); });
392
393                         Assert.IsTrue (mre2.WaitOne (1000), "#0");
394                         cts.Token.Register (() => { called++; });
395                         Assert.AreEqual (1, called, "#1");
396                         Assert.IsFalse (t.IsCompleted, "#2");
397
398                         mre.Set ();
399                         Assert.IsTrue (t.Wait (1000), "#3");
400                         Assert.AreEqual (12, called, "#4");
401                 }
402
403                 [Test]
404                 public void ReEntrantRegistrationTest ()
405                 {
406                         bool unregister = false;
407                         bool register = false;
408                         var source = new CancellationTokenSource ();
409                         var token = source.Token;
410
411                         Console.WriteLine ("Test1");
412                         var reg = token.Register (() => unregister = true);
413                         token.Register (() => reg.Dispose ());
414                         token.Register (() => { Console.WriteLine ("Gnyah"); token.Register (() => register = true); });
415                         source.Cancel ();
416
417                         Assert.IsFalse (unregister);
418                         Assert.IsTrue (register);
419                 }
420
421                 [Test]
422                 public void DisposeAfterRegistrationTest ()
423                 {
424                         var source = new CancellationTokenSource ();
425                         bool ran = false;
426                         var req = source.Token.Register (() => ran = true);
427                         source.Dispose ();
428                         req.Dispose ();
429                         Assert.IsFalse (ran);
430                 }
431
432                 [Test]
433                 public void CancelLinkedTokenSource ()
434                 {
435                         var cts = new CancellationTokenSource ();
436                         bool canceled = false;
437                         cts.Token.Register (() => canceled = true);
438
439                         using (var linked = CancellationTokenSource.CreateLinkedTokenSource (cts.Token))
440                                 ;
441
442                         Assert.IsFalse (canceled, "#1");
443                         Assert.IsFalse (cts.IsCancellationRequested, "#2");
444
445                         cts.Cancel ();
446
447                         Assert.IsTrue (canceled, "#3");
448                 }
449
450                 [Test]
451                 public void ConcurrentCancelLinkedTokenSourceWhileDisposing ()
452                 {
453                         ParallelTestHelper.Repeat (delegate {
454                                 var src = new CancellationTokenSource ();
455                                 var linked = CancellationTokenSource.CreateLinkedTokenSource (src.Token);
456                                 var cntd = new CountdownEvent (2);
457
458                                 var t1 = new Thread (() => {
459                                         if (!cntd.Signal ())
460                                                 cntd.Wait (200);
461                                         src.Cancel ();
462                                 });
463                                 var t2 = new Thread (() => {
464                                         if (!cntd.Signal ())
465                                                 cntd.Wait (200);
466                                         linked.Dispose ();
467                                 });
468
469                                 t1.Start ();
470                                 t2.Start ();
471                                 t1.Join (500);
472                                 t2.Join (500);
473                         }, 500);
474                 }
475
476 #if NET_4_5
477                 [Test]
478                 public void DisposeRace ()
479                 {
480                         for (int i = 0; i < 1000; ++i) {
481                                 var c1 = new CancellationTokenSource ();
482                                 using (c1) {
483                                         var wh = c1.Token.WaitHandle;
484                                         c1.CancelAfter (1);
485                                         Thread.Sleep (1);
486                                 }
487                         }
488                 }
489 #endif
490         }
491 }
492
493 #endif
494