Merge pull request #323 from crazyjncsu/master
[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 || MOBILE
31
32 using System;
33 using System.Threading;
34 using NUnit.Framework;
35 using 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 (20);
93                         cts.Dispose ();
94                         Thread.Sleep (50);
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 CancelWithDispose ()
135                 {
136                         CancellationTokenSource cts = new CancellationTokenSource ();
137                         CancellationToken c = cts.Token;
138                         c.Register (() => {
139                                 cts.Dispose ();
140                         });
141
142                         int called = 0;
143                         c.Register (() => {
144                                 called++;
145                         });
146
147                         cts.Cancel ();
148                         Assert.AreEqual (1, called, "#1");
149                 }
150
151                 [Test]
152                 public void Cancel_SingleException ()
153                 {
154                         var cts = new CancellationTokenSource ();
155
156                         cts.Token.Register (() => { throw new ApplicationException (); });
157                         try {
158                                 cts.Cancel ();
159                                 Assert.Fail ("#1");
160                         } catch (AggregateException e) {
161                                 Assert.AreEqual (1, e.InnerExceptions.Count, "#2");
162                         }
163
164                         cts.Cancel ();
165                 }
166
167                 [Test]
168                 public void Cancel_MultipleExceptions ()
169                 {
170                         var cts = new CancellationTokenSource ();
171
172                         cts.Token.Register (() => { throw new ApplicationException ("1"); });
173                         cts.Token.Register (() => { throw new ApplicationException ("2"); });
174                         cts.Token.Register (() => { throw new ApplicationException ("3"); });
175
176                         try {
177                                 cts.Cancel ();
178                                 Assert.Fail ("#1");
179                         } catch (AggregateException e) {
180                                 Assert.AreEqual (3, e.InnerExceptions.Count, "#2");
181                         }
182
183                         cts.Cancel ();
184
185                         try {
186                                 cts.Token.Register (() => { throw new ApplicationException ("1"); });
187                                 Assert.Fail ("#11");
188                         } catch (ApplicationException) {
189                         }
190
191                         cts.Cancel ();
192                 }
193
194                 [Test]
195                 public void Cancel_MultipleException_Recursive ()
196                 {
197                         CancellationTokenSource cts = new CancellationTokenSource ();
198                         CancellationToken c = cts.Token;
199                         c.Register (() => {
200                                 cts.Cancel ();
201                         });
202
203                         c.Register (() => {
204                                 throw new ApplicationException ();
205                         });
206
207                         c.Register (() => {
208                                 throw new NotSupportedException ();
209                         });
210
211                         try {
212                                 cts.Cancel (false);
213                                 Assert.Fail ("#1");
214                         } catch (AggregateException e) {
215                                 Assert.AreEqual (2, e.InnerExceptions.Count, "#2");
216                         }
217                 }
218
219                 [Test]
220                 public void Cancel_MultipleExceptionsFirstThrows ()
221                 {
222                         var cts = new CancellationTokenSource ();
223
224                         cts.Token.Register (() => { throw new ApplicationException ("1"); });
225                         cts.Token.Register (() => { throw new ApplicationException ("2"); });
226                         cts.Token.Register (() => { throw new ApplicationException ("3"); });
227
228                         try {
229                                 cts.Cancel (true);
230                                 Assert.Fail ("#1");
231                         } catch (ApplicationException) {
232                         }
233
234                         cts.Cancel ();
235                 }
236
237                 [Test]
238                 public void CreateLinkedTokenSource_InvalidArguments ()
239                 {
240                         var cts = new CancellationTokenSource ();
241                         var token = cts.Token;
242
243                         try {
244                                 CancellationTokenSource.CreateLinkedTokenSource (null);
245                                 Assert.Fail ("#1");
246                         } catch (ArgumentNullException) {
247                         }
248
249                         try {
250                                 CancellationTokenSource.CreateLinkedTokenSource (new CancellationToken[0]);
251                                 Assert.Fail ("#2");
252                         } catch (ArgumentException) {
253                         }
254                 }
255
256                 [Test]
257                 public void CreateLinkedTokenSource ()
258                 {
259                         var cts = new CancellationTokenSource ();
260                         cts.Cancel ();
261
262                         var linked = CancellationTokenSource.CreateLinkedTokenSource (cts.Token);
263                         Assert.IsTrue (linked.IsCancellationRequested, "#1");
264
265                         linked = CancellationTokenSource.CreateLinkedTokenSource (new CancellationToken ());
266                         Assert.IsFalse (linked.IsCancellationRequested, "#2");
267                 }
268
269                 [Test]
270                 public void Dispose ()
271                 {
272                         var cts = new CancellationTokenSource ();
273                         var token = cts.Token;
274
275                         cts.Dispose ();
276                         cts.Dispose ();
277                         var b = cts.IsCancellationRequested;
278                         token.ThrowIfCancellationRequested ();
279
280                         try {
281                                 cts.Cancel ();
282                                 Assert.Fail ("#1");
283                         } catch (ObjectDisposedException) {
284                         }
285
286                         try {
287                                 var t = cts.Token;
288                                 Assert.Fail ("#2");
289                         } catch (ObjectDisposedException) {
290                         }
291
292                         try {
293                                 token.Register (() => { });
294                                 Assert.Fail ("#3");
295                         } catch (ObjectDisposedException) {
296                         }
297
298                         try {
299                                 var wh = token.WaitHandle;
300                                 Assert.Fail ("#4");
301                         } catch (ObjectDisposedException) {
302                         }
303
304                         try {
305                                 CancellationTokenSource.CreateLinkedTokenSource (token);
306                                 Assert.Fail ("#5");
307                         } catch (ObjectDisposedException) {
308                         }
309
310 #if NET_4_5
311                         try {
312                                 cts.CancelAfter (1);
313                                 Assert.Fail ("#6");
314                         } catch (ObjectDisposedException) {
315                         }
316 #endif
317                 }
318
319                 [Test]
320                 public void RegisterThenDispose ()
321                 {
322                         var cts1 = new CancellationTokenSource ();
323                         var reg1 = cts1.Token.Register (() => { throw new ApplicationException (); });
324
325                         var cts2 = new CancellationTokenSource ();
326                         var reg2 = cts2.Token.Register (() => { throw new ApplicationException (); });
327
328                         Assert.AreNotEqual (cts1, cts2, "#1");
329                         Assert.AreNotSame (cts1, cts2, "#2");
330
331                         reg1.Dispose ();
332                         cts1.Cancel ();
333
334                         try {
335                                 cts2.Cancel ();
336                                 Assert.Fail ("#3");
337                         } catch (AggregateException) {
338                         }
339                 }
340
341                 [Test]
342                 public void RegisterWhileCancelling ()
343                 {
344                         var cts = new CancellationTokenSource ();
345                         var mre = new ManualResetEvent (false);
346                         var mre2 = new ManualResetEvent (false);
347                         int called = 0;
348
349                         cts.Token.Register (() => {
350                                 Assert.IsTrue (cts.IsCancellationRequested, "#10");
351                                 Assert.IsTrue (cts.Token.WaitHandle.WaitOne (0), "#11");
352                                 mre2.Set ();
353                                 mre.WaitOne (3000);
354                                 called += 11;
355                         });
356
357                         var t = Task.Factory.StartNew (() => { cts.Cancel (); });
358
359                         Assert.IsTrue (mre2.WaitOne (1000), "#0");
360                         cts.Token.Register (() => { called++; });
361                         Assert.AreEqual (1, called, "#1");
362                         Assert.IsFalse (t.IsCompleted, "#2");
363
364                         mre.Set ();
365                         Assert.IsTrue (t.Wait (1000), "#3");
366                         Assert.AreEqual (12, called, "#4");
367                 }
368
369                 [Test]
370                 public void ReEntrantRegistrationTest ()
371                 {
372                         bool unregister = false;
373                         bool register = false;
374                         var source = new CancellationTokenSource ();
375                         var token = source.Token;
376
377                         var reg = new CancellationTokenRegistration ();
378                         Console.WriteLine ("Test1");
379                         token.Register (() => reg.Dispose ());
380                         reg = token.Register (() => unregister = true);
381                         token.Register (() => { Console.WriteLine ("Gnyah"); token.Register (() => register = true); });
382                         source.Cancel ();
383
384                         Assert.IsFalse (unregister);
385                         Assert.IsTrue (register);
386                 }
387
388                 [Test]
389                 public void DisposeAfterRegistrationTest ()
390                 {
391                         var source = new CancellationTokenSource ();
392                         bool ran = false;
393                         var req = source.Token.Register (() => ran = true);
394                         source.Dispose ();
395                         req.Dispose ();
396                         Assert.IsFalse (ran);
397                 }
398         }
399 }
400
401 #endif
402