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.
33 using System.Threading;
34 using NUnit.Framework;
35 using System.Threading.Tasks;
36 using MonoTests.System.Threading.Tasks;
38 namespace MonoTests.System.Threading
41 public class CancellationTokenSourceTest
46 public void Ctor_Invalid ()
49 new CancellationTokenSource (-4);
51 } catch (ArgumentException) {
56 public void Ctor_Timeout ()
59 var cts = new CancellationTokenSource (TimeSpan.FromMilliseconds (20));
60 cts.Token.Register (() => called++);
62 Assert.AreEqual (1, called, "#1");
66 public void CancelAfter ()
69 var cts = new CancellationTokenSource ();
70 cts.Token.Register (() => called++);
73 Assert.AreEqual (1, called, "#1");
77 public void CancelAfter_Invalid ()
79 var cts = new CancellationTokenSource ();
83 } catch (ArgumentException) {
88 public void CancelAfter_Disposed ()
91 var cts = new CancellationTokenSource ();
92 cts.Token.Register (() => called++);
96 Assert.AreEqual (0, called, "#1");
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");
111 public void Cancel_NoRegistration ()
113 CancellationTokenSource cts = new CancellationTokenSource ();
118 public void Cancel ()
120 var cts = new CancellationTokenSource ();
123 cts.Token.Register (l => { Assert.AreEqual ("v", l); ++called; }, "v");
125 Assert.AreEqual (1, called, "#1");
128 cts.Token.Register (() => { called += 12; });
130 Assert.AreEqual (12, called, "#2");
135 public void Cancel_Order ()
137 var cts = new CancellationTokenSource ();
139 Action<object> a = x => { Assert.AreEqual(current, x); current++; };
141 cts.Token.Register (a, 2);
142 cts.Token.Register (a, 1);
143 cts.Token.Register (a, 0);
149 public void CancelWithDispose ()
151 CancellationTokenSource cts = new CancellationTokenSource ();
152 CancellationToken c = cts.Token;
163 Assert.AreEqual (1, called, "#1");
167 public void Cancel_SingleException ()
169 var cts = new CancellationTokenSource ();
171 cts.Token.Register (() => { throw new ApplicationException (); });
175 } catch (AggregateException e) {
176 Assert.AreEqual (1, e.InnerExceptions.Count, "#2");
183 public void Cancel_MultipleExceptions ()
185 var cts = new CancellationTokenSource ();
187 cts.Token.Register (() => { throw new ApplicationException ("1"); });
188 cts.Token.Register (() => { throw new ApplicationException ("2"); });
189 cts.Token.Register (() => { throw new ApplicationException ("3"); });
194 } catch (AggregateException e) {
195 Assert.AreEqual (3, e.InnerExceptions.Count, "#2");
201 cts.Token.Register (() => { throw new ApplicationException ("1"); });
203 } catch (ApplicationException) {
210 public void Cancel_ExceptionOrder ()
212 var cts = new CancellationTokenSource ();
214 cts.Token.Register (() => { throw new ApplicationException ("1"); });
215 cts.Token.Register (() => { throw new ApplicationException ("2"); });
216 cts.Token.Register (() => { throw new ApplicationException ("3"); });
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");
229 public void Cancel_MultipleException_Recursive ()
231 CancellationTokenSource cts = new CancellationTokenSource ();
232 CancellationToken c = cts.Token;
238 throw new ApplicationException ();
242 throw new NotSupportedException ();
248 } catch (AggregateException e) {
249 Assert.AreEqual (2, e.InnerExceptions.Count, "#2");
254 public void Cancel_MultipleExceptionsFirstThrows ()
256 var cts = new CancellationTokenSource ();
258 cts.Token.Register (() => { throw new ApplicationException ("1"); });
259 cts.Token.Register (() => { throw new ApplicationException ("2"); });
260 cts.Token.Register (() => { throw new ApplicationException ("3"); });
265 } catch (ApplicationException) {
272 public void CreateLinkedTokenSource_InvalidArguments ()
274 var cts = new CancellationTokenSource ();
275 var token = cts.Token;
278 CancellationTokenSource.CreateLinkedTokenSource (null);
280 } catch (ArgumentNullException) {
284 CancellationTokenSource.CreateLinkedTokenSource (new CancellationToken[0]);
286 } catch (ArgumentException) {
291 public void CreateLinkedTokenSource ()
293 var cts = new CancellationTokenSource ();
296 var linked = CancellationTokenSource.CreateLinkedTokenSource (cts.Token);
297 Assert.IsTrue (linked.IsCancellationRequested, "#1");
299 linked = CancellationTokenSource.CreateLinkedTokenSource (new CancellationToken ());
300 Assert.IsFalse (linked.IsCancellationRequested, "#2");
304 public void Dispose ()
306 var cts = new CancellationTokenSource ();
307 var token = cts.Token;
311 var b = cts.IsCancellationRequested;
312 token.ThrowIfCancellationRequested ();
317 } catch (ObjectDisposedException) {
323 } catch (ObjectDisposedException) {
327 token.Register (() => { });
329 } catch (ObjectDisposedException) {
333 var wh = token.WaitHandle;
335 } catch (ObjectDisposedException) {
339 CancellationTokenSource.CreateLinkedTokenSource (token);
341 } catch (ObjectDisposedException) {
348 } catch (ObjectDisposedException) {
354 public void RegisterThenDispose ()
356 var cts1 = new CancellationTokenSource ();
357 var reg1 = cts1.Token.Register (() => { throw new ApplicationException (); });
359 var cts2 = new CancellationTokenSource ();
360 var reg2 = cts2.Token.Register (() => { throw new ApplicationException (); });
362 Assert.AreNotEqual (cts1, cts2, "#1");
363 Assert.AreNotSame (cts1, cts2, "#2");
371 } catch (AggregateException) {
376 public void RegisterWhileCancelling ()
378 var cts = new CancellationTokenSource ();
379 var mre = new ManualResetEvent (false);
380 var mre2 = new ManualResetEvent (false);
383 cts.Token.Register (() => {
384 Assert.IsTrue (cts.IsCancellationRequested, "#10");
385 Assert.IsTrue (cts.Token.WaitHandle.WaitOne (0), "#11");
391 var t = Task.Factory.StartNew (() => { cts.Cancel (); });
393 Assert.IsTrue (mre2.WaitOne (1000), "#0");
394 cts.Token.Register (() => { called++; });
395 Assert.AreEqual (1, called, "#1");
396 Assert.IsFalse (t.IsCompleted, "#2");
399 Assert.IsTrue (t.Wait (1000), "#3");
400 Assert.AreEqual (12, called, "#4");
404 public void ReEntrantRegistrationTest ()
406 bool unregister = false;
407 bool register = false;
408 var source = new CancellationTokenSource ();
409 var token = source.Token;
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); });
417 Assert.IsFalse (unregister);
418 Assert.IsTrue (register);
422 public void DisposeAfterRegistrationTest ()
424 var source = new CancellationTokenSource ();
426 var req = source.Token.Register (() => ran = true);
429 Assert.IsFalse (ran);
433 public void CancelLinkedTokenSource ()
435 var cts = new CancellationTokenSource ();
436 bool canceled = false;
437 cts.Token.Register (() => canceled = true);
439 using (var linked = CancellationTokenSource.CreateLinkedTokenSource (cts.Token))
442 Assert.IsFalse (canceled, "#1");
443 Assert.IsFalse (cts.IsCancellationRequested, "#2");
447 Assert.IsTrue (canceled, "#3");
451 public void ConcurrentCancelLinkedTokenSourceWhileDisposing ()
453 ParallelTestHelper.Repeat (delegate {
454 var src = new CancellationTokenSource ();
455 var linked = CancellationTokenSource.CreateLinkedTokenSource (src.Token);
456 var cntd = new CountdownEvent (2);
458 var t1 = new Thread (() => {
463 var t2 = new Thread (() => {
478 public void DisposeRace ()
480 for (int i = 0; i < 1000; ++i) {
481 var c1 = new CancellationTokenSource ();
483 var wh = c1.Token.WaitHandle;