Merge pull request #1200 from akoeplinger/remove-jvm
[mono.git] / mcs / class / corlib / Test / System.Threading / CancellationTokenSourceTest.cs
index 45d9ba9a90359a1309bfe8271a335bdb17d40b1b..5bf805aae0b6e0264998d15c63b8d01f5768c77a 100644 (file)
@@ -3,6 +3,7 @@
 //
 // Authors:
 //       Marek Safar (marek.safar@gmail.com)
+//       Jeremie Laval (jeremie.laval@gmail.com)
 //
 // Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
 //
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
-#if NET_4_0 || MOBILE
+#if NET_4_0
 
 using System;
 using System.Threading;
 using NUnit.Framework;
 using System.Threading.Tasks;
+using MonoTests.System.Threading.Tasks;
 
 namespace MonoTests.System.Threading
 {
@@ -88,9 +90,9 @@ namespace MonoTests.System.Threading
                        int called = 0;
                        var cts = new CancellationTokenSource ();
                        cts.Token.Register (() => called++);
-                       cts.CancelAfter (20);
+                       cts.CancelAfter (50);
                        cts.Dispose ();
-                       Thread.Sleep (50);
+                       Thread.Sleep (100);
                        Assert.AreEqual (0, called, "#1");
                }
 
@@ -128,6 +130,39 @@ namespace MonoTests.System.Threading
                        Assert.AreEqual (12, called, "#2");
                }
 
+
+               [Test]
+               public void Cancel_Order ()
+               {
+                       var cts = new CancellationTokenSource ();
+                       var current = 0;
+                       Action<object> a = x => { Assert.AreEqual(current, x); current++; };
+
+                       cts.Token.Register (a, 2);
+                       cts.Token.Register (a, 1);
+                       cts.Token.Register (a, 0);
+                       cts.Cancel ();
+               }
+
+
+               [Test]
+               public void CancelWithDispose ()
+               {
+                       CancellationTokenSource cts = new CancellationTokenSource ();
+                       CancellationToken c = cts.Token;
+                       c.Register (() => {
+                               cts.Dispose ();
+                       });
+
+                       int called = 0;
+                       c.Register (() => {
+                               called++;
+                       });
+
+                       cts.Cancel ();
+                       Assert.AreEqual (1, called, "#1");
+               }
+
                [Test]
                public void Cancel_SingleException ()
                {
@@ -171,6 +206,50 @@ namespace MonoTests.System.Threading
                        cts.Cancel ();
                }
 
+               [Test]
+               public void Cancel_ExceptionOrder ()
+               {
+                       var cts = new CancellationTokenSource ();
+
+                       cts.Token.Register (() => { throw new ApplicationException ("1"); });
+                       cts.Token.Register (() => { throw new ApplicationException ("2"); });
+                       cts.Token.Register (() => { throw new ApplicationException ("3"); });
+
+                       try {
+                               cts.Cancel ();
+                       } catch (AggregateException e) {
+                               Assert.AreEqual (3, e.InnerExceptions.Count, "#2");
+                               Assert.AreEqual ("3", e.InnerExceptions[0].Message, "#3");
+                               Assert.AreEqual ("2", e.InnerExceptions[1].Message, "#4");
+                               Assert.AreEqual ("1", e.InnerExceptions[2].Message, "#5");
+                       }
+               }
+
+               [Test]
+               public void Cancel_MultipleException_Recursive ()
+               {
+                       CancellationTokenSource cts = new CancellationTokenSource ();
+                       CancellationToken c = cts.Token;
+                       c.Register (() => {
+                               cts.Cancel ();
+                       });
+
+                       c.Register (() => {
+                               throw new ApplicationException ();
+                       });
+
+                       c.Register (() => {
+                               throw new NotSupportedException ();
+                       });
+
+                       try {
+                               cts.Cancel (false);
+                               Assert.Fail ("#1");
+                       } catch (AggregateException e) {
+                               Assert.AreEqual (2, e.InnerExceptions.Count, "#2");
+                       }
+               }
+
                [Test]
                public void Cancel_MultipleExceptionsFirstThrows ()
                {
@@ -320,6 +399,94 @@ namespace MonoTests.System.Threading
                        Assert.IsTrue (t.Wait (1000), "#3");
                        Assert.AreEqual (12, called, "#4");
                }
+
+               [Test]
+               public void ReEntrantRegistrationTest ()
+               {
+                       bool unregister = false;
+                       bool register = false;
+                       var source = new CancellationTokenSource ();
+                       var token = source.Token;
+
+                       Console.WriteLine ("Test1");
+                       var reg = token.Register (() => unregister = true);
+                       token.Register (() => reg.Dispose ());
+                       token.Register (() => { Console.WriteLine ("Gnyah"); token.Register (() => register = true); });
+                       source.Cancel ();
+
+                       Assert.IsFalse (unregister);
+                       Assert.IsTrue (register);
+               }
+
+               [Test]
+               public void DisposeAfterRegistrationTest ()
+               {
+                       var source = new CancellationTokenSource ();
+                       bool ran = false;
+                       var req = source.Token.Register (() => ran = true);
+                       source.Dispose ();
+                       req.Dispose ();
+                       Assert.IsFalse (ran);
+               }
+
+               [Test]
+               public void CancelLinkedTokenSource ()
+               {
+                       var cts = new CancellationTokenSource ();
+                       bool canceled = false;
+                       cts.Token.Register (() => canceled = true);
+
+                       using (var linked = CancellationTokenSource.CreateLinkedTokenSource (cts.Token))
+                               ;
+
+                       Assert.IsFalse (canceled, "#1");
+                       Assert.IsFalse (cts.IsCancellationRequested, "#2");
+
+                       cts.Cancel ();
+
+                       Assert.IsTrue (canceled, "#3");
+               }
+
+               [Test]
+               public void ConcurrentCancelLinkedTokenSourceWhileDisposing ()
+               {
+                       ParallelTestHelper.Repeat (delegate {
+                               var src = new CancellationTokenSource ();
+                               var linked = CancellationTokenSource.CreateLinkedTokenSource (src.Token);
+                               var cntd = new CountdownEvent (2);
+
+                               var t1 = new Thread (() => {
+                                       if (!cntd.Signal ())
+                                               cntd.Wait (200);
+                                       src.Cancel ();
+                               });
+                               var t2 = new Thread (() => {
+                                       if (!cntd.Signal ())
+                                               cntd.Wait (200);
+                                       linked.Dispose ();
+                               });
+
+                               t1.Start ();
+                               t2.Start ();
+                               t1.Join (500);
+                               t2.Join (500);
+                       }, 500);
+               }
+
+#if NET_4_5
+               [Test]
+               public void DisposeRace ()
+               {
+                       for (int i = 0; i < 1000; ++i) {
+                               var c1 = new CancellationTokenSource ();
+                               using (c1) {
+                                       var wh = c1.Token.WaitHandle;
+                                       c1.CancelAfter (1);
+                                       Thread.Sleep (1);
+                               }
+                       }
+               }
+#endif
        }
 }