[mono-config] use right type for result of strlen
[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
31 using System;
32 using System.Threading;
33 using NUnit.Framework;
34 using System.Threading.Tasks;
35 using MonoTests.System.Threading.Tasks;
36
37 namespace MonoTests.System.Threading
38 {
39         [TestFixture]
40         public class CancellationTokenSourceTest
41         {
42 #if NET_4_5
43
44                 [Test]
45                 public void Ctor_Invalid ()
46                 {
47                         try {
48                                 new CancellationTokenSource (-4);
49                                 Assert.Fail ("#1");
50                         } catch (ArgumentException) {
51                         }
52                 }
53
54                 [Test]
55                 public void Ctor_Timeout ()
56                 {
57                         int called = 0;
58                         var cts = new CancellationTokenSource (TimeSpan.FromMilliseconds (20));
59                         cts.Token.Register (() => called++);
60                         Thread.Sleep (50);
61                         Assert.AreEqual (1, called, "#1");
62                 }
63
64                 [Test]
65                 public void CancelAfter ()
66                 {
67                         int called = 0;
68                         var cts = new CancellationTokenSource ();
69                         cts.Token.Register (() => called++);
70                         cts.CancelAfter (20);
71                         Thread.Sleep (50);
72                         Assert.AreEqual (1, called, "#1");
73                 }
74
75                 [Test]
76                 public void CancelAfter_Invalid ()
77                 {
78                         var cts = new CancellationTokenSource ();
79                         try {
80                                 cts.CancelAfter (-9);
81                                 Assert.Fail ("#1");
82                         } catch (ArgumentException) {
83                         }
84                 }
85
86                 [Test]
87                 public void CancelAfter_Disposed ()
88                 {
89                         int called = 0;
90                         var cts = new CancellationTokenSource ();
91                         cts.Token.Register (() => called++);
92                         cts.CancelAfter (50);
93                         cts.Dispose ();
94                         Thread.Sleep (100);
95                         Assert.AreEqual (0, called, "#1");
96                 }
97
98 #endif
99
100                 [Test]
101                 public void Token ()
102                 {
103                         CancellationTokenSource cts = new CancellationTokenSource ();
104                         Assert.IsTrue (cts.Token.CanBeCanceled, "#1");
105                         Assert.IsFalse (cts.Token.IsCancellationRequested, "#2");
106                         Assert.IsNotNull (cts.Token.WaitHandle, "#3");
107                 }
108
109                 [Test]
110                 public void Cancel_NoRegistration ()
111                 {
112                         CancellationTokenSource cts = new CancellationTokenSource ();
113                         cts.Cancel ();
114                 }
115
116                 [Test]
117                 public void Cancel ()
118                 {
119                         var cts = new CancellationTokenSource ();
120
121                         int called = 0;
122                         cts.Token.Register (l => { Assert.AreEqual ("v", l); ++called; }, "v");
123                         cts.Cancel ();
124                         Assert.AreEqual (1, called, "#1");
125
126                         called = 0;
127                         cts.Token.Register (() => { called += 12; });
128                         cts.Cancel ();
129                         Assert.AreEqual (12, called, "#2");
130                 }
131
132
133                 [Test]
134                 public void Cancel_Order ()
135                 {
136                         var cts = new CancellationTokenSource ();
137                         var current = 0;
138                         Action<object> a = x => { Assert.AreEqual(current, x); current++; };
139
140                         cts.Token.Register (a, 2);
141                         cts.Token.Register (a, 1);
142                         cts.Token.Register (a, 0);
143                         cts.Cancel ();
144                 }
145
146
147                 [Test]
148                 public void CancelWithDispose ()
149                 {
150                         CancellationTokenSource cts = new CancellationTokenSource ();
151                         CancellationToken c = cts.Token;
152                         c.Register (() => {
153                                 cts.Dispose ();
154                         });
155
156                         int called = 0;
157                         c.Register (() => {
158                                 called++;
159                         });
160
161                         cts.Cancel ();
162                         Assert.AreEqual (1, called, "#1");
163                 }
164
165                 [Test]
166                 public void Cancel_SingleException ()
167                 {
168                         var cts = new CancellationTokenSource ();
169
170                         cts.Token.Register (() => { throw new ApplicationException (); });
171                         try {
172                                 cts.Cancel ();
173                                 Assert.Fail ("#1");
174                         } catch (AggregateException e) {
175                                 Assert.AreEqual (1, e.InnerExceptions.Count, "#2");
176                         }
177
178                         cts.Cancel ();
179                 }
180
181                 [Test]
182                 public void Cancel_MultipleExceptions ()
183                 {
184                         var cts = new CancellationTokenSource ();
185
186                         cts.Token.Register (() => { throw new ApplicationException ("1"); });
187                         cts.Token.Register (() => { throw new ApplicationException ("2"); });
188                         cts.Token.Register (() => { throw new ApplicationException ("3"); });
189
190                         try {
191                                 cts.Cancel ();
192                                 Assert.Fail ("#1");
193                         } catch (AggregateException e) {
194                                 Assert.AreEqual (3, e.InnerExceptions.Count, "#2");
195                         }
196
197                         cts.Cancel ();
198
199                         try {
200                                 cts.Token.Register (() => { throw new ApplicationException ("1"); });
201                                 Assert.Fail ("#11");
202                         } catch (ApplicationException) {
203                         }
204
205                         cts.Cancel ();
206                 }
207
208                 [Test]
209                 public void Cancel_ExceptionOrder ()
210                 {
211                         var cts = new CancellationTokenSource ();
212
213                         cts.Token.Register (() => { throw new ApplicationException ("1"); });
214                         cts.Token.Register (() => { throw new ApplicationException ("2"); });
215                         cts.Token.Register (() => { throw new ApplicationException ("3"); });
216
217                         try {
218                                 cts.Cancel ();
219                         } catch (AggregateException e) {
220                                 Assert.AreEqual (3, e.InnerExceptions.Count, "#2");
221                                 Assert.AreEqual ("3", e.InnerExceptions[0].Message, "#3");
222                                 Assert.AreEqual ("2", e.InnerExceptions[1].Message, "#4");
223                                 Assert.AreEqual ("1", e.InnerExceptions[2].Message, "#5");
224                         }
225                 }
226
227                 [Test]
228                 public void Cancel_MultipleException_Recursive ()
229                 {
230                         CancellationTokenSource cts = new CancellationTokenSource ();
231                         CancellationToken c = cts.Token;
232                         c.Register (() => {
233                                 cts.Cancel ();
234                         });
235
236                         c.Register (() => {
237                                 throw new ApplicationException ();
238                         });
239
240                         c.Register (() => {
241                                 throw new NotSupportedException ();
242                         });
243
244                         try {
245                                 cts.Cancel (false);
246                                 Assert.Fail ("#1");
247                         } catch (AggregateException e) {
248                                 Assert.AreEqual (2, e.InnerExceptions.Count, "#2");
249                         }
250                 }
251
252                 [Test]
253                 public void Cancel_MultipleExceptionsFirstThrows ()
254                 {
255                         var cts = new CancellationTokenSource ();
256
257                         cts.Token.Register (() => { throw new ApplicationException ("1"); });
258                         cts.Token.Register (() => { throw new ApplicationException ("2"); });
259                         cts.Token.Register (() => { throw new ApplicationException ("3"); });
260
261                         try {
262                                 cts.Cancel (true);
263                                 Assert.Fail ("#1");
264                         } catch (ApplicationException) {
265                         }
266
267                         cts.Cancel ();
268                 }
269
270                 [Test]
271                 public void CreateLinkedTokenSource_InvalidArguments ()
272                 {
273                         var cts = new CancellationTokenSource ();
274                         var token = cts.Token;
275
276                         try {
277                                 CancellationTokenSource.CreateLinkedTokenSource (null);
278                                 Assert.Fail ("#1");
279                         } catch (ArgumentNullException) {
280                         }
281
282                         try {
283                                 CancellationTokenSource.CreateLinkedTokenSource (new CancellationToken[0]);
284                                 Assert.Fail ("#2");
285                         } catch (ArgumentException) {
286                         }
287                 }
288
289                 [Test]
290                 public void CreateLinkedTokenSource ()
291                 {
292                         var cts = new CancellationTokenSource ();
293                         cts.Cancel ();
294
295                         var linked = CancellationTokenSource.CreateLinkedTokenSource (cts.Token);
296                         Assert.IsTrue (linked.IsCancellationRequested, "#1");
297
298                         linked = CancellationTokenSource.CreateLinkedTokenSource (new CancellationToken ());
299                         Assert.IsFalse (linked.IsCancellationRequested, "#2");
300                 }
301
302                 [Test]
303                 public void Dispose ()
304                 {
305                         var cts = new CancellationTokenSource ();
306                         var token = cts.Token;
307
308                         cts.Dispose ();
309                         cts.Dispose ();
310                         var b = cts.IsCancellationRequested;
311                         token.ThrowIfCancellationRequested ();
312
313                         try {
314                                 cts.Cancel ();
315                                 Assert.Fail ("#1");
316                         } catch (ObjectDisposedException) {
317                         }
318
319                         try {
320                                 var t = cts.Token;
321                                 Assert.Fail ("#2");
322                         } catch (ObjectDisposedException) {
323                         }
324
325                         try {
326                                 token.Register (() => { });
327                                 Assert.Fail ("#3");
328                         } catch (ObjectDisposedException) {
329                         }
330
331                         try {
332                                 var wh = token.WaitHandle;
333                                 Assert.Fail ("#4");
334                         } catch (ObjectDisposedException) {
335                         }
336
337                         try {
338                                 CancellationTokenSource.CreateLinkedTokenSource (token);
339                                 Assert.Fail ("#5");
340                         } catch (ObjectDisposedException) {
341                         }
342
343 #if NET_4_5
344                         try {
345                                 cts.CancelAfter (1);
346                                 Assert.Fail ("#6");
347                         } catch (ObjectDisposedException) {
348                         }
349 #endif
350                 }
351
352                 [Test]
353                 public void RegisterThenDispose ()
354                 {
355                         var cts1 = new CancellationTokenSource ();
356                         var reg1 = cts1.Token.Register (() => { throw new ApplicationException (); });
357
358                         var cts2 = new CancellationTokenSource ();
359                         var reg2 = cts2.Token.Register (() => { throw new ApplicationException (); });
360
361                         Assert.AreNotEqual (cts1, cts2, "#1");
362                         Assert.AreNotSame (cts1, cts2, "#2");
363
364                         reg1.Dispose ();
365                         cts1.Cancel ();
366
367                         try {
368                                 cts2.Cancel ();
369                                 Assert.Fail ("#3");
370                         } catch (AggregateException) {
371                         }
372                 }
373
374                 [Test]
375                 public void RegisterWhileCancelling ()
376                 {
377                         var cts = new CancellationTokenSource ();
378                         var mre = new ManualResetEvent (false);
379                         var mre2 = new ManualResetEvent (false);
380                         int called = 0;
381
382                         cts.Token.Register (() => {
383                                 Assert.IsTrue (cts.IsCancellationRequested, "#10");
384                                 Assert.IsTrue (cts.Token.WaitHandle.WaitOne (0), "#11");
385                                 mre2.Set ();
386                                 mre.WaitOne (3000);
387                                 called += 11;
388                         });
389
390                         var t = Task.Factory.StartNew (() => { cts.Cancel (); });
391
392                         Assert.IsTrue (mre2.WaitOne (1000), "#0");
393                         cts.Token.Register (() => { called++; });
394                         Assert.AreEqual (1, called, "#1");
395                         Assert.IsFalse (t.IsCompleted, "#2");
396
397                         mre.Set ();
398                         Assert.IsTrue (t.Wait (1000), "#3");
399                         Assert.AreEqual (12, called, "#4");
400                 }
401
402                 [Test]
403                 public void ReEntrantRegistrationTest ()
404                 {
405                         bool unregister = false;
406                         bool register = false;
407                         var source = new CancellationTokenSource ();
408                         var token = source.Token;
409
410                         Console.WriteLine ("Test1");
411                         var reg = token.Register (() => unregister = true);
412                         token.Register (() => reg.Dispose ());
413                         token.Register (() => { Console.WriteLine ("Gnyah"); token.Register (() => register = true); });
414                         source.Cancel ();
415
416                         Assert.IsFalse (unregister);
417                         Assert.IsTrue (register);
418                 }
419
420                 [Test]
421                 public void DisposeAfterRegistrationTest ()
422                 {
423                         var source = new CancellationTokenSource ();
424                         bool ran = false;
425                         var req = source.Token.Register (() => ran = true);
426                         source.Dispose ();
427                         req.Dispose ();
428                         Assert.IsFalse (ran);
429                 }
430
431                 [Test]
432                 public void CancelLinkedTokenSource ()
433                 {
434                         var cts = new CancellationTokenSource ();
435                         bool canceled = false;
436                         cts.Token.Register (() => canceled = true);
437
438                         using (var linked = CancellationTokenSource.CreateLinkedTokenSource (cts.Token))
439                                 ;
440
441                         Assert.IsFalse (canceled, "#1");
442                         Assert.IsFalse (cts.IsCancellationRequested, "#2");
443
444                         cts.Cancel ();
445
446                         Assert.IsTrue (canceled, "#3");
447                 }
448
449                 [Test]
450                 public void ConcurrentCancelLinkedTokenSourceWhileDisposing ()
451                 {
452                         ParallelTestHelper.Repeat (delegate {
453                                 var src = new CancellationTokenSource ();
454                                 var linked = CancellationTokenSource.CreateLinkedTokenSource (src.Token);
455                                 var cntd = new CountdownEvent (2);
456
457                                 var t1 = new Thread (() => {
458                                         if (!cntd.Signal ())
459                                                 cntd.Wait (200);
460                                         src.Cancel ();
461                                 });
462                                 var t2 = new Thread (() => {
463                                         if (!cntd.Signal ())
464                                                 cntd.Wait (200);
465                                         linked.Dispose ();
466                                 });
467
468                                 t1.Start ();
469                                 t2.Start ();
470                                 t1.Join (500);
471                                 t2.Join (500);
472                         }, 500);
473                 }
474
475 #if NET_4_5
476                 [Test]
477                 public void DisposeRace ()
478                 {
479                         for (int i = 0; i < 1000; ++i) {
480                                 var c1 = new CancellationTokenSource ();
481                                 using (c1) {
482                                         var wh = c1.Token.WaitHandle;
483                                         c1.CancelAfter (1);
484                                         Thread.Sleep (1);
485                                 }
486                         }
487                 }
488 #endif
489         }
490 }
491
492