2 // CancellationTokenSourceTest.cs
5 // Marek Safar (marek.safar@gmail.com)
6 // Jeremie Laval (jeremie.laval@gmail.com)
8 // Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
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:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
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.
32 using System.Threading;
33 using NUnit.Framework;
34 using System.Threading.Tasks;
36 namespace MonoTests.System.Threading
39 public class CancellationTokenSourceTest
44 public void Ctor_Invalid ()
47 new CancellationTokenSource (-4);
49 } catch (ArgumentException) {
54 public void Ctor_Timeout ()
57 var cts = new CancellationTokenSource (TimeSpan.FromMilliseconds (20));
58 cts.Token.Register (() => called++);
60 Assert.AreEqual (1, called, "#1");
64 public void CancelAfter ()
67 var cts = new CancellationTokenSource ();
68 cts.Token.Register (() => called++);
71 Assert.AreEqual (1, called, "#1");
75 public void CancelAfter_Invalid ()
77 var cts = new CancellationTokenSource ();
81 } catch (ArgumentException) {
86 public void CancelAfter_Disposed ()
89 var cts = new CancellationTokenSource ();
90 cts.Token.Register (() => called++);
94 Assert.AreEqual (0, called, "#1");
102 CancellationTokenSource cts = new CancellationTokenSource ();
103 Assert.IsTrue (cts.Token.CanBeCanceled, "#1");
104 Assert.IsFalse (cts.Token.IsCancellationRequested, "#2");
105 Assert.IsNotNull (cts.Token.WaitHandle, "#3");
109 public void Cancel_NoRegistration ()
111 CancellationTokenSource cts = new CancellationTokenSource ();
116 public void Cancel ()
118 var cts = new CancellationTokenSource ();
121 cts.Token.Register (l => { Assert.AreEqual ("v", l); ++called; }, "v");
123 Assert.AreEqual (1, called, "#1");
126 cts.Token.Register (() => { called += 12; });
128 Assert.AreEqual (12, called, "#2");
133 public void Cancel_Order ()
135 var cts = new CancellationTokenSource ();
137 Action<object> a = x => { Assert.AreEqual(current, x); current++; };
139 cts.Token.Register (a, 2);
140 cts.Token.Register (a, 1);
141 cts.Token.Register (a, 0);
147 public void CancelWithDispose ()
149 CancellationTokenSource cts = new CancellationTokenSource ();
150 CancellationToken c = cts.Token;
161 Assert.AreEqual (1, called, "#1");
165 public void Cancel_SingleException ()
167 var cts = new CancellationTokenSource ();
169 cts.Token.Register (() => { throw new ApplicationException (); });
173 } catch (AggregateException e) {
174 Assert.AreEqual (1, e.InnerExceptions.Count, "#2");
181 public void Cancel_MultipleExceptions ()
183 var cts = new CancellationTokenSource ();
185 cts.Token.Register (() => { throw new ApplicationException ("1"); });
186 cts.Token.Register (() => { throw new ApplicationException ("2"); });
187 cts.Token.Register (() => { throw new ApplicationException ("3"); });
192 } catch (AggregateException e) {
193 Assert.AreEqual (3, e.InnerExceptions.Count, "#2");
199 cts.Token.Register (() => { throw new ApplicationException ("1"); });
201 } catch (ApplicationException) {
208 public void Cancel_ExceptionOrder ()
210 var cts = new CancellationTokenSource ();
212 cts.Token.Register (() => { throw new ApplicationException ("1"); });
213 cts.Token.Register (() => { throw new ApplicationException ("2"); });
214 cts.Token.Register (() => { throw new ApplicationException ("3"); });
218 } catch (AggregateException e) {
219 Assert.AreEqual (3, e.InnerExceptions.Count, "#2");
220 Assert.AreEqual ("3", e.InnerExceptions[0].Message, "#3");
221 Assert.AreEqual ("2", e.InnerExceptions[1].Message, "#4");
222 Assert.AreEqual ("1", e.InnerExceptions[2].Message, "#5");
227 public void Cancel_MultipleException_Recursive ()
229 CancellationTokenSource cts = new CancellationTokenSource ();
230 CancellationToken c = cts.Token;
236 throw new ApplicationException ();
240 throw new NotSupportedException ();
246 } catch (AggregateException e) {
247 Assert.AreEqual (2, e.InnerExceptions.Count, "#2");
252 public void Cancel_MultipleExceptionsFirstThrows ()
254 var cts = new CancellationTokenSource ();
256 cts.Token.Register (() => { throw new ApplicationException ("1"); });
257 cts.Token.Register (() => { throw new ApplicationException ("2"); });
258 cts.Token.Register (() => { throw new ApplicationException ("3"); });
263 } catch (ApplicationException) {
270 public void CreateLinkedTokenSource_InvalidArguments ()
272 var cts = new CancellationTokenSource ();
273 var token = cts.Token;
276 CancellationTokenSource.CreateLinkedTokenSource (null);
278 } catch (ArgumentNullException) {
282 CancellationTokenSource.CreateLinkedTokenSource (new CancellationToken[0]);
284 } catch (ArgumentException) {
289 public void CreateLinkedTokenSource ()
291 var cts = new CancellationTokenSource ();
294 var linked = CancellationTokenSource.CreateLinkedTokenSource (cts.Token);
295 Assert.IsTrue (linked.IsCancellationRequested, "#1");
297 linked = CancellationTokenSource.CreateLinkedTokenSource (new CancellationToken ());
298 Assert.IsFalse (linked.IsCancellationRequested, "#2");
302 public void Dispose ()
304 var cts = new CancellationTokenSource ();
305 var token = cts.Token;
309 var b = cts.IsCancellationRequested;
310 token.ThrowIfCancellationRequested ();
315 } catch (ObjectDisposedException) {
321 } catch (ObjectDisposedException) {
325 token.Register (() => { });
327 } catch (ObjectDisposedException) {
331 var wh = token.WaitHandle;
333 } catch (ObjectDisposedException) {
337 CancellationTokenSource.CreateLinkedTokenSource (token);
339 } catch (ObjectDisposedException) {
346 } catch (ObjectDisposedException) {
352 public void RegisterThenDispose ()
354 var cts1 = new CancellationTokenSource ();
355 var reg1 = cts1.Token.Register (() => { throw new ApplicationException (); });
357 var cts2 = new CancellationTokenSource ();
358 var reg2 = cts2.Token.Register (() => { throw new ApplicationException (); });
360 Assert.AreNotEqual (cts1, cts2, "#1");
361 Assert.AreNotSame (cts1, cts2, "#2");
369 } catch (AggregateException) {
374 public void RegisterWhileCancelling ()
376 var cts = new CancellationTokenSource ();
377 var mre = new ManualResetEvent (false);
378 var mre2 = new ManualResetEvent (false);
381 cts.Token.Register (() => {
382 Assert.IsTrue (cts.IsCancellationRequested, "#10");
383 Assert.IsTrue (cts.Token.WaitHandle.WaitOne (0), "#11");
389 var t = Task.Factory.StartNew (() => { cts.Cancel (); });
391 Assert.IsTrue (mre2.WaitOne (1000), "#0");
392 cts.Token.Register (() => { called++; });
393 Assert.AreEqual (1, called, "#1");
394 Assert.IsFalse (t.IsCompleted, "#2");
397 Assert.IsTrue (t.Wait (1000), "#3");
398 Assert.AreEqual (12, called, "#4");
402 public void ReEntrantRegistrationTest ()
404 bool unregister = false;
405 bool register = false;
406 var source = new CancellationTokenSource ();
407 var token = source.Token;
409 Console.WriteLine ("Test1");
410 var reg = token.Register (() => unregister = true);
411 token.Register (() => reg.Dispose ());
412 token.Register (() => { Console.WriteLine ("Gnyah"); token.Register (() => register = true); });
415 Assert.IsFalse (unregister);
416 Assert.IsTrue (register);
420 public void DisposeAfterRegistrationTest ()
422 var source = new CancellationTokenSource ();
424 var req = source.Token.Register (() => ran = true);
427 Assert.IsFalse (ran);
431 public void CancelLinkedTokenSource ()
433 var cts = new CancellationTokenSource ();
434 bool canceled = false;
435 cts.Token.Register (() => canceled = true);
437 using (var linked = CancellationTokenSource.CreateLinkedTokenSource (cts.Token))
440 Assert.IsFalse (canceled, "#1");
441 Assert.IsFalse (cts.IsCancellationRequested, "#2");
445 Assert.IsTrue (canceled, "#3");
448 [Category ("NotWorking")] // why would linked token be imune to ObjectDisposedException on Cancel?
450 public void ConcurrentCancelLinkedTokenSourceWhileDisposing ()
452 for (int i = 0, total = 500; i < total; ++i) {
453 var src = new CancellationTokenSource ();
454 var linked = CancellationTokenSource.CreateLinkedTokenSource (src.Token);
455 var cntd = new CountdownEvent (2);
457 var t1 = new Thread (() => {
462 var t2 = new Thread (() => {
477 public void DisposeRace ()
479 for (int i = 0, total = 1000; i < total; ++i) {
480 var c1 = new CancellationTokenSource ();
481 var wh = c1.Token.WaitHandle;